summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk63
-rw-r--r--api/4.xml4
-rw-r--r--api/current.xml7342
-rw-r--r--camera/libcameraservice/Android.mk11
-rw-r--r--camera/libcameraservice/CameraHardwareStub.cpp100
-rw-r--r--camera/libcameraservice/CameraHardwareStub.h54
-rw-r--r--camera/libcameraservice/CameraService.cpp490
-rw-r--r--camera/libcameraservice/CameraService.h28
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java566
-rw-r--r--cmds/app_process/app_main.cpp4
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java41
-rw-r--r--cmds/bootanimation/Android.mk5
-rw-r--r--cmds/bootanimation/BootAnimation.cpp40
-rw-r--r--cmds/bootanimation/BootAnimation.h3
-rw-r--r--cmds/bootanimation/bootanimation_main.cpp7
-rw-r--r--cmds/dumpstate/dumpstate.c2
-rw-r--r--cmds/dumpsys/Android.mk4
-rw-r--r--cmds/dumpsys/dumpsys.cpp6
-rw-r--r--cmds/keystore/netkeystore.c1
-rw-r--r--cmds/keystore/netkeystore.h8
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java3
-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/servicemanager/service_manager.c1
-rw-r--r--cmds/stagefright/Android.mk40
-rw-r--r--cmds/stagefright/JPEGSource.cpp233
-rw-r--r--cmds/stagefright/JPEGSource.h59
-rw-r--r--cmds/stagefright/WaveWriter.h71
-rw-r--r--cmds/stagefright/record.cpp207
-rw-r--r--cmds/stagefright/stagefright.cpp265
-rw-r--r--cmds/surfaceflinger/Android.mk1
-rw-r--r--cmds/surfaceflinger/main_surfaceflinger.cpp6
-rw-r--r--cmds/svc/src/com/android/commands/svc/PowerCommand.java6
-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.cpp10
-rw-r--r--cmds/system_server/system_main.cpp2
-rw-r--r--core/java/android/GoogleLocationSettingManager.java156
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java6
-rw-r--r--core/java/android/accounts/AbstractAccountAuthenticator.java266
-rw-r--r--core/java/android/accounts/Account.aidl19
-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.java60
-rw-r--r--core/java/android/accounts/AccountAuthenticatorResponse.java82
-rw-r--r--core/java/android/accounts/AccountManager.java856
-rw-r--r--core/java/android/accounts/AccountManagerCallback.java20
-rw-r--r--core/java/android/accounts/AccountManagerFuture.java67
-rw-r--r--core/java/android/accounts/AccountManagerResponse.java74
-rw-r--r--core/java/android/accounts/AccountManagerService.java1622
-rw-r--r--core/java/android/accounts/AccountMonitor.java174
-rw-r--r--core/java/android/accounts/AccountMonitorListener.java29
-rw-r--r--core/java/android/accounts/AccountsServiceConstants.java78
-rw-r--r--core/java/android/accounts/AuthenticatorBindHelper.java252
-rw-r--r--core/java/android/accounts/AuthenticatorDescription.aidl19
-rw-r--r--core/java/android/accounts/AuthenticatorDescription.java72
-rw-r--r--core/java/android/accounts/AuthenticatorException.java32
-rw-r--r--core/java/android/accounts/ChooseAccountActivity.java78
-rw-r--r--core/java/android/accounts/Constants.java59
-rw-r--r--core/java/android/accounts/GrantCredentialsPermissionActivity.java172
-rw-r--r--core/java/android/accounts/IAccountAuthenticator.aidl78
-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.java29
-rw-r--r--core/java/android/accounts/OperationCanceledException.java31
-rwxr-xr-xcore/java/android/accounts/package.html5
-rw-r--r--core/java/android/app/Activity.java43
-rw-r--r--core/java/android/app/ActivityManagerNative.java34
-rw-r--r--core/java/android/app/ActivityThread.java19
-rw-r--r--core/java/android/app/ApplicationContext.java233
-rw-r--r--core/java/android/app/ApplicationErrorReport.java8
-rw-r--r--core/java/android/app/ApplicationThreadNative.java26
-rw-r--r--core/java/android/app/Dialog.java6
-rw-r--r--core/java/android/app/IActivityManager.java5
-rw-r--r--core/java/android/app/IApplicationThread.java3
-rw-r--r--core/java/android/app/ISearchManager.aidl11
-rw-r--r--core/java/android/app/IWallpaperManager.aidl63
-rw-r--r--core/java/android/app/IWallpaperManagerCallback.aidl31
-rw-r--r--core/java/android/app/IWallpaperService.aidl55
-rw-r--r--core/java/android/app/IWallpaperServiceCallback.aidl31
-rw-r--r--core/java/android/app/IntentService.java21
-rw-r--r--core/java/android/app/LauncherActivity.java34
-rw-r--r--core/java/android/app/Notification.java11
-rw-r--r--core/java/android/app/NotificationManager.java3
-rw-r--r--core/java/android/app/SearchDialog.java2
-rw-r--r--core/java/android/app/SearchManager.java64
-rw-r--r--core/java/android/app/Service.java159
-rw-r--r--core/java/android/app/WallpaperManager.java439
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java60
-rw-r--r--core/java/android/backup/BackupDataInput.java7
-rw-r--r--core/java/android/backup/BackupManager.java2
-rw-r--r--core/java/android/backup/IRestoreSession.aidl5
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java91
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java376
-rw-r--r--core/java/android/bluetooth/BluetoothAudioGateway.java60
-rw-r--r--core/java/android/bluetooth/BluetoothClass.java73
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.aidl19
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java595
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java80
-rw-r--r--core/java/android/bluetooth/BluetoothInputStream.java98
-rw-r--r--core/java/android/bluetooth/BluetoothIntent.java37
-rw-r--r--core/java/android/bluetooth/BluetoothOutputStream.java87
-rw-r--r--core/java/android/bluetooth/BluetoothPbap.java257
-rw-r--r--core/java/android/bluetooth/BluetoothServerSocket.java102
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java187
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java69
-rw-r--r--core/java/android/bluetooth/Database.java200
-rw-r--r--core/java/android/bluetooth/HeadsetBase.java33
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl61
-rw-r--r--core/java/android/bluetooth/IBluetoothA2dp.aidl14
-rw-r--r--core/java/android/bluetooth/IBluetoothDevice.aidl78
-rw-r--r--core/java/android/bluetooth/IBluetoothDeviceCallback.aidl25
-rw-r--r--core/java/android/bluetooth/IBluetoothHeadset.aidl12
-rw-r--r--core/java/android/bluetooth/IBluetoothPbap.aidl32
-rw-r--r--core/java/android/bluetooth/RfcommSocket.java674
-rw-r--r--core/java/android/content/AbstractCursorEntityIterator.java120
-rw-r--r--core/java/android/content/AbstractSyncableContentProvider.java403
-rw-r--r--core/java/android/content/AbstractTableMerger.java606
-rw-r--r--core/java/android/content/AbstractThreadedSyncAdapter.java199
-rw-r--r--core/java/android/content/ActiveSyncInfo.java9
-rw-r--r--core/java/android/content/AsyncQueryHandler.java78
-rw-r--r--core/java/android/content/ContentProvider.java106
-rw-r--r--core/java/android/content/ContentProviderClient.java135
-rw-r--r--core/java/android/content/ContentProviderNative.java215
-rw-r--r--core/java/android/content/ContentProviderOperation.java561
-rw-r--r--core/java/android/content/ContentProviderResult.java84
-rw-r--r--core/java/android/content/ContentResolver.java448
-rw-r--r--core/java/android/content/ContentService.java106
-rw-r--r--core/java/android/content/Context.java95
-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.java51
-rw-r--r--core/java/android/content/IContentProvider.java14
-rw-r--r--core/java/android/content/IContentService.aidl38
-rw-r--r--core/java/android/content/IEntityIterator.java210
-rw-r--r--core/java/android/content/ISyncAdapter.aidl8
-rw-r--r--core/java/android/content/Intent.java124
-rw-r--r--core/java/android/content/OperationApplicationException.java54
-rw-r--r--core/java/android/content/SyncAdapter.java15
-rw-r--r--core/java/android/content/SyncAdapterType.aidl20
-rw-r--r--core/java/android/content/SyncAdapterType.java145
-rw-r--r--core/java/android/content/SyncAdaptersCache.java60
-rw-r--r--core/java/android/content/SyncManager.java627
-rw-r--r--core/java/android/content/SyncResult.java21
-rw-r--r--core/java/android/content/SyncStateContentProviderHelper.java43
-rw-r--r--core/java/android/content/SyncStats.java21
-rw-r--r--core/java/android/content/SyncStatusObserver.java21
-rw-r--r--core/java/android/content/SyncStorageEngine.java237
-rw-r--r--core/java/android/content/SyncableContentProvider.java29
-rw-r--r--core/java/android/content/TempProviderSyncAdapter.java63
-rwxr-xr-xcore/java/android/content/pm/ConfigurationInfo.java16
-rwxr-xr-xcore/java/android/content/pm/FeatureInfo.aidl19
-rw-r--r--core/java/android/content/pm/FeatureInfo.java101
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl9
-rw-r--r--core/java/android/content/pm/PackageInfo.java7
-rw-r--r--core/java/android/content/pm/PackageManager.java55
-rw-r--r--core/java/android/content/pm/PackageParser.java81
-rw-r--r--core/java/android/content/pm/ProviderInfo.java7
-rw-r--r--core/java/android/content/pm/RegisteredServicesCache.java238
-rw-r--r--core/java/android/content/res/Configuration.java7
-rw-r--r--core/java/android/content/res/Resources.java4
-rw-r--r--core/java/android/content/res/StringBlock.java34
-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/SQLiteDatabase.java32
-rw-r--r--core/java/android/database/sqlite/SQLiteQueryBuilder.java15
-rw-r--r--core/java/android/hardware/Camera.java99
-rw-r--r--core/java/android/hardware/SensorListener.java3
-rw-r--r--core/java/android/hardware/SensorManager.java40
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java5
-rwxr-xr-xcore/java/android/inputmethodservice/Keyboard.java2
-rwxr-xr-xcore/java/android/inputmethodservice/KeyboardView.java96
-rw-r--r--core/java/android/net/ConnectivityManager.java59
-rw-r--r--core/java/android/net/IConnectivityManager.aidl4
-rw-r--r--core/java/android/net/MobileDataStateTracker.java403
-rw-r--r--core/java/android/net/NetworkStateTracker.java73
-rw-r--r--core/java/android/net/NetworkUtils.java3
-rw-r--r--core/java/android/net/Uri.java2
-rw-r--r--core/java/android/net/WebAddress.java2
-rw-r--r--core/java/android/net/http/ConnectionThread.java29
-rw-r--r--core/java/android/net/http/Request.java30
-rw-r--r--core/java/android/net/http/RequestHandle.java2
-rw-r--r--core/java/android/net/http/RequestQueue.java30
-rw-r--r--core/java/android/os/Build.java14
-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/FileObserver.java39
-rw-r--r--core/java/android/os/HandlerStateMachine.java8
-rwxr-xr-xcore/java/android/os/IHardwareService.aidl4
-rw-r--r--core/java/android/os/IPowerManager.aidl1
-rw-r--r--core/java/android/os/LatencyTimer.java94
-rw-r--r--core/java/android/os/MemoryFile.java17
-rw-r--r--core/java/android/os/PowerManager.java43
-rw-r--r--core/java/android/os/Process.java2
-rw-r--r--core/java/android/os/RemoteCallbackList.java57
-rw-r--r--core/java/android/os/SystemClock.java8
-rw-r--r--core/java/android/os/SystemProperties.java40
-rw-r--r--core/java/android/os/Vibrator.java7
-rw-r--r--core/java/android/pim/ContactsAsyncHelper.java128
-rw-r--r--core/java/android/pim/RecurrenceSet.java67
-rw-r--r--core/java/android/pim/vcard/Constants.java94
-rw-r--r--core/java/android/pim/vcard/ContactStruct.java1218
-rw-r--r--core/java/android/pim/vcard/EntryCommitter.java48
-rw-r--r--core/java/android/pim/vcard/EntryHandler.java38
-rw-r--r--core/java/android/pim/vcard/VCardBuilder.java64
-rw-r--r--core/java/android/pim/vcard/VCardBuilderCollection.java99
-rw-r--r--core/java/android/pim/vcard/VCardComposer.java1436
-rw-r--r--core/java/android/pim/vcard/VCardConfig.java283
-rw-r--r--core/java/android/pim/vcard/VCardDataBuilder.java320
-rw-r--r--core/java/android/pim/vcard/VCardEntryCounter.java60
-rw-r--r--core/java/android/pim/vcard/VCardParser.java90
-rw-r--r--core/java/android/pim/vcard/VCardParser_V21.java928
-rw-r--r--core/java/android/pim/vcard/VCardParser_V30.java306
-rw-r--r--core/java/android/pim/vcard/VCardSourceDetector.java137
-rw-r--r--core/java/android/pim/vcard/VCardUtils.java764
-rw-r--r--core/java/android/pim/vcard/exception/VCardException.java35
-rw-r--r--core/java/android/pim/vcard/exception/VCardNestedException.java29
-rw-r--r--core/java/android/pim/vcard/exception/VCardNotSupportedException.java33
-rw-r--r--core/java/android/pim/vcard/exception/VCardVersionException.java29
-rw-r--r--core/java/android/pim/vcard/exception/package.html5
-rw-r--r--core/java/android/pim/vcard/package.html5
-rw-r--r--core/java/android/preference/CheckBoxPreference.java14
-rw-r--r--core/java/android/preference/RingtonePreference.java5
-rw-r--r--core/java/android/preference/VolumePreference.java173
-rw-r--r--core/java/android/provider/Browser.java19
-rw-r--r--core/java/android/provider/Calendar.java74
-rw-r--r--core/java/android/provider/CallLog.java2
-rw-r--r--core/java/android/provider/Contacts.java455
-rw-r--r--core/java/android/provider/ContactsContract.java2123
-rw-r--r--core/java/android/provider/Downloads.java46
-rw-r--r--core/java/android/provider/DrmStore.java66
-rw-r--r--core/java/android/provider/Gmail.java11
-rw-r--r--core/java/android/provider/Im.java481
-rw-r--r--core/java/android/provider/LiveFolders.java2
-rw-r--r--core/java/android/provider/MediaStore.java6
-rw-r--r--core/java/android/provider/Settings.java262
-rw-r--r--core/java/android/provider/SocialContract.java187
-rw-r--r--core/java/android/provider/SubscribedFeeds.java31
-rw-r--r--core/java/android/provider/SyncConstValue.java11
-rw-r--r--core/java/android/provider/SyncStateContract.java125
-rw-r--r--core/java/android/provider/Telephony.java39
-rw-r--r--core/java/android/server/BluetoothA2dpService.java503
-rw-r--r--core/java/android/server/BluetoothDeviceService.java1263
-rw-r--r--core/java/android/server/BluetoothEventLoop.java364
-rw-r--r--core/java/android/server/BluetoothService.java1224
-rw-r--r--core/java/android/server/search/SearchDialogWrapper.java17
-rw-r--r--core/java/android/server/search/SearchManagerService.java26
-rw-r--r--core/java/android/service/wallpaper/IWallpaperConnection.aidl28
-rw-r--r--core/java/android/service/wallpaper/IWallpaperEngine.aidl26
-rw-r--r--core/java/android/service/wallpaper/IWallpaperService.aidl28
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java698
-rw-r--r--core/java/android/speech/IRecognitionListener.aidl60
-rw-r--r--core/java/android/speech/IRecognitionService.aidl37
-rw-r--r--core/java/android/speech/RecognitionResult.aidl19
-rw-r--r--core/java/android/speech/RecognitionResult.java176
-rw-r--r--core/java/android/speech/RecognitionServiceUtil.java101
-rw-r--r--core/java/android/syncml/pim/vcard/ContactStruct.java27
-rw-r--r--core/java/android/syncml/pim/vcard/VCardDataBuilder.java6
-rw-r--r--core/java/android/syncml/pim/vcard/VCardParser.java1
-rw-r--r--core/java/android/test/AndroidTestCase.java26
-rw-r--r--core/java/android/test/InstrumentationTestCase.java16
-rw-r--r--core/java/android/test/InstrumentationTestSuite.java2
-rw-r--r--core/java/android/text/BoringLayout.java9
-rw-r--r--core/java/android/text/StaticLayout.java8
-rw-r--r--core/java/android/text/TextPaint.java2
-rw-r--r--core/java/android/text/format/DateUtils.java58
-rw-r--r--core/java/android/text/method/ArrowKeyMovementMethod.java81
-rw-r--r--core/java/android/text/method/QwertyKeyListener.java2
-rw-r--r--core/java/android/text/style/AbsoluteSizeSpan.java32
-rw-r--r--core/java/android/text/style/ImageSpan.java2
-rw-r--r--core/java/android/text/style/LineHeightSpan.java7
-rw-r--r--core/java/android/util/Config.java8
-rw-r--r--core/java/android/util/EventLog.java25
-rw-r--r--core/java/android/util/MathUtils.java176
-rw-r--r--core/java/android/util/Pair.java76
-rw-r--r--core/java/android/view/HapticFeedbackConstants.java9
-rw-r--r--core/java/android/view/IWindow.aidl9
-rw-r--r--core/java/android/view/IWindowManager.aidl1
-rw-r--r--core/java/android/view/IWindowSession.aidl6
-rw-r--r--core/java/android/view/KeyEvent.java27
-rw-r--r--core/java/android/view/MotionEvent.java864
-rw-r--r--core/java/android/view/RawInputEvent.java18
-rw-r--r--core/java/android/view/Surface.java25
-rw-r--r--core/java/android/view/SurfaceHolder.java18
-rw-r--r--core/java/android/view/SurfaceView.java24
-rw-r--r--core/java/android/view/View.java8
-rw-r--r--core/java/android/view/ViewRoot.java116
-rw-r--r--core/java/android/view/ViewStub.java18
-rw-r--r--core/java/android/view/VolumePanel.java31
-rw-r--r--core/java/android/view/Window.java25
-rw-r--r--core/java/android/view/WindowManager.java31
-rw-r--r--core/java/android/view/WindowManagerPolicy.java20
-rw-r--r--core/java/android/view/animation/Animation.java2
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java11
-rw-r--r--core/java/android/webkit/BrowserFrame.java65
-rw-r--r--core/java/android/webkit/CacheLoader.java16
-rw-r--r--core/java/android/webkit/CacheManager.java80
-rw-r--r--core/java/android/webkit/CallbackProxy.java341
-rw-r--r--core/java/android/webkit/ContentLoader.java3
-rw-r--r--core/java/android/webkit/CookieManager.java75
-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/DateSorter.java3
-rw-r--r--core/java/android/webkit/DebugFlags.java49
-rw-r--r--core/java/android/webkit/FrameLoader.java76
-rw-r--r--core/java/android/webkit/GearsPermissionsManager.java246
-rwxr-xr-xcore/java/android/webkit/GeolocationPermissions.java259
-rwxr-xr-xcore/java/android/webkit/GeolocationService.java189
-rw-r--r--core/java/android/webkit/HTML5VideoViewProxy.java232
-rw-r--r--core/java/android/webkit/HttpAuthHandler.java4
-rw-r--r--core/java/android/webkit/HttpDateTime.java42
-rw-r--r--core/java/android/webkit/JWebCoreJavaBridge.java67
-rw-r--r--core/java/android/webkit/LoadListener.java142
-rw-r--r--core/java/android/webkit/MimeTypeMap.java630
-rw-r--r--core/java/android/webkit/MockGeolocation.java59
-rw-r--r--core/java/android/webkit/Network.java30
-rw-r--r--core/java/android/webkit/Plugin.java75
-rw-r--r--core/java/android/webkit/PluginContentLoader.java96
-rw-r--r--core/java/android/webkit/PluginData.java27
-rw-r--r--core/java/android/webkit/PluginList.java28
-rw-r--r--core/java/android/webkit/PluginManager.java157
-rw-r--r--core/java/android/webkit/SslErrorHandler.java86
-rw-r--r--core/java/android/webkit/StreamLoader.java9
-rw-r--r--core/java/android/webkit/TextDialog.java593
-rw-r--r--core/java/android/webkit/URLUtil.java29
-rw-r--r--core/java/android/webkit/UrlInterceptHandler.java12
-rw-r--r--core/java/android/webkit/UrlInterceptRegistry.java30
-rw-r--r--core/java/android/webkit/ViewManager.java137
-rw-r--r--core/java/android/webkit/WebBackForwardList.java2
-rw-r--r--core/java/android/webkit/WebChromeClient.java110
-rw-r--r--core/java/android/webkit/WebHistoryItem.java18
-rw-r--r--core/java/android/webkit/WebIconDatabase.java2
-rw-r--r--core/java/android/webkit/WebSettings.java307
-rw-r--r--core/java/android/webkit/WebStorage.java311
-rw-r--r--core/java/android/webkit/WebSyncManager.java10
-rw-r--r--core/java/android/webkit/WebTextView.java785
-rw-r--r--core/java/android/webkit/WebView.java2357
-rw-r--r--core/java/android/webkit/WebViewCore.java1016
-rw-r--r--core/java/android/webkit/WebViewDatabase.java38
-rw-r--r--core/java/android/webkit/gears/AndroidGpsLocationProvider.java156
-rw-r--r--core/java/android/webkit/gears/AndroidRadioDataProvider.java260
-rw-r--r--core/java/android/webkit/gears/AndroidWifiDataProvider.java140
-rw-r--r--core/java/android/webkit/gears/ApacheHttpRequestAndroid.java1134
-rw-r--r--core/java/android/webkit/gears/DesktopAndroid.java113
-rw-r--r--core/java/android/webkit/gears/NativeDialog.java142
-rw-r--r--core/java/android/webkit/gears/PluginSettings.java79
-rw-r--r--core/java/android/webkit/gears/UrlInterceptHandlerGears.java417
-rw-r--r--core/java/android/webkit/gears/VersionExtractor.java147
-rw-r--r--core/java/android/webkit/gears/ZipInflater.java200
-rw-r--r--core/java/android/webkit/gears/package.html3
-rw-r--r--core/java/android/widget/AbsListView.java63
-rw-r--r--core/java/android/widget/AbsSeekBar.java21
-rw-r--r--core/java/android/widget/AdapterView.java2
-rw-r--r--core/java/android/widget/AlphabetIndexer.java41
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java76
-rw-r--r--core/java/android/widget/ExpandableListView.java10
-rw-r--r--core/java/android/widget/FastScroller.java14
-rw-r--r--core/java/android/widget/LinearLayout.java2
-rw-r--r--core/java/android/widget/ListView.java57
-rw-r--r--core/java/android/widget/MediaController.java47
-rw-r--r--core/java/android/widget/PopupWindow.java1
-rw-r--r--core/java/android/widget/Scroller.java44
-rw-r--r--core/java/android/widget/SimpleCursorTreeAdapter.java114
-rw-r--r--core/java/android/widget/TabHost.java29
-rw-r--r--core/java/android/widget/TabWidget.java91
-rw-r--r--core/java/android/widget/TextView.java14
-rw-r--r--core/java/android/widget/VideoView.java199
-rwxr-xr-xcore/java/com/android/internal/app/NetInitiatedActivity.java139
-rw-r--r--core/java/com/android/internal/app/ShutdownThread.java12
-rw-r--r--core/java/com/android/internal/backup/SystemBackupAgent.java35
-rw-r--r--core/java/com/android/internal/content/SyncStateContentProviderHelper.java115
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java5
-rw-r--r--core/java/com/android/internal/os/HandlerCaller.java20
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java61
-rw-r--r--core/java/com/android/internal/service/wallpaper/ImageWallpaper.java148
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java95
-rw-r--r--core/java/com/android/internal/view/BaseSurfaceHolder.java174
-rw-r--r--core/java/com/android/internal/widget/ContactHeaderWidget.java495
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java10
-rw-r--r--core/java/com/google/android/gdata/client/QueryParamsImpl.java4
-rw-r--r--core/java/com/google/android/gdata2/client/AndroidGDataClient.java590
-rw-r--r--core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java31
-rw-r--r--core/java/com/google/android/gdata2/client/QueryParamsImpl.java99
-rw-r--r--core/java/com/google/android/mms/pdu/EncodedStringValue.java12
-rw-r--r--core/java/com/google/android/mms/pdu/PduPersister.java102
-rw-r--r--core/java/com/google/android/net/GoogleHttpClient.java6
-rw-r--r--core/java/com/google/android/net/UrlRules.java11
-rw-r--r--core/jni/.android_server_BluetoothEventLoop.cpp.swpbin0 -> 16384 bytes
-rw-r--r--core/jni/ActivityManager.cpp6
-rw-r--r--core/jni/Android.mk16
-rw-r--r--core/jni/AndroidRuntime.cpp226
-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/Canvas.cpp3
-rw-r--r--core/jni/android/graphics/ColorFilter.cpp6
-rw-r--r--core/jni/android/graphics/Paint.cpp13
-rw-r--r--core/jni/android/graphics/Path.cpp5
-rw-r--r--core/jni/android/graphics/Region.cpp2
-rw-r--r--core/jni/android/graphics/Typeface.cpp22
-rw-r--r--core/jni/android/opengl/util.cpp141
-rw-r--r--core/jni/android_bluetooth_BluetoothSocket.cpp534
-rw-r--r--core/jni/android_bluetooth_Database.cpp184
-rw-r--r--core/jni/android_bluetooth_RfcommSocket.cpp621
-rw-r--r--core/jni/android_bluetooth_common.cpp332
-rw-r--r--core/jni/android_bluetooth_common.h19
-rw-r--r--core/jni/android_database_CursorWindow.cpp65
-rw-r--r--core/jni/android_database_SQLiteDatabase.cpp5
-rw-r--r--core/jni/android_emoji_EmojiFactory.cpp3
-rw-r--r--core/jni/android_hardware_Camera.cpp2
-rwxr-xr-xcore/jni/android_location_GpsLocationProvider.cpp161
-rw-r--r--core/jni/android_media_AudioRecord.cpp26
-rw-r--r--core/jni/android_media_AudioSystem.cpp166
-rw-r--r--core/jni/android_media_AudioTrack.cpp49
-rw-r--r--core/jni/android_net_NetUtils.cpp12
-rw-r--r--core/jni/android_net_wifi_Wifi.cpp24
-rw-r--r--core/jni/android_os_Exec.cpp215
-rw-r--r--core/jni/android_os_MemoryFile.cpp12
-rw-r--r--core/jni/android_os_SystemProperties.cpp109
-rw-r--r--core/jni/android_server_BluetoothA2dpService.cpp318
-rw-r--r--core/jni/android_server_BluetoothDeviceService.cpp1035
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp718
-rw-r--r--core/jni/android_server_BluetoothService.cpp750
-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_EventLog.cpp92
-rw-r--r--core/jni/android_util_Process.cpp14
-rw-r--r--core/jni/android_view_Surface.cpp305
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp3
-rw-r--r--core/res/AndroidManifest.xml121
-rw-r--r--core/res/res/anim/wallpaper_activity_close_enter.xml32
-rw-r--r--core/res/res/anim/wallpaper_activity_close_exit.xml31
-rw-r--r--core/res/res/anim/wallpaper_activity_open_enter.xml31
-rw-r--r--core/res/res/anim/wallpaper_activity_open_exit.xml32
-rw-r--r--core/res/res/anim/wallpaper_enter.xml29
-rw-r--r--core/res/res/anim/wallpaper_exit.xml29
-rw-r--r--core/res/res/color/tab_indicator_text.xml4
-rw-r--r--core/res/res/drawable-hdpi/activity_title_bar.9.pngbin0 -> 1697 bytes
-rw-r--r--core/res/res/drawable-hdpi/arrow_down_float.pngbin0 -> 618 bytes
-rw-r--r--core/res/res/drawable-hdpi/arrow_up_float.pngbin0 -> 616 bytes
-rw-r--r--core/res/res/drawable-hdpi/battery_charge_background.pngbin0 -> 4925 bytes
-rw-r--r--core/res/res/drawable-hdpi/battery_charge_fill_empty.9.pngbin0 -> 783 bytes
-rw-r--r--core/res/res/drawable-hdpi/battery_charge_fill_full.9.pngbin0 -> 756 bytes
-rw-r--r--core/res/res/drawable-hdpi/battery_charge_fill_warning.9.pngbin0 -> 819 bytes
-rw-r--r--core/res/res/drawable-hdpi/battery_low_battery.pngbin0 -> 4759 bytes
-rw-r--r--core/res/res/drawable-hdpi/blank_tile.pngbin0 -> 685 bytes
-rw-r--r--core/res/res/drawable-hdpi/bottom_bar.pngbin0 -> 389 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_buttonless_off.pngbin0 -> 895 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_buttonless_on.pngbin0 -> 1027 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_label_background.9.pngbin0 -> 224 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off.pngbin0 -> 1693 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_disable.pngbin0 -> 1170 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_disable_focused.pngbin0 -> 1568 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_pressed.pngbin0 -> 2413 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_off_selected.pngbin0 -> 2378 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on.pngbin0 -> 2115 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_disable.pngbin0 -> 1417 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_disable_focused.pngbin0 -> 1788 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_pressed.pngbin0 -> 2586 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_on_selected.pngbin0 -> 2546 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_circle_disable.pngbin0 -> 1447 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_circle_disable_focused.pngbin0 -> 2559 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_circle_normal.pngbin0 -> 1960 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_circle_pressed.pngbin0 -> 2634 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_circle_selected.pngbin0 -> 2654 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_close_normal.pngbin0 -> 1681 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_close_pressed.pngbin0 -> 2429 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_code_lock_default.pngbin0 -> 2269 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_code_lock_touched.pngbin0 -> 3215 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_default_normal.9.pngbin0 -> 962 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_default_normal_disable.9.pngbin0 -> 567 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_default_normal_disable_focused.9.pngbin0 -> 892 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_default_pressed.9.pngbin0 -> 1469 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_default_selected.9.pngbin0 -> 1512 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_default_small_normal.9.pngbin0 -> 894 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.pngbin0 -> 541 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.pngbin0 -> 830 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_default_small_pressed.9.pngbin0 -> 1301 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_default_small_selected.9.pngbin0 -> 1323 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_dialog_disable.pngbin0 -> 1859 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_dialog_normal.pngbin0 -> 1891 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_dialog_pressed.pngbin0 -> 2425 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_dialog_selected.pngbin0 -> 2577 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_dropdown_normal.9.pngbin0 -> 1840 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_dropdown_pressed.9.pngbin0 -> 3199 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_dropdown_selected.9.pngbin0 -> 3231 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_erase_default.9.pngbin0 -> 690 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_erase_pressed.9.pngbin0 -> 726 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_erase_selected.9.pngbin0 -> 747 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_global_search_normal.9.pngbin0 -> 1060 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_keyboard_key_normal.9.pngbin0 -> 674 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_keyboard_key_normal_off.9.pngbin0 -> 968 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_keyboard_key_normal_on.9.pngbin0 -> 1039 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_keyboard_key_pressed.9.pngbin0 -> 638 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.pngbin0 -> 911 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.pngbin0 -> 979 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_media_player.9.pngbin0 -> 940 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_media_player_disabled.9.pngbin0 -> 941 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_media_player_disabled_selected.9.pngbin0 -> 1085 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_media_player_pressed.9.pngbin0 -> 861 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_media_player_selected.9.pngbin0 -> 1333 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_minus_default.pngbin0 -> 8289 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_minus_disable.pngbin0 -> 8595 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_minus_disable_focused.pngbin0 -> 6341 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_minus_pressed.pngbin0 -> 6387 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_minus_selected.pngbin0 -> 9023 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_plus_default.pngbin0 -> 8495 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_plus_disable.pngbin0 -> 8831 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_plus_disable_focused.pngbin0 -> 6519 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_plus_pressed.pngbin0 -> 9267 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_plus_selected.pngbin0 -> 9249 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_label_background.9.pngbin0 -> 216 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_off.pngbin0 -> 2491 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_off_pressed.pngbin0 -> 3304 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_off_selected.pngbin0 -> 3267 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_on.pngbin0 -> 2777 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_on_pressed.pngbin0 -> 3454 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_radio_on_selected.pngbin0 -> 3441 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_rating_star_off_normal.pngbin0 -> 4372 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_rating_star_off_pressed.pngbin0 -> 6013 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_rating_star_off_selected.pngbin0 -> 5951 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_rating_star_on_normal.pngbin0 -> 4988 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_rating_star_on_pressed.pngbin0 -> 6199 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_rating_star_on_selected.pngbin0 -> 6111 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_default.9.pngbin0 -> 648 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_pressed.9.pngbin0 -> 1347 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_selected.9.pngbin0 -> 1367 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_voice_default.9.pngbin0 -> 878 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_voice_pressed.9.pngbin0 -> 1537 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_voice_selected.9.pngbin0 -> 1590 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_square_overlay_disabled.pngbin0 -> 822 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_square_overlay_disabled_focused.pngbin0 -> 1115 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_square_overlay_normal.pngbin0 -> 858 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_square_overlay_pressed.pngbin0 -> 955 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_square_overlay_selected.pngbin0 -> 971 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_big_off.pngbin0 -> 2208 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_big_off_disable.pngbin0 -> 2024 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_big_off_disable_focused.pngbin0 -> 2602 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_big_off_pressed.pngbin0 -> 2674 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_big_off_selected.pngbin0 -> 2447 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_big_on.pngbin0 -> 2615 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_big_on_disable.pngbin0 -> 2081 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_big_on_disable_focused.pngbin0 -> 2360 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_big_on_pressed.pngbin0 -> 2721 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_big_on_selected.pngbin0 -> 2427 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_star_label_background.9.pngbin0 -> 185 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_toggle_off.9.pngbin0 -> 584 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_toggle_on.9.pngbin0 -> 602 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_down_disabled.9.pngbin0 -> 2229 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_down_disabled_focused.9.pngbin0 -> 2669 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_down_normal.9.pngbin0 -> 3215 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_down_pressed.9.pngbin0 -> 4541 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_down_selected.9.pngbin0 -> 4549 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_page_normal.pngbin0 -> 3207 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_page_press.pngbin0 -> 3484 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_up_disabled.9.pngbin0 -> 2327 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_up_disabled_focused.9.pngbin0 -> 2712 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_up_normal.9.pngbin0 -> 3147 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_up_pressed.9.pngbin0 -> 3980 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_zoom_up_selected.9.pngbin0 -> 3963 bytes
-rw-r--r--core/res/res/drawable-hdpi/button_onoff_indicator_off.pngbin0 -> 431 bytes
-rw-r--r--core/res/res/drawable-hdpi/button_onoff_indicator_on.pngbin0 -> 431 bytes
-rw-r--r--core/res/res/drawable-hdpi/call_contact.pngbin0 -> 1877 bytes
-rw-r--r--core/res/res/drawable-hdpi/checkbox_off_background.pngbin0 -> 803 bytes
-rw-r--r--core/res/res/drawable-hdpi/checkbox_on_background.pngbin0 -> 1212 bytes
-rw-r--r--core/res/res/drawable-hdpi/clock_dial.pngbin0 -> 10519 bytes
-rw-r--r--core/res/res/drawable-hdpi/clock_hand_hour.pngbin0 -> 2196 bytes
-rw-r--r--core/res/res/drawable-hdpi/clock_hand_minute.pngbin0 -> 2518 bytes
-rw-r--r--core/res/res/drawable-hdpi/code_lock_bottom.9.pngbin0 -> 222 bytes
-rw-r--r--core/res/res/drawable-hdpi/code_lock_left.9.pngbin0 -> 168 bytes
-rw-r--r--core/res/res/drawable-hdpi/code_lock_top.9.pngbin0 -> 165 bytes
-rw-r--r--core/res/res/drawable-hdpi/compass_arrow.pngbin0 -> 1033 bytes
-rw-r--r--core/res/res/drawable-hdpi/compass_base.pngbin0 -> 3986 bytes
-rw-r--r--core/res/res/drawable-hdpi/create_contact.pngbin0 -> 2138 bytes
-rw-r--r--core/res/res/drawable-hdpi/dark_header.9.pngbin0 -> 203 bytes
-rw-r--r--core/res/res/drawable-hdpi/dialog_divider_horizontal_light.9.pngbin0 -> 296 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_horizontal_bright.9.pngbin0 -> 268 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.pngbin0 -> 287 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_horizontal_dark.9.pngbin0 -> 285 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.pngbin0 -> 289 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_horizontal_dim_dark.9.pngbin0 -> 285 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_horizontal_textfield.9.pngbin0 -> 142 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_vertical_bright.9.pngbin0 -> 145 bytes
-rw-r--r--core/res/res/drawable-hdpi/editbox_background_focus_yellow.9.pngbin0 -> 1347 bytes
-rw-r--r--core/res/res/drawable-hdpi/editbox_background_normal.9.pngbin0 -> 642 bytes
-rw-r--r--core/res/res/drawable-hdpi/editbox_dropdown_background.9.pngbin0 -> 395 bytes
-rw-r--r--core/res/res/drawable-hdpi/editbox_dropdown_background_dark.9.pngbin0 -> 402 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_angel.pngbin0 -> 1534 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_cool.pngbin0 -> 1321 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_crying.pngbin0 -> 1401 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_foot_in_mouth.pngbin0 -> 1387 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_happy.pngbin0 -> 1486 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_kissing.pngbin0 -> 1156 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_laughing.pngbin0 -> 1382 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_lips_are_sealed.pngbin0 -> 1543 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_money_mouth.pngbin0 -> 1404 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_sad.pngbin0 -> 1455 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_surprised.pngbin0 -> 1252 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_tongue_sticking_out.pngbin0 -> 1577 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_undecided.pngbin0 -> 1400 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_winking.pngbin0 -> 1322 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_wtf.pngbin0 -> 1385 bytes
-rw-r--r--core/res/res/drawable-hdpi/emo_im_yelling.pngbin0 -> 1433 bytes
-rw-r--r--core/res/res/drawable-hdpi/expander_ic_maximized.9.pngbin0 -> 2241 bytes
-rw-r--r--core/res/res/drawable-hdpi/expander_ic_minimized.9.pngbin0 -> 2196 bytes
-rw-r--r--core/res/res/drawable-hdpi/focused_application_background_static.pngbin0 -> 2277 bytes
-rw-r--r--core/res/res/drawable-hdpi/frame_gallery_thumb.9.pngbin0 -> 990 bytes
-rw-r--r--core/res/res/drawable-hdpi/frame_gallery_thumb_pressed.9.pngbin0 -> 976 bytes
-rw-r--r--core/res/res/drawable-hdpi/frame_gallery_thumb_selected.9.pngbin0 -> 783 bytes
-rw-r--r--core/res/res/drawable-hdpi/gallery_selected_default.9.pngbin0 -> 1445 bytes
-rw-r--r--core/res/res/drawable-hdpi/gallery_selected_focused.9.pngbin0 -> 1642 bytes
-rw-r--r--core/res/res/drawable-hdpi/gallery_selected_pressed.9.pngbin0 -> 1664 bytes
-rw-r--r--core/res/res/drawable-hdpi/gallery_unselected_default.9.pngbin0 -> 729 bytes
-rw-r--r--core/res/res/drawable-hdpi/gallery_unselected_pressed.9.pngbin0 -> 874 bytes
-rw-r--r--core/res/res/drawable-hdpi/grid_selector_background_focus.9.pngbin0 -> 1664 bytes
-rw-r--r--core/res/res/drawable-hdpi/grid_selector_background_pressed.9.pngbin0 -> 1540 bytes
-rw-r--r--core/res/res/drawable-hdpi/highlight_disabled.9.pngbin0 -> 1506 bytes
-rw-r--r--core/res/res/drawable-hdpi/highlight_pressed.9.pngbin0 -> 1538 bytes
-rw-r--r--core/res/res/drawable-hdpi/highlight_selected.9.pngbin0 -> 1666 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_btn_round_more_disabled.pngbin0 -> 648 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_btn_round_more_normal.pngbin0 -> 1622 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_btn_search.pngbin0 -> 2619 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_btn_speak_now.pngbin0 -> 1936 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_fit_page_disabled.pngbin0 -> 655 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_fit_page_normal.pngbin0 -> 1396 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_page_overview_disabled.pngbin0 -> 702 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_page_overview_normal.pngbin0 -> 2055 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_bullet_key_permission.pngbin0 -> 3255 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_contact_picture.pngbin0 -> 1469 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_delete.pngbin0 -> 1445 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_dialog_alert.pngbin0 -> 1337 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_dialog_dialer.pngbin0 -> 1158 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_dialog_email.pngbin0 -> 1621 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_dialog_info.pngbin0 -> 1342 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_dialog_map.pngbin0 -> 1774 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_dialog_menu_generic.pngbin0 -> 5541 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_dialog_time.pngbin0 -> 2038 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_dialog_usb.pngbin0 -> 1475 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_emergency.pngbin0 -> 846 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_input_add.pngbin0 -> 686 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_input_delete.pngbin0 -> 1307 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_input_get.pngbin0 -> 976 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_launcher_android.pngbin0 -> 4833 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_airplane_mode.pngbin0 -> 2250 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_airplane_mode_off.pngbin0 -> 3003 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_idle_alarm.pngbin0 -> 965 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_idle_charging.pngbin0 -> 890 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_idle_lock.pngbin0 -> 784 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_idle_low_battery.pngbin0 -> 951 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_lock.pngbin0 -> 1998 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_power_off.pngbin0 -> 3037 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_silent_mode.pngbin0 -> 2242 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_silent_mode_off.pngbin0 -> 2548 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_maps_indicator_current_position.pngbin0 -> 2079 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim1.pngbin0 -> 2073 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim2.pngbin0 -> 2082 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim3.pngbin0 -> 2069 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_ff.pngbin0 -> 1505 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_next.pngbin0 -> 1675 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_pause.pngbin0 -> 755 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_play.pngbin0 -> 1261 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_previous.pngbin0 -> 1713 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_media_rew.pngbin0 -> 1510 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_account_list.pngbin0 -> 3662 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_add.pngbin0 -> 3765 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_agenda.pngbin0 -> 3000 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_allfriends.pngbin0 -> 3153 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_always_landscape_portrait.pngbin0 -> 2307 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_archive.pngbin0 -> 2003 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_attachment.pngbin0 -> 3639 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_back.pngbin0 -> 2096 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_block.pngbin0 -> 3774 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_blocked_user.pngbin0 -> 4174 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_call.pngbin0 -> 3391 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_camera.pngbin0 -> 2736 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_cc.pngbin0 -> 3417 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_chat_dashboard.pngbin0 -> 3086 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_clear_playlist.pngbin0 -> 3631 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_close_clear_cancel.pngbin0 -> 4704 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_compass.pngbin0 -> 5882 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_compose.pngbin0 -> 2993 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_crop.pngbin0 -> 2352 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_day.pngbin0 -> 1947 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_delete.pngbin0 -> 2343 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_directions.pngbin0 -> 2447 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_edit.pngbin0 -> 2310 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_emoticons.pngbin0 -> 4286 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_end_conversation.pngbin0 -> 3867 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_forward.pngbin0 -> 1881 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_friendslist.pngbin0 -> 2567 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_gallery.pngbin0 -> 4037 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_goto.pngbin0 -> 2824 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_help.pngbin0 -> 3926 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_home.pngbin0 -> 3259 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_info_details.pngbin0 -> 3080 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_invite.pngbin0 -> 3693 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_login.pngbin0 -> 3638 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_manage.pngbin0 -> 3726 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_mapmode.pngbin0 -> 2985 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_mark.pngbin0 -> 3834 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_month.pngbin0 -> 3849 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_more.pngbin0 -> 4305 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_my_calendar.pngbin0 -> 2926 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_mylocation.pngbin0 -> 3948 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_myplaces.pngbin0 -> 3138 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_notifications.pngbin0 -> 2535 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_play_clip.pngbin0 -> 2247 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_preferences.pngbin0 -> 3341 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_recent_history.pngbin0 -> 4616 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_refresh.pngbin0 -> 4174 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_report_image.pngbin0 -> 3035 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_revert.pngbin0 -> 2806 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_rotate.pngbin0 -> 4672 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_save.pngbin0 -> 2189 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_search.pngbin0 -> 3808 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_send.pngbin0 -> 3065 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_set_as.pngbin0 -> 3187 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_share.pngbin0 -> 3706 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_slideshow.pngbin0 -> 4155 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_sort_alphabetically.pngbin0 -> 3079 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_sort_by_size.pngbin0 -> 1460 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_star.pngbin0 -> 2382 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_start_conversation.pngbin0 -> 2717 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_stop.pngbin0 -> 3253 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_today.pngbin0 -> 2825 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_upload.pngbin0 -> 2250 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_upload_you_tube.pngbin0 -> 3766 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_view.pngbin0 -> 3265 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_week.pngbin0 -> 2570 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_menu_zoom.pngbin0 -> 3993 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_notification_clear_all.pngbin0 -> 2210 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_notification_overlay.9.pngbin0 -> 1014 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_partial_secure.pngbin0 -> 542 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_popup_disk_full.pngbin0 -> 2074 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_popup_reminder.pngbin0 -> 1596 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_popup_sync_1.pngbin0 -> 1612 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_popup_sync_2.pngbin0 -> 1778 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_popup_sync_3.pngbin0 -> 1689 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_popup_sync_4.pngbin0 -> 1649 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_popup_sync_5.pngbin0 -> 1879 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_popup_sync_6.pngbin0 -> 1756 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_search_category_default.pngbin0 -> 3225 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_secure.pngbin0 -> 420 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_text_dot.pngbin0 -> 865 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_vibrate.pngbin0 -> 3273 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_volume.pngbin0 -> 4283 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_volume_bluetooth_ad2p.pngbin0 -> 5210 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_volume_bluetooth_in_call.pngbin0 -> 4376 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_volume_off.pngbin0 -> 3567 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_volume_off_small.pngbin0 -> 1414 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_volume_small.pngbin0 -> 1599 bytes
-rw-r--r--core/res/res/drawable-hdpi/icon_highlight_rectangle.9.pngbin0 -> 1317 bytes
-rw-r--r--core/res/res/drawable-hdpi/icon_highlight_square.9.pngbin0 -> 1528 bytes
-rw-r--r--core/res/res/drawable-hdpi/ime_qwerty.pngbin0 -> 708 bytes
-rw-r--r--core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up.pngbin0 -> 298 bytes
-rw-r--r--core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up.pngbin0 -> 298 bytes
-rw-r--r--core/res/res/drawable-hdpi/indicator_code_lock_point_area_default.pngbin0 -> 4675 bytes
-rw-r--r--core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.pngbin0 -> 5904 bytes
-rw-r--r--core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.pngbin0 -> 5742 bytes
-rw-r--r--core/res/res/drawable-hdpi/indicator_input_error.pngbin0 -> 1461 bytes
-rw-r--r--core/res/res/drawable-hdpi/keyboard_accessory_bg_landscape.9.pngbin0 -> 217 bytes
-rw-r--r--core/res/res/drawable-hdpi/keyboard_background.9.pngbin0 -> 206 bytes
-rw-r--r--core/res/res/drawable-hdpi/keyboard_key_feedback_background.9.pngbin0 -> 1853 bytes
-rw-r--r--core/res/res/drawable-hdpi/keyboard_key_feedback_more_background.9.pngbin0 -> 2066 bytes
-rw-r--r--core/res/res/drawable-hdpi/keyboard_popup_panel_background.9.pngbin0 -> 1443 bytes
-rw-r--r--core/res/res/drawable-hdpi/keyboard_textfield_selected.9.pngbin0 -> 955 bytes
-rw-r--r--core/res/res/drawable-hdpi/light_header.9.pngbin0 -> 202 bytes
-rw-r--r--core/res/res/drawable-hdpi/list_selector_background_disabled.9.pngbin0 -> 4205 bytes
-rw-r--r--core/res/res/drawable-hdpi/list_selector_background_focus.9.pngbin0 -> 4329 bytes
-rw-r--r--core/res/res/drawable-hdpi/list_selector_background_longpress.9.pngbin0 -> 544 bytes
-rw-r--r--core/res/res/drawable-hdpi/list_selector_background_pressed.9.pngbin0 -> 4203 bytes
-rw-r--r--core/res/res/drawable-hdpi/loading_tile.pngbin0 -> 617 bytes
-rw-r--r--core/res/res/drawable-hdpi/maps_google_logo.pngbin0 -> 4169 bytes
-rw-r--r--core/res/res/drawable-hdpi/menu_background.9.pngbin0 -> 1307 bytes
-rw-r--r--core/res/res/drawable-hdpi/menu_background_fill_parent_width.9.pngbin0 -> 322 bytes
-rw-r--r--core/res/res/drawable-hdpi/menu_separator.9.pngbin0 -> 2826 bytes
-rw-r--r--core/res/res/drawable-hdpi/menu_submenu_background.9.pngbin0 -> 2413 bytes
-rw-r--r--core/res/res/drawable-hdpi/menuitem_background_focus.9.pngbin0 -> 4329 bytes
-rw-r--r--core/res/res/drawable-hdpi/menuitem_background_pressed.9.pngbin0 -> 4203 bytes
-rw-r--r--core/res/res/drawable-hdpi/menuitem_background_solid_focused.9.png (renamed from core/res/res/drawable/menuitem_background_solid_focused.9.png)bin165 -> 165 bytes
-rw-r--r--core/res/res/drawable-hdpi/menuitem_background_solid_pressed.9.png (renamed from core/res/res/drawable/menuitem_background_solid_pressed.9.png)bin165 -> 165 bytes
-rw-r--r--core/res/res/drawable-hdpi/menuitem_checkbox_on.pngbin0 -> 328 bytes
-rw-r--r--core/res/res/drawable-hdpi/no_tile_128.pngbin0 -> 1698 bytes
-rw-r--r--core/res/res/drawable-hdpi/panel_background.9.pngbin0 -> 2135 bytes
-rw-r--r--core/res/res/drawable-hdpi/panel_picture_frame_bg_focus_blue.9.pngbin0 -> 2065 bytes
-rw-r--r--core/res/res/drawable-hdpi/panel_picture_frame_bg_normal.9.pngbin0 -> 862 bytes
-rw-r--r--core/res/res/drawable-hdpi/panel_picture_frame_bg_pressed_blue.9.pngbin0 -> 1951 bytes
-rw-r--r--core/res/res/drawable-hdpi/pickerbox_background.pngbin0 -> 1131 bytes
-rw-r--r--core/res/res/drawable-hdpi/pickerbox_selected.9.pngbin0 -> 2129 bytes
-rw-r--r--core/res/res/drawable-hdpi/pickerbox_unselected.9.pngbin0 -> 1419 bytes
-rw-r--r--core/res/res/drawable-hdpi/picture_emergency.pngbin0 -> 1153 bytes
-rw-r--r--core/res/res/drawable-hdpi/picture_frame.9.pngbin0 -> 901 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_bottom_bright.9.pngbin0 -> 1231 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_bottom_dark.9.pngbin0 -> 1336 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_bottom_medium.9.pngbin0 -> 1329 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_center_bright.9.pngbin0 -> 240 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_center_dark.9.pngbin0 -> 255 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_center_medium.9.pngbin0 -> 156 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_full_bright.9.pngbin0 -> 2009 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_full_dark.9.pngbin0 -> 2218 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_inline_error.9.pngbin0 -> 2372 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_inline_error_above.9.pngbin0 -> 2383 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_top_bright.9.pngbin0 -> 1192 bytes
-rw-r--r--core/res/res/drawable-hdpi/popup_top_dark.9.pngbin0 -> 1339 bytes
-rw-r--r--core/res/res/drawable-hdpi/presence_away.pngbin0 -> 1306 bytes
-rw-r--r--core/res/res/drawable-hdpi/presence_busy.pngbin0 -> 1241 bytes
-rw-r--r--core/res/res/drawable-hdpi/presence_invisible.pngbin0 -> 1094 bytes
-rw-r--r--core/res/res/drawable-hdpi/presence_offline.pngbin0 -> 1340 bytes
-rw-r--r--core/res/res/drawable-hdpi/presence_online.pngbin0 -> 1265 bytes
-rw-r--r--core/res/res/drawable-hdpi/pressed_application_background_static.pngbin0 -> 1651 bytes
-rw-r--r--core/res/res/drawable-hdpi/progressbar_indeterminate1.pngbin0 -> 779 bytes
-rw-r--r--core/res/res/drawable-hdpi/progressbar_indeterminate2.pngbin0 -> 775 bytes
-rw-r--r--core/res/res/drawable-hdpi/progressbar_indeterminate3.pngbin0 -> 779 bytes
-rw-r--r--core/res/res/drawable-hdpi/radiobutton_off_background.pngbin0 -> 882 bytes
-rw-r--r--core/res/res/drawable-hdpi/radiobutton_on_background.pngbin0 -> 1187 bytes
-rw-r--r--core/res/res/drawable-hdpi/rate_star_big_half.pngbin0 -> 1458 bytes
-rw-r--r--core/res/res/drawable-hdpi/rate_star_big_off.pngbin0 -> 833 bytes
-rw-r--r--core/res/res/drawable-hdpi/rate_star_big_on.pngbin0 -> 2694 bytes
-rw-r--r--core/res/res/drawable-hdpi/rate_star_small_half.pngbin0 -> 866 bytes
-rw-r--r--core/res/res/drawable-hdpi/rate_star_small_off.pngbin0 -> 509 bytes
-rw-r--r--core/res/res/drawable-hdpi/rate_star_small_on.pngbin0 -> 856 bytes
-rw-r--r--core/res/res/drawable-hdpi/reticle.pngbin0 -> 1090 bytes
-rw-r--r--core/res/res/drawable-hdpi/screen_progress_frame.9.pngbin0 -> 370 bytes
-rw-r--r--core/res/res/drawable-hdpi/screen_progress_inner.9.pngbin0 -> 178 bytes
-rw-r--r--core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.pngbin0 -> 1720 bytes
-rw-r--r--core/res/res/drawable-hdpi/scrollbar_handle_horizontal.9.pngbin0 -> 336 bytes
-rw-r--r--core/res/res/drawable-hdpi/scrollbar_handle_vertical.9.pngbin0 -> 308 bytes
-rw-r--r--core/res/res/drawable-hdpi/search_dropdown_background.9.pngbin0 -> 552 bytes
-rw-r--r--core/res/res/drawable-hdpi/search_plate.9.pngbin0 -> 319 bytes
-rw-r--r--core/res/res/drawable-hdpi/search_plate_global.9.pngbin0 -> 301 bytes
-rw-r--r--core/res/res/drawable-hdpi/seek_thumb_normal.pngbin0 -> 1350 bytes
-rw-r--r--core/res/res/drawable-hdpi/seek_thumb_pressed.pngbin0 -> 1626 bytes
-rw-r--r--core/res/res/drawable-hdpi/seek_thumb_selected.pngbin0 -> 1672 bytes
-rw-r--r--core/res/res/drawable-hdpi/settings_header_raw.9.pngbin0 -> 13362 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_black_16.pngbin0 -> 630 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_black_20.pngbin0 -> 847 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_black_48.pngbin0 -> 1812 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_black_76.pngbin0 -> 2663 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_dropdown_background_down.9.pngbin0 -> 592 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_dropdown_background_up.9.pngbin0 -> 574 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_normal.9.pngbin0 -> 911 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_press.9.pngbin0 -> 1954 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_select.9.pngbin0 -> 2082 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_white_16.pngbin0 -> 606 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_white_48.pngbin0 -> 1736 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_white_76.pngbin0 -> 2603 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinnerbox_arrow_first.9.pngbin0 -> 491 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinnerbox_arrow_last.9.pngbin0 -> 489 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinnerbox_arrow_middle.9.pngbin0 -> 486 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinnerbox_arrow_single.9.pngbin0 -> 451 bytes
-rw-r--r--core/res/res/drawable-hdpi/star_big_off.pngbin0 -> 2473 bytes
-rw-r--r--core/res/res/drawable-hdpi/star_big_on.pngbin0 -> 2980 bytes
-rw-r--r--core/res/res/drawable-hdpi/star_off.pngbin0 -> 891 bytes
-rw-r--r--core/res/res/drawable-hdpi/star_on.pngbin0 -> 1582 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_ecb_mode.pngbin0 -> 537 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_alarm.pngbin0 -> 1382 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_call_mute.pngbin0 -> 1158 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_chat.pngbin0 -> 994 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_disk_full.pngbin0 -> 1084 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_error.pngbin0 -> 1031 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_missed_call.pngbin0 -> 1219 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_more.pngbin0 -> 864 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_sdcard.pngbin0 -> 758 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_sdcard_usb.pngbin0 -> 1040 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_sim_toolkit.pngbin0 -> 1322 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_sync.pngbin0 -> 1599 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_sync_anim0.pngbin0 -> 1604 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_sync_error.pngbin0 -> 1566 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_voicemail.pngbin0 -> 999 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_notify_wifi_in_range.pngbin0 -> 1457 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_0.pngbin0 -> 1475 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_10.pngbin0 -> 736 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_100.pngbin0 -> 776 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_20.pngbin0 -> 741 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_40.pngbin0 -> 741 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_60.pngbin0 -> 746 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_80.pngbin0 -> 735 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.pngbin0 -> 925 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.pngbin0 -> 934 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.pngbin0 -> 934 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.pngbin0 -> 971 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.pngbin0 -> 975 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.pngbin0 -> 1024 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_battery_unknown.pngbin0 -> 1019 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_bluetooth.pngbin0 -> 918 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_bluetooth_connected.pngbin0 -> 1096 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_connected_3g.pngbin0 -> 1170 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_connected_e.pngbin0 -> 1100 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_connected_g.pngbin0 -> 1119 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_in_3g.pngbin0 -> 1179 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_in_e.pngbin0 -> 1103 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_in_g.pngbin0 -> 1116 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.pngbin0 -> 1158 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_inandout_e.pngbin0 -> 1090 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_inandout_g.pngbin0 -> 1106 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_out_3g.pngbin0 -> 1160 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_out_e.pngbin0 -> 1091 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_out_g.pngbin0 -> 1111 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_usb.pngbin0 -> 977 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_download_anim0.pngbin0 -> 734 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_download_anim1.pngbin0 -> 738 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_download_anim2.pngbin0 -> 754 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_download_anim3.pngbin0 -> 752 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_download_anim4.pngbin0 -> 724 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_download_anim5.pngbin0 -> 744 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_gps_acquiring.pngbin0 -> 716 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_gps_on.pngbin0 -> 1615 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_headset.pngbin0 -> 664 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_no_sim.pngbin0 -> 960 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_phone_call.pngbin0 -> 999 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.pngbin0 -> 1067 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_phone_call_forward.pngbin0 -> 1054 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_phone_call_on_hold.pngbin0 -> 988 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_r_signal_0.pngbin0 -> 933 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_r_signal_0_cdma.pngbin0 -> 901 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_r_signal_1.pngbin0 -> 955 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_r_signal_1_cdma.pngbin0 -> 929 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_r_signal_2.pngbin0 -> 956 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_r_signal_2_cdma.pngbin0 -> 933 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_r_signal_3.pngbin0 -> 958 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.pngbin0 -> 930 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_r_signal_4.pngbin0 -> 878 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma.pngbin0 -> 856 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.pngbin0 -> 859 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.pngbin0 -> 875 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.pngbin0 -> 889 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma.pngbin0 -> 891 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.pngbin0 -> 799 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_ringer_silent.pngbin0 -> 1096 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.pngbin0 -> 4980 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_roaming_cdma_0.pngbin0 -> 446 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.pngbin0 -> 139 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.pngbin0 -> 446 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_signal_0.pngbin0 -> 751 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_signal_1.pngbin0 -> 777 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_signal_2.pngbin0 -> 787 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_signal_3.pngbin0 -> 789 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_signal_4.pngbin0 -> 706 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_signal_flightmode.pngbin0 -> 1081 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_signal_null.pngbin0 -> 975 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_speakerphone.pngbin0 -> 1157 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_tty_mode.pngbin0 -> 400 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_upload_anim0.pngbin0 -> 767 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_upload_anim1.pngbin0 -> 771 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_upload_anim2.pngbin0 -> 774 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_upload_anim3.pngbin0 -> 767 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_upload_anim4.pngbin0 -> 750 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_upload_anim5.pngbin0 -> 762 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_vp_phone_call.pngbin0 -> 1201 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.pngbin0 -> 1067 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.pngbin0 -> 1064 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_warning.pngbin0 -> 1034 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_wifi_signal_0.pngbin0 -> 1033 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_wifi_signal_1.pngbin0 -> 1047 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_wifi_signal_2.pngbin0 -> 1054 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_wifi_signal_3.pngbin0 -> 1074 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_wifi_signal_4.pngbin0 -> 4484 bytes
-rw-r--r--core/res/res/drawable-hdpi/status_bar_background.pngbin0 -> 839 bytes
-rw-r--r--core/res/res/drawable-hdpi/status_bar_close_on.9.pngbin0 -> 945 bytes
-rw-r--r--core/res/res/drawable-hdpi/status_bar_header_background.9.pngbin0 -> 187 bytes
-rw-r--r--core/res/res/drawable-hdpi/status_bar_item_app_background_normal.9.pngbin0 -> 322 bytes
-rw-r--r--core/res/res/drawable-hdpi/status_bar_item_background_focus.9.pngbin0 -> 1657 bytes
-rw-r--r--core/res/res/drawable-hdpi/status_bar_item_background_normal.9.pngbin0 -> 197 bytes
-rw-r--r--core/res/res/drawable-hdpi/status_bar_item_background_pressed.9.pngbin0 -> 1531 bytes
-rw-r--r--core/res/res/drawable-hdpi/statusbar_background.pngbin0 -> 743 bytes
-rw-r--r--core/res/res/drawable-hdpi/submenu_arrow_nofocus.pngbin0 -> 251 bytes
-rw-r--r--core/res/res/drawable-hdpi/sym_action_add.pngbin0 -> 1575 bytes
-rw-r--r--core/res/res/drawable-hdpi/sym_action_call.pngbin0 -> 1446 bytes
-rw-r--r--core/res/res/drawable-hdpi/sym_action_chat.pngbin0 -> 1277 bytes
-rw-r--r--core/res/res/drawable-hdpi/sym_action_email.pngbin0 -> 1462 bytes
-rw-r--r--core/res/res/drawable-hdpi/sym_call_incoming.pngbin0 -> 2046 bytes
-rw-r--r--core/res/res/drawable-hdpi/sym_call_missed.pngbin0 -> 1959 bytes
-rw-r--r--core/res/res/drawable-hdpi/sym_call_outgoing.pngbin0 -> 1949 bytes
-rw-r--r--core/res/res/drawable-hdpi/sym_contact_card.pngbin0 -> 498 bytes
-rw-r--r--core/res/res/drawable-hdpi/sym_def_app_icon.pngbin0 -> 5182 bytes
-rw-r--r--core/res/res/drawable-hdpi/tab_focus.9.pngbin0 -> 1989 bytes
-rw-r--r--core/res/res/drawable-hdpi/tab_focus_bar_left.9.pngbin0 -> 220 bytes
-rw-r--r--core/res/res/drawable-hdpi/tab_focus_bar_right.9.pngbin0 -> 216 bytes
-rw-r--r--core/res/res/drawable-hdpi/tab_press.9.pngbin0 -> 1977 bytes
-rw-r--r--core/res/res/drawable-hdpi/tab_press_bar_left.9.pngbin0 -> 220 bytes
-rw-r--r--core/res/res/drawable-hdpi/tab_press_bar_right.9.pngbin0 -> 216 bytes
-rw-r--r--core/res/res/drawable-hdpi/tab_selected.9.pngbin0 -> 924 bytes
-rw-r--r--core/res/res/drawable-hdpi/tab_selected_bar_left.9.pngbin0 -> 195 bytes
-rw-r--r--core/res/res/drawable-hdpi/tab_selected_bar_right.9.pngbin0 -> 194 bytes
-rw-r--r--core/res/res/drawable-hdpi/tab_unselected.9.pngbin0 -> 956 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_default.9.pngbin0 -> 997 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_disabled.9.pngbin0 -> 710 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_disabled_selected.9.pngbin0 -> 915 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_pressed.9.pngbin0 -> 1356 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_search_default.9.pngbin0 -> 790 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_search_pressed.9.pngbin0 -> 1311 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_search_selected.9.pngbin0 -> 873 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_selected.9.pngbin0 -> 1058 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_down_disabled.9.pngbin0 -> 554 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_down_disabled_focused.9.pngbin0 -> 786 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_down_normal.9.pngbin0 -> 1124 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_down_pressed.9.pngbin0 -> 1710 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_down_selected.9.pngbin0 -> 1738 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_input_disabled.9.pngbin0 -> 391 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_input_normal.9.pngbin0 -> 694 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_input_pressed.9.pngbin0 -> 970 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_input_selected.9.pngbin0 -> 662 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_up_disabled.9.pngbin0 -> 710 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_up_disabled_focused.9.pngbin0 -> 946 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_up_normal.9.pngbin0 -> 1388 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_up_pressed.9.pngbin0 -> 2068 bytes
-rw-r--r--core/res/res/drawable-hdpi/timepicker_up_selected.9.pngbin0 -> 2103 bytes
-rw-r--r--core/res/res/drawable-hdpi/title_bar_portrait.9.pngbin0 -> 355 bytes
-rw-r--r--core/res/res/drawable-hdpi/title_bar_shadow.9.pngbin0 -> 199 bytes
-rw-r--r--core/res/res/drawable-hdpi/title_bar_tall.pngbin0 -> 599 bytes
-rw-r--r--core/res/res/drawable-hdpi/toast_frame.9.pngbin0 -> 2461 bytes
-rw-r--r--core/res/res/drawable-hdpi/unknown_image.pngbin0 -> 148 bytes
-rw-r--r--core/res/res/drawable-hdpi/zoom_plate.9.pngbin0 -> 1662 bytes
-rw-r--r--core/res/res/drawable-land-hdpi/statusbar_background.pngbin0 -> 858 bytes
-rw-r--r--core/res/res/drawable-land-hdpi/title_bar_tall.pngbin0 -> 721 bytes
-rw-r--r--core/res/res/drawable-land-mdpi/statusbar_background.png (renamed from core/res/res/drawable-land/statusbar_background.png)bin4475 -> 4475 bytes
-rw-r--r--core/res/res/drawable-land-mdpi/title_bar_tall.png (renamed from core/res/res/drawable-land/title_bar_tall.png)bin18449 -> 18449 bytes
-rw-r--r--core/res/res/drawable-mdpi/activity_title_bar.9.png (renamed from core/res/res/drawable/activity_title_bar.9.png)bin205 -> 205 bytes
-rw-r--r--core/res/res/drawable-mdpi/arrow_down_float.png (renamed from core/res/res/drawable/arrow_down_float.png)bin3141 -> 3141 bytes
-rw-r--r--core/res/res/drawable-mdpi/arrow_up_float.png (renamed from core/res/res/drawable/arrow_up_float.png)bin3128 -> 3128 bytes
-rw-r--r--core/res/res/drawable-mdpi/battery_charge_background.png (renamed from core/res/res/drawable/battery_charge_background.png)bin4694 -> 4694 bytes
-rw-r--r--core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png (renamed from core/res/res/drawable/battery_charge_fill_empty.9.png)bin3384 -> 3384 bytes
-rw-r--r--core/res/res/drawable-mdpi/battery_charge_fill_full.9.png (renamed from core/res/res/drawable/battery_charge_fill_full.9.png)bin3409 -> 3409 bytes
-rw-r--r--core/res/res/drawable-mdpi/battery_charge_fill_warning.9.png (renamed from core/res/res/drawable/battery_charge_fill_warning.9.png)bin3427 -> 3427 bytes
-rw-r--r--core/res/res/drawable-mdpi/battery_low_battery.png (renamed from core/res/res/drawable/battery_low_battery.png)bin5306 -> 5306 bytes
-rw-r--r--core/res/res/drawable-mdpi/blank_tile.png (renamed from core/res/res/drawable/blank_tile.png)bin557 -> 557 bytes
-rw-r--r--core/res/res/drawable-mdpi/bottom_bar.png (renamed from core/res/res/drawable/bottom_bar.png)bin2426 -> 2426 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_check_buttonless_off.png (renamed from core/res/res/drawable/btn_check_buttonless_off.png)bin608 -> 608 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_check_buttonless_on.png (renamed from core/res/res/drawable/btn_check_buttonless_on.png)bin721 -> 721 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_label_background.9.png (renamed from core/res/res/drawable/btn_check_label_background.9.png)bin178 -> 178 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off.png (renamed from core/res/res/drawable/btn_check_off.png)bin1172 -> 1172 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_disable.png (renamed from core/res/res/drawable/btn_check_off_disable.png)bin903 -> 903 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_disable_focused.png (renamed from core/res/res/drawable/btn_check_off_disable_focused.png)bin1073 -> 1073 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_pressed.png (renamed from core/res/res/drawable/btn_check_off_pressed.png)bin1630 -> 1630 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_off_selected.png (renamed from core/res/res/drawable/btn_check_off_selected.png)bin1598 -> 1598 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on.png (renamed from core/res/res/drawable/btn_check_on.png)bin1390 -> 1390 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_disable.png (renamed from core/res/res/drawable/btn_check_on_disable.png)bin973 -> 973 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_disable_focused.png (renamed from core/res/res/drawable/btn_check_on_disable_focused.png)bin1138 -> 1138 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_pressed.png (renamed from core/res/res/drawable/btn_check_on_pressed.png)bin1680 -> 1680 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_on_selected.png (renamed from core/res/res/drawable/btn_check_on_selected.png)bin1661 -> 1661 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_circle_disable.png (renamed from core/res/res/drawable/btn_circle_disable.png)bin938 -> 938 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_circle_disable_focused.png (renamed from core/res/res/drawable/btn_circle_disable_focused.png)bin1436 -> 1436 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_circle_normal.png (renamed from core/res/res/drawable/btn_circle_normal.png)bin1249 -> 1249 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_circle_pressed.png (renamed from core/res/res/drawable/btn_circle_pressed.png)bin1613 -> 1613 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_circle_selected.png (renamed from core/res/res/drawable/btn_circle_selected.png)bin1645 -> 1645 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_close_normal.png (renamed from core/res/res/drawable/btn_close_normal.png)bin1213 -> 1213 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_close_pressed.png (renamed from core/res/res/drawable/btn_close_pressed.png)bin1585 -> 1585 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_code_lock_default.png (renamed from core/res/res/drawable/btn_code_lock_default.png)bin3943 -> 3943 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_code_lock_touched.png (renamed from core/res/res/drawable/btn_code_lock_touched.png)bin4506 -> 4506 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_default_normal.9.png (renamed from core/res/res/drawable/btn_default_normal.9.png)bin763 -> 763 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_default_normal_disable.9.png (renamed from core/res/res/drawable/btn_default_normal_disable.9.png)bin474 -> 474 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_default_normal_disable_focused.9.png (renamed from core/res/res/drawable/btn_default_normal_disable_focused.9.png)bin673 -> 673 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_default_pressed.9.png (renamed from core/res/res/drawable/btn_default_pressed.9.png)bin1083 -> 1083 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_default_selected.9.png (renamed from core/res/res/drawable/btn_default_selected.9.png)bin1099 -> 1099 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_default_small_normal.9.png (renamed from core/res/res/drawable/btn_default_small_normal.9.png)bin679 -> 679 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_default_small_normal_disable.9.png (renamed from core/res/res/drawable/btn_default_small_normal_disable.9.png)bin456 -> 456 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png (renamed from core/res/res/drawable/btn_default_small_normal_disable_focused.9.png)bin648 -> 648 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_default_small_pressed.9.png (renamed from core/res/res/drawable/btn_default_small_pressed.9.png)bin936 -> 936 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_default_small_selected.9.png (renamed from core/res/res/drawable/btn_default_small_selected.9.png)bin964 -> 964 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_dialog_disable.png (renamed from core/res/res/drawable/btn_dialog_disable.png)bin1477 -> 1477 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_dialog_normal.png (renamed from core/res/res/drawable/btn_dialog_normal.png)bin1263 -> 1263 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_dialog_pressed.png (renamed from core/res/res/drawable/btn_dialog_pressed.png)bin1496 -> 1496 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_dialog_selected.png (renamed from core/res/res/drawable/btn_dialog_selected.png)bin1522 -> 1522 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_dropdown_normal.9.png (renamed from core/res/res/drawable/btn_dropdown_normal.9.png)bin1290 -> 1290 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_dropdown_pressed.9.png (renamed from core/res/res/drawable/btn_dropdown_pressed.9.png)bin2025 -> 2025 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_dropdown_selected.9.png (renamed from core/res/res/drawable/btn_dropdown_selected.9.png)bin2014 -> 2014 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_erase_default.9.png (renamed from core/res/res/drawable/btn_erase_default.9.png)bin1468 -> 1468 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_erase_pressed.9.png (renamed from core/res/res/drawable/btn_erase_pressed.9.png)bin1313 -> 1313 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_erase_selected.9.png (renamed from core/res/res/drawable/btn_erase_selected.9.png)bin1184 -> 1184 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_global_search_normal.9.png (renamed from core/res/res/drawable/btn_global_search_normal.9.png)bin676 -> 676 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_keyboard_key_normal.9.png (renamed from core/res/res/drawable/btn_keyboard_key_normal.9.png)bin726 -> 726 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_keyboard_key_normal_off.9.png (renamed from core/res/res/drawable/btn_keyboard_key_normal_off.9.png)bin860 -> 860 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_keyboard_key_normal_on.9.png (renamed from core/res/res/drawable/btn_keyboard_key_normal_on.9.png)bin926 -> 926 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_keyboard_key_pressed.9.png (renamed from core/res/res/drawable/btn_keyboard_key_pressed.9.png)bin664 -> 664 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.png (renamed from core/res/res/drawable/btn_keyboard_key_pressed_off.9.png)bin836 -> 836 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.png (renamed from core/res/res/drawable/btn_keyboard_key_pressed_on.9.png)bin886 -> 886 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_media_player.9.png (renamed from core/res/res/drawable/btn_media_player.9.png)bin1677 -> 1677 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_media_player_disabled.9.png (renamed from core/res/res/drawable/btn_media_player_disabled.9.png)bin724 -> 724 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_media_player_disabled_selected.9.png (renamed from core/res/res/drawable/btn_media_player_disabled_selected.9.png)bin1040 -> 1040 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_media_player_pressed.9.png (renamed from core/res/res/drawable/btn_media_player_pressed.9.png)bin1222 -> 1222 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_media_player_selected.9.png (renamed from core/res/res/drawable/btn_media_player_selected.9.png)bin1481 -> 1481 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_minus_default.png (renamed from core/res/res/drawable/btn_minus_default.png)bin3366 -> 3366 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_minus_disable.png (renamed from core/res/res/drawable/btn_minus_disable.png)bin3564 -> 3564 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_minus_disable_focused.png (renamed from core/res/res/drawable/btn_minus_disable_focused.png)bin3914 -> 3914 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_minus_pressed.png (renamed from core/res/res/drawable/btn_minus_pressed.png)bin3592 -> 3592 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_minus_selected.png (renamed from core/res/res/drawable/btn_minus_selected.png)bin3561 -> 3561 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_plus_default.png (renamed from core/res/res/drawable/btn_plus_default.png)bin3353 -> 3353 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_plus_disable.png (renamed from core/res/res/drawable/btn_plus_disable.png)bin3669 -> 3669 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_plus_disable_focused.png (renamed from core/res/res/drawable/btn_plus_disable_focused.png)bin4031 -> 4031 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_plus_pressed.png (renamed from core/res/res/drawable/btn_plus_pressed.png)bin3721 -> 3721 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_plus_selected.png (renamed from core/res/res/drawable/btn_plus_selected.png)bin3674 -> 3674 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_label_background.9.png (renamed from core/res/res/drawable/btn_radio_label_background.9.png)bin178 -> 178 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_off.png (renamed from core/res/res/drawable/btn_radio_off.png)bin1542 -> 1542 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_off_pressed.png (renamed from core/res/res/drawable/btn_radio_off_pressed.png)bin1928 -> 1928 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_off_selected.png (renamed from core/res/res/drawable/btn_radio_off_selected.png)bin1954 -> 1954 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_on.png (renamed from core/res/res/drawable/btn_radio_on.png)bin1692 -> 1692 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_on_pressed.png (renamed from core/res/res/drawable/btn_radio_on_pressed.png)bin1997 -> 1997 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_radio_on_selected.png (renamed from core/res/res/drawable/btn_radio_on_selected.png)bin2009 -> 2009 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_rating_star_off_normal.png (renamed from core/res/res/drawable/btn_rating_star_off_normal.png)bin2760 -> 2760 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_rating_star_off_pressed.png (renamed from core/res/res/drawable/btn_rating_star_off_pressed.png)bin3613 -> 3613 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_rating_star_off_selected.png (renamed from core/res/res/drawable/btn_rating_star_off_selected.png)bin3622 -> 3622 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_rating_star_on_normal.png (renamed from core/res/res/drawable/btn_rating_star_on_normal.png)bin3290 -> 3290 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_rating_star_on_pressed.png (renamed from core/res/res/drawable/btn_rating_star_on_pressed.png)bin3756 -> 3756 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_rating_star_on_selected.png (renamed from core/res/res/drawable/btn_rating_star_on_selected.png)bin3768 -> 3768 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_search_dialog_default.9.png (renamed from core/res/res/drawable/btn_search_dialog_default.9.png)bin3207 -> 3207 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_search_dialog_pressed.9.png (renamed from core/res/res/drawable/btn_search_dialog_pressed.9.png)bin3597 -> 3597 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_search_dialog_selected.9.png (renamed from core/res/res/drawable/btn_search_dialog_selected.9.png)bin3596 -> 3596 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_search_dialog_voice_default.9.png (renamed from core/res/res/drawable/btn_search_dialog_voice_default.9.png)bin3371 -> 3371 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_search_dialog_voice_pressed.9.png (renamed from core/res/res/drawable/btn_search_dialog_voice_pressed.9.png)bin3722 -> 3722 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_search_dialog_voice_selected.9.png (renamed from core/res/res/drawable/btn_search_dialog_voice_selected.9.png)bin3690 -> 3690 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_square_overlay_disabled.png (renamed from core/res/res/drawable/btn_square_overlay_disabled.png)bin653 -> 653 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_square_overlay_disabled_focused.png (renamed from core/res/res/drawable/btn_square_overlay_disabled_focused.png)bin826 -> 826 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_square_overlay_normal.png (renamed from core/res/res/drawable/btn_square_overlay_normal.png)bin910 -> 910 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_square_overlay_pressed.png (renamed from core/res/res/drawable/btn_square_overlay_pressed.png)bin1201 -> 1201 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_square_overlay_selected.png (renamed from core/res/res/drawable/btn_square_overlay_selected.png)bin1237 -> 1237 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_star_big_off.png (renamed from core/res/res/drawable/btn_star_big_off.png)bin1316 -> 1316 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_star_big_off_disable.png (renamed from core/res/res/drawable/btn_star_big_off_disable.png)bin1886 -> 1886 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_star_big_off_disable_focused.png (renamed from core/res/res/drawable/btn_star_big_off_disable_focused.png)bin1868 -> 1868 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_star_big_off_pressed.png (renamed from core/res/res/drawable/btn_star_big_off_pressed.png)bin1507 -> 1507 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_star_big_off_selected.png (renamed from core/res/res/drawable/btn_star_big_off_selected.png)bin1471 -> 1471 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_star_big_on.png (renamed from core/res/res/drawable/btn_star_big_on.png)bin1521 -> 1521 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_star_big_on_disable.png (renamed from core/res/res/drawable/btn_star_big_on_disable.png)bin4522 -> 4522 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_star_big_on_disable_focused.png (renamed from core/res/res/drawable/btn_star_big_on_disable_focused.png)bin1911 -> 1911 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_star_big_on_pressed.png (renamed from core/res/res/drawable/btn_star_big_on_pressed.png)bin1540 -> 1540 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/btn_star_big_on_selected.png (renamed from core/res/res/drawable/btn_star_big_on_selected.png)bin1456 -> 1456 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_star_label_background.9.png (renamed from core/res/res/drawable/btn_star_label_background.9.png)bin153 -> 153 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_toggle_off.9.png (renamed from core/res/res/drawable/btn_toggle_off.9.png)bin364 -> 364 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_toggle_on.9.png (renamed from core/res/res/drawable/btn_toggle_on.9.png)bin442 -> 442 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_down_disabled.9.png (renamed from core/res/res/drawable/btn_zoom_down_disabled.9.png)bin1455 -> 1455 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_down_disabled_focused.9.png (renamed from core/res/res/drawable/btn_zoom_down_disabled_focused.9.png)bin1804 -> 1804 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_down_normal.9.png (renamed from core/res/res/drawable/btn_zoom_down_normal.9.png)bin1983 -> 1983 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_down_pressed.9.png (renamed from core/res/res/drawable/btn_zoom_down_pressed.9.png)bin2522 -> 2522 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_down_selected.9.png (renamed from core/res/res/drawable/btn_zoom_down_selected.9.png)bin2532 -> 2532 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_page_normal.png (renamed from core/res/res/drawable/btn_zoom_page_normal.png)bin1991 -> 1991 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_page_press.png (renamed from core/res/res/drawable/btn_zoom_page_press.png)bin2075 -> 2075 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_up_disabled.9.png (renamed from core/res/res/drawable/btn_zoom_up_disabled.9.png)bin1445 -> 1445 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_up_disabled_focused.9.png (renamed from core/res/res/drawable/btn_zoom_up_disabled_focused.9.png)bin1798 -> 1798 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_up_normal.9.png (renamed from core/res/res/drawable/btn_zoom_up_normal.9.png)bin1962 -> 1962 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_up_pressed.9.png (renamed from core/res/res/drawable/btn_zoom_up_pressed.9.png)bin2547 -> 2547 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_zoom_up_selected.9.png (renamed from core/res/res/drawable/btn_zoom_up_selected.9.png)bin2540 -> 2540 bytes
-rw-r--r--core/res/res/drawable-mdpi/button_onoff_indicator_off.png (renamed from core/res/res/drawable/button_onoff_indicator_off.png)bin298 -> 298 bytes
-rw-r--r--core/res/res/drawable-mdpi/button_onoff_indicator_on.png (renamed from core/res/res/drawable/button_onoff_indicator_on.png)bin380 -> 380 bytes
-rw-r--r--core/res/res/drawable-mdpi/call_contact.png (renamed from core/res/res/drawable/call_contact.png)bin1025 -> 1025 bytes
-rw-r--r--core/res/res/drawable-mdpi/checkbox_off_background.png (renamed from core/res/res/drawable/checkbox_off_background.png)bin3106 -> 3106 bytes
-rw-r--r--core/res/res/drawable-mdpi/checkbox_on_background.png (renamed from core/res/res/drawable/checkbox_on_background.png)bin3354 -> 3354 bytes
-rw-r--r--core/res/res/drawable-mdpi/clock_dial.png (renamed from core/res/res/drawable/clock_dial.png)bin7384 -> 7384 bytes
-rw-r--r--core/res/res/drawable-mdpi/clock_hand_hour.png (renamed from core/res/res/drawable/clock_hand_hour.png)bin1412 -> 1412 bytes
-rw-r--r--core/res/res/drawable-mdpi/clock_hand_minute.png (renamed from core/res/res/drawable/clock_hand_minute.png)bin1550 -> 1550 bytes
-rw-r--r--core/res/res/drawable-mdpi/code_lock_bottom.9.png (renamed from core/res/res/drawable/code_lock_bottom.9.png)bin158 -> 158 bytes
-rw-r--r--core/res/res/drawable-mdpi/code_lock_left.9.png (renamed from core/res/res/drawable/code_lock_left.9.png)bin131 -> 131 bytes
-rw-r--r--core/res/res/drawable-mdpi/code_lock_top.9.png (renamed from core/res/res/drawable/code_lock_top.9.png)bin124 -> 124 bytes
-rw-r--r--core/res/res/drawable-mdpi/compass_arrow.png (renamed from core/res/res/drawable/compass_arrow.png)bin732 -> 732 bytes
-rw-r--r--core/res/res/drawable-mdpi/compass_base.png (renamed from core/res/res/drawable/compass_base.png)bin2508 -> 2508 bytes
-rw-r--r--core/res/res/drawable-mdpi/create_contact.png (renamed from core/res/res/drawable/create_contact.png)bin1132 -> 1132 bytes
-rw-r--r--core/res/res/drawable-mdpi/dark_header.9.pngbin0 -> 161 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/dialog_divider_horizontal_light.9.png (renamed from core/res/res/drawable/dialog_divider_horizontal_light.9.png)bin2921 -> 2921 bytes
-rw-r--r--core/res/res/drawable-mdpi/divider_horizontal_bright.9.pngbin0 -> 119 bytes
-rw-r--r--core/res/res/drawable-mdpi/divider_horizontal_bright_opaque.9.pngbin0 -> 120 bytes
-rw-r--r--core/res/res/drawable-mdpi/divider_horizontal_dark.9.pngbin0 -> 121 bytes
-rw-r--r--core/res/res/drawable-mdpi/divider_horizontal_dark_opaque.9.pngbin0 -> 120 bytes
-rw-r--r--core/res/res/drawable-mdpi/divider_horizontal_dim_dark.9.png (renamed from core/res/res/drawable/divider_horizontal_dim_dark.9.png)bin232 -> 232 bytes
-rw-r--r--core/res/res/drawable-mdpi/divider_horizontal_textfield.9.png (renamed from core/res/res/drawable/divider_horizontal_textfield.9.png)bin137 -> 137 bytes
-rw-r--r--core/res/res/drawable-mdpi/divider_vertical_bright.9.pngbin0 -> 119 bytes
-rw-r--r--core/res/res/drawable-mdpi/editbox_background_focus_yellow.9.png (renamed from core/res/res/drawable/editbox_background_focus_yellow.9.png)bin3425 -> 3425 bytes
-rw-r--r--core/res/res/drawable-mdpi/editbox_background_normal.9.png (renamed from core/res/res/drawable/editbox_background_normal.9.png)bin3130 -> 3130 bytes
-rw-r--r--core/res/res/drawable-mdpi/editbox_dropdown_background.9.png (renamed from core/res/res/drawable/editbox_dropdown_background.9.png)bin3229 -> 3229 bytes
-rw-r--r--core/res/res/drawable-mdpi/editbox_dropdown_background_dark.9.png (renamed from core/res/res/drawable/editbox_dropdown_background_dark.9.png)bin367 -> 367 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_angel.png (renamed from core/res/res/drawable/emo_im_angel.png)bin3592 -> 3592 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_cool.png (renamed from core/res/res/drawable/emo_im_cool.png)bin3466 -> 3466 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_crying.png (renamed from core/res/res/drawable/emo_im_crying.png)bin3558 -> 3558 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_foot_in_mouth.png (renamed from core/res/res/drawable/emo_im_foot_in_mouth.png)bin3603 -> 3603 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_happy.png (renamed from core/res/res/drawable/emo_im_happy.png)bin3591 -> 3591 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_kissing.png (renamed from core/res/res/drawable/emo_im_kissing.png)bin3492 -> 3492 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_laughing.png (renamed from core/res/res/drawable/emo_im_laughing.png)bin3624 -> 3624 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_lips_are_sealed.png (renamed from core/res/res/drawable/emo_im_lips_are_sealed.png)bin3670 -> 3670 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_money_mouth.png (renamed from core/res/res/drawable/emo_im_money_mouth.png)bin3649 -> 3649 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_sad.png (renamed from core/res/res/drawable/emo_im_sad.png)bin3572 -> 3572 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_surprised.png (renamed from core/res/res/drawable/emo_im_surprised.png)bin3490 -> 3490 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_tongue_sticking_out.png (renamed from core/res/res/drawable/emo_im_tongue_sticking_out.png)bin3653 -> 3653 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_undecided.png (renamed from core/res/res/drawable/emo_im_undecided.png)bin3552 -> 3552 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_winking.png (renamed from core/res/res/drawable/emo_im_winking.png)bin3568 -> 3568 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_wtf.png (renamed from core/res/res/drawable/emo_im_wtf.png)bin3591 -> 3591 bytes
-rw-r--r--core/res/res/drawable-mdpi/emo_im_yelling.png (renamed from core/res/res/drawable/emo_im_yelling.png)bin3575 -> 3575 bytes
-rw-r--r--core/res/res/drawable-mdpi/expander_ic_maximized.9.png (renamed from core/res/res/drawable/expander_ic_maximized.9.png)bin1150 -> 1150 bytes
-rw-r--r--core/res/res/drawable-mdpi/expander_ic_minimized.9.png (renamed from core/res/res/drawable/expander_ic_minimized.9.png)bin1167 -> 1167 bytes
-rw-r--r--core/res/res/drawable-mdpi/focused_application_background_static.png (renamed from core/res/res/drawable/focused_application_background_static.png)bin3928 -> 3928 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/frame_gallery_thumb.9.png (renamed from core/res/res/drawable/frame_gallery_thumb.9.png)bin925 -> 925 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/frame_gallery_thumb_pressed.9.png (renamed from core/res/res/drawable/frame_gallery_thumb_pressed.9.png)bin1704 -> 1704 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/frame_gallery_thumb_selected.9.png (renamed from core/res/res/drawable/frame_gallery_thumb_selected.9.png)bin621 -> 621 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/gallery_selected_default.9.png (renamed from core/res/res/drawable/gallery_selected_default.9.png)bin1088 -> 1088 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/gallery_selected_focused.9.png (renamed from core/res/res/drawable/gallery_selected_focused.9.png)bin1313 -> 1313 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/gallery_selected_pressed.9.png (renamed from core/res/res/drawable/gallery_selected_pressed.9.png)bin1317 -> 1317 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/gallery_unselected_default.9.png (renamed from core/res/res/drawable/gallery_unselected_default.9.png)bin560 -> 560 bytes
-rw-r--r--core/res/res/drawable-mdpi/gallery_unselected_pressed.9.png (renamed from core/res/res/drawable/gallery_unselected_pressed.9.png)bin686 -> 686 bytes
-rw-r--r--core/res/res/drawable-mdpi/grid_selector_background_focus.9.png (renamed from core/res/res/drawable/grid_selector_background_focus.9.png)bin985 -> 985 bytes
-rw-r--r--core/res/res/drawable-mdpi/grid_selector_background_pressed.9.png (renamed from core/res/res/drawable/grid_selector_background_pressed.9.png)bin920 -> 920 bytes
-rw-r--r--core/res/res/drawable-mdpi/highlight_disabled.9.png (renamed from core/res/res/drawable/highlight_disabled.9.png)bin1291 -> 1291 bytes
-rw-r--r--core/res/res/drawable-mdpi/highlight_pressed.9.png (renamed from core/res/res/drawable/highlight_pressed.9.png)bin1103 -> 1103 bytes
-rw-r--r--core/res/res/drawable-mdpi/highlight_selected.9.png (renamed from core/res/res/drawable/highlight_selected.9.png)bin1145 -> 1145 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_btn_round_more_disabled.png (renamed from core/res/res/drawable/ic_btn_round_more_disabled.png)bin421 -> 421 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_btn_round_more_normal.png (renamed from core/res/res/drawable/ic_btn_round_more_normal.png)bin968 -> 968 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_btn_search.png (renamed from core/res/res/drawable/ic_btn_search.png)bin1390 -> 1390 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_btn_speak_now.png (renamed from core/res/res/drawable/ic_btn_speak_now.png)bin954 -> 954 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_fit_page_disabled.png (renamed from core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_disabled.png)bin456 -> 456 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_fit_page_normal.png (renamed from core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_normal.png)bin820 -> 820 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_page_overview_disabled.png (renamed from core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_disabled.png)bin461 -> 461 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_page_overview_normal.png (renamed from core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_normal.png)bin839 -> 839 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_bullet_key_permission.png (renamed from core/res/res/drawable/ic_bullet_key_permission.png)bin597 -> 597 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_contact_picture.png (renamed from core/res/res/drawable/ic_contact_picture.png)bin1719 -> 1719 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_delete.png (renamed from core/res/res/drawable/ic_delete.png)bin3440 -> 3440 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_dialog_alert.png (renamed from core/res/res/drawable/ic_dialog_alert.png)bin3645 -> 3645 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_dialog_dialer.png (renamed from core/res/res/drawable/ic_dialog_dialer.png)bin3529 -> 3529 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_dialog_email.png (renamed from core/res/res/drawable/ic_dialog_email.png)bin3726 -> 3726 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_dialog_info.png (renamed from core/res/res/drawable/ic_dialog_info.png)bin3593 -> 3593 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_dialog_map.png (renamed from core/res/res/drawable/ic_dialog_map.png)bin3862 -> 3862 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_dialog_menu_generic.png (renamed from core/res/res/drawable/ic_dialog_menu_generic.png)bin1187 -> 1187 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_dialog_time.png (renamed from core/res/res/drawable/ic_dialog_time.png)bin1490 -> 1490 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_dialog_usb.png (renamed from core/res/res/drawable/ic_dialog_usb.png)bin938 -> 938 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_emergency.png (renamed from core/res/res/drawable/ic_emergency.png)bin605 -> 605 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_input_add.png (renamed from core/res/res/drawable/ic_input_add.png)bin3180 -> 3180 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_input_delete.png (renamed from core/res/res/drawable/ic_input_delete.png)bin3769 -> 3769 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_input_get.png (renamed from core/res/res/drawable/ic_input_get.png)bin995 -> 995 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_launcher_android.png (renamed from core/res/res/drawable/ic_launcher_android.png)bin3019 -> 3019 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_lock_airplane_mode.png (renamed from core/res/res/drawable/ic_lock_airplane_mode.png)bin1119 -> 1119 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_lock_airplane_mode_off.png (renamed from core/res/res/drawable/ic_lock_airplane_mode_off.png)bin1570 -> 1570 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_idle_alarm.png (renamed from core/res/res/drawable/ic_lock_idle_alarm.png)bin640 -> 640 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_lock_idle_charging.png (renamed from core/res/res/drawable/ic_lock_idle_charging.png)bin599 -> 599 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_lock_idle_lock.png (renamed from core/res/res/drawable/ic_lock_idle_lock.png)bin547 -> 547 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_lock_idle_low_battery.png (renamed from core/res/res/drawable/ic_lock_idle_low_battery.png)bin665 -> 665 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_lock.png (renamed from core/res/res/drawable/ic_lock_lock.png)bin1303 -> 1303 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_power_off.png (renamed from core/res/res/drawable/ic_lock_power_off.png)bin1709 -> 1709 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_silent_mode.png (renamed from core/res/res/drawable/ic_lock_silent_mode.png)bin1362 -> 1362 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_silent_mode_off.png (renamed from core/res/res/drawable/ic_lock_silent_mode_off.png)bin1554 -> 1554 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_maps_indicator_current_position.png (renamed from core/res/res/drawable/ic_maps_indicator_current_position.png)bin1205 -> 1205 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_maps_indicator_current_position_anim1.png (renamed from core/res/res/drawable/ic_maps_indicator_current_position_anim1.png)bin1301 -> 1301 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_maps_indicator_current_position_anim2.png (renamed from core/res/res/drawable/ic_maps_indicator_current_position_anim2.png)bin1300 -> 1300 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_maps_indicator_current_position_anim3.png (renamed from core/res/res/drawable/ic_maps_indicator_current_position_anim3.png)bin1201 -> 1201 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_media_ff.png (renamed from core/res/res/drawable/ic_media_ff.png)bin1159 -> 1159 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_media_next.png (renamed from core/res/res/drawable/ic_media_next.png)bin1309 -> 1309 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_media_pause.png (renamed from core/res/res/drawable/ic_media_pause.png)bin512 -> 512 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_media_play.png (renamed from core/res/res/drawable/ic_media_play.png)bin919 -> 919 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_media_previous.png (renamed from core/res/res/drawable/ic_media_previous.png)bin1295 -> 1295 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_media_rew.png (renamed from core/res/res/drawable/ic_media_rew.png)bin1192 -> 1192 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_account_list.png (renamed from core/res/res/drawable/ic_menu_account_list.png)bin2394 -> 2394 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_add.png (renamed from core/res/res/drawable/ic_menu_add.png)bin2017 -> 2017 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_agenda.png (renamed from core/res/res/drawable/ic_menu_agenda.png)bin4805 -> 4805 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_allfriends.png (renamed from core/res/res/drawable/ic_menu_allfriends.png)bin2257 -> 2257 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_always_landscape_portrait.png (renamed from core/res/res/drawable/ic_menu_always_landscape_portrait.png)bin1658 -> 1658 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_archive.png (renamed from core/res/res/drawable/ic_menu_archive.png)bin1354 -> 1354 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_attachment.png (renamed from core/res/res/drawable/ic_menu_attachment.png)bin2247 -> 2247 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_back.png (renamed from core/res/res/drawable/ic_menu_back.png)bin1237 -> 1237 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_block.png (renamed from core/res/res/drawable/ic_menu_block.png)bin2336 -> 2336 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_blocked_user.png (renamed from core/res/res/drawable/ic_menu_blocked_user.png)bin2408 -> 2408 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_call.png (renamed from core/res/res/drawable/ic_menu_call.png)bin1755 -> 1755 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_camera.png (renamed from core/res/res/drawable/ic_menu_camera.png)bin1971 -> 1971 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_cc.png (renamed from core/res/res/drawable/ic_menu_cc.png)bin2046 -> 2046 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_chat_dashboard.png (renamed from core/res/res/drawable/ic_menu_chat_dashboard.png)bin1865 -> 1865 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_clear_playlist.png (renamed from core/res/res/drawable/ic_menu_clear_playlist.png)bin2281 -> 2281 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_close_clear_cancel.png (renamed from core/res/res/drawable/ic_menu_close_clear_cancel.png)bin5306 -> 5306 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_compass.png (renamed from core/res/res/drawable/ic_menu_compass.png)bin3943 -> 3943 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_compose.png (renamed from core/res/res/drawable/ic_menu_compose.png)bin2014 -> 2014 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_crop.png (renamed from core/res/res/drawable/ic_menu_crop.png)bin1743 -> 1743 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_day.png (renamed from core/res/res/drawable/ic_menu_day.png)bin3924 -> 3924 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_delete.png (renamed from core/res/res/drawable/ic_menu_delete.png)bin1747 -> 1747 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_directions.png (renamed from core/res/res/drawable/ic_menu_directions.png)bin4383 -> 4383 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_edit.png (renamed from core/res/res/drawable/ic_menu_edit.png)bin1661 -> 1661 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_emoticons.png (renamed from core/res/res/drawable/ic_menu_emoticons.png)bin2620 -> 2620 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_end_conversation.png (renamed from core/res/res/drawable/ic_menu_end_conversation.png)bin1932 -> 1932 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_forward.png (renamed from core/res/res/drawable/ic_menu_forward.png)bin1228 -> 1228 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_friendslist.png (renamed from core/res/res/drawable/ic_menu_friendslist.png)bin1561 -> 1561 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_gallery.png (renamed from core/res/res/drawable/ic_menu_gallery.png)bin2379 -> 2379 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_goto.png (renamed from core/res/res/drawable/ic_menu_goto.png)bin1636 -> 1636 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_help.png (renamed from core/res/res/drawable/ic_menu_help.png)bin5304 -> 5304 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_home.png (renamed from core/res/res/drawable/ic_menu_home.png)bin2048 -> 2048 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_info_details.png (renamed from core/res/res/drawable/ic_menu_info_details.png)bin2128 -> 2128 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_invite.png (renamed from core/res/res/drawable/ic_menu_invite.png)bin2349 -> 2349 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_login.png (renamed from core/res/res/drawable/ic_menu_login.png)bin2466 -> 2466 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_manage.png (renamed from core/res/res/drawable/ic_menu_manage.png)bin5082 -> 5082 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_mapmode.png (renamed from core/res/res/drawable/ic_menu_mapmode.png)bin1923 -> 1923 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_mark.png (renamed from core/res/res/drawable/ic_menu_mark.png)bin2519 -> 2519 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_month.png (renamed from core/res/res/drawable/ic_menu_month.png)bin5123 -> 5123 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_more.png (renamed from core/res/res/drawable/ic_menu_more.png)bin5223 -> 5223 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_my_calendar.png (renamed from core/res/res/drawable/ic_menu_my_calendar.png)bin4469 -> 4469 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_mylocation.png (renamed from core/res/res/drawable/ic_menu_mylocation.png)bin5307 -> 5307 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_myplaces.png (renamed from core/res/res/drawable/ic_menu_myplaces.png)bin2011 -> 2011 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_notifications.png (renamed from core/res/res/drawable/ic_menu_notifications.png)bin1771 -> 1771 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_play_clip.png (renamed from core/res/res/drawable/ic_menu_play_clip.png)bin1471 -> 1471 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_preferences.png (renamed from core/res/res/drawable/ic_menu_preferences.png)bin2144 -> 2144 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_recent_history.png (renamed from core/res/res/drawable/ic_menu_recent_history.png)bin2647 -> 2647 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_refresh.png (renamed from core/res/res/drawable/ic_menu_refresh.png)bin2450 -> 2450 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_report_image.png (renamed from core/res/res/drawable/ic_menu_report_image.png)bin1996 -> 1996 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_revert.png (renamed from core/res/res/drawable/ic_menu_revert.png)bin1731 -> 1731 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_rotate.png (renamed from core/res/res/drawable/ic_menu_rotate.png)bin2477 -> 2477 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_save.png (renamed from core/res/res/drawable/ic_menu_save.png)bin1645 -> 1645 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_search.png (renamed from core/res/res/drawable/ic_menu_search.png)bin5059 -> 5059 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_send.png (renamed from core/res/res/drawable/ic_menu_send.png)bin1966 -> 1966 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_set_as.png (renamed from core/res/res/drawable/ic_menu_set_as.png)bin1828 -> 1828 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_share.png (renamed from core/res/res/drawable/ic_menu_share.png)bin2194 -> 2194 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_slideshow.png (renamed from core/res/res/drawable/ic_menu_slideshow.png)bin2392 -> 2392 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_sort_alphabetically.png (renamed from core/res/res/drawable/ic_menu_sort_alphabetically.png)bin2077 -> 2077 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_sort_by_size.png (renamed from core/res/res/drawable/ic_menu_sort_by_size.png)bin1067 -> 1067 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_star.png (renamed from core/res/res/drawable/ic_menu_star.png)bin1608 -> 1608 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_start_conversation.png (renamed from core/res/res/drawable/ic_menu_start_conversation.png)bin1715 -> 1715 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_stop.png (renamed from core/res/res/drawable/ic_menu_stop.png)bin1930 -> 1930 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_today.png (renamed from core/res/res/drawable/ic_menu_today.png)bin4450 -> 4450 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_upload.png (renamed from core/res/res/drawable/ic_menu_upload.png)bin1571 -> 1571 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_upload_you_tube.png (renamed from core/res/res/drawable/ic_menu_upload_you_tube.png)bin2384 -> 2384 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_view.png (renamed from core/res/res/drawable/ic_menu_view.png)bin1929 -> 1929 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_menu_week.png (renamed from core/res/res/drawable/ic_menu_week.png)bin4202 -> 4202 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_menu_zoom.png (renamed from core/res/res/drawable/ic_menu_zoom.png)bin2290 -> 2290 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_notification_clear_all.png (renamed from core/res/res/drawable/ic_notification_clear_all.png)bin1558 -> 1558 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_notification_overlay.9.png (renamed from core/res/res/drawable/ic_notification_overlay.9.png)bin3201 -> 3201 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_partial_secure.png (renamed from core/res/res/drawable/ic_partial_secure.png)bin315 -> 315 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_popup_disk_full.png (renamed from core/res/res/drawable/ic_popup_disk_full.png)bin4135 -> 4135 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_popup_reminder.png (renamed from core/res/res/drawable/ic_popup_reminder.png)bin1288 -> 1288 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_popup_sync_1.png (renamed from core/res/res/drawable/ic_popup_sync_1.png)bin4001 -> 4001 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_popup_sync_2.png (renamed from core/res/res/drawable/ic_popup_sync_2.png)bin4065 -> 4065 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_popup_sync_3.png (renamed from core/res/res/drawable/ic_popup_sync_3.png)bin4029 -> 4029 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_popup_sync_4.png (renamed from core/res/res/drawable/ic_popup_sync_4.png)bin4019 -> 4019 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_popup_sync_5.png (renamed from core/res/res/drawable/ic_popup_sync_5.png)bin4144 -> 4144 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_popup_sync_6.png (renamed from core/res/res/drawable/ic_popup_sync_6.png)bin3956 -> 3956 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_search_category_default.png (renamed from core/res/res/drawable/ic_search_category_default.png)bin1747 -> 1747 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_secure.png (renamed from core/res/res/drawable/ic_secure.png)bin398 -> 398 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_text_dot.png (renamed from core/res/res/drawable/ic_text_dot.png)bin476 -> 476 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_vibrate.png (renamed from core/res/res/drawable/ic_vibrate.png)bin4103 -> 4103 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_volume.png (renamed from core/res/res/drawable/ic_volume.png)bin2669 -> 2669 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_volume_bluetooth_ad2p.png (renamed from core/res/res/drawable/ic_volume_bluetooth_ad2p.png)bin2996 -> 2996 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_volume_bluetooth_in_call.png (renamed from core/res/res/drawable/ic_volume_bluetooth_in_call.png)bin2172 -> 2172 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_volume_off.png (renamed from core/res/res/drawable/ic_volume_off.png)bin2462 -> 2462 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_volume_off_small.png (renamed from core/res/res/drawable/ic_volume_off_small.png)bin832 -> 832 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/ic_volume_small.png (renamed from core/res/res/drawable/ic_volume_small.png)bin866 -> 866 bytes
-rw-r--r--core/res/res/drawable-mdpi/icon_highlight_rectangle.9.png (renamed from core/res/res/drawable/icon_highlight_rectangle.9.png)bin1022 -> 1022 bytes
-rw-r--r--core/res/res/drawable-mdpi/icon_highlight_square.9.png (renamed from core/res/res/drawable/icon_highlight_square.9.png)bin1408 -> 1408 bytes
-rw-r--r--core/res/res/drawable-mdpi/ime_qwerty.png (renamed from core/res/res/drawable/ime_qwerty.png)bin3052 -> 3052 bytes
-rw-r--r--core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up.png (renamed from core/res/res/drawable/indicator_code_lock_drag_direction_green_up.png)bin268 -> 268 bytes
-rw-r--r--core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up.png (renamed from core/res/res/drawable/indicator_code_lock_drag_direction_red_up.png)bin315 -> 315 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/indicator_code_lock_point_area_default.png (renamed from core/res/res/drawable/indicator_code_lock_point_area_default.png)bin3939 -> 3939 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/indicator_code_lock_point_area_green.png (renamed from core/res/res/drawable/indicator_code_lock_point_area_green.png)bin4201 -> 4201 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/indicator_code_lock_point_area_red.png (renamed from core/res/res/drawable/indicator_code_lock_point_area_red.png)bin4462 -> 4462 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/indicator_input_error.png (renamed from core/res/res/drawable/indicator_input_error.png)bin884 -> 884 bytes
-rw-r--r--core/res/res/drawable-mdpi/keyboard_accessory_bg_landscape.9.png (renamed from core/res/res/drawable/keyboard_accessory_bg_landscape.9.png)bin197 -> 197 bytes
-rw-r--r--core/res/res/drawable-mdpi/keyboard_background.9.png (renamed from core/res/res/drawable/keyboard_background.9.png)bin189 -> 189 bytes
-rw-r--r--core/res/res/drawable-mdpi/keyboard_key_feedback_background.9.png (renamed from core/res/res/drawable/keyboard_key_feedback_background.9.png)bin1182 -> 1182 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/keyboard_key_feedback_more_background.9.png (renamed from core/res/res/drawable/keyboard_key_feedback_more_background.9.png)bin1385 -> 1385 bytes
-rw-r--r--core/res/res/drawable-mdpi/keyboard_popup_panel_background.9.png (renamed from core/res/res/drawable/keyboard_popup_panel_background.9.png)bin996 -> 996 bytes
-rw-r--r--core/res/res/drawable-mdpi/keyboard_textfield_selected.9.png (renamed from core/res/res/drawable/keyboard_textfield_selected.9.png)bin782 -> 782 bytes
-rw-r--r--core/res/res/drawable-mdpi/light_header.9.pngbin0 -> 162 bytes
-rw-r--r--core/res/res/drawable-mdpi/list_selector_background_disabled.9.png (renamed from core/res/res/drawable/list_selector_background_disabled.9.png)bin1252 -> 1252 bytes
-rw-r--r--core/res/res/drawable-mdpi/list_selector_background_focus.9.png (renamed from core/res/res/drawable/list_selector_background_focus.9.png)bin11006 -> 11006 bytes
-rw-r--r--core/res/res/drawable-mdpi/list_selector_background_longpress.9.png (renamed from core/res/res/drawable/list_selector_background_longpress.9.png)bin3017 -> 3017 bytes
-rw-r--r--core/res/res/drawable-mdpi/list_selector_background_pressed.9.png (renamed from core/res/res/drawable/list_selector_background_pressed.9.png)bin11006 -> 11006 bytes
-rw-r--r--core/res/res/drawable-mdpi/loading_tile.png (renamed from core/res/res/drawable/loading_tile.png)bin729 -> 729 bytes
-rw-r--r--core/res/res/drawable-mdpi/maps_google_logo.png (renamed from core/res/res/drawable/maps_google_logo.png)bin2776 -> 2776 bytes
-rw-r--r--core/res/res/drawable-mdpi/menu_background.9.png (renamed from core/res/res/drawable/menu_background.9.png)bin3390 -> 3390 bytes
-rw-r--r--core/res/res/drawable-mdpi/menu_background_fill_parent_width.9.png (renamed from core/res/res/drawable/menu_background_fill_parent_width.9.png)bin2969 -> 2969 bytes
-rw-r--r--core/res/res/drawable-mdpi/menu_separator.9.png (renamed from core/res/res/drawable/menu_separator.9.png)bin2823 -> 2823 bytes
-rw-r--r--core/res/res/drawable-mdpi/menu_submenu_background.9.png (renamed from core/res/res/drawable/menu_submenu_background.9.png)bin4394 -> 4394 bytes
-rw-r--r--core/res/res/drawable-mdpi/menuitem_background_focus.9.png (renamed from core/res/res/drawable/menuitem_background_focus.9.png)bin11006 -> 11006 bytes
-rw-r--r--core/res/res/drawable-mdpi/menuitem_background_pressed.9.png (renamed from core/res/res/drawable/menuitem_background_pressed.9.png)bin11006 -> 11006 bytes
-rw-r--r--core/res/res/drawable-mdpi/menuitem_background_solid_focused.9.pngbin0 -> 165 bytes
-rw-r--r--core/res/res/drawable-mdpi/menuitem_background_solid_pressed.9.pngbin0 -> 165 bytes
-rw-r--r--core/res/res/drawable-mdpi/menuitem_checkbox_on.png (renamed from core/res/res/drawable/menuitem_checkbox_on.png)bin2920 -> 2920 bytes
-rw-r--r--core/res/res/drawable-mdpi/no_tile_128.png (renamed from core/res/res/drawable/no_tile_128.png)bin1392 -> 1392 bytes
-rw-r--r--core/res/res/drawable-mdpi/panel_background.9.png (renamed from core/res/res/drawable/panel_background.9.png)bin1332 -> 1332 bytes
-rw-r--r--core/res/res/drawable-mdpi/panel_picture_frame_bg_focus_blue.9.png (renamed from core/res/res/drawable/panel_picture_frame_bg_focus_blue.9.png)bin5311 -> 5311 bytes
-rw-r--r--core/res/res/drawable-mdpi/panel_picture_frame_bg_normal.9.png (renamed from core/res/res/drawable/panel_picture_frame_bg_normal.9.png)bin3532 -> 3532 bytes
-rw-r--r--core/res/res/drawable-mdpi/panel_picture_frame_bg_pressed_blue.9.png (renamed from core/res/res/drawable/panel_picture_frame_bg_pressed_blue.9.png)bin5111 -> 5111 bytes
-rw-r--r--core/res/res/drawable-mdpi/pickerbox_background.png (renamed from core/res/res/drawable/pickerbox_background.png)bin4226 -> 4226 bytes
-rw-r--r--core/res/res/drawable-mdpi/pickerbox_selected.9.png (renamed from core/res/res/drawable/pickerbox_selected.9.png)bin2155 -> 2155 bytes
-rw-r--r--core/res/res/drawable-mdpi/pickerbox_unselected.9.png (renamed from core/res/res/drawable/pickerbox_unselected.9.png)bin1474 -> 1474 bytes
-rw-r--r--core/res/res/drawable-mdpi/picture_emergency.png (renamed from core/res/res/drawable/picture_emergency.png)bin8339 -> 8339 bytes
-rw-r--r--core/res/res/drawable-mdpi/picture_frame.9.png (renamed from core/res/res/drawable/picture_frame.9.png)bin547 -> 547 bytes
-rw-r--r--core/res/res/drawable-mdpi/popup_bottom_bright.9.png (renamed from core/res/res/drawable/popup_bottom_bright.9.png)bin881 -> 881 bytes
-rw-r--r--core/res/res/drawable-mdpi/popup_bottom_dark.9.png (renamed from core/res/res/drawable/popup_bottom_dark.9.png)bin975 -> 975 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/popup_bottom_medium.9.png (renamed from core/res/res/drawable/popup_bottom_medium.9.png)bin960 -> 960 bytes
-rw-r--r--core/res/res/drawable-mdpi/popup_center_bright.9.png (renamed from core/res/res/drawable/popup_center_bright.9.png)bin196 -> 196 bytes
-rw-r--r--core/res/res/drawable-mdpi/popup_center_dark.9.png (renamed from core/res/res/drawable/popup_center_dark.9.png)bin209 -> 209 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/popup_center_medium.9.png (renamed from core/res/res/drawable/popup_center_medium.9.png)bin148 -> 148 bytes
-rw-r--r--core/res/res/drawable-mdpi/popup_full_bright.9.png (renamed from core/res/res/drawable/popup_full_bright.9.png)bin1251 -> 1251 bytes
-rw-r--r--core/res/res/drawable-mdpi/popup_full_dark.9.png (renamed from core/res/res/drawable/popup_full_dark.9.png)bin1332 -> 1332 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/popup_inline_error.9.png (renamed from core/res/res/drawable/popup_inline_error.9.png)bin1779 -> 1779 bytes
-rw-r--r--core/res/res/drawable-mdpi/popup_inline_error_above.9.png (renamed from core/res/res/drawable/popup_inline_error_above.9.png)bin2043 -> 2043 bytes
-rw-r--r--core/res/res/drawable-mdpi/popup_top_bright.9.png (renamed from core/res/res/drawable/popup_top_bright.9.png)bin701 -> 701 bytes
-rw-r--r--core/res/res/drawable-mdpi/popup_top_dark.9.png (renamed from core/res/res/drawable/popup_top_dark.9.png)bin815 -> 815 bytes
-rw-r--r--core/res/res/drawable-mdpi/presence_away.png (renamed from core/res/res/drawable/presence_away.png)bin810 -> 810 bytes
-rw-r--r--core/res/res/drawable-mdpi/presence_busy.png (renamed from core/res/res/drawable/presence_busy.png)bin811 -> 811 bytes
-rw-r--r--core/res/res/drawable-mdpi/presence_invisible.png (renamed from core/res/res/drawable/presence_invisible.png)bin693 -> 693 bytes
-rw-r--r--core/res/res/drawable-mdpi/presence_offline.png (renamed from core/res/res/drawable/presence_offline.png)bin767 -> 767 bytes
-rw-r--r--core/res/res/drawable-mdpi/presence_online.png (renamed from core/res/res/drawable/presence_online.png)bin812 -> 812 bytes
-rw-r--r--core/res/res/drawable-mdpi/pressed_application_background_static.png (renamed from core/res/res/drawable/pressed_application_background_static.png)bin3902 -> 3902 bytes
-rw-r--r--core/res/res/drawable-mdpi/progressbar_indeterminate1.png (renamed from core/res/res/drawable/progressbar_indeterminate1.png)bin3678 -> 3678 bytes
-rw-r--r--core/res/res/drawable-mdpi/progressbar_indeterminate2.png (renamed from core/res/res/drawable/progressbar_indeterminate2.png)bin3704 -> 3704 bytes
-rw-r--r--core/res/res/drawable-mdpi/progressbar_indeterminate3.png (renamed from core/res/res/drawable/progressbar_indeterminate3.png)bin3752 -> 3752 bytes
-rw-r--r--core/res/res/drawable-mdpi/radiobutton_off_background.png (renamed from core/res/res/drawable/radiobutton_off_background.png)bin3335 -> 3335 bytes
-rw-r--r--core/res/res/drawable-mdpi/radiobutton_on_background.png (renamed from core/res/res/drawable/radiobutton_on_background.png)bin3468 -> 3468 bytes
-rw-r--r--core/res/res/drawable-mdpi/rate_star_big_half.png (renamed from core/res/res/drawable/rate_star_big_half.png)bin818 -> 818 bytes
-rw-r--r--core/res/res/drawable-mdpi/rate_star_big_off.png (renamed from core/res/res/drawable/rate_star_big_off.png)bin527 -> 527 bytes
-rw-r--r--core/res/res/drawable-mdpi/rate_star_big_on.png (renamed from core/res/res/drawable/rate_star_big_on.png)bin992 -> 992 bytes
-rw-r--r--core/res/res/drawable-mdpi/rate_star_small_half.png (renamed from core/res/res/drawable/rate_star_small_half.png)bin540 -> 540 bytes
-rw-r--r--core/res/res/drawable-mdpi/rate_star_small_off.png (renamed from core/res/res/drawable/rate_star_small_off.png)bin447 -> 447 bytes
-rw-r--r--core/res/res/drawable-mdpi/rate_star_small_on.png (renamed from core/res/res/drawable/rate_star_small_on.png)bin570 -> 570 bytes
-rw-r--r--core/res/res/drawable-mdpi/reticle.png (renamed from core/res/res/drawable/reticle.png)bin3226 -> 3226 bytes
-rw-r--r--core/res/res/drawable-mdpi/screen_progress_frame.9.png (renamed from core/res/res/drawable/screen_progress_frame.9.png)bin322 -> 322 bytes
-rw-r--r--core/res/res/drawable-mdpi/screen_progress_inner.9.png (renamed from core/res/res/drawable/screen_progress_inner.9.png)bin185 -> 185 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/scrollbar_handle_accelerated_anim2.9.png (renamed from core/res/res/drawable/scrollbar_handle_accelerated_anim2.9.png)bin1144 -> 1144 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/scrollbar_handle_horizontal.9.png (renamed from core/res/res/drawable/scrollbar_handle_horizontal.9.png)bin266 -> 266 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/scrollbar_handle_vertical.9.png (renamed from core/res/res/drawable/scrollbar_handle_vertical.9.png)bin254 -> 254 bytes
-rw-r--r--core/res/res/drawable-mdpi/search_dropdown_background.9.png (renamed from core/res/res/drawable/search_dropdown_background.9.png)bin3058 -> 3058 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/search_plate.9.png (renamed from core/res/res/drawable/search_plate.9.png)bin2943 -> 2943 bytes
-rw-r--r--core/res/res/drawable-mdpi/search_plate_global.9.png (renamed from core/res/res/drawable/search_plate_global.9.png)bin293 -> 293 bytes
-rw-r--r--core/res/res/drawable-mdpi/seek_thumb_normal.png (renamed from core/res/res/drawable/seek_thumb_normal.png)bin880 -> 880 bytes
-rw-r--r--core/res/res/drawable-mdpi/seek_thumb_pressed.png (renamed from core/res/res/drawable/seek_thumb_pressed.png)bin1073 -> 1073 bytes
-rw-r--r--core/res/res/drawable-mdpi/seek_thumb_selected.png (renamed from core/res/res/drawable/seek_thumb_selected.png)bin1090 -> 1090 bytes
-rw-r--r--core/res/res/drawable-mdpi/settings_header_raw.9.png (renamed from core/res/res/drawable/settings_header_raw.9.png)bin285 -> 285 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_black_16.png (renamed from core/res/res/drawable/spinner_black_16.png)bin291 -> 291 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/spinner_black_20.png (renamed from core/res/res/drawable/spinner_black_20.png)bin523 -> 523 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_black_48.png (renamed from core/res/res/drawable/spinner_black_48.png)bin1022 -> 1022 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_black_76.png (renamed from core/res/res/drawable/spinner_black_76.png)bin1086 -> 1086 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_dropdown_background_down.9.png (renamed from core/res/res/drawable/spinner_dropdown_background_down.9.png)bin350 -> 350 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_dropdown_background_up.9.png (renamed from core/res/res/drawable/spinner_dropdown_background_up.9.png)bin347 -> 347 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_normal.9.png (renamed from core/res/res/drawable/spinner_normal.9.png)bin1135 -> 1135 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_press.9.png (renamed from core/res/res/drawable/spinner_press.9.png)bin1778 -> 1778 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_select.9.png (renamed from core/res/res/drawable/spinner_select.9.png)bin1755 -> 1755 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_white_16.png (renamed from core/res/res/drawable/spinner_white_16.png)bin2968 -> 2968 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_white_48.png (renamed from core/res/res/drawable/spinner_white_48.png)bin782 -> 782 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_white_76.png (renamed from core/res/res/drawable/spinner_white_76.png)bin3745 -> 3745 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinnerbox_arrow_first.9.png (renamed from core/res/res/drawable/spinnerbox_arrow_first.9.png)bin3053 -> 3053 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinnerbox_arrow_last.9.png (renamed from core/res/res/drawable/spinnerbox_arrow_last.9.png)bin3052 -> 3052 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinnerbox_arrow_middle.9.png (renamed from core/res/res/drawable/spinnerbox_arrow_middle.9.png)bin3020 -> 3020 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinnerbox_arrow_single.9.png (renamed from core/res/res/drawable/spinnerbox_arrow_single.9.png)bin3037 -> 3037 bytes
-rw-r--r--core/res/res/drawable-mdpi/star_big_off.png (renamed from core/res/res/drawable/star_big_off.png)bin1508 -> 1508 bytes
-rw-r--r--core/res/res/drawable-mdpi/star_big_on.png (renamed from core/res/res/drawable/star_big_on.png)bin1734 -> 1734 bytes
-rw-r--r--core/res/res/drawable-mdpi/star_off.png (renamed from core/res/res/drawable/star_off.png)bin594 -> 594 bytes
-rw-r--r--core/res/res/drawable-mdpi/star_on.png (renamed from core/res/res/drawable/star_on.png)bin1231 -> 1231 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_ecb_mode.png (renamed from core/res/res/drawable/stat_ecb_mode.png)bin625 -> 625 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_alarm.png (renamed from core/res/res/drawable/stat_notify_alarm.png)bin1035 -> 1035 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_call_mute.png (renamed from core/res/res/drawable/stat_notify_call_mute.png)bin788 -> 788 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_chat.png (renamed from core/res/res/drawable/stat_notify_chat.png)bin806 -> 806 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_notify_disk_full.png (renamed from core/res/res/drawable/stat_notify_disk_full.png)bin842 -> 842 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_error.png (renamed from core/res/res/drawable/stat_notify_error.png)bin704 -> 704 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_missed_call.png (renamed from core/res/res/drawable/stat_notify_missed_call.png)bin875 -> 875 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_more.png (renamed from core/res/res/drawable/stat_notify_more.png)bin786 -> 786 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_sdcard.png (renamed from core/res/res/drawable/stat_notify_sdcard.png)bin369 -> 369 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_sdcard_usb.png (renamed from core/res/res/drawable/stat_notify_sdcard_usb.png)bin430 -> 430 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_notify_sim_toolkit.png (renamed from core/res/res/drawable/stat_notify_sim_toolkit.png)bin1063 -> 1063 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_sync.png (renamed from core/res/res/drawable/stat_notify_sync.png)bin1076 -> 1076 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_sync_anim0.png (renamed from core/res/res/drawable/stat_notify_sync_anim0.png)bin1076 -> 1076 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_sync_error.png (renamed from core/res/res/drawable/stat_notify_sync_error.png)bin1146 -> 1146 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_voicemail.png (renamed from core/res/res/drawable/stat_notify_voicemail.png)bin655 -> 655 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_notify_wifi_in_range.png (renamed from core/res/res/drawable/stat_notify_wifi_in_range.png)bin1075 -> 1075 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_0.png (renamed from core/res/res/drawable/stat_sys_battery_0.png)bin1034 -> 1034 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_battery_10.png (renamed from core/res/res/drawable/stat_sys_battery_10.png)bin738 -> 738 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_100.png (renamed from core/res/res/drawable/stat_sys_battery_100.png)bin738 -> 738 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_20.png (renamed from core/res/res/drawable/stat_sys_battery_20.png)bin746 -> 746 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_40.png (renamed from core/res/res/drawable/stat_sys_battery_40.png)bin769 -> 769 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_60.png (renamed from core/res/res/drawable/stat_sys_battery_60.png)bin762 -> 762 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_80.png (renamed from core/res/res/drawable/stat_sys_battery_80.png)bin724 -> 724 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_charge_anim0.png (renamed from core/res/res/drawable/stat_sys_battery_charge_anim0.png)bin854 -> 854 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_charge_anim1.png (renamed from core/res/res/drawable/stat_sys_battery_charge_anim1.png)bin864 -> 864 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_charge_anim2.png (renamed from core/res/res/drawable/stat_sys_battery_charge_anim2.png)bin875 -> 875 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_charge_anim3.png (renamed from core/res/res/drawable/stat_sys_battery_charge_anim3.png)bin888 -> 888 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_charge_anim4.png (renamed from core/res/res/drawable/stat_sys_battery_charge_anim4.png)bin879 -> 879 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_charge_anim5.png (renamed from core/res/res/drawable/stat_sys_battery_charge_anim5.png)bin868 -> 868 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_battery_unknown.png (renamed from core/res/res/drawable/stat_sys_battery_unknown.png)bin895 -> 895 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_bluetooth.png (renamed from core/res/res/drawable/stat_sys_data_bluetooth.png)bin818 -> 818 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png (renamed from core/res/res/drawable/stat_sys_data_bluetooth_connected.png)bin967 -> 967 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_connected_3g.png (renamed from core/res/res/drawable/stat_sys_data_connected_3g.png)bin832 -> 832 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_connected_e.png (renamed from core/res/res/drawable/stat_sys_data_connected_e.png)bin833 -> 833 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_connected_g.png (renamed from core/res/res/drawable/stat_sys_data_connected_g.png)bin838 -> 838 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_in_3g.png (renamed from core/res/res/drawable/stat_sys_data_in_3g.png)bin757 -> 757 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_in_e.png (renamed from core/res/res/drawable/stat_sys_data_in_e.png)bin719 -> 719 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_in_g.png (renamed from core/res/res/drawable/stat_sys_data_in_g.png)bin724 -> 724 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_inandout_3g.png (renamed from core/res/res/drawable/stat_sys_data_inandout_3g.png)bin709 -> 709 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_inandout_e.png (renamed from core/res/res/drawable/stat_sys_data_inandout_e.png)bin682 -> 682 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_inandout_g.png (renamed from core/res/res/drawable/stat_sys_data_inandout_g.png)bin683 -> 683 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_out_3g.png (renamed from core/res/res/drawable/stat_sys_data_out_3g.png)bin768 -> 768 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_out_e.png (renamed from core/res/res/drawable/stat_sys_data_out_e.png)bin735 -> 735 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_out_g.png (renamed from core/res/res/drawable/stat_sys_data_out_g.png)bin739 -> 739 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_usb.png (renamed from core/res/res/drawable/stat_sys_data_usb.png)bin786 -> 786 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_download_anim0.png (renamed from core/res/res/drawable/stat_sys_download_anim0.png)bin645 -> 645 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_download_anim1.png (renamed from core/res/res/drawable/stat_sys_download_anim1.png)bin645 -> 645 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_download_anim2.png (renamed from core/res/res/drawable/stat_sys_download_anim2.png)bin653 -> 653 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_download_anim3.png (renamed from core/res/res/drawable/stat_sys_download_anim3.png)bin659 -> 659 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_download_anim4.png (renamed from core/res/res/drawable/stat_sys_download_anim4.png)bin645 -> 645 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_download_anim5.png (renamed from core/res/res/drawable/stat_sys_download_anim5.png)bin626 -> 626 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_gps_acquiring.png (renamed from core/res/res/drawable/stat_sys_gps_acquiring.png)bin595 -> 595 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_gps_on.png (renamed from core/res/res/drawable/stat_sys_gps_on.png)bin1035 -> 1035 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_headset.png (renamed from core/res/res/drawable/stat_sys_headset.png)bin408 -> 408 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_no_sim.png (renamed from core/res/res/drawable/stat_sys_no_sim.png)bin809 -> 809 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_phone_call.png (renamed from core/res/res/drawable/stat_sys_phone_call.png)bin773 -> 773 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png (renamed from core/res/res/drawable/stat_sys_phone_call_bluetooth.png)bin815 -> 815 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_phone_call_forward.png (renamed from core/res/res/drawable/stat_sys_phone_call_forward.png)bin835 -> 835 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_phone_call_on_hold.png (renamed from core/res/res/drawable/stat_sys_phone_call_on_hold.png)bin754 -> 754 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_r_signal_0.png (renamed from core/res/res/drawable/stat_sys_r_signal_0.png)bin802 -> 802 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_r_signal_0_cdma.png (renamed from core/res/res/drawable/stat_sys_r_signal_0_cdma.png)bin743 -> 743 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_r_signal_1.png (renamed from core/res/res/drawable/stat_sys_r_signal_1.png)bin818 -> 818 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_r_signal_1_cdma.png (renamed from core/res/res/drawable/stat_sys_r_signal_1_cdma.png)bin743 -> 743 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_r_signal_2.png (renamed from core/res/res/drawable/stat_sys_r_signal_2.png)bin802 -> 802 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_r_signal_2_cdma.png (renamed from core/res/res/drawable/stat_sys_r_signal_2_cdma.png)bin736 -> 736 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_r_signal_3.png (renamed from core/res/res/drawable/stat_sys_r_signal_3.png)bin798 -> 798 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_r_signal_3_cdma.png (renamed from core/res/res/drawable/stat_sys_r_signal_3_cdma.png)bin730 -> 730 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_r_signal_4.png (renamed from core/res/res/drawable/stat_sys_r_signal_4.png)bin726 -> 726 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_r_signal_4_cdma.png (renamed from core/res/res/drawable/stat_sys_r_signal_4_cdma.png)bin675 -> 675 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_ra_signal_0_cdma.png (renamed from core/res/res/drawable/stat_sys_ra_signal_0_cdma.png)bin719 -> 719 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_ra_signal_1_cdma.png (renamed from core/res/res/drawable/stat_sys_ra_signal_1_cdma.png)bin725 -> 725 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_ra_signal_2_cdma.png (renamed from core/res/res/drawable/stat_sys_ra_signal_2_cdma.png)bin712 -> 712 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_ra_signal_3_cdma.png (renamed from core/res/res/drawable/stat_sys_ra_signal_3_cdma.png)bin705 -> 705 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_ra_signal_4_cdma.png (renamed from core/res/res/drawable/stat_sys_ra_signal_4_cdma.png)bin637 -> 637 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_ringer_silent.png (renamed from core/res/res/drawable/stat_sys_ringer_silent.png)bin767 -> 767 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_ringer_vibrate.png (renamed from core/res/res/drawable/stat_sys_ringer_vibrate.png)bin1255 -> 1255 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_roaming_cdma_0.png (renamed from core/res/res/drawable/stat_sys_roaming_cdma_0.png)bin377 -> 377 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png (renamed from core/res/res/drawable/stat_sys_roaming_cdma_flash_anim0.png)bin150 -> 150 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png (renamed from core/res/res/drawable/stat_sys_roaming_cdma_flash_anim1.png)bin377 -> 377 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_signal_0.png (renamed from core/res/res/drawable/stat_sys_signal_0.png)bin587 -> 587 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_signal_1.png (renamed from core/res/res/drawable/stat_sys_signal_1.png)bin597 -> 597 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_signal_2.png (renamed from core/res/res/drawable/stat_sys_signal_2.png)bin595 -> 595 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_signal_3.png (renamed from core/res/res/drawable/stat_sys_signal_3.png)bin594 -> 594 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_signal_4.png (renamed from core/res/res/drawable/stat_sys_signal_4.png)bin532 -> 532 bytes
-rwxr-xr-x[-rw-r--r--]core/res/res/drawable-mdpi/stat_sys_signal_flightmode.png (renamed from core/res/res/drawable/stat_sys_signal_flightmode.png)bin898 -> 898 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_signal_null.png (renamed from core/res/res/drawable/stat_sys_signal_null.png)bin730 -> 730 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_speakerphone.png (renamed from core/res/res/drawable/stat_sys_speakerphone.png)bin978 -> 978 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_tty_mode.png (renamed from core/res/res/drawable/stat_sys_tty_mode.png)bin725 -> 725 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_upload_anim0.png (renamed from core/res/res/drawable/stat_sys_upload_anim0.png)bin657 -> 657 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_upload_anim1.png (renamed from core/res/res/drawable/stat_sys_upload_anim1.png)bin653 -> 653 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_upload_anim2.png (renamed from core/res/res/drawable/stat_sys_upload_anim2.png)bin666 -> 666 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_upload_anim3.png (renamed from core/res/res/drawable/stat_sys_upload_anim3.png)bin659 -> 659 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_upload_anim4.png (renamed from core/res/res/drawable/stat_sys_upload_anim4.png)bin641 -> 641 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/stat_sys_upload_anim5.png (renamed from core/res/res/drawable/stat_sys_upload_anim5.png)bin641 -> 641 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_vp_phone_call.png (renamed from core/res/res/drawable/stat_sys_vp_phone_call.png)bin1161 -> 1161 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png (renamed from core/res/res/drawable/stat_sys_vp_phone_call_bluetooth.png)bin815 -> 815 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_vp_phone_call_on_hold.png (renamed from core/res/res/drawable/stat_sys_vp_phone_call_on_hold.png)bin1177 -> 1177 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_warning.png (renamed from core/res/res/drawable/stat_sys_warning.png)bin651 -> 651 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_wifi_signal_0.png (renamed from core/res/res/drawable/stat_sys_wifi_signal_0.png)bin743 -> 743 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_wifi_signal_1.png (renamed from core/res/res/drawable/stat_sys_wifi_signal_1.png)bin768 -> 768 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_wifi_signal_2.png (renamed from core/res/res/drawable/stat_sys_wifi_signal_2.png)bin785 -> 785 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_wifi_signal_3.png (renamed from core/res/res/drawable/stat_sys_wifi_signal_3.png)bin807 -> 807 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_wifi_signal_4.png (renamed from core/res/res/drawable/stat_sys_wifi_signal_4.png)bin826 -> 826 bytes
-rw-r--r--core/res/res/drawable-mdpi/status_bar_background.png (renamed from core/res/res/drawable/status_bar_background.png)bin3109 -> 3109 bytes
-rw-r--r--core/res/res/drawable-mdpi/status_bar_close_on.9.png (renamed from core/res/res/drawable/status_bar_close_on.9.png)bin646 -> 646 bytes
-rw-r--r--core/res/res/drawable-mdpi/status_bar_header_background.9.png (renamed from core/res/res/drawable/status_bar_header_background.9.png)bin2867 -> 2867 bytes
-rw-r--r--core/res/res/drawable-mdpi/status_bar_item_app_background_normal.9.png (renamed from core/res/res/drawable/status_bar_item_app_background_normal.9.png)bin3013 -> 3013 bytes
-rw-r--r--core/res/res/drawable-mdpi/status_bar_item_background_focus.9.png (renamed from core/res/res/drawable/status_bar_item_background_focus.9.png)bin11006 -> 11006 bytes
-rw-r--r--core/res/res/drawable-mdpi/status_bar_item_background_normal.9.png (renamed from core/res/res/drawable/status_bar_item_background_normal.9.png)bin186 -> 186 bytes
-rw-r--r--core/res/res/drawable-mdpi/status_bar_item_background_pressed.9.png (renamed from core/res/res/drawable/status_bar_item_background_pressed.9.png)bin11006 -> 11006 bytes
-rw-r--r--core/res/res/drawable-mdpi/statusbar_background.png (renamed from core/res/res/drawable/statusbar_background.png)bin3160 -> 3160 bytes
-rw-r--r--core/res/res/drawable-mdpi/submenu_arrow_nofocus.png (renamed from core/res/res/drawable/submenu_arrow_nofocus.png)bin2878 -> 2878 bytes
-rw-r--r--core/res/res/drawable-mdpi/sym_action_add.png (renamed from core/res/res/drawable/sym_action_add.png)bin930 -> 930 bytes
-rw-r--r--core/res/res/drawable-mdpi/sym_action_call.png (renamed from core/res/res/drawable/sym_action_call.png)bin904 -> 904 bytes
-rw-r--r--core/res/res/drawable-mdpi/sym_action_chat.png (renamed from core/res/res/drawable/sym_action_chat.png)bin808 -> 808 bytes
-rw-r--r--core/res/res/drawable-mdpi/sym_action_email.png (renamed from core/res/res/drawable/sym_action_email.png)bin791 -> 791 bytes
-rw-r--r--core/res/res/drawable-mdpi/sym_call_incoming.png (renamed from core/res/res/drawable/sym_call_incoming.png)bin1200 -> 1200 bytes
-rw-r--r--core/res/res/drawable-mdpi/sym_call_missed.png (renamed from core/res/res/drawable/sym_call_missed.png)bin1234 -> 1234 bytes
-rw-r--r--core/res/res/drawable-mdpi/sym_call_outgoing.png (renamed from core/res/res/drawable/sym_call_outgoing.png)bin1206 -> 1206 bytes
-rw-r--r--core/res/res/drawable-mdpi/sym_contact_card.png (renamed from core/res/res/drawable/sym_contact_card.png)bin3032 -> 3032 bytes
-rw-r--r--core/res/res/drawable-mdpi/sym_def_app_icon.png (renamed from core/res/res/drawable/sym_def_app_icon.png)bin4499 -> 4499 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/tab_focus.9.pngbin0 -> 280 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/tab_focus_bar_left.9.pngbin0 -> 141 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/tab_focus_bar_right.9.pngbin0 -> 141 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/tab_press.9.pngbin0 -> 271 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/tab_press_bar_left.9.pngbin0 -> 141 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/tab_press_bar_right.9.pngbin0 -> 141 bytes
-rw-r--r--core/res/res/drawable-mdpi/tab_selected.9.pngbin0 -> 287 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/tab_selected_bar_left.9.pngbin0 -> 143 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/tab_selected_bar_right.9.pngbin0 -> 143 bytes
-rw-r--r--core/res/res/drawable-mdpi/tab_unselected.9.pngbin0 -> 300 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_default.9.png (renamed from core/res/res/drawable/textfield_default.9.png)bin758 -> 758 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_disabled.9.png (renamed from core/res/res/drawable/textfield_disabled.9.png)bin545 -> 545 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_disabled_selected.9.png (renamed from core/res/res/drawable/textfield_disabled_selected.9.png)bin570 -> 570 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_pressed.9.png (renamed from core/res/res/drawable/textfield_pressed.9.png)bin1040 -> 1040 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/textfield_search_default.9.png (renamed from core/res/res/drawable/textfield_search_default.9.png)bin3361 -> 3361 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_search_pressed.9.png (renamed from core/res/res/drawable/textfield_search_pressed.9.png)bin3586 -> 3586 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/textfield_search_selected.9.png (renamed from core/res/res/drawable/textfield_search_selected.9.png)bin3354 -> 3354 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_selected.9.png (renamed from core/res/res/drawable/textfield_selected.9.png)bin790 -> 790 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_down_disabled.9.png (renamed from core/res/res/drawable/timepicker_down_disabled.9.png)bin422 -> 422 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_down_disabled_focused.9.png (renamed from core/res/res/drawable/timepicker_down_disabled_focused.9.png)bin580 -> 580 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_down_normal.9.png (renamed from core/res/res/drawable/timepicker_down_normal.9.png)bin795 -> 795 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_down_pressed.9.png (renamed from core/res/res/drawable/timepicker_down_pressed.9.png)bin1161 -> 1161 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_down_selected.9.png (renamed from core/res/res/drawable/timepicker_down_selected.9.png)bin1170 -> 1170 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_input_disabled.9.png (renamed from core/res/res/drawable/timepicker_input_disabled.9.png)bin280 -> 280 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_input_normal.9.png (renamed from core/res/res/drawable/timepicker_input_normal.9.png)bin582 -> 582 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_input_pressed.9.png (renamed from core/res/res/drawable/timepicker_input_pressed.9.png)bin604 -> 604 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_input_selected.9.png (renamed from core/res/res/drawable/timepicker_input_selected.9.png)bin517 -> 517 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_up_disabled.9.png (renamed from core/res/res/drawable/timepicker_up_disabled.9.png)bin491 -> 491 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_up_disabled_focused.9.png (renamed from core/res/res/drawable/timepicker_up_disabled_focused.9.png)bin728 -> 728 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_up_normal.9.png (renamed from core/res/res/drawable/timepicker_up_normal.9.png)bin989 -> 989 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_up_pressed.9.png (renamed from core/res/res/drawable/timepicker_up_pressed.9.png)bin1433 -> 1433 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/timepicker_up_selected.9.png (renamed from core/res/res/drawable/timepicker_up_selected.9.png)bin1428 -> 1428 bytes
-rw-r--r--core/res/res/drawable-mdpi/title_bar_portrait.9.png (renamed from core/res/res/drawable/title_bar_portrait.9.png)bin4121 -> 4121 bytes
-rw-r--r--core/res/res/drawable-mdpi/title_bar_shadow.9.png (renamed from core/res/res/drawable/title_bar_shadow.9.png)bin178 -> 178 bytes
-rw-r--r--core/res/res/drawable-mdpi/title_bar_tall.png (renamed from core/res/res/drawable/title_bar_tall.png)bin12764 -> 12764 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/toast_frame.9.png (renamed from core/res/res/drawable/toast_frame.9.png)bin4328 -> 4328 bytes
-rw-r--r--core/res/res/drawable-mdpi/unknown_image.png (renamed from core/res/res/drawable/unknown_image.png)bin208 -> 208 bytes
-rw-r--r--core/res/res/drawable-mdpi/zoom_plate.9.png (renamed from core/res/res/drawable/zoom_plate.9.png)bin2177 -> 2177 bytes
-rw-r--r--core/res/res/drawable/contact_header_bg.9.pngbin0 -> 231 bytes
-rw-r--r--core/res/res/drawable/dark_header.9.pngbin179 -> 0 bytes
-rw-r--r--core/res/res/drawable/dark_header_dither.xml20
-rw-r--r--core/res/res/drawable/divider_horizontal_bright.9.pngbin240 -> 0 bytes
-rw-r--r--core/res/res/drawable/divider_horizontal_bright_opaque.9.pngbin2933 -> 0 bytes
-rw-r--r--core/res/res/drawable/divider_horizontal_dark.9.pngbin232 -> 0 bytes
-rw-r--r--core/res/res/drawable/divider_horizontal_dark_opaque.9.pngbin2941 -> 0 bytes
-rw-r--r--core/res/res/drawable/divider_vertical_bright.9.pngbin130 -> 0 bytes
-rw-r--r--core/res/res/drawable/divider_vertical_bright_opaque.9.pngbin0 -> 120 bytes
-rw-r--r--core/res/res/drawable/divider_vertical_dark.9.pngbin0 -> 121 bytes
-rw-r--r--core/res/res/drawable/divider_vertical_dark_opaque.9.pngbin0 -> 120 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_dark.xml28
-rw-r--r--core/res/res/drawable/fasttrack_badge_dark_normal.9.pngbin0 -> 624 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_dark_pressed.9.pngbin0 -> 846 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_light.xml28
-rw-r--r--core/res/res/drawable/fasttrack_badge_light_normal.9.pngbin0 -> 824 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_light_pressed.9.pngbin0 -> 831 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_middle.xml28
-rw-r--r--core/res/res/drawable/fasttrack_badge_middle_normal.9.pngbin0 -> 606 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_middle_pressed.9.pngbin0 -> 818 bytes
-rw-r--r--core/res/res/drawable/ic_contact_picture_2.pngbin0 -> 1894 bytes
-rw-r--r--core/res/res/drawable/ic_contact_picture_3.pngbin0 -> 1364 bytes
-rw-r--r--core/res/res/drawable/light_header.9.pngbin183 -> 0 bytes
-rw-r--r--core/res/res/drawable/light_header_dither.xml20
-rw-r--r--core/res/res/drawable/stat_sys_data_connected_1x.pngbin0 -> 892 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_connected_1xrtt.pngbin984 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_connected_evdo.pngbin995 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_connected_h.pngbin0 -> 642 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_data_dormant_1xrtt.pngbin1081 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_data_dormant_evdo.pngbin1008 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_in_1x.pngbin0 -> 808 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_in_1xrtt.pngbin948 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_in_evdo.pngbin967 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_in_h.pngbin0 -> 669 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_inandout_1x.pngbin0 -> 770 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_inandout_1xrtt.pngbin942 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_inandout_evdo.pngbin960 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_inandout_h.pngbin0 -> 655 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_out_1x.pngbin0 -> 820 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_out_1xrtt.pngbin942 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_out_evdo.pngbin963 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_data_out_h.pngbin0 -> 654 bytes
-rw-r--r--core/res/res/drawable/stat_sys_signal_0_cdma.pngbin701 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_signal_1_cdma.pngbin714 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_signal_2_cdma.pngbin706 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_signal_3_cdma.pngbin702 -> 0 bytes
-rw-r--r--core/res/res/drawable/stat_sys_signal_4_cdma.pngbin621 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_signal_cdma_0.pngbin701 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_signal_cdma_1.pngbin714 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_signal_cdma_2.pngbin706 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_signal_cdma_3.pngbin702 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_signal_cdma_4.pngbin621 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_signal_evdo_0.pngbin912 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_signal_evdo_1.pngbin925 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_signal_evdo_2.pngbin904 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_signal_evdo_3.pngbin907 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/stat_sys_signal_evdo_4.pngbin823 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/tab_focus.9.pngbin3326 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/tab_focus_bar_left.9.pngbin2967 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/tab_focus_bar_right.9.pngbin2949 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/tab_press.9.pngbin3037 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/tab_press_bar_left.9.pngbin2959 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/tab_press_bar_right.9.pngbin2951 -> 0 bytes
-rw-r--r--core/res/res/drawable/tab_selected.9.pngbin657 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/tab_selected_bar_left.9.pngbin2934 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/tab_selected_bar_right.9.pngbin2935 -> 0 bytes
-rw-r--r--core/res/res/drawable/tab_unselected.9.pngbin825 -> 0 bytes
-rw-r--r--core/res/res/layout-ja/contact_header_name.xml42
-rw-r--r--core/res/res/layout/contact_header.xml68
-rw-r--r--core/res/res/layout/contact_header_name.xml26
-rw-r--r--core/res/res/layout/grant_credentials_permission.xml41
-rw-r--r--core/res/res/layout/keyguard_screen_glogin_unlock.xml1
-rw-r--r--core/res/res/layout/preference_dialog.xml26
-rw-r--r--core/res/res/layout/tab_indicator.xml2
-rw-r--r--core/res/res/layout/zoom_browser_accessory_buttons.xml11
-rw-r--r--core/res/res/raw/loaderror.html1
-rw-r--r--core/res/res/raw/nodomain.html1
-rw-r--r--core/res/res/values-cs/strings.xml1289
-rw-r--r--core/res/res/values-da/strings.xml1179
-rw-r--r--core/res/res/values-de/strings.xml1289
-rw-r--r--core/res/res/values-el/strings.xml1179
-rw-r--r--core/res/res/values-en-rUS/donottranslate-names.xml155
-rw-r--r--core/res/res/values-es-rUS/strings.xml1179
-rw-r--r--core/res/res/values-es/strings.xml1289
-rw-r--r--core/res/res/values-fr/strings.xml1289
-rw-r--r--core/res/res/values-it/strings.xml1289
-rw-r--r--core/res/res/values-ja/strings.xml1339
-rw-r--r--core/res/res/values-ko/strings.xml1179
-rw-r--r--core/res/res/values-mcc204-cs/strings.xml2
-rw-r--r--core/res/res/values-mcc204-da/strings.xml2
-rw-r--r--core/res/res/values-mcc204-de/strings.xml2
-rw-r--r--core/res/res/values-mcc204-el/strings.xml2
-rw-r--r--core/res/res/values-mcc204-es-rUS/strings.xml2
-rw-r--r--core/res/res/values-mcc204-es/strings.xml2
-rw-r--r--core/res/res/values-mcc204-fr/strings.xml2
-rw-r--r--core/res/res/values-mcc204-it/strings.xml2
-rw-r--r--core/res/res/values-mcc204-ja/strings.xml2
-rw-r--r--core/res/res/values-mcc204-ko/strings.xml2
-rw-r--r--core/res/res/values-mcc204-nl/strings.xml2
-rw-r--r--core/res/res/values-mcc204-pl/strings.xml2
-rw-r--r--core/res/res/values-mcc204-pt-rPT/strings.xml2
-rw-r--r--core/res/res/values-mcc204-pt/strings.xml2
-rw-r--r--core/res/res/values-mcc204-ru/strings.xml2
-rw-r--r--core/res/res/values-mcc204-sv/strings.xml2
-rw-r--r--core/res/res/values-mcc204-tr/strings.xml2
-rw-r--r--core/res/res/values-mcc204-zh-rCN/strings.xml2
-rw-r--r--core/res/res/values-mcc204-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values-mcc230-cs/strings.xml2
-rw-r--r--core/res/res/values-mcc230-da/strings.xml2
-rw-r--r--core/res/res/values-mcc230-de/strings.xml2
-rw-r--r--core/res/res/values-mcc230-el/strings.xml2
-rw-r--r--core/res/res/values-mcc230-es-rUS/strings.xml2
-rw-r--r--core/res/res/values-mcc230-es/strings.xml2
-rw-r--r--core/res/res/values-mcc230-fr/strings.xml2
-rw-r--r--core/res/res/values-mcc230-it/strings.xml2
-rw-r--r--core/res/res/values-mcc230-ja/strings.xml2
-rw-r--r--core/res/res/values-mcc230-ko/strings.xml2
-rw-r--r--core/res/res/values-mcc230-nl/strings.xml2
-rw-r--r--core/res/res/values-mcc230-pl/strings.xml2
-rw-r--r--core/res/res/values-mcc230-pt-rPT/strings.xml2
-rw-r--r--core/res/res/values-mcc230-pt/strings.xml2
-rw-r--r--core/res/res/values-mcc230-ru/strings.xml2
-rw-r--r--core/res/res/values-mcc230-sv/strings.xml2
-rw-r--r--core/res/res/values-mcc230-tr/strings.xml2
-rw-r--r--core/res/res/values-mcc230-zh-rCN/strings.xml2
-rw-r--r--core/res/res/values-mcc230-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values-mcc232-cs/strings.xml2
-rw-r--r--core/res/res/values-mcc232-da/strings.xml2
-rw-r--r--core/res/res/values-mcc232-de/strings.xml2
-rw-r--r--core/res/res/values-mcc232-el/strings.xml2
-rw-r--r--core/res/res/values-mcc232-es-rUS/strings.xml2
-rw-r--r--core/res/res/values-mcc232-es/strings.xml2
-rw-r--r--core/res/res/values-mcc232-fr/strings.xml2
-rw-r--r--core/res/res/values-mcc232-it/strings.xml2
-rw-r--r--core/res/res/values-mcc232-ja/strings.xml2
-rw-r--r--core/res/res/values-mcc232-ko/strings.xml2
-rw-r--r--core/res/res/values-mcc232-nl/strings.xml2
-rw-r--r--core/res/res/values-mcc232-pl/strings.xml2
-rw-r--r--core/res/res/values-mcc232-pt-rPT/strings.xml2
-rw-r--r--core/res/res/values-mcc232-pt/strings.xml2
-rw-r--r--core/res/res/values-mcc232-ru/strings.xml2
-rw-r--r--core/res/res/values-mcc232-sv/strings.xml2
-rw-r--r--core/res/res/values-mcc232-tr/strings.xml2
-rw-r--r--core/res/res/values-mcc232-zh-rCN/strings.xml2
-rw-r--r--core/res/res/values-mcc232-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values-mcc234-cs/strings.xml2
-rw-r--r--core/res/res/values-mcc234-da/strings.xml2
-rw-r--r--core/res/res/values-mcc234-de/strings.xml2
-rw-r--r--core/res/res/values-mcc234-el/strings.xml2
-rw-r--r--core/res/res/values-mcc234-es-rUS/strings.xml2
-rw-r--r--core/res/res/values-mcc234-es/strings.xml2
-rw-r--r--core/res/res/values-mcc234-fr/strings.xml2
-rw-r--r--core/res/res/values-mcc234-it/strings.xml2
-rw-r--r--core/res/res/values-mcc234-ja/strings.xml2
-rw-r--r--core/res/res/values-mcc234-ko/strings.xml2
-rw-r--r--core/res/res/values-mcc234-nl/strings.xml2
-rw-r--r--core/res/res/values-mcc234-pl/strings.xml2
-rw-r--r--core/res/res/values-mcc234-pt-rPT/strings.xml2
-rw-r--r--core/res/res/values-mcc234-pt/strings.xml2
-rw-r--r--core/res/res/values-mcc234-ru/strings.xml2
-rw-r--r--core/res/res/values-mcc234-sv/strings.xml2
-rw-r--r--core/res/res/values-mcc234-tr/strings.xml2
-rw-r--r--core/res/res/values-mcc234-zh-rCN/strings.xml2
-rw-r--r--core/res/res/values-mcc234-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values-mcc260-cs/strings.xml2
-rw-r--r--core/res/res/values-mcc260-da/strings.xml2
-rw-r--r--core/res/res/values-mcc260-de/strings.xml2
-rw-r--r--core/res/res/values-mcc260-el/strings.xml2
-rw-r--r--core/res/res/values-mcc260-es-rUS/strings.xml2
-rw-r--r--core/res/res/values-mcc260-es/strings.xml2
-rw-r--r--core/res/res/values-mcc260-fr/strings.xml2
-rw-r--r--core/res/res/values-mcc260-it/strings.xml2
-rw-r--r--core/res/res/values-mcc260-ja/strings.xml2
-rw-r--r--core/res/res/values-mcc260-ko/strings.xml2
-rw-r--r--core/res/res/values-mcc260-nl/strings.xml2
-rw-r--r--core/res/res/values-mcc260-pl/strings.xml2
-rw-r--r--core/res/res/values-mcc260-pt-rPT/strings.xml2
-rw-r--r--core/res/res/values-mcc260-pt/strings.xml2
-rw-r--r--core/res/res/values-mcc260-ru/strings.xml2
-rw-r--r--core/res/res/values-mcc260-sv/strings.xml2
-rw-r--r--core/res/res/values-mcc260-tr/strings.xml2
-rw-r--r--core/res/res/values-mcc260-zh-rCN/strings.xml2
-rw-r--r--core/res/res/values-mcc260-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values-mcc262-cs/strings.xml2
-rw-r--r--core/res/res/values-mcc262-da/strings.xml2
-rw-r--r--core/res/res/values-mcc262-de/strings.xml2
-rw-r--r--core/res/res/values-mcc262-el/strings.xml2
-rw-r--r--core/res/res/values-mcc262-es-rUS/strings.xml2
-rw-r--r--core/res/res/values-mcc262-es/strings.xml2
-rw-r--r--core/res/res/values-mcc262-fr/strings.xml2
-rw-r--r--core/res/res/values-mcc262-it/strings.xml2
-rw-r--r--core/res/res/values-mcc262-ja/strings.xml2
-rw-r--r--core/res/res/values-mcc262-ko/strings.xml2
-rw-r--r--core/res/res/values-mcc262-nl/strings.xml2
-rw-r--r--core/res/res/values-mcc262-pl/strings.xml2
-rw-r--r--core/res/res/values-mcc262-pt-rPT/strings.xml2
-rw-r--r--core/res/res/values-mcc262-pt/strings.xml2
-rw-r--r--core/res/res/values-mcc262-ru/strings.xml2
-rw-r--r--core/res/res/values-mcc262-sv/strings.xml2
-rw-r--r--core/res/res/values-mcc262-tr/strings.xml2
-rw-r--r--core/res/res/values-mcc262-zh-rCN/strings.xml2
-rw-r--r--core/res/res/values-mcc262-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values-nb/strings.xml1345
-rw-r--r--core/res/res/values-nl/strings.xml1289
-rw-r--r--core/res/res/values-pl/strings.xml1289
-rw-r--r--core/res/res/values-pt-rPT/strings.xml1179
-rw-r--r--core/res/res/values-pt/strings.xml1179
-rw-r--r--core/res/res/values-ru/strings.xml1179
-rw-r--r--core/res/res/values-sv/strings.xml1179
-rw-r--r--core/res/res/values-tr/strings.xml1179
-rw-r--r--core/res/res/values-zh-rCN/strings.xml1179
-rw-r--r--core/res/res/values-zh-rTW/strings.xml1289
-rw-r--r--core/res/res/values/attrs.xml116
-rw-r--r--core/res/res/values/attrs_manifest.xml17
-rw-r--r--core/res/res/values/colors.xml4
-rw-r--r--core/res/res/values/config.xml49
-rw-r--r--core/res/res/values/dimens.xml6
-rw-r--r--core/res/res/values/donottranslate-names.xml11
-rw-r--r--core/res/res/values/public.xml53
-rw-r--r--core/res/res/values/strings.xml144
-rw-r--r--core/res/res/values/styles.xml27
-rw-r--r--core/res/res/values/themes.xml20
-rw-r--r--data/etc/android.hardware.camera.autofocus.xml21
-rw-r--r--data/etc/platform.xml5
-rw-r--r--docs/html/guide/appendix/faq/commontasks.jd13
-rw-r--r--docs/html/guide/developing/device.jd2
-rw-r--r--docs/html/guide/developing/tools/adb.jd2
-rw-r--r--docs/html/guide/developing/tools/aidl.jd1
-rw-r--r--docs/html/guide/developing/tools/ddms.jd13
-rw-r--r--docs/html/guide/topics/manifest/manifest-element.jd7
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java43
-rw-r--r--graphics/java/android/graphics/Color.java196
-rw-r--r--graphics/java/android/graphics/DashPathEffect.java6
-rw-r--r--graphics/java/android/graphics/Typeface.java10
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java15
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java2
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java2
-rw-r--r--graphics/java/android/graphics/drawable/StateListDrawable.java2
-rw-r--r--graphics/java/android/renderscript/Allocation.java277
-rw-r--r--graphics/java/android/renderscript/BaseObj.java83
-rw-r--r--graphics/java/android/renderscript/Dimension.java35
-rw-r--r--graphics/java/android/renderscript/Element.java372
-rw-r--r--graphics/java/android/renderscript/Light.java73
-rw-r--r--graphics/java/android/renderscript/Matrix.java192
-rw-r--r--graphics/java/android/renderscript/Primitive.java37
-rw-r--r--graphics/java/android/renderscript/ProgramFragment.java158
-rw-r--r--graphics/java/android/renderscript/ProgramStore.java173
-rw-r--r--graphics/java/android/renderscript/ProgramVertex.java185
-rw-r--r--graphics/java/android/renderscript/RSSurfaceView.java146
-rw-r--r--graphics/java/android/renderscript/RenderScript.java318
-rw-r--r--graphics/java/android/renderscript/Sampler.java108
-rw-r--r--graphics/java/android/renderscript/Script.java107
-rw-r--r--graphics/java/android/renderscript/ScriptC.java161
-rw-r--r--graphics/java/android/renderscript/SimpleMesh.java316
-rw-r--r--graphics/java/android/renderscript/Type.java144
-rw-r--r--graphics/jni/Android.mk45
-rw-r--r--graphics/jni/android_renderscript_RenderScript.cpp1397
-rw-r--r--im/java/android/im/BrandingResourceIDs.java52
-rw-r--r--im/java/android/im/IImPlugin.aidl69
-rw-r--r--im/java/android/im/ImPluginConsts.java27
-rw-r--r--include/android_runtime/AndroidRuntime.h3
-rw-r--r--include/binder/Binder.h104
-rw-r--r--include/binder/BpBinder.h124
-rw-r--r--include/binder/IBinder.h159
-rw-r--r--include/binder/IInterface.h147
-rw-r--r--include/binder/IMemory.h102
-rw-r--r--include/binder/IPCThreadState.h110
-rw-r--r--include/binder/IPermissionController.h56
-rw-r--r--include/binder/IServiceManager.h100
-rw-r--r--include/binder/MemoryBase.h51
-rw-r--r--include/binder/MemoryDealer.h257
-rw-r--r--include/binder/MemoryHeapBase.h98
-rw-r--r--include/binder/MemoryHeapPmem.h80
-rw-r--r--include/binder/Parcel.h223
-rw-r--r--include/binder/Permission.h68
-rw-r--r--include/binder/ProcessState.h117
-rw-r--r--include/media/AudioRecord.h61
-rw-r--r--include/media/AudioSystem.h399
-rw-r--r--include/media/AudioTrack.h29
-rw-r--r--include/media/IAudioFlinger.h48
-rw-r--r--include/media/IAudioFlingerClient.h8
-rw-r--r--include/media/IAudioPolicyService.h90
-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.h36
-rw-r--r--include/media/IMediaPlayerClient.h4
-rw-r--r--include/media/IMediaPlayerService.h8
-rw-r--r--include/media/IMediaRecorder.h2
-rw-r--r--include/media/IOMX.h191
-rw-r--r--include/media/MediaPlayerInterface.h50
-rw-r--r--include/media/Metadata.h133
-rw-r--r--include/media/PVPlayer.h6
-rw-r--r--include/media/mediametadataretriever.h3
-rw-r--r--include/media/mediaplayer.h8
-rw-r--r--include/media/mediarecorder.h9
-rw-r--r--include/media/mediascanner.h5
-rw-r--r--include/media/stagefright/AudioPlayer.h98
-rw-r--r--include/media/stagefright/AudioSource.h51
-rw-r--r--include/media/stagefright/CachingDataSource.h62
-rw-r--r--include/media/stagefright/CameraSource.h72
-rw-r--r--include/media/stagefright/DataSource.h67
-rw-r--r--include/media/stagefright/ESDS.h64
-rw-r--r--include/media/stagefright/FileSource.h49
-rw-r--r--include/media/stagefright/HTTPDataSource.h59
-rw-r--r--include/media/stagefright/HTTPStream.h74
-rw-r--r--include/media/stagefright/MP3Extractor.h55
-rw-r--r--include/media/stagefright/MPEG4Extractor.h68
-rw-r--r--include/media/stagefright/MPEG4Writer.h75
-rw-r--r--include/media/stagefright/MediaBuffer.h113
-rw-r--r--include/media/stagefright/MediaBufferGroup.h58
-rw-r--r--include/media/stagefright/MediaDebug.h20
-rw-r--r--include/media/stagefright/MediaErrors.h43
-rw-r--r--include/media/stagefright/MediaExtractor.h49
-rw-r--r--include/media/stagefright/MediaPlayerImpl.h128
-rw-r--r--include/media/stagefright/MediaSource.h93
-rw-r--r--include/media/stagefright/MetaData.h134
-rw-r--r--include/media/stagefright/MmapSource.h52
-rw-r--r--include/media/stagefright/OMXClient.h45
-rw-r--r--include/media/stagefright/OMXCodec.h203
-rw-r--r--include/media/stagefright/QComHardwareRenderer.h57
-rw-r--r--include/media/stagefright/SampleTable.h109
-rw-r--r--include/media/stagefright/ShoutcastSource.h59
-rw-r--r--include/media/stagefright/SoftwareRenderer.h55
-rw-r--r--include/media/stagefright/TIHardwareRenderer.h59
-rw-r--r--include/media/stagefright/TimeSource.h51
-rw-r--r--include/media/stagefright/TimedEventQueue.h106
-rw-r--r--include/media/stagefright/Utils.h37
-rw-r--r--include/media/stagefright/VideoRenderer.h41
-rw-r--r--include/media/stagefright/string.h54
-rw-r--r--include/private/binder/Static.h39
-rw-r--r--include/private/binder/binder_module.h (renamed from include/private/utils/binder_module.h)0
-rw-r--r--include/private/media/AudioTrackShared.h13
-rw-r--r--include/private/opengles/gl_context.h43
-rw-r--r--include/private/ui/RegionHelper.h281
-rw-r--r--include/private/ui/SharedState.h36
-rw-r--r--include/private/ui/SurfaceBuffer.h77
-rw-r--r--include/private/ui/SurfaceFlingerSynchro.h28
-rw-r--r--include/private/ui/android_natives_priv.h62
-rw-r--r--include/private/utils/Static.h23
-rw-r--r--include/private/utils/futex_synchro.h60
-rw-r--r--include/tts/TtsEngine.h6
-rw-r--r--include/ui/BufferMapper.h64
-rw-r--r--include/ui/Camera.h19
-rw-r--r--include/ui/CameraHardwareInterface.h139
-rw-r--r--include/ui/EGLDisplaySurface.h86
-rw-r--r--include/ui/EGLNativeWindowSurface.h59
-rw-r--r--include/ui/EGLUtils.h53
-rw-r--r--include/ui/EventHub.h29
-rw-r--r--include/ui/FramebufferNativeWindow.h87
-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.h8
-rw-r--r--include/ui/ISurfaceComposer.h44
-rw-r--r--include/ui/ISurfaceFlingerClient.h8
-rw-r--r--include/ui/Overlay.h12
-rw-r--r--include/ui/PixelFormat.h36
-rw-r--r--include/ui/Rect.h8
-rw-r--r--include/ui/Region.h129
-rw-r--r--include/ui/Surface.h213
-rw-r--r--include/ui/SurfaceComposerClient.h55
-rw-r--r--include/ui/egl/android_natives.h263
-rw-r--r--include/utils.h33
-rw-r--r--include/utils/Binder.h103
-rw-r--r--include/utils/BpBinder.h122
-rw-r--r--include/utils/Debug.h33
-rw-r--r--include/utils/IBinder.h159
-rw-r--r--include/utils/IInterface.h135
-rw-r--r--include/utils/IMemory.h94
-rw-r--r--include/utils/IPCThreadState.h110
-rw-r--r--include/utils/IPermissionController.h56
-rw-r--r--include/utils/IServiceManager.h98
-rw-r--r--include/utils/KeyedVector.h2
-rw-r--r--include/utils/List.h272
-rw-r--r--include/utils/LogSocket.h20
-rw-r--r--include/utils/MemoryBase.h51
-rw-r--r--include/utils/MemoryDealer.h238
-rw-r--r--include/utils/MemoryHeapBase.h98
-rw-r--r--include/utils/MemoryHeapPmem.h80
-rw-r--r--include/utils/Parcel.h211
-rw-r--r--include/utils/Pipe.h108
-rw-r--r--include/utils/ProcessState.h117
-rw-r--r--include/utils/RefBase.h4
-rw-r--r--include/utils/Singleton.h69
-rw-r--r--include/utils/Socket.h80
-rw-r--r--include/utils/SortedVector.h3
-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/TypeHelpers.h141
-rw-r--r--include/utils/Vector.h3
-rw-r--r--include/utils/VectorImpl.h1
-rw-r--r--include/utils/ZipEntry.h345
-rw-r--r--include/utils/ZipFile.h269
-rw-r--r--include/utils/executablepath.h28
-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.h117
-rw-r--r--keystore/java/android/security/CertTool.java13
-rw-r--r--keystore/java/android/security/ServiceCommand.java31
-rw-r--r--libs/audioflinger/A2dpAudioInterface.cpp236
-rw-r--r--libs/audioflinger/A2dpAudioInterface.h51
-rw-r--r--libs/audioflinger/Android.mk83
-rw-r--r--libs/audioflinger/AudioDumpInterface.cpp454
-rw-r--r--libs/audioflinger/AudioDumpInterface.h117
-rw-r--r--libs/audioflinger/AudioFlinger.cpp3286
-rw-r--r--libs/audioflinger/AudioFlinger.h541
-rw-r--r--libs/audioflinger/AudioHardwareGeneric.cpp161
-rw-r--r--libs/audioflinger/AudioHardwareGeneric.h49
-rw-r--r--libs/audioflinger/AudioHardwareInterface.cpp109
-rw-r--r--libs/audioflinger/AudioHardwareStub.cpp64
-rw-r--r--libs/audioflinger/AudioHardwareStub.h37
-rw-r--r--libs/audioflinger/AudioMixer.cpp1
-rw-r--r--libs/audioflinger/AudioMixer.h3
-rw-r--r--libs/audioflinger/AudioPolicyManagerGeneric.cpp826
-rw-r--r--libs/audioflinger/AudioPolicyManagerGeneric.h189
-rw-r--r--libs/audioflinger/AudioPolicyService.cpp771
-rw-r--r--libs/audioflinger/AudioPolicyService.h203
-rw-r--r--libs/binder/Android.mk45
-rw-r--r--libs/binder/Binder.cpp255
-rw-r--r--libs/binder/BpBinder.cpp365
-rw-r--r--libs/binder/IInterface.cpp42
-rw-r--r--libs/binder/IMemory.cpp492
-rw-r--r--libs/binder/IPCThreadState.cpp1025
-rw-r--r--libs/binder/IPermissionController.cpp80
-rw-r--r--libs/binder/IServiceManager.cpp229
-rw-r--r--libs/binder/MemoryBase.cpp46
-rw-r--r--libs/binder/MemoryDealer.cpp421
-rw-r--r--libs/binder/MemoryHeapBase.cpp183
-rw-r--r--libs/binder/MemoryHeapPmem.cpp248
-rw-r--r--libs/binder/Parcel.cpp1336
-rw-r--r--libs/binder/Permission.cpp88
-rw-r--r--libs/binder/ProcessState.cpp398
-rw-r--r--libs/binder/Static.cpp53
-rw-r--r--libs/rs/Android.mk115
-rw-r--r--libs/rs/RenderScript.h201
-rw-r--r--libs/rs/RenderScriptEnv.h33
-rw-r--r--libs/rs/java/Android.mk1
-rw-r--r--libs/rs/java/Fall/Android.mk25
-rw-r--r--libs/rs/java/Fall/AndroidManifest.xml21
-rw-r--r--libs/rs/java/Fall/res/drawable-hdpi/leaves.pngbin0 -> 154875 bytes
-rw-r--r--libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpgbin0 -> 228373 bytes
-rw-r--r--libs/rs/java/Fall/res/drawable-hdpi/sky.jpgbin0 -> 82354 bytes
-rw-r--r--libs/rs/java/Fall/res/raw/fall.c518
-rw-r--r--libs/rs/java/Fall/src/com/android/fall/rs/Fall.java47
-rw-r--r--libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java423
-rw-r--r--libs/rs/java/Fall/src/com/android/fall/rs/FallView.java59
-rw-r--r--libs/rs/java/Film/Android.mk25
-rw-r--r--libs/rs/java/Film/AndroidManifest.xml14
-rw-r--r--libs/rs/java/Film/res/drawable/p01.pngbin0 -> 254040 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p02.pngbin0 -> 138822 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p03.pngbin0 -> 152567 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p04.pngbin0 -> 280950 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p05.pngbin0 -> 349923 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p06.pngbin0 -> 120523 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p07.pngbin0 -> 139555 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p08.pngbin0 -> 321251 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p09.pngbin0 -> 281133 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p10.pngbin0 -> 366289 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p11.pngbin0 -> 319259 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p12.pngbin0 -> 368751 bytes
-rw-r--r--libs/rs/java/Film/res/drawable/p13.pngbin0 -> 312561 bytes
-rw-r--r--libs/rs/java/Film/res/raw/filmimage.c110
-rw-r--r--libs/rs/java/Film/res/raw/filmstrip.c96
-rw-r--r--libs/rs/java/Film/src/com/android/film/Film.java90
-rw-r--r--libs/rs/java/Film/src/com/android/film/FilmRS.java256
-rw-r--r--libs/rs/java/Film/src/com/android/film/FilmStripMesh.java254
-rw-r--r--libs/rs/java/Film/src/com/android/film/FilmView.java82
-rw-r--r--libs/rs/java/Fountain/Android.mk25
-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.c51
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/Fountain.java90
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java115
-rw-r--r--libs/rs/java/Fountain/src/com/android/fountain/FountainView.java79
-rw-r--r--libs/rs/java/Rollo/Android.mk25
-rw-r--r--libs/rs/java/Rollo/AndroidManifest.xml13
-rw-r--r--libs/rs/java/Rollo/res/raw/browser.pngbin0 -> 5772 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/calendar.pngbin0 -> 4551 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/g1155.pngbin0 -> 5094 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/g2140.pngbin0 -> 3982 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/maps.pngbin0 -> 5374 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/market.pngbin0 -> 4810 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/path1920.pngbin0 -> 3812 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/path1927.pngbin0 -> 4034 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/path3099.pngbin0 -> 4981 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/path3950.pngbin0 -> 4873 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/path431.pngbin0 -> 3995 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/path4481.pngbin0 -> 4113 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/path5168.pngbin0 -> 5328 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/path676.pngbin0 -> 4351 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/path754.pngbin0 -> 3205 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/path815.pngbin0 -> 5536 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/photos.pngbin0 -> 4902 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/polygon2408.pngbin0 -> 3873 bytes
-rw-r--r--libs/rs/java/Rollo/res/raw/rollo.c184
-rw-r--r--libs/rs/java/Rollo/res/raw/rollo2.c155
-rw-r--r--libs/rs/java/Rollo/res/raw/settings.pngbin0 -> 3764 bytes
-rw-r--r--libs/rs/java/Rollo/src/com/android/rollo/Rollo.java90
-rw-r--r--libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java315
-rw-r--r--libs/rs/java/Rollo/src/com/android/rollo/RolloView.java214
-rw-r--r--libs/rs/rs.spec482
-rw-r--r--libs/rs/rsAdapter.cpp237
-rw-r--r--libs/rs/rsAdapter.h96
-rw-r--r--libs/rs/rsAllocation.cpp552
-rw-r--r--libs/rs/rsAllocation.h101
-rw-r--r--libs/rs/rsComponent.cpp101
-rw-r--r--libs/rs/rsComponent.h77
-rw-r--r--libs/rs/rsContext.cpp561
-rw-r--r--libs/rs/rsContext.h210
-rw-r--r--libs/rs/rsDevice.cpp62
-rw-r--r--libs/rs/rsDevice.h48
-rw-r--r--libs/rs/rsElement.cpp421
-rw-r--r--libs/rs/rsElement.h95
-rw-r--r--libs/rs/rsFileA3D.cpp384
-rw-r--r--libs/rs/rsFileA3D.h122
-rw-r--r--libs/rs/rsFileA3DDecls.h44
-rw-r--r--libs/rs/rsHandcode.h47
-rw-r--r--libs/rs/rsLight.cpp128
-rw-r--r--libs/rs/rsLight.h64
-rw-r--r--libs/rs/rsLocklessFifo.cpp258
-rw-r--r--libs/rs/rsLocklessFifo.h91
-rw-r--r--libs/rs/rsMatrix.cpp159
-rw-r--r--libs/rs/rsMatrix.h87
-rw-r--r--libs/rs/rsMesh.cpp46
-rw-r--r--libs/rs/rsMesh.h90
-rw-r--r--libs/rs/rsNoise.cpp256
-rw-r--r--libs/rs/rsNoise.h35
-rw-r--r--libs/rs/rsObjectBase.cpp98
-rw-r--r--libs/rs/rsObjectBase.h118
-rw-r--r--libs/rs/rsProgram.cpp49
-rw-r--r--libs/rs/rsProgram.h56
-rw-r--r--libs/rs/rsProgramFragment.cpp238
-rw-r--r--libs/rs/rsProgramFragment.h93
-rw-r--r--libs/rs/rsProgramFragmentStore.cpp266
-rw-r--r--libs/rs/rsProgramFragmentStore.h82
-rw-r--r--libs/rs/rsProgramVertex.cpp188
-rw-r--r--libs/rs/rsProgramVertex.h81
-rw-r--r--libs/rs/rsSampler.cpp151
-rw-r--r--libs/rs/rsSampler.h87
-rw-r--r--libs/rs/rsScript.cpp95
-rw-r--r--libs/rs/rsScript.h74
-rw-r--r--libs/rs/rsScriptC.cpp367
-rw-r--r--libs/rs/rsScriptC.h100
-rw-r--r--libs/rs/rsScriptC_Lib.cpp1159
-rw-r--r--libs/rs/rsSimpleMesh.cpp142
-rw-r--r--libs/rs/rsSimpleMesh.h68
-rw-r--r--libs/rs/rsThreadIO.cpp61
-rw-r--r--libs/rs/rsThreadIO.h52
-rw-r--r--libs/rs/rsTriangleMesh.cpp287
-rw-r--r--libs/rs/rsTriangleMesh.h83
-rw-r--r--libs/rs/rsType.cpp382
-rw-r--r--libs/rs/rsType.h153
-rw-r--r--libs/rs/rsUtils.h133
-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.c306
-rw-r--r--libs/rs/spec.h43
-rw-r--r--libs/rs/spec.l165
-rw-r--r--libs/surfaceflinger/Android.mk34
-rw-r--r--libs/surfaceflinger/BufferAllocator.cpp118
-rw-r--r--libs/surfaceflinger/BufferAllocator.h96
-rw-r--r--libs/surfaceflinger/CPUGauge.cpp171
-rw-r--r--libs/surfaceflinger/CPUGauge.h74
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp198
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.h24
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp2
-rw-r--r--libs/surfaceflinger/GPUHardware/GPUHardware.cpp585
-rw-r--r--libs/surfaceflinger/Layer.cpp381
-rw-r--r--libs/surfaceflinger/Layer.h49
-rw-r--r--libs/surfaceflinger/LayerBase.cpp413
-rw-r--r--libs/surfaceflinger/LayerBase.h151
-rw-r--r--libs/surfaceflinger/LayerBitmap.cpp247
-rw-r--r--libs/surfaceflinger/LayerBitmap.h116
-rw-r--r--libs/surfaceflinger/LayerBlur.cpp42
-rw-r--r--libs/surfaceflinger/LayerBlur.h2
-rw-r--r--libs/surfaceflinger/LayerBuffer.cpp346
-rw-r--r--libs/surfaceflinger/LayerBuffer.h54
-rw-r--r--libs/surfaceflinger/LayerDim.cpp159
-rw-r--r--libs/surfaceflinger/LayerDim.h14
-rw-r--r--libs/surfaceflinger/LayerOrientationAnim.cpp206
-rw-r--r--libs/surfaceflinger/LayerOrientationAnim.h80
-rw-r--r--libs/surfaceflinger/MessageQueue.cpp192
-rw-r--r--libs/surfaceflinger/MessageQueue.h127
-rw-r--r--libs/surfaceflinger/OrientationAnimation.cpp155
-rw-r--r--libs/surfaceflinger/OrientationAnimation.h85
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.cpp855
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.h191
-rw-r--r--libs/surfaceflinger/Tokenizer.cpp5
-rw-r--r--libs/surfaceflinger/Transform.cpp8
-rw-r--r--libs/surfaceflinger/VRamHeap.cpp178
-rw-r--r--libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.cpp585
-rw-r--r--libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.h (renamed from libs/surfaceflinger/GPUHardware/GPUHardware.h)0
-rw-r--r--libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp272
-rw-r--r--libs/surfaceflinger/purgatory/LayerOrientationAnim.h112
-rw-r--r--libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp269
-rw-r--r--libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.h77
-rw-r--r--libs/surfaceflinger/purgatory/OrientationAnimation.cpp150
-rw-r--r--libs/surfaceflinger/purgatory/OrientationAnimation.h84
-rw-r--r--libs/surfaceflinger/purgatory/VRamHeap.cpp174
-rw-r--r--libs/surfaceflinger/purgatory/VRamHeap.h (renamed from libs/surfaceflinger/VRamHeap.h)0
-rw-r--r--libs/surfaceflinger/tests/overlays/overlays.cpp6
-rw-r--r--libs/surfaceflinger/tests/resize/Android.mk16
-rw-r--r--libs/surfaceflinger/tests/resize/resize.cpp60
-rw-r--r--libs/ui/Android.mk8
-rw-r--r--libs/ui/BufferMapper.cpp80
-rw-r--r--libs/ui/Camera.cpp4
-rw-r--r--libs/ui/EGLDisplaySurface.cpp519
-rw-r--r--libs/ui/EGLNativeWindowSurface.cpp161
-rw-r--r--libs/ui/EGLUtils.cpp136
-rw-r--r--libs/ui/EventHub.cpp178
-rw-r--r--libs/ui/FramebufferNativeWindow.cpp267
-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.cpp34
-rw-r--r--libs/ui/ISurfaceComposer.cpp125
-rw-r--r--libs/ui/ISurfaceFlingerClient.cpp35
-rw-r--r--libs/ui/LayerState.cpp2
-rw-r--r--libs/ui/Overlay.cpp39
-rw-r--r--libs/ui/Region.cpp636
-rw-r--r--libs/ui/Surface.cpp884
-rw-r--r--libs/ui/SurfaceComposerClient.cpp361
-rw-r--r--libs/ui/SurfaceFlingerSynchro.cpp81
-rw-r--r--libs/ui/tests/Android.mk16
-rw-r--r--libs/ui/tests/region.cpp62
-rw-r--r--libs/utils/Android.mk62
-rw-r--r--libs/utils/BackupData.cpp28
-rw-r--r--libs/utils/Binder.cpp242
-rw-r--r--libs/utils/BpBinder.cpp348
-rw-r--r--libs/utils/CallStack.cpp3
-rw-r--r--libs/utils/IDataConnection.cpp89
-rw-r--r--libs/utils/IInterface.cpp35
-rw-r--r--libs/utils/IMemory.cpp486
-rw-r--r--libs/utils/IPCThreadState.cpp1030
-rw-r--r--libs/utils/IPermissionController.cpp86
-rw-r--r--libs/utils/IServiceManager.cpp230
-rw-r--r--libs/utils/InetAddress.cpp236
-rw-r--r--libs/utils/LogSocket.cpp129
-rw-r--r--libs/utils/MemoryBase.cpp46
-rw-r--r--libs/utils/MemoryDealer.cpp409
-rw-r--r--libs/utils/MemoryHeapBase.cpp183
-rw-r--r--libs/utils/MemoryHeapPmem.cpp248
-rw-r--r--libs/utils/Parcel.cpp1363
-rw-r--r--libs/utils/Pipe.cpp465
-rw-r--r--libs/utils/ProcessState.cpp398
-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/Threads.cpp299
-rw-r--r--libs/utils/TimerProbe.cpp131
-rw-r--r--libs/utils/Timers.cpp125
-rw-r--r--libs/utils/ZipEntry.cpp696
-rw-r--r--libs/utils/ZipFile.cpp1296
-rw-r--r--libs/utils/executablepath_darwin.cpp31
-rw-r--r--libs/utils/executablepath_linux.cpp30
-rw-r--r--libs/utils/futex_synchro.c176
-rw-r--r--libs/utils/ported.cpp106
-rw-r--r--location/java/android/location/Geocoder.java6
-rw-r--r--location/java/android/location/GpsStatus.java12
-rw-r--r--location/java/android/location/IGpsStatusListener.aidl1
-rw-r--r--location/java/android/location/ILocationManager.aidl3
-rwxr-xr-xlocation/java/android/location/INetInitiatedListener.aidl26
-rw-r--r--location/java/android/location/LocationManager.java160
-rwxr-xr-xlocation/java/com/android/internal/location/GpsLocationProvider.java171
-rwxr-xr-xlocation/java/com/android/internal/location/GpsNetInitiatedHandler.java457
-rw-r--r--location/java/com/android/internal/location/GpsXtraDownloader.java1
-rw-r--r--media/java/android/media/AudioFormat.java56
-rw-r--r--media/java/android/media/AudioManager.java226
-rw-r--r--media/java/android/media/AudioRecord.java44
-rw-r--r--media/java/android/media/AudioService.java853
-rw-r--r--media/java/android/media/AudioSystem.java158
-rw-r--r--media/java/android/media/AudioTrack.java42
-rw-r--r--media/java/android/media/ExifInterface.java27
-rw-r--r--media/java/android/media/IAudioService.aidl24
-rw-r--r--media/java/android/media/JetPlayer.java2
-rw-r--r--media/java/android/media/MediaFile.java8
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java5
-rw-r--r--media/java/android/media/MediaPlayer.java205
-rw-r--r--media/java/android/media/MediaRecorder.java5
-rw-r--r--media/java/android/media/MediaScanner.java23
-rw-r--r--media/java/android/media/Metadata.java418
-rw-r--r--media/java/android/media/RingtoneManager.java54
-rw-r--r--media/java/android/media/ToneGenerator.java4
-rw-r--r--media/jni/Android.mk6
-rw-r--r--media/jni/android_media_AmrInputStream.cpp7
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp62
-rw-r--r--media/jni/android_media_MediaPlayer.cpp169
-rw-r--r--media/jni/android_media_MediaRecorder.cpp93
-rw-r--r--media/jni/android_media_MediaScanner.cpp38
-rw-r--r--media/jni/android_media_ResampleInputStream.cpp7
-rw-r--r--media/jni/soundpool/Android.mk1
-rw-r--r--media/jni/soundpool/SoundPool.cpp5
-rw-r--r--media/libdrm/mobile2/include/rights/RoManager.h6
-rw-r--r--media/libdrm/mobile2/src/rights/RoManager.cpp6
-rw-r--r--media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp2
-rw-r--r--media/libmedia/Android.mk44
-rw-r--r--media/libmedia/AudioRecord.cpp98
-rw-r--r--media/libmedia/AudioSystem.cpp753
-rw-r--r--media/libmedia/AudioTrack.cpp205
-rw-r--r--media/libmedia/IAudioFlinger.cpp348
-rw-r--r--media/libmedia/IAudioFlingerClient.cpp52
-rw-r--r--media/libmedia/IAudioPolicyService.cpp413
-rw-r--r--media/libmedia/IAudioRecord.cpp8
-rw-r--r--media/libmedia/IAudioTrack.cpp8
-rw-r--r--media/libmedia/IMediaMetadataRetriever.cpp11
-rw-r--r--media/libmedia/IMediaPlayer.cpp60
-rw-r--r--media/libmedia/IMediaPlayerClient.cpp13
-rw-r--r--media/libmedia/IMediaPlayerService.cpp29
-rw-r--r--media/libmedia/IMediaRecorder.cpp10
-rw-r--r--media/libmedia/IOMX.cpp733
-rw-r--r--media/libmedia/JetPlayer.cpp2
-rw-r--r--media/libmedia/Metadata.cpp168
-rw-r--r--media/libmedia/ToneGenerator.cpp4
-rw-r--r--media/libmedia/mediametadataretriever.cpp4
-rw-r--r--media/libmedia/mediaplayer.cpp43
-rw-r--r--media/libmedia/mediarecorder.cpp2
-rw-r--r--media/libmediaplayerservice/Android.mk41
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp333
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h59
-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/libmediaplayerservice/MidiFile.h4
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.cpp208
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.h60
-rw-r--r--media/libmediaplayerservice/TestPlayerStub.cpp196
-rw-r--r--media/libmediaplayerservice/TestPlayerStub.h119
-rw-r--r--media/libmediaplayerservice/VorbisPlayer.h2
-rw-r--r--media/libstagefright/Android.mk54
-rw-r--r--media/libstagefright/AudioPlayer.cpp287
-rw-r--r--media/libstagefright/CachingDataSource.cpp157
-rw-r--r--media/libstagefright/CameraSource.cpp224
-rw-r--r--media/libstagefright/DataSource.cpp89
-rw-r--r--media/libstagefright/ESDS.cpp196
-rw-r--r--media/libstagefright/FileSource.cpp48
-rw-r--r--media/libstagefright/HTTPDataSource.cpp172
-rw-r--r--media/libstagefright/HTTPStream.cpp285
-rw-r--r--media/libstagefright/MP3Extractor.cpp519
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp978
-rw-r--r--media/libstagefright/MPEG4Writer.cpp647
-rw-r--r--media/libstagefright/MediaBuffer.cpp172
-rw-r--r--media/libstagefright/MediaBufferGroup.cpp86
-rw-r--r--media/libstagefright/MediaExtractor.cpp55
-rw-r--r--media/libstagefright/MediaPlayerImpl.cpp647
-rw-r--r--media/libstagefright/MediaSource.cpp60
-rw-r--r--media/libstagefright/MetaData.cpp232
-rw-r--r--media/libstagefright/MmapSource.cpp110
-rw-r--r--media/libstagefright/OMXClient.cpp47
-rw-r--r--media/libstagefright/OMXCodec.cpp2171
-rw-r--r--media/libstagefright/SampleTable.cpp578
-rw-r--r--media/libstagefright/ShoutcastSource.cpp155
-rw-r--r--media/libstagefright/TimeSource.cpp41
-rw-r--r--media/libstagefright/TimedEventQueue.cpp205
-rw-r--r--media/libstagefright/Utils.cpp45
-rw-r--r--media/libstagefright/omx/Android.mk33
-rw-r--r--media/libstagefright/omx/OMX.cpp639
-rw-r--r--media/libstagefright/omx/OMX.h138
-rw-r--r--media/libstagefright/omx/OMXRenderer.h44
-rw-r--r--media/libstagefright/omx/QComHardwareRenderer.cpp137
-rw-r--r--media/libstagefright/omx/SoftwareRenderer.cpp175
-rw-r--r--media/libstagefright/omx/TIHardwareRenderer.cpp130
-rw-r--r--media/libstagefright/string.cpp83
-rw-r--r--media/mediaserver/Android.mk3
-rw-r--r--media/mediaserver/main_mediaserver.cpp8
-rw-r--r--media/sdutils/sdutil.cpp4
-rw-r--r--media/tests/MediaFrameworkTest/res/drawable-hdpi/icon.pngbin0 -> 9734 bytes
-rw-r--r--media/tests/MediaFrameworkTest/res/drawable-mdpi/icon.png (renamed from media/tests/MediaFrameworkTest/res/drawable/icon.png)bin6094 -> 6094 bytes
-rw-r--r--media/tests/MediaFrameworkTest/res/layout/surface_view.xml7
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java4
-rwxr-xr-xmedia/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java6
-rwxr-xr-xmedia/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java13
-rwxr-xr-xmedia/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java56
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java96
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java8
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java9
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java70
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java10
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java432
-rw-r--r--media/tests/players/Android.mk29
-rw-r--r--media/tests/players/README8
-rw-r--r--media/tests/players/invoke_mock_media_player.cpp121
-rw-r--r--obex/Android.mk9
-rw-r--r--obex/javax/obex/ApplicationParameter.java134
-rw-r--r--obex/javax/obex/Authenticator.java115
-rw-r--r--obex/javax/obex/BaseStream.java76
-rw-r--r--obex/javax/obex/ClientOperation.java720
-rw-r--r--obex/javax/obex/ClientSession.java523
-rw-r--r--obex/javax/obex/HeaderSet.java628
-rw-r--r--obex/javax/obex/ObexHelper.java995
-rw-r--r--obex/javax/obex/ObexSession.java218
-rw-r--r--obex/javax/obex/ObexTransport.java76
-rw-r--r--obex/javax/obex/Operation.java179
-rw-r--r--obex/javax/obex/PasswordAuthentication.java79
-rw-r--r--obex/javax/obex/PrivateInputStream.java181
-rw-r--r--obex/javax/obex/PrivateOutputStream.java175
-rw-r--r--obex/javax/obex/ResponseCodes.java326
-rw-r--r--obex/javax/obex/ServerOperation.java686
-rw-r--r--obex/javax/obex/ServerRequestHandler.java271
-rw-r--r--obex/javax/obex/ServerSession.java669
-rw-r--r--obex/javax/obex/SessionNotifier.java128
-rw-r--r--opengl/include/EGL/eglext.h24
-rw-r--r--opengl/include/EGL/eglnatives.h271
-rw-r--r--opengl/include/EGL/eglplatform.h5
-rw-r--r--opengl/include/GLES/glplatform.h6
-rw-r--r--opengl/include/GLES2/gl2.h620
-rw-r--r--opengl/include/GLES2/gl2ext.h518
-rw-r--r--opengl/include/GLES2/gl2platform.h29
-rw-r--r--opengl/java/android/opengl/GLSurfaceView.java33
-rw-r--r--opengl/libagl/Android.mk19
-rw-r--r--opengl/libagl/TextureObjectManager.cpp47
-rw-r--r--opengl/libagl/TextureObjectManager.h70
-rw-r--r--opengl/libagl/array.cpp126
-rw-r--r--opengl/libagl/copybit.cpp460
-rw-r--r--opengl/libagl/copybit.h75
-rw-r--r--opengl/libagl/egl.cpp795
-rw-r--r--opengl/libagl/light.cpp11
-rw-r--r--opengl/libagl/matrix.cpp2
-rw-r--r--opengl/libagl/primitives.cpp2
-rw-r--r--opengl/libagl/state.cpp82
-rw-r--r--opengl/libagl/texture.cpp248
-rw-r--r--opengl/libagl/texture.h10
-rw-r--r--opengl/libs/Android.mk78
-rw-r--r--opengl/libs/EGL/Loader.cpp276
-rw-r--r--opengl/libs/EGL/Loader.h90
-rw-r--r--opengl/libs/EGL/egl.cpp1010
-rw-r--r--opengl/libs/EGL/egl_entries.in57
-rw-r--r--opengl/libs/EGL/gpu.cpp217
-rw-r--r--opengl/libs/EGL/hooks.cpp67
-rw-r--r--opengl/libs/GLES2/gl2.cpp111
-rw-r--r--opengl/libs/GLES2/gl2_api.in426
-rw-r--r--opengl/libs/GLES2/gl2_entries.in142
-rw-r--r--opengl/libs/GLES2/gl2ext_api.in105
-rw-r--r--opengl/libs/GLES2/gl2ext_entries.in35
-rw-r--r--opengl/libs/GLES_CM/gl.cpp15
-rw-r--r--opengl/libs/GLES_CM/gl_entries.in (renamed from opengl/libs/gl_entries.in)0
-rw-r--r--opengl/libs/GLES_CM/glext_entries.in (renamed from opengl/libs/glext_entries.in)0
-rw-r--r--opengl/libs/egl_entries.in52
-rw-r--r--opengl/libs/egl_impl.h5
-rw-r--r--opengl/libs/gl_enums.in261
-rw-r--r--opengl/libs/hooks.h27
-rw-r--r--opengl/libs/tools/enumextract.sh32
-rwxr-xr-xopengl/libs/tools/genfiles11
-rwxr-xr-xopengl/libs/tools/glapigen15
-rwxr-xr-xopengl/libs/tools/glentrygen15
-rw-r--r--opengl/tests/angeles/Android.mk2
-rw-r--r--opengl/tests/angeles/app-linux.c223
-rw-r--r--opengl/tests/angeles/app-linux.cpp213
-rw-r--r--opengl/tests/copybits/Android.mk18
-rw-r--r--opengl/tests/copybits/copybits.cpp726
-rw-r--r--opengl/tests/fillrate/Android.mk17
-rw-r--r--opengl/tests/fillrate/fillrate.cpp161
-rw-r--r--opengl/tests/filter/Android.mk4
-rw-r--r--opengl/tests/filter/filter.c130
-rw-r--r--opengl/tests/filter/filter.cpp190
-rw-r--r--opengl/tests/finish/Android.mk4
-rw-r--r--opengl/tests/finish/finish.c224
-rw-r--r--opengl/tests/finish/finish.cpp226
-rw-r--r--opengl/tests/swapinterval/Android.mk17
-rw-r--r--opengl/tests/swapinterval/swapinterval.cpp121
-rw-r--r--opengl/tests/textures/Android.mk4
-rw-r--r--opengl/tests/textures/textures.c109
-rw-r--r--opengl/tests/textures/textures.cpp118
-rw-r--r--packages/SettingsProvider/AndroidManifest.xml2
-rw-r--r--packages/SettingsProvider/etc/bookmarks.xml2
-rw-r--r--packages/SettingsProvider/res/values-ja/strings.xml19
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java73
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java26
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java8
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java71
-rw-r--r--packages/SubscribedFeedsProvider/AndroidManifest.xml5
-rw-r--r--packages/SubscribedFeedsProvider/res/values-cs/strings.xml2
-rw-r--r--packages/SubscribedFeedsProvider/res/values-de/strings.xml2
-rw-r--r--packages/SubscribedFeedsProvider/res/values-es/strings.xml2
-rw-r--r--packages/SubscribedFeedsProvider/res/values-fr/strings.xml2
-rw-r--r--packages/SubscribedFeedsProvider/res/values-it/strings.xml2
-rw-r--r--packages/SubscribedFeedsProvider/res/values-ja/strings.xml19
-rw-r--r--packages/SubscribedFeedsProvider/res/values-nl/strings.xml2
-rw-r--r--packages/SubscribedFeedsProvider/res/values-pl/strings.xml2
-rw-r--r--packages/SubscribedFeedsProvider/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SubscribedFeedsProvider/res/values/strings.xml4
-rw-r--r--packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java6
-rw-r--r--packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java76
-rw-r--r--packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java26
-rw-r--r--packages/TtsService/jni/android_tts_SynthProxy.cpp35
-rwxr-xr-xpackages/TtsService/src/android/tts/SynthProxy.java16
-rwxr-xr-xpackages/TtsService/src/android/tts/TtsService.java116
-rw-r--r--packages/VpnServices/res/values-cs/strings.xml11
-rw-r--r--packages/VpnServices/res/values-de/strings.xml11
-rw-r--r--packages/VpnServices/res/values-es/strings.xml11
-rw-r--r--packages/VpnServices/res/values-fr/strings.xml11
-rw-r--r--packages/VpnServices/res/values-it/strings.xml11
-rw-r--r--packages/VpnServices/res/values-ja/strings.xml22
-rw-r--r--packages/VpnServices/res/values-nl/strings.xml11
-rw-r--r--packages/VpnServices/res/values-pl/strings.xml11
-rw-r--r--packages/VpnServices/res/values-zh-rTW/strings.xml11
-rwxr-xr-xpackages/VpnServices/res/values/strings.xml6
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/VpnService.java24
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java3
-rw-r--r--preloaded-classes1363
-rw-r--r--services/java/com/android/server/BackupManagerService.java685
-rw-r--r--services/java/com/android/server/BatteryService.java60
-rw-r--r--services/java/com/android/server/ConnectivityService.java1015
-rw-r--r--services/java/com/android/server/DockObserver.java112
-rwxr-xr-xservices/java/com/android/server/HardwareService.java250
-rw-r--r--services/java/com/android/server/HeadsetObserver.java48
-rw-r--r--services/java/com/android/server/InputDevice.java582
-rw-r--r--services/java/com/android/server/JournaledFile.java107
-rw-r--r--services/java/com/android/server/KeyInputQueue.java579
-rw-r--r--services/java/com/android/server/LocationManagerService.java27
-rw-r--r--services/java/com/android/server/MasterClearReceiver.java4
-rw-r--r--services/java/com/android/server/MountService.java1
-rw-r--r--services/java/com/android/server/NotificationManagerService.java87
-rw-r--r--services/java/com/android/server/PackageManagerService.java176
-rw-r--r--services/java/com/android/server/PowerManagerService.java116
-rw-r--r--services/java/com/android/server/SensorService.java21
-rw-r--r--services/java/com/android/server/ShutdownActivity.java46
-rw-r--r--services/java/com/android/server/SystemBackupAgent.java67
-rw-r--r--services/java/com/android/server/SystemServer.java67
-rw-r--r--services/java/com/android/server/TelephonyRegistry.java20
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java637
-rw-r--r--services/java/com/android/server/WallpaperService.java203
-rw-r--r--services/java/com/android/server/WifiService.java324
-rw-r--r--services/java/com/android/server/WindowManagerService.java894
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java516
-rw-r--r--services/java/com/android/server/am/BatteryStatsService.java1
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java134
-rw-r--r--[-rwxr-xr-x]services/java/com/android/server/am/UsageStatsService.java9
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java332
-rw-r--r--services/jni/com_android_server_AlarmManagerService.cpp4
-rw-r--r--services/jni/com_android_server_BatteryService.cpp159
-rw-r--r--services/jni/com_android_server_HardwareService.cpp2
-rw-r--r--services/jni/com_android_server_KeyInputQueue.cpp38
-rw-r--r--services/jni/com_android_server_SensorService.cpp10
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java341
-rw-r--r--telephony/java/android/telephony/PhoneStateListener.java3
-rw-r--r--telephony/java/android/telephony/ServiceState.java15
-rw-r--r--telephony/java/android/telephony/SmsManager.java46
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java49
-rw-r--r--telephony/java/android/telephony/gsm/SmsMessage.java1
-rw-r--r--telephony/java/com/android/internal/telephony/Call.java4
-rw-r--r--telephony/java/com/android/internal/telephony/CallerInfo.java29
-rw-r--r--telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java4
-rw-r--r--telephony/java/com/android/internal/telephony/CommandsInterface.java42
-rw-r--r--telephony/java/com/android/internal/telephony/Connection.java3
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnectionTracker.java238
-rw-r--r--telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java7
-rw-r--r--telephony/java/com/android/internal/telephony/GsmAlphabet.java63
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl9
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl2
-rw-r--r--telephony/java/com/android/internal/telephony/IccCard.java612
-rw-r--r--telephony/java/com/android/internal/telephony/IccCardStatus.java105
-rw-r--r--telephony/java/com/android/internal/telephony/IccUtils.java11
-rw-r--r--telephony/java/com/android/internal/telephony/Phone.java103
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneBase.java312
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneProxy.java33
-rw-r--r--telephony/java/com/android/internal/telephony/RIL.java112
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java8
-rw-r--r--telephony/java/com/android/internal/telephony/RetryManager.java392
-rw-r--r--telephony/java/com/android/internal/telephony/SMSDispatcher.java67
-rw-r--r--telephony/java/com/android/internal/telephony/ServiceStateTracker.java14
-rw-r--r--telephony/java/com/android/internal/telephony/SmsMessageBase.java54
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyIntents.java24
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyProperties.java21
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CDMAPhone.java655
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaCall.java2
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java125
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java18
-rwxr-xr-x[-rw-r--r--]telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java45
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java5
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java275
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java42
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java306
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/RuimCard.java497
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/RuimRecords.java48
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java16
-rwxr-xr-x[-rw-r--r--]telephony/java/com/android/internal/telephony/cdma/SmsMessage.java62
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java693
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java125
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java8
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/UserData.java59
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/ApnSetting.java5
-rwxr-xr-xtelephony/java/com/android/internal/telephony/gsm/GSMPhone.java425
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmCall.java1
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java18
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmConnection.java8
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java316
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java14
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/MccTable.java844
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/PdpConnection.java8
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SIMRecords.java52
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SimCard.java467
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java18
-rw-r--r--telephony/java/com/android/internal/telephony/test/SimulatedCommands.java40
-rw-r--r--test-runner/android/test/AndroidTestRunner.java19
-rw-r--r--test-runner/android/test/InstrumentationTestRunner.java2
-rw-r--r--test-runner/android/test/IsolatedContext.java21
-rw-r--r--test-runner/android/test/ProviderTestCase.java1
-rw-r--r--test-runner/android/test/RenamingDelegatingContext.java35
-rw-r--r--test-runner/android/test/SyncBaseInstrumentation.java33
-rw-r--r--test-runner/android/test/TestRunner.java8
-rw-r--r--test-runner/android/test/TouchUtils.java1
-rw-r--r--test-runner/android/test/mock/MockContentProvider.java32
-rw-r--r--test-runner/android/test/mock/MockPackageManager.java14
-rw-r--r--tests/AndroidTests/AndroidManifest.xml1
-rw-r--r--tests/AndroidTests/res/raw/v21_simple_1.vcf3
-rw-r--r--tests/AndroidTests/res/raw/v21_simple_2.vcf3
-rw-r--r--tests/AndroidTests/res/raw/v21_simple_3.vcf (renamed from tests/AndroidTests/res/raw/v21_simple.vcf)0
-rwxr-xr-xtests/AndroidTests/run_test.sh2
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java127
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java87
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/VCardTests.java773
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java178
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java322
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java923
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java30
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java313
-rw-r--r--tests/BrowserTestPlugin/Android.mk36
-rw-r--r--tests/BrowserTestPlugin/AndroidManifest.xml35
-rw-r--r--tests/BrowserTestPlugin/MODULE_LICENSE_APACHE20
-rw-r--r--tests/BrowserTestPlugin/NOTICE190
-rw-r--r--tests/BrowserTestPlugin/jni/Android.mk49
-rw-r--r--tests/BrowserTestPlugin/jni/PluginObject.cpp202
-rw-r--r--tests/BrowserTestPlugin/jni/PluginObject.h87
-rw-r--r--tests/BrowserTestPlugin/jni/event/EventPlugin.cpp198
-rw-r--r--tests/BrowserTestPlugin/jni/event/EventPlugin.h45
-rw-r--r--tests/BrowserTestPlugin/jni/main.cpp280
-rw-r--r--tests/BrowserTestPlugin/jni/main.h31
-rwxr-xr-xtests/BrowserTestPlugin/res/drawable/browser_test_plugin.pngbin0 -> 3610 bytes
-rw-r--r--tests/BrowserTestPlugin/src/com/android/testplugin/TestPlugin.java15
-rw-r--r--tests/CoreTests/android/content/SyncStorageEngineTest.java3
-rw-r--r--tests/CoreTests/android/core/RecurrenceSetTest.java82
-rw-r--r--tests/CoreTests/android/core/RequestAPITest.java24
-rw-r--r--tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java77
-rw-r--r--tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java18
-rw-r--r--tests/CoreTests/com/android/internal/telephony/TelephonyTests.java1
-rw-r--r--tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java219
-rw-r--r--tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java4
-rwxr-xr-xtests/DumpRenderTree/assets/run_layout_tests.py21
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java53
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java22
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java8
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java147
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java234
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java112
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java117
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java92
-rw-r--r--tests/FrameworkTest/res/drawable-hdpi/big_drawable_background.9.pngbin0 -> 430 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-hdpi/black_square.pngbin0 -> 116 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-hdpi/black_square_stretchable.9.pngbin0 -> 135 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-hdpi/drawable_background.9.pngbin0 -> 354 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_pause_1.pngbin0 -> 668 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_skip_backward_1.pngbin0 -> 1296 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_skip_forward_1.pngbin0 -> 1247 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-mdpi/big_drawable_background.9.png (renamed from tests/FrameworkTest/res/drawable/big_drawable_background.9.png)bin330 -> 330 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-mdpi/black_square.png (renamed from tests/FrameworkTest/res/drawable/black_square.png)bin151 -> 151 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-mdpi/black_square_stretchable.9.png (renamed from tests/FrameworkTest/res/drawable/black_square_stretchable.9.png)bin175 -> 175 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-mdpi/drawable_background.9.png (renamed from tests/FrameworkTest/res/drawable/drawable_background.9.png)bin270 -> 270 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-mdpi/sym_now_playing_pause_1.png (renamed from tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png)bin3038 -> 3038 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-mdpi/sym_now_playing_skip_backward_1.png (renamed from tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png)bin3262 -> 3262 bytes
-rw-r--r--tests/FrameworkTest/res/drawable-mdpi/sym_now_playing_skip_forward_1.png (renamed from tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png)bin3275 -> 3275 bytes
-rw-r--r--tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java35
-rw-r--r--tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java498
-rw-r--r--tests/appwidgets/AppWidgetHostTest/res/drawable-hdpi/oh_hai_icon.pngbin0 -> 4912 bytes
-rw-r--r--tests/appwidgets/AppWidgetHostTest/res/drawable-mdpi/oh_hai_icon.png (renamed from tests/appwidgets/AppWidgetHostTest/res/drawable/oh_hai_icon.png)bin2988 -> 2988 bytes
-rw-r--r--tests/backup/AndroidManifest.xml1
-rwxr-xr-xtests/backup/backup_stress_test.sh64
-rwxr-xr-xtests/backup/test_backup.sh66
-rwxr-xr-xtests/backup/test_backup_common.sh33
-rwxr-xr-xtests/backup/test_restore.sh96
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java4
-rw-r--r--tools/aapt/AaptAssets.cpp13
-rw-r--r--tools/aapt/AaptAssets.h23
-rw-r--r--tools/aapt/Android.mk5
-rw-r--r--tools/aapt/Bundle.h10
-rw-r--r--tools/aapt/Command.cpp251
-rw-r--r--tools/aapt/Images.cpp5
-rw-r--r--tools/aapt/Main.cpp22
-rw-r--r--tools/aapt/Main.h12
-rw-r--r--tools/aapt/Package.cpp12
-rw-r--r--tools/aapt/Resource.cpp390
-rw-r--r--tools/aapt/ResourceTable.cpp84
-rw-r--r--tools/aapt/ResourceTable.h10
-rw-r--r--tools/aapt/SourcePos.cpp2
-rw-r--r--tools/aapt/XMLNode.cpp3
-rw-r--r--tools/aapt/ZipEntry.cpp696
-rw-r--r--tools/aapt/ZipEntry.h345
-rw-r--r--tools/aapt/ZipFile.cpp1297
-rw-r--r--tools/aapt/ZipFile.h270
-rwxr-xr-xtools/aidl/AST.cpp17
-rw-r--r--tools/aidl/generate_java.cpp7
-rw-r--r--tools/aidl/options.h1
-rw-r--r--tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java61
-rw-r--r--tools/layoutlib/bridge/src/android/webkit/WebView.java7
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java65
-rw-r--r--tools/localize/Perforce.cpp3
-rw-r--r--tools/localize/SourcePos.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--vpn/java/android/net/vpn/VpnManager.java21
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl2
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java7
-rw-r--r--wifi/java/android/net/wifi/WifiNative.java2
-rw-r--r--wifi/java/android/net/wifi/WifiStateTracker.java65
2720 files changed, 152909 insertions, 59967 deletions
diff --git a/Android.mk b/Android.mk
index 1b5c70b..97f012c 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/IActivityController.aidl \
core/java/android/app/IActivityPendingResult.aidl \
core/java/android/app/IActivityWatcher.aidl \
@@ -80,15 +83,15 @@ LOCAL_SRC_FILES += \
core/java/android/app/IStatusBar.aidl \
core/java/android/app/IThumbnailReceiver.aidl \
core/java/android/app/ITransientNotification.aidl \
- core/java/android/app/IWallpaperService.aidl \
- core/java/android/app/IWallpaperServiceCallback.aidl \
+ core/java/android/app/IWallpaperManager.aidl \
+ core/java/android/app/IWallpaperManagerCallback.aidl \
core/java/android/backup/IBackupManager.aidl \
core/java/android/backup/IRestoreObserver.aidl \
core/java/android/backup/IRestoreSession.aidl \
+ core/java/android/bluetooth/IBluetooth.aidl \
core/java/android/bluetooth/IBluetoothA2dp.aidl \
- core/java/android/bluetooth/IBluetoothDevice.aidl \
- core/java/android/bluetooth/IBluetoothDeviceCallback.aidl \
core/java/android/bluetooth/IBluetoothHeadset.aidl \
+ core/java/android/bluetooth/IBluetoothPbap.aidl \
core/java/android/content/IContentService.aidl \
core/java/android/content/IIntentReceiver.aidl \
core/java/android/content/IIntentSender.aidl \
@@ -111,6 +114,9 @@ LOCAL_SRC_FILES += \
core/java/android/os/IParentalControlCallback.aidl \
core/java/android/os/IPermissionController.aidl \
core/java/android/os/IPowerManager.aidl \
+ core/java/android/service/wallpaper/IWallpaperConnection.aidl \
+ core/java/android/service/wallpaper/IWallpaperEngine.aidl \
+ core/java/android/service/wallpaper/IWallpaperService.aidl \
core/java/android/text/IClipboard.aidl \
core/java/android/view/accessibility/IAccessibilityManager.aidl \
core/java/android/view/accessibility/IAccessibilityManagerClient.aidl \
@@ -120,8 +126,6 @@ LOCAL_SRC_FILES += \
core/java/android/view/IWindow.aidl \
core/java/android/view/IWindowManager.aidl \
core/java/android/view/IWindowSession.aidl \
- core/java/android/speech/IRecognitionListener.aidl \
- core/java/android/speech/IRecognitionService.aidl \
core/java/android/speech/tts/ITts.aidl \
core/java/android/speech/tts/ITtsCallback.aidl \
core/java/com/android/internal/app/IBatteryStats.aidl \
@@ -137,13 +141,13 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/view/IInputMethodClient.aidl \
core/java/com/android/internal/view/IInputMethodManager.aidl \
core/java/com/android/internal/view/IInputMethodSession.aidl \
- im/java/android/im/IImPlugin.aidl \
location/java/android/location/IGeocodeProvider.aidl \
location/java/android/location/IGpsStatusListener.aidl \
location/java/android/location/IGpsStatusProvider.aidl \
location/java/android/location/ILocationListener.aidl \
location/java/android/location/ILocationManager.aidl \
location/java/android/location/ILocationProvider.aidl \
+ location/java/android/location/INetInitiatedListener.aidl \
media/java/android/media/IAudioService.aidl \
media/java/android/media/IMediaScannerListener.aidl \
media/java/android/media/IMediaScannerService.aidl \
@@ -195,7 +199,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 \
@@ -221,7 +228,6 @@ aidl_files := \
frameworks/base/graphics/java/android/graphics/Bitmap.aidl \
frameworks/base/graphics/java/android/graphics/Rect.aidl \
frameworks/base/graphics/java/android/graphics/Region.aidl \
- frameworks/base/im/java/android/im/IImPlugin.aidl \
frameworks/base/location/java/android/location/Criteria.aidl \
frameworks/base/location/java/android/location/Location.aidl \
frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
@@ -374,6 +380,34 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
-hdf sdk.current $(framework_docs_SDK_CURRENT_DIR)
+# ==== the api stubs and current.xml ===========================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
+LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
+LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
+LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
+LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
+LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+
+LOCAL_MODULE := api-stubs
+
+LOCAL_DROIDDOC_OPTIONS:=\
+ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_stubs_current_intermediates/src \
+ -apixml $(INTERNAL_PLATFORM_API_FILE) \
+ -nodocs
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk
+
+include $(BUILD_DROIDDOC)
+
+$(full_target): $(framework_built)
+$(INTERNAL_PLATFORM_API_FILE): $(full_target)
+$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
+
# ==== static html in the sdk ==================================
include $(CLEAR_VARS)
@@ -392,10 +426,7 @@ LOCAL_DROIDDOC_OPTIONS:=\
-title "Android SDK" \
-proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \
-todo $(OUT_DOCS)/$(LOCAL_MODULE)-docs-todo.html \
- -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_stubs_current_intermediates/src \
- -apixml $(INTERNAL_PLATFORM_API_FILE) \
-sdkvalues $(OUT_DOCS) \
- -warning 3 \
-hdf android.whichdoc offline
ifeq ($(framework_docs_SDK_PREVIEW),true)
@@ -415,8 +446,6 @@ $(static_doc_index_redirect): \
$(full_target): $(static_doc_index_redirect)
$(full_target): $(framework_built)
-$(INTERNAL_PLATFORM_API_FILE): $(full_target)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
# ==== docs for the web (on the google app engine server) =======================
@@ -501,5 +530,3 @@ include $(BUILD_JAVA_LIBRARY)
ifeq (,$(ONE_SHOT_MAKEFILE))
include $(call first-makefiles-under,$(LOCAL_PATH))
endif
-
-
diff --git a/api/4.xml b/api/4.xml
index 55d9105..49f5271 100644
--- a/api/4.xml
+++ b/api/4.xml
@@ -275171,7 +275171,7 @@
extends="java.lang.Enum"
abstract="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -277224,7 +277224,7 @@
<package name="java.util.concurrent.locks"
>
<class name="AbstractQueuedSynchronizer"
- extends="java.lang.Object"
+ extends="java.util.concurrent.locks.AbstractOwnableSynchronizer"
abstract="true"
static="false"
final="false"
diff --git a/api/current.xml b/api/current.xml
index fc54859..3e616a4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -122,6 +122,28 @@
visibility="public"
>
</field>
+<field name="ACCOUNT_MANAGER_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.ACCOUNT_MANAGER_SERVICE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHENTICATE_ACCOUNTS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.AUTHENTICATE_ACCOUNTS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BATTERY_STATS"
type="java.lang.String"
transient="false"
@@ -155,6 +177,17 @@
visibility="public"
>
</field>
+<field name="BIND_WALLPAPER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.BIND_WALLPAPER&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BLUETOOTH"
type="java.lang.String"
transient="false"
@@ -573,6 +606,17 @@
visibility="public"
>
</field>
+<field name="MANAGE_ACCOUNTS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.MANAGE_ACCOUNTS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MANAGE_APP_TOKENS"
type="java.lang.String"
transient="false"
@@ -1057,6 +1101,17 @@
visibility="public"
>
</field>
+<field name="USE_CREDENTIALS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.USE_CREDENTIALS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="VIBRATE"
type="java.lang.String"
transient="false"
@@ -1604,6 +1659,17 @@
visibility="public"
>
</field>
+<field name="accountType"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843407"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="action"
type="int"
transient="false"
@@ -2594,6 +2660,17 @@
visibility="public"
>
</field>
+<field name="contentAuthority"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843408"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="contentDescription"
type="int"
transient="false"
@@ -6367,6 +6444,17 @@
visibility="public"
>
</field>
+<field name="required"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843406"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="resizeable"
type="int"
transient="false"
@@ -7412,6 +7500,17 @@
visibility="public"
>
</field>
+<field name="supportsUploading"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843415"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="syncable"
type="int"
transient="false"
@@ -8314,6 +8413,17 @@
visibility="public"
>
</field>
+<field name="userVisible"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843409"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="value"
type="int"
transient="false"
@@ -8479,6 +8589,50 @@
visibility="public"
>
</field>
+<field name="wallpaperActivityCloseEnterAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843413"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="wallpaperActivityCloseExitAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843414"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="wallpaperActivityOpenEnterAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843411"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="wallpaperActivityOpenExitAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843412"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="webViewStyle"
type="int"
transient="false"
@@ -8677,6 +8831,17 @@
visibility="public"
>
</field>
+<field name="windowShowWallpaper"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843410"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="windowSoftInputMode"
type="int"
transient="false"
@@ -11988,6 +12153,17 @@
visibility="public"
>
</field>
+<field name="Animation_InputMethod"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973910"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Animation_Toast"
type="int"
transient="false"
@@ -12516,6 +12692,39 @@
visibility="public"
>
</field>
+<field name="Theme_Wallpaper"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973918"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="Theme_Wallpaper_NoTitleBar"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973919"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="Theme_Wallpaper_NoTitleBar_Fullscreen"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973920"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget"
type="int"
transient="false"
@@ -13250,6 +13459,1962 @@
</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"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</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="getAccountRemovalAllowed"
+ return="android.os.Bundle"
+ abstract="false"
+ 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>
+<exception name="NetworkErrorException" type="android.accounts.NetworkErrorException">
+</exception>
+</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="getAuthTokenLabel"
+ return="java.lang.String"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="authTokenType" type="java.lang.String">
+</parameter>
+</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="name"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="type"
+ 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.AccountManagerFuture&lt;android.os.Bundle&gt;"
+ 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.AccountManagerCallback&lt;android.os.Bundle&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="addAccountExplicitly"
+ 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="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="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="clearPassword"
+ 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="confirmCredentials"
+ return="android.accounts.AccountManagerFuture&lt;android.os.Bundle&gt;"
+ 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.AccountManagerCallback&lt;android.os.Bundle&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="confirmPassword"
+ return="android.accounts.AccountManagerFuture&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.AccountManagerCallback&lt;java.lang.Boolean&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="editProperties"
+ return="android.accounts.AccountManagerFuture&lt;android.os.Bundle&gt;"
+ 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.AccountManagerCallback&lt;android.os.Bundle&gt;">
+</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.Account[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAccountsByType"
+ 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>
+</method>
+<method name="getAccountsByTypeAndFeatures"
+ return="android.accounts.AccountManagerFuture&lt;android.accounts.Account[]&gt;"
+ 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.AccountManagerCallback&lt;android.accounts.Account[]&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthToken"
+ return="android.accounts.AccountManagerFuture&lt;android.os.Bundle&gt;"
+ 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.AccountManagerCallback&lt;android.os.Bundle&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthToken"
+ return="android.accounts.AccountManagerFuture&lt;android.os.Bundle&gt;"
+ 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.AccountManagerCallback&lt;android.os.Bundle&gt;">
+</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.AccountManagerCallback&lt;android.os.Bundle&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="getAuthenticatorTypes"
+ return="android.accounts.AuthenticatorDescription[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPassword"
+ 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="getUserData"
+ 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="invalidateAuthToken"
+ 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="peekAuthToken"
+ 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="removeAccount"
+ return="android.accounts.AccountManagerFuture&lt;java.lang.Boolean&gt;"
+ 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="callback" type="android.accounts.AccountManagerCallback&lt;java.lang.Boolean&gt;">
+</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="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="setPassword"
+ 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="setUserData"
+ 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="updateCredentials"
+ return="android.accounts.AccountManagerFuture&lt;android.os.Bundle&gt;"
+ 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.AccountManagerCallback&lt;android.os.Bundle&gt;">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+</class>
+<interface name="AccountManagerCallback"
+ 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.AccountManagerFuture&lt;V&gt;">
+</parameter>
+</method>
+</interface>
+<interface name="AccountManagerFuture"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.util.concurrent.Future">
+</implements>
+<method name="get"
+ return="V"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<exception name="ExecutionException" type="java.util.concurrent.ExecutionException">
+</exception>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+</method>
+<method name="get"
+ return="V"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="ExecutionException" type="java.util.concurrent.ExecutionException">
+</exception>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
+<exception name="TimeoutException" type="java.util.concurrent.TimeoutException">
+</exception>
+</method>
+<method name="getResult"
+ return="V"
+ 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="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="AuthenticatorException" type="android.accounts.AuthenticatorException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+<exception name="OperationCanceledException" type="android.accounts.OperationCanceledException">
+</exception>
+</method>
+</interface>
+<class name="AuthenticatorDescription"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="AuthenticatorDescription"
+ type="android.accounts.AuthenticatorDescription"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="labelId" type="int">
+</parameter>
+<parameter name="iconId" type="int">
+</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="newKey"
+ return="android.accounts.AuthenticatorDescription"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</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>
+<field name="iconId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="labelId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="packageName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="type"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</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_ATTRIBUTES_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;account-authenticator&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHENTICATOR_INTENT_ACTION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.accounts.AccountAuthenticator&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUTHENTICATOR_META_DATA_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.accounts.AccountAuthenticator&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="AUTH_TOKEN_LABEL_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;authTokenLabelKey&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_BAD_REQUEST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ 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="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="not 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="getAccountRemovalAllowed"
+ 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="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="getAuthTokenLabel"
+ 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="authTokenType" type="java.lang.String">
+</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"
@@ -13790,6 +15955,17 @@
<parameter name="data" type="android.content.Intent">
</parameter>
</method>
+<method name="onAttachedToWindow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onChildTitleChanged"
return="void"
abstract="false"
@@ -13993,6 +16169,17 @@
visibility="protected"
>
</method>
+<method name="onDetachedFromWindow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onKeyDown"
return="boolean"
abstract="false"
@@ -14914,6 +17101,23 @@
<parameter name="get" type="boolean">
</parameter>
</method>
+<method name="triggerSearch"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="query" type="java.lang.String">
+</parameter>
+<parameter name="appSearchData" type="android.os.Bundle">
+</parameter>
+<parameter name="globalSearch" type="boolean">
+</parameter>
+</method>
<method name="unregisterForContextMenu"
return="void"
abstract="false"
@@ -17506,6 +19710,17 @@
visibility="public"
>
</method>
+<method name="onAttachedToWindow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onContentChanged"
return="void"
abstract="false"
@@ -17614,6 +19829,17 @@
<parameter name="featureId" type="int">
</parameter>
</method>
+<method name="onDetachedFromWindow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onKeyDown"
return="boolean"
abstract="false"
@@ -19397,6 +21623,19 @@
<parameter name="intent" type="android.content.Intent">
</parameter>
</method>
+<method name="setIntentRedelivery"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
</class>
<class name="KeyguardManager"
extends="java.lang.Object"
@@ -19560,6 +21799,30 @@
visibility="public"
>
</method>
+<method name="onQueryPackageManager"
+ return="java.util.List&lt;android.content.pm.ResolveInfo&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="queryIntent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onSetContentView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
</class>
<class name="LauncherActivity.IconResizer"
extends="java.lang.Object"
@@ -20095,6 +22358,17 @@
visibility="public"
>
</field>
+<field name="FLAG_FOREGROUND_SERVICE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_INSISTENT"
type="int"
transient="false"
@@ -21136,6 +23410,25 @@
visibility="public"
>
</method>
+<method name="triggerSearch"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="query" type="java.lang.String">
+</parameter>
+<parameter name="launchActivity" type="android.content.ComponentName">
+</parameter>
+<parameter name="appSearchData" type="android.os.Bundle">
+</parameter>
+<parameter name="globalSearch" type="boolean">
+</parameter>
+</method>
<field name="ACTION_KEY"
type="java.lang.String"
transient="false"
@@ -21608,11 +23901,28 @@
synchronized="false"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="startId" type="int">
+</parameter>
+</method>
+<method name="onStartCommand"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="intent" type="android.content.Intent">
</parameter>
+<parameter name="flags" type="int">
+</parameter>
<parameter name="startId" type="int">
</parameter>
</method>
@@ -21636,12 +23946,40 @@
synchronized="false"
static="false"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="isForeground" type="boolean">
</parameter>
</method>
+<method name="startForeground"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="notification" type="android.app.Notification">
+</parameter>
+</method>
+<method name="stopForeground"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="removeNotification" type="boolean">
+</parameter>
+</method>
<method name="stopSelf"
return="void"
abstract="false"
@@ -21679,6 +24017,83 @@
<parameter name="startId" type="int">
</parameter>
</method>
+<field name="START_CONTINUATION_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="15"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_FLAG_REDELIVERY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_FLAG_RETRY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_NOT_STICKY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_REDELIVER_INTENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_STICKY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="START_STICKY_COMPATIBILITY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="TabActivity"
extends="android.app.ActivityGroup"
@@ -21868,6 +24283,175 @@
</parameter>
</method>
</interface>
+<class name="WallpaperManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="clear"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="clearWallpaperOffsets"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="windowToken" type="android.os.IBinder">
+</parameter>
+</method>
+<method name="getDesiredMinimumHeight"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDesiredMinimumWidth"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInstance"
+ return="android.app.WallpaperManager"
+ 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="peekDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setBitmap"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bitmap" type="android.graphics.Bitmap">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setResource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="resid" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setStream"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="data" type="java.io.InputStream">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setWallpaperOffsets"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="windowToken" type="android.os.IBinder">
+</parameter>
+<parameter name="xOffset" type="float">
+</parameter>
+<parameter name="yOffset" type="float">
+</parameter>
+</method>
+<method name="suggestDesiredDimensions"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="minimumWidth" type="int">
+</parameter>
+<parameter name="minimumHeight" type="int">
+</parameter>
+</method>
+</class>
</package>
<package name="android.appwidget"
>
@@ -22614,8 +25198,319 @@
</field>
</class>
</package>
+<package name="android.bluetooth"
+>
+<class name="BluetoothAdapter"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="getRemoteDevice"
+ return="android.bluetooth.BluetoothDevice"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="address" type="java.lang.String">
+</parameter>
+</method>
+<method name="listenUsingRfcommOn"
+ return="android.bluetooth.BluetoothServerSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="channel" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+</class>
+<class name="BluetoothDevice"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="createRfcommSocket"
+ return="android.bluetooth.BluetoothSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="channel" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</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="getAddress"
+ return="java.lang.String"
+ 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="out" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+</class>
+<class name="BluetoothServerSocket"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.io.Closeable">
+</implements>
+<method name="accept"
+ return="android.bluetooth.BluetoothSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="accept"
+ return="android.bluetooth.BluetoothSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeout" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+</class>
+<class name="BluetoothSocket"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="java.io.Closeable">
+</implements>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="connect"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="getInputStream"
+ return="java.io.InputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="getOutputStream"
+ return="java.io.OutputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="getRemoteDevice"
+ return="android.bluetooth.BluetoothDevice"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</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>
+<method name="reset"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
<class name="ActivityNotFoundException"
extends="java.lang.RuntimeException"
abstract="false"
@@ -22738,6 +25633,23 @@
<parameter name="cursor" type="android.database.Cursor">
</parameter>
</method>
+<method name="onQueryEntitiesComplete"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="token" type="int">
+</parameter>
+<parameter name="cookie" type="java.lang.Object">
+</parameter>
+<parameter name="iterator" type="android.content.EntityIterator">
+</parameter>
+</method>
<method name="onUpdateComplete"
return="void"
abstract="false"
@@ -22820,6 +25732,29 @@
<parameter name="orderBy" type="java.lang.String">
</parameter>
</method>
+<method name="startQueryEntities"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="token" type="int">
+</parameter>
+<parameter name="cookie" type="java.lang.Object">
+</parameter>
+<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="orderBy" type="java.lang.String">
+</parameter>
+</method>
<method name="startUpdate"
return="void"
abstract="false"
@@ -23445,6 +26380,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"
@@ -23564,6 +26514,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"
@@ -23682,6 +26647,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="setPathPermissions"
return="void"
abstract="false"
@@ -23740,6 +26724,695 @@
<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="isYieldAllowed"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="newAssertQuery"
+ 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>
+<method name="withYieldAllowed"
+ return="android.content.ContentProviderOperation.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="yieldAllowed" type="boolean">
+</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"
@@ -23843,6 +27516,66 @@
<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="addStatusChangeListener"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mask" type="int">
+</parameter>
+<parameter name="callback" type="android.content.SyncStatusObserver">
+</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"
@@ -23865,12 +27598,27 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="uri" type="android.net.Uri">
</parameter>
</method>
+<method name="cancelSync"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+</method>
<method name="delete"
return="int"
abstract="false"
@@ -23888,6 +27636,58 @@
<parameter name="selectionArgs" type="java.lang.String[]">
</parameter>
</method>
+<method name="getIsSyncable"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+</method>
+<method name="getMasterSyncAutomatically"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSyncAdapterTypes"
+ return="android.content.SyncAdapterType[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSyncAutomatically"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+</method>
<method name="getType"
return="java.lang.String"
abstract="false"
@@ -23916,6 +27716,36 @@
<parameter name="values" type="android.content.ContentValues">
</parameter>
</method>
+<method name="isSyncActive"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+</method>
+<method name="isSyncPending"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+</method>
<method name="notifyChange"
return="void"
abstract="false"
@@ -24050,6 +27880,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"
@@ -24067,6 +27918,83 @@
<parameter name="observer" type="android.database.ContentObserver">
</parameter>
</method>
+<method name="removeStatusChangeListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="handle" type="java.lang.Object">
+</parameter>
+</method>
+<method name="requestSync"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="extras" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="setIsSyncable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="syncable" type="int">
+</parameter>
+</method>
+<method name="setMasterSyncAutomatically"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sync" type="boolean">
+</parameter>
+</method>
+<method name="setSyncAutomatically"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="sync" type="boolean">
+</parameter>
+</method>
<method name="startSync"
return="void"
abstract="false"
@@ -24074,7 +28002,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="uri" type="android.net.Uri">
@@ -24189,7 +28117,7 @@
value="&quot;account&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -24222,6 +28150,28 @@
value="&quot;force&quot;"
static="true"
final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
+<field name="SYNC_EXTRAS_INITIALIZE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;initialize&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SYNC_EXTRAS_MANUAL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;force&quot;"
+ static="true"
+ final="true"
deprecated="not deprecated"
visibility="public"
>
@@ -24900,7 +28850,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<exception name="IOException" type="java.io.IOException">
@@ -25349,7 +29299,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -25360,7 +29310,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -25371,7 +29321,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -25523,7 +29473,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -25690,7 +29640,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="bitmap" type="android.graphics.Bitmap">
@@ -25705,7 +29655,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="data" type="java.io.InputStream">
@@ -25806,6 +29756,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"
@@ -25861,6 +29822,17 @@
visibility="public"
>
</field>
+<field name="BLUETOOTH_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;bluetooth&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="CLIPBOARD_SERVICE"
type="java.lang.String"
transient="false"
@@ -27298,6 +31270,199 @@
</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>
+<method name="reset"
+ 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>
+</interface>
<class name="Intent"
extends="java.lang.Object"
abstract="false"
@@ -29467,6 +33632,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"
@@ -30016,6 +34192,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"
@@ -31622,6 +35809,88 @@
</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>
+<constructor name="OperationApplicationException"
+ type="android.content.OperationApplicationException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="numSuccessfulYieldPoints" type="int">
+</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="numSuccessfulYieldPoints" type="int">
+</parameter>
+</constructor>
+<method name="getNumSuccessfulYieldPoints"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="ReceiverCallNotAllowedException"
extends="android.util.AndroidRuntimeException"
abstract="false"
@@ -32112,6 +36381,167 @@
</parameter>
</method>
</interface>
+<class name="SyncAdapterType"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<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>
+<parameter name="userVisible" type="boolean">
+</parameter>
+<parameter name="supportsUploading" type="boolean">
+</parameter>
+</constructor>
+<constructor name="SyncAdapterType"
+ type="android.content.SyncAdapterType"
+ 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="isUserVisible"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="newKey"
+ return="android.content.SyncAdapterType"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="authority" type="java.lang.String">
+</parameter>
+<parameter name="accountType" type="java.lang.String">
+</parameter>
+</method>
+<method name="supportsUploading"
+ return="boolean"
+ 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="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>
+<field name="isKey"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="SyncStatusObserver"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onStatusChanged"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="which" type="int">
+</parameter>
+</method>
+</interface>
<class name="UriMatcher"
extends="java.lang.Object"
abstract="false"
@@ -33326,6 +37756,134 @@
>
</field>
</class>
+<class name="FeatureInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="FeatureInfo"
+ type="android.content.pm.FeatureInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="FeatureInfo"
+ type="android.content.pm.FeatureInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="orig" type="android.content.pm.FeatureInfo">
+</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="getGlEsVersion"
+ return="java.lang.String"
+ 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="parcelableFlags" 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="FLAG_REQUIRED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="GL_ES_VERSION_UNDEFINED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="flags"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="name"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="reqGlEsVersion"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="InstrumentationInfo"
extends="android.content.pm.PackageItemInfo"
abstract="false"
@@ -33587,6 +38145,17 @@
visibility="public"
>
</field>
+<field name="reqFeatures"
+ type="android.content.pm.FeatureInfo[]"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="requestedPermissions"
type="java.lang.String[]"
transient="false"
@@ -33971,6 +38540,21 @@
<parameter name="pkg2" type="java.lang.String">
</parameter>
</method>
+<method name="checkSignatures"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid1" type="int">
+</parameter>
+<parameter name="uid2" type="int">
+</parameter>
+</method>
<method name="clearPackagePreferredActivities"
return="void"
abstract="true"
@@ -34182,6 +38766,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"
@@ -34428,6 +39025,17 @@
<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
</exception>
</method>
+<method name="getSystemAvailableFeatures"
+ return="android.content.pm.FeatureInfo[]"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSystemSharedLibraryNames"
return="java.lang.String[]"
abstract="true"
@@ -35570,7 +40178,7 @@
volatile="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -39384,6 +43992,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"
@@ -39397,6 +44031,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"
@@ -40477,6 +45124,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"
@@ -40492,6 +45169,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"
@@ -41687,6 +46379,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"
@@ -43395,6 +48102,19 @@
visibility="public"
>
</method>
+<method name="yieldIfContendedSafely"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sleepAfterYieldDelay" type="long">
+</parameter>
+</method>
<field name="CREATE_IF_NECESSARY"
type="int"
transient="false"
@@ -56128,6 +60848,21 @@
visibility="public"
>
</method>
+<method name="setGammaForText"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="blackGamma" type="float">
+</parameter>
+<parameter name="whiteGamma" type="float">
+</parameter>
+</method>
<field name="BOLD"
type="int"
transient="false"
@@ -57029,6 +61764,27 @@
<parameter name="srcName" type="java.lang.String">
</parameter>
</method>
+<method name="createFromResourceStream"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="res" type="android.content.res.Resources">
+</parameter>
+<parameter name="value" type="android.util.TypedValue">
+</parameter>
+<parameter name="is" type="java.io.InputStream">
+</parameter>
+<parameter name="srcName" type="java.lang.String">
+</parameter>
+<parameter name="opts" type="android.graphics.BitmapFactory.Options">
+</parameter>
+</method>
<method name="createFromStream"
return="android.graphics.drawable.Drawable"
abstract="false"
@@ -60038,6 +64794,19 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="setZoomCallback"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cb" type="android.hardware.Camera.ZoomCallback">
+</parameter>
+</method>
<method name="startPreview"
return="void"
abstract="false"
@@ -60077,6 +64846,25 @@
<parameter name="jpeg" type="android.hardware.Camera.PictureCallback">
</parameter>
</method>
+<method name="takePicture"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="shutter" type="android.hardware.Camera.ShutterCallback">
+</parameter>
+<parameter name="raw" type="android.hardware.Camera.PictureCallback">
+</parameter>
+<parameter name="postview" type="android.hardware.Camera.PictureCallback">
+</parameter>
+<parameter name="jpeg" type="android.hardware.Camera.PictureCallback">
+</parameter>
+</method>
<field name="CAMERA_ERROR_SERVER_DIED"
type="int"
transient="false"
@@ -60478,6 +65266,29 @@
>
</field>
</class>
+<interface name="Camera.ZoomCallback"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onZoomUpdate"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="zoomLevel" type="int">
+</parameter>
+<parameter name="camera" type="android.hardware.Camera">
+</parameter>
+</method>
+</interface>
<class name="GeomagneticField"
extends="java.lang.Object"
abstract="false"
@@ -65545,6 +70356,29 @@
</parameter>
</method>
</interface>
+<interface name="GpsStatus.NmeaListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onNmeaReceived"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timestamp" type="long">
+</parameter>
+<parameter name="nmea" type="java.lang.String">
+</parameter>
+</method>
+</interface>
<class name="Location"
extends="java.lang.Object"
abstract="false"
@@ -66148,6 +70982,19 @@
<parameter name="listener" type="android.location.GpsStatus.Listener">
</parameter>
</method>
+<method name="addNmeaListener"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.location.GpsStatus.NmeaListener">
+</parameter>
+</method>
<method name="addProximityAlert"
return="void"
abstract="false"
@@ -66358,6 +71205,19 @@
<parameter name="listener" type="android.location.GpsStatus.Listener">
</parameter>
</method>
+<method name="removeNmeaListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.location.GpsStatus.NmeaListener">
+</parameter>
+</method>
<method name="removeProximityAlert"
return="void"
abstract="false"
@@ -66842,7 +71702,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -66853,7 +71713,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -66864,7 +71724,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -66875,6 +71735,380 @@
value="3"
static="true"
final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_INVALID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_BACK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_BACK_PROCESSED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_FRONT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_FRONT_PROCESSED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_LEFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_LEFT_PROCESSED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_MONO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_PRESSURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1024"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_RIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_RIGHT_PROCESSED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="128"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_STEREO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_VOICE_DNLINK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32768"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_VOICE_UPLINK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16384"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_X_AXIS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2048"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_Y_AXIS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4096"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_IN_Z_AXIS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8192"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_5POINT1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="252"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_7POINT1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1020"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_BACK_CENTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1024"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_BACK_LEFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_BACK_RIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="128"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_FRONT_CENTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_FRONT_LEFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_FRONT_LEFT_OF_CENTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_FRONT_RIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_FRONT_RIGHT_OF_CENTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_LOW_FREQUENCY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_MONO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_QUAD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="204"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_STEREO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_OUT_SURROUND"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1052"
+ static="true"
+ final="true"
deprecated="not deprecated"
visibility="public"
>
@@ -66992,6 +72226,19 @@
visibility="public"
>
</method>
+<method name="getParameters"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keys" type="java.lang.String">
+</parameter>
+</method>
<method name="getRingerMode"
return="int"
abstract="false"
@@ -67110,6 +72357,17 @@
visibility="public"
>
</method>
+<method name="isWiredHeadsetOn"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="loadSoundEffects"
return="void"
abstract="false"
@@ -67156,7 +72414,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="on" type="boolean">
@@ -67201,6 +72459,19 @@
<parameter name="mode" type="int">
</parameter>
</method>
+<method name="setParameters"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyValuePairs" type="java.lang.String">
+</parameter>
+</method>
<method name="setRingerMode"
return="void"
abstract="false"
@@ -67306,6 +72577,19 @@
<parameter name="vibrateSetting" type="int">
</parameter>
</method>
+<method name="setWiredHeadsetOn"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="on" type="boolean">
+</parameter>
+</method>
<method name="shouldVibrate"
return="boolean"
abstract="false"
@@ -67678,7 +72962,7 @@
value="-1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67700,7 +72984,7 @@
value="16"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67711,7 +72995,7 @@
value="4"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67722,7 +73006,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67733,7 +73017,7 @@
value="8"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67744,7 +73028,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -67759,6 +73043,17 @@
visibility="public"
>
</field>
+<field name="STREAM_DTMF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="STREAM_MUSIC"
type="int"
transient="false"
@@ -69494,6 +74789,21 @@
visibility="public"
>
</method>
+<method name="invoke"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="request" type="android.os.Parcel">
+</parameter>
+<parameter name="reply" type="android.os.Parcel">
+</parameter>
+</method>
<method name="isLooping"
return="boolean"
abstract="false"
@@ -69516,6 +74826,17 @@
visibility="public"
>
</method>
+<method name="newRequest"
+ return="android.os.Parcel"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="pause"
return="void"
abstract="false"
@@ -69921,6 +75242,17 @@
visibility="public"
>
</field>
+<field name="MEDIA_INFO_METADATA_UPDATE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="802"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MEDIA_INFO_NOT_SEEKABLE"
type="int"
transient="false"
@@ -90140,6 +95472,17 @@
visibility="public"
>
</field>
+<field name="ECLAIR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10000"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="Bundle"
extends="java.lang.Object"
@@ -100567,7 +105910,7 @@
abstract="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="AUTHORITY"
@@ -100577,7 +105920,7 @@
value="&quot;contacts&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100587,7 +105930,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100598,7 +105941,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100609,7 +105952,7 @@
value="3"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100620,7 +105963,7 @@
value="4"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100631,7 +105974,7 @@
value="5"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100642,7 +105985,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100652,7 +105995,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -100668,7 +106011,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -100687,7 +106030,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="encodedString" type="java.lang.String">
@@ -100700,7 +106043,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="protocolString" type="java.lang.String">
@@ -100713,7 +106056,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="protocol" type="int">
@@ -100726,7 +106069,7 @@
synchronized="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -100745,7 +106088,7 @@
value="&quot;vnd.android.cursor.item/email&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100756,7 +106099,7 @@
value="&quot;vnd.android.cursor.dir/email&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100766,7 +106109,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100777,7 +106120,7 @@
value="&quot;vnd.android.cursor.item/jabber-im&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100788,7 +106131,7 @@
value="&quot;vnd.android.cursor.item/postal-address&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100799,7 +106142,7 @@
value="&quot;vnd.android.cursor.dir/postal-address&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100810,7 +106153,7 @@
value="&quot;vnd.android.cursor.dir/contact-methods&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100820,7 +106163,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100831,7 +106174,7 @@
value="&quot;name ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100842,7 +106185,7 @@
value="&quot;person&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100853,7 +106196,7 @@
value="&quot;data&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100864,7 +106207,7 @@
value="&quot;aux_data&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100875,7 +106218,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100886,7 +106229,7 @@
value="5"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100897,7 +106240,7 @@
value="6"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100908,7 +106251,7 @@
value="7"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100919,7 +106262,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100930,7 +106273,7 @@
value="4"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100941,7 +106284,7 @@
value="3"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100952,7 +106295,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100961,7 +106304,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="AUX_DATA"
@@ -100971,7 +106314,7 @@
value="&quot;aux_data&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100982,7 +106325,7 @@
value="&quot;data&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -100993,7 +106336,7 @@
value="&quot;isprimary&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101004,7 +106347,7 @@
value="&quot;kind&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101015,7 +106358,7 @@
value="&quot;label&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101026,7 +106369,7 @@
value="&quot;type&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101037,7 +106380,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101048,7 +106391,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101059,7 +106402,7 @@
value="3"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101070,7 +106413,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101080,7 +106423,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -101094,7 +106437,7 @@
value="&quot;vnd.android.cursor.item/contact_extensions&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101105,7 +106448,7 @@
value="&quot;vnd.android.cursor.dir/contact_extensions&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101115,7 +106458,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101126,7 +106469,7 @@
value="&quot;person, name ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101137,7 +106480,7 @@
value="&quot;person&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101146,7 +106489,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="NAME"
@@ -101156,7 +106499,7 @@
value="&quot;name&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101167,7 +106510,7 @@
value="&quot;value&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101177,7 +106520,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -101191,7 +106534,7 @@
value="&quot;groupmembership&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101202,7 +106545,7 @@
value="&quot;vnd.android.cursor.item/contactsgroupmembership&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101213,7 +106556,7 @@
value="&quot;vnd.android.cursor.dir/contactsgroupmembership&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101223,7 +106566,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101234,7 +106577,7 @@
value="&quot;group_id ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101245,7 +106588,7 @@
value="&quot;group_id&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101256,7 +106599,18 @@
value="&quot;group_sync_account&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
+ 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="deprecated"
visibility="public"
>
</field>
@@ -101267,7 +106621,7 @@
value="&quot;group_sync_id&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101278,7 +106632,7 @@
value="&quot;person&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101288,7 +106642,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101298,7 +106652,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -101312,7 +106666,7 @@
value="&quot;vnd.android.cursor.item/contactsgroup&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101323,7 +106677,7 @@
value="&quot;vnd.android.cursor.dir/contactsgroup&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101333,7 +106687,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101344,7 +106698,7 @@
value="&quot;name ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101354,7 +106708,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101365,7 +106719,7 @@
value="&quot;Starred in Android&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101376,7 +106730,7 @@
value="&quot;Contacts&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101385,7 +106739,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="NAME"
@@ -101395,7 +106749,7 @@
value="&quot;name&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101406,7 +106760,7 @@
value="&quot;notes&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101417,7 +106771,7 @@
value="&quot;should_sync&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101428,7 +106782,7 @@
value="&quot;system_id&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101438,14 +106792,14 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="Contacts.Intents"
type="android.provider.Contacts.Intents"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</constructor>
@@ -101456,7 +106810,7 @@
value="&quot;com.android.contacts.action.ATTACH_IMAGE&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101467,7 +106821,7 @@
value="&quot;com.android.contacts.action.CREATE_DESCRIPTION&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101478,7 +106832,7 @@
value="&quot;com.android.contacts.action.FORCE_CREATE&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101489,7 +106843,7 @@
value="&quot;android.provider.Contacts.SEARCH_SUGGESTION_CLICKED&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101500,7 +106854,7 @@
value="&quot;android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101511,7 +106865,7 @@
value="&quot;android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101522,7 +106876,7 @@
value="&quot;com.android.contacts.action.SHOW_OR_CREATE_CONTACT&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101532,14 +106886,14 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="Contacts.Intents.Insert"
type="android.provider.Contacts.Intents.Insert"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</constructor>
@@ -101550,7 +106904,7 @@
value="&quot;android.intent.action.INSERT&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101561,7 +106915,7 @@
value="&quot;company&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101572,7 +106926,7 @@
value="&quot;email&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101583,7 +106937,7 @@
value="&quot;email_isprimary&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101594,7 +106948,7 @@
value="&quot;email_type&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101605,7 +106959,7 @@
value="&quot;full_mode&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101616,7 +106970,7 @@
value="&quot;im_handle&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101627,7 +106981,7 @@
value="&quot;im_isprimary&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101638,7 +106992,7 @@
value="&quot;im_protocol&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101649,7 +107003,7 @@
value="&quot;job_title&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101660,7 +107014,7 @@
value="&quot;name&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101671,7 +107025,7 @@
value="&quot;notes&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101682,7 +107036,7 @@
value="&quot;phone&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101693,7 +107047,7 @@
value="&quot;phonetic_name&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101704,7 +107058,7 @@
value="&quot;phone_isprimary&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101715,7 +107069,7 @@
value="&quot;phone_type&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101726,7 +107080,7 @@
value="&quot;postal&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101737,7 +107091,7 @@
value="&quot;postal_isprimary&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101748,7 +107102,7 @@
value="&quot;postal_type&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101759,7 +107113,7 @@
value="&quot;secondary_email&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101770,7 +107124,7 @@
value="&quot;secondary_email_type&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101781,7 +107135,7 @@
value="&quot;secondary_phone&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101792,7 +107146,7 @@
value="&quot;secondary_phone_type&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101803,7 +107157,7 @@
value="&quot;tertiary_email&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101814,7 +107168,7 @@
value="&quot;tertiary_email_type&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101825,7 +107179,7 @@
value="&quot;tertiary_phone&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101836,7 +107190,7 @@
value="&quot;tertiary_phone_type&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101846,14 +107200,14 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="Contacts.Intents.UI"
type="android.provider.Contacts.Intents.UI"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</constructor>
@@ -101864,7 +107218,7 @@
value="&quot;com.android.contacts.action.FILTER_CONTACTS&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101875,7 +107229,7 @@
value="&quot;com.android.contacts.extra.FILTER_TEXT&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101886,7 +107240,7 @@
value="&quot;com.android.contacts.extra.GROUP&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101897,7 +107251,7 @@
value="&quot;com.android.contacts.action.LIST_ALL_CONTACTS&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101908,7 +107262,7 @@
value="&quot;com.android.contacts.action.LIST_CONTACTS_WITH_PHONES&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101919,7 +107273,7 @@
value="&quot;com.android.contacts.action.LIST_DEFAULT&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101930,7 +107284,7 @@
value="&quot;com.android.contacts.action.LIST_FREQUENT&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101941,7 +107295,7 @@
value="&quot;com.android.contacts.action.LIST_GROUP&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101952,7 +107306,7 @@
value="&quot;com.android.contacts.action.LIST_STARRED&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101963,7 +107317,7 @@
value="&quot;com.android.contacts.action.LIST_STREQUENT&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101974,7 +107328,7 @@
value="&quot;com.android.contacts.extra.TITLE_EXTRA&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -101983,7 +107337,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="COMPANY"
@@ -101993,7 +107347,7 @@
value="&quot;company&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102004,7 +107358,7 @@
value="&quot;isprimary&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102015,7 +107369,7 @@
value="&quot;label&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102026,7 +107380,7 @@
value="&quot;person&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102037,7 +107391,7 @@
value="&quot;title&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102048,7 +107402,7 @@
value="&quot;type&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102059,7 +107413,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102070,7 +107424,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102081,7 +107435,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102091,7 +107445,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -102105,7 +107459,7 @@
synchronized="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -102122,7 +107476,7 @@
value="&quot;organizations&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102132,7 +107486,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102143,7 +107497,7 @@
value="&quot;company, title, isprimary ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102153,7 +107507,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -102171,7 +107525,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -102188,7 +107542,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -102205,7 +107559,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -102220,7 +107574,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -102235,7 +107589,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -102254,7 +107608,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -102269,7 +107623,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="cr" type="android.content.ContentResolver">
@@ -102284,7 +107638,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="resolver" type="android.content.ContentResolver">
@@ -102299,7 +107653,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="cr" type="android.content.ContentResolver">
@@ -102315,7 +107669,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102326,7 +107680,7 @@
value="&quot;vnd.android.cursor.item/person&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102337,7 +107691,7 @@
value="&quot;vnd.android.cursor.dir/person&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102347,7 +107701,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102358,7 +107712,7 @@
value="&quot;name ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102368,7 +107722,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102379,7 +107733,7 @@
value="&quot;primary_email&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102390,7 +107744,7 @@
value="&quot;primary_organization&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102401,7 +107755,7 @@
value="&quot;primary_phone&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102411,7 +107765,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -102427,7 +107781,7 @@
value="&quot;contact_methods&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102438,7 +107792,7 @@
value="&quot;data ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102448,7 +107802,7 @@
abstract="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -102462,7 +107816,7 @@
value="&quot;extensions&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102473,7 +107827,7 @@
value="&quot;name ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102484,7 +107838,7 @@
value="&quot;person&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102494,7 +107848,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -102510,7 +107864,7 @@
value="&quot;phones&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102521,7 +107875,7 @@
value="&quot;number ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102530,7 +107884,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="CUSTOM_RINGTONE"
@@ -102540,7 +107894,7 @@
value="&quot;custom_ringtone&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102551,7 +107905,7 @@
value="&quot;display_name&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102562,7 +107916,7 @@
value="&quot;last_time_contacted&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102573,7 +107927,7 @@
value="&quot;name&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102584,7 +107938,7 @@
value="&quot;notes&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102595,7 +107949,7 @@
value="&quot;phonetic_name&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102606,7 +107960,7 @@
value="&quot;photo_version&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102617,7 +107971,7 @@
value="&quot;send_to_voicemail&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102628,7 +107982,7 @@
value="&quot;starred&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102639,7 +107993,7 @@
value="&quot;times_contacted&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102649,7 +108003,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -102665,7 +108019,7 @@
synchronized="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -102684,7 +108038,7 @@
synchronized="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -102700,7 +108054,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102711,7 +108065,7 @@
value="&quot;vnd.android.cursor.item/phone&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102722,7 +108076,7 @@
value="&quot;vnd.android.cursor.dir/phone&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102732,7 +108086,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102743,7 +108097,7 @@
value="&quot;name ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102754,7 +108108,7 @@
value="&quot;person&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102763,7 +108117,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="ISPRIMARY"
@@ -102773,7 +108127,7 @@
value="&quot;isprimary&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102784,7 +108138,7 @@
value="&quot;label&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102795,7 +108149,7 @@
value="&quot;number&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102806,7 +108160,7 @@
value="&quot;number_key&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102817,7 +108171,7 @@
value="&quot;type&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102828,7 +108182,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102839,7 +108193,7 @@
value="5"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102850,7 +108204,7 @@
value="4"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102861,7 +108215,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102872,7 +108226,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102883,7 +108237,7 @@
value="7"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102894,7 +108248,7 @@
value="6"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102905,7 +108259,7 @@
value="3"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102915,7 +108269,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -102929,7 +108283,7 @@
value="&quot;photo&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102939,7 +108293,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102950,7 +108304,7 @@
value="&quot;person ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102959,7 +108313,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="DATA"
@@ -102969,7 +108323,7 @@
value="&quot;data&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102980,7 +108334,7 @@
value="&quot;download_required&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -102991,7 +108345,7 @@
value="&quot;exists_on_server&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103002,7 +108356,7 @@
value="&quot;local_version&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103013,7 +108367,7 @@
value="&quot;person&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103024,7 +108378,7 @@
value="&quot;sync_error&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103033,7 +108387,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="IM_ACCOUNT"
@@ -103043,7 +108397,7 @@
value="&quot;im_account&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103054,7 +108408,7 @@
value="&quot;im_handle&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103065,7 +108419,7 @@
value="&quot;im_protocol&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103075,7 +108429,7 @@
abstract="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<implements name="android.provider.BaseColumns">
@@ -103089,7 +108443,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="cr" type="android.content.ContentResolver">
@@ -103106,7 +108460,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="cr" type="android.content.ContentResolver">
@@ -103125,7 +108479,7 @@
value="&quot;settings&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103135,7 +108489,7 @@
volatile="false"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103146,7 +108500,7 @@
value="&quot;key ASC&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103157,7 +108511,7 @@
value="&quot;syncEverything&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103166,7 +108520,7 @@
abstract="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<field name="KEY"
@@ -103176,7 +108530,7 @@
value="&quot;key&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103187,7 +108541,7 @@
value="&quot;value&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -103198,7 +108552,18 @@
value="&quot;_sync_account&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
+ 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="deprecated"
visibility="public"
>
</field>
@@ -107209,6 +112574,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"
@@ -107329,6 +112705,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"
@@ -108252,6 +113638,170 @@
>
</field>
</class>
+<class name="SyncStateContract"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SyncStateContract"
+ type="android.provider.SyncStateContract"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+</class>
+<interface name="SyncStateContract.Columns"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.BaseColumns">
+</implements>
+<field name="ACCOUNT_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;account_name&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACCOUNT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;account_type&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;data&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</interface>
+<class name="SyncStateContract.Constants"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.SyncStateContract.Columns">
+</implements>
+<constructor name="SyncStateContract.Constants"
+ type="android.provider.SyncStateContract.Constants"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="CONTENT_DIRECTORY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;syncstate&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="SyncStateContract.Helpers"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SyncStateContract.Helpers"
+ type="android.provider.SyncStateContract.Helpers"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="get"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="android.content.ContentProviderClient">
+</parameter>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+<method name="newSetOperation"
+ return="android.content.ContentProviderOperation"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="data" type="byte[]">
+</parameter>
+</method>
+<method name="set"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="android.content.ContentProviderClient">
+</parameter>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="account" type="android.accounts.Account">
+</parameter>
+<parameter name="data" type="byte[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
+</class>
<class name="UserDictionary"
extends="java.lang.Object"
abstract="false"
@@ -110368,7 +115918,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="asu" type="int">
@@ -113455,6 +119005,19 @@
synchronized="false"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="instrumentation" type="android.app.Instrumentation">
+</parameter>
+</method>
+<method name="setInstrumentation"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -113704,6 +119267,19 @@
synchronized="false"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="instrumentation" type="android.app.Instrumentation">
+</parameter>
+</method>
+<method name="injectInstrumentation"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -115200,7 +120776,7 @@
>
<parameter name="uri" type="android.net.Uri">
</parameter>
-<parameter name="account" type="java.lang.String">
+<parameter name="accountName" type="java.lang.String">
</parameter>
<parameter name="authority" type="java.lang.String">
</parameter>
@@ -117216,6 +122792,21 @@
<parameter name="pkg2" type="java.lang.String">
</parameter>
</method>
+<method name="checkSignatures"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uid1" type="int">
+</parameter>
+<parameter name="uid2" type="int">
+</parameter>
+</method>
<method name="clearPackagePreferredActivities"
return="void"
abstract="false"
@@ -117427,6 +123018,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"
@@ -117656,6 +123260,17 @@
<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
</exception>
</method>
+<method name="getSystemAvailableFeatures"
+ return="android.content.pm.FeatureInfo[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSystemSharedLibraryNames"
return="java.lang.String[]"
abstract="false"
@@ -122715,6 +128330,16 @@
visibility="public"
>
</field>
+<field name="density"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="drawableState"
type="int[]"
transient="false"
@@ -123926,6 +129551,27 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="formatDateRange"
+ return="java.util.Formatter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="formatter" type="java.util.Formatter">
+</parameter>
+<parameter name="startMillis" type="long">
+</parameter>
+<parameter name="endMillis" type="long">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
<method name="formatDateTime"
return="java.lang.String"
abstract="false"
@@ -127692,6 +133338,18 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="size" type="int">
+</parameter>
+<parameter name="dip" type="boolean">
+</parameter>
+</constructor>
+<constructor name="AbsoluteSizeSpan"
+ type="android.text.style.AbsoluteSizeSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="src" type="android.os.Parcel">
</parameter>
</constructor>
@@ -127706,6 +133364,17 @@
visibility="public"
>
</method>
+<method name="getDip"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSize"
return="int"
abstract="false"
@@ -129096,6 +134765,41 @@
</parameter>
</method>
</interface>
+<interface name="LineHeightSpan.WithDensity"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.text.style.LineHeightSpan">
+</implements>
+<method name="chooseHeight"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="java.lang.CharSequence">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+<parameter name="spanstartv" type="int">
+</parameter>
+<parameter name="v" type="int">
+</parameter>
+<parameter name="fm" type="android.graphics.Paint.FontMetricsInt">
+</parameter>
+<parameter name="paint" type="android.text.TextPaint">
+</parameter>
+</method>
+</interface>
<class name="MaskFilterSpan"
extends="android.text.style.CharacterStyle"
abstract="false"
@@ -132387,6 +138091,62 @@
>
</method>
</class>
+<class name="Pair"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Pair"
+ type="android.util.Pair"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="first" type="F">
+</parameter>
+<parameter name="second" type="S">
+</parameter>
+</constructor>
+<method name="create"
+ return="android.util.Pair&lt;A, B&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="a" type="A">
+</parameter>
+<parameter name="b" type="B">
+</parameter>
+</method>
+<field name="first"
+ type="F"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="second"
+ type="S"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="PrintStreamPrinter"
extends="java.lang.Object"
abstract="false"
@@ -135357,6 +141117,17 @@
visibility="public"
>
</field>
+<field name="VIRTUAL_KEY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="InflateException"
extends="java.lang.RuntimeException"
@@ -136197,6 +141968,17 @@
visibility="public"
>
</method>
+<method name="isCanceled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isModifierKey"
return="boolean"
abstract="false"
@@ -136312,6 +142094,17 @@
visibility="public"
>
</field>
+<field name="FLAG_CANCELED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_EDITOR_ACTION"
type="int"
transient="false"
@@ -136356,6 +142149,17 @@
visibility="public"
>
</field>
+<field name="FLAG_VIRTUAL_HARD_KEY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_WOKE_HERE"
type="int"
transient="false"
@@ -138719,6 +144523,19 @@
visibility="public"
>
</method>
+<method name="findPointerIndex"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerId" type="int">
+</parameter>
+</method>
<method name="getAction"
return="int"
abstract="false"
@@ -138800,6 +144617,34 @@
<parameter name="pos" type="int">
</parameter>
</method>
+<method name="getHistoricalPressure"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalSize"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pos" type="int">
+</parameter>
+</method>
<method name="getHistoricalSize"
return="float"
abstract="false"
@@ -138810,6 +144655,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="pointerIndex" type="int">
+</parameter>
<parameter name="pos" type="int">
</parameter>
</method>
@@ -138826,6 +144673,21 @@
<parameter name="pos" type="int">
</parameter>
</method>
+<method name="getHistoricalX"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
<method name="getHistoricalY"
return="float"
abstract="false"
@@ -138839,6 +144701,21 @@
<parameter name="pos" type="int">
</parameter>
</method>
+<method name="getHistoricalY"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
<method name="getHistorySize"
return="int"
abstract="false"
@@ -138861,6 +144738,30 @@
visibility="public"
>
</method>
+<method name="getPointerCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPointerId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
<method name="getPressure"
return="float"
abstract="false"
@@ -138872,6 +144773,19 @@
visibility="public"
>
</method>
+<method name="getPressure"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
<method name="getRawX"
return="float"
abstract="false"
@@ -138905,6 +144819,19 @@
visibility="public"
>
</method>
+<method name="getSize"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
<method name="getX"
return="float"
abstract="false"
@@ -138916,6 +144843,19 @@
visibility="public"
>
</method>
+<method name="getX"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
<method name="getXPrecision"
return="float"
abstract="false"
@@ -138938,6 +144878,19 @@
visibility="public"
>
</method>
+<method name="getY"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
<method name="getYPrecision"
return="float"
abstract="false"
@@ -139000,6 +144953,43 @@
</parameter>
<parameter name="action" type="int">
</parameter>
+<parameter name="pointers" type="int">
+</parameter>
+<parameter name="x" type="float">
+</parameter>
+<parameter name="y" type="float">
+</parameter>
+<parameter name="pressure" type="float">
+</parameter>
+<parameter name="size" type="float">
+</parameter>
+<parameter name="metaState" type="int">
+</parameter>
+<parameter name="xPrecision" type="float">
+</parameter>
+<parameter name="yPrecision" type="float">
+</parameter>
+<parameter name="deviceId" type="int">
+</parameter>
+<parameter name="edgeFlags" type="int">
+</parameter>
+</method>
+<method name="obtain"
+ return="android.view.MotionEvent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="downTime" type="long">
+</parameter>
+<parameter name="eventTime" type="long">
+</parameter>
+<parameter name="action" type="int">
+</parameter>
<parameter name="x" type="float">
</parameter>
<parameter name="y" type="float">
@@ -139020,6 +145010,19 @@
<parameter name="o" type="android.view.MotionEvent">
</parameter>
</method>
+<method name="obtainNoHistory"
+ return="android.view.MotionEvent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="android.view.MotionEvent">
+</parameter>
+</method>
<method name="offsetLocation"
return="void"
abstract="false"
@@ -139124,6 +145127,17 @@
visibility="public"
>
</field>
+<field name="ACTION_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="255"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_MOVE"
type="int"
transient="false"
@@ -139146,6 +145160,116 @@
visibility="public"
>
</field>
+<field name="ACTION_POINTER_1_DOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_1_UP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_2_DOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="261"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_2_UP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="262"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_3_DOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="517"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_3_UP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="518"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_DOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_ID_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="65280"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_ID_SHIFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_POINTER_UP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_UP"
type="int"
transient="false"
@@ -139675,6 +145799,8 @@
>
<parameter name="dirty" type="android.graphics.Rect">
</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
<exception name="Surface.OutOfResourcesException" type="android.view.Surface.OutOfResourcesException">
</exception>
</method>
@@ -139946,7 +146072,7 @@
value="40"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -139957,7 +146083,7 @@
value="16"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -140307,7 +146433,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -140318,7 +146444,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -148960,6 +155086,17 @@
<parameter name="event" type="android.view.MotionEvent">
</parameter>
</method>
+<method name="onAttachedToWindow"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onContentChanged"
return="void"
abstract="true"
@@ -148999,6 +155136,17 @@
<parameter name="featureId" type="int">
</parameter>
</method>
+<method name="onDetachedFromWindow"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onMenuItemSelected"
return="boolean"
abstract="true"
@@ -149616,6 +155764,28 @@
visibility="public"
>
</field>
+<field name="FLAG_SHOW_WALLPAPER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_SHOW_WHEN_LOCKED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="524288"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_TOUCHABLE_WHEN_WAKING"
type="int"
transient="false"
@@ -149711,7 +155881,7 @@
value="2"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -149722,7 +155892,7 @@
value="1"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -150166,6 +156336,17 @@
visibility="public"
>
</field>
+<field name="TYPE_WALLPAPER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2013"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="alpha"
type="float"
transient="false"
@@ -156602,6 +162783,29 @@
<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="estimatedSize" type="long">
+</parameter>
+<parameter name="totalUsedQuota" type="long">
+</parameter>
+<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
+</parameter>
+</method>
<method name="onFormResubmission"
return="void"
abstract="false"
@@ -157423,14 +163627,14 @@
abstract="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="Plugin"
type="android.webkit.Plugin"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="name" type="java.lang.String">
@@ -157449,7 +163653,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -157462,7 +163666,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157473,7 +163677,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157484,7 +163688,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157495,7 +163699,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157506,7 +163710,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="handler" type="android.webkit.Plugin.PreferencesClickHandler">
@@ -157519,7 +163723,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="description" type="java.lang.String">
@@ -157532,7 +163736,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="fileName" type="java.lang.String">
@@ -157545,7 +163749,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="name" type="java.lang.String">
@@ -157558,7 +163762,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="path" type="java.lang.String">
@@ -157591,14 +163795,14 @@
abstract="false"
static="false"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="PluginData"
type="android.webkit.PluginData"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="stream" type="java.io.InputStream">
@@ -157617,7 +163821,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157628,7 +163832,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157639,7 +163843,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157650,7 +163854,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157660,14 +163864,14 @@
abstract="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="PluginList"
type="android.webkit.PluginList"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</constructor>
@@ -157678,7 +163882,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="plugin" type="android.webkit.Plugin">
@@ -157691,7 +163895,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157702,7 +163906,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -157713,7 +163917,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="context" type="android.content.Context">
@@ -157728,7 +163932,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="plugin" type="android.webkit.Plugin">
@@ -158005,7 +164209,7 @@
abstract="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<method name="getPluginData"
@@ -158015,7 +164219,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="url" type="java.lang.String">
@@ -158044,7 +164248,7 @@
abstract="false"
static="false"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<constructor name="UrlInterceptRegistry"
@@ -158062,7 +164266,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="url" type="java.lang.String">
@@ -158092,7 +164296,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="handler" type="android.webkit.UrlInterceptHandler">
@@ -158105,7 +164309,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="disabled" type="boolean">
@@ -158118,7 +164322,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="handler" type="android.webkit.UrlInterceptHandler">
@@ -158131,7 +164335,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -158243,6 +164447,29 @@
<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="estimatedSize" type="long">
+</parameter>
+<parameter name="totalUsedQuota" type="long">
+</parameter>
+<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
+</parameter>
+</method>
<method name="onJsAlert"
return="boolean"
abstract="false"
@@ -158628,6 +164855,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"
@@ -158866,7 +165115,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -158968,6 +165217,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"
@@ -159300,7 +165575,7 @@
synchronized="true"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="use" type="boolean">
@@ -159522,6 +165797,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"
@@ -160018,7 +166331,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -160289,7 +166602,7 @@
visibility="public"
>
</method>
-<method name="refreshPlugins"
+<method name="postUrl"
return="void"
abstract="false"
native="false"
@@ -160299,6 +166612,21 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="postData" type="byte[]">
+</parameter>
+</method>
+<method name="refreshPlugins"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
<parameter name="reloadOpenPages" type="boolean">
</parameter>
</method>
@@ -163625,6 +169953,17 @@
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="getDropDownHeight"
return="int"
abstract="false"
@@ -163636,6 +169975,28 @@
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"
@@ -163859,6 +170220,32 @@
<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="setDropDownHeight"
return="void"
abstract="false"
@@ -163872,6 +170259,32 @@
<parameter name="height" 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"
@@ -169636,6 +176049,39 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="canPause"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekBackward"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekForward"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getBufferPercentage"
return="int"
abstract="true"
@@ -173572,6 +180018,30 @@
<parameter name="isExpanded" type="boolean">
</parameter>
</method>
+<method name="getViewBinder"
+ return="android.widget.SimpleCursorTreeAdapter.ViewBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setViewBinder"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewBinder" type="android.widget.SimpleCursorTreeAdapter.ViewBinder">
+</parameter>
+</method>
<method name="setViewImage"
return="void"
abstract="false"
@@ -173587,7 +180057,47 @@
<parameter name="value" type="java.lang.String">
</parameter>
</method>
+<method name="setViewText"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="v" type="android.widget.TextView">
+</parameter>
+<parameter name="text" type="java.lang.String">
+</parameter>
+</method>
</class>
+<interface name="SimpleCursorTreeAdapter.ViewBinder"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="setViewValue"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="cursor" type="android.database.Cursor">
+</parameter>
+<parameter name="columnIndex" type="int">
+</parameter>
+</method>
+</interface>
<class name="SimpleExpandableListAdapter"
extends="android.widget.BaseExpandableListAdapter"
abstract="false"
@@ -177900,6 +184410,39 @@
<parameter name="defStyle" type="int">
</parameter>
</constructor>
+<method name="canPause"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekBackward"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="canSeekForward"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getBufferPercentage"
return="int"
abstract="false"
@@ -186532,7 +193075,7 @@
<method name="valid"
return="boolean"
abstract="false"
- native="true"
+ native="false"
synchronized="false"
static="false"
final="false"
@@ -191655,7 +198198,7 @@
return="java.nio.channels.FileChannel"
abstract="false"
native="false"
- synchronized="false"
+ synchronized="true"
static="false"
final="true"
deprecated="not deprecated"
@@ -200525,7 +207068,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="i" type="int">
+<parameter name="value" type="int">
</parameter>
</method>
<method name="toString"
@@ -201325,10 +207868,10 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="y" type="double">
-</parameter>
<parameter name="x" type="double">
</parameter>
+<parameter name="y" type="double">
+</parameter>
</method>
<method name="cbrt"
return="double"
@@ -257911,7 +264454,7 @@
</parameter>
<parameter name="buffer" type="java.lang.StringBuffer">
</parameter>
-<parameter name="field" type="java.text.FieldPosition">
+<parameter name="fieldPos" type="java.text.FieldPosition">
</parameter>
</method>
<method name="get2DigitYearStart"
@@ -266685,7 +273228,7 @@
return="void"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -266698,7 +273241,7 @@
return="void"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -266709,7 +273252,7 @@
return="int"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -266744,7 +273287,7 @@
return="boolean"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -266779,7 +273322,7 @@
return="void"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -269124,7 +275667,7 @@
return="E"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -269580,6 +276123,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="name" type="java.lang.String">
+</parameter>
<parameter name="isDaemon" type="boolean">
</parameter>
</constructor>
@@ -269590,6 +276135,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="name" type="java.lang.String">
+</parameter>
</constructor>
<constructor name="Timer"
type="java.util.Timer"
@@ -269598,8 +276145,6 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="name" type="java.lang.String">
-</parameter>
<parameter name="isDaemon" type="boolean">
</parameter>
</constructor>
@@ -269610,8 +276155,6 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="name" type="java.lang.String">
-</parameter>
</constructor>
<method name="cancel"
return="void"
@@ -270490,7 +277033,7 @@
return="E"
abstract="false"
native="false"
- synchronized="true"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -270970,7 +277513,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -270983,7 +277526,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -271041,7 +277584,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -271101,7 +277644,20 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
+</parameter>
+</method>
+<method name="contains"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="drainTo"
@@ -271142,7 +277698,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -271155,7 +277711,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -271191,7 +277747,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -271207,6 +277763,19 @@
visibility="public"
>
</method>
+<method name="remove"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
<method name="take"
return="E"
abstract="true"
@@ -271424,7 +277993,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="java.util.Map&lt;? extends K, ? extends V&gt;">
+<parameter name="m" type="java.util.Map&lt;? extends K, ? extends V&gt;">
</parameter>
</constructor>
<method name="contains"
@@ -271587,7 +278156,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
@@ -271737,7 +278306,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="array" type="E[]">
+<parameter name="toCopyIn" type="E[]">
</parameter>
</constructor>
<method name="add"
@@ -271765,7 +278334,7 @@
>
<parameter name="index" type="int">
</parameter>
-<parameter name="e" type="E">
+<parameter name="element" type="E">
</parameter>
</method>
<method name="addAll"
@@ -271893,9 +278462,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="e" type="E">
-</parameter>
-<parameter name="index" type="int">
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="indexOf"
@@ -271908,7 +278475,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="java.lang.Object">
+<parameter name="e" type="E">
+</parameter>
+<parameter name="index" type="int">
</parameter>
</method>
<method name="isEmpty"
@@ -271943,9 +278512,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="e" type="E">
-</parameter>
-<parameter name="index" type="int">
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="lastIndexOf"
@@ -271958,7 +278525,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="java.lang.Object">
+<parameter name="e" type="E">
+</parameter>
+<parameter name="index" type="int">
</parameter>
</method>
<method name="listIterator"
@@ -272049,7 +278618,7 @@
>
<parameter name="index" type="int">
</parameter>
-<parameter name="e" type="E">
+<parameter name="element" type="E">
</parameter>
</method>
<method name="size"
@@ -272413,7 +278982,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -272426,7 +278995,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -272454,12 +279023,6 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="time" type="long">
-</parameter>
-<parameter name="unit" type="java.util.concurrent.TimeUnit">
-</parameter>
-<exception name="InterruptedException" type="java.lang.InterruptedException">
-</exception>
</method>
<method name="poll"
return="E"
@@ -272471,6 +279034,12 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="timeout" type="long">
+</parameter>
+<parameter name="unit" type="java.util.concurrent.TimeUnit">
+</parameter>
+<exception name="InterruptedException" type="java.lang.InterruptedException">
+</exception>
</method>
<method name="put"
return="void"
@@ -272482,7 +279051,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="remainingCapacity"
@@ -273553,7 +280122,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -273572,7 +280141,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
@@ -273624,7 +280193,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<exception name="InterruptedException" type="java.lang.InterruptedException">
</exception>
@@ -273777,7 +280346,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="offer"
@@ -273790,7 +280359,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
<parameter name="timeout" type="long">
</parameter>
@@ -273846,7 +280415,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="remainingCapacity"
@@ -274576,7 +281145,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
@@ -275281,7 +281850,7 @@
extends="java.lang.Enum"
abstract="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -275295,9 +281864,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="duration" type="long">
+<parameter name="sourceDuration" type="long">
</parameter>
-<parameter name="unit" type="java.util.concurrent.TimeUnit">
+<parameter name="sourceUnit" type="java.util.concurrent.TimeUnit">
</parameter>
</method>
<method name="sleep"
@@ -277333,12 +283902,55 @@
</package>
<package name="java.util.concurrent.locks"
>
-<class name="AbstractQueuedSynchronizer"
+<class name="AbstractOwnableSynchronizer"
extends="java.lang.Object"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
+ visibility=""
+>
+<implements name="java.io.Serializable">
+</implements>
+<constructor name="AbstractOwnableSynchronizer"
+ type="java.util.concurrent.locks.AbstractOwnableSynchronizer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</constructor>
+<method name="getExclusiveOwnerThread"
+ return="java.lang.Thread"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="setExclusiveOwnerThread"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="t" type="java.lang.Thread">
+</parameter>
+</method>
+</class>
+<class name="AbstractQueuedSynchronizer"
+ extends="java.util.concurrent.locks.AbstractOwnableSynchronizer"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
visibility="public"
>
<implements name="java.io.Serializable">
@@ -284906,7 +291518,11 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="val" type="int">
+<parameter name="buf" type="byte[]">
+</parameter>
+<parameter name="off" type="int">
+</parameter>
+<parameter name="nbytes" type="int">
</parameter>
</method>
<method name="update"
@@ -284919,11 +291535,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="buf" type="byte[]">
-</parameter>
-<parameter name="off" type="int">
-</parameter>
-<parameter name="nbytes" type="int">
+<parameter name="val" type="int">
</parameter>
</method>
</interface>
@@ -303751,7 +310363,7 @@
return="javax.net.ServerSocketFactory"
abstract="false"
native="false"
- synchronized="false"
+ synchronized="true"
static="true"
final="false"
deprecated="not deprecated"
@@ -304541,7 +311153,7 @@
return="javax.net.SocketFactory"
abstract="false"
native="false"
- synchronized="false"
+ synchronized="true"
static="true"
final="false"
deprecated="not deprecated"
diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk
index 96cc512..ecaebff 100644
--- a/camera/libcameraservice/Android.mk
+++ b/camera/libcameraservice/Android.mk
@@ -25,6 +25,10 @@ LOCAL_SRC_FILES:= \
LOCAL_MODULE:= libcamerastub
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_CFLAGS += -DSINGLE_PROCESS
+endif
+
LOCAL_SHARED_LIBRARIES:= libui
include $(BUILD_STATIC_LIBRARY)
@@ -42,12 +46,17 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES:= \
libui \
libutils \
+ libbinder \
libcutils \
libmedia
LOCAL_MODULE:= libcameraservice
-LOCAL_CFLAGS+=-DLOG_TAG=\"CameraService\"
+LOCAL_CFLAGS += -DLOG_TAG=\"CameraService\"
+
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_CFLAGS += -DSINGLE_PROCESS
+endif
ifeq ($(USE_CAMERA_STUB), true)
LOCAL_STATIC_LIBRARIES += libcamerastub
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
index a7af57c..24496bb 100644
--- a/camera/libcameraservice/CameraHardwareStub.cpp
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -33,13 +33,11 @@ CameraHardwareStub::CameraHardwareStub()
mRawHeap(0),
mFakeCamera(0),
mPreviewFrameSize(0),
- mRawPictureCallback(0),
- mJpegPictureCallback(0),
- mPictureCallbackCookie(0),
- mPreviewCallback(0),
- mPreviewCallbackCookie(0),
- mAutoFocusCallback(0),
- mAutoFocusCallbackCookie(0),
+ mNotifyCb(0),
+ mDataCb(0),
+ mDataCbTimestamp(0),
+ mCallbackCookie(0),
+ mMsgEnabled(0),
mCurrentPreviewFrame(0)
{
initDefaultParameters();
@@ -112,6 +110,36 @@ sp<IMemoryHeap> CameraHardwareStub::getRawHeap() const
return mRawHeap;
}
+void CameraHardwareStub::setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user)
+{
+ Mutex::Autolock lock(mLock);
+ mNotifyCb = notify_cb;
+ mDataCb = data_cb;
+ mDataCbTimestamp = data_cb_timestamp;
+ mCallbackCookie = user;
+}
+
+void CameraHardwareStub::enableMsgType(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ mMsgEnabled |= msgType;
+}
+
+void CameraHardwareStub::disableMsgType(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ mMsgEnabled &= ~msgType;
+}
+
+bool CameraHardwareStub::msgTypeEnabled(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ return (mMsgEnabled & msgType);
+}
+
// ---------------------------------------------------------------------------
int CameraHardwareStub::previewThread()
@@ -150,7 +178,8 @@ int CameraHardwareStub::previewThread()
//LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
// Notify the client of a new frame.
- mPreviewCallback(buffer, mPreviewCallbackCookie);
+ if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
+ mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
// Advance the buffer pointer.
mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
@@ -162,15 +191,13 @@ int CameraHardwareStub::previewThread()
return NO_ERROR;
}
-status_t CameraHardwareStub::startPreview(preview_callback cb, void* user)
+status_t CameraHardwareStub::startPreview()
{
Mutex::Autolock lock(mLock);
if (mPreviewThread != 0) {
// already running
return INVALID_OPERATION;
}
- mPreviewCallback = cb;
- mPreviewCallbackCookie = user;
mPreviewThread = new PreviewThread(this);
return NO_ERROR;
}
@@ -197,7 +224,7 @@ bool CameraHardwareStub::previewEnabled() {
return mPreviewThread != 0;
}
-status_t CameraHardwareStub::startRecording(recording_callback cb, void* user)
+status_t CameraHardwareStub::startRecording()
{
return UNKNOWN_ERROR;
}
@@ -225,25 +252,14 @@ int CameraHardwareStub::beginAutoFocusThread(void *cookie)
int CameraHardwareStub::autoFocusThread()
{
- if (mAutoFocusCallback != NULL) {
- mAutoFocusCallback(true, mAutoFocusCallbackCookie);
- mAutoFocusCallback = NULL;
- return NO_ERROR;
- }
- return UNKNOWN_ERROR;
+ if (mMsgEnabled & CAMERA_MSG_FOCUS)
+ mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie);
+ return NO_ERROR;
}
-status_t CameraHardwareStub::autoFocus(autofocus_callback af_cb,
- void *user)
+status_t CameraHardwareStub::autoFocus()
{
Mutex::Autolock lock(mLock);
-
- if (mAutoFocusCallback != NULL) {
- return mAutoFocusCallback == af_cb ? NO_ERROR : INVALID_OPERATION;
- }
-
- mAutoFocusCallback = af_cb;
- mAutoFocusCallbackCookie = user;
if (createThread(beginAutoFocusThread, this) == false)
return UNKNOWN_ERROR;
return NO_ERROR;
@@ -257,10 +273,10 @@ status_t CameraHardwareStub::autoFocus(autofocus_callback af_cb,
int CameraHardwareStub::pictureThread()
{
- if (mShutterCallback)
- mShutterCallback(mPictureCallbackCookie);
+ if (mMsgEnabled & CAMERA_MSG_SHUTTER)
+ mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie);
- if (mRawPictureCallback) {
+ if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
//FIXME: use a canned YUV image!
// In the meantime just make another fake camera picture.
int w, h;
@@ -268,42 +284,28 @@ int CameraHardwareStub::pictureThread()
sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * 2 * h);
FakeCamera cam(w, h);
cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base());
- if (mRawPictureCallback)
- mRawPictureCallback(mem, mPictureCallbackCookie);
+ mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);
}
- if (mJpegPictureCallback) {
+ if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
sp<MemoryBase> mem = new MemoryBase(heap, 0, kCannedJpegSize);
memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
- if (mJpegPictureCallback)
- mJpegPictureCallback(mem, mPictureCallbackCookie);
+ mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, mCallbackCookie);
}
return NO_ERROR;
}
-status_t CameraHardwareStub::takePicture(shutter_callback shutter_cb,
- raw_callback raw_cb,
- jpeg_callback jpeg_cb,
- void* user)
+status_t CameraHardwareStub::takePicture()
{
stopPreview();
- mShutterCallback = shutter_cb;
- mRawPictureCallback = raw_cb;
- mJpegPictureCallback = jpeg_cb;
- mPictureCallbackCookie = user;
if (createThread(beginPictureThread, this) == false)
return -1;
return NO_ERROR;
}
-status_t CameraHardwareStub::cancelPicture(bool cancel_shutter,
- bool cancel_raw,
- bool cancel_jpeg)
+status_t CameraHardwareStub::cancelPicture()
{
- if (cancel_shutter) mShutterCallback = NULL;
- if (cancel_raw) mRawPictureCallback = NULL;
- if (cancel_jpeg) mJpegPictureCallback = NULL;
return NO_ERROR;
}
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
index 0d26d47..000906a 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 {
@@ -32,23 +32,27 @@ public:
virtual sp<IMemoryHeap> getPreviewHeap() const;
virtual sp<IMemoryHeap> getRawHeap() const;
- virtual status_t startPreview(preview_callback cb, void* user);
+ virtual void setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user);
+
+ virtual void enableMsgType(int32_t msgType);
+ virtual void disableMsgType(int32_t msgType);
+ virtual bool msgTypeEnabled(int32_t msgType);
+
+ virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
- virtual status_t startRecording(recording_callback cb, void* user);
+ virtual status_t startRecording();
virtual void stopRecording();
virtual bool recordingEnabled();
virtual void releaseRecordingFrame(const sp<IMemory>& mem);
- virtual status_t autoFocus(autofocus_callback, void *user);
- virtual status_t takePicture(shutter_callback,
- raw_callback,
- jpeg_callback,
- void* user);
- virtual status_t cancelPicture(bool cancel_shutter,
- bool cancel_raw,
- bool cancel_jpeg);
+ virtual status_t autoFocus();
+ virtual status_t takePicture();
+ virtual status_t cancelPicture();
virtual status_t dump(int fd, const Vector<String16>& args) const;
virtual status_t setParameters(const CameraParameters& params);
virtual CameraParameters getParameters() const;
@@ -67,8 +71,15 @@ private:
class PreviewThread : public Thread {
CameraHardwareStub* mHardware;
public:
- PreviewThread(CameraHardwareStub* hw)
- : Thread(false), mHardware(hw) { }
+ PreviewThread(CameraHardwareStub* hw) :
+#ifdef SINGLE_PROCESS
+ // In single process mode this thread needs to be a java thread,
+ // since we won't be calling through the binder.
+ Thread(true),
+#else
+ Thread(false),
+#endif
+ mHardware(hw) { }
virtual void onFirstRef() {
run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
}
@@ -102,18 +113,15 @@ private:
bool mPreviewRunning;
int mPreviewFrameSize;
- shutter_callback mShutterCallback;
- raw_callback mRawPictureCallback;
- jpeg_callback mJpegPictureCallback;
- void *mPictureCallbackCookie;
-
// protected by mLock
sp<PreviewThread> mPreviewThread;
- preview_callback mPreviewCallback;
- void *mPreviewCallbackCookie;
- autofocus_callback mAutoFocusCallback;
- void *mAutoFocusCallbackCookie;
+ notify_callback mNotifyCb;
+ data_callback mDataCb;
+ data_callback_timestamp mDataCbTimestamp;
+ void *mCallbackCookie;
+
+ int32_t mMsgEnabled;
// only used from PreviewThread
int mCurrentPreviewFrame;
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index e4b6791..e66b00f 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>
@@ -33,7 +33,6 @@
#include "CameraService.h"
#include <cutils/atomic.h>
-#include <cutils/properties.h>
namespace android {
@@ -60,6 +59,7 @@ extern "C" {
#define DEBUG_DUMP_PREVIEW_FRAME_TO_FILE 0 /* n-th frame to write */
#define DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE 0
#define DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE 0
+#define DEBUG_DUMP_POSTVIEW_SNAPSHOT_TO_FILE 0
#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
static int debug_frame_cnt;
@@ -199,13 +199,7 @@ static sp<MediaPlayer> newMediaPlayer(const char *file)
{
sp<MediaPlayer> mp = new MediaPlayer();
if (mp->setDataSource(file) == NO_ERROR) {
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.camera.sound.forced", value, "0");
- if (atoi(value)) {
- mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
- } else {
- mp->setAudioStreamType(AudioSystem::SYSTEM);
- }
+ mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
mp->prepare();
} else {
mp.clear();
@@ -225,8 +219,20 @@ CameraService::Client::Client(const sp<CameraService>& cameraService,
mHardware = openCameraHardware();
mUseOverlay = mHardware->useOverlay();
+ mHardware->setCallbacks(notifyCallback,
+ dataCallback,
+ dataCallbackTimestamp,
+ mCameraService.get());
+
+ // Enable zoom, error, and focus messages by default
+ mHardware->enableMsgType(CAMERA_MSG_ERROR |
+ CAMERA_MSG_ZOOM |
+ CAMERA_MSG_FOCUS);
+
mMediaPlayerClick = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
mMediaPlayerBeep = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
+ mOverlayW = 0;
+ mOverlayH = 0;
// Callback is disabled by default
mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
@@ -396,9 +402,20 @@ void CameraService::Client::disconnect()
// idle state.
mHardware->stopPreview();
// Cancel all picture callbacks.
- mHardware->cancelPicture(true, true, true);
+ mHardware->disableMsgType(CAMERA_MSG_SHUTTER |
+ CAMERA_MSG_POSTVIEW_FRAME |
+ CAMERA_MSG_RAW_IMAGE |
+ CAMERA_MSG_COMPRESSED_IMAGE);
+ mHardware->cancelPicture();
+ // Turn off remaining messages.
+ mHardware->disableMsgType(CAMERA_MSG_ALL_MSGS);
// Release the hardware resources.
mHardware->release();
+ // Release the held overlay resources.
+ if (mUseOverlay)
+ {
+ mOverlayRef = 0;
+ }
mHardware.clear();
mCameraService->removeClient(mCameraClient);
@@ -420,11 +437,21 @@ status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
result = NO_ERROR;
// asBinder() is safe on NULL (returns NULL)
if (surface->asBinder() != mSurface->asBinder()) {
- if (mSurface != 0 && !mUseOverlay) {
+ if (mSurface != 0) {
LOGD("clearing old preview surface %p", mSurface.get());
- mSurface->unregisterBuffers();
+ if ( !mUseOverlay)
+ {
+ mSurface->unregisterBuffers();
+ }
+ else
+ {
+ // Force the destruction of any previous overlay
+ sp<Overlay> dummy;
+ mHardware->setOverlay( dummy );
+ }
}
mSurface = surface;
+ mOverlayRef = 0;
// If preview has been already started, set overlay or register preview
// buffers now.
if (mHardware->previewEnabled()) {
@@ -446,6 +473,13 @@ void CameraService::Client::setPreviewCallbackFlag(int callback_flag)
Mutex::Autolock lock(mLock);
if (checkPid() != NO_ERROR) return;
mPreviewCallbackFlag = callback_flag;
+
+ if(mUseOverlay) {
+ if(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)
+ mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ else
+ mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ }
}
// start preview mode
@@ -504,7 +538,7 @@ status_t CameraService::Client::startRecordingMode()
}
// start recording mode
- ret = mHardware->startRecording(recordingCallback, mCameraService.get());
+ ret = mHardware->startRecording();
if (ret != NO_ERROR) {
LOGE("mHardware->startRecording() failed with status %d", ret);
}
@@ -520,8 +554,8 @@ status_t CameraService::Client::setOverlay()
const char *format = params.getPreviewFormat();
int fmt;
- if (!strcmp(format, "yuv422i"))
- fmt = OVERLAY_FORMAT_YCbCr_422_I;
+ if (!strcmp(format, "yuv422i-yuyv"))
+ fmt = OVERLAY_FORMAT_YCbYCr_422_I;
else if (!strcmp(format, "rgb565"))
fmt = OVERLAY_FORMAT_RGB_565;
else {
@@ -529,16 +563,35 @@ status_t CameraService::Client::setOverlay()
return -EINVAL;
}
+ if ( w != mOverlayW || h != mOverlayH )
+ {
+ // Force the destruction of any previous overlay
+ sp<Overlay> dummy;
+ mHardware->setOverlay( dummy );
+ mOverlayRef = 0;
+ }
+
status_t ret = NO_ERROR;
if (mSurface != 0) {
- sp<OverlayRef> ref = mSurface->createOverlay(w, h, fmt);
- ret = mHardware->setOverlay(new Overlay(ref));
+ if (mOverlayRef.get() == NULL) {
+ mOverlayRef = mSurface->createOverlay(w, h, fmt);
+ if ( mOverlayRef.get() == NULL )
+ {
+ LOGE("Overlay Creation Failed!");
+ return -EINVAL;
+ }
+ ret = mHardware->setOverlay(new Overlay(mOverlayRef));
+ }
} else {
ret = mHardware->setOverlay(NULL);
}
if (ret != NO_ERROR) {
LOGE("mHardware->setOverlay() failed with status %d\n", ret);
}
+
+ mOverlayW = w;
+ mOverlayH = h;
+
return ret;
}
@@ -588,10 +641,10 @@ status_t CameraService::Client::startPreviewMode()
ret = setOverlay();
}
if (ret != NO_ERROR) return ret;
- ret = mHardware->startPreview(NULL, mCameraService.get());
+ ret = mHardware->startPreview();
} else {
- ret = mHardware->startPreview(previewCallback,
- mCameraService.get());
+ mHardware->enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ ret = mHardware->startPreview();
if (ret != NO_ERROR) return ret;
// If preview display has been set, register preview buffers now.
if (mSurface != 0) {
@@ -618,6 +671,9 @@ status_t CameraService::Client::startRecording()
mMediaPlayerBeep->seekTo(0);
mMediaPlayerBeep->start();
}
+
+ mHardware->enableMsgType(CAMERA_MSG_VIDEO_FRAME);
+
return startCameraMode(CAMERA_RECORDING_MODE);
}
@@ -635,6 +691,7 @@ void CameraService::Client::stopPreview()
}
mHardware->stopPreview();
+ mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
LOGD("stopPreview(), hardware stopped OK");
if (mSurface != 0 && !mUseOverlay) {
@@ -660,8 +717,11 @@ void CameraService::Client::stopRecording()
mMediaPlayerBeep->seekTo(0);
mMediaPlayerBeep->start();
}
+
mHardware->stopRecording();
+ mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME);
LOGD("stopRecording(), hardware stopped OK");
+
mPreviewBuffer.clear();
}
@@ -749,65 +809,6 @@ static void dump_to_file(const char *fname,
}
#endif
-// preview callback - frame buffer update
-void CameraService::Client::previewCallback(const sp<IMemory>& mem, void* user)
-{
- LOGV("previewCallback()");
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
- }
-
-#if DEBUG_HEAP_LEAKS && 0 // debugging
- if (gWeakHeap == NULL) {
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- if (gWeakHeap != heap) {
- LOGD("SETTING PREVIEW HEAP");
- heap->trackMe(true, true);
- gWeakHeap = heap;
- }
- }
-#endif
-
-#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
- {
- if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) {
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- dump_to_file("/data/preview.yuv",
- (uint8_t *)heap->base() + offset, size);
- }
- }
-#endif
-
- // The strong pointer guarantees the client will exist, but no lock is held.
- client->postPreviewFrame(mem);
-
-#if DEBUG_CLIENT_REFERENCES
- //**** if the client's refcount is 1, then we are about to destroy it here,
- // which is bad--print all refcounts.
- if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (PREVIEW) THIS WILL CAUSE A LOCKUP!");
- client->printRefs();
- }
-#endif
-}
-
-// recording callback
-void CameraService::Client::recordingCallback(nsecs_t timestamp, const sp<IMemory>& mem, void* user)
-{
- LOGV("recordingCallback");
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
- }
- // The strong pointer guarantees the client will exist, but no lock is held.
- client->postRecordingFrame(timestamp, mem);
-}
-
// take a picture - image is returned in callback
status_t CameraService::Client::autoFocus()
{
@@ -822,8 +823,7 @@ status_t CameraService::Client::autoFocus()
return INVALID_OPERATION;
}
- return mHardware->autoFocus(autoFocusCallback,
- mCameraService.get());
+ return mHardware->autoFocus();
}
// take a picture - image is returned in callback
@@ -840,38 +840,36 @@ status_t CameraService::Client::takePicture()
return INVALID_OPERATION;
}
- return mHardware->takePicture(shutterCallback,
- yuvPictureCallback,
- jpegPictureCallback,
- mCameraService.get());
+ mHardware->enableMsgType(CAMERA_MSG_SHUTTER |
+ CAMERA_MSG_POSTVIEW_FRAME |
+ CAMERA_MSG_RAW_IMAGE |
+ CAMERA_MSG_COMPRESSED_IMAGE);
+
+ return mHardware->takePicture();
}
-// picture callback - snapshot taken
-void CameraService::Client::shutterCallback(void *user)
+// snapshot taken
+void CameraService::Client::handleShutter()
{
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
- }
-
// Play shutter sound.
- if (client->mMediaPlayerClick.get() != NULL) {
- client->mMediaPlayerClick->seekTo(0);
- client->mMediaPlayerClick->start();
+ if (mMediaPlayerClick.get() != NULL) {
+ mMediaPlayerClick->seekTo(0);
+ mMediaPlayerClick->start();
}
// Screen goes black after the buffer is unregistered.
- if (client->mSurface != 0 && !client->mUseOverlay) {
- client->mSurface->unregisterBuffers();
+ if (mSurface != 0 && !mUseOverlay) {
+ mSurface->unregisterBuffers();
}
- client->postShutter();
+ mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
+ mHardware->disableMsgType(CAMERA_MSG_SHUTTER);
// It takes some time before yuvPicture callback to be called.
// Register the buffer for raw image here to reduce latency.
- if (client->mSurface != 0 && !client->mUseOverlay) {
+ if (mSurface != 0 && !mUseOverlay) {
int w, h;
- CameraParameters params(client->mHardware->getParameters());
+ CameraParameters params(mHardware->getParameters());
params.getPictureSize(&w, &h);
uint32_t transform = 0;
if (params.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
@@ -879,26 +877,92 @@ void CameraService::Client::shutterCallback(void *user)
transform = ISurface::BufferHeap::ROT_90;
}
ISurface::BufferHeap buffers(w, h, w, h,
- PIXEL_FORMAT_YCbCr_420_SP, transform, 0, client->mHardware->getRawHeap());
+ PIXEL_FORMAT_YCbCr_420_SP, transform, 0, mHardware->getRawHeap());
- client->mSurface->registerBuffers(buffers);
+ mSurface->registerBuffers(buffers);
}
}
-// picture callback - raw image ready
-void CameraService::Client::yuvPictureCallback(const sp<IMemory>& mem,
- void *user)
+// preview callback - frame buffer update
+void CameraService::Client::handlePreviewData(const sp<IMemory>& mem)
{
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) {
- return;
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+#if DEBUG_HEAP_LEAKS && 0 // debugging
+ if (gWeakHeap == NULL) {
+ if (gWeakHeap != heap) {
+ LOGD("SETTING PREVIEW HEAP");
+ heap->trackMe(true, true);
+ gWeakHeap = heap;
+ }
}
- if (mem == NULL) {
- client->postRaw(NULL);
- client->postError(UNKNOWN_ERROR);
+#endif
+#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
+ {
+ if (debug_frame_cnt++ == DEBUG_DUMP_PREVIEW_FRAME_TO_FILE) {
+ dump_to_file("/data/preview.yuv",
+ (uint8_t *)heap->base() + offset, size);
+ }
+ }
+#endif
+
+ if (!mUseOverlay)
+ {
+ Mutex::Autolock surfaceLock(mSurfaceLock);
+ if (mSurface != NULL) {
+ mSurface->postBuffer(offset);
+ }
+ }
+
+ // Is the callback enabled or not?
+ if (!(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+ // If the enable bit is off, the copy-out and one-shot bits are ignored
+ LOGV("frame callback is diabled");
return;
}
+ // Is the received frame copied out or not?
+ if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+ LOGV("frame is copied out");
+ copyFrameAndPostCopiedFrame(heap, offset, size);
+ } else {
+ LOGV("frame is directly sent out without copying");
+ mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
+ }
+
+ // Is this is one-shot only?
+ if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
+ LOGV("One-shot only, thus clear the bits and disable frame callback");
+ mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+ FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
+ FRAME_CALLBACK_FLAG_ENABLE_MASK);
+ if (mUseOverlay)
+ mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+ }
+}
+
+// picture callback - postview image ready
+void CameraService::Client::handlePostview(const sp<IMemory>& mem)
+{
+#if DEBUG_DUMP_POSTVIEW_SNAPSHOT_TO_FILE // for testing pursposes only
+ {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ dump_to_file("/data/postview.yuv",
+ (uint8_t *)heap->base() + offset, size);
+ }
+#endif
+
+ mCameraClient->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem);
+ mHardware->disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
+}
+
+// picture callback - raw image ready
+void CameraService::Client::handleRawPicture(const sp<IMemory>& mem)
+{
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
@@ -906,80 +970,128 @@ void CameraService::Client::yuvPictureCallback(const sp<IMemory>& mem,
gWeakHeap = heap; // debugging
#endif
- //LOGV("yuvPictureCallback(%d, %d, %p)", offset, size, user);
+ //LOGV("handleRawPicture(%d, %d)", offset, size);
#if DEBUG_DUMP_YUV_SNAPSHOT_TO_FILE // for testing pursposes only
dump_to_file("/data/photo.yuv",
(uint8_t *)heap->base() + offset, size);
#endif
// Put the YUV version of the snapshot in the preview display.
- if (client->mSurface != 0 && !client->mUseOverlay) {
- client->mSurface->postBuffer(offset);
+ if (mSurface != 0 && !mUseOverlay) {
+ mSurface->postBuffer(offset);
}
- client->postRaw(mem);
+ mCameraClient->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
+ mHardware->disableMsgType(CAMERA_MSG_RAW_IMAGE);
+}
+
+// picture callback - compressed picture ready
+void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem)
+{
+#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE // for testing pursposes only
+ {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ dump_to_file("/data/photo.jpg",
+ (uint8_t *)heap->base() + offset, size);
+ }
+#endif
+
+ mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
+ mHardware->disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
+}
+
+void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user)
+{
+ LOGV("notifyCallback(%d)", msgType);
+
+ sp<Client> client = getClientFromCookie(user);
+ if (client == 0) {
+ return;
+ }
+
+ switch (msgType) {
+ case CAMERA_MSG_SHUTTER:
+ client->handleShutter();
+ break;
+ default:
+ client->mCameraClient->notifyCallback(msgType, ext1, ext2);
+ break;
+ }
#if DEBUG_CLIENT_REFERENCES
- //**** if the client's refcount is 1, then we are about to destroy it here,
- // which is bad--print all refcounts.
if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (RAW) THIS WILL CAUSE A LOCKUP!");
+ LOGE("++++++++++++++++ (NOTIFY CALLBACK) THIS WILL CAUSE A LOCKUP!");
client->printRefs();
}
#endif
}
-// picture callback - jpeg ready
-void CameraService::Client::jpegPictureCallback(const sp<IMemory>& mem, void *user)
+void CameraService::Client::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user)
{
+ LOGV("dataCallback(%d)", msgType);
+
sp<Client> client = getClientFromCookie(user);
if (client == 0) {
return;
}
- if (mem == NULL) {
- client->postJpeg(NULL);
- client->postError(UNKNOWN_ERROR);
+
+ if (dataPtr == NULL) {
+ LOGE("Null data returned in data callback");
+ client->mCameraClient->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+ client->mCameraClient->dataCallback(msgType, NULL);
return;
}
- /** We absolutely CANNOT call into user code with a lock held **/
-
-#if DEBUG_DUMP_JPEG_SNAPSHOT_TO_FILE // for testing pursposes only
- {
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- dump_to_file("/data/photo.jpg",
- (uint8_t *)heap->base() + offset, size);
+ switch (msgType) {
+ case CAMERA_MSG_PREVIEW_FRAME:
+ client->handlePreviewData(dataPtr);
+ break;
+ case CAMERA_MSG_POSTVIEW_FRAME:
+ client->handlePostview(dataPtr);
+ break;
+ case CAMERA_MSG_RAW_IMAGE:
+ client->handleRawPicture(dataPtr);
+ break;
+ case CAMERA_MSG_COMPRESSED_IMAGE:
+ client->handleCompressedPicture(dataPtr);
+ break;
+ default:
+ client->mCameraClient->dataCallback(msgType, dataPtr);
+ break;
}
-#endif
-
- client->postJpeg(mem);
#if DEBUG_CLIENT_REFERENCES
- //**** if the client's refcount is 1, then we are about to destroy it here,
- // which is bad--print all refcounts.
if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (JPEG) THIS WILL CAUSE A LOCKUP!");
+ LOGE("++++++++++++++++ (DATA CALLBACK) THIS WILL CAUSE A LOCKUP!");
client->printRefs();
}
#endif
}
-void CameraService::Client::autoFocusCallback(bool focused, void *user)
+void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
+ const sp<IMemory>& dataPtr, void* user)
{
- LOGV("autoFocusCallback");
+ LOGV("dataCallbackTimestamp(%d)", msgType);
sp<Client> client = getClientFromCookie(user);
if (client == 0) {
return;
}
- client->postAutoFocus(focused);
+ if (dataPtr == NULL) {
+ LOGE("Null data returned in data with timestamp callback");
+ client->mCameraClient->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+ client->mCameraClient->dataCallbackTimestamp(0, msgType, NULL);
+ return;
+ }
+
+ client->mCameraClient->dataCallbackTimestamp(timestamp, msgType, dataPtr);
#if DEBUG_CLIENT_REFERENCES
if (client->getStrongCount() == 1) {
- LOGE("++++++++++++++++ (AUTOFOCUS) THIS WILL CAUSE A LOCKUP!");
+ LOGE("++++++++++++++++ (DATA CALLBACK TIMESTAMP) THIS WILL CAUSE A LOCKUP!");
client->printRefs();
}
#endif
@@ -1019,30 +1131,6 @@ String8 CameraService::Client::getParameters() const
return params;
}
-void CameraService::Client::postAutoFocus(bool focused)
-{
- LOGV("postAutoFocus");
- mCameraClient->notifyCallback(CAMERA_MSG_FOCUS, (int32_t)focused, 0);
-}
-
-void CameraService::Client::postShutter()
-{
- LOGD("postShutter");
- mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
-}
-
-void CameraService::Client::postRaw(const sp<IMemory>& mem)
-{
- LOGD("postRaw");
- mCameraClient->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
-}
-
-void CameraService::Client::postJpeg(const sp<IMemory>& mem)
-{
- LOGD("postJpeg");
- mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
-}
-
void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size)
{
LOGV("copyFrameAndPostCopiedFrame");
@@ -1071,64 +1159,6 @@ void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, si
mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
}
-void CameraService::Client::postRecordingFrame(nsecs_t timestamp, const sp<IMemory>& frame)
-{
- LOGV("postRecordingFrame");
- if (frame == 0) {
- LOGW("frame is a null pointer");
- return;
- }
- mCameraClient->dataCallbackTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, frame);
-}
-
-void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem)
-{
- LOGV("postPreviewFrame");
- if (mem == 0) {
- LOGW("mem is a null pointer");
- return;
- }
-
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- {
- Mutex::Autolock surfaceLock(mSurfaceLock);
- if (mSurface != NULL) {
- mSurface->postBuffer(offset);
- }
- }
-
- // Is the callback enabled or not?
- if (!(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
- // If the enable bit is off, the copy-out and one-shot bits are ignored
- LOGV("frame callback is diabled");
- return;
- }
-
- // Is the received frame copied out or not?
- if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
- LOGV("frame is copied out");
- copyFrameAndPostCopiedFrame(heap, offset, size);
- } else {
- LOGV("frame is directly sent out without copying");
- mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
- }
-
- // Is this is one-shot only?
- if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
- LOGV("One-shot only, thus clear the bits and disable frame callback");
- mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
- FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
- FRAME_CALLBACK_FLAG_ENABLE_MASK);
- }
-}
-
-void CameraService::Client::postError(status_t error)
-{
- mCameraClient->notifyCallback(CAMERA_MSG_ERROR, error, 0);
-}
-
status_t CameraService::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
@@ -1160,12 +1190,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/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index ea93789..f8c7216 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -132,22 +132,20 @@ private:
status_t checkPid();
- static void recordingCallback(nsecs_t timestamp, const sp<IMemory>& mem, void* user);
- static void previewCallback(const sp<IMemory>& mem, void* user);
- static void shutterCallback(void *user);
- static void yuvPictureCallback(const sp<IMemory>& mem, void* user);
- static void jpegPictureCallback(const sp<IMemory>& mem, void* user);
- static void autoFocusCallback(bool focused, void* user);
+ static void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
+ static void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user);
+ static void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
+ const sp<IMemory>& dataPtr, void* user);
+
static sp<Client> getClientFromCookie(void* user);
- void postShutter();
- void postRaw(const sp<IMemory>& mem);
- void postJpeg(const sp<IMemory>& mem);
- void postPreviewFrame(const sp<IMemory>& mem);
- void postRecordingFrame(nsecs_t timestamp, const sp<IMemory>& frame);
+ void handlePreviewData(const sp<IMemory>&);
+ void handleShutter();
+ void handlePostview(const sp<IMemory>&);
+ void handleRawPicture(const sp<IMemory>&);
+ void handleCompressedPicture(const sp<IMemory>&);
+
void copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size);
- void postError(status_t error);
- void postAutoFocus(bool focused);
// camera operation mode
enum camera_mode {
@@ -189,6 +187,10 @@ private:
sp<CameraHardwareInterface> mHardware;
pid_t mClientPid;
bool mUseOverlay;
+
+ sp<OverlayRef> mOverlayRef;
+ int mOverlayW;
+ int mOverlayH;
};
// ----------------------------------------------------------------------------
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3782136..0b4f25e 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -23,16 +23,19 @@ import android.app.IActivityManager;
import android.app.IInstrumentationWatcher;
import android.app.Instrumentation;
import android.content.ComponentName;
+import android.content.IIntentReceiver;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.AndroidException;
import android.view.IWindowManager;
import java.io.File;
import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.Set;
@@ -45,16 +48,29 @@ public class Am {
private boolean mDebugOption = false;
+ // These are magic strings understood by the Eclipse plugin.
+ private static final String FATAL_ERROR_CODE = "Error type 1";
+ private static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
+ private static final String NO_CLASS_ERROR_CODE = "Error type 3";
+
/**
* Command-line entry point.
*
* @param args The command-line arguments
*/
public static void main(String[] args) {
- (new Am()).run(args);
+ try {
+ (new Am()).run(args);
+ } catch (IllegalArgumentException e) {
+ showUsage();
+ System.err.println("Error: " + e.getMessage());
+ } catch (Exception e) {
+ System.err.println(e.toString());
+ System.exit(1);
+ }
}
- private void run(String[] args) {
+ private void run(String[] args) throws Exception {
if (args.length < 1) {
showUsage();
return;
@@ -62,16 +78,14 @@ public class Am {
mAm = ActivityManagerNative.getDefault();
if (mAm == null) {
- System.err.println("Error type 2");
- System.err.println("Error: Unable to connect to activity manager; is the system running?");
- showUsage();
- return;
+ System.err.println(NO_SYSTEM_ERROR_CODE);
+ throw new AndroidException("Can't connect to activity manager; is the system running?");
}
mArgs = args;
-
String op = args[0];
mNextArg = 1;
+
if (op.equals("start")) {
runStart();
} else if (op.equals("instrument")) {
@@ -81,13 +95,11 @@ public class Am {
} else if (op.equals("profile")) {
runProfile();
} else {
- System.err.println("Error: Unknown command: " + op);
- showUsage();
- return;
+ throw new IllegalArgumentException("Unknown command: " + op);
}
}
- private Intent makeIntent() {
+ private Intent makeIntent() throws URISyntaxException {
Intent intent = new Intent();
boolean hasIntentInfo = false;
@@ -95,186 +107,146 @@ public class Am {
Uri data = null;
String type = null;
- try {
- String opt;
- while ((opt=nextOption()) != null) {
- if (opt.equals("-a")) {
- intent.setAction(nextOptionData());
- hasIntentInfo = true;
- } else if (opt.equals("-d")) {
- data = Uri.parse(nextOptionData());
- hasIntentInfo = true;
- } else if (opt.equals("-t")) {
- type = nextOptionData();
- hasIntentInfo = true;
- } else if (opt.equals("-c")) {
- intent.addCategory(nextOptionData());
- hasIntentInfo = true;
- } else if (opt.equals("-e") || opt.equals("--es")) {
- String key = nextOptionData();
- String value = nextOptionData();
- intent.putExtra(key, value);
- hasIntentInfo = true;
- } else if (opt.equals("--ei")) {
- String key = nextOptionData();
- String value = nextOptionData();
- intent.putExtra(key, Integer.valueOf(value));
- hasIntentInfo = true;
- } else if (opt.equals("--ez")) {
- String key = nextOptionData();
- String value = nextOptionData();
- intent.putExtra(key, Boolean.valueOf(value));
- hasIntentInfo = true;
- } else if (opt.equals("-n")) {
- String str = nextOptionData();
- ComponentName cn = ComponentName.unflattenFromString(str);
- if (cn == null) {
- System.err.println("Error: Bad component name: " + str);
- showUsage();
- return null;
- }
- intent.setComponent(cn);
- hasIntentInfo = true;
- } else if (opt.equals("-f")) {
- String str = nextOptionData();
- intent.setFlags(Integer.decode(str).intValue());
- } else if (opt.equals("-D")) {
- mDebugOption = true;
- } else {
- System.err.println("Error: Unknown option: " + opt);
- showUsage();
- return null;
- }
+ String opt;
+ while ((opt=nextOption()) != null) {
+ if (opt.equals("-a")) {
+ intent.setAction(nextArgRequired());
+ hasIntentInfo = true;
+ } else if (opt.equals("-d")) {
+ data = Uri.parse(nextArgRequired());
+ hasIntentInfo = true;
+ } else if (opt.equals("-t")) {
+ type = nextArgRequired();
+ hasIntentInfo = true;
+ } else if (opt.equals("-c")) {
+ intent.addCategory(nextArgRequired());
+ hasIntentInfo = true;
+ } else if (opt.equals("-e") || opt.equals("--es")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, value);
+ hasIntentInfo = true;
+ } else if (opt.equals("--ei")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, Integer.valueOf(value));
+ hasIntentInfo = true;
+ } else if (opt.equals("--ez")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, Boolean.valueOf(value));
+ hasIntentInfo = true;
+ } else if (opt.equals("-n")) {
+ String str = nextArgRequired();
+ ComponentName cn = ComponentName.unflattenFromString(str);
+ if (cn == null) throw new IllegalArgumentException("Bad component name: " + str);
+ intent.setComponent(cn);
+ hasIntentInfo = true;
+ } else if (opt.equals("-f")) {
+ String str = nextArgRequired();
+ intent.setFlags(Integer.decode(str).intValue());
+ } else if (opt.equals("-D")) {
+ mDebugOption = true;
+ } else {
+ System.err.println("Error: Unknown option: " + opt);
+ showUsage();
+ return null;
}
- } catch (RuntimeException ex) {
- System.err.println("Error: " + ex.toString());
- showUsage();
- return null;
}
intent.setDataAndType(data, type);
String uri = nextArg();
if (uri != null) {
- try {
- Intent oldIntent = intent;
- try {
- intent = Intent.getIntent(uri);
- } catch (java.net.URISyntaxException ex) {
- System.err.println("Bad URI: " + uri);
- showUsage();
- return null;
- }
- if (oldIntent.getAction() != null) {
- intent.setAction(oldIntent.getAction());
- }
- if (oldIntent.getData() != null || oldIntent.getType() != null) {
- intent.setDataAndType(oldIntent.getData(), oldIntent.getType());
- }
- Set cats = oldIntent.getCategories();
- if (cats != null) {
- Iterator it = cats.iterator();
- while (it.hasNext()) {
- intent.addCategory((String)it.next());
- }
+ Intent oldIntent = intent;
+ intent = Intent.getIntent(uri);
+ if (oldIntent.getAction() != null) {
+ intent.setAction(oldIntent.getAction());
+ }
+ if (oldIntent.getData() != null || oldIntent.getType() != null) {
+ intent.setDataAndType(oldIntent.getData(), oldIntent.getType());
+ }
+ Set cats = oldIntent.getCategories();
+ if (cats != null) {
+ Iterator it = cats.iterator();
+ while (it.hasNext()) {
+ intent.addCategory((String)it.next());
}
- } catch (RuntimeException ex) {
- System.err.println("Error creating from URI: " + ex.toString());
- showUsage();
- return null;
}
- } else if (!hasIntentInfo) {
- System.err.println("Error: No intent supplied");
- showUsage();
- return null;
+ hasIntentInfo = true;
}
+ if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied");
return intent;
}
- private void runStart() {
+ private void runStart() throws Exception {
Intent intent = makeIntent();
-
- if (intent != null) {
- System.out.println("Starting: " + intent);
- try {
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- // XXX should do something to determine the MIME type.
- int res = mAm.startActivity(null, intent, intent.getType(),
- null, 0, null, null, 0, false, mDebugOption);
- switch (res) {
- case IActivityManager.START_SUCCESS:
- break;
- case IActivityManager.START_SWITCHES_CANCELED:
- System.err.println(
- "Warning: Activity not started because the "
- + " current activity is being kept for the user.");
- break;
- case IActivityManager.START_DELIVERED_TO_TOP:
- System.err.println(
- "Warning: Activity not started, intent has "
- + "been delivered to currently running "
- + "top-most instance.");
- break;
- case IActivityManager.START_RETURN_INTENT_TO_CALLER:
- System.err.println(
- "Warning: Activity not started because intent "
- + "should be handled by the caller");
- break;
- case IActivityManager.START_TASK_TO_FRONT:
- System.err.println(
- "Warning: Activity not started, its current "
- + "task has been brought to the front");
- break;
- case IActivityManager.START_INTENT_NOT_RESOLVED:
- System.err.println(
- "Error: Activity not started, unable to "
- + "resolve " + intent.toString());
- break;
- case IActivityManager.START_CLASS_NOT_FOUND:
- System.err.println("Error type 3");
- System.err.println("Error: Activity class " +
- intent.getComponent().toShortString()
- + " does not exist.");
- break;
- case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
- System.err.println(
- "Error: Activity not started, you requested to "
- + "both forward and receive its result");
- break;
- case IActivityManager.START_PERMISSION_DENIED:
- System.err.println(
- "Error: Activity not started, you do not "
- + "have permission to access it.");
- break;
- default:
- System.err.println(
- "Error: Activity not started, unknown error "
- + "code " + res);
- break;
- }
- } catch (RemoteException e) {
- System.err.println("Error type 1");
+ System.out.println("Starting: " + intent);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // XXX should do something to determine the MIME type.
+ int res = mAm.startActivity(null, intent, intent.getType(),
+ null, 0, null, null, 0, false, mDebugOption);
+ switch (res) {
+ case IActivityManager.START_SUCCESS:
+ break;
+ case IActivityManager.START_SWITCHES_CANCELED:
+ System.err.println(
+ "Warning: Activity not started because the "
+ + " current activity is being kept for the user.");
+ break;
+ case IActivityManager.START_DELIVERED_TO_TOP:
+ System.err.println(
+ "Warning: Activity not started, intent has "
+ + "been delivered to currently running "
+ + "top-most instance.");
+ break;
+ case IActivityManager.START_RETURN_INTENT_TO_CALLER:
+ System.err.println(
+ "Warning: Activity not started because intent "
+ + "should be handled by the caller");
+ break;
+ case IActivityManager.START_TASK_TO_FRONT:
+ System.err.println(
+ "Warning: Activity not started, its current "
+ + "task has been brought to the front");
+ break;
+ case IActivityManager.START_INTENT_NOT_RESOLVED:
System.err.println(
"Error: Activity not started, unable to "
- + "call on to activity manager service");
- }
+ + "resolve " + intent.toString());
+ break;
+ case IActivityManager.START_CLASS_NOT_FOUND:
+ System.err.println(NO_CLASS_ERROR_CODE);
+ System.err.println("Error: Activity class " +
+ intent.getComponent().toShortString()
+ + " does not exist.");
+ break;
+ case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
+ System.err.println(
+ "Error: Activity not started, you requested to "
+ + "both forward and receive its result");
+ break;
+ case IActivityManager.START_PERMISSION_DENIED:
+ System.err.println(
+ "Error: Activity not started, you do not "
+ + "have permission to access it.");
+ break;
+ default:
+ System.err.println(
+ "Error: Activity not started, unknown error code " + res);
+ break;
}
}
- private void sendBroadcast() {
+ private void sendBroadcast() throws Exception {
Intent intent = makeIntent();
-
- if (intent != null) {
- System.out.println("Broadcasting: " + intent);
- try {
- mAm.broadcastIntent(null, intent, null, null, 0, null, null,
- null, true, false);
- } catch (RemoteException e) {
- }
- }
+ IntentReceiver receiver = new IntentReceiver();
+ System.out.println("Broadcasting: " + intent);
+ mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false);
+ receiver.waitForFinish();
}
- private void runInstrument() {
+ private void runInstrument() throws Exception {
String profileFile = null;
boolean wait = false;
boolean rawMode = false;
@@ -283,46 +255,30 @@ public class Am {
String argKey = null, argValue = null;
IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
- try {
- String opt;
- while ((opt=nextOption()) != null) {
- if (opt.equals("-p")) {
- profileFile = nextOptionData();
- } else if (opt.equals("-w")) {
- wait = true;
- } else if (opt.equals("-r")) {
- rawMode = true;
- } else if (opt.equals("-e")) {
- argKey = nextOptionData();
- argValue = nextOptionData();
- args.putString(argKey, argValue);
- } else if (opt.equals("--no_window_animation")) {
- no_window_animation = true;
- } else {
- System.err.println("Error: Unknown option: " + opt);
- showUsage();
- return;
- }
+ String opt;
+ while ((opt=nextOption()) != null) {
+ if (opt.equals("-p")) {
+ profileFile = nextArgRequired();
+ } else if (opt.equals("-w")) {
+ wait = true;
+ } else if (opt.equals("-r")) {
+ rawMode = true;
+ } else if (opt.equals("-e")) {
+ argKey = nextArgRequired();
+ argValue = nextArgRequired();
+ args.putString(argKey, argValue);
+ } else if (opt.equals("--no_window_animation")) {
+ no_window_animation = true;
+ } else {
+ System.err.println("Error: Unknown option: " + opt);
+ showUsage();
+ return;
}
- } catch (RuntimeException ex) {
- System.err.println("Error: " + ex.toString());
- showUsage();
- return;
}
- String cnArg = nextArg();
- if (cnArg == null) {
- System.err.println("Error: No instrumentation component supplied");
- showUsage();
- return;
- }
-
+ String cnArg = nextArgRequired();
ComponentName cn = ComponentName.unflattenFromString(cnArg);
- if (cn == null) {
- System.err.println("Error: Bad component name: " + cnArg);
- showUsage();
- return;
- }
+ if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
InstrumentationWatcher watcher = null;
if (wait) {
@@ -331,22 +287,13 @@ public class Am {
}
float[] oldAnims = null;
if (no_window_animation) {
- try {
- oldAnims = wm.getAnimationScales();
- wm.setAnimationScale(0, 0.0f);
- wm.setAnimationScale(1, 0.0f);
- } catch (RemoteException e) {
- }
+ oldAnims = wm.getAnimationScales();
+ wm.setAnimationScale(0, 0.0f);
+ wm.setAnimationScale(1, 0.0f);
}
- try {
- if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) {
- System.out.println("INSTRUMENTATION_FAILED: " +
- cn.flattenToString());
- showUsage();
- return;
- }
- } catch (RemoteException e) {
+ if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) {
+ throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
}
if (watcher != null) {
@@ -356,9 +303,57 @@ public class Am {
}
if (oldAnims != null) {
+ wm.setAnimationScales(oldAnims);
+ }
+ }
+
+ private void runProfile() throws Exception {
+ String profileFile = null;
+ boolean start = false;
+ String process = nextArgRequired();
+ ParcelFileDescriptor fd = null;
+
+ String cmd = nextArgRequired();
+ if ("start".equals(cmd)) {
+ start = true;
+ profileFile = nextArgRequired();
+ try {
+ fd = ParcelFileDescriptor.open(
+ new File(profileFile),
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE |
+ ParcelFileDescriptor.MODE_READ_WRITE);
+ } catch (FileNotFoundException e) {
+ System.err.println("Error: Unable to open file: " + profileFile);
+ return;
+ }
+ } else if (!"stop".equals(cmd)) {
+ throw new IllegalArgumentException("Profile command " + cmd + " not valid");
+ }
+
+ if (!mAm.profileControl(process, start, profileFile, fd)) {
+ throw new AndroidException("PROFILE FAILED on process " + process);
+ }
+ }
+
+ private class IntentReceiver extends IIntentReceiver.Stub {
+ private boolean mFinished = false;
+
+ public synchronized void performReceive(
+ Intent intent, int rc, String data, Bundle ext, boolean ord) {
+ String line = "Broadcast completed: result=" + rc;
+ if (data != null) line = line + ", data=\"" + data + "\"";
+ if (ext != null) line = line + ", extras: " + ext;
+ System.out.println(line);
+ mFinished = true;
+ notifyAll();
+ }
+
+ public synchronized void waitForFinish() {
try {
- wm.setAnimationScales(oldAnims);
- } catch (RemoteException e) {
+ while (!mFinished) wait();
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
}
}
}
@@ -366,7 +361,7 @@ public class Am {
private class InstrumentationWatcher extends IInstrumentationWatcher.Stub {
private boolean mFinished = false;
private boolean mRawMode = false;
-
+
/**
* Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode",
* if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that.
@@ -375,7 +370,7 @@ public class Am {
public void setRawOutput(boolean rawMode) {
mRawMode = rawMode;
}
-
+
public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
synchronized (this) {
// pretty printer mode?
@@ -431,6 +426,7 @@ public class Am {
}
wait(1000);
} catch (InterruptedException e) {
+ throw new IllegalStateException(e);
}
}
}
@@ -438,62 +434,11 @@ public class Am {
}
}
- private void runProfile() {
- String profileFile = null;
- boolean start = false;
-
- String process = nextArg();
- if (process == null) {
- System.err.println("Error: No profile process supplied");
- showUsage();
- return;
- }
-
- ParcelFileDescriptor fd = null;
-
- String cmd = nextArg();
- if ("start".equals(cmd)) {
- start = true;
- profileFile = nextArg();
- if (profileFile == null) {
- System.err.println("Error: No profile file path supplied");
- showUsage();
- return;
- }
- try {
- fd = ParcelFileDescriptor.open(
- new File(profileFile),
- ParcelFileDescriptor.MODE_CREATE |
- ParcelFileDescriptor.MODE_TRUNCATE |
- ParcelFileDescriptor.MODE_READ_WRITE);
- } catch (FileNotFoundException e) {
- System.err.println("Error: Unable to open file: " + profileFile);
- return;
- }
- } else if (!"stop".equals(cmd)) {
- System.err.println("Error: Profile command " + cmd + " not valid");
- showUsage();
- return;
- }
-
- try {
- if (!mAm.profileControl(process, start, profileFile, fd)) {
- System.err.println("PROFILE FAILED on process " + process);
- return;
- }
- } catch (IllegalArgumentException e) {
- System.out.println("PROFILE FAILED: " + e.getMessage());
- return;
- } catch (IllegalStateException e) {
- System.out.println("PROFILE FAILED: " + e.getMessage());
- return;
- } catch (RemoteException e) {
- System.out.println("PROFILE FAILED: activity manager gone");
- return;
- }
- }
-
private String nextOption() {
+ if (mCurArgData != null) {
+ String prev = mArgs[mNextArg - 1];
+ throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
+ }
if (mNextArg >= mArgs.length) {
return null;
}
@@ -518,41 +463,52 @@ public class Am {
return arg;
}
- private String nextOptionData() {
+ private String nextArg() {
if (mCurArgData != null) {
- return mCurArgData;
- }
- if (mNextArg >= mArgs.length) {
+ String arg = mCurArgData;
+ mCurArgData = null;
+ return arg;
+ } else if (mNextArg < mArgs.length) {
+ return mArgs[mNextArg++];
+ } else {
return null;
}
- String data = mArgs[mNextArg];
- mNextArg++;
- return data;
}
- private String nextArg() {
- if (mNextArg >= mArgs.length) {
- return null;
+ private String nextArgRequired() {
+ String arg = nextArg();
+ if (arg == null) {
+ String prev = mArgs[mNextArg - 1];
+ throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
}
- String arg = mArgs[mNextArg];
- mNextArg++;
return arg;
}
- private void showUsage() {
- System.err.println("usage: am [start|broadcast|instrument|profile]");
- System.err.println(" am start [-D] INTENT");
- System.err.println(" am broadcast INTENT");
- System.err.println(" am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]");
- System.err.println(" [-w] <COMPONENT> ");
- System.err.println(" am profile <PROCESS> [start <PROF_FILE>|stop]");
- System.err.println("");
- System.err.println(" INTENT is described with:");
- System.err.println(" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]");
- System.err.println(" [-c <CATEGORY> [-c <CATEGORY>] ...]");
- System.err.println(" [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]");
- System.err.println(" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]");
- System.err.println(" [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]");
- System.err.println(" [-n <COMPONENT>] [-f <FLAGS>] [<URI>]");
+ private static void showUsage() {
+ System.err.println(
+ "usage: am [subcommand] [options]\n" +
+ "\n" +
+ " start an Activity: am start [-D] <INTENT>\n" +
+ " -D: enable debugging\n" +
+ "\n" +
+ " send a broadcast Intent: am broadcast <INTENT>\n" +
+ "\n" +
+ " start an Instrumentation: am instrument [flags] <COMPONENT>\n" +
+ " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT)\n" +
+ " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>\n" +
+ " -p <FILE>: write profiling data to <FILE>\n" +
+ " -w: wait for instrumentation to finish before returning\n" +
+ "\n" +
+ " start profiling: am profile <PROCESS> start <FILE>\n" +
+ " stop profiling: am profile <PROCESS> stop\n" +
+ "\n" +
+ " <INTENT> specifications include these flags:\n" +
+ " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
+ " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
+ " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
+ " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
+ " [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
+ " [-n <COMPONENT>] [-f <FLAGS>] [<URI>]\n"
+ );
}
}
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/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index ee3ec1a..8c15d0b 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -268,7 +268,7 @@ public final class Bmgr {
private void printRestoreSets(RestoreSet[] sets) {
for (RestoreSet s : sets) {
- System.out.println(" " + s.token + " : " + s.name);
+ System.out.println(" " + Long.toHexString(s.token) + " : " + s.name);
}
}
@@ -294,7 +294,7 @@ public final class Bmgr {
private void doRestore() {
long token;
try {
- token = Long.parseLong(nextArg());
+ token = Long.parseLong(nextArg(), 16);
} catch (NumberFormatException e) {
showUsage();
return;
@@ -311,12 +311,13 @@ public final class Bmgr {
return;
}
RestoreSet[] sets = mRestore.getAvailableRestoreSets();
- for (RestoreSet s : sets) {
- if (s.token == token) {
- System.out.println("Scheduling restore: " + s.name);
- mRestore.performRestore(token, observer);
- didRestore = true;
- break;
+ if (sets != null) {
+ for (RestoreSet s : sets) {
+ if (s.token == token) {
+ System.out.println("Scheduling restore: " + s.name);
+ didRestore = (mRestore.performRestore(token, observer) == 0);
+ break;
+ }
}
}
if (!didRestore) {
@@ -327,21 +328,27 @@ public final class Bmgr {
printRestoreSets(sets);
}
}
+
+ // if we kicked off a restore successfully, we have to wait for it
+ // to complete before we can shut down the restore session safely
+ if (didRestore) {
+ synchronized (observer) {
+ while (!observer.done) {
+ try {
+ observer.wait();
+ } catch (InterruptedException ex) {
+ }
+ }
+ }
+ }
+
+ // once the restore has finished, close down the session and we're done
mRestore.endRestoreSession();
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
}
- // now wait for it to be done
- synchronized (observer) {
- while (!observer.done) {
- try {
- observer.wait();
- } catch (InterruptedException ex) {
- }
- }
- }
System.out.println("done");
}
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 9c94c2e..3449de1 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -12,12 +12,13 @@ ifeq ($(TARGET_SIMULATOR),true)
endif
endif
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libui \
- libcorecg \
- libsgl \
+ libskia \
libEGL \
libGLESv1_CM
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 2fb3f79..99e513c 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-#define LOG_TAG "BootAnimation"
-
#include <stdint.h>
#include <sys/types.h>
#include <math.h>
#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>
@@ -35,7 +33,8 @@
#include <ui/DisplayInfo.h>
#include <ui/ISurfaceComposer.h>
#include <ui/ISurfaceFlingerClient.h>
-#include <ui/EGLNativeWindowSurface.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
#include <core/SkBitmap.h>
#include <images/SkImageDecoder.h>
@@ -130,15 +129,19 @@ status_t BootAnimation::readyToRun() {
return -1;
// create the native surface
- sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h,
- PIXEL_FORMAT_RGB_565, ISurfaceComposer::eGPU);
+ sp<SurfaceControl> control = session()->createSurface(
+ getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
session()->openTransaction();
- s->setLayer(0x40000000);
+ control->setLayer(0x40000000);
session()->closeTransaction();
+ sp<Surface> s = control->getSurface();
+
// initialize opengl and egl
- const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
+ const EGLint attribs[] = {
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
EGLint w, h, dummy;
EGLint numConfigs;
EGLConfig config;
@@ -148,21 +151,21 @@ status_t BootAnimation::readyToRun() {
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
- eglChooseConfig(display, attribs, &config, 1, &numConfigs);
-
- mNativeWindowSurface = new EGLNativeWindowSurface(s);
- surface = eglCreateWindowSurface(display, config,
- mNativeWindowSurface.get(), NULL);
-
+ EGLUtils::selectConfigForNativeWindow(display, attribs, s.get(), &config);
+ surface = eglCreateWindowSurface(display, config, s.get(), NULL);
context = eglCreateContext(display, config, NULL, NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
- eglMakeCurrent(display, surface, surface, context);
+
+ if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
+ return NO_INIT;
+
mDisplay = display;
mContext = context;
mSurface = surface;
mWidth = w;
mHeight = h;
+ mFlingerSurfaceControl = control;
mFlingerSurface = s;
// initialize GL
@@ -178,8 +181,8 @@ bool BootAnimation::threadLoop() {
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
- mNativeWindowSurface.clear();
mFlingerSurface.clear();
+ mFlingerSurfaceControl.clear();
eglTerminate(mDisplay);
IPCThreadState::self()->stopProcess();
return r;
@@ -200,8 +203,7 @@ bool BootAnimation::android() {
const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
// draw and update only what we need
- mNativeWindowSurface->setSwapRectangle(updateRect.left,
- updateRect.top, updateRect.width(), updateRect.height());
+ mFlingerSurface->setSwapRectangle(updateRect);
glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
updateRect.height());
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 42e9eed..796077d 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -34,7 +34,6 @@ class SkBitmap;
namespace android {
class AssetManager;
-class EGLNativeWindowSurface;
// ---------------------------------------------------------------------------
@@ -68,8 +67,8 @@ private:
EGLDisplay mDisplay;
EGLDisplay mContext;
EGLDisplay mSurface;
+ sp<SurfaceControl> mFlingerSurfaceControl;
sp<Surface> mFlingerSurface;
- sp<EGLNativeWindowSurface> mNativeWindowSurface;
};
// ---------------------------------------------------------------------------
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index a8359c4..3c82fe5 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -18,9 +18,10 @@
#include <cutils/properties.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 <utils/threads.h>
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index cc951c1..18713e9 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -102,7 +102,7 @@ static void dumpstate(int full) {
PRINT("------ PACKAGE UID ERRORS ------");
DUMP("/data/system/uiderrors.txt");
PRINT("------ LAST KERNEL LOG ------");
- DUMP("/proc/last_kmsg");
+ DUMP("/data/last_kmsg");
}
PRINT("========================================================");
PRINT("== build.prop");
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/keystore/netkeystore.c b/cmds/keystore/netkeystore.c
index 637e0d8..bdd5960 100644
--- a/cmds/keystore/netkeystore.c
+++ b/cmds/keystore/netkeystore.c
@@ -242,6 +242,7 @@ static int set_read_timeout(int socket)
{
struct timeval tv;
tv.tv_sec = READ_TIMEOUT;
+ tv.tv_usec = 0;
if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv))
{
LOGE("setsockopt failed");
diff --git a/cmds/keystore/netkeystore.h b/cmds/keystore/netkeystore.h
index a87a667..d80ddae 100644
--- a/cmds/keystore/netkeystore.h
+++ b/cmds/keystore/netkeystore.h
@@ -19,6 +19,7 @@
#define __NETKEYSTORE_H__
#include <stdio.h>
+#include <arpa/inet.h>
#include <cutils/sockets.h>
#include <cutils/log.h>
@@ -68,6 +69,8 @@ static inline int read_marshal(int s, LPC_MARSHAL *cmd)
LOGE("failed to read header\n");
return -1;
}
+ cmd->len = ntohl(cmd->len);
+ cmd->opcode = ntohl(cmd->opcode);
if (cmd->len > BUFFER_MAX) {
LOGE("invalid size %d\n", cmd->len);
return -1;
@@ -82,11 +85,14 @@ static inline int read_marshal(int s, LPC_MARSHAL *cmd)
static inline int write_marshal(int s, LPC_MARSHAL *cmd)
{
+ int len = cmd->len;
+ cmd->len = htonl(cmd->len);
+ cmd->opcode = htonl(cmd->opcode);
if (writex(s, cmd, 2 * sizeof(uint32_t))) {
LOGE("failed to write marshal header\n");
return -1;
}
- if (writex(s, cmd->data, cmd->len)) {
+ if (writex(s, cmd->data, len)) {
LOGE("failed to write marshal data\n");
return -1;
}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index fd9e708..7adaf57 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -546,6 +546,9 @@ public final class Pm {
case PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE:
s = "INSTALL_FAILED_CPU_ABI_INCOMPATIBLE";
break;
+ case PackageManager.INSTALL_FAILED_MISSING_FEATURE:
+ s = "INSTALL_FAILED_MISSING_FEATURE";
+ break;
case PackageManager.INSTALL_PARSE_FAILED_NOT_APK:
s = "INSTALL_PARSE_FAILED_NOT_APK";
break;
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/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index e4aa8b5..f3a4713 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -30,6 +30,7 @@ static struct {
{ AID_MEDIA, "media.audio_flinger" },
{ AID_MEDIA, "media.player" },
{ AID_MEDIA, "media.camera" },
+ { AID_MEDIA, "media.audio_policy" },
{ AID_RADIO, "radio.phone" },
{ AID_RADIO, "radio.sms" },
{ AID_RADIO, "radio.phonesubinfo" },
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
new file mode 100644
index 0000000..ef67611
--- /dev/null
+++ b/cmds/stagefright/Android.mk
@@ -0,0 +1,40 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ JPEGSource.cpp \
+ stagefright.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright
+
+LOCAL_C_INCLUDES:= \
+ frameworks/base/media/libstagefright \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE:= stagefright
+
+include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ record.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright
+
+LOCAL_C_INCLUDES:= \
+ frameworks/base/media/libstagefright \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE:= record
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/stagefright/JPEGSource.cpp b/cmds/stagefright/JPEGSource.cpp
new file mode 100644
index 0000000..a7994ed
--- /dev/null
+++ b/cmds/stagefright/JPEGSource.cpp
@@ -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.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "JPEGSource"
+#include <utils/Log.h>
+
+#include "JPEGSource.h"
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+
+#define JPEG_SOF0 0xC0 /* nStart Of Frame N*/
+#define JPEG_SOF1 0xC1 /* N indicates which compression process*/
+#define JPEG_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use*/
+#define JPEG_SOF3 0xC3
+#define JPEG_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers*/
+#define JPEG_SOF6 0xC6
+#define JPEG_SOF7 0xC7
+#define JPEG_SOF9 0xC9
+#define JPEG_SOF10 0xCA
+#define JPEG_SOF11 0xCB
+#define JPEG_SOF13 0xCD
+#define JPEG_SOF14 0xCE
+#define JPEG_SOF15 0xCF
+#define JPEG_SOI 0xD8 /* nStart Of Image (beginning of datastream)*/
+#define JPEG_EOI 0xD9 /* End Of Image (end of datastream)*/
+#define JPEG_SOS 0xDA /* nStart Of Scan (begins compressed data)*/
+#define JPEG_JFIF 0xE0 /* Jfif marker*/
+#define JPEG_EXIF 0xE1 /* Exif marker*/
+#define JPEG_COM 0xFE /* COMment */
+#define JPEG_DQT 0xDB
+#define JPEG_DHT 0xC4
+#define JPEG_DRI 0xDD
+
+namespace android {
+
+JPEGSource::JPEGSource(const sp<DataSource> &source)
+ : mSource(source),
+ mGroup(NULL),
+ mStarted(false),
+ mSize(0),
+ mWidth(0),
+ mHeight(0),
+ mOffset(0) {
+ CHECK_EQ(parseJPEG(), OK);
+ CHECK(mSource->getSize(&mSize) == OK);
+}
+
+JPEGSource::~JPEGSource() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t JPEGSource::start(MetaData *) {
+ if (mStarted) {
+ return UNKNOWN_ERROR;
+ }
+
+ mGroup = new MediaBufferGroup;
+ mGroup->add_buffer(new MediaBuffer(mSize));
+
+ mOffset = 0;
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t JPEGSource::stop() {
+ if (!mStarted) {
+ return UNKNOWN_ERROR;
+ }
+
+ delete mGroup;
+ mGroup = NULL;
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> JPEGSource::getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, "image/jpeg");
+ meta->setInt32(kKeyWidth, mWidth);
+ meta->setInt32(kKeyHeight, mHeight);
+ meta->setInt32(kKeyCompressedSize, mSize);
+
+ return meta;
+}
+
+status_t JPEGSource::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ *out = NULL;
+
+ int64_t seekTimeUs;
+ if (options != NULL && options->getSeekTo(&seekTimeUs)) {
+ return UNKNOWN_ERROR;
+ }
+
+ MediaBuffer *buffer;
+ mGroup->acquire_buffer(&buffer);
+
+ ssize_t n = mSource->read_at(mOffset, buffer->data(), mSize - mOffset);
+
+ if (n <= 0) {
+ buffer->release();
+ buffer = NULL;
+
+ return UNKNOWN_ERROR;
+ }
+
+ buffer->set_range(0, n);
+
+ mOffset += n;
+
+ *out = buffer;
+
+ return OK;
+}
+
+status_t JPEGSource::parseJPEG() {
+ mWidth = 0;
+ mHeight = 0;
+
+ off_t i = 0;
+
+ uint16_t soi;
+ if (!mSource->getUInt16(i, &soi)) {
+ return ERROR_IO;
+ }
+
+ i += 2;
+
+ if (soi != 0xffd8) {
+ return UNKNOWN_ERROR;
+ }
+
+ for (;;) {
+ uint8_t marker;
+ if (mSource->read_at(i++, &marker, 1) != 1) {
+ return ERROR_IO;
+ }
+
+ CHECK_EQ(marker, 0xff);
+
+ if (mSource->read_at(i++, &marker, 1) != 1) {
+ return ERROR_IO;
+ }
+
+ CHECK(marker != 0xff);
+
+ uint16_t chunkSize;
+ if (!mSource->getUInt16(i, &chunkSize)) {
+ return ERROR_IO;
+ }
+
+ i += 2;
+
+ if (chunkSize < 2) {
+ return UNKNOWN_ERROR;
+ }
+
+ switch (marker) {
+ case JPEG_SOS:
+ {
+ return (mWidth > 0 && mHeight > 0) ? OK : UNKNOWN_ERROR;
+ }
+
+ case JPEG_EOI:
+ {
+ return UNKNOWN_ERROR;
+ }
+
+ case JPEG_SOF0:
+ case JPEG_SOF1:
+ case JPEG_SOF3:
+ case JPEG_SOF5:
+ case JPEG_SOF6:
+ case JPEG_SOF7:
+ case JPEG_SOF9:
+ case JPEG_SOF10:
+ case JPEG_SOF11:
+ case JPEG_SOF13:
+ case JPEG_SOF14:
+ case JPEG_SOF15:
+ {
+ uint16_t width, height;
+ if (!mSource->getUInt16(i + 1, &height)
+ || !mSource->getUInt16(i + 3, &width)) {
+ return ERROR_IO;
+ }
+
+ mWidth = width;
+ mHeight = height;
+
+ i += chunkSize - 2;
+ break;
+ }
+
+ default:
+ {
+ // Skip chunk
+
+ i += chunkSize - 2;
+
+ break;
+ }
+ }
+ }
+
+ return OK;
+}
+
+} // namespace android
diff --git a/cmds/stagefright/JPEGSource.h b/cmds/stagefright/JPEGSource.h
new file mode 100644
index 0000000..051c034
--- /dev/null
+++ b/cmds/stagefright/JPEGSource.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 JPEG_SOURCE_H_
+
+#define JPEG_SOURCE_H_
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+class DataSource;
+class MediaBufferGroup;
+
+struct JPEGSource : public MediaSource {
+ // Assumes ownership of "source".
+ JPEGSource(const sp<DataSource> &source);
+
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+ virtual ~JPEGSource();
+
+private:
+ sp<DataSource> mSource;
+ MediaBufferGroup *mGroup;
+ bool mStarted;
+ off_t mSize;
+ int32_t mWidth, mHeight;
+ off_t mOffset;
+
+ status_t parseJPEG();
+
+ JPEGSource(const JPEGSource &);
+ JPEGSource &operator=(const JPEGSource &);
+};
+
+} // namespace android
+
+#endif // JPEG_SOURCE_H_
+
diff --git a/cmds/stagefright/WaveWriter.h b/cmds/stagefright/WaveWriter.h
new file mode 100644
index 0000000..a0eb66e
--- /dev/null
+++ b/cmds/stagefright/WaveWriter.h
@@ -0,0 +1,71 @@
+/*
+ * 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_WAVEWRITER_H_
+
+#define ANDROID_WAVEWRITER_H_
+
+namespace android {
+
+class WaveWriter {
+public:
+ WaveWriter(const char *filename,
+ uint16_t num_channels, uint32_t sampling_rate)
+ : mFile(fopen(filename, "wb")),
+ mTotalBytes(0) {
+ fwrite("RIFFxxxxWAVEfmt \x10\x00\x00\x00\x01\x00", 1, 22, mFile);
+ write_u16(num_channels);
+ write_u32(sampling_rate);
+ write_u32(sampling_rate * num_channels * 2);
+ write_u16(num_channels * 2);
+ write_u16(16);
+ fwrite("dataxxxx", 1, 8, mFile);
+ }
+
+ ~WaveWriter() {
+ fseek(mFile, 40, SEEK_SET);
+ write_u32(mTotalBytes);
+
+ fseek(mFile, 4, SEEK_SET);
+ write_u32(36 + mTotalBytes);
+
+ fclose(mFile);
+ mFile = NULL;
+ }
+
+ void Append(const void *data, size_t size) {
+ fwrite(data, 1, size, mFile);
+ mTotalBytes += size;
+ }
+
+private:
+ void write_u16(uint16_t x) {
+ fputc(x & 0xff, mFile);
+ fputc(x >> 8, mFile);
+ }
+
+ void write_u32(uint32_t x) {
+ write_u16(x & 0xffff);
+ write_u16(x >> 16);
+ }
+
+ FILE *mFile;
+ size_t mTotalBytes;
+};
+
+} // namespace android
+
+#endif // ANDROID_WAVEWRITER_H_
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
new file mode 100644
index 0000000..4b44761
--- /dev/null
+++ b/cmds/stagefright/record.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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 <binder/ProcessState.h>
+#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+
+using namespace android;
+
+class DummySource : public MediaSource {
+public:
+ DummySource(int width, int height)
+ : mWidth(width),
+ mHeight(height),
+ mSize((width * height * 3) / 2) {
+ mGroup.add_buffer(new MediaBuffer(mSize));
+ }
+
+ virtual sp<MetaData> getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setInt32(kKeyWidth, mWidth);
+ meta->setInt32(kKeyHeight, mHeight);
+ meta->setCString(kKeyMIMEType, "video/raw");
+
+ return meta;
+ }
+
+ virtual status_t getMaxSampleSize(size_t *max_size) {
+ *max_size = mSize;
+ return OK;
+ }
+
+ virtual status_t start(MetaData *params) {
+ return OK;
+ }
+
+ virtual status_t stop() {
+ return OK;
+ }
+
+ virtual status_t read(
+ MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+ status_t err = mGroup.acquire_buffer(buffer);
+ if (err != OK) {
+ return err;
+ }
+
+ char x = (char)((double)rand() / RAND_MAX * 255);
+ memset((*buffer)->data(), x, mSize);
+ (*buffer)->set_range(0, mSize);
+
+ return OK;
+ }
+
+protected:
+ virtual ~DummySource() {}
+
+private:
+ MediaBufferGroup mGroup;
+ int mWidth, mHeight;
+ size_t mSize;
+
+ DummySource(const DummySource &);
+ DummySource &operator=(const DummySource &);
+};
+
+sp<MediaSource> createSource(const char *filename) {
+ sp<MediaSource> source;
+
+ sp<MPEG4Extractor> extractor =
+ new MPEG4Extractor(new MmapSource(filename));
+
+ size_t num_tracks = extractor->countTracks();
+
+ sp<MetaData> meta;
+ for (size_t i = 0; i < num_tracks; ++i) {
+ meta = extractor->getTrackMetaData(i);
+ CHECK(meta.get() != NULL);
+
+ const char *mime;
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ continue;
+ }
+
+ if (strncasecmp(mime, "video/", 6)) {
+ continue;
+ }
+
+ source = extractor->getTrack(i);
+ break;
+ }
+
+ return source;
+}
+
+int main(int argc, char **argv) {
+ android::ProcessState::self()->startThreadPool();
+
+#if 1
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s filename\n", argv[0]);
+ return 1;
+ }
+
+ OMXClient client;
+ CHECK_EQ(client.connect(), OK);
+
+#if 0
+ sp<MediaSource> source = createSource(argv[1]);
+
+ if (source == NULL) {
+ fprintf(stderr, "Unable to find a suitable video track.\n");
+ return 1;
+ }
+
+ sp<MetaData> meta = source->getFormat();
+
+ sp<OMXCodec> decoder = OMXCodec::Create(
+ client.interface(), meta, false /* createEncoder */, source);
+
+ int width, height;
+ bool success = meta->findInt32(kKeyWidth, &width);
+ success = success && meta->findInt32(kKeyHeight, &height);
+ CHECK(success);
+#else
+ int width = 320;
+ int height = 240;
+ sp<MediaSource> decoder = new DummySource(width, height);
+#endif
+
+ sp<MetaData> enc_meta = new MetaData;
+ // enc_meta->setCString(kKeyMIMEType, "video/3gpp");
+ enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
+ enc_meta->setInt32(kKeyWidth, width);
+ enc_meta->setInt32(kKeyHeight, height);
+
+ sp<OMXCodec> encoder =
+ OMXCodec::Create(
+ client.interface(), enc_meta, true /* createEncoder */, decoder);
+
+#if 1
+ sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
+ writer->addSource(enc_meta, encoder);
+ writer->start();
+ sleep(20);
+ printf("stopping now.\n");
+ writer->stop();
+#else
+ encoder->start();
+
+ MediaBuffer *buffer;
+ while (encoder->read(&buffer) == OK) {
+ printf("got an output frame of size %d\n", buffer->range_length());
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ encoder->stop();
+#endif
+
+ client.disconnect();
+#endif
+
+#if 0
+ CameraSource *source = CameraSource::Create();
+ printf("source = %p\n", source);
+
+ for (int i = 0; i < 100; ++i) {
+ MediaBuffer *buffer;
+ status_t err = source->read(&buffer);
+ CHECK_EQ(err, OK);
+
+ printf("got a frame, data=%p, size=%d\n",
+ buffer->data(), buffer->range_length());
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ delete source;
+ source = NULL;
+#endif
+
+ return 0;
+}
+
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
new file mode 100644
index 0000000..54c6a0c
--- /dev/null
+++ b/cmds/stagefright/stagefright.cpp
@@ -0,0 +1,265 @@
+/*
+ * 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 <sys/time.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/CachingDataSource.h>
+#include <media/stagefright/HTTPDataSource.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaPlayerImpl.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+
+#include "JPEGSource.h"
+
+using namespace android;
+
+static long gNumRepetitions;
+static long gMaxNumFrames; // 0 means decode all available.
+static long gReproduceBug; // if not -1.
+
+static int64_t getNowUs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
+}
+
+static void playSource(OMXClient *client, const sp<MediaSource> &source) {
+ sp<MetaData> meta = source->getFormat();
+
+ sp<OMXCodec> decoder = OMXCodec::Create(
+ client->interface(), meta, false /* createEncoder */, source);
+
+ if (decoder == NULL) {
+ return;
+ }
+
+ decoder->start();
+
+ int n = 0;
+ int64_t startTime = getNowUs();
+
+ long numIterationsLeft = gNumRepetitions;
+ MediaSource::ReadOptions options;
+
+ while (numIterationsLeft-- > 0) {
+ long numFrames = 0;
+
+ MediaBuffer *buffer;
+
+ for (;;) {
+ status_t err = decoder->read(&buffer, &options);
+ options.clearSeekTo();
+
+ if (err != OK) {
+ CHECK_EQ(buffer, NULL);
+ break;
+ }
+
+ if ((n++ % 16) == 0) {
+ printf(".");
+ fflush(stdout);
+ }
+
+ buffer->release();
+ buffer = NULL;
+
+ ++numFrames;
+ if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) {
+ break;
+ }
+
+ if (gReproduceBug == 1 && numFrames == 40) {
+ printf("seeking past the end now.");
+ options.setSeekTo(0x7fffffffL);
+ }
+ }
+
+ printf("$");
+ fflush(stdout);
+
+ options.setSeekTo(0);
+ }
+
+ decoder->stop();
+ printf("\n");
+
+ int64_t delay = getNowUs() - startTime;
+ printf("avg. %.2f fps\n", n * 1E6 / delay);
+
+ printf("decoded a total of %d frame(s).\n", n);
+}
+
+static void usage(const char *me) {
+ fprintf(stderr, "usage: %s\n", me);
+ fprintf(stderr, " -h(elp)\n");
+ fprintf(stderr, " -a(udio)\n");
+ fprintf(stderr, " -n repetitions\n");
+ fprintf(stderr, " -l(ist) components\n");
+ fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n");
+ fprintf(stderr, " -b bug to reproduce\n");
+}
+
+int main(int argc, char **argv) {
+ android::ProcessState::self()->startThreadPool();
+
+ bool audioOnly = false;
+ bool listComponents = false;
+ gNumRepetitions = 1;
+ gMaxNumFrames = 0;
+ gReproduceBug = -1;
+
+ int res;
+ while ((res = getopt(argc, argv, "han:lm:b:")) >= 0) {
+ switch (res) {
+ case 'a':
+ {
+ audioOnly = true;
+ break;
+ }
+
+ case 'l':
+ {
+ listComponents = true;
+ break;
+ }
+
+ case 'm':
+ case 'n':
+ case 'b':
+ {
+ char *end;
+ long x = strtol(optarg, &end, 10);
+
+ if (*end != '\0' || end == optarg || x <= 0) {
+ x = 1;
+ }
+
+ if (res == 'n') {
+ gNumRepetitions = x;
+ } else if (res == 'm') {
+ gMaxNumFrames = x;
+ } else {
+ CHECK_EQ(res, 'b');
+ gReproduceBug = x;
+ }
+ break;
+ }
+
+ case '?':
+ case 'h':
+ default:
+ {
+ usage(argv[0]);
+ exit(1);
+ break;
+ }
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (listComponents) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+
+ CHECK(service.get() != NULL);
+
+ sp<IOMX> omx = service->createOMX();
+ CHECK(omx.get() != NULL);
+
+ List<String8> list;
+ omx->list_nodes(&list);
+
+ for (List<String8>::iterator it = list.begin();
+ it != list.end(); ++it) {
+ printf("%s\n", (*it).string());
+ }
+ }
+
+ DataSource::RegisterDefaultSniffers();
+
+ OMXClient client;
+ status_t err = client.connect();
+
+ for (int k = 0; k < argc; ++k) {
+ const char *filename = argv[k];
+
+ sp<DataSource> dataSource;
+ if (!strncasecmp("http://", filename, 7)) {
+ dataSource = new HTTPDataSource(filename);
+ dataSource = new CachingDataSource(dataSource, 64 * 1024, 10);
+ } else {
+ dataSource = new MmapSource(filename);
+ }
+
+ bool isJPEG = false;
+
+ size_t len = strlen(filename);
+ if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) {
+ isJPEG = true;
+ }
+
+ sp<MediaSource> mediaSource;
+
+ if (isJPEG) {
+ mediaSource = new JPEGSource(dataSource);
+ } else {
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+
+ size_t numTracks = extractor->countTracks();
+
+ sp<MetaData> meta;
+ size_t i;
+ for (i = 0; i < numTracks; ++i) {
+ meta = extractor->getTrackMetaData(i);
+
+ const char *mime;
+ meta->findCString(kKeyMIMEType, &mime);
+
+ if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
+ break;
+ }
+
+ if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
+ break;
+ }
+ }
+
+ mediaSource = extractor->getTrack(i);
+ }
+
+ playSource(&client, mediaSource);
+ }
+
+ client.disconnect();
+
+ return 0;
+}
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/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index 2b54f54..e021012 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -16,7 +16,10 @@
package com.android.commands.svc;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.IPowerManager;
+import android.os.PowerManager;
import android.os.ServiceManager;
import android.os.RemoteException;
import android.os.BatteryManager;
@@ -60,7 +63,10 @@ public class PowerCommand extends Svc.Command {
IPowerManager pm
= IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
try {
+ IBinder lock = new Binder();
+ pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power");
pm.setStayOnSetting(val);
+ pm.releaseWakeLock(lock);
}
catch (RemoteException e) {
System.err.println("Faild to set setting: " + e);
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..1d57fdc 100644
--- a/cmds/system_server/library/system_init.cpp
+++ b/cmds/system_server/library/system_init.cpp
@@ -8,15 +8,16 @@
#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>
#include <SurfaceFlinger.h>
#include <AudioFlinger.h>
#include <CameraService.h>
+#include <AudioPolicyService.h>
#include <MediaPlayerService.h>
#include <android_runtime/AndroidRuntime.h>
@@ -80,6 +81,9 @@ extern "C" status_t system_init()
// Start the camera service
CameraService::instantiate();
+
+ // Start the audio policy service
+ AudioPolicyService::instantiate();
}
// And now start the Android runtime. We have to do this bit
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/GoogleLocationSettingManager.java b/core/java/android/GoogleLocationSettingManager.java
new file mode 100644
index 0000000..fe7fce6
--- /dev/null
+++ b/core/java/android/GoogleLocationSettingManager.java
@@ -0,0 +1,156 @@
+/*
+ * 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.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.provider.Settings;
+
+import java.util.HashSet;
+
+/**
+ * A class to manage the interaction between the system setting 'Location &
+ * Security - Share with Google' and the browser. When this setting is set
+ * to true, we allow Geolocation for Google origins. When this setting is
+ * set to false, we clear Geolocation permissions for Google origins.
+ * @hide pending API council review
+ */
+class GoogleLocationSettingManager {
+ // The application context.
+ private Context mContext;
+ // The observer used to listen to the system setting.
+ private GoogleLocationSettingObserver mSettingObserver;
+
+ // The value of the system setting that indicates true.
+ private final static int sSystemSettingTrue = 1;
+ // The value of the system setting that indicates false.
+ private final static int sSystemSettingFalse = 0;
+ // The value of the USE_LOCATION_FOR_SERVICES system setting last read
+ // by the browser.
+ private final static String LAST_READ_USE_LOCATION_FOR_SERVICES =
+ "lastReadUseLocationForServices";
+ // The Google origins we consider.
+ private static HashSet<String> sGoogleOrigins;
+ static {
+ sGoogleOrigins = new HashSet<String>();
+ // NOTE: DO NOT ADD A "/" AT THE END!
+ sGoogleOrigins.add("http://www.google.com");
+ sGoogleOrigins.add("http://www.google.co.uk");
+ }
+
+ GoogleLocationSettingManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Starts the manager. Checks whether the setting has changed and
+ * installs an observer to listen for future changes.
+ */
+ public void start() {
+ maybeApplySetting();
+
+ mSettingObserver = new GoogleLocationSettingObserver();
+ mSettingObserver.observe();
+ }
+
+ /**
+ * Checks to see if the system setting has changed and if so,
+ * updates the Geolocation permissions accordingly.
+ */
+ private void maybeApplySetting() {
+ int setting = getSystemSetting();
+ if (settingChanged(setting)) {
+ applySetting(setting);
+ }
+ }
+
+ /**
+ * Gets the current system setting for 'Use location for Google services'.
+ * @return The system setting.
+ */
+ private int getSystemSetting() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.USE_LOCATION_FOR_SERVICES,
+ sSystemSettingFalse);
+ }
+
+ /**
+ * Determines whether the supplied setting has changed from the last
+ * value read by the browser.
+ * @param setting The setting.
+ * @return Whether the setting has changed from the last value read
+ * by the browser.
+ */
+ private boolean settingChanged(int setting) {
+ SharedPreferences preferences =
+ PreferenceManager.getDefaultSharedPreferences(mContext);
+ // Default to false. If the system setting is false the first time it is ever read by the
+ // browser, there's nothing to do.
+ int lastReadSetting = sSystemSettingFalse;
+ lastReadSetting = preferences.getInt(LAST_READ_USE_LOCATION_FOR_SERVICES,
+ lastReadSetting);
+
+ if (lastReadSetting == setting) {
+ return false;
+ }
+
+ Editor editor = preferences.edit();
+ editor.putInt(LAST_READ_USE_LOCATION_FOR_SERVICES, setting);
+ editor.commit();
+ return true;
+ }
+
+ /**
+ * Applies the supplied setting to the Geolocation permissions.
+ * @param setting The setting.
+ */
+ private void applySetting(int setting) {
+ for (String origin : sGoogleOrigins) {
+ if (setting == sSystemSettingTrue) {
+ GeolocationPermissions.getInstance().allow(origin);
+ } else {
+ GeolocationPermissions.getInstance().clear(origin);
+ }
+ }
+ }
+
+ /**
+ * This class implements an observer to listen for changes to the
+ * system setting.
+ */
+ class GoogleLocationSettingObserver extends ContentObserver {
+ GoogleLocationSettingObserver() {
+ super(new Handler());
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.USE_LOCATION_FOR_SERVICES), false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ maybeApplySetting();
+ }
+ }
+}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 79bd6e7..8c422a2 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -211,8 +211,10 @@ public abstract class AccessibilityService extends Service {
switch (message.what) {
case DO_ON_ACCESSIBILITY_EVENT :
AccessibilityEvent event = (AccessibilityEvent) message.obj;
- mTarget.onAccessibilityEvent(event);
- event.recycle();
+ if (event != null){
+ mTarget.onAccessibilityEvent(event);
+ event.recycle();
+ }
return;
case DO_ON_INTERRUPT :
mTarget.onInterrupt();
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
new file mode 100644
index 0000000..38ae962
--- /dev/null
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -0,0 +1,266 @@
+/*
+ * 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;
+import android.os.Binder;
+import android.util.Log;
+import android.content.pm.PackageManager;
+import android.content.Context;
+import android.Manifest;
+
+/**
+ * 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 {
+ private final Context mContext;
+
+ public AbstractAccountAuthenticator(Context context) {
+ mContext = context;
+ }
+
+ class Transport extends IAccountAuthenticator.Stub {
+ public void addAccount(IAccountAuthenticatorResponse response, String accountType,
+ String authTokenType, String[] requiredFeatures, Bundle options)
+ throws RemoteException {
+ checkBinderPermission();
+ 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 {
+ checkBinderPermission();
+ 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 {
+ checkBinderPermission();
+ 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 getAuthTokenLabel(IAccountAuthenticatorResponse response,
+ String authTokenType)
+ throws RemoteException {
+ checkBinderPermission();
+ try {
+ Bundle result = new Bundle();
+ result.putString(Constants.AUTH_TOKEN_LABEL_KEY,
+ AbstractAccountAuthenticator.this.getAuthTokenLabel(authTokenType));
+ response.onResult(result);
+ } catch (IllegalArgumentException e) {
+ response.onError(Constants.ERROR_CODE_BAD_ARGUMENTS,
+ "unknown authTokenType");
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "getAuthTokenTypeLabel not supported");
+ }
+ }
+
+ public void getAuthToken(IAccountAuthenticatorResponse response,
+ Account account, String authTokenType, Bundle loginOptions)
+ throws RemoteException {
+ checkBinderPermission();
+ 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 {
+ checkBinderPermission();
+ 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 {
+ checkBinderPermission();
+ 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 {
+ checkBinderPermission();
+ 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);
+ }
+ }
+
+ public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response,
+ Account account) throws RemoteException {
+ checkBinderPermission();
+ try {
+ final Bundle result = AbstractAccountAuthenticator.this.getAccountRemovalAllowed(
+ new AccountAuthenticatorResponse(response), account);
+ if (result != null) {
+ response.onResult(result);
+ }
+ } catch (UnsupportedOperationException e) {
+ response.onError(Constants.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "getAccountRemovalAllowed not supported");
+ return;
+ } catch (NetworkErrorException e) {
+ response.onError(Constants.ERROR_CODE_NETWORK_ERROR, e.getMessage());
+ return;
+ }
+ }
+ }
+
+ private void checkBinderPermission() {
+ final int uid = Binder.getCallingUid();
+ final String perm = Manifest.permission.ACCOUNT_MANAGER_SERVICE;
+ if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("caller uid " + uid + " lacks " + perm);
+ }
+ }
+
+ 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 String getAuthTokenLabel(String authTokenType);
+ public abstract Bundle updateCredentials(AccountAuthenticatorResponse response,
+ Account account, String authTokenType, Bundle loginOptions);
+ public abstract Bundle hasFeatures(AccountAuthenticatorResponse response,
+ Account account, String[] features) throws NetworkErrorException;
+ public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response,
+ Account account) throws NetworkErrorException {
+ final Bundle result = new Bundle();
+ result.putBoolean(Constants.BOOLEAN_RESULT_KEY, true);
+ return result;
+ }
+}
diff --git a/core/java/android/accounts/Account.aidl b/core/java/android/accounts/Account.aidl
new file mode 100644
index 0000000..8752d99
--- /dev/null
+++ b/core/java/android/accounts/Account.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+parcelable Account;
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
new file mode 100644
index 0000000..7b83a30
--- /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 name;
+ public final String type;
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof Account)) return false;
+ final Account other = (Account)o;
+ return name.equals(other.name) && type.equals(other.type);
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + name.hashCode();
+ result = 31 * result + type.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);
+ }
+ this.name = name;
+ this.type = type;
+ }
+
+ public Account(Parcel in) {
+ this.name = in.readString();
+ this.type = in.readString();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(name);
+ dest.writeString(type);
+ }
+
+ 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=" + name + ", type=" + type + "}";
+ }
+}
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..82cadd5
--- /dev/null
+++ b/core/java/android/accounts/AccountAuthenticatorCache.java
@@ -0,0 +1,60 @@
+/*
+ * 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.RegisteredServicesCache;
+import android.content.res.TypedArray;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.text.TextUtils;
+
+/**
+ * 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<AuthenticatorDescription> {
+ private static final String TAG = "Account";
+
+ public AccountAuthenticatorCache(Context context) {
+ super(context, Constants.AUTHENTICATOR_INTENT_ACTION,
+ Constants.AUTHENTICATOR_META_DATA_NAME, Constants.AUTHENTICATOR_ATTRIBUTES_NAME);
+ }
+
+ public AuthenticatorDescription parseServiceAttributes(String packageName, AttributeSet attrs) {
+ TypedArray sa = mContext.getResources().obtainAttributes(attrs,
+ com.android.internal.R.styleable.AccountAuthenticator);
+ try {
+ final String accountType =
+ sa.getString(com.android.internal.R.styleable.AccountAuthenticator_accountType);
+ final int labelId = sa.getResourceId(
+ com.android.internal.R.styleable.AccountAuthenticator_label, 0);
+ final int iconId = sa.getResourceId(
+ com.android.internal.R.styleable.AccountAuthenticator_icon, 0);
+ if (TextUtils.isEmpty(accountType)) {
+ return null;
+ }
+ return new AuthenticatorDescription(accountType, packageName, labelId, iconId);
+ } 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..d04abe5
--- /dev/null
+++ b/core/java/android/accounts/AccountManager.java
@@ -0,0 +1,856 @@
+/*
+ * 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 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 getPassword(final Account account) {
+ try {
+ return mService.getPassword(account);
+ } catch (RemoteException e) {
+ // will never happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String getUserData(final Account account, final String key) {
+ try {
+ return mService.getUserData(account, key);
+ } catch (RemoteException e) {
+ // will never happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public AuthenticatorDescription[] getAuthenticatorTypes() {
+ try {
+ return mService.getAuthenticatorTypes();
+ } catch (RemoteException e) {
+ // will never happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Account[] getAccounts() {
+ try {
+ return mService.getAccounts(null);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Account[] getAccountsByType(String type) {
+ try {
+ return mService.getAccounts(type);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
+ try {
+ return mService.addAccount(account, password, extras);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public AccountManagerFuture<Boolean> removeAccount(final Account account,
+ AccountManagerCallback<Boolean> callback, Handler handler) {
+ return new Future2Task<Boolean>(handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.removeAccount(mResponse, account);
+ }
+ public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
+ if (!bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) {
+ throw new AuthenticatorException("no result in response");
+ }
+ return bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY);
+ }
+ }.start();
+ }
+
+ public void invalidateAuthToken(final String accountType, final String authToken) {
+ try {
+ mService.invalidateAuthToken(accountType, authToken);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String peekAuthToken(final Account account, final String authTokenType) {
+ try {
+ return mService.peekAuthToken(account, authTokenType);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setPassword(final Account account, final String password) {
+ try {
+ mService.setPassword(account, password);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void clearPassword(final Account account) {
+ try {
+ mService.clearPassword(account);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setUserData(final Account account, final String key, final String value) {
+ try {
+ mService.setUserData(account, key, value);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setAuthToken(Account account, final String authTokenType, final String authToken) {
+ try {
+ mService.setAuthToken(account, authTokenType, authToken);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String blockingGetAuthToken(Account account, String authTokenType,
+ boolean notifyAuthFailure)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ 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 AccountManagerFuture<Bundle> getAuthToken(
+ final Account account, final String authTokenType, final Bundle loginOptions,
+ final Activity activity, AccountManagerCallback<Bundle> 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 AccountManagerFuture<Bundle> getAuthToken(
+ final Account account, final String authTokenType, final boolean notifyAuthFailure,
+ AccountManagerCallback<Bundle> 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 AccountManagerFuture<Bundle> addAccount(final String accountType,
+ final String authTokenType, final String[] requiredFeatures,
+ final Bundle addAccountOptions,
+ final Activity activity, AccountManagerCallback<Bundle> 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 */
+ @Deprecated
+ public AccountManagerFuture<Boolean> confirmPassword(final Account account, final String password,
+ AccountManagerCallback<Boolean> callback, Handler handler) {
+ return new Future2Task<Boolean>(handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.confirmPassword(mResponse, account, password);
+ }
+ public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
+ if (!bundle.containsKey(Constants.BOOLEAN_RESULT_KEY)) {
+ throw new AuthenticatorException("no result in response");
+ }
+ return bundle.getBoolean(Constants.BOOLEAN_RESULT_KEY);
+ }
+ }.start();
+ }
+
+ public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
+ final String type, final String[] features,
+ AccountManagerCallback<Account[]> callback, Handler handler) {
+ if (type == null) throw new IllegalArgumentException("type is null");
+ return new Future2Task<Account[]>(handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.getAccountsByFeatures(mResponse, type, features);
+ }
+ public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
+ if (!bundle.containsKey(Constants.ACCOUNTS_KEY)) {
+ throw new AuthenticatorException("no result in response");
+ }
+ final Parcelable[] parcelables = bundle.getParcelableArray(Constants.ACCOUNTS_KEY);
+ Account[] descs = new Account[parcelables.length];
+ for (int i = 0; i < parcelables.length; i++) {
+ descs[i] = (Account) parcelables[i];
+ }
+ return descs;
+ }
+ }.start();
+ }
+
+ public AccountManagerFuture<Bundle> confirmCredentials(final Account account, final Activity activity,
+ final AccountManagerCallback<Bundle> callback,
+ final Handler handler) {
+ return new AmsTask(activity, handler, callback) {
+ public void doWork() throws RemoteException {
+ mService.confirmCredentials(mResponse, account, activity != null);
+ }
+ }.start();
+ }
+
+ public AccountManagerFuture<Bundle> updateCredentials(final Account account, final String authTokenType,
+ final Bundle loginOptions, final Activity activity,
+ final AccountManagerCallback<Bundle> 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 AccountManagerFuture<Bundle> editProperties(final String accountType, final Activity activity,
+ final AccountManagerCallback<Bundle> 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 AccountManagerCallback<Bundle> callback,
+ final AccountManagerFuture<Bundle> 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) {
+ final Account[] accountsCopy = new Account[accounts.length];
+ // send a copy to make sure that one doesn't
+ // change what another sees
+ System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
+ handler = (handler == null) ? mMainHandler : handler;
+ handler.post(new Runnable() {
+ public void run() {
+ listener.onAccountsUpdated(accountsCopy);
+ }
+ });
+ }
+
+ private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {
+ final IAccountManagerResponse mResponse;
+ final Handler mHandler;
+ final AccountManagerCallback<Bundle> mCallback;
+ final Activity mActivity;
+ public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> 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();
+ }
+
+ public final AccountManagerFuture<Bundle> start() {
+ try {
+ doWork();
+ } catch (RemoteException e) {
+ setException(e);
+ }
+ return this;
+ }
+
+ public abstract void doWork() throws RemoteException;
+
+ private Bundle internalGetResult(Long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ ensureNotOnMainThread();
+ 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 if (bundle.getBoolean("retry")) {
+ try {
+ doWork();
+ } catch (RemoteException e) {
+ // this will only happen if the system process is dead, which means
+ // we will be dying ourselves
+ }
+ } 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 BaseFutureTask<T> extends FutureTask<T> {
+ final public IAccountManagerResponse mResponse;
+ final Handler mHandler;
+
+ public BaseFutureTask(Handler handler) {
+ super(new Callable<T>() {
+ public T call() throws Exception {
+ throw new IllegalStateException("this should never be called");
+ }
+ });
+ mHandler = handler;
+ mResponse = new Response();
+ }
+
+ public abstract void doWork() throws RemoteException;
+
+ public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException;
+
+ protected void postRunnableToHandler(Runnable runnable) {
+ Handler handler = (mHandler == null) ? mMainHandler : mHandler;
+ handler.post(runnable);
+ }
+
+ protected void startTask() {
+ try {
+ doWork();
+ } catch (RemoteException e) {
+ setException(e);
+ }
+ }
+
+ protected class Response extends IAccountManagerResponse.Stub {
+ public void onResult(Bundle bundle) {
+ try {
+ T result = bundleToResult(bundle);
+ if (result == null) {
+ return;
+ }
+ set(result);
+ return;
+ } catch (ClassCastException e) {
+ // we will set the exception below
+ } catch (AuthenticatorException 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 abstract class Future2Task<T>
+ extends BaseFutureTask<T> implements AccountManagerFuture<T> {
+ final AccountManagerCallback<T> mCallback;
+ public Future2Task(Handler handler, AccountManagerCallback<T> callback) {
+ super(handler);
+ mCallback = callback;
+ }
+
+ protected void done() {
+ if (mCallback != null) {
+ postRunnableToHandler(new Runnable() {
+ public void run() {
+ mCallback.run(Future2Task.this);
+ }
+ });
+ }
+ }
+
+ public Future2Task<T> start() {
+ startTask();
+ return this;
+ }
+
+ private T internalGetResult(Long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ ensureNotOnMainThread();
+ 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) {
+ // 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 T getResult()
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return internalGetResult(null, null);
+ }
+
+ public T getResult(long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException {
+ return internalGetResult(timeout, unit);
+ }
+
+ }
+
+ 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 AccountManagerCallback<Bundle> {
+ GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
+ final String[] features, Activity activityForPrompting,
+ final Bundle addAccountOptions, final Bundle loginOptions,
+ AccountManagerCallback<Bundle> 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 AccountManagerFuture<Bundle> mFuture = null;
+ final String mAccountType;
+ final String mAuthTokenType;
+ final String[] mFeatures;
+ final Bundle mAddAccountOptions;
+ final Bundle mLoginOptions;
+ final AccountManagerCallback<Bundle> mMyCallback;
+
+ public void doWork() throws RemoteException {
+ getAccountsByTypeAndFeatures(mAccountType, mFeatures,
+ new AccountManagerCallback<Account[]>() {
+ public void run(AccountManagerFuture<Account[]> future) {
+ Account[] accounts;
+ try {
+ accounts = future.getResult();
+ } catch (OperationCanceledException e) {
+ setException(e);
+ return;
+ } catch (IOException e) {
+ setException(e);
+ return;
+ } catch (AuthenticatorException e) {
+ setException(e);
+ return;
+ }
+
+ 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(accounts[0], mAuthTokenType,
+ false /* notifyAuthFailure */, mMyCallback, mHandler);
+ } else {
+ mFuture = getAuthToken(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(AccountManagerFuture<Bundle> 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 AccountManagerCallback<Bundle> 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();
+
+ /**
+ * 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) {
+ final Account[] accounts = getAccounts();
+ // send the result to the listeners
+ synchronized (mAccountsUpdatedListeners) {
+ for (Map.Entry<OnAccountsUpdatedListener, Handler> entry :
+ mAccountsUpdatedListeners.entrySet()) {
+ postToHandler(entry.getValue(), entry.getKey(), accounts);
+ }
+ }
+ }
+ };
+
+ /**
+ * 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) {
+ postToHandler(handler, listener, getAccounts());
+ }
+ }
+
+ /**
+ * 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/AccountManagerCallback.java b/core/java/android/accounts/AccountManagerCallback.java
new file mode 100644
index 0000000..4aa7169
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerCallback.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 AccountManagerCallback<V> {
+ void run(AccountManagerFuture<V> future);
+} \ No newline at end of file
diff --git a/core/java/android/accounts/AccountManagerFuture.java b/core/java/android/accounts/AccountManagerFuture.java
new file mode 100644
index 0000000..74d83eb
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerFuture.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.io.IOException;
+
+/**
+ * An extension of {@link java.util.concurrent.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 android.accounts.AccountManager}.
+ */
+public interface AccountManagerFuture<V> extends Future<V> {
+ /**
+ * Wrapper for {@link java.util.concurrent.Future#get()}. If the get() throws
+ * {@link InterruptedException} then the
+ * {@link AccountManagerFuture} is canceled and
+ * {@link android.accounts.OperationCanceledException} is thrown.
+ * @return the {@link android.os.Bundle} that is returned by get()
+ * @throws android.accounts.OperationCanceledException if get() throws the unchecked
+ * CancellationException
+ * or if the Future was interrupted.
+ */
+ V getResult() throws OperationCanceledException, IOException, AuthenticatorException;
+
+ /**
+ * Wrapper for {@link java.util.concurrent.Future#get()}. If the get() throws
+ * {@link InterruptedException} then the
+ * {@link AccountManagerFuture} is canceled and
+ * {@link android.accounts.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 java.util.concurrent.Future#get()}
+ * @throws android.accounts.OperationCanceledException if get() throws the unchecked
+ * {@link java.util.concurrent.CancellationException} or if the {@link AccountManagerFuture}
+ * was interrupted.
+ */
+ V getResult(long timeout, TimeUnit unit)
+ throws OperationCanceledException, IOException, AuthenticatorException;
+
+ /** @deprecated Use {@link #getResult} */
+ @Deprecated
+ V get() throws InterruptedException, ExecutionException;
+
+ /** @deprecated Use {@link #getResult} */
+ @Deprecated
+ V get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException;
+} \ No newline at end of file
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..5ed8941
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -0,0 +1,1622 @@
+/*
+ * 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.content.pm.PackageManager;
+import android.content.pm.RegisteredServicesCache;
+import android.content.pm.PackageInfo;
+import android.content.pm.ApplicationInfo;
+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.os.Binder;
+import android.os.SystemProperties;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.app.PendingIntent;
+import android.app.NotificationManager;
+import android.app.Notification;
+import android.app.Activity;
+import android.Manifest;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+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 = 3;
+
+ 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_GRANTS = "grants";
+ private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
+ private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
+ private static final String GRANTS_GRANTEE_UID = "uid";
+
+ 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;
+
+ private static final String COUNT_OF_MATCHING_GRANTS = ""
+ + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
+ + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
+ + " AND " + GRANTS_GRANTEE_UID + "=?"
+ + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
+ + " AND " + ACCOUNTS_NAME + "=?"
+ + " AND " + ACCOUNTS_TYPE + "=?";
+
+ private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
+ private final AtomicInteger mNotificationIds = new AtomicInteger(1);
+
+ private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
+ mCredentialsPermissionNotificationIds =
+ new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
+ private final HashMap<Account, Integer> mSigninRequiredNotificationIds =
+ new HashMap<Account, Integer>();
+ private static AtomicReference<AccountManagerService> sThis =
+ new AtomicReference<AccountManagerService>();
+
+ private static final boolean isDebuggableMonkeyBuild =
+ SystemProperties.getBoolean("ro.monkey", false)
+ && SystemProperties.getBoolean("ro.debuggable", false);
+
+ static {
+ ACCOUNTS_CHANGED_INTENT = new Intent(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
+ ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ }
+
+ /**
+ * This should only be called by system code. One should only call this after the service
+ * has started.
+ * @return a reference to the AccountManagerService instance
+ * @hide
+ */
+ public static AccountManagerService getSingleton() {
+ return sThis.get();
+ }
+
+ 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);
+ sThis.set(this);
+ }
+
+ public String getPassword(Account account) {
+ checkAuthenticateAccountsPermission(account);
+
+ long identityToken = clearCallingIdentity();
+ try {
+ return readPasswordFromDatabase(account);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private String readPasswordFromDatabase(Account account) {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.name, account.type}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ public String getUserData(Account account, String key) {
+ checkAuthenticateAccountsPermission(account);
+ long identityToken = clearCallingIdentity();
+ try {
+ return readUserDataFromDatabase(account, key);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private String readUserDataFromDatabase(Account account, String key) {
+ 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.endTransaction();
+ }
+ }
+
+ public AuthenticatorDescription[] getAuthenticatorTypes() {
+ long identityToken = clearCallingIdentity();
+ try {
+ Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
+ authenticatorCollection = mAuthenticatorCache.getAllServices();
+ AuthenticatorDescription[] types =
+ new AuthenticatorDescription[authenticatorCollection.size()];
+ int i = 0;
+ for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
+ : authenticatorCollection) {
+ types[i] = authenticator.type;
+ i++;
+ }
+ return types;
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public Account[] getAccountsByType(String accountType) {
+ 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();
+ }
+ }
+
+ public boolean addAccount(Account account, String password, Bundle extras) {
+ checkAuthenticateAccountsPermission(account);
+
+ // fails if the account already exists
+ long identityToken = clearCallingIdentity();
+ try {
+ return insertAccountIntoDatabase(account, password, extras);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private boolean insertAccountIntoDatabase(Account account, String password, Bundle extras) {
+ 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.name, account.type});
+ if (numMatches > 0) {
+ return false;
+ }
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ 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();
+ }
+ }
+
+ 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(IAccountManagerResponse response, Account account) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ new RemoveAccountSession(response, account).bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private class RemoveAccountSession extends Session {
+ final Account mAccount;
+ public RemoveAccountSession(IAccountManagerResponse response, Account account) {
+ super(response, account.type, false /* expectActivityLaunch */);
+ mAccount = account;
+ }
+
+ protected String toDebugString(long now) {
+ return super.toDebugString(now) + ", removeAccount"
+ + ", account " + mAccount;
+ }
+
+ public void run() throws RemoteException {
+ mAuthenticator.getAccountRemovalAllowed(this, mAccount);
+ }
+
+ public void onResult(Bundle result) {
+ if (result != null && result.containsKey(Constants.BOOLEAN_RESULT_KEY)
+ && !result.containsKey(Constants.INTENT_KEY)) {
+ final boolean removalAllowed = result.getBoolean(Constants.BOOLEAN_RESULT_KEY);
+ if (removalAllowed) {
+ removeAccount(mAccount);
+ }
+ IAccountManagerResponse response = getResponseAndClose();
+ if (response != null) {
+ Bundle result2 = new Bundle();
+ result2.putBoolean(Constants.BOOLEAN_RESULT_KEY, removalAllowed);
+ try {
+ response.onResult(result2);
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+ }
+ super.onResult(result);
+ }
+ }
+
+ private void removeAccount(Account account) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+ new String[]{account.name, account.type});
+ sendAccountsChangedBroadcast();
+ }
+
+ public void invalidateAuthToken(String accountType, String authToken) {
+ checkManageAccountsPermission();
+ 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) {
+ if (authToken == null || accountType == null) {
+ return;
+ }
+ 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.endTransaction();
+ }
+ }
+
+ public String peekAuthToken(Account account, String authTokenType) {
+ checkAuthenticateAccountsPermission(account);
+ long identityToken = clearCallingIdentity();
+ try {
+ return readAuthTokenFromDatabase(account, authTokenType);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void setAuthToken(Account account, String authTokenType, String authToken) {
+ checkAuthenticateAccountsPermission(account);
+ long identityToken = clearCallingIdentity();
+ try {
+ cacheAuthToken(account, authTokenType, authToken);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void setPassword(Account account, String password) {
+ checkAuthenticateAccountsPermission(account);
+ 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.name, account.type});
+ sendAccountsChangedBroadcast();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void sendAccountsChangedBroadcast() {
+ mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT);
+ }
+
+ public void clearPassword(Account account) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ setPassword(account, null);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void sendResult(IAccountManagerResponse response, Bundle bundle) {
+ if (response != null) {
+ try {
+ response.onResult(bundle);
+ } 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 setUserData(Account account, String key, String value) {
+ checkAuthenticateAccountsPermission(account);
+ long identityToken = clearCallingIdentity();
+ try {
+ writeUserdataIntoDatabase(account, key, value);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void writeUserdataIntoDatabase(Account account, String key, String value) {
+ 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();
+ }
+ }
+
+ private void onResult(IAccountManagerResponse response, Bundle result) {
+ try {
+ 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 getAuthToken(IAccountManagerResponse response, final Account account,
+ final String authTokenType, final boolean notifyOnAuthFailure,
+ final boolean expectActivityLaunch, final Bundle loginOptions) {
+ checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
+ final int callerUid = Binder.getCallingUid();
+ final boolean permissionGranted = permissionIsGranted(account, authTokenType, callerUid);
+
+ long identityToken = clearCallingIdentity();
+ try {
+ // if the caller has permission, do the peek. otherwise go the more expensive
+ // route of starting a Session
+ if (permissionGranted) {
+ String authToken = readAuthTokenFromDatabase(account, authTokenType);
+ if (authToken != null) {
+ Bundle result = new Bundle();
+ result.putString(Constants.AUTHTOKEN_KEY, authToken);
+ result.putString(Constants.ACCOUNT_NAME_KEY, account.name);
+ result.putString(Constants.ACCOUNT_TYPE_KEY, account.type);
+ onResult(response, result);
+ return;
+ }
+ }
+
+ new Session(response, account.type, 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 {
+ // If the caller doesn't have permission then create and return the
+ // "grant permission" intent instead of the "getAuthToken" intent.
+ if (!permissionGranted) {
+ mAuthenticator.getAuthTokenLabel(this, authTokenType);
+ } else {
+ mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
+ }
+ }
+
+ public void onResult(Bundle result) {
+ if (result != null) {
+ if (result.containsKey(Constants.AUTH_TOKEN_LABEL_KEY)) {
+ Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
+ new AccountAuthenticatorResponse(this),
+ authTokenType,
+ result.getString(Constants.AUTH_TOKEN_LABEL_KEY));
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(Constants.INTENT_KEY, intent);
+ onResult(bundle);
+ return;
+ }
+ 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(
+ account, result.getString(Constants.AUTH_FAILED_MESSAGE_KEY),
+ intent);
+ }
+ }
+ super.onResult(result);
+ }
+ }.bind();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void createNoCredentialsPermissionNotification(Account account, Intent intent) {
+ int uid = intent.getIntExtra(
+ GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
+ String authTokenType = intent.getStringExtra(
+ GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
+ String authTokenLabel = intent.getStringExtra(
+ GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
+
+ Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
+ 0 /* when */);
+ final CharSequence subtitleFormatString =
+ mContext.getText(R.string.permission_request_notification_subtitle);
+ n.setLatestEventInfo(mContext,
+ mContext.getText(R.string.permission_request_notification_title),
+ String.format(subtitleFormatString.toString(), account.name),
+ PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
+ ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+ .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
+ }
+
+ private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
+ AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
+ RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
+ mAuthenticatorCache.getServiceInfo(
+ AuthenticatorDescription.newKey(account.type));
+ if (serviceInfo == null) {
+ throw new IllegalArgumentException("unknown account type: " + account.type);
+ }
+
+ final Context authContext;
+ try {
+ authContext = mContext.createPackageContext(
+ serviceInfo.type.packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("unknown account type: " + account.type);
+ }
+
+ Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addCategory(
+ String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL, authTokenLabel);
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT_TYPE_LABEL,
+ authContext.getString(serviceInfo.type.labelId));
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_PACKAGES,
+ mContext.getPackageManager().getPackagesForUid(uid));
+ intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
+ return intent;
+ }
+
+ private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
+ int uid) {
+ Integer id;
+ synchronized(mCredentialsPermissionNotificationIds) {
+ final Pair<Pair<Account, String>, Integer> key =
+ new Pair<Pair<Account, String>, Integer>(
+ new Pair<Account, String>(account, authTokenType), uid);
+ id = mCredentialsPermissionNotificationIds.get(key);
+ if (id == null) {
+ id = mNotificationIds.incrementAndGet();
+ mCredentialsPermissionNotificationIds.put(key, id);
+ }
+ }
+ return id;
+ }
+
+ private Integer getSigninRequiredNotificationId(Account account) {
+ Integer id;
+ synchronized(mSigninRequiredNotificationIds) {
+ id = mSigninRequiredNotificationIds.get(account);
+ if (id == null) {
+ id = mNotificationIds.incrementAndGet();
+ mSigninRequiredNotificationIds.put(account, id);
+ }
+ }
+ return id;
+ }
+
+
+ public void addAcount(final IAccountManagerResponse response, final String accountType,
+ final String authTokenType, final String[] requiredFeatures,
+ final boolean expectActivityLaunch, final Bundle options) {
+ checkManageAccountsPermission();
+ 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) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, account.type, 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) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, account.type, 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) {
+ checkManageAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ new Session(response, account.type, 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) {
+ checkManageAccountsPermission();
+ 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 Account[] getAccounts(String type) {
+ checkReadAccountsPermission();
+ long identityToken = clearCallingIdentity();
+ try {
+ return getAccountsByType(type);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void getAccountsByFeatures(IAccountManagerResponse response,
+ String type, String[] features) {
+ checkReadAccountsPermission();
+ if (features != null && 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 {
+ if (features == null || features.length == 0) {
+ getAccountsByType(type);
+ return;
+ }
+ 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.name, account.type}, 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))) {
+ String accountName = result.getString(Constants.ACCOUNT_NAME_KEY);
+ String accountType = result.getString(Constants.ACCOUNT_TYPE_KEY);
+ if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
+ Account account = new Account(accountName, accountType);
+ cancelNotification(getSigninRequiredNotificationId(account));
+ }
+ }
+ 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 + "))");
+
+ createGrantsTable(db);
+
+ 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)");
+
+ createAccountsDeletionTrigger(db);
+ }
+
+ private void createAccountsDeletionTrigger(SQLiteDatabase db) {
+ 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 + " ;"
+ + " DELETE FROM " + TABLE_GRANTS
+ + " WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
+ + " END");
+ }
+
+ private void createGrantsTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
+ + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
+ + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL, "
+ + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
+ + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
+ + "," + GRANTS_GRANTEE_UID + "))");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
+
+ if (oldVersion == 1) {
+ // no longer need to do anything since the work is done
+ // when upgrading from version 2
+ oldVersion++;
+ }
+
+ if (oldVersion == 2) {
+ createGrantsTable(db);
+ db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
+ createAccountsDeletionTrigger(db);
+ 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(Account account, CharSequence message, Intent intent) {
+ long identityToken = clearCallingIdentity();
+ try {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "doNotification: " + message + " intent:" + intent);
+ }
+
+ if (intent.getComponent() != null &&
+ GrantCredentialsPermissionActivity.class.getName().equals(
+ intent.getComponent().getClassName())) {
+ createNoCredentialsPermissionNotification(account, intent);
+ } else {
+ 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(getSigninRequiredNotificationId(account), n);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void cancelNotification(int id) {
+ long identityToken = clearCallingIdentity();
+ try {
+ ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
+ .cancel(id);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ private void checkBinderPermission(String permission) {
+ final int uid = Binder.getCallingUid();
+ if (mContext.checkCallingOrSelfPermission(permission) !=
+ PackageManager.PERMISSION_GRANTED) {
+ String msg = "caller uid " + uid + " lacks " + permission;
+ Log.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "caller uid " + uid + " has " + permission);
+ }
+ }
+
+ private boolean inSystemImage(int callerUid) {
+ String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
+ for (String name : packages) {
+ try {
+ PackageInfo packageInfo =
+ mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
+ if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
+ final boolean fromAuthenticator = hasAuthenticatorUid(account.type, callerUid);
+ final boolean hasExplicitGrants = hasExplicitlyGrantedPermission(account, authTokenType);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
+ + callerUid + ", account " + account
+ + ": is authenticator? " + fromAuthenticator
+ + ", has explicit permission? " + hasExplicitGrants);
+ }
+ return fromAuthenticator || hasExplicitGrants || inSystemImage(callerUid);
+ }
+
+ private boolean hasAuthenticatorUid(String accountType, int callingUid) {
+ for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
+ mAuthenticatorCache.getAllServices()) {
+ if (serviceInfo.type.type.equals(accountType)) {
+ return (serviceInfo.uid == callingUid) ||
+ (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
+ == PackageManager.SIGNATURE_MATCH);
+ }
+ }
+ return false;
+ }
+
+ private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType) {
+ if (Binder.getCallingUid() == android.os.Process.SYSTEM_UID) {
+ return true;
+ }
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ String[] args = {String.valueOf(Binder.getCallingUid()), authTokenType,
+ account.name, account.type};
+ final boolean permissionGranted =
+ DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
+ if (!permissionGranted && isDebuggableMonkeyBuild) {
+ // TODO: Skip this check when running automated tests. Replace this
+ // with a more general solution.
+ Log.w(TAG, "no credentials permission for usage of " + account + ", "
+ + authTokenType + " by uid " + Binder.getCallingUid()
+ + " but ignoring since this is a monkey build");
+ return true;
+ }
+ return permissionGranted;
+ }
+
+ private void checkCallingUidAgainstAuthenticator(Account account) {
+ final int uid = Binder.getCallingUid();
+ if (!hasAuthenticatorUid(account.type, uid)) {
+ String msg = "caller uid " + uid + " is different than the authenticator's uid";
+ Log.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
+ }
+ }
+
+ private void checkAuthenticateAccountsPermission(Account account) {
+ checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
+ checkCallingUidAgainstAuthenticator(account);
+ }
+
+ private void checkReadAccountsPermission() {
+ checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
+ }
+
+ private void checkManageAccountsPermission() {
+ checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
+ }
+
+ /**
+ * Allow callers with the given uid permission to get credentials for account/authTokenType.
+ * <p>
+ * Although this is public it can only be accessed via the AccountManagerService object
+ * which is in the system. This means we don't need to protect it with permissions.
+ * @hide
+ */
+ public void grantAppPermission(Account account, String authTokenType, int uid) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId >= 0) {
+ ContentValues values = new ContentValues();
+ values.put(GRANTS_ACCOUNTS_ID, accountId);
+ values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
+ values.put(GRANTS_GRANTEE_UID, uid);
+ db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
+ db.setTransactionSuccessful();
+ }
+ } finally {
+ db.endTransaction();
+ }
+ cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
+ }
+
+ /**
+ * Don't allow callers with the given uid permission to get credentials for
+ * account/authTokenType.
+ * <p>
+ * Although this is public it can only be accessed via the AccountManagerService object
+ * which is in the system. This means we don't need to protect it with permissions.
+ * @hide
+ */
+ public void revokeAppPermission(Account account, String authTokenType, int uid) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountId(db, account);
+ if (accountId >= 0) {
+ db.delete(TABLE_GRANTS,
+ GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
+ + GRANTS_GRANTEE_UID + "=?",
+ new String[]{String.valueOf(accountId), authTokenType,
+ String.valueOf(uid)});
+ db.setTransactionSuccessful();
+ }
+ } finally {
+ db.endTransaction();
+ }
+ cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
+ }
+}
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/AccountMonitorListener.java b/core/java/android/accounts/AccountMonitorListener.java
deleted file mode 100644
index d0bd9a9..0000000
--- a/core/java/android/accounts/AccountMonitorListener.java
+++ /dev/null
@@ -1,29 +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;
-
-/**
- * An interface that contains the callback used by the AccountMonitor
- */
-public interface AccountMonitorListener {
- /**
- * This invoked when the AccountMonitor starts up and whenever the account
- * set changes.
- * @param currentAccounts the current accounts
- */
- void onAccountsUpdated(String[] currentAccounts);
-}
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..91e23ab
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorBindHelper.java
@@ -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.
+ */
+
+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<AuthenticatorDescription> authenticatorInfo =
+ mAuthenticatorCache.getServiceInfo(
+ AuthenticatorDescription.newKey(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/core/java/android/accounts/AuthenticatorDescription.aidl b/core/java/android/accounts/AuthenticatorDescription.aidl
new file mode 100644
index 0000000..136361c
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorDescription.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accounts;
+
+parcelable AuthenticatorDescription;
diff --git a/core/java/android/accounts/AuthenticatorDescription.java b/core/java/android/accounts/AuthenticatorDescription.java
new file mode 100644
index 0000000..672e648
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorDescription.java
@@ -0,0 +1,72 @@
+package android.accounts;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+public class AuthenticatorDescription implements Parcelable {
+ final public String type;
+ final public int labelId;
+ final public int iconId;
+ final public String packageName;
+
+ public AuthenticatorDescription(String type, String packageName, int labelId, int iconId) {
+ if (type == null) throw new IllegalArgumentException("type cannot be null");
+ if (packageName == null) throw new IllegalArgumentException("packageName cannot be null");
+ this.type = type;
+ this.packageName = packageName;
+ this.labelId = labelId;
+ this.iconId = iconId;
+ }
+
+ public static AuthenticatorDescription newKey(String type) {
+ if (type == null) throw new IllegalArgumentException("type cannot be null");
+ return new AuthenticatorDescription(type);
+ }
+
+ private AuthenticatorDescription(String type) {
+ this.type = type;
+ this.packageName = null;
+ this.labelId = 0;
+ this.iconId = 0;
+ }
+
+ private AuthenticatorDescription(Parcel source) {
+ this.type = source.readString();
+ this.packageName = source.readString();
+ this.labelId = source.readInt();
+ this.iconId = source.readInt();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public int hashCode() {
+ return type.hashCode();
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof AuthenticatorDescription)) return false;
+ final AuthenticatorDescription other = (AuthenticatorDescription) o;
+ return type.equals(other.type);
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(type);
+ dest.writeString(packageName);
+ dest.writeInt(labelId);
+ dest.writeInt(iconId);
+ }
+
+ public static final Creator<AuthenticatorDescription> CREATOR =
+ new Creator<AuthenticatorDescription>() {
+ public AuthenticatorDescription createFromParcel(Parcel source) {
+ return new AuthenticatorDescription(source);
+ }
+
+ public AuthenticatorDescription[] newArray(int size) {
+ return new AuthenticatorDescription[size];
+ }
+ };
+}
diff --git a/core/java/android/accounts/AuthenticatorException.java b/core/java/android/accounts/AuthenticatorException.java
new file mode 100644
index 0000000..4023494
--- /dev/null
+++ b/core/java/android/accounts/AuthenticatorException.java
@@ -0,0 +1,32 @@
+/*
+ * 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 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..bd6f205
--- /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]).name;
+ }
+
+ // 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.name);
+ bundle.putString(Constants.ACCOUNT_TYPE_KEY, account.type);
+ 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..8736f41
--- /dev/null
+++ b/core/java/android/accounts/Constants.java
@@ -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.
+ */
+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 int ERROR_CODE_BAD_REQUEST = 8;
+
+ public static final String ACCOUNTS_KEY = "accounts";
+ public static final String AUTHENTICATOR_TYPES_KEY = "authenticator_types";
+ public static final String USERDATA_KEY = "userdata";
+ public static final String AUTHTOKEN_KEY = "authtoken";
+ public static final String PASSWORD_KEY = "password";
+ 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";
+ public static final String AUTH_TOKEN_LABEL_KEY = "authTokenLabelKey";
+
+ public static final String AUTHENTICATOR_INTENT_ACTION =
+ "android.accounts.AccountAuthenticator";
+ public static final String AUTHENTICATOR_META_DATA_NAME =
+ "android.accounts.AccountAuthenticator";
+ public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
+
+ /**
+ * 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/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
new file mode 100644
index 0000000..e06afb4
--- /dev/null
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -0,0 +1,172 @@
+/*
+ * 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.os.Bundle;
+import android.widget.TextView;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.view.View;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import com.android.internal.R;
+
+/**
+ * @hide
+ */
+public class GrantCredentialsPermissionActivity extends Activity implements View.OnClickListener {
+ public static final String EXTRAS_ACCOUNT = "account";
+ public static final String EXTRAS_AUTH_TOKEN_LABEL = "authTokenLabel";
+ public static final String EXTRAS_AUTH_TOKEN_TYPE = "authTokenType";
+ public static final String EXTRAS_RESPONSE = "response";
+ public static final String EXTRAS_ACCOUNT_TYPE_LABEL = "accountTypeLabel";
+ public static final String EXTRAS_PACKAGES = "application";
+ public static final String EXTRAS_REQUESTING_UID = "uid";
+ private Account mAccount;
+ private String mAuthTokenType;
+ private int mUid;
+ private Bundle mResultBundle = null;
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setContentView(R.layout.grant_credentials_permission);
+ mAccount = getIntent().getExtras().getParcelable(EXTRAS_ACCOUNT);
+ mAuthTokenType = getIntent().getExtras().getString(EXTRAS_AUTH_TOKEN_TYPE);
+ mUid = getIntent().getExtras().getInt(EXTRAS_REQUESTING_UID);
+ final String accountTypeLabel =
+ getIntent().getExtras().getString(EXTRAS_ACCOUNT_TYPE_LABEL);
+ final String[] packages = getIntent().getExtras().getStringArray(EXTRAS_PACKAGES);
+
+ findViewById(R.id.allow).setOnClickListener(this);
+ findViewById(R.id.deny).setOnClickListener(this);
+
+ TextView messageView = (TextView) getWindow().findViewById(R.id.message);
+ String authTokenLabel = getIntent().getExtras().getString(EXTRAS_AUTH_TOKEN_LABEL);
+ if (authTokenLabel.length() == 0) {
+ CharSequence grantCredentialsPermissionFormat = getResources().getText(
+ R.string.grant_credentials_permission_message_desc);
+ messageView.setText(String.format(grantCredentialsPermissionFormat.toString(),
+ mAccount.name, accountTypeLabel));
+ } else {
+ CharSequence grantCredentialsPermissionFormat = getResources().getText(
+ R.string.grant_credentials_permission_message_with_authtokenlabel_desc);
+ messageView.setText(String.format(grantCredentialsPermissionFormat.toString(),
+ authTokenLabel, mAccount.name, accountTypeLabel));
+ }
+
+ String[] packageLabels = new String[packages.length];
+ final PackageManager pm = getPackageManager();
+ for (int i = 0; i < packages.length; i++) {
+ try {
+ packageLabels[i] =
+ pm.getApplicationLabel(pm.getApplicationInfo(packages[i], 0)).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ packageLabels[i] = packages[i];
+ }
+ }
+ ((ListView) findViewById(R.id.packages_list)).setAdapter(
+ new PackagesArrayAdapter(this, packageLabels));
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.allow:
+ AccountManagerService.getSingleton().grantAppPermission(mAccount, mAuthTokenType,
+ mUid);
+ Intent result = new Intent();
+ result.putExtra("retry", true);
+ setResult(RESULT_OK, result);
+ setAccountAuthenticatorResult(result.getExtras());
+ break;
+
+ case R.id.deny:
+ AccountManagerService.getSingleton().revokeAppPermission(mAccount, mAuthTokenType,
+ mUid);
+ setResult(RESULT_CANCELED);
+ break;
+ }
+ finish();
+ }
+
+ public final void setAccountAuthenticatorResult(Bundle result) {
+ mResultBundle = result;
+ }
+
+ /**
+ * Sends the result or a Constants.ERROR_CODE_CANCELED error if a result isn't present.
+ */
+ public void finish() {
+ Intent intent = getIntent();
+ AccountAuthenticatorResponse accountAuthenticatorResponse =
+ intent.getParcelableExtra(EXTRAS_RESPONSE);
+ if (accountAuthenticatorResponse != null) {
+ // send the result bundle back if set, otherwise send an error.
+ if (mResultBundle != null) {
+ accountAuthenticatorResponse.onResult(mResultBundle);
+ } else {
+ accountAuthenticatorResponse.onError(Constants.ERROR_CODE_CANCELED, "canceled");
+ }
+ }
+ super.finish();
+ }
+
+ private static class PackagesArrayAdapter extends ArrayAdapter<String> {
+ protected LayoutInflater mInflater;
+ private static final int mResource = R.layout.simple_list_item_1;
+
+ public PackagesArrayAdapter(Context context, String[] items) {
+ super(context, mResource, items);
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ static class ViewHolder {
+ TextView label;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ // A ViewHolder keeps references to children views to avoid unneccessary calls
+ // to findViewById() on each row.
+ ViewHolder holder;
+
+ // When convertView is not null, we can reuse it directly, there is no need
+ // to reinflate it. We only inflate a new View when the convertView supplied
+ // by ListView is null.
+ if (convertView == null) {
+ convertView = mInflater.inflate(mResource, null);
+
+ // Creates a ViewHolder and store references to the two children views
+ // we want to bind data to.
+ holder = new ViewHolder();
+ holder.label = (TextView) convertView.findViewById(R.id.text1);
+
+ convertView.setTag(holder);
+ } else {
+ // Get the ViewHolder back to get fast access to the TextView
+ // and the ImageView.
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ holder.label.setText(getItem(position));
+
+ return convertView;
+ }
+ }
+}
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
new file mode 100644
index 0000000..1592eea
--- /dev/null
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -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.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.
+ * note -- 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);
+
+ /**
+ * Gets the user-visible label of the given authtoken type.
+ */
+ void getAuthTokenLabel(in IAccountAuthenticatorResponse response, String authTokenType);
+
+ /**
+ * 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);
+
+ /**
+ * Gets whether or not the account is allowed to be removed.
+ */
+ void getAccountRemovalAllowed(in IAccountAuthenticatorResponse response, in Account account);
+}
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..411952b
--- /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.accounts.AuthenticatorDescription;
+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);
+ AuthenticatorDescription[] getAuthenticatorTypes();
+ Account[] getAccounts(String accountType);
+ void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features);
+ boolean addAccount(in Account account, String password, in Bundle extras);
+ void removeAccount(in IAccountManagerResponse response, 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);
+
+ /*
+ * @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/OnAccountsUpdatedListener.java b/core/java/android/accounts/OnAccountsUpdatedListener.java
new file mode 100644
index 0000000..bd249d0
--- /dev/null
+++ b/core/java/android/accounts/OnAccountsUpdatedListener.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ * An interface that contains the callback used by the AccountMonitor
+ */
+public interface OnAccountsUpdatedListener {
+ /**
+ * This invoked when the AccountMonitor starts up and whenever the account
+ * set changes.
+ * @param accounts the current accounts
+ */
+ 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/Activity.java b/core/java/android/app/Activity.java
index f2905a7..80d7285 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1930,11 +1930,32 @@ public class Activity extends ContextThemeWrapper
*
* @see #hasWindowFocus()
* @see #onResume
+ * @see View#onWindowFocusChanged(boolean)
*/
public void onWindowFocusChanged(boolean hasFocus) {
}
/**
+ * Called when the main window associated with the activity has been
+ * attached to the window manager.
+ * See {@link View#onAttachedToWindow() View.onAttachedToWindow()}
+ * for more information.
+ * @see View#onAttachedToWindow
+ */
+ public void onAttachedToWindow() {
+ }
+
+ /**
+ * Called when the main window associated with the activity has been
+ * detached from the window manager.
+ * See {@link View#onDetachedFromWindow() View.onDetachedFromWindow()}
+ * for more information.
+ * @see View#onDetachedFromWindow
+ */
+ public void onDetachedFromWindow() {
+ }
+
+ /**
* Returns true if this activity's <em>main</em> window currently has window focus.
* Note that this is not the same as the view itself having focus.
*
@@ -2394,6 +2415,7 @@ public class Activity extends ContextThemeWrapper
*
* @param id The id of the managed dialog.
*
+ * @see Dialog
* @see #onCreateDialog(int)
* @see #onPrepareDialog(int, Dialog)
* @see #dismissDialog(int)
@@ -2535,6 +2557,25 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * Similar to {@link #startSearch}, but actually fires off the search query after invoking
+ * the search dialog. Made available for testing purposes.
+ *
+ * @param query The query to trigger. If empty, the request will be ignored.
+ * @param appSearchData An application can insert application-specific
+ * context here, in order to improve quality or specificity of its own
+ * searches. This data will be returned with SEARCH intent(s). Null if
+ * no extra data is required.
+ * @param globalSearch If false, this will only launch the search that has been specifically
+ * defined by the application (which is usually defined as a local search). If no default
+ * search is defined in the current application or activity, no search will be launched.
+ * If true, this will always launch a platform-global (e.g. web-based) search instead.
+ */
+ public void triggerSearch(String query, Bundle appSearchData, boolean globalSearch) {
+ ensureSearchManager();
+ mSearchManager.triggerSearch(query, getComponentName(), appSearchData, globalSearch);
+ }
+
+ /**
* Request that key events come to this activity. Use this if your
* activity has no views with focus, but the activity still wants
* a chance to process key events.
@@ -3255,7 +3296,7 @@ public class Activity extends ContextThemeWrapper
throw new IllegalArgumentException("no ident");
}
}
- mSearchManager.setIdent(ident);
+ mSearchManager.setIdent(ident, getComponentName());
}
@Override
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 447512a..d14ec15 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -39,9 +39,6 @@ import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
-import java.io.FileNotFoundException;
-import java.io.FileDescriptor;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -551,8 +548,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
data.enforceInterface(IActivityManager.descriptor);
ComponentName className = ComponentName.readFromParcel(data);
IBinder token = data.readStrongBinder();
- boolean isForeground = data.readInt() != 0;
- setServiceForeground(className, token, isForeground);
+ int id = data.readInt();
+ Notification notification = null;
+ if (data.readInt() != 0) {
+ notification = Notification.CREATOR.createFromParcel(data);
+ }
+ boolean removeNotification = data.readInt() != 0;
+ setServiceForeground(className, token, id, notification, removeNotification);
reply.writeNoException();
return true;
}
@@ -606,7 +608,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case SERVICE_DONE_EXECUTING_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- serviceDoneExecuting(token);
+ int type = data.readInt();
+ int startId = data.readInt();
+ int res = data.readInt();
+ serviceDoneExecuting(token, type, startId, res);
reply.writeNoException();
return true;
}
@@ -1664,13 +1669,20 @@ class ActivityManagerProxy implements IActivityManager
return res;
}
public void setServiceForeground(ComponentName className, IBinder token,
- boolean isForeground) throws RemoteException {
+ int id, Notification notification, boolean removeNotification) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
ComponentName.writeToParcel(className, data);
data.writeStrongBinder(token);
- data.writeInt(isForeground ? 1 : 0);
+ data.writeInt(id);
+ if (notification != null) {
+ data.writeInt(1);
+ notification.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ data.writeInt(removeNotification ? 1 : 0);
mRemote.transact(SET_SERVICE_FOREGROUND_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -1737,11 +1749,15 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
- public void serviceDoneExecuting(IBinder token) throws RemoteException {
+ public void serviceDoneExecuting(IBinder token, int type, int startId,
+ int res) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
+ data.writeInt(type);
+ data.writeInt(startId);
+ data.writeInt(res);
mRemote.transact(SERVICE_DONE_EXECUTING_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e045105..1e915b4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1215,6 +1215,7 @@ public final class ActivityThread {
private static final class ServiceArgsData {
IBinder token;
int startId;
+ int flags;
Intent args;
public String toString() {
return "ServiceArgsData{token=" + token + " startId=" + startId
@@ -1417,10 +1418,11 @@ public final class ActivityThread {
}
public final void scheduleServiceArgs(IBinder token, int startId,
- Intent args) {
+ int flags ,Intent args) {
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.startId = startId;
+ s.flags = flags;
s.args = args;
queueOrSendMessage(H.SERVICE_ARGS, s);
@@ -2684,7 +2686,8 @@ public final class ActivityThread {
service.onCreate();
mServices.put(data.token, service);
try {
- ActivityManagerNative.getDefault().serviceDoneExecuting(data.token);
+ ActivityManagerNative.getDefault().serviceDoneExecuting(
+ data.token, 0, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
@@ -2710,7 +2713,7 @@ public final class ActivityThread {
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
- data.token);
+ data.token, 0, 0, 0);
}
} catch (RemoteException ex) {
}
@@ -2736,7 +2739,7 @@ public final class ActivityThread {
data.token, data.intent, doRebind);
} else {
ActivityManagerNative.getDefault().serviceDoneExecuting(
- data.token);
+ data.token, 0, 0, 0);
}
} catch (RemoteException ex) {
}
@@ -2773,9 +2776,10 @@ public final class ActivityThread {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
}
- s.onStart(data.args, data.startId);
+ int res = s.onStartCommand(data.args, data.flags, data.startId);
try {
- ActivityManagerNative.getDefault().serviceDoneExecuting(data.token);
+ ActivityManagerNative.getDefault().serviceDoneExecuting(
+ data.token, 1, data.startId, res);
} catch (RemoteException e) {
// nothing to do.
}
@@ -2801,7 +2805,8 @@ public final class ActivityThread {
((ApplicationContext) context).scheduleFinalCleanup(who, "Service");
}
try {
- ActivityManagerNative.getDefault().serviceDoneExecuting(token);
+ ActivityManagerNative.getDefault().serviceDoneExecuting(
+ token, 0, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 92929ea..487cfda 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -22,8 +22,8 @@ import com.google.android.collect.Maps;
import org.xmlpull.v1.XmlPullParserException;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.IBluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.IBluetooth;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -40,6 +40,7 @@ import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
+import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
@@ -59,8 +60,6 @@ import android.content.res.XmlResourceParser;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.SensorManager;
import android.location.ILocationManager;
@@ -78,7 +77,6 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.Looper;
-import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -88,14 +86,14 @@ import android.os.FileUtils.FileStatus;
import android.telephony.TelephonyManager;
import android.text.ClipboardManager;
import android.util.AndroidRuntimeException;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.view.ContextThemeWrapper;
-import android.view.Display;
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;
@@ -155,14 +153,12 @@ 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;
private static WifiManager sWifiManager;
private static LocationManager sLocationManager;
- private static boolean sIsBluetoothDeviceCached = false;
- private static BluetoothDevice sBluetoothDevice;
- private static IWallpaperService sWallpaperService;
private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =
new HashMap<File, SharedPreferencesImpl>();
@@ -177,8 +173,8 @@ class ApplicationContext extends Context {
private Resources.Theme mTheme = null;
private PackageManager mPackageManager;
private NotificationManager mNotificationManager = null;
- private AccessibilityManager mAccessibilityManager = null;
private ActivityManager mActivityManager = null;
+ private WallpaperManager mWallpaperManager = null;
private Context mReceiverRestrictedContext = null;
private SearchManager mSearchManager = null;
private SensorManager mSensorManager = null;
@@ -187,6 +183,8 @@ class ApplicationContext extends Context {
private StatusBarManager mStatusBarManager = null;
private TelephonyManager mTelephonyManager = null;
private ClipboardManager mClipboardManager = null;
+ private boolean mIsBluetoothAdapterCached = false;
+ private BluetoothAdapter mBluetoothAdapter;
private boolean mRestricted;
private final Object mSync = new Object();
@@ -198,9 +196,6 @@ class ApplicationContext extends Context {
private File mCacheDir;
- private Drawable mWallpaper;
- private IWallpaperServiceCallback mWallpaperCallback = null;
-
private static long sInstanceCount = 0;
private static final String[] EMPTY_FILE_LIST = {};
@@ -520,127 +515,37 @@ class ApplicationContext extends Context {
@Override
public Drawable getWallpaper() {
- Drawable dr = peekWallpaper();
- return dr != null ? dr : getResources().getDrawable(
- com.android.internal.R.drawable.default_wallpaper);
+ return getWallpaperManager().getDrawable();
}
@Override
- public synchronized Drawable peekWallpaper() {
- if (mWallpaper != null) {
- return mWallpaper;
- }
- mWallpaperCallback = new WallpaperCallback(this);
- mWallpaper = getCurrentWallpaperLocked();
- return mWallpaper;
- }
-
- private Drawable getCurrentWallpaperLocked() {
- try {
- ParcelFileDescriptor fd = getWallpaperService().getWallpaper(mWallpaperCallback);
- if (fd != null) {
- Bitmap bm = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor());
- if (bm != null) {
- // For now clear the density until we figure out how
- // to deal with it for wallpapers.
- bm.setDensity(0);
- return new BitmapDrawable(getResources(), bm);
- }
- }
- } catch (RemoteException e) {
- }
- return null;
+ public Drawable peekWallpaper() {
+ return getWallpaperManager().peekDrawable();
}
@Override
public int getWallpaperDesiredMinimumWidth() {
- try {
- return getWallpaperService().getWidthHint();
- } catch (RemoteException e) {
- // Shouldn't happen!
- return 0;
- }
+ return getWallpaperManager().getDesiredMinimumWidth();
}
@Override
public int getWallpaperDesiredMinimumHeight() {
- try {
- return getWallpaperService().getHeightHint();
- } catch (RemoteException e) {
- // Shouldn't happen!
- return 0;
- }
+ return getWallpaperManager().getDesiredMinimumHeight();
}
@Override
public void setWallpaper(Bitmap bitmap) throws IOException {
- try {
- ParcelFileDescriptor fd = getWallpaperService().setWallpaper();
- if (fd == null) {
- return;
- }
- FileOutputStream fos = null;
- try {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
- } catch (RemoteException e) {
- }
+ getWallpaperManager().setBitmap(bitmap);
}
@Override
public void setWallpaper(InputStream data) throws IOException {
- try {
- ParcelFileDescriptor fd = getWallpaperService().setWallpaper();
- if (fd == null) {
- return;
- }
- FileOutputStream fos = null;
- try {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- setWallpaper(data, fos);
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
- } catch (RemoteException e) {
- }
- }
-
- private void setWallpaper(InputStream data, FileOutputStream fos)
- throws IOException {
- byte[] buffer = new byte[32768];
- int amt;
- while ((amt=data.read(buffer)) > 0) {
- fos.write(buffer, 0, amt);
- }
+ getWallpaperManager().setStream(data);
}
@Override
public void clearWallpaper() throws IOException {
- try {
- /* Set the wallpaper to the default values */
- ParcelFileDescriptor fd = getWallpaperService().setWallpaper();
- if (fd != null) {
- FileOutputStream fos = null;
- try {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- setWallpaper(getResources().openRawResource(
- com.android.internal.R.drawable.default_wallpaper),
- fos);
- } finally {
- if (fos != null) {
- fos.close();
- }
- }
- }
- } catch (RemoteException e) {
- }
+ getWallpaperManager().clear();
}
@Override
@@ -901,8 +806,12 @@ class ApplicationContext extends Context {
}
} else if (ACTIVITY_SERVICE.equals(name)) {
return getActivityManager();
+ } else if (INPUT_METHOD_SERVICE.equals(name)) {
+ return InputMethodManager.getInstance(this);
} 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)) {
@@ -919,10 +828,10 @@ class ApplicationContext extends Context {
return getLocationManager();
} else if (SEARCH_SERVICE.equals(name)) {
return getSearchManager();
- } else if ( SENSOR_SERVICE.equals(name)) {
+ } else if (SENSOR_SERVICE.equals(name)) {
return getSensorManager();
} else if (BLUETOOTH_SERVICE.equals(name)) {
- return getBluetoothDevice();
+ return getBluetoothAdapter();
} else if (VIBRATOR_SERVICE.equals(name)) {
return getVibrator();
} else if (STATUS_BAR_SERVICE.equals(name)) {
@@ -938,13 +847,24 @@ class ApplicationContext extends Context {
return getTelephonyManager();
} else if (CLIPBOARD_SERVICE.equals(name)) {
return getClipboardManager();
- } else if (INPUT_METHOD_SERVICE.equals(name)) {
- return InputMethodManager.getInstance(this);
+ } else if (WALLPAPER_SERVICE.equals(name)) {
+ return getWallpaperManager();
}
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) {
@@ -1001,8 +921,7 @@ class ApplicationContext extends Context {
return sWifiManager;
}
- private NotificationManager getNotificationManager()
- {
+ private NotificationManager getNotificationManager() {
synchronized (mSync) {
if (mNotificationManager == null) {
mNotificationManager = new NotificationManager(
@@ -1013,6 +932,16 @@ class ApplicationContext extends Context {
return mNotificationManager;
}
+ private WallpaperManager getWallpaperManager() {
+ synchronized (mSync) {
+ if (mWallpaperManager == null) {
+ mWallpaperManager = new WallpaperManager(getOuterContext(),
+ mMainThread.getHandler());
+ }
+ }
+ return mWallpaperManager;
+ }
+
private TelephonyManager getTelephonyManager() {
synchronized (mSync) {
if (mTelephonyManager == null) {
@@ -1052,21 +981,16 @@ class ApplicationContext extends Context {
return mSearchManager;
}
- private BluetoothDevice getBluetoothDevice() {
- if (sIsBluetoothDeviceCached) {
- return sBluetoothDevice;
- }
- synchronized (sSync) {
+ private synchronized BluetoothAdapter getBluetoothAdapter() {
+ if (!mIsBluetoothAdapterCached) {
+ mIsBluetoothAdapterCached = true;
IBinder b = ServiceManager.getService(BLUETOOTH_SERVICE);
- if (b == null) {
- sBluetoothDevice = null;
- } else {
- IBluetoothDevice service = IBluetoothDevice.Stub.asInterface(b);
- sBluetoothDevice = new BluetoothDevice(service);
+ if (b != null) {
+ IBluetooth service = IBluetooth.Stub.asInterface(b);
+ mBluetoothAdapter = new BluetoothAdapter(service);
}
- sIsBluetoothDeviceCached = true;
}
- return sBluetoothDevice;
+ return mBluetoothAdapter;
}
private SensorManager getSensorManager() {
@@ -1087,16 +1011,6 @@ class ApplicationContext extends Context {
return mVibrator;
}
- private IWallpaperService getWallpaperService() {
- synchronized (sSync) {
- if (sWallpaperService == null) {
- IBinder b = ServiceManager.getService(WALLPAPER_SERVICE);
- sWallpaperService = IWallpaperService.Stub.asInterface(b);
- }
- }
- return sWallpaperService;
- }
-
private AudioManager getAudioManager()
{
if (mAudioManager == null) {
@@ -1710,6 +1624,15 @@ class ApplicationContext extends Context {
}
@Override
+ public FeatureInfo[] getSystemAvailableFeatures() {
+ try {
+ return mPM.getSystemAvailableFeatures();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
public int checkPermission(String permName, String pkgName) {
try {
return mPM.checkPermission(permName, pkgName);
@@ -1746,6 +1669,15 @@ class ApplicationContext extends Context {
}
@Override
+ public int checkSignatures(int uid1, int uid2) {
+ try {
+ return mPM.checkUidSignatures(uid1, uid2);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
public String[] getPackagesForUid(int uid) {
try {
return mPM.getPackagesForUid(uid);
@@ -2801,25 +2733,4 @@ class ApplicationContext extends Context {
return false;
}
}
-
- private static class WallpaperCallback extends IWallpaperServiceCallback.Stub {
- private WeakReference<ApplicationContext> mContext;
-
- public WallpaperCallback(ApplicationContext context) {
- mContext = new WeakReference<ApplicationContext>(context);
- }
-
- public synchronized void onWallpaperChanged() {
-
- /* The wallpaper has changed but we shouldn't eagerly load the
- * wallpaper as that would be inefficient. Reset the cached wallpaper
- * to null so if the user requests the wallpaper again then we'll
- * fetch it.
- */
- final ApplicationContext applicationContext = mContext.get();
- if (applicationContext != null) {
- applicationContext.mWallpaper = null;
- }
- }
- }
}
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 6b17236..aeae5f9 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -171,6 +171,11 @@ public class ApplicationErrorReport implements Parcelable {
public String throwMethodName;
/**
+ * Line number the exception was thrown from.
+ */
+ public int throwLineNumber;
+
+ /**
* Stack trace.
*/
public String stackTrace;
@@ -190,6 +195,7 @@ public class ApplicationErrorReport implements Parcelable {
throwFileName = in.readString();
throwClassName = in.readString();
throwMethodName = in.readString();
+ throwLineNumber = in.readInt();
stackTrace = in.readString();
}
@@ -202,6 +208,7 @@ public class ApplicationErrorReport implements Parcelable {
dest.writeString(throwFileName);
dest.writeString(throwClassName);
dest.writeString(throwMethodName);
+ dest.writeInt(throwLineNumber);
dest.writeString(stackTrace);
}
@@ -214,6 +221,7 @@ public class ApplicationErrorReport implements Parcelable {
pw.println(prefix + "throwFileName: " + throwFileName);
pw.println(prefix + "throwClassName: " + throwClassName);
pw.println(prefix + "throwMethodName: " + throwMethodName);
+ pw.println(prefix + "throwLineNumber: " + throwLineNumber);
pw.println(prefix + "stackTrace: " + stackTrace);
}
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index a3c6325..ad64465 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -206,8 +206,14 @@ public abstract class ApplicationThreadNative extends Binder
data.enforceInterface(IApplicationThread.descriptor);
IBinder token = data.readStrongBinder();
int startId = data.readInt();
- Intent args = Intent.CREATOR.createFromParcel(data);
- scheduleServiceArgs(token, startId, args);
+ int fl = data.readInt();
+ Intent args;
+ if (data.readInt() != 0) {
+ args = Intent.CREATOR.createFromParcel(data);
+ } else {
+ args = null;
+ }
+ scheduleServiceArgs(token, startId, fl, args);
return true;
}
@@ -524,7 +530,8 @@ class ApplicationThreadProxy implements IApplicationThread {
data.writeInterfaceToken(IApplicationThread.descriptor);
app.writeToParcel(data, 0);
data.writeInt(backupMode);
- mRemote.transact(SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION, data, null, 0);
+ mRemote.transact(SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
data.recycle();
}
@@ -532,7 +539,8 @@ class ApplicationThreadProxy implements IApplicationThread {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
app.writeToParcel(data, 0);
- mRemote.transact(SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION, data, null, 0);
+ mRemote.transact(SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
data.recycle();
}
@@ -571,12 +579,18 @@ class ApplicationThreadProxy implements IApplicationThread {
}
public final void scheduleServiceArgs(IBinder token, int startId,
- Intent args) throws RemoteException {
+ int flags, Intent args) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
data.writeInt(startId);
- args.writeToParcel(data, 0);
+ data.writeInt(flags);
+ if (args != null) {
+ data.writeInt(1);
+ args.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
mRemote.transact(SCHEDULE_SERVICE_ARGS_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 9432755..35d1004 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -576,6 +576,12 @@ public class Dialog implements DialogInterface, Window.Callback,
public void onWindowFocusChanged(boolean hasFocus) {
}
+ public void onAttachedToWindow() {
+ }
+
+ public void onDetachedFromWindow() {
+ }
+
/**
* Called to process key events. You can override this to intercept all
* key events before they are dispatched to the window. Be sure to call
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index f6ef549..c3e7224 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -139,7 +139,7 @@ public interface IActivityManager extends IInterface {
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) throws RemoteException;
public void setServiceForeground(ComponentName className, IBinder token,
- boolean isForeground) throws RemoteException;
+ int id, Notification notification, boolean keepNotification) throws RemoteException;
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags) throws RemoteException;
@@ -149,7 +149,8 @@ public interface IActivityManager extends IInterface {
public void unbindFinished(IBinder token, Intent service,
boolean doRebind) throws RemoteException;
/* oneway */
- public void serviceDoneExecuting(IBinder token) throws RemoteException;
+ public void serviceDoneExecuting(IBinder token, int type, int startId,
+ int res) throws RemoteException;
public IBinder peekService(Intent service, String resolvedType) throws RemoteException;
public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode)
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index c915770..6faaa34 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -71,7 +71,8 @@ public interface IApplicationThread extends IInterface {
Intent intent, boolean rebind) throws RemoteException;
void scheduleUnbindService(IBinder token,
Intent intent) throws RemoteException;
- void scheduleServiceArgs(IBinder token, int startId, Intent args) throws RemoteException;
+ void scheduleServiceArgs(IBinder token, int startId, int flags, Intent args)
+ throws RemoteException;
void scheduleStopService(IBinder token) throws RemoteException;
static final int DEBUG_OFF = 0;
static final int DEBUG_ON = 1;
diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl
index bd72544..ed5dd3d 100644
--- a/core/java/android/app/ISearchManager.aidl
+++ b/core/java/android/app/ISearchManager.aidl
@@ -36,6 +36,17 @@ interface ISearchManager {
boolean globalSearch,
ISearchManagerCallback searchManagerCallback,
int ident);
+
+ void triggerSearch(in String query,
+ in ComponentName launchActivity,
+ in Bundle appSearchData,
+ ISearchManagerCallback searchManagerCallback,
+ boolean globalSearch,
+ int ident);
+
void stopSearch();
+
+
boolean isVisible();
+
}
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
new file mode 100644
index 0000000..4d1e254
--- /dev/null
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -0,0 +1,63 @@
+/**
+ * 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.app;
+
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.app.IWallpaperManagerCallback;
+import android.content.ComponentName;
+
+/** @hide */
+interface IWallpaperManager {
+
+ /**
+ * Set the wallpaper.
+ */
+ ParcelFileDescriptor setWallpaper(String name);
+
+ /**
+ * Set the live wallpaper.
+ */
+ void setWallpaperComponent(in ComponentName name);
+
+ /**
+ * Get the wallpaper.
+ */
+ ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
+ out Bundle outParams);
+
+ /**
+ * Clear the wallpaper.
+ */
+ void clearWallpaper();
+
+ /**
+ * Sets the dimension hint for the wallpaper. These hints indicate the desired
+ * minimum width and height for the wallpaper.
+ */
+ void setDimensionHints(in int width, in int height);
+
+ /**
+ * Returns the desired minimum width for the wallpaper.
+ */
+ int getWidthHint();
+
+ /**
+ * Returns the desired minimum height for the wallpaper.
+ */
+ int getHeightHint();
+}
diff --git a/core/java/android/app/IWallpaperManagerCallback.aidl b/core/java/android/app/IWallpaperManagerCallback.aidl
new file mode 100644
index 0000000..991b2bc
--- /dev/null
+++ b/core/java/android/app/IWallpaperManagerCallback.aidl
@@ -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.
+ */
+
+package android.app;
+
+/**
+ * Callback interface used by IWallpaperManager to send asynchronous
+ * notifications back to its clients. Note that this is a
+ * one-way interface so the server does not block waiting for the client.
+ *
+ * @hide
+ */
+oneway interface IWallpaperManagerCallback {
+ /**
+ * Called when the wallpaper has changed
+ */
+ void onWallpaperChanged();
+}
diff --git a/core/java/android/app/IWallpaperService.aidl b/core/java/android/app/IWallpaperService.aidl
deleted file mode 100644
index a332b1a..0000000
--- a/core/java/android/app/IWallpaperService.aidl
+++ /dev/null
@@ -1,55 +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.app;
-
-import android.os.ParcelFileDescriptor;
-import android.app.IWallpaperServiceCallback;
-
-/** @hide */
-interface IWallpaperService {
-
- /**
- * Set the wallpaper.
- */
- ParcelFileDescriptor setWallpaper();
-
- /**
- * Get the wallpaper.
- */
- ParcelFileDescriptor getWallpaper(IWallpaperServiceCallback cb);
-
- /**
- * Clear the wallpaper.
- */
- void clearWallpaper();
-
- /**
- * Sets the dimension hint for the wallpaper. These hints indicate the desired
- * minimum width and height for the wallpaper.
- */
- void setDimensionHints(in int width, in int height);
-
- /**
- * Returns the desired minimum width for the wallpaper.
- */
- int getWidthHint();
-
- /**
- * Returns the desired minimum height for the wallpaper.
- */
- int getHeightHint();
-}
diff --git a/core/java/android/app/IWallpaperServiceCallback.aidl b/core/java/android/app/IWallpaperServiceCallback.aidl
deleted file mode 100644
index 6086f40..0000000
--- a/core/java/android/app/IWallpaperServiceCallback.aidl
+++ /dev/null
@@ -1,31 +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.app;
-
-/**
- * Callback interface used by IWallpaperService to send asynchronous
- * notifications back to its clients. Note that this is a
- * one-way interface so the server does not block waiting for the client.
- *
- * @hide
- */
-oneway interface IWallpaperServiceCallback {
- /**
- * Called when the wallpaper has changed
- */
- void onWallpaperChanged();
-}
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 2b12a2a..804c8eb 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -18,6 +18,7 @@ public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
+ private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
@@ -36,6 +37,19 @@ public abstract class IntentService extends Service {
mName = name;
}
+ /**
+ * Control redelivery of intents. If called with true,
+ * {@link #onStartCommand(Intent, int, int)} will return
+ * {@link Service#START_REDELIVER_INTENT} instead of
+ * {@link Service#START_NOT_STICKY}, so that if this service's process
+ * is called while it is executing the Intent in
+ * {@link #onHandleIntent(Intent)}, then when later restarted the same Intent
+ * will be re-delivered to it, to retry its execution.
+ */
+ public void setIntentRedelivery(boolean enabled) {
+ mRedelivery = enabled;
+ }
+
@Override
public void onCreate() {
super.onCreate();
@@ -48,7 +62,6 @@ public abstract class IntentService extends Service {
@Override
public void onStart(Intent intent, int startId) {
- super.onStart(intent, startId);
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
@@ -56,6 +69,12 @@ public abstract class IntentService extends Service {
}
@Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ onStart(intent, startId);
+ return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
+ }
+
+ @Override
public void onDestroy() {
mServiceLooper.quit();
}
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index d788c43..a83f4e8 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -18,6 +18,7 @@ package android.app;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
@@ -70,13 +71,15 @@ public abstract class LauncherActivity extends ListActivity {
ListItem(PackageManager pm, ResolveInfo resolveInfo, IconResizer resizer) {
this.resolveInfo = resolveInfo;
label = resolveInfo.loadLabel(pm);
- if (label == null && resolveInfo.activityInfo != null) {
+ ComponentInfo ci = resolveInfo.activityInfo;
+ if (ci == null) ci = resolveInfo.serviceInfo;
+ if (label == null && ci != null) {
label = resolveInfo.activityInfo.name;
}
icon = resizer.createIconThumbnail(resolveInfo.loadIcon(pm));
- packageName = resolveInfo.activityInfo.applicationInfo.packageName;
- className = resolveInfo.activityInfo.name;
+ packageName = ci.applicationInfo.packageName;
+ className = ci.name;
}
public ListItem() {
@@ -325,8 +328,7 @@ public abstract class LauncherActivity extends ListActivity {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setProgressBarIndeterminateVisibility(true);
- setContentView(com.android.internal.R.layout.activity_list);
-
+ onSetContentView();
mIntent = new Intent(getTargetIntent());
mIntent.setComponent(null);
@@ -338,10 +340,17 @@ public abstract class LauncherActivity extends ListActivity {
setProgressBarIndeterminateVisibility(false);
}
+ /**
+ * Override to call setContentView() with your own content view to
+ * customize the list layout.
+ */
+ protected void onSetContentView() {
+ setContentView(com.android.internal.R.layout.activity_list);
+ }
+
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
- Intent intent = ((ActivityAdapter)mAdapter).intentForPosition(position);
-
+ Intent intent = intentForPosition(position);
startActivity(intent);
}
@@ -374,12 +383,19 @@ public abstract class LauncherActivity extends ListActivity {
}
/**
+ * Perform query on package manager for list items. The default
+ * implementation queries for activities.
+ */
+ protected List<ResolveInfo> onQueryPackageManager(Intent queryIntent) {
+ return mPackageManager.queryIntentActivities(queryIntent, /* no flags */ 0);
+ }
+
+ /**
* Perform the query to determine which results to show and return a list of them.
*/
public List<ListItem> makeListItems() {
// Load all matching activities and sort correctly
- List<ResolveInfo> list = mPackageManager.queryIntentActivities(mIntent,
- /* no flags */ 0);
+ List<ResolveInfo> list = onQueryPackageManager(mIntent);
Collections.sort(list, new ResolveInfo.DisplayNameComparator(mPackageManager));
IconResizer resizer = new IconResizer();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9834c75..be5a7d3 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -257,6 +257,13 @@ public class Notification implements Parcelable
*/
public static final int FLAG_NO_CLEAR = 0x00000020;
+ /**
+ * Bit to be bitwise-ored into the {@link #flags} field that should be
+ * set if this notification represents a currently running service. This
+ * will normally be set for you by {@link Service#startForeground}.
+ */
+ public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
+
public int flags;
/**
@@ -458,7 +465,9 @@ public class Notification implements Parcelable
sb.append(this.vibrate[i]);
sb.append(',');
}
- sb.append(this.vibrate[N]);
+ if (N != -1) {
+ sb.append(this.vibrate[N]);
+ }
sb.append("]");
} else if ((this.defaults & DEFAULT_VIBRATE) != 0) {
sb.append("default");
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 39edab7..7b51fdf 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -61,7 +61,8 @@ public class NotificationManager
private static INotificationManager sService;
- static private INotificationManager getService()
+ /** @hide */
+ static public INotificationManager getService()
{
if (sService != null) {
return sService;
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 5844079..f776452 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -1120,7 +1120,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
/**
* Launch a search for the text in the query text field.
*/
- protected void launchQuerySearch() {
+ public void launchQuerySearch() {
launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);
}
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 2245562..7e6efec 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -29,6 +29,7 @@ import android.os.ServiceManager;
import android.server.search.SearchableInfo;
import android.util.Log;
import android.view.KeyEvent;
+import android.text.TextUtils;
import java.util.List;
@@ -1636,7 +1637,17 @@ public class SearchManager
private final Context mContext;
+ /**
+ * compact representation of the activity associated with this search manager so
+ * we can say who we are when starting search. the search managerservice, in turn,
+ * uses this to properly handle the back stack.
+ */
private int mIdent;
+
+ /**
+ * The package associated with this seach manager.
+ */
+ private String mAssociatedPackage;
// package private since they are used by the inner class SearchManagerCallback
/* package */ final Handler mHandler;
@@ -1656,11 +1667,15 @@ public class SearchManager
return mIdent != 0;
}
- /*package*/ void setIdent(int ident) {
+ /*package*/ void setIdent(int ident, ComponentName component) {
if (mIdent != 0) {
throw new IllegalStateException("mIdent already set");
}
+ if (component == null) {
+ throw new IllegalArgumentException("component must be non-null");
+ }
mIdent = ident;
+ mAssociatedPackage = component.getPackageName();
}
/**
@@ -1710,12 +1725,55 @@ public class SearchManager
boolean globalSearch) {
if (mIdent == 0) throw new IllegalArgumentException(
"Called from outside of an Activity context");
+ if (!globalSearch && !mAssociatedPackage.equals(launchActivity.getPackageName())) {
+ Log.w(TAG, "invoking app search on a different package " +
+ "not associated with this search manager");
+ }
try {
// activate the search manager and start it up!
mService.startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData,
globalSearch, mSearchManagerCallback, mIdent);
} catch (RemoteException ex) {
- Log.e(TAG, "startSearch() failed: " + ex);
+ Log.e(TAG, "startSearch() failed.", ex);
+ }
+ }
+
+ /**
+ * Similar to {@link #startSearch} but actually fires off the search query after invoking
+ * the search dialog. Made available for testing purposes.
+ *
+ * @param query The query to trigger. If empty, request will be ignored.
+ * @param launchActivity The ComponentName of the activity that has launched this search.
+ * @param appSearchData An application can insert application-specific
+ * context here, in order to improve quality or specificity of its own
+ * searches. This data will be returned with SEARCH intent(s). Null if
+ * no extra data is required.
+ * @param globalSearch If false, this will only launch the search that has been specifically
+ * defined by the application (which is usually defined as a local search). If no default
+ * search is defined in the current application or activity, no search will be launched.
+ * If true, this will always launch a platform-global (e.g. web-based) search instead.
+ *
+ * @see #startSearch
+ */
+ public void triggerSearch(String query,
+ ComponentName launchActivity,
+ Bundle appSearchData,
+ boolean globalSearch) {
+ if (mIdent == 0) throw new IllegalArgumentException(
+ "Called from outside of an Activity context");
+ if (!mAssociatedPackage.equals(launchActivity.getPackageName())) {
+ throw new IllegalArgumentException("invoking app search on a different package " +
+ "not associated with this search manager");
+ }
+ if (query == null || TextUtils.getTrimmedLength(query) == 0) {
+ Log.w(TAG, "triggerSearch called with empty query, ignoring.");
+ return;
+ }
+ try {
+ mService.triggerSearch(query, launchActivity, appSearchData, mSearchManagerCallback,
+ globalSearch, mIdent);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "triggerSearch() failed.", ex);
}
}
@@ -1836,6 +1894,7 @@ public class SearchManager
/**
* @deprecated This method is an obsolete internal implementation detail. Do not use.
*/
+ @Deprecated
public void onCancel(DialogInterface dialog) {
throw new UnsupportedOperationException();
}
@@ -1843,6 +1902,7 @@ public class SearchManager
/**
* @deprecated This method is an obsolete internal implementation detail. Do not use.
*/
+ @Deprecated
public void onDismiss(DialogInterface dialog) {
throw new UnsupportedOperationException();
}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index d2fb605..60c756b 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -22,8 +22,10 @@ import android.content.Intent;
import android.content.ContextWrapper;
import android.content.Context;
import android.content.res.Configuration;
+import android.os.Build;
import android.os.RemoteException;
import android.os.IBinder;
+import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -168,20 +170,119 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
}
/**
+ * @deprecated Implement {@link #onStartCommand(Intent, int, int)} instead.
+ */
+ @Deprecated
+ public void onStart(Intent intent, int startId) {
+ }
+
+ /**
+ * Bits returned by {@link #onStartCommand} describing how to continue
+ * the service if it is killed. May be {@link #START_STICKY},
+ * {@link #START_NOT_STICKY}, {@link #START_REDELIVER_INTENT},
+ * or {@link #START_STICKY_COMPATIBILITY}.
+ */
+ public static final int START_CONTINUATION_MASK = 0xf;
+
+ /**
+ * Constant to return from {@link #onStartCommand}: compatibility
+ * version of {@link #START_STICKY} that does not guarantee that
+ * {@link #onStartCommand} will be called again after being killed.
+ */
+ public static final int START_STICKY_COMPATIBILITY = 0;
+
+ /**
+ * Constant to return from {@link #onStartCommand}: if this service's
+ * process is killed while it is started (after returning from
+ * {@link #onStartCommand}), then leave it in the started state but
+ * don't retain this delivered intent. Later the system will try to
+ * re-create the service, but it will <em>not</em> call
+ * {@link #onStartCommand} unless there has been a new call to
+ * {@link Context#startService Context.startService(Intent)} with a new
+ * Intent to deliver.
+ *
+ * <p>This mode makes sense for things that will be explicitly started
+ * and stopped to run for arbitrary periods of time, such as a service
+ * performing background music playback.
+ */
+ public static final int START_STICKY = 1;
+
+ /**
+ * Constant to return from {@link #onStartCommand}: if this service's
+ * process is killed while it is started (after returning from
+ * {@link #onStartCommand}), and there are no new start intents to
+ * deliver to it, then take the service out of the started state and
+ * don't recreate until a future explicit call to
+ * {@link Context#startService Context.startService(Intent)}.
+ *
+ * <p>This mode makes sense for things that want to do some work as a
+ * result of being started, but can be stopped when under memory pressure
+ * and will explicit start themselves again later to do more work. An
+ * example of such a service would be one that polls for data from
+ * a server: it could schedule an alarm to poll every N minutes by having
+ * the alarm start its service. When its {@link #onStartCommand} is
+ * called from the alarm, it schedules a new alarm for N minutes later,
+ * and spawns a thread to do its networking. If its process is killed
+ * while doing that check, the service will not be restarted until the
+ * alarm goes off.
+ */
+ public static final int START_NOT_STICKY = 2;
+
+ /**
+ * Constant to return from {@link #onStartCommand}: if this service's
+ * process is killed while it is started (after returning from
+ * {@link #onStartCommand}), then it will be scheduled for a restart
+ * and the last delivered Intent re-delivered to it again via
+ * {@link #onStartCommand}. This Intent will remain scheduled for
+ * redelivery until the service calls {@link #stopSelf(int)} with the
+ * start ID provided to {@link #onStartCommand}.
+ */
+ public static final int START_REDELIVER_INTENT = 3;
+
+ /**
+ * This flag is set in {@link #onStartCommand} if the Intent is a
+ * re-delivery of a previously delivered intent, because the service
+ * had previously returned {@link #START_REDELIVER_INTENT} but had been
+ * killed before calling {@link #stopSelf(int)} for that Intent.
+ */
+ public static final int START_FLAG_REDELIVERY = 0x0001;
+
+ /**
+ * This flag is set in {@link #onStartCommand} if the Intent is a
+ * a retry because the original attempt never got to or returned from
+ * {@link #onStartCommand(Intent, int, int)}.
+ */
+ public static final int START_FLAG_RETRY = 0x0002;
+
+ /**
* Called by the system every time a client explicitly starts the service by calling
* {@link android.content.Context#startService}, providing the arguments it supplied and a
* unique integer token representing the start request. Do not call this method directly.
- *
+ *
+ * <p>For backwards compatibility, the default implementation calls
+ * {@link #onStart} and returns either {@link #START_STICKY}
+ * or {@link #START_STICKY_COMPATIBILITY}.
+ *
* @param intent The Intent supplied to {@link android.content.Context#startService},
- * as given.
+ * as given. This may be null if the service is being restarted after
+ * its process has gone away, and it had previously returned anything
+ * except {@link #START_STICKY_COMPATIBILITY}.
+ * @param flags Additional data about this start request. Currently either
+ * 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}.
* @param startId A unique integer representing this specific request to
- * start. Use with {@link #stopSelfResult(int)}.
+ * start. Use with {@link #stopSelfResult(int)}.
+ *
+ * @return The return value indicates what semantics the system should
+ * use for the service's current started state. It may be one of the
+ * constants associated with the {@link #START_CONTINUATION_MASK} bits.
*
* @see #stopSelfResult(int)
*/
- public void onStart(Intent intent, int startId) {
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ onStart(intent, startId);
+ return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
-
+
/**
* Called by the system to notify a Service that it is no longer used and is being removed. The
* service should clean up an resources it holds (threads, registered
@@ -304,24 +405,53 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
}
/**
- * Control whether this service is considered to be a foreground service.
+ * @deprecated This is a now a no-op, use
+ * {@link #startForeground(int, Notification)} instead.
+ */
+ @Deprecated
+ public final void setForeground(boolean isForeground) {
+ Log.w(TAG, "setForeground: ignoring old API call on " + getClass().getName());
+ }
+
+ /**
+ * Make this service run in the foreground, supplying the ongoing
+ * notification to be shown to the user while in this state.
* By default services are background, meaning that if the system needs to
* kill them to reclaim more memory (such as to display a large page in a
* web browser), they can be killed without too much harm. You can set this
- * flag if killing your service would be disruptive to the user: such as
+ * flag if killing your service would be disruptive to the user, such as
* if your service is performing background music playback, so the user
* would notice if their music stopped playing.
*
- * @param isForeground Determines whether this service is considered to
- * be foreground (true) or background (false).
+ * @param id The identifier for this notification as per
+ * {@link NotificationManager#notify(int, Notification)
+ * NotificationManager.notify(int, Notification)}.
+ * @param notification The Notification to be displayed.
+ *
+ * @see #stopForeground(boolean)
*/
- public final void setForeground(boolean isForeground) {
- if (mActivityManager == null) {
- return;
+ public final void startForeground(int id, Notification notification) {
+ try {
+ mActivityManager.setServiceForeground(
+ new ComponentName(this, mClassName), mToken, id,
+ notification, true);
+ } catch (RemoteException ex) {
}
+ }
+
+ /**
+ * Remove this service from foreground state, allowing it to be killed if
+ * more memory is needed.
+ * @param removeNotification If true, the notification previously provided
+ * to {@link #startForeground} will be removed. Otherwise it will remain
+ * until a later call removes it (or the service is destroyed).
+ * @see #startForeground(int, Notification)
+ */
+ public final void stopForeground(boolean removeNotification) {
try {
mActivityManager.setServiceForeground(
- new ComponentName(this, mClassName), mToken, isForeground);
+ new ComponentName(this, mClassName), mToken, 0, null,
+ removeNotification);
} catch (RemoteException ex) {
}
}
@@ -363,6 +493,8 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
+ mStartCompatibility = getApplicationInfo().targetSdkVersion
+ < Build.VERSION_CODES.ECLAIR;
}
final String getClassName() {
@@ -375,4 +507,5 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
private IBinder mToken = null;
private Application mApplication = null;
private IActivityManager mActivityManager = null;
+ private boolean mStartCompatibility = false;
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
new file mode 100644
index 0000000..7669306
--- /dev/null
+++ b/core/java/android/app/WallpaperManager.java
@@ -0,0 +1,439 @@
+/*
+ * 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.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.ViewRoot;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class WallpaperManager {
+ private static String TAG = "WallpaperManager";
+ private static boolean DEBUG = false;
+
+ /**
+ * Launch an activity for the user to pick the current global live
+ * wallpaper.
+ * @hide
+ */
+ public static final String ACTION_LIVE_WALLPAPER_CHOOSER
+ = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER";
+
+ private final Context mContext;
+
+ static class Globals extends IWallpaperManagerCallback.Stub {
+ private IWallpaperManager mService;
+ private Bitmap mWallpaper;
+
+ Globals() {
+ IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
+ mService = IWallpaperManager.Stub.asInterface(b);
+ }
+
+ public void onWallpaperChanged() {
+ /* The wallpaper has changed but we shouldn't eagerly load the
+ * wallpaper as that would be inefficient. Reset the cached wallpaper
+ * to null so if the user requests the wallpaper again then we'll
+ * fetch it.
+ */
+ synchronized (this) {
+ mWallpaper = null;
+ }
+ }
+
+ public Bitmap peekWallpaperBitmap(Context context) {
+ synchronized (this) {
+ if (mWallpaper != null) {
+ return mWallpaper;
+ }
+ mWallpaper = getCurrentWallpaperLocked(context);
+ return mWallpaper;
+ }
+ }
+
+ private Bitmap getCurrentWallpaperLocked(Context context) {
+ try {
+ Bundle params = new Bundle();
+ ParcelFileDescriptor fd = mService.getWallpaper(this, params);
+ if (fd != null) {
+ int width = params.getInt("width", 0);
+ int height = params.getInt("height", 0);
+
+ if (width <= 0 || height <= 0) {
+ // Degenerate case: no size requested, just load
+ // bitmap as-is.
+ Bitmap bm = BitmapFactory.decodeFileDescriptor(
+ fd.getFileDescriptor(), null, null);
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
+ if (bm != null) {
+ bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+ }
+ return bm;
+ }
+
+ // Load the bitmap with full color depth, to preserve
+ // quality for later processing.
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inDither = false;
+ options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ Bitmap bm = BitmapFactory.decodeFileDescriptor(
+ fd.getFileDescriptor(), null, options);
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
+ if (bm == null) {
+ return bm;
+ }
+ bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+
+ // This is the final bitmap we want to return.
+ Bitmap newbm = Bitmap.createBitmap(width, height,
+ bm.getConfig());
+ newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+ Canvas c = new Canvas(newbm);
+ c.setDensity(DisplayMetrics.DENSITY_DEVICE);
+ Rect targetRect = new Rect();
+ targetRect.left = targetRect.top = 0;
+ targetRect.right = bm.getWidth();
+ targetRect.bottom = bm.getHeight();
+
+ int deltaw = width - targetRect.right;
+ int deltah = height - targetRect.bottom;
+
+ if (deltaw > 0 || deltah > 0) {
+ // We need to scale up so it covers the entire
+ // area.
+ float scale = 1.0f;
+ if (deltaw > deltah) {
+ scale = width / (float)targetRect.right;
+ } else {
+ scale = height / (float)targetRect.bottom;
+ }
+ targetRect.right = (int)(targetRect.right*scale);
+ targetRect.bottom = (int)(targetRect.bottom*scale);
+ deltaw = width - targetRect.right;
+ deltah = height - targetRect.bottom;
+ }
+
+ targetRect.offset(deltaw/2, deltah/2);
+ Paint paint = new Paint();
+ paint.setFilterBitmap(true);
+ paint.setDither(true);
+ c.drawBitmap(bm, null, targetRect, paint);
+
+ bm.recycle();
+ return newbm;
+ }
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+ }
+
+ private static Object mSync = new Object();
+ private static Globals sGlobals;
+
+ static Globals getGlobals() {
+ synchronized (mSync) {
+ if (sGlobals == null) {
+ sGlobals = new Globals();
+ }
+ return sGlobals;
+ }
+ }
+
+ /*package*/ WallpaperManager(Context context, Handler handler) {
+ mContext = context;
+ }
+
+ /**
+ * Retrieve a WallpaperManager associated with the given Context.
+ */
+ public static WallpaperManager getInstance(Context context) {
+ return (WallpaperManager)context.getSystemService(
+ Context.WALLPAPER_SERVICE);
+ }
+
+ /** @hide */
+ public IWallpaperManager getIWallpaperManager() {
+ return getGlobals().mService;
+ }
+
+ /**
+ * Like {@link #peekDrawable}, but always returns a valid Drawable. If
+ * no wallpaper is set, the system default wallpaper is returned.
+ *
+ * @return Returns a Drawable object that will draw the wallpaper.
+ */
+ public Drawable getDrawable() {
+ Drawable dr = peekDrawable();
+ return dr != null ? dr : Resources.getSystem().getDrawable(
+ com.android.internal.R.drawable.default_wallpaper);
+ }
+
+ /**
+ * Retrieve the current system wallpaper. This is returned as an
+ * abstract Drawable that you can install in a View to display whatever
+ * wallpaper the user has currently set. If there is no wallpaper set,
+ * a null pointer is returned.
+ *
+ * @return Returns a Drawable object that will draw the wallpaper or a
+ * null pointer if these is none.
+ */
+ public Drawable peekDrawable() {
+ Bitmap bm = getGlobals().peekWallpaperBitmap(mContext);
+ return bm != null ? new BitmapDrawable(mContext.getResources(), bm) : null;
+ }
+
+ /**
+ * Change the current system wallpaper to the bitmap in the given resource.
+ * The resource is opened as a raw data stream and copied into the
+ * wallpaper; it must be a valid PNG or JPEG image. On success, the intent
+ * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
+ *
+ * @param resid The bitmap to save.
+ *
+ * @throws IOException If an error occurs reverting to the default
+ * wallpaper.
+ */
+ public void setResource(int resid) throws IOException {
+ try {
+ Resources resources = mContext.getResources();
+ /* Set the wallpaper to the default values */
+ ParcelFileDescriptor fd = getGlobals().mService.setWallpaper(
+ "res:" + resources.getResourceName(resid));
+ if (fd != null) {
+ FileOutputStream fos = null;
+ try {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ setWallpaper(resources.openRawResource(resid), fos);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Change the current system wallpaper to a bitmap. The given bitmap is
+ * converted to a PNG and stored as the wallpaper. On success, the intent
+ * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
+ *
+ * @param bitmap The bitmap to save.
+ *
+ * @throws IOException If an error occurs reverting to the default
+ * wallpaper.
+ */
+ public void setBitmap(Bitmap bitmap) throws IOException {
+ try {
+ ParcelFileDescriptor fd = getGlobals().mService.setWallpaper(null);
+ if (fd == null) {
+ return;
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Change the current system wallpaper to a specific byte stream. The
+ * give InputStream is copied into persistent storage and will now be
+ * used as the wallpaper. Currently it must be either a JPEG or PNG
+ * image. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
+ * is broadcast.
+ *
+ * @param data A stream containing the raw data to install as a wallpaper.
+ *
+ * @throws IOException If an error occurs reverting to the default
+ * wallpaper.
+ */
+ public void setStream(InputStream data) throws IOException {
+ try {
+ ParcelFileDescriptor fd = getGlobals().mService.setWallpaper(null);
+ if (fd == null) {
+ return;
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ setWallpaper(data, fos);
+ } finally {
+ if (fos != null) {
+ fos.close();
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ private void setWallpaper(InputStream data, FileOutputStream fos)
+ throws IOException {
+ byte[] buffer = new byte[32768];
+ int amt;
+ while ((amt=data.read(buffer)) > 0) {
+ fos.write(buffer, 0, amt);
+ }
+ }
+
+ /**
+ * Returns the desired minimum width for the wallpaper. Callers of
+ * {@link #setBitmap(android.graphics.Bitmap)} or
+ * {@link #setStream(java.io.InputStream)} should check this value
+ * beforehand to make sure the supplied wallpaper respects the desired
+ * minimum width.
+ *
+ * If the returned value is <= 0, the caller should use the width of
+ * the default display instead.
+ *
+ * @return The desired minimum width for the wallpaper. This value should
+ * be honored by applications that set the wallpaper but it is not
+ * mandatory.
+ */
+ public int getDesiredMinimumWidth() {
+ try {
+ return getGlobals().mService.getWidthHint();
+ } catch (RemoteException e) {
+ // Shouldn't happen!
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the desired minimum height for the wallpaper. Callers of
+ * {@link #setBitmap(android.graphics.Bitmap)} or
+ * {@link #setStream(java.io.InputStream)} should check this value
+ * beforehand to make sure the supplied wallpaper respects the desired
+ * minimum height.
+ *
+ * If the returned value is <= 0, the caller should use the height of
+ * the default display instead.
+ *
+ * @return The desired minimum height for the wallpaper. This value should
+ * be honored by applications that set the wallpaper but it is not
+ * mandatory.
+ */
+ public int getDesiredMinimumHeight() {
+ try {
+ return getGlobals().mService.getHeightHint();
+ } catch (RemoteException e) {
+ // Shouldn't happen!
+ return 0;
+ }
+ }
+
+ /**
+ * For use only by the current home application, to specify the size of
+ * wallpaper it would like to use. This allows such applications to have
+ * a virtual wallpaper that is larger than the physical screen, matching
+ * the size of their workspace.
+ * @param minimumWidth Desired minimum width
+ * @param minimumHeight Desired minimum height
+ */
+ public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
+ try {
+ getGlobals().mService.setDimensionHints(minimumWidth, minimumHeight);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Set the position of the current wallpaper within any larger space, when
+ * that wallpaper is visible behind the given window. The X and Y offsets
+ * are floating point numbers ranging from 0 to 1, representing where the
+ * wallpaper should be positioned within the screen space. These only
+ * make sense when the wallpaper is larger than the screen.
+ *
+ * @param windowToken The window who these offsets should be associated
+ * with, as returned by {@link android.view.View#getWindowVisibility()
+ * View.getWindowToken()}.
+ * @param xOffset The offset olong the X dimension, from 0 to 1.
+ * @param yOffset The offset along the Y dimension, from 0 to 1.
+ */
+ public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
+ try {
+ ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ windowToken, xOffset, yOffset);
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ }
+
+ /**
+ * Clear the offsets previously associated with this window through
+ * {@link #setWallpaperOffsets(IBinder, float, float)}. This reverts
+ * the window to its default state, where it does not cause the wallpaper
+ * to scroll from whatever its last offsets were.
+ *
+ * @param windowToken The window who these offsets should be associated
+ * with, as returned by {@link android.view.View#getWindowVisibility()
+ * View.getWindowToken()}.
+ */
+ public void clearWallpaperOffsets(IBinder windowToken) {
+ try {
+ ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ windowToken, -1, -1);
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ }
+
+ /**
+ * Remove any currently set wallpaper, reverting to the system's default
+ * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
+ * is broadcast.
+ *
+ * @throws IOException If an error occurs reverting to the default
+ * wallpaper.
+ */
+ public void clear() throws IOException {
+ setResource(com.android.internal.R.drawable.default_wallpaper);
+ }
+}
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 9799ac4..a4c141e 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -24,16 +24,17 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.SystemClock;
+import android.os.Parcelable;
+import android.os.Parcel;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.SparseArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
-import android.widget.FrameLayout.LayoutParams;
/**
* Provides the glue to show AppWidget views. This class offers automatic animation
@@ -108,6 +109,24 @@ public class AppWidgetHostView extends FrameLayout {
return mInfo;
}
+ @Override
+ protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
+ final ParcelableSparseArray jail = new ParcelableSparseArray();
+ super.dispatchSaveInstanceState(jail);
+ container.put(generateId(), jail);
+ }
+
+ private int generateId() {
+ final int id = getId();
+ return id == View.NO_ID ? mAppWidgetId : id;
+ }
+
+ @Override
+ protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
+ final ParcelableSparseArray jail = (ParcelableSparseArray) container.get(generateId());
+ super.dispatchRestoreInstanceState(jail);
+ }
+
/** {@inheritDoc} */
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
@@ -303,6 +322,7 @@ public class AppWidgetHostView extends FrameLayout {
if (mInfo != null) {
Context theirContext = mContext.createPackageContext(
mInfo.provider.getPackageName(), Context.CONTEXT_RESTRICTED);
+ mRemoteContext = theirContext;
LayoutInflater inflater = (LayoutInflater)
theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater = inflater.cloneInContext(theirContext);
@@ -317,8 +337,8 @@ public class AppWidgetHostView extends FrameLayout {
exception = e;
}
- if (exception != null && LOGD) {
- Log.w(TAG, "Error inflating AppWidget " + mInfo, exception);
+ if (exception != null) {
+ Log.w(TAG, "Error inflating AppWidget " + mInfo + ": " + exception.toString());
}
if (defaultView == null) {
@@ -339,4 +359,36 @@ public class AppWidgetHostView extends FrameLayout {
tv.setBackgroundColor(Color.argb(127, 0, 0, 0));
return tv;
}
+
+ private static class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable {
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ final int count = size();
+ dest.writeInt(count);
+ for (int i = 0; i < count; i++) {
+ dest.writeInt(keyAt(i));
+ dest.writeParcelable(valueAt(i), 0);
+ }
+ }
+
+ public static final Parcelable.Creator<ParcelableSparseArray> CREATOR =
+ new Parcelable.Creator<ParcelableSparseArray>() {
+ public ParcelableSparseArray createFromParcel(Parcel source) {
+ final ParcelableSparseArray array = new ParcelableSparseArray();
+ final ClassLoader loader = array.getClass().getClassLoader();
+ final int count = source.readInt();
+ for (int i = 0; i < count; i++) {
+ array.put(source.readInt(), source.readParcelable(loader));
+ }
+ return array;
+ }
+
+ public ParcelableSparseArray[] newArray(int size) {
+ return new ParcelableSparseArray[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java
index 69c206c..e67b0be 100644
--- a/core/java/android/backup/BackupDataInput.java
+++ b/core/java/android/backup/BackupDataInput.java
@@ -97,12 +97,7 @@ public class BackupDataInput {
public void skipEntityData() throws IOException {
if (mHeaderReady) {
- int result = skipEntityData_native(mBackupReader);
- if (result >= 0) {
- return;
- } else {
- throw new IOException("result=0x" + Integer.toHexString(result));
- }
+ skipEntityData_native(mBackupReader);
} else {
throw new IllegalStateException("mHeaderReady=false");
}
diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java
index c52fcd2..da1647a 100644
--- a/core/java/android/backup/BackupManager.java
+++ b/core/java/android/backup/BackupManager.java
@@ -43,7 +43,7 @@ public class BackupManager {
private static final String TAG = "BackupManager";
/** @hide TODO: REMOVE THIS */
- public static final boolean EVEN_THINK_ABOUT_DOING_RESTORE = false;
+ public static final boolean EVEN_THINK_ABOUT_DOING_RESTORE = true;
private Context mContext;
private static IBackupManager sService;
diff --git a/core/java/android/backup/IRestoreSession.aidl b/core/java/android/backup/IRestoreSession.aidl
index 2a1fbc1..fd40d98 100644
--- a/core/java/android/backup/IRestoreSession.aidl
+++ b/core/java/android/backup/IRestoreSession.aidl
@@ -40,6 +40,8 @@ interface IRestoreSession {
* Restore the given set onto the device, replacing the current data of any app
* contained in the restore set with the data previously backed up.
*
+ * @return Zero on success; nonzero on error. The observer will only receive
+ * progress callbacks if this method returned zero.
* @param token The token from {@link getAvailableRestoreSets()} corresponding to
* the restore set that should be used.
* @param observer If non-null, this binder points to an object that will receive
@@ -50,6 +52,9 @@ interface IRestoreSession {
/**
* End this restore session. After this method is called, the IRestoreSession binder
* is no longer valid.
+ *
+ * <p><b>Note:</b> The caller <i>must</i> invoke this method to end the restore session,
+ * even if {@link getAvailableRestoreSets} or {@link performRestore} failed.
*/
void endRestoreSession();
}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 2ea45d5..b531a50 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -25,7 +25,10 @@ import android.os.RemoteException;
import android.os.IBinder;
import android.util.Log;
-import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
/**
* Public API for controlling the Bluetooth A2DP Profile Service.
@@ -47,7 +50,7 @@ import java.util.List;
*
* @hide
*/
-public class BluetoothA2dp {
+public final class BluetoothA2dp {
private static final String TAG = "BluetoothA2dp";
private static final boolean DBG = false;
@@ -79,6 +82,7 @@ public class BluetoothA2dp {
/** Default priority for a2dp devices that should not allow incoming
* connections */
public static final int PRIORITY_OFF = 0;
+
private final IBluetoothA2dp mService;
private final Context mContext;
@@ -89,6 +93,7 @@ public class BluetoothA2dp {
*/
public BluetoothA2dp(Context c) {
mContext = c;
+
IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE);
if (b == null) {
throw new RuntimeException("Bluetooth A2DP service not available!");
@@ -99,14 +104,14 @@ public class BluetoothA2dp {
/** Initiate a connection to an A2DP sink.
* Listen for SINK_STATE_CHANGED_ACTION to find out when the
* connection is completed.
- * @param address Remote BT address.
+ * @param device Remote BT device.
* @return Result code, negative indicates an immediate error.
* @hide
*/
- public int connectSink(String address) {
- if (DBG) log("connectSink(" + address + ")");
+ public int connectSink(BluetoothDevice device) {
+ if (DBG) log("connectSink(" + device + ")");
try {
- return mService.connectSink(address);
+ return mService.connectSink(device);
} catch (RemoteException e) {
Log.w(TAG, "", e);
return BluetoothError.ERROR_IPC;
@@ -116,14 +121,14 @@ public class BluetoothA2dp {
/** Initiate disconnect from an A2DP sink.
* Listen for SINK_STATE_CHANGED_ACTION to find out when
* disconnect is completed.
- * @param address Remote BT address.
+ * @param device Remote BT device.
* @return Result code, negative indicates an immediate error.
* @hide
*/
- public int disconnectSink(String address) {
- if (DBG) log("disconnectSink(" + address + ")");
+ public int disconnectSink(BluetoothDevice device) {
+ if (DBG) log("disconnectSink(" + device + ")");
try {
- return mService.disconnectSink(address);
+ return mService.disconnectSink(device);
} catch (RemoteException e) {
Log.w(TAG, "", e);
return BluetoothError.ERROR_IPC;
@@ -131,24 +136,25 @@ public class BluetoothA2dp {
}
/** Check if a specified A2DP sink is connected.
- * @param address Remote BT address.
+ * @param device Remote BT device.
* @return True if connected (or playing), false otherwise and on error.
* @hide
*/
- public boolean isSinkConnected(String address) {
- if (DBG) log("isSinkConnected(" + address + ")");
- int state = getSinkState(address);
+ public boolean isSinkConnected(BluetoothDevice device) {
+ if (DBG) log("isSinkConnected(" + device + ")");
+ int state = getSinkState(device);
return state == STATE_CONNECTED || state == STATE_PLAYING;
}
/** Check if any A2DP sink is connected.
- * @return a List of connected A2DP sinks, or null on error.
+ * @return a unmodifiable set of connected A2DP sinks, or null on error.
* @hide
*/
- public List<String> listConnectedSinks() {
- if (DBG) log("listConnectedSinks()");
+ public Set<BluetoothDevice> getConnectedSinks() {
+ if (DBG) log("getConnectedSinks()");
try {
- return mService.listConnectedSinks();
+ return Collections.unmodifiableSet(
+ new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks())));
} catch (RemoteException e) {
Log.w(TAG, "", e);
return null;
@@ -156,14 +162,14 @@ public class BluetoothA2dp {
}
/** Get the state of an A2DP sink
- * @param address Remote BT address.
+ * @param device Remote BT device.
* @return State code, or negative on error
* @hide
*/
- public int getSinkState(String address) {
- if (DBG) log("getSinkState(" + address + ")");
+ public int getSinkState(BluetoothDevice device) {
+ if (DBG) log("getSinkState(" + device + ")");
try {
- return mService.getSinkState(address);
+ return mService.getSinkState(device);
} catch (RemoteException e) {
Log.w(TAG, "", e);
return BluetoothError.ERROR_IPC;
@@ -177,15 +183,15 @@ public class BluetoothA2dp {
* Sinks with priority greater than zero will accept incoming connections
* (if no sink is currently connected).
* Priority for unpaired sink must be PRIORITY_NONE.
- * @param address Paired sink
+ * @param device Paired sink
* @param priority Integer priority, for example PRIORITY_AUTO or
* PRIORITY_NONE
* @return Result code, negative indicates an error
*/
- public int setSinkPriority(String address, int priority) {
- if (DBG) log("setSinkPriority(" + address + ", " + priority + ")");
+ public int setSinkPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setSinkPriority(" + device + ", " + priority + ")");
try {
- return mService.setSinkPriority(address, priority);
+ return mService.setSinkPriority(device, priority);
} catch (RemoteException e) {
Log.w(TAG, "", e);
return BluetoothError.ERROR_IPC;
@@ -194,44 +200,19 @@ public class BluetoothA2dp {
/**
* Get priority of a2dp sink.
- * @param address Sink
+ * @param device Sink
* @return non-negative priority, or negative error code on error.
*/
- public int getSinkPriority(String address) {
- if (DBG) log("getSinkPriority(" + address + ")");
+ public int getSinkPriority(BluetoothDevice device) {
+ if (DBG) log("getSinkPriority(" + device + ")");
try {
- return mService.getSinkPriority(address);
+ return mService.getSinkPriority(device);
} catch (RemoteException e) {
Log.w(TAG, "", e);
return BluetoothError.ERROR_IPC;
}
}
- /**
- * Check class bits for possible A2DP Sink support.
- * This is a simple heuristic that tries to guess if a device with the
- * given class bits might be a A2DP Sink. It is not accurate for all
- * devices. It tries to err on the side of false positives.
- * @return True if this device might be a A2DP sink
- */
- public static boolean doesClassMatchSink(int btClass) {
- if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
- return true;
- }
- // By the A2DP spec, sinks must indicate the RENDER service.
- // However we found some that do not (Chordette). So lets also
- // match on some other class bits.
- switch (BluetoothClass.Device.getDevice(btClass)) {
- case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
- case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
- case BluetoothClass.Device.AUDIO_VIDEO_LOUDSPEAKER:
- case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
- return true;
- default:
- return false;
- }
- }
-
/** Helper for converting a state to a string.
* For debug use only - strings are not internationalized.
* @hide
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
new file mode 100644
index 0000000..6bd2a5a
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -0,0 +1,376 @@
+/*
+ * 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 android.os.RemoteException;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * Represents the local Bluetooth adapter.
+ *
+ * <p>Use {@link android.content.Context#getSystemService} with {@link
+ * android.content.Context#BLUETOOTH_SERVICE} to get the default local
+ * Bluetooth adapter. On most Android devices there is only one local
+ * Bluetotoh adapter.
+ *
+ * <p>Use the {@link BluetoothDevice} class for operations on remote Bluetooth
+ * devices.
+ *
+ * <p>TODO: unhide more of this class
+ */
+public final class BluetoothAdapter {
+ private static final String TAG = "BluetoothAdapter";
+
+ /** @hide */
+ public static final int BLUETOOTH_STATE_OFF = 0;
+ /** @hide */
+ public static final int BLUETOOTH_STATE_TURNING_ON = 1;
+ /** @hide */
+ public static final int BLUETOOTH_STATE_ON = 2;
+ /** @hide */
+ public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
+
+ /** Inquiry scan and page scan are both off.
+ * Device is neither discoverable nor connectable
+ * @hide */
+ public static final int SCAN_MODE_NONE = 0;
+ /** Page scan is on, inquiry scan is off.
+ * Device is connectable, but not discoverable
+ * @hide*/
+ public static final int SCAN_MODE_CONNECTABLE = 1;
+ /** Page scan and inquiry scan are on.
+ * Device is connectable and discoverable
+ * @hide*/
+ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
+
+ /** @hide */
+ public static final int RESULT_FAILURE = -1;
+ /** @hide */
+ public static final int RESULT_SUCCESS = 0;
+
+ /** The user will be prompted to enter a pin
+ * @hide */
+ public static final int PAIRING_VARIANT_PIN = 0;
+ /** The user will be prompted to enter a passkey
+ * @hide */
+ public static final int PAIRING_VARIANT_PASSKEY = 1;
+ /** The user will be prompted to confirm the passkey displayed on the screen
+ * @hide */
+ public static final int PAIRING_VARIANT_CONFIRMATION = 2;
+
+ private final IBluetooth mService;
+
+ /**
+ * Do not use this constructor. Use Context.getSystemService() instead.
+ * @hide
+ */
+ public BluetoothAdapter(IBluetooth service) {
+ if (service == null) {
+ throw new IllegalArgumentException("service is null");
+ }
+ mService = service;
+ }
+
+ /**
+ * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
+ * address.
+ * <p>Valid Bluetooth hardware addresses must be upper case, in a format
+ * such as "00:11:22:33:AA:BB".
+ * <p>A {@link BluetoothDevice} will always be returned for a valid
+ * hardware address, even if this adapter has never seen that device.
+ * @param address valid Bluetooth MAC address
+ * @throws IllegalArgumentException if address is invalid
+ */
+ public BluetoothDevice getRemoteDevice(String address) {
+ return new BluetoothDevice(address);
+ }
+
+ /**
+ * Is Bluetooth currently turned on.
+ *
+ * @return true if Bluetooth enabled, false otherwise.
+ * @hide
+ */
+ public boolean isEnabled() {
+ try {
+ return mService.isEnabled();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
+ * Get the current state of Bluetooth.
+ *
+ * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
+ * @hide
+ */
+ public int getBluetoothState() {
+ try {
+ return mService.getBluetoothState();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return BluetoothError.ERROR;
+ }
+
+ /**
+ * Enable the Bluetooth device.
+ * Turn on the underlying hardware.
+ * This is an asynchronous call,
+ * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
+ * and when the device is sucessfully enabled.
+ * @return false if we cannot enable the Bluetooth device. True does not
+ * imply the device was enabled, it only implies that so far there were no
+ * problems.
+ * @hide
+ */
+ public boolean enable() {
+ try {
+ return mService.enable();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
+ * Disable the Bluetooth device.
+ * This turns off the underlying hardware.
+ *
+ * @return true if successful, false otherwise.
+ * @hide
+ */
+ public boolean disable() {
+ try {
+ return mService.disable(true);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /** @hide */
+ public String getAddress() {
+ try {
+ return mService.getAddress();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return null;
+ }
+
+ /**
+ * Get the friendly Bluetooth name of this device.
+ *
+ * This name is visible to remote Bluetooth devices. Currently it is only
+ * possible to retrieve the Bluetooth name when Bluetooth is enabled.
+ *
+ * @return the Bluetooth name, or null if there was a problem.
+ * @hide
+ */
+ public String getName() {
+ try {
+ return mService.getName();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return null;
+ }
+
+ /**
+ * Set the friendly Bluetooth name of this device.
+ *
+ * This name is visible to remote Bluetooth devices. The Bluetooth Service
+ * is responsible for persisting this name.
+ *
+ * @param name the name to set
+ * @return true, if the name was successfully set. False otherwise.
+ * @hide
+ */
+ public boolean setName(String name) {
+ try {
+ return mService.setName(name);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
+ * Get the current scan mode.
+ * Used to determine if the local device is connectable and/or discoverable
+ * @return Scan mode, one of SCAN_MODE_* or an error code
+ * @hide
+ */
+ public int getScanMode() {
+ try {
+ return mService.getScanMode();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return BluetoothError.ERROR_IPC;
+ }
+
+ /**
+ * Set the current scan mode.
+ * Used to make the local device connectable and/or discoverable
+ * @param scanMode One of SCAN_MODE_*
+ * @hide
+ */
+ public void setScanMode(int scanMode) {
+ try {
+ mService.setScanMode(scanMode);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ }
+
+ /** @hide */
+ public int getDiscoverableTimeout() {
+ try {
+ return mService.getDiscoverableTimeout();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return -1;
+ }
+
+ /** @hide */
+ public void setDiscoverableTimeout(int timeout) {
+ try {
+ mService.setDiscoverableTimeout(timeout);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ }
+
+ /** @hide */
+ public boolean startDiscovery() {
+ try {
+ return mService.startDiscovery();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /** @hide */
+ public void cancelDiscovery() {
+ try {
+ mService.cancelDiscovery();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ }
+
+ /** @hide */
+ public boolean isDiscovering() {
+ try {
+ return mService.isDiscovering();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
+ * List remote devices that are bonded (paired) to the local adapter.
+ *
+ * Bonding (pairing) is the process by which the user enters a pin code for
+ * the device, which generates a shared link key, allowing for
+ * authentication and encryption of future connections. In Android we
+ * require bonding before RFCOMM or SCO connections can be made to a remote
+ * device.
+ *
+ * This function lists which remote devices we have a link key for. It does
+ * not cause any RF transmission, and does not check if the remote device
+ * still has it's link key with us. If the other side no longer has its
+ * link key then the RFCOMM or SCO connection attempt will result in an
+ * error.
+ *
+ * This function does not check if the remote device is in range.
+ *
+ * Remote devices that have an in-progress bonding attempt are not
+ * returned.
+ *
+ * @return unmodifiable set of bonded devices, or null on error
+ * @hide
+ */
+ public Set<BluetoothDevice> getBondedDevices() {
+ try {
+ return toDeviceSet(mService.listBonds());
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return null;
+ }
+
+ /**
+ * Create a listening, secure RFCOMM Bluetooth socket.
+ * <p>A remote device connecting to this socket will be authenticated and
+ * communication on this socket will be encrypted.
+ * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
+ * connections to listening {@link BluetoothServerSocket}.
+ * <p>Valid RFCOMM channels are in range 1 to 30.
+ * @param channel RFCOMM channel to listen on
+ * @return a listening RFCOMM BluetoothServerSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions, or channel in use.
+ */
+ public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
+ BluetoothServerSocket socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_RFCOMM, true, true, channel);
+ 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.
+ * @hide
+ */
+ public 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.
+ * @hide
+ */
+ 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;
+ }
+
+ private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
+ Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
+ for (int i = 0; i < addresses.length; i++) {
+ devices.add(getRemoteDevice(addresses[i]));
+ }
+ return Collections.unmodifiableSet(devices);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothAudioGateway.java b/core/java/android/bluetooth/BluetoothAudioGateway.java
index f3afd2a..abd7723 100644
--- a/core/java/android/bluetooth/BluetoothAudioGateway.java
+++ b/core/java/android/bluetooth/BluetoothAudioGateway.java
@@ -9,24 +9,22 @@ import android.util.Log;
/**
* Listen's for incoming RFCOMM connection for the headset / handsfree service.
*
- * This class is planned for deletion, in favor of a generic Rfcomm class.
+ * TODO: Use the new generic BluetoothSocket class instead of this legacy code
*
* @hide
*/
-public class BluetoothAudioGateway {
+public final class BluetoothAudioGateway {
private static final String TAG = "BT Audio Gateway";
private static final boolean DBG = false;
private int mNativeData;
static { classInitNative(); }
- private BluetoothDevice mBluetooth;
-
/* in */
private int mHandsfreeAgRfcommChannel = -1;
private int mHeadsetAgRfcommChannel = -1;
- /* out */
+ /* out - written by native code */
private String mConnectingHeadsetAddress;
private int mConnectingHeadsetRfcommChannel; /* -1 when not connected */
private int mConnectingHeadsetSocketFd;
@@ -35,17 +33,18 @@ public class BluetoothAudioGateway {
private int mConnectingHandsfreeSocketFd;
private int mTimeoutRemainingMs; /* in/out */
+ private final BluetoothAdapter mAdapter;
+
public static final int DEFAULT_HF_AG_CHANNEL = 10;
public static final int DEFAULT_HS_AG_CHANNEL = 11;
- public BluetoothAudioGateway(BluetoothDevice bluetooth) {
- this(bluetooth, DEFAULT_HF_AG_CHANNEL, DEFAULT_HS_AG_CHANNEL);
+ public BluetoothAudioGateway(BluetoothAdapter adapter) {
+ this(adapter, DEFAULT_HF_AG_CHANNEL, DEFAULT_HS_AG_CHANNEL);
}
- public BluetoothAudioGateway(BluetoothDevice bluetooth,
- int handsfreeAgRfcommChannel,
- int headsetAgRfcommChannel) {
- mBluetooth = bluetooth;
+ public BluetoothAudioGateway(BluetoothAdapter adapter, int handsfreeAgRfcommChannel,
+ int headsetAgRfcommChannel) {
+ mAdapter = adapter;
mHandsfreeAgRfcommChannel = handsfreeAgRfcommChannel;
mHeadsetAgRfcommChannel = headsetAgRfcommChannel;
initializeNativeDataNative();
@@ -58,18 +57,17 @@ public class BluetoothAudioGateway {
private Handler mCallback;
public class IncomingConnectionInfo {
- IncomingConnectionInfo(BluetoothDevice bluetooth, String address, int socketFd,
- int rfcommChan) {
- mBluetooth = bluetooth;
- mAddress = address;
+ public BluetoothAdapter mAdapter;
+ public BluetoothDevice mRemoteDevice;
+ public int mSocketFd;
+ public int mRfcommChan;
+ IncomingConnectionInfo(BluetoothAdapter adapter, BluetoothDevice remoteDevice,
+ int socketFd, int rfcommChan) {
+ mAdapter = adapter;
+ mRemoteDevice = remoteDevice;
mSocketFd = socketFd;
mRfcommChan = rfcommChan;
}
-
- public BluetoothDevice mBluetooth;
- public String mAddress;
- public int mSocketFd;
- public int mRfcommChan;
}
public static final int MSG_INCOMING_HEADSET_CONNECTION = 100;
@@ -111,12 +109,11 @@ public class BluetoothAudioGateway {
mConnectingHeadsetRfcommChannel);
Message msg = Message.obtain(mCallback);
msg.what = MSG_INCOMING_HEADSET_CONNECTION;
- msg.obj =
- new IncomingConnectionInfo(
- mBluetooth,
- mConnectingHeadsetAddress,
- mConnectingHeadsetSocketFd,
- mConnectingHeadsetRfcommChannel);
+ msg.obj = new IncomingConnectionInfo(
+ mAdapter,
+ mAdapter.getRemoteDevice(mConnectingHeadsetAddress),
+ mConnectingHeadsetSocketFd,
+ mConnectingHeadsetRfcommChannel);
msg.sendToTarget();
}
if (mConnectingHandsfreeRfcommChannel >= 0) {
@@ -126,12 +123,11 @@ public class BluetoothAudioGateway {
Message msg = Message.obtain();
msg.setTarget(mCallback);
msg.what = MSG_INCOMING_HANDSFREE_CONNECTION;
- msg.obj =
- new IncomingConnectionInfo(
- mBluetooth,
- mConnectingHandsfreeAddress,
- mConnectingHandsfreeSocketFd,
- mConnectingHandsfreeRfcommChannel);
+ msg.obj = new IncomingConnectionInfo(
+ mAdapter,
+ mAdapter.getRemoteDevice(mConnectingHandsfreeAddress),
+ mConnectingHandsfreeSocketFd,
+ mConnectingHandsfreeRfcommChannel);
msg.sendToTarget();
}
}
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 88ce18b..0061f10 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -46,6 +46,10 @@ public class BluetoothClass {
/** Indicates the Bluetooth API could not retrieve the class */
public static final int ERROR = 0xFF000000;
+ public static final int PROFILE_HEADSET = 0;
+ public static final int PROFILE_A2DP = 1;
+ public static final int PROFILE_OPP = 2;
+
/** Every Bluetooth device has zero or more service classes */
public static class Service {
public static final int BITMASK = 0xFFE000;
@@ -187,5 +191,74 @@ public class BluetoothClass {
return (btClass & Device.BITMASK);
}
}
+
+ /**
+ * Check class bits for possible bluetooth profile support.
+ * This is a simple heuristic that tries to guess if a device with the
+ * given class bits might support specified profile. It is not accurate for all
+ * devices. It tries to err on the side of false positives.
+ * @param btClass The class
+ * @param profile The profile to be checked
+ * @return True if this device might support specified profile.
+ */
+ public static boolean doesClassMatch(int btClass, int profile) {
+ if (profile == PROFILE_A2DP) {
+ if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
+ return true;
+ }
+ // By the A2DP spec, sinks must indicate the RENDER service.
+ // However we found some that do not (Chordette). So lets also
+ // match on some other class bits.
+ switch (BluetoothClass.Device.getDevice(btClass)) {
+ case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
+ case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
+ case BluetoothClass.Device.AUDIO_VIDEO_LOUDSPEAKER:
+ case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+ return true;
+ default:
+ return false;
+ }
+ } else if (profile == PROFILE_HEADSET) {
+ // The render service class is required by the spec for HFP, so is a
+ // pretty good signal
+ if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
+ return true;
+ }
+ // Just in case they forgot the render service class
+ switch (BluetoothClass.Device.getDevice(btClass)) {
+ case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
+ case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
+ case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+ return true;
+ default:
+ return false;
+ }
+ } else if (profile == PROFILE_OPP) {
+ if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.OBJECT_TRANSFER)) {
+ return true;
+ }
+
+ switch (BluetoothClass.Device.getDevice(btClass)) {
+ case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
+ case BluetoothClass.Device.COMPUTER_DESKTOP:
+ case BluetoothClass.Device.COMPUTER_SERVER:
+ case BluetoothClass.Device.COMPUTER_LAPTOP:
+ case BluetoothClass.Device.COMPUTER_HANDHELD_PC_PDA:
+ case BluetoothClass.Device.COMPUTER_PALM_SIZE_PC_PDA:
+ case BluetoothClass.Device.COMPUTER_WEARABLE:
+ case BluetoothClass.Device.PHONE_UNCATEGORIZED:
+ case BluetoothClass.Device.PHONE_CELLULAR:
+ case BluetoothClass.Device.PHONE_CORDLESS:
+ case BluetoothClass.Device.PHONE_SMART:
+ case BluetoothClass.Device.PHONE_MODEM_OR_GATEWAY:
+ case BluetoothClass.Device.PHONE_ISDN:
+ return true;
+ default:
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.aidl b/core/java/android/bluetooth/BluetoothDevice.aidl
new file mode 100644
index 0000000..daae74d
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothDevice.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothDevice;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 951b4b0..0a71961 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.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.
@@ -16,337 +16,192 @@
package android.bluetooth;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
+import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
+ * Represents a remote Bluetooth device.
*
- * Manages the local Bluetooth device. Scan for devices, create bondings,
- * power up and down the adapter.
+ * <p>Use {@link BluetoothAdapter#getRemoteDevice} to create a {@link
+ * BluetoothDevice}.
*
- * @hide
+ * <p>This class is really just a thin wrapper for a Bluetooth hardware
+ * address. Objects of this class are immutable. Operations on this class
+ * are performed on the remote Bluetooth hardware address, using the
+ * {@link BluetoothAdapter} that was used to create this {@link
+ * BluetoothDevice}.
+ *
+ * TODO: unhide more of this class
*/
-public class BluetoothDevice {
-
- public static final int BLUETOOTH_STATE_OFF = 0;
- public static final int BLUETOOTH_STATE_TURNING_ON = 1;
- public static final int BLUETOOTH_STATE_ON = 2;
- public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
-
- /** Inquiry scan and page scan are both off.
- * Device is neither discoverable nor connectable */
- public static final int SCAN_MODE_NONE = 0;
- /** Page scan is on, inquiry scan is off.
- * Device is connectable, but not discoverable */
- public static final int SCAN_MODE_CONNECTABLE = 1;
- /** Page scan and inquiry scan are on.
- * Device is connectable and discoverable */
- public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
-
- public static final int RESULT_FAILURE = -1;
- public static final int RESULT_SUCCESS = 0;
+public final class BluetoothDevice implements Parcelable {
+ private static final String TAG = "BluetoothDevice";
/** We do not have a link key for the remote device, and are therefore not
- * bonded */
+ * bonded
+ * @hide*/
public static final int BOND_NOT_BONDED = 0;
- /** We have a link key for the remote device, and are probably bonded. */
+ /** We have a link key for the remote device, and are probably bonded.
+ * @hide */
public static final int BOND_BONDED = 1;
- /** We are currently attempting bonding */
+ /** We are currently attempting bonding
+ * @hide */
public static final int BOND_BONDING = 2;
+ /** Ask device picker to show all kinds of BT devices.
+ * @hide */
+ public static final int DEVICE_PICKER_FILTER_TYPE_ALL = 0;
+ /** Ask device picker to show BT devices that support AUDIO profiles.
+ * @hide */
+ public static final int DEVICE_PICKER_FILTER_TYPE_AUDIO = 1;
+ /** Ask device picker to show BT devices that support Object Transfer.
+ * @hide */
+ public static final int DEVICE_PICKER_FILTER_TYPE_TRANSFER = 2;
+
//TODO: Unify these result codes in BluetoothResult or BluetoothError
/** A bond attempt failed because pins did not match, or remote device did
- * not respond to pin request in time */
+ * not respond to pin request in time
+ * @hide */
public static final int UNBOND_REASON_AUTH_FAILED = 1;
/** A bond attempt failed because the other side explicilty rejected
- * bonding */
+ * bonding
+ * @hide */
public static final int UNBOND_REASON_AUTH_REJECTED = 2;
- /** A bond attempt failed because we canceled the bonding process */
+ /** A bond attempt failed because we canceled the bonding process
+ * @hide */
public static final int UNBOND_REASON_AUTH_CANCELED = 3;
- /** A bond attempt failed because we could not contact the remote device */
+ /** A bond attempt failed because we could not contact the remote device
+ * @hide */
public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
- /** A bond attempt failed because a discovery is in progress */
+ /** A bond attempt failed because a discovery is in progress
+ * @hide */
public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
- /** An existing bond was explicitly revoked */
+ /** An existing bond was explicitly revoked
+ * @hide */
public static final int UNBOND_REASON_REMOVED = 6;
- private static final String TAG = "BluetoothDevice";
-
- private final IBluetoothDevice mService;
- /**
- * @hide - hide this because it takes a parameter of type
- * IBluetoothDevice, which is a System private class.
- * Also note that Context.getSystemService is a factory that
- * returns a BlueToothDevice. That is the right way to get
- * a BluetoothDevice.
- */
- public BluetoothDevice(IBluetoothDevice service) {
- mService = service;
- }
+ //TODO: Remove duplicates between here and BluetoothAdapter
+ /** The user will be prompted to enter a pin
+ * @hide */
+ public static final int PAIRING_VARIANT_PIN = 0;
+ /** The user will be prompted to enter a passkey
+ * @hide */
+ public static final int PAIRING_VARIANT_PASSKEY = 1;
+ /** The user will be prompted to confirm the passkey displayed on the screen
+ * @hide */
+ public static final int PAIRING_VARIANT_CONFIRMATION = 2;
- /**
- * Is Bluetooth currently turned on.
- *
- * @return true if Bluetooth enabled, false otherwise.
- */
- public boolean isEnabled() {
- try {
- return mService.isEnabled();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
+ private static final int ADDRESS_LENGTH = 17;
- /**
- * Get the current state of Bluetooth.
- *
- * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
- */
- public int getBluetoothState() {
- try {
- return mService.getBluetoothState();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return BluetoothError.ERROR;
- }
+ private static IBluetooth sService; /* Guarenteed constant after first object constructed */
- /**
- * Enable the Bluetooth device.
- * Turn on the underlying hardware.
- * This is an asynchronous call,
- * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
- * and when the device is sucessfully enabled.
- * @return false if we cannot enable the Bluetooth device. True does not
- * imply the device was enabled, it only implies that so far there were no
- * problems.
- */
- public boolean enable() {
- try {
- return mService.enable();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
+ private final String mAddress;
/**
- * Disable the Bluetooth device.
- * This turns off the underlying hardware.
- *
- * @return true if successful, false otherwise.
+ * Create a new BluetoothDevice
+ * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
+ * and is validated in this constructor.
+ * @param address valid Bluetooth MAC address
+ * @throws RuntimeException Bluetooth is not available on this platform
+ * @throws IllegalArgumentException address is invalid
+ * @hide
*/
- public boolean disable() {
- try {
- return mService.disable(true);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
+ /*package*/ BluetoothDevice(String address) {
+ synchronized (BluetoothDevice.class) {
+ if (sService == null) {
+ IBinder b = ServiceManager.getService(Context.BLUETOOTH_SERVICE);
+ if (b == null) {
+ throw new RuntimeException("Bluetooth service not available");
+ }
+ sService = IBluetooth.Stub.asInterface(b);
+ }
+ }
- public String getAddress() {
- try {
- return mService.getAddress();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
+ if (!checkBluetoothAddress(address)) {
+ throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
+ }
- /**
- * Get the friendly Bluetooth name of this device.
- *
- * This name is visible to remote Bluetooth devices. Currently it is only
- * possible to retrieve the Bluetooth name when Bluetooth is enabled.
- *
- * @return the Bluetooth name, or null if there was a problem.
- */
- public String getName() {
- try {
- return mService.getName();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ mAddress = address;
}
- /**
- * Set the friendly Bluetooth name of this device.
- *
- * This name is visible to remote Bluetooth devices. The Bluetooth Service
- * is responsible for persisting this name.
- *
- * @param name the name to set
- * @return true, if the name was successfully set. False otherwise.
- */
- public boolean setName(String name) {
- try {
- return mService.setName(name);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothDevice) {
+ return mAddress.equals(((BluetoothDevice)o).getAddress());
+ }
return false;
}
- public String getVersion() {
- try {
- return mService.getVersion();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getRevision() {
- try {
- return mService.getRevision();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getManufacturer() {
- try {
- return mService.getManufacturer();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getCompany() {
- try {
- return mService.getCompany();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ @Override
+ public int hashCode() {
+ return mAddress.hashCode();
}
/**
- * Get the current scan mode.
- * Used to determine if the local device is connectable and/or discoverable
- * @return Scan mode, one of SCAN_MODE_* or an error code
+ * Returns a string representation of this BluetoothDevice.
+ * <p>Currently this is the Bluetooth hardware address, for example
+ * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
+ * if you explicitly require the Bluetooth hardware address in case the
+ * {@link #toString} representation changes in the future.
+ * @return string representation of this BluetoothDevice
*/
- public int getScanMode() {
- try {
- return mService.getScanMode();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return BluetoothError.ERROR_IPC;
- }
-
- /**
- * Set the current scan mode.
- * Used to make the local device connectable and/or discoverable
- * @param scanMode One of SCAN_MODE_*
- */
- public void setScanMode(int scanMode) {
- try {
- mService.setScanMode(scanMode);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- }
-
- public int getDiscoverableTimeout() {
- try {
- return mService.getDiscoverableTimeout();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return -1;
- }
- public void setDiscoverableTimeout(int timeout) {
- try {
- mService.setDiscoverableTimeout(timeout);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- }
-
- public boolean startDiscovery() {
- return startDiscovery(true);
- }
- public boolean startDiscovery(boolean resolveNames) {
- try {
- return mService.startDiscovery(resolveNames);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
-
- public void cancelDiscovery() {
- try {
- mService.cancelDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- }
-
- public boolean isDiscovering() {
- try {
- return mService.isDiscovering();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ @Override
+ public String toString() {
+ return mAddress;
}
- public boolean startPeriodicDiscovery() {
- try {
- return mService.startPeriodicDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
- public boolean stopPeriodicDiscovery() {
- try {
- return mService.stopPeriodicDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
- public boolean isPeriodicDiscovery() {
- try {
- return mService.isPeriodicDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ /** @hide */
+ public int describeContents() {
+ return 0;
}
- public String[] listRemoteDevices() {
- try {
- return mService.listRemoteDevices();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
+ /** @hide */
+ public static final Parcelable.Creator<BluetoothDevice> CREATOR =
+ new Parcelable.Creator<BluetoothDevice>() {
+ public BluetoothDevice createFromParcel(Parcel in) {
+ return new BluetoothDevice(in.readString());
+ }
+ public BluetoothDevice[] newArray(int size) {
+ return new BluetoothDevice[size];
+ }
+ };
- /**
- * List remote devices that have a low level (ACL) connection.
- *
- * RFCOMM, SDP and L2CAP are all built on ACL connections. Devices can have
- * an ACL connection even when not paired - this is common for SDP queries
- * or for in-progress pairing requests.
- *
- * In most cases you probably want to test if a higher level protocol is
- * connected, rather than testing ACL connections.
- *
- * @return bluetooth hardware addresses of remote devices with a current
- * ACL connection. Array size is 0 if no devices have a
- * connection. Null on error.
- */
- public String[] listAclConnections() {
- try {
- return mService.listAclConnections();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ /** @hide */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mAddress);
}
/**
- * Check if a specified remote device has a low level (ACL) connection.
- *
- * RFCOMM, SDP and L2CAP are all built on ACL connections. Devices can have
- * an ACL connection even when not paired - this is common for SDP queries
- * or for in-progress pairing requests.
- *
- * In most cases you probably want to test if a higher level protocol is
- * connected, rather than testing ACL connections.
- *
- * @param address the Bluetooth hardware address you want to check.
- * @return true if there is an ACL connection, false otherwise and on
- * error.
+ * Returns the hardware address of this BluetoothDevice.
+ * <p> For example, "00:11:22:AA:BB:CC".
+ * @return Bluetooth hardware address as string
*/
- public boolean isAclConnected(String address) {
- try {
- return mService.isAclConnected(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ public String getAddress() {
+ return mAddress;
}
/**
- * Perform a low level (ACL) disconnection of a remote device.
+ * Get the friendly Bluetooth name of the remote device.
*
- * This forcably disconnects the ACL layer connection to a remote device,
- * which will cause all RFCOMM, SDP and L2CAP connections to this remote
- * device to close.
+ * <p>The local adapter will automatically retrieve remote names when
+ * performing a device scan, and will cache them. This method just returns
+ * the name for this device from the cache.
*
- * @param address the Bluetooth hardware address you want to disconnect.
- * @return true if the device was disconnected, false otherwise and on
- * error.
+ * @return the Bluetooth name, or null if there was a problem.
+ * @hide
*/
- public boolean disconnectRemoteDeviceAcl(String address) {
+ public String getName() {
try {
- return mService.disconnectRemoteDeviceAcl(address);
+ return sService.getRemoteName(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ return null;
}
/**
@@ -358,62 +213,39 @@ public class BluetoothDevice {
* @param address the remote device Bluetooth address.
* @return false If there was an immediate problem creating the bonding,
* true otherwise.
+ * @hide
*/
- public boolean createBond(String address) {
+ public boolean createBond() {
try {
- return mService.createBond(address);
+ return sService.createBond(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
* Cancel an in-progress bonding request started with createBond.
+ * @hide
*/
- public boolean cancelBondProcess(String address) {
- try {
- return mService.cancelBondProcess(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
-
- /**
- * Remove an already exisiting bonding (delete the link key).
- */
- public boolean removeBond(String address) {
+ public boolean cancelBondProcess() {
try {
- return mService.removeBond(address);
+ return sService.cancelBondProcess(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
- * List remote devices that are bonded (paired) to the local device.
+ * Removes the remote device and the pairing information associated
+ * with it.
*
- * Bonding (pairing) is the process by which the user enters a pin code for
- * the device, which generates a shared link key, allowing for
- * authentication and encryption of future connections. In Android we
- * require bonding before RFCOMM or SCO connections can be made to a remote
- * device.
- *
- * This function lists which remote devices we have a link key for. It does
- * not cause any RF transmission, and does not check if the remote device
- * still has it's link key with us. If the other side no longer has its
- * link key then the RFCOMM or SCO connection attempt will result in an
- * error.
- *
- * This function does not check if the remote device is in range.
- *
- * Remote devices that have an in-progress bonding attempt are not
- * returned.
- *
- * @return bluetooth hardware addresses of remote devices that are
- * bonded. Array size is 0 if no devices are bonded. Null on error.
+ * @return true if the device was disconnected, false otherwise and on
+ * error.
+ * @hide
*/
- public String[] listBonds() {
+ public boolean removeBond() {
try {
- return mService.listBonds();
+ return sService.removeBond(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return false;
}
/**
@@ -425,106 +257,114 @@ public class BluetoothDevice {
*
* @param address Bluetooth hardware address of the remote device to check.
* @return Result code
+ * @hide
*/
- public int getBondState(String address) {
+ public int getBondState() {
try {
- return mService.getBondState(address);
+ return sService.getBondState(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return BluetoothError.ERROR_IPC;
}
- public String getRemoteName(String address) {
+ /** @hide */
+ public int getBluetoothClass() {
try {
- return mService.getRemoteName(address);
+ return sService.getRemoteClass(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return BluetoothError.ERROR_IPC;
}
- public String getRemoteVersion(String address) {
+ /** @hide */
+ public String[] getUuids() {
try {
- return mService.getRemoteVersion(address);
+ return sService.getRemoteUuids(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
- public String getRemoteRevision(String address) {
+
+ /** @hide */
+ public int getServiceChannel(String uuid) {
+ try {
+ return sService.getRemoteServiceChannel(mAddress, uuid);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return BluetoothError.ERROR_IPC;
+ }
+
+ /** @hide */
+ public boolean setPin(byte[] pin) {
try {
- return mService.getRemoteRevision(address);
+ return sService.setPin(mAddress, pin);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return false;
}
- public String getRemoteManufacturer(String address) {
+
+ /** @hide */
+ public boolean setPasskey(int passkey) {
try {
- return mService.getRemoteManufacturer(address);
+ return sService.setPasskey(mAddress, passkey);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return false;
}
- public String getRemoteCompany(String address) {
+
+ /** @hide */
+ public boolean setPairingConfirmation(boolean confirm) {
try {
- return mService.getRemoteCompany(address);
+ return sService.setPairingConfirmation(mAddress, confirm);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return false;
}
- /**
- * Returns the RFCOMM channel associated with the 16-byte UUID on
- * the remote Bluetooth address.
- *
- * Performs a SDP ServiceSearchAttributeRequest transaction. The provided
- * uuid is verified in the returned record. If there was a problem, or the
- * specified uuid does not exist, -1 is returned.
- */
- public boolean getRemoteServiceChannel(String address, short uuid16,
- IBluetoothDeviceCallback callback) {
+ /** @hide */
+ public boolean cancelPairingUserInput() {
try {
- return mService.getRemoteServiceChannel(address, uuid16, callback);
+ return sService.cancelPairingUserInput(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
- * Get the major, minor and servics classes of a remote device.
- * These classes are encoded as a 32-bit integer. See BluetoothClass.
- * @param address remote device
- * @return 32-bit class suitable for use with BluetoothClass, or
- * BluetoothClass.ERROR on error
+ * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
+ * outgoing connection to this remote device.
+ * <p>The remote device will be authenticated and communication on this
+ * socket will be encrypted.
+ * <p>Use {@link BluetoothSocket#connect} to intiate the outgoing
+ * connection.
+ * <p>Valid RFCOMM channels are in range 1 to 30.
+ * @param channel RFCOMM channel to connect to
+ * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions
*/
- public int getRemoteClass(String address) {
- try {
- return mService.getRemoteClass(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return BluetoothClass.ERROR;
+ public BluetoothSocket createRfcommSocket(int channel) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel);
}
- public byte[] getRemoteFeatures(String address) {
- try {
- return mService.getRemoteFeatures(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String lastSeen(String address) {
- try {
- return mService.lastSeen(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String lastUsed(String address) {
- try {
- return mService.lastUsed(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ /**
+ * 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 port remote port
+ * @return An RFCOMM BluetoothSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port);
}
- public boolean setPin(String address, byte[] pin) {
- try {
- return mService.setPin(address, pin);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
- public boolean cancelPin(String address) {
- try {
- return mService.cancelPin(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ /**
+ * Construct a SCO socket ready to start an outgoing connection.
+ * Call #connect on the returned #BluetoothSocket to begin the connection.
+ * @return a SCO BluetoothSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothSocket createScoSocket() throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1);
}
/**
@@ -534,6 +374,7 @@ public class BluetoothDevice {
* @param pin pin as java String
* @return the pin code as a UTF8 byte array, or null if it is an invalid
* Bluetooth pin.
+ * @hide
*/
public static byte[] convertPinToBytes(String pin) {
if (pin == null) {
@@ -552,8 +393,8 @@ public class BluetoothDevice {
return pinBytes;
}
- private static final int ADDRESS_LENGTH = 17;
- /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */
+ /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0"
+ * @hide */
public static boolean checkBluetoothAddress(String address) {
if (address == null || address.length() != ADDRESS_LENGTH) {
return false;
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index fe1e09a..d31b6ae 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -49,7 +49,7 @@ import android.util.Log;
*
* @hide
*/
-public class BluetoothHeadset {
+public final class BluetoothHeadset {
private static final String TAG = "BluetoothHeadset";
private static final boolean DBG = false;
@@ -163,16 +163,16 @@ public class BluetoothHeadset {
}
/**
- * Get the Bluetooth address of the current headset.
- * @return The Bluetooth address, or null if not in connected or connecting
+ * Get the BluetoothDevice for the current headset.
+ * @return current headset, or null if not in connected or connecting
* state, or if this proxy object is not connected to the Headset
* service.
*/
- public String getHeadsetAddress() {
- if (DBG) log("getHeadsetAddress()");
+ public BluetoothDevice getCurrentHeadset() {
+ if (DBG) log("getCurrentHeadset()");
if (mService != null) {
try {
- return mService.getHeadsetAddress();
+ return mService.getCurrentHeadset();
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
Log.w(TAG, "Proxy not attached to service");
@@ -185,19 +185,19 @@ public class BluetoothHeadset {
* Request to initiate a connection to a headset.
* This call does not block. Fails if a headset is already connecting
* or connected.
- * Initiates auto-connection if address is null. Tries to connect to all
+ * Initiates auto-connection if device is null. Tries to connect to all
* devices with priority greater than PRIORITY_AUTO in descending order.
- * @param address The Bluetooth Address to connect to, or null to
- * auto-connect to the last connected headset.
- * @return False if there was a problem initiating the connection
- * procedure, and no further HEADSET_STATE_CHANGED intents
- * will be expected.
+ * @param device device to connect to, or null to auto-connect last connected
+ * headset
+ * @return false if there was a problem initiating the connection
+ * procedure, and no further HEADSET_STATE_CHANGED intents
+ * will be expected.
*/
- public boolean connectHeadset(String address) {
- if (DBG) log("connectHeadset(" + address + ")");
+ public boolean connectHeadset(BluetoothDevice device) {
+ if (DBG) log("connectHeadset(" + device + ")");
if (mService != null) {
try {
- if (mService.connectHeadset(address)) {
+ if (mService.connectHeadset(device)) {
return true;
}
} catch (RemoteException e) {Log.e(TAG, e.toString());}
@@ -213,11 +213,11 @@ public class BluetoothHeadset {
* connecting). Returns false if not connected, or if this proxy object
* if not currently connected to the headset service.
*/
- public boolean isConnected(String address) {
- if (DBG) log("isConnected(" + address + ")");
+ public boolean isConnected(BluetoothDevice device) {
+ if (DBG) log("isConnected(" + device + ")");
if (mService != null) {
try {
- return mService.isConnected(address);
+ return mService.isConnected(device);
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
Log.w(TAG, "Proxy not attached to service");
@@ -295,16 +295,16 @@ public class BluetoothHeadset {
* auto-connected.
* Incoming connections are ignored regardless of priority if there is
* already a headset connected.
- * @param address Paired headset
+ * @param device paired headset
* @param priority Integer priority, for example PRIORITY_AUTO or
* PRIORITY_NONE
- * @return True if successful, false if there was some error.
+ * @return true if successful, false if there was some error
*/
- public boolean setPriority(String address, int priority) {
- if (DBG) log("setPriority(" + address + ", " + priority + ")");
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
if (mService != null) {
try {
- return mService.setPriority(address, priority);
+ return mService.setPriority(device, priority);
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
Log.w(TAG, "Proxy not attached to service");
@@ -315,14 +315,14 @@ public class BluetoothHeadset {
/**
* Get priority of headset.
- * @param address Headset
- * @return non-negative priority, or negative error code on error.
+ * @param device headset
+ * @return non-negative priority, or negative error code on error
*/
- public int getPriority(String address) {
- if (DBG) log("getPriority(" + address + ")");
+ public int getPriority(BluetoothDevice device) {
+ if (DBG) log("getPriority(" + device + ")");
if (mService != null) {
try {
- return mService.getPriority(address);
+ return mService.getPriority(device);
} catch (RemoteException e) {Log.e(TAG, e.toString());}
} else {
Log.w(TAG, "Proxy not attached to service");
@@ -356,30 +356,6 @@ public class BluetoothHeadset {
return -1;
}
- /**
- * Check class bits for possible HSP or HFP support.
- * This is a simple heuristic that tries to guess if a device with the
- * given class bits might support HSP or HFP. It is not accurate for all
- * devices. It tries to err on the side of false positives.
- * @return True if this device might support HSP or HFP.
- */
- public static boolean doesClassMatch(int btClass) {
- // The render service class is required by the spec for HFP, so is a
- // pretty good signal
- if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
- return true;
- }
- // Just in case they forgot the render service class
- switch (BluetoothClass.Device.getDevice(btClass)) {
- case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
- case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
- case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
- return true;
- default:
- return false;
- }
- }
-
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
diff --git a/core/java/android/bluetooth/BluetoothInputStream.java b/core/java/android/bluetooth/BluetoothInputStream.java
new file mode 100644
index 0000000..c060f32
--- /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] & 0xff;
+ } 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/BluetoothIntent.java b/core/java/android/bluetooth/BluetoothIntent.java
index 344601b..c39bc3d 100644
--- a/core/java/android/bluetooth/BluetoothIntent.java
+++ b/core/java/android/bluetooth/BluetoothIntent.java
@@ -31,8 +31,8 @@ import android.annotation.SdkConstant.SdkConstantType;
public interface BluetoothIntent {
public static final String SCAN_MODE =
"android.bluetooth.intent.SCAN_MODE";
- public static final String ADDRESS =
- "android.bluetooth.intent.ADDRESS";
+ public static final String DEVICE =
+ "android.bluetooth.intent.DEVICE";
public static final String NAME =
"android.bluetooth.intent.NAME";
public static final String ALIAS =
@@ -57,6 +57,39 @@ public interface BluetoothIntent {
"android.bluetooth.intent.BOND_PREVIOUS_STATE";
public static final String REASON =
"android.bluetooth.intent.REASON";
+ public static final String PAIRING_VARIANT =
+ "android.bluetooth.intent.PAIRING_VARIANT";
+ public static final String PASSKEY =
+ "android.bluetooth.intent.PASSKEY";
+
+ public static final String DEVICE_PICKER_NEED_AUTH =
+ "android.bluetooth.intent.DEVICE_PICKER_NEED_AUTH";
+ public static final String DEVICE_PICKER_FILTER_TYPE =
+ "android.bluetooth.intent.DEVICE_PICKER_FILTER_TYPE";
+ public static final String DEVICE_PICKER_LAUNCH_PACKAGE =
+ "android.bluetooth.intent.DEVICE_PICKER_LAUNCH_PACKAGE";
+ public static final String DEVICE_PICKER_LAUNCH_CLASS =
+ "android.bluetooth.intent.DEVICE_PICKER_LAUNCH_CLASS";
+
+ /**
+ * Broadcast when one BT device is selected from BT device picker screen.
+ * Selected BT device address is contained in extra string "BluetoothIntent.ADDRESS".
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String DEVICE_PICKER_DEVICE_SELECTED =
+ "android.bluetooth.intent.action.DEVICE_SELECTED";
+
+ /**
+ * Broadcast when someone want to select one BT device from devices list.
+ * This intent contains below extra data:
+ * - BluetoothIntent.DEVICE_PICKER_NEED_AUTH (boolean): if need authentication
+ * - BluetoothIntent.DEVICE_PICKER_FILTER_TYPE (int): what kinds of device should be listed
+ * - BluetoothIntent.DEVICE_PICKER_LAUNCH_PACKAGE (string): where(which package) this intent come from
+ * - BluetoothIntent.DEVICE_PICKER_LAUNCH_CLASS (string): where(which class) this intent come from
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String DEVICE_PICKER_DEVICE_PICKER =
+ "android.bluetooth.intent.action.DEVICE_PICKER";
/** Broadcast when the local Bluetooth device state changes, for example
* when Bluetooth is enabled. Will contain int extra's BLUETOOTH_STATE and
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/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
new file mode 100644
index 0000000..645e241
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -0,0 +1,257 @@
+/*
+ * 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.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * The Android Bluetooth API is not finalized, and *will* change. Use at your
+ * own risk.
+ *
+ * Public API for controlling the Bluetooth Pbap Service. This includes
+ * Bluetooth Phone book Access profile.
+ * BluetoothPbap is a proxy object for controlling the Bluetooth Pbap
+ * Service via IPC.
+ *
+ * Creating a BluetoothPbap object will create a binding with the
+ * BluetoothPbap service. Users of this object should call close() when they
+ * are finished with the BluetoothPbap, so that this proxy object can unbind
+ * from the service.
+ *
+ * This BluetoothPbap object is not immediately bound to the
+ * BluetoothPbap service. Use the ServiceListener interface to obtain a
+ * notification when it is bound, this is especially important if you wish to
+ * immediately call methods on BluetoothPbap after construction.
+ *
+ * Android only supports one connected Bluetooth Pce at a time.
+ *
+ * @hide
+ */
+public class BluetoothPbap {
+
+ private static final String TAG = "BluetoothPbap";
+ private static final boolean DBG = false;
+
+ /** int extra for PBAP_STATE_CHANGED_ACTION */
+ public static final String PBAP_STATE =
+ "android.bluetooth.pbap.intent.PBAP_STATE";
+ /** int extra for PBAP_STATE_CHANGED_ACTION */
+ public static final String PBAP_PREVIOUS_STATE =
+ "android.bluetooth.pbap.intent.PBAP_PREVIOUS_STATE";
+
+ /** Indicates the state of an pbap connection state has changed.
+ * This intent will always contain PBAP_STATE, PBAP_PREVIOUS_STATE and
+ * BluetoothIntent.ADDRESS extras.
+ */
+ public static final String PBAP_STATE_CHANGED_ACTION =
+ "android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED";
+
+ private IBluetoothPbap mService;
+ private final Context mContext;
+ private final ServiceListener mServiceListener;
+
+ /** There was an error trying to obtain the state */
+ public static final int STATE_ERROR = -1;
+ /** No client currently connected */
+ public static final int STATE_DISCONNECTED = 0;
+ /** Connection attempt in progress */
+ public static final int STATE_CONNECTING = 1;
+ /** Client is currently connected */
+ public static final int STATE_CONNECTED = 2;
+
+ public static final int RESULT_FAILURE = 0;
+ public static final int RESULT_SUCCESS = 1;
+ /** Connection canceled before completion. */
+ public static final int RESULT_CANCELED = 2;
+
+ /**
+ * An interface for notifying Bluetooth PCE IPC clients when they have
+ * been connected to the BluetoothPbap service.
+ */
+ public interface ServiceListener {
+ /**
+ * Called to notify the client when this proxy object has been
+ * connected to the BluetoothPbap service. Clients must wait for
+ * this callback before making IPC calls on the BluetoothPbap
+ * service.
+ */
+ public void onServiceConnected();
+
+ /**
+ * Called to notify the client that this proxy object has been
+ * disconnected from the BluetoothPbap service. Clients must not
+ * make IPC calls on the BluetoothPbap service after this callback.
+ * This callback will currently only occur if the application hosting
+ * the BluetoothPbap service, but may be called more often in future.
+ */
+ public void onServiceDisconnected();
+ }
+
+ /**
+ * Create a BluetoothPbap proxy object.
+ */
+ public BluetoothPbap(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ if (!context.bindService(new Intent(IBluetoothPbap.class.getName()), mConnection, 0)) {
+ Log.e(TAG, "Could not bind to Bluetooth Pbap Service");
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Close the connection to the backing service.
+ * Other public functions of BluetoothPbap will return default error
+ * results once close() has been called. Multiple invocations of close()
+ * are ok.
+ */
+ public synchronized void close() {
+ if (mConnection != null) {
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ }
+ }
+
+ /**
+ * Get the current state of the BluetoothPbap service.
+ * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
+ * object is currently not connected to the Pbap service.
+ */
+ public int getState() {
+ if (DBG) log("getState()");
+ if (mService != null) {
+ try {
+ return mService.getState();
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ }
+ return BluetoothPbap.STATE_ERROR;
+ }
+
+ /**
+ * Get the currently connected remote Bluetooth device (PCE).
+ * @return The remote Bluetooth device, or null if not in connected or
+ * connecting state, or if this proxy object is not connected to
+ * the Pbap service.
+ */
+ public BluetoothDevice getClient() {
+ if (DBG) log("getClient()");
+ if (mService != null) {
+ try {
+ return mService.getClient();
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if the specified Bluetooth device is connected (does not
+ * include connecting). Returns false if not connected, or if this proxy
+ * object is not currently connected to the Pbap service.
+ */
+ public boolean isConnected(BluetoothDevice device) {
+ if (DBG) log("isConnected(" + device + ")");
+ if (mService != null) {
+ try {
+ return mService.isConnected(device);
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Disconnects the current Pbap client (PCE). Currently this call blocks,
+ * it may soon be made asynchornous. Returns false if this proxy object is
+ * not currently connected to the Pbap service.
+ */
+ public boolean disconnect() {
+ if (DBG) log("disconnect()");
+ if (mService != null) {
+ try {
+ mService.disconnect();
+ return true;
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) log(Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Check class bits for possible PBAP support.
+ * This is a simple heuristic that tries to guess if a device with the
+ * given class bits might support PBAP. It is not accurate for all
+ * devices. It tries to err on the side of false positives.
+ * @return True if this device might support PBAP.
+ */
+ public static boolean doesClassMatchSink(int btClass) {
+ // TODO optimize the rule
+ switch (BluetoothClass.Device.getDevice(btClass)) {
+ case BluetoothClass.Device.COMPUTER_DESKTOP:
+ case BluetoothClass.Device.COMPUTER_LAPTOP:
+ case BluetoothClass.Device.COMPUTER_SERVER:
+ case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) log("Proxy object connected");
+ mService = IBluetoothPbap.Stub.asInterface(service);
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected();
+ }
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) log("Proxy object disconnected");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected();
+ }
+ }
+ };
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
new file mode 100644
index 0000000..e653c23
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothServerSocket.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.bluetooth;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * A listening Bluetooth socket.
+ *
+ * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
+ * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
+ * side, use a {@link BluetoothServerSocket} to create a listening server
+ * socket. It will return a new, connected {@link BluetoothSocket} on an
+ * accepted connection. On the client side, use the same
+ * {@link BluetoothSocket} object to both intiate the outgoing connection,
+ * and to manage the connected socket.
+ *
+ * <p>The most common type of Bluetooth Socket is RFCOMM. RFCOMM is a
+ * connection orientated, streaming transport over Bluetooth. It is also known
+ * as the Serial Port Profile (SPP).
+ *
+ * <p>Use {@link BluetoothDevice#createRfcommSocket} to create a new {@link
+ * BluetoothSocket} ready for an outgoing connection to a remote
+ * {@link BluetoothDevice}.
+ *
+ * <p>Use {@link BluetoothAdapter#listenUsingRfcommOn} to create a listening
+ * {@link BluetoothServerSocket} ready for incoming connections to the local
+ * {@link BluetoothAdapter}.
+ *
+ * <p>{@link BluetoothSocket} and {@link BluetoothServerSocket} are thread
+ * safe. In particular, {@link #close} will always immediately abort ongoing
+ * operations and close the socket.
+ */
+public final class BluetoothServerSocket implements Closeable {
+ /*package*/ final BluetoothSocket mSocket;
+
+ /**
+ * 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
+ */
+ /*package*/ 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.
+ * <p>Returns a connected {@link BluetoothSocket} on successful connection.
+ * <p>Once this call returns, it can be called again to accept subsequent
+ * incoming connections.
+ * <p>{@link #close} can be used to abort this call from another thread.
+ * @return a connected {@link BluetoothSocket}
+ * @throws IOException on error, for example this call was aborted, or
+ * timeout
+ */
+ public BluetoothSocket accept() throws IOException {
+ return accept(-1);
+ }
+
+ /**
+ * Block until a connection is established, with timeout.
+ * <p>Returns a connected {@link BluetoothSocket} on successful connection.
+ * <p>Once this call returns, it can be called again to accept subsequent
+ * incoming connections.
+ * <p>{@link #close} can be used to abort this call from another thread.
+ * @return a connected {@link BluetoothSocket}
+ * @throws IOException on error, for example this call was aborted, or
+ * timeout
+ */
+ public BluetoothSocket accept(int timeout) throws IOException {
+ return mSocket.acceptNative(timeout);
+ }
+
+ /**
+ * Immediately close this socket, and release all associated resources.
+ * <p>Causes blocked calls on this socket in other threads 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..eae0f37
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -0,0 +1,187 @@
+/*
+ * 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;
+
+/**
+ * A connected or connecting Bluetooth socket.
+ *
+ * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
+ * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
+ * side, use a {@link BluetoothServerSocket} to create a listening server
+ * socket. It will return a new, connected {@link BluetoothSocket} on an
+ * accepted connection. On the client side, use the same
+ * {@link BluetoothSocket} object to both intiate the outgoing connection,
+ * and to manage the connected socket.
+ *
+ * <p>The most common type of Bluetooth Socket is RFCOMM. RFCOMM is a
+ * connection orientated, streaming transport over Bluetooth. It is also known
+ * as the Serial Port Profile (SPP).
+ *
+ * <p>Use {@link BluetoothDevice#createRfcommSocket} to create a new {@link
+ * BluetoothSocket} ready for an outgoing connection to a remote
+ * {@link BluetoothDevice}.
+ *
+ * <p>Use {@link BluetoothAdapter#listenUsingRfcommOn} to create a listening
+ * {@link BluetoothServerSocket} ready for incoming connections to the local
+ * {@link BluetoothAdapter}.
+ *
+ * <p>{@link BluetoothSocket} and {@link BluetoothServerSocket} are thread
+ * safe. In particular, {@link #close} will always immediately abort ongoing
+ * operations and close the socket.
+ */
+public final class BluetoothSocket implements Closeable {
+ /** Keep TYPE_ fields 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 BluetoothDevice mDevice; /* remote device */
+ 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 BluetoothSocket.
+ * @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 device remote device 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,
+ BluetoothDevice device, int port) throws IOException {
+ mType = type;
+ mAuth = auth;
+ mEncrypt = encrypt;
+ mDevice = device;
+ if (device == null) {
+ mAddress = null;
+ } else {
+ mAddress = device.getAddress();
+ }
+ mPort = port;
+ if (fd == -1) {
+ initSocketNative();
+ } else {
+ initSocketFromFdNative(fd);
+ }
+ mInputStream = new BluetoothInputStream(this);
+ mOutputStream = new BluetoothOutputStream(this);
+ }
+
+ /**
+ * Construct a BluetoothSocket from address.
+ * @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 device that this socket can connect to
+ * @param port remote port
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient priveleges
+ */
+ private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
+ int port) throws IOException {
+ this(type, fd, auth, encrypt, new BluetoothDevice(address), port);
+ }
+
+ /** @hide */
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Attempt to connect to a remote device.
+ * <p>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.
+ * <p>{@link #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();
+ }
+
+ /**
+ * Immediately close this socket, and release all associated resources.
+ * <p>Causes blocked calls on this socket in other threads to immediately
+ * throw an IOException.
+ */
+ public void close() throws IOException {
+ closeNative();
+ }
+
+ /**
+ * Get the remote device this socket is connecting, or connected, to.
+ * @return remote device
+ */
+ public BluetoothDevice getRemoteDevice() {
+ return mDevice;
+ }
+
+ /**
+ * Get the input stream associated with this socket.
+ * <p>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.
+ * <p>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/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
new file mode 100644
index 0000000..c15bc20
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -0,0 +1,69 @@
+/*
+ * 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.util.UUID;
+
+/**
+* Static helper methods and constants to decode the UUID of remote devices.
+* @hide
+*/
+public final class BluetoothUuid {
+
+ /* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
+ * for the various services.
+ *
+ * The following 128 bit values are calculated as:
+ * uuid * 2^96 + BASE_UUID
+ */
+ public static final UUID AudioSink = UUID.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+ public static final UUID AudioSource = UUID.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+ public static final UUID AdvAudioDist = UUID.fromString("0000110D-0000-1000-8000-00805F9B34FB");
+ public static final UUID HSP = UUID.fromString("00001108-0000-1000-8000-00805F9B34FB");
+ public static final UUID Handsfree = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
+ public static final UUID AvrcpController =
+ UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");
+ public static final UUID AvrcpTarget = UUID.fromString("0000110C-0000-1000-8000-00805F9B34FB");
+
+ public static boolean isAudioSource(UUID uuid) {
+ return uuid.equals(AudioSource);
+ }
+
+ public static boolean isAudioSink(UUID uuid) {
+ return uuid.equals(AudioSink);
+ }
+
+ public static boolean isAdvAudioDist(UUID uuid) {
+ return uuid.equals(AdvAudioDist);
+ }
+
+ public static boolean isHandsfree(UUID uuid) {
+ return uuid.equals(Handsfree);
+ }
+
+ public static boolean isHeadset(UUID uuid) {
+ return uuid.equals(HSP);
+ }
+
+ public static boolean isAvrcpController(UUID uuid) {
+ return uuid.equals(AvrcpController);
+ }
+
+ public static boolean isAvrcpTarget(UUID uuid) {
+ return uuid.equals(AvrcpTarget);
+ }
+}
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/HeadsetBase.java b/core/java/android/bluetooth/HeadsetBase.java
index f987ffd..29cf41d 100644
--- a/core/java/android/bluetooth/HeadsetBase.java
+++ b/core/java/android/bluetooth/HeadsetBase.java
@@ -31,7 +31,7 @@ import android.util.Log;
*
* @hide
*/
-public class HeadsetBase {
+public final class HeadsetBase {
private static final String TAG = "Bluetooth HeadsetBase";
private static final boolean DBG = false;
@@ -42,8 +42,9 @@ public class HeadsetBase {
private static int sAtInputCount = 0; /* TODO: Consider not using a static variable */
- private final BluetoothDevice mBluetooth;
- private final String mAddress;
+ private final BluetoothAdapter mAdapter;
+ private final BluetoothDevice mRemoteDevice;
+ private final String mAddress; // for native code
private final int mRfcommChannel;
private int mNativeData;
private Thread mEventThread;
@@ -73,12 +74,13 @@ public class HeadsetBase {
private native void cleanupNativeDataNative();
- public HeadsetBase(PowerManager pm, BluetoothDevice bluetooth, String address,
- int rfcommChannel) {
+ public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device,
+ int rfcommChannel) {
mDirection = DIRECTION_OUTGOING;
mConnectTimestamp = System.currentTimeMillis();
- mBluetooth = bluetooth;
- mAddress = address;
+ mAdapter = adapter;
+ mRemoteDevice = device;
+ mAddress = device.getAddress();
mRfcommChannel = rfcommChannel;
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetBase");
mWakeLock.setReferenceCounted(false);
@@ -88,12 +90,13 @@ public class HeadsetBase {
}
/* Create from an already exisiting rfcomm connection */
- public HeadsetBase(PowerManager pm, BluetoothDevice bluetooth, String address, int socketFd,
- int rfcommChannel, Handler handler) {
+ public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device,
+ int socketFd, int rfcommChannel, Handler handler) {
mDirection = DIRECTION_INCOMING;
mConnectTimestamp = System.currentTimeMillis();
- mBluetooth = bluetooth;
- mAddress = address;
+ mAdapter = adapter;
+ mRemoteDevice = device;
+ mAddress = device.getAddress();
mRfcommChannel = rfcommChannel;
mEventThreadHandler = handler;
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetBase");
@@ -252,12 +255,8 @@ public class HeadsetBase {
return mEventThread != null;
}
- public String getAddress() {
- return mAddress;
- }
-
- public String getName() {
- return mBluetooth.getRemoteName(mAddress);
+ public BluetoothDevice getRemoteDevice() {
+ return mRemoteDevice;
}
public int getDirection() {
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
new file mode 100644
index 0000000..9e05a87
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -0,0 +1,61 @@
+/*
+ * 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.bluetooth;
+
+/**
+ * System private API for talking with the Bluetooth service.
+ *
+ * {@hide}
+ */
+interface IBluetooth
+{
+ boolean isEnabled();
+ int getBluetoothState();
+ boolean enable();
+ boolean disable(boolean persistSetting);
+
+ String getAddress();
+ String getName();
+ boolean setName(in String name);
+
+ int getScanMode();
+ boolean setScanMode(int mode);
+
+ int getDiscoverableTimeout();
+ boolean setDiscoverableTimeout(int timeout);
+
+ boolean startDiscovery();
+ boolean cancelDiscovery();
+ boolean isDiscovering();
+
+ boolean createBond(in String address);
+ boolean cancelBondProcess(in String address);
+ boolean removeBond(in String address);
+ String[] listBonds();
+ int getBondState(in String address);
+
+ String getRemoteName(in String address);
+ int getRemoteClass(in String address);
+ String[] getRemoteUuids(in String address);
+ int getRemoteServiceChannel(in String address, String uuid);
+
+ boolean setPin(in String address, in byte[] pin);
+ boolean setPasskey(in String address, int passkey);
+ boolean setPairingConfirmation(in String address, boolean confirm);
+ boolean cancelPairingUserInput(in String address);
+
+}
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index 55ff27f..e6c6be2 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -16,16 +16,18 @@
package android.bluetooth;
+import android.bluetooth.BluetoothDevice;
+
/**
* System private API for Bluetooth A2DP service
*
* {@hide}
*/
interface IBluetoothA2dp {
- int connectSink(in String address);
- int disconnectSink(in String address);
- List<String> listConnectedSinks();
- int getSinkState(in String address);
- int setSinkPriority(in String address, int priority);
- int getSinkPriority(in String address);
+ int connectSink(in BluetoothDevice device);
+ int disconnectSink(in BluetoothDevice device);
+ BluetoothDevice[] getConnectedSinks(); // change to Set<> once AIDL supports
+ int getSinkState(in BluetoothDevice device);
+ int setSinkPriority(in BluetoothDevice device, int priority);
+ int getSinkPriority(in BluetoothDevice device);
}
diff --git a/core/java/android/bluetooth/IBluetoothDevice.aidl b/core/java/android/bluetooth/IBluetoothDevice.aidl
deleted file mode 100644
index 6cd792e..0000000
--- a/core/java/android/bluetooth/IBluetoothDevice.aidl
+++ /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.bluetooth;
-
-import android.bluetooth.IBluetoothDeviceCallback;
-
-/**
- * System private API for talking with the Bluetooth service.
- *
- * {@hide}
- */
-interface IBluetoothDevice
-{
- boolean isEnabled();
- int getBluetoothState();
- boolean enable();
- boolean disable(boolean persistSetting);
-
- String getAddress();
- String getName();
- boolean setName(in String name);
- String getVersion();
- String getRevision();
- String getManufacturer();
- String getCompany();
-
- int getScanMode();
- boolean setScanMode(int mode);
-
- int getDiscoverableTimeout();
- boolean setDiscoverableTimeout(int timeout);
-
- boolean startDiscovery(boolean resolveNames);
- boolean cancelDiscovery();
- boolean isDiscovering();
- boolean startPeriodicDiscovery();
- boolean stopPeriodicDiscovery();
- boolean isPeriodicDiscovery();
- String[] listRemoteDevices();
-
- String[] listAclConnections();
- boolean isAclConnected(in String address);
- boolean disconnectRemoteDeviceAcl(in String address);
-
- boolean createBond(in String address);
- boolean cancelBondProcess(in String address);
- boolean removeBond(in String address);
- String[] listBonds();
- int getBondState(in String address);
-
- String getRemoteName(in String address);
- String getRemoteVersion(in String address);
- String getRemoteRevision(in String address);
- int getRemoteClass(in String address);
- String getRemoteManufacturer(in String address);
- String getRemoteCompany(in String address);
- boolean getRemoteServiceChannel(in String address, int uuid16, in IBluetoothDeviceCallback callback);
- byte[] getRemoteFeatures(in String adddress);
- String lastSeen(in String address);
- String lastUsed(in String address);
-
- boolean setPin(in String address, in byte[] pin);
- boolean cancelPin(in String address);
-}
diff --git a/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl b/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl
deleted file mode 100644
index d057093..0000000
--- a/core/java/android/bluetooth/IBluetoothDeviceCallback.aidl
+++ /dev/null
@@ -1,25 +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.bluetooth;
-
-/**
- * {@hide}
- */
-oneway interface IBluetoothDeviceCallback
-{
- void onGetRemoteServiceChannelResult(in String address, int channel);
-}
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 5f42fd6..6cccd50 100644
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.bluetooth.BluetoothDevice;
+
/**
* System private API for Bluetooth Headset service
*
@@ -23,13 +25,13 @@ package android.bluetooth;
*/
interface IBluetoothHeadset {
int getState();
- String getHeadsetAddress();
- boolean connectHeadset(in String address);
+ BluetoothDevice getCurrentHeadset();
+ boolean connectHeadset(in BluetoothDevice device);
void disconnectHeadset();
- boolean isConnected(in String address);
+ boolean isConnected(in BluetoothDevice device);
boolean startVoiceRecognition();
boolean stopVoiceRecognition();
- boolean setPriority(in String address, int priority);
- int getPriority(in String address);
+ boolean setPriority(in BluetoothDevice device, int priority);
+ int getPriority(in BluetoothDevice device);
int getBatteryUsageHint();
}
diff --git a/core/java/android/bluetooth/IBluetoothPbap.aidl b/core/java/android/bluetooth/IBluetoothPbap.aidl
new file mode 100644
index 0000000..7cc77d1
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothPbap.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * System private API for Bluetooth pbap service
+ *
+ * {@hide}
+ */
+interface IBluetoothPbap {
+ int getState();
+ BluetoothDevice getClient();
+ boolean connect(in BluetoothDevice device);
+ void disconnect();
+ boolean isConnected(in BluetoothDevice device);
+}
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..c2b13a4
--- /dev/null
+++ b/core/java/android/content/AbstractCursorEntityIterator.java
@@ -0,0 +1,120 @@
+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;
+ }
+ }
+
+ public void reset() throws RemoteException {
+ if (mIsClosed) {
+ throw new IllegalStateException("calling reset() when the iterator is closed");
+ }
+ mEntityCursor.moveToPosition(-1);
+ 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..808f30c 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
@@ -133,7 +141,8 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (!upgradeDatabase(db, oldVersion, newVersion)) {
mSyncState.discardSyncData(db, null /* all accounts */);
- getContext().getContentResolver().startSync(mContentUri, new Bundle());
+ ContentResolver.requestSync(null /* all accounts */,
+ mContentUri.getAuthority(), new Bundle());
}
}
@@ -150,23 +159,36 @@ 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();
+ // Only call onAccountsChanged on GAIA accounts; otherwise, the contacts and
+ // calendar providers will choke as they try to sync unknown accounts with
+ // AbstractGDataSyncAdapter, which will put acore into a crash loop
+ ArrayList<Account> gaiaAccounts = new ArrayList<Account>();
+ for (Account acct: accounts) {
+ if (acct.type.equals("com.google.GAIA")) {
+ gaiaAccounts.add(acct);
+ }
+ }
+ accounts = new Account[gaiaAccounts.size()];
+ int i = 0;
+ for (Account acct: gaiaAccounts) {
+ accounts[i++] = acct;
+ }
+ onAccountsChanged(accounts);
+ TempProviderSyncAdapter syncAdapter = getTempProviderSyncAdapter();
+ if (syncAdapter != null) {
+ syncAdapter.onAccountsChanged(accounts);
+ }
+ }
+ }, null /* handler */, true /* updateImmediately */);
return true;
}
-
/**
* Get a non-persistent instance of this content provider.
* You must call {@link #close} on the returned
@@ -236,147 +258,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 +403,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 +515,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 +535,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 +646,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 +662,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 +677,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.name, account.type});
if (Config.LOGV) {
Log.v(TAG, "deleted " + numDeleted
+ " records from table " + table
@@ -634,7 +710,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 +725,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.name, account.type});
}
db.setTransactionSuccessful();
} finally {
@@ -660,14 +737,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 9f609a3..9545fd7 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 +"=?";
private static final String SELECT_UNSYNCED =
- "(" + _SYNC_ACCOUNT + " IS NULL OR " + _SYNC_ACCOUNT + "=?) AND "
- + "(" + _SYNC_ID + " IS NULL OR (" + _SYNC_DIRTY + " > 0 AND "
+ "(" + _SYNC_ACCOUNT + " IS NULL OR ("
+ + _SYNC_ACCOUNT + "=? and " + _SYNC_ACCOUNT_TYPE + "=?)) and "
+ + "(" + _SYNC_ID + " IS NULL OR (" + _SYNC_DIRTY + " > 0 and "
+ _SYNC_VERSION + " IS NOT 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,342 +169,340 @@ 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.name, account.type};
+ 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");
+ }
+ 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});
}
- 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.
- boolean recordChanged = (localSyncVersion == null) ||
- (serverSyncVersion == 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);
+ 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.
+ boolean recordChanged = (localSyncVersion == null) ||
+ (serverSyncVersion == 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;
}
- conflict = true;
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG,
- "remote record " +
- serverSyncId +
- " updates local _sync_id " +
- localSyncID + ", local _id " +
- localRowId);
+ "Skipping update: localSyncVersion: " + localSyncVersion +
+ ", serverSyncVersion: " + serverSyncVersion);
}
- update = true;
}
} else {
+ // the local db doesn't know about this record so add it
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG,
- "Skipping update: localSyncVersion: " + localSyncVersion +
- ", serverSyncVersion: " + serverSyncVersion);
+ 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.name, account.type};
+ 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);
@@ -519,43 +520,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.name, account.type};
// 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");
@@ -564,23 +568,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/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
new file mode 100644
index 0000000..1edcb0a
--- /dev/null
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -0,0 +1,199 @@
+/*
+ * 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.accounts.Account;
+import android.os.Bundle;
+import android.os.Process;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * An abstract implementation of a SyncAdapter that spawns a thread to invoke a sync operation.
+ * If a sync operation is already in progress when a startSync() request is received then an error
+ * will be returned to the new request and the existing request will be allowed to continue.
+ * When a startSync() is received and there is no sync operation in progress then a thread
+ * will be started to run the operation and {@link #performSync} will be invoked on that thread.
+ * If a cancelSync() is received that matches an existing sync operation then the thread
+ * that is running that sync operation will be interrupted, which will indicate to the thread
+ * that the sync has been canceled.
+ *
+ * @hide
+ */
+public abstract class AbstractThreadedSyncAdapter {
+ private final Context mContext;
+ private final AtomicInteger mNumSyncStarts;
+ private final ISyncAdapterImpl mISyncAdapterImpl;
+
+ // all accesses to this member variable must be synchronized on mSyncThreadLock
+ private SyncThread mSyncThread;
+ private final Object mSyncThreadLock = new Object();
+
+ /** Kernel event log tag. Also listed in data/etc/event-log-tags. */
+ public static final int LOG_SYNC_DETAILS = 2743;
+ private final boolean mAutoInitialize;
+
+ /**
+ * Creates an {@link AbstractThreadedSyncAdapter}.
+ * @param context the {@link android.content.Context} that this is running within.
+ * @param autoInitialize if true then sync requests that have
+ * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by
+ * {@link AbstractThreadedSyncAdapter} by calling
+ * {@link ContentResolver#setIsSyncable(android.accounts.Account, String, int)} with 1 if it
+ * is currently set to <0.
+ */
+ public AbstractThreadedSyncAdapter(Context context, boolean autoInitialize) {
+ mContext = context;
+ mISyncAdapterImpl = new ISyncAdapterImpl();
+ mNumSyncStarts = new AtomicInteger(0);
+ mSyncThread = null;
+ mAutoInitialize = autoInitialize;
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ class ISyncAdapterImpl extends ISyncAdapter.Stub {
+ public void startSync(ISyncContext syncContext, String authority, Account account,
+ Bundle extras) {
+ final SyncContext syncContextClient = new SyncContext(syncContext);
+
+ boolean alreadyInProgress;
+ // synchronize to make sure that mSyncThread doesn't change between when we
+ // check it and when we use it
+ synchronized (mSyncThreadLock) {
+ if (mSyncThread == null) {
+ if (mAutoInitialize
+ && extras != null
+ && extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) {
+ if (ContentResolver.getIsSyncable(account, authority) < 0) {
+ ContentResolver.setIsSyncable(account, authority, 1);
+ }
+ syncContextClient.onFinished(new SyncResult());
+ return;
+ }
+ mSyncThread = new SyncThread(
+ "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(),
+ syncContextClient, authority, account, extras);
+ mSyncThread.start();
+ alreadyInProgress = false;
+ } else {
+ alreadyInProgress = true;
+ }
+ }
+
+ // do this outside since we don't want to call back into the syncContext while
+ // holding the synchronization lock
+ if (alreadyInProgress) {
+ syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS);
+ }
+ }
+
+ public void cancelSync(ISyncContext syncContext) {
+ // synchronize to make sure that mSyncThread doesn't change between when we
+ // check it and when we use it
+ synchronized (mSyncThreadLock) {
+ if (mSyncThread != null
+ && mSyncThread.mSyncContext.getISyncContext().asBinder()
+ == syncContext.asBinder()) {
+ mSyncThread.interrupt();
+ }
+ }
+ }
+ }
+
+ /**
+ * The thread that invokes performSync(). It also acquires the provider for this sync
+ * before calling performSync and releases it afterwards. Cancel this thread in order to
+ * cancel the sync.
+ */
+ private class SyncThread extends Thread {
+ private final SyncContext mSyncContext;
+ private final String mAuthority;
+ private final Account mAccount;
+ private final Bundle mExtras;
+
+ private SyncThread(String name, SyncContext syncContext, String authority,
+ Account account, Bundle extras) {
+ super(name);
+ mSyncContext = syncContext;
+ mAuthority = authority;
+ mAccount = account;
+ mExtras = extras;
+ }
+
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+
+ if (isCanceled()) {
+ return;
+ }
+
+ SyncResult syncResult = new SyncResult();
+ ContentProviderClient provider = null;
+ try {
+ provider = mContext.getContentResolver().acquireContentProviderClient(mAuthority);
+ if (provider != null) {
+ AbstractThreadedSyncAdapter.this.performSync(mAccount, mExtras,
+ mAuthority, provider, syncResult);
+ } else {
+ // TODO(fredq) update the syncResults to indicate that we were unable to
+ // find the provider. maybe with a ProviderError?
+ }
+ } finally {
+ if (provider != null) {
+ provider.release();
+ }
+ if (!isCanceled()) {
+ mSyncContext.onFinished(syncResult);
+ }
+ // synchronize so that the assignment will be seen by other threads
+ // that also synchronize accesses to mSyncThread
+ synchronized (mSyncThreadLock) {
+ mSyncThread = null;
+ }
+ }
+ }
+
+ private boolean isCanceled() {
+ return Thread.currentThread().isInterrupted();
+ }
+ }
+
+ /**
+ * @return a reference to the ISyncAdapter interface into this SyncAdapter implementation.
+ */
+ public final ISyncAdapter getISyncAdapter() {
+ return mISyncAdapterImpl;
+ }
+
+ /**
+ * 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
+ * @param authority the authority of this sync request
+ * @param provider a ContentProviderClient that points to the ContentProvider for this
+ * authority
+ * @param syncResult SyncAdapter-specific parameters
+ */
+ public abstract void performSync(Account account, Bundle extras,
+ String authority, ContentProviderClient provider, SyncResult syncResult);
+} \ No newline at end of file
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/AsyncQueryHandler.java b/core/java/android/content/AsyncQueryHandler.java
index ac851cc..5e88de0 100644
--- a/core/java/android/content/AsyncQueryHandler.java
+++ b/core/java/android/content/AsyncQueryHandler.java
@@ -38,7 +38,8 @@ public abstract class AsyncQueryHandler extends Handler {
private static final int EVENT_ARG_INSERT = 2;
private static final int EVENT_ARG_UPDATE = 3;
private static final int EVENT_ARG_DELETE = 4;
-
+ private static final int EVENT_ARG_QUERY_ENTITIES = 5;
+
/* package */ final WeakReference<ContentResolver> mResolver;
private static Looper sLooper = null;
@@ -85,12 +86,25 @@ public abstract class AsyncQueryHandler extends Handler {
cursor.getCount();
}
} catch (Exception e) {
+ Log.w(TAG, e.toString());
cursor = null;
}
args.result = cursor;
break;
+ case EVENT_ARG_QUERY_ENTITIES:
+ EntityIterator iterator = null;
+ try {
+ iterator = resolver.queryEntities(args.uri, args.selection,
+ args.selectionArgs, args.orderBy);
+ } catch (Exception e) {
+ Log.w(TAG, e.toString());
+ }
+
+ args.result = iterator;
+ break;
+
case EVENT_ARG_INSERT:
args.result = resolver.insert(args.uri, args.values);
break;
@@ -103,7 +117,6 @@ public abstract class AsyncQueryHandler extends Handler {
case EVENT_ARG_DELETE:
args.result = resolver.delete(args.uri, args.selection, args.selectionArgs);
break;
-
}
// passing the original token value back to the caller
@@ -128,7 +141,7 @@ public abstract class AsyncQueryHandler extends Handler {
if (sLooper == null) {
HandlerThread thread = new HandlerThread("AsyncQueryWorker");
thread.start();
-
+
sLooper = thread.getLooper();
}
}
@@ -182,6 +195,44 @@ public abstract class AsyncQueryHandler extends Handler {
}
/**
+ * This method begins an asynchronous query for an {@link EntityIterator}.
+ * When the query is done {@link #onQueryEntitiesComplete} is called.
+ *
+ * @param token A token passed into {@link #onQueryComplete} to identify the
+ * query.
+ * @param cookie An object that gets passed into {@link #onQueryComplete}
+ * @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 orderBy 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.
+ */
+ public void startQueryEntities(int token, Object cookie, Uri uri, String selection,
+ String[] selectionArgs, String orderBy) {
+ // Use the token as what so cancelOperations works properly
+ Message msg = mWorkerThreadHandler.obtainMessage(token);
+ msg.arg1 = EVENT_ARG_QUERY_ENTITIES;
+
+ WorkerArgs args = new WorkerArgs();
+ args.handler = this;
+ args.uri = uri;
+ args.selection = selection;
+ args.selectionArgs = selectionArgs;
+ args.orderBy = orderBy;
+ args.cookie = cookie;
+ msg.obj = args;
+
+ mWorkerThreadHandler.sendMessage(msg);
+ }
+
+ /**
* Attempts to cancel operation that has not already started. Note that
* there is no guarantee that the operation will be canceled. They still may
* result in a call to on[Query/Insert/Update/Delete]Complete after this
@@ -279,8 +330,8 @@ public abstract class AsyncQueryHandler extends Handler {
* Called when an asynchronous query is completed.
*
* @param token the token to identify the query, passed in from
- * {@link #startQuery}.
- * @param cookie the cookie object that's passed in from {@link #startQuery}.
+ * {@link #startQuery}.
+ * @param cookie the cookie object passed in from {@link #startQuery}.
* @param cursor The cursor holding the results from the query.
*/
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
@@ -288,6 +339,17 @@ public abstract class AsyncQueryHandler extends Handler {
}
/**
+ * Called when an asynchronous query is completed.
+ *
+ * @param token The token to identify the query.
+ * @param cookie The cookie object.
+ * @param iterator The iterator holding the query results.
+ */
+ protected void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
+ // Empty
+ }
+
+ /**
* Called when an asynchronous insert is completed.
*
* @param token the token to identify the query, passed in from
@@ -337,13 +399,17 @@ public abstract class AsyncQueryHandler extends Handler {
int token = msg.what;
int event = msg.arg1;
-
+
// pass token back to caller on each callback.
switch (event) {
case EVENT_ARG_QUERY:
onQueryComplete(token, args.cookie, (Cursor) args.result);
break;
+ case EVENT_ARG_QUERY_ENTITIES:
+ onQueryEntitiesComplete(token, args.cookie, (EntityIterator)args.result);
+ break;
+
case EVENT_ARG_INSERT:
onInsertComplete(token, args.cookie, (Uri) args.result);
break;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 6b50405..5b29b97 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -34,6 +34,7 @@ import android.os.Process;
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) {
+ enforceReadPermission(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) {
+ enforceWritePermission(uri);
+ return ContentProvider.this.insertEntity(uri, entities);
+ }
+
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ throws OperationApplicationException {
+ for (ContentProviderOperation operation : operations) {
+ if (operation.isReadOperation()) {
+ enforceReadPermission(operation.getUri());
+ }
+
+ if (operation.isWriteOperation()) {
+ enforceWritePermission(operation.getUri());
+ }
+ }
+ return ContentProvider.this.applyBatch(operations);
+ }
+
public int delete(Uri uri, String selection, String[] selectionArgs) {
enforceWritePermission(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) {
+ enforceWritePermission(uri);
+ return ContentProvider.this.updateEntity(uri, entity);
+ }
+
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
@@ -170,12 +201,6 @@ public abstract class ContentProvider implements ComponentCallbacks {
return ContentProvider.this.openAssetFile(uri, mode);
}
- public ISyncAdapter getSyncAdapter() {
- enforceWritePermission(null);
- SyncAdapter sa = ContentProvider.this.getSyncAdapter();
- return sa != null ? sa.getISyncAdapter() : null;
- }
-
private void enforceReadPermission(Uri uri) {
final int uid = Binder.getCallingUid();
if (uid == mMyUid) {
@@ -377,9 +402,10 @@ public abstract class ContentProvider implements ComponentCallbacks {
* Example client call:<p>
* <pre>// Request a specific record.
* Cursor managedCursor = managedQuery(
- Contacts.People.CONTENT_URI.addId(2),
+ ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
projection, // Which columns to return.
null, // WHERE clause.
+ null, // WHERE clause value substitution
People.NAME + " ASC"); // Sort order.</pre>
* Example implementation:<p>
* <pre>// SQLiteQueryBuilder is a helper class that creates the
@@ -408,20 +434,28 @@ public abstract class ContentProvider implements ComponentCallbacks {
return c;</pre>
*
* @param uri The URI to query. This will be the full URI sent by the client;
- * if the client is requesting a specific record, the URI will end in a record number
- * that the implementation should parse and add to a WHERE or HAVING clause, specifying
- * that _id value.
+ * if the client is requesting a specific record, the URI will end in a record number
+ * that the implementation should parse and add to a WHERE or HAVING clause, specifying
+ * that _id value.
* @param projection The list of columns to put into the cursor. If
* null all columns are included.
* @param selection A selection criteria to apply when filtering rows.
* If null then all rows are included.
+ * @param selectionArgs You may include ?s in selection, which will be replaced by
+ * the values from selectionArgs, in order that they appear in the selection.
+ * The values will be bound as Strings.
* @param sortOrder How the rows in the cursor should be sorted.
- * If null then the provider is free to define the sort order.
+ * If null then the provider is free to define the sort order.
* @return a Cursor or null.
*/
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,
@@ -472,6 +506,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
@@ -516,6 +554,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
@@ -639,23 +681,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
*/
@@ -697,4 +722,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..e367ceb 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,29 @@ 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 reset() throws RemoteException {
+ mEntityIterator.reset();
+ }
+
+ public void close() throws RemoteException {
+ mEntityIterator.close();
+ }
+ }
+
public IBinder asBinder()
{
return this;
@@ -297,7 +363,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 +371,58 @@ 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 reset() throws RemoteException {
+ mEntityIterator.reset();
+ }
+
+ 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 +484,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 +634,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..238792b
--- /dev/null
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -0,0 +1,561 @@
+/*
+ * 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.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ContentProviderOperation implements Parcelable {
+ /** @hide exposed for unit tests */
+ public final static int TYPE_INSERT = 1;
+ /** @hide exposed for unit tests */
+ public final static int TYPE_UPDATE = 2;
+ /** @hide exposed for unit tests */
+ public final static int TYPE_DELETE = 3;
+ /** @hide exposed for unit tests */
+ public final static int TYPE_ASSERT = 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 final boolean mYieldAllowed;
+
+ /**
+ * 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;
+ mYieldAllowed = builder.mYieldAllowed;
+ }
+
+ 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());
+ }
+ }
+ mYieldAllowed = source.readInt() != 0;
+ }
+
+ 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);
+ }
+ dest.writeInt(mYieldAllowed ? 1 : 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
+ * {@link ContentProviderOperation} to assert a set of values as provided
+ * through {@link Builder#withValues(ContentValues)}.
+ */
+ public static Builder newAssertQuery(Uri uri) {
+ return new Builder(TYPE_ASSERT, uri);
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ public boolean isYieldAllowed() {
+ return mYieldAllowed;
+ }
+
+ /** @hide exposed for unit tests */
+ public int getType() {
+ return mType;
+ }
+
+ public boolean isWriteOperation() {
+ return mType == TYPE_DELETE || mType == TYPE_INSERT || mType == TYPE_UPDATE;
+ }
+
+ public boolean isReadOperation() {
+ return mType == TYPE_ASSERT;
+ }
+
+ /**
+ * 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_ASSERT) {
+ // Build projection map from expected values
+ final ArrayList<String> projectionList = new ArrayList<String>();
+ for (Map.Entry<String, Object> entry : values.valueSet()) {
+ projectionList.add(entry.getKey());
+ }
+
+ // Assert that all rows match expected values
+ final String[] projection = projectionList.toArray(new String[projectionList.size()]);
+ final Cursor cursor = provider.query(mUri, projection, mSelection, selectionArgs, null);
+ numRows = cursor.getCount();
+ try {
+ while (cursor.moveToNext()) {
+ for (int i = 0; i < projection.length; i++) {
+ final String cursorValue = cursor.getString(i);
+ final String expectedValue = values.getAsString(projection[i]);
+ if (!TextUtils.equals(cursorValue, expectedValue)) {
+ // Throw exception when expected values don't match
+ throw new OperationApplicationException("Found value " + cursorValue
+ + " when expected " + expectedValue + " for column "
+ + projection[i]);
+ }
+ }
+ }
+ } 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] =
+ String.valueOf(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 long 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];
+ long backRefValue;
+ if (backRef.uri != null) {
+ backRefValue = ContentUris.parseId(backRef.uri);
+ } else {
+ backRefValue = 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#newAssertQuery(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;
+ private boolean mYieldAllowed;
+
+ /** 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() {
+ if (mType == TYPE_UPDATE || mType == TYPE_ASSERT) {
+ if ((mValues == null || mValues.size() == 0)
+ && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)) {
+ throw new IllegalArgumentException("Empty values");
+ }
+ }
+ 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, update, or assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValueBackReferences(ContentValues backReferences) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException(
+ "only inserts, updates, and asserts 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, update, or assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValueBackReference(String key, int previousResult) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException(
+ "only inserts, updates, and asserts 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 assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withSelectionBackReference(int selectionArgIndex, int previousResult) {
+ if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException("only updates, deletes, and asserts "
+ + "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, update, or assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withValues(ContentValues values) {
+ if (mType != TYPE_INSERT && mType != TYPE_UPDATE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException(
+ "only inserts, updates, and asserts 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, update, or assert.
+ * @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 && mType != TYPE_ASSERT) {
+ 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 assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withSelection(String selection, String[] selectionArgs) {
+ if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException(
+ "only updates, deletes, and asserts 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 assert.
+ * @return this builder, to allow for chaining.
+ */
+ public Builder withExpectedCount(int count) {
+ if (mType != TYPE_UPDATE && mType != TYPE_DELETE && mType != TYPE_ASSERT) {
+ throw new IllegalArgumentException(
+ "only updates, deletes, and asserts can have expected counts");
+ }
+ mExpectedCount = count;
+ return this;
+ }
+
+ public Builder withYieldAllowed(boolean yieldAllowed) {
+ mYieldAllowed = yieldAllowed;
+ 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..88a4d02 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,19 +41,40 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
+import java.util.ArrayList;
/**
* This class provides applications access to the content model.
*/
public abstract class ContentResolver {
- public final static String SYNC_EXTRAS_ACCOUNT = "account";
+ /**
+ * @deprecated instead use
+ * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
+ */
+ @Deprecated
+ public static final String SYNC_EXTRAS_ACCOUNT = "account";
public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
+ /**
+ * @deprecated instead use
+ * {@link #SYNC_EXTRAS_MANUAL}
+ */
+ @Deprecated
public static final String SYNC_EXTRAS_FORCE = "force";
+ public static final String SYNC_EXTRAS_MANUAL = "force";
public static final String SYNC_EXTRAS_UPLOAD = "upload";
public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
+ /**
+ * Set by the SyncManager to request that the SyncAdapter initialize itself for
+ * the given account/authority pair. One required initialization step is to
+ * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been
+ * called with a >= 0 value. When this flag is set the SyncAdapter does not need to
+ * do a full sync, though it is allowed to do so.
+ */
+ public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
+
public static final String SCHEME_CONTENT = "content";
public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
public static final String SCHEME_FILE = "file";
@@ -88,7 +110,35 @@ public abstract class ContentResolver {
* in the cursor is the same.
*/
public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
-
+
+ /** @hide */
+ public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
+ /** @hide */
+ public static final int SYNC_ERROR_AUTHENTICATION = 2;
+ /** @hide */
+ public static final int SYNC_ERROR_IO = 3;
+ /** @hide */
+ public static final int SYNC_ERROR_PARSE = 4;
+ /** @hide */
+ public static final int SYNC_ERROR_CONFLICT = 5;
+ /** @hide */
+ public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
+ /** @hide */
+ public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
+ /** @hide */
+ public static final int SYNC_ERROR_INTERNAL = 8;
+
+ /** @hide */
+ public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0;
+ /** @hide */
+ public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1;
+ /** @hide */
+ public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2;
+ /** @hide */
+ public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3;
+ /** @hide */
+ public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
+
public ContentResolver(Context context) {
mContext = context;
}
@@ -166,6 +216,94 @@ 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 reset() throws RemoteException {
+ if (mClientReleased) {
+ throw new IllegalStateException("this iterator is already closed");
+ }
+ mInner.reset();
+ }
+
+ 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 +623,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 +760,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.
*
@@ -676,11 +884,43 @@ public abstract class ContentResolver {
*
* @param uri the uri of the provider to sync or null to sync all providers.
* @param extras any extras to pass to the SyncAdapter.
+ * @deprecated instead use
+ * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
*/
+ @Deprecated
public void startSync(Uri uri, Bundle extras) {
+ Account account = null;
+ if (extras != null) {
+ String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
+ if (!TextUtils.isEmpty(accountName)) {
+ account = new Account(accountName, "com.google.GAIA");
+ }
+ extras.remove(SYNC_EXTRAS_ACCOUNT);
+ }
+ requestSync(account, uri != null ? uri.getAuthority() : null, extras);
+ }
+
+ /**
+ * Start an asynchronous sync operation. If you want to monitor the progress
+ * of the sync you may register a SyncObserver. Only values of the following
+ * types may be used in the extras bundle:
+ * <ul>
+ * <li>Integer</li>
+ * <li>Long</li>
+ * <li>Boolean</li>
+ * <li>Float</li>
+ * <li>Double</li>
+ * <li>String</li>
+ * </ul>
+ *
+ * @param account which account should be synced
+ * @param authority which authority should be synced
+ * @param extras any extras to pass to the SyncAdapter.
+ */
+ public static void requestSync(Account account, String authority, Bundle extras) {
validateSyncExtrasBundle(extras);
try {
- getContentService().startSync(uri, extras);
+ getContentService().requestSync(account, authority, extras);
} catch (RemoteException e) {
}
}
@@ -694,6 +934,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 +950,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());
}
@@ -719,13 +961,211 @@ public abstract class ContentResolver {
}
}
+ /**
+ * Cancel any active or pending syncs that match the Uri. If the uri is null then
+ * all syncs will be canceled.
+ *
+ * @param uri the uri of the provider to sync or null to sync all providers.
+ * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
+ */
+ @Deprecated
public void cancelSync(Uri uri) {
+ cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
+ }
+
+ /**
+ * Cancel any active or pending syncs that match account and authority. The account and
+ * authority can each independently be set to null, which means that syncs with any account
+ * or authority, respectively, will match.
+ *
+ * @param account filters the syncs that match by this account
+ * @param authority filters the syncs that match by this authority
+ */
+ public static void cancelSync(Account account, String authority) {
+ try {
+ getContentService().cancelSync(account, authority);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Get information about the SyncAdapters that are known to the system.
+ * @return an array of SyncAdapters that have registered with the system
+ */
+ public static SyncAdapterType[] getSyncAdapterTypes() {
+ try {
+ return getContentService().getSyncAdapterTypes();
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Check if the provider should be synced when a network tickle is received
+ *
+ * @param account the account whose setting we are querying
+ * @param authority the provider whose setting we are querying
+ * @return true if the provider should be synced when a network tickle is received
+ */
+ public static boolean getSyncAutomatically(Account account, String authority) {
+ try {
+ return getContentService().getSyncAutomatically(account, authority);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Set whether or not the provider is synced when it receives a network tickle.
+ *
+ * @param account the account whose setting we are querying
+ * @param authority the provider whose behavior is being controlled
+ * @param sync true if the provider should be synced when tickles are received for it
+ */
+ public static void setSyncAutomatically(Account account, String authority, boolean sync) {
+ try {
+ getContentService().setSyncAutomatically(account, authority, sync);
+ } catch (RemoteException e) {
+ // exception ignored; if this is thrown then it means the runtime is in the midst of
+ // being restarted
+ }
+ }
+
+ /**
+ * Check if this account/provider is syncable.
+ * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
+ */
+ public static int getIsSyncable(Account account, String authority) {
+ try {
+ return getContentService().getIsSyncable(account, authority);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Set whether this account/provider is syncable.
+ * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown
+ */
+ public static void setIsSyncable(Account account, String authority, int syncable) {
+ try {
+ getContentService().setIsSyncable(account, authority, syncable);
+ } catch (RemoteException e) {
+ // exception ignored; if this is thrown then it means the runtime is in the midst of
+ // being restarted
+ }
+ }
+
+ /**
+ * Gets the master auto-sync setting that applies to all the providers and accounts.
+ * If this is false then the per-provider auto-sync setting is ignored.
+ *
+ * @return the master auto-sync setting that applies to all the providers and accounts
+ */
+ public static boolean getMasterSyncAutomatically() {
+ try {
+ return getContentService().getMasterSyncAutomatically();
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Sets the master auto-sync setting that applies to all the providers and accounts.
+ * If this is false then the per-provider auto-sync setting is ignored.
+ *
+ * @param sync the master auto-sync setting that applies to all the providers and accounts
+ */
+ public static void setMasterSyncAutomatically(boolean sync) {
+ try {
+ getContentService().setMasterSyncAutomatically(sync);
+ } catch (RemoteException e) {
+ // exception ignored; if this is thrown then it means the runtime is in the midst of
+ // being restarted
+ }
+ }
+
+ /**
+ * Returns true if there is currently a sync operation for the given
+ * account or authority in the pending list, or actively being processed.
+ * @param account the account whose setting we are querying
+ * @param authority the provider whose behavior is being queried
+ * @return true if a sync is active for the given account or authority.
+ */
+ public static boolean isSyncActive(Account account, String authority) {
+ try {
+ return getContentService().isSyncActive(account, authority);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * If a sync is active returns the information about it, otherwise returns false.
+ * @return the ActiveSyncInfo for the currently active sync or null if one is not active.
+ * @hide
+ */
+ public static ActiveSyncInfo getActiveSync() {
try {
- getContentService().cancelSync(uri);
+ return getContentService().getActiveSync();
} catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
}
}
+ /**
+ * Returns the status that matches the authority.
+ * @param account the account whose setting we are querying
+ * @param authority the provider whose behavior is being queried
+ * @return the SyncStatusInfo for the authority, or null if none exists
+ * @hide
+ */
+ public static SyncStatusInfo getSyncStatus(Account account, String authority) {
+ try {
+ return getContentService().getSyncStatus(account, authority);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ /**
+ * Return true if the pending status is true of any matching authorities.
+ * @param account the account whose setting we are querying
+ * @param authority the provider whose behavior is being queried
+ * @return true if there is a pending sync with the matching account and authority
+ */
+ public static boolean isSyncPending(Account account, String authority) {
+ try {
+ return getContentService().isSyncPending(account, authority);
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) {
+ try {
+ ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() {
+ public void onStatusChanged(int which) throws RemoteException {
+ callback.onStatusChanged(which);
+ }
+ };
+ getContentService().addStatusChangeListener(mask, observer);
+ return observer;
+ } catch (RemoteException e) {
+ throw new RuntimeException("the ContentService should always be reachable", e);
+ }
+ }
+
+ public static void removeStatusChangeListener(Object handle) {
+ try {
+ getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle);
+ } catch (RemoteException e) {
+ // exception ignored; if this is thrown then it means the runtime is in the midst of
+ // being restarted
+ }
+ }
+
+
private final class CursorWrapperInner extends CursorWrapper {
private IContentProvider mContentProvider;
public static final String TAG="CursorWrapperInner";
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 6cd2c54..f742448 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;
@@ -160,7 +161,9 @@ public final class ContentService extends IContentService.Stub {
}
if (syncToNetwork) {
SyncManager syncManager = getSyncManager();
- if (syncManager != null) syncManager.scheduleLocalSync(uri);
+ if (syncManager != null) {
+ syncManager.scheduleLocalSync(null /* all accounts */, uri.getAuthority());
+ }
}
} finally {
restoreCallingIdentity(identityToken);
@@ -186,14 +189,17 @@ public final class ContentService extends IContentService.Stub {
}
}
- public void startSync(Uri url, Bundle extras) {
+ public void requestSync(Account account, String authority, Bundle extras) {
ContentResolver.validateSyncExtrasBundle(extras);
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- if (syncManager != null) syncManager.startSync(url, extras);
+ if (syncManager != null) {
+ syncManager.scheduleSync(account, authority, extras, 0 /* no delay */,
+ false /* onlyThoseWithUnkownSyncableState */);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
@@ -201,34 +207,50 @@ public final class ContentService extends IContentService.Stub {
/**
* Clear all scheduled sync operations that match the uri and cancel the active sync
- * if it matches the uri. If the uri is null, clear all scheduled syncs and cancel
- * the active one, if there is one.
- * @param uri Filter on the sync operations to cancel, or all if null.
+ * if they match the authority and account, if they are present.
+ * @param account filter the pending and active syncs to cancel using this account
+ * @param authority filter the pending and active syncs to cancel using this authority
*/
- public void cancelSync(Uri uri) {
+ public void cancelSync(Account account, String authority) {
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.clearScheduledSyncOperations(uri);
- syncManager.cancelActiveSync(uri);
+ syncManager.clearScheduledSyncOperations(account, authority);
+ syncManager.cancelActiveSync(account, authority);
}
} finally {
restoreCallingIdentity(identityToken);
}
}
- public boolean getSyncProviderAutomatically(String providerName) {
+ /**
+ * Get information about the SyncAdapters that are known to the system.
+ * @return an array of SyncAdapters that have registered with the system
+ */
+ public SyncAdapterType[] getSyncAdapterTypes() {
+ // This makes it so that future permission checks will be in the context of this
+ // process rather than the caller's process. We will restore this before returning.
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ return syncManager.getSyncAdapterTypes();
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public boolean getSyncAutomatically(Account account, String providerName) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- return syncManager.getSyncStorageEngine().getSyncProviderAutomatically(
- null, providerName);
+ return syncManager.getSyncStorageEngine().getSyncAutomatically(
+ account, providerName);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -236,29 +258,60 @@ public final class ContentService extends IContentService.Stub {
return false;
}
- public void setSyncProviderAutomatically(String providerName, boolean sync) {
+ public void setSyncAutomatically(Account account, String providerName, boolean sync) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
+ "no permission to write the sync settings");
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ syncManager.getSyncStorageEngine().setSyncAutomatically(
+ account, providerName, sync);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public int getIsSyncable(Account account, String providerName) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
+ "no permission to read the sync settings");
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ return syncManager.getSyncStorageEngine().getIsSyncable(
+ account, providerName);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ return -1;
+ }
+
+ public void setIsSyncable(Account account, String providerName, int syncable) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.getSyncStorageEngine().setSyncProviderAutomatically(
- null, providerName, sync);
+ syncManager.getSyncStorageEngine().setIsSyncable(
+ account, providerName, syncable);
}
} finally {
restoreCallingIdentity(identityToken);
}
}
- public boolean getListenForNetworkTickles() {
+ public boolean getMasterSyncAutomatically() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- return syncManager.getSyncStorageEngine().getListenForNetworkTickles();
+ return syncManager.getSyncStorageEngine().getMasterSyncAutomatically();
}
} finally {
restoreCallingIdentity(identityToken);
@@ -266,21 +319,21 @@ public final class ContentService extends IContentService.Stub {
return false;
}
- public void setListenForNetworkTickles(boolean flag) {
+ public void setMasterSyncAutomatically(boolean flag) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.getSyncStorageEngine().setListenForNetworkTickles(flag);
+ syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag);
}
} finally {
restoreCallingIdentity(identityToken);
}
}
- 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();
@@ -311,7 +364,7 @@ public final class ContentService extends IContentService.Stub {
return null;
}
- public SyncStatusInfo getStatusByAuthority(String authority) {
+ public SyncStatusInfo getSyncStatus(Account account, String authority) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
long identityToken = clearCallingIdentity();
@@ -327,15 +380,14 @@ public final class ContentService extends IContentService.Stub {
return null;
}
- public boolean isAuthorityPending(String account, String authority) {
+ public boolean isSyncPending(Account account, String authority) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- return syncManager.getSyncStorageEngine().isAuthorityPending(
- account, authority);
+ return syncManager.getSyncStorageEngine().isSyncPending(account, authority);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -348,8 +400,7 @@ public final class ContentService extends IContentService.Stub {
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.getSyncStorageEngine().addStatusChangeListener(
- mask, callback);
+ syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -361,8 +412,7 @@ public final class ContentService extends IContentService.Stub {
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.getSyncStorageEngine().removeStatusChangeListener(
- callback);
+ syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
}
} finally {
restoreCallingIdentity(identityToken);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 25b5de3..60551b8 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -488,90 +488,52 @@ public abstract class Context {
public abstract String[] databaseList();
/**
- * Like {@link #peekWallpaper}, but always returns a valid Drawable. If
- * no wallpaper is set, the system default wallpaper is returned.
- *
- * @return Returns a Drawable object that will draw the wallpaper.
+ * @deprecated Use {@link android.app.WallpaperManager#getDrawable
+ * WallpaperManager.get()} instead.
*/
+ @Deprecated
public abstract Drawable getWallpaper();
/**
- * Retrieve the current system wallpaper. This is returned as an
- * abstract Drawable that you can install in a View to display whatever
- * wallpaper the user has currently set. If there is no wallpaper set,
- * a null pointer is returned.
- *
- * @return Returns a Drawable object that will draw the wallpaper or a
- * null pointer if these is none.
+ * @deprecated Use {@link android.app.WallpaperManager#peekDrawable
+ * WallpaperManager.peek()} instead.
*/
+ @Deprecated
public abstract Drawable peekWallpaper();
/**
- * Returns the desired minimum width for the wallpaper. Callers of
- * {@link #setWallpaper(android.graphics.Bitmap)} or
- * {@link #setWallpaper(java.io.InputStream)} should check this value
- * beforehand to make sure the supplied wallpaper respects the desired
- * minimum width.
- *
- * If the returned value is <= 0, the caller should use the width of
- * the default display instead.
- *
- * @return The desired minimum width for the wallpaper. This value should
- * be honored by applications that set the wallpaper but it is not
- * mandatory.
+ * @deprecated Use {@link android.app.WallpaperManager#getDesiredMinimumWidth()
+ * WallpaperManager.getDesiredMinimumWidth()} instead.
*/
+ @Deprecated
public abstract int getWallpaperDesiredMinimumWidth();
/**
- * Returns the desired minimum height for the wallpaper. Callers of
- * {@link #setWallpaper(android.graphics.Bitmap)} or
- * {@link #setWallpaper(java.io.InputStream)} should check this value
- * beforehand to make sure the supplied wallpaper respects the desired
- * minimum height.
- *
- * If the returned value is <= 0, the caller should use the height of
- * the default display instead.
- *
- * @return The desired minimum height for the wallpaper. This value should
- * be honored by applications that set the wallpaper but it is not
- * mandatory.
+ * @deprecated Use {@link android.app.WallpaperManager#getDesiredMinimumHeight()
+ * WallpaperManager.getDesiredMinimumHeight()} instead.
*/
+ @Deprecated
public abstract int getWallpaperDesiredMinimumHeight();
/**
- * Change the current system wallpaper to a bitmap. The given bitmap is
- * converted to a PNG and stored as the wallpaper. On success, the intent
- * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
- *
- * @param bitmap The bitmap to save.
- *
- * @throws IOException If an error occurs reverting to the default
- * wallpaper.
+ * @deprecated Use {@link android.app.WallpaperManager#setBitmap(Bitmap)
+ * WallpaperManager.set()} instead.
*/
+ @Deprecated
public abstract void setWallpaper(Bitmap bitmap) throws IOException;
/**
- * Change the current system wallpaper to a specific byte stream. The
- * give InputStream is copied into persistent storage and will now be
- * used as the wallpaper. Currently it must be either a JPEG or PNG
- * image. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
- * is broadcast.
- *
- * @param data A stream containing the raw data to install as a wallpaper.
- *
- * @throws IOException If an error occurs reverting to the default
- * wallpaper.
+ * @deprecated Use {@link android.app.WallpaperManager#setStream(InputStream)
+ * WallpaperManager.set()} instead.
*/
+ @Deprecated
public abstract void setWallpaper(InputStream data) throws IOException;
/**
- * Remove any currently set wallpaper, reverting to the system's default
- * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
- * is broadcast.
- *
- * @throws IOException If an error occurs reverting to the default
- * wallpaper.
+ * @deprecated Use {@link android.app.WallpaperManager#clear
+ * WallpaperManager.clear()} instead.
*/
+ @Deprecated
public abstract void clearWallpaper() throws IOException;
/**
@@ -1110,6 +1072,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.
*
@@ -1179,11 +1151,10 @@ public abstract class Context {
public static final String SENSOR_SERVICE = "sensor";
/**
* Use with {@link #getSystemService} to retrieve a {@link
- * android.bluetooth.BluetoothDevice} for interacting with Bluetooth.
+ * android.bluetooth.BluetoothAdapter} for using Bluetooth.
*
* @see #getSystemService
- * @see android.bluetooth.BluetoothDevice
- * @hide
+ * @see android.bluetooth.BluetoothAdapter
*/
public static final String BLUETOOTH_SERVICE = "bluetooth";
/**
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..3cc1040
--- /dev/null
+++ b/core/java/android/content/EntityIterator.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+ public void reset() 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..b0f14c1 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -16,8 +16,10 @@
package android.content;
+import android.accounts.Account;
import android.content.ActiveSyncInfo;
import android.content.ISyncStatusObserver;
+import android.content.SyncAdapterType;
import android.content.SyncStatusInfo;
import android.net.Uri;
import android.os.Bundle;
@@ -34,15 +36,15 @@ interface IContentService {
void notifyChange(in Uri uri, IContentObserver observer,
boolean observerWantsSelfNotifications, boolean syncToNetwork);
- void startSync(in Uri url, in Bundle extras);
- void cancelSync(in Uri uri);
+ void requestSync(in Account account, String authority, in Bundle extras);
+ void cancelSync(in Account account, String authority);
/**
* 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
*/
- boolean getSyncProviderAutomatically(String providerName);
+ boolean getSyncAutomatically(in Account account, String providerName);
/**
* Set whether or not the provider is synced when it receives a network tickle.
@@ -50,32 +52,50 @@ interface IContentService {
* @param providerName the provider whose behavior is being controlled
* @param sync true if the provider should be synced when tickles are received for it
*/
- void setSyncProviderAutomatically(String providerName, boolean sync);
+ void setSyncAutomatically(in Account account, String providerName, boolean sync);
- void setListenForNetworkTickles(boolean flag);
+ /**
+ * Check if this account/provider is syncable.
+ * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
+ */
+ int getIsSyncable(in Account account, String providerName);
+
+ /**
+ * Set whether this account/provider is syncable.
+ * @param syncable, >0 denotes syncable, 0 means not syncable, <0 means unknown
+ */
+ void setIsSyncable(in Account account, String providerName, int syncable);
- boolean getListenForNetworkTickles();
+ void setMasterSyncAutomatically(boolean flag);
+
+ boolean getMasterSyncAutomatically();
/**
* 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();
/**
+ * Returns the types of the SyncAdapters that are registered with the system.
+ * @return Returns the types of the SyncAdapters that are registered with the system.
+ */
+ SyncAdapterType[] getSyncAdapterTypes();
+
+ /**
* Returns the status that matches the authority. If there are multiples accounts for
* the authority, the one with the latest "lastSuccessTime" status is returned.
* @param authority the authority whose row should be selected
* @return the SyncStatusInfo for the authority, or null if none exists
*/
- SyncStatusInfo getStatusByAuthority(String authority);
+ SyncStatusInfo getSyncStatus(in Account account, String authority);
/**
* Return true if the pending status is true of any matching authorities.
*/
- boolean isAuthorityPending(String account, String authority);
+ boolean isSyncPending(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..068581e
--- /dev/null
+++ b/core/java/android/content/IEntityIterator.java
@@ -0,0 +1,210 @@
+/*
+ * 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_reset:
+ {
+ data.enforceInterface(DESCRIPTOR);
+ try {
+ this.reset();
+ } catch (RemoteException e) {
+ Log.e(TAG, "caught exception in next()", e);
+ reply.writeException(e);
+ return true;
+ }
+ reply.writeNoException();
+ 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 reset() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_reset, _data, _reply, 0);
+ _reply.readException();
+ } 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);
+ static final int TRANSACTION_reset = (IBinder.FIRST_CALL_TRANSACTION + 3);
+ }
+ public boolean hasNext() throws RemoteException;
+ public Entity next() throws RemoteException;
+ public void reset() 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..4660527 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;
@@ -30,14 +31,17 @@ oneway interface ISyncAdapter {
*
* @param syncContext the ISyncContext used to indicate the progress of the sync. When
* the sync is finished (successfully or not) ISyncContext.onFinished() must be called.
+ * @param authority the authority that should be synced
* @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, String authority,
+ in Account account, in Bundle extras);
/**
* Cancel the most recently initiated sync. Due to race conditions, this may arrive
* after the ISyncContext.onFinished() for that sync was called.
+ * @param syncContext the ISyncContext that was passed to {@link #startSync}
*/
- void cancelSync();
+ void cancelSync(ISyncContext syncContext);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c62d66b..59529be 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -75,10 +75,10 @@ import java.util.Set;
* <p>Some examples of action/data pairs are:</p>
*
* <ul>
- * <li> <p><b>{@link #ACTION_VIEW} <i>content://contacts/1</i></b> -- Display
+ * <li> <p><b>{@link #ACTION_VIEW} <i>content://contacts/people/1</i></b> -- Display
* information about the person whose identifier is "1".</p>
* </li>
- * <li> <p><b>{@link #ACTION_DIAL} <i>content://contacts/1</i></b> -- Display
+ * <li> <p><b>{@link #ACTION_DIAL} <i>content://contacts/people/1</i></b> -- Display
* the phone dialer with the person filled in.</p>
* </li>
* <li> <p><b>{@link #ACTION_VIEW} <i>tel:123</i></b> -- Display
@@ -89,10 +89,10 @@ import java.util.Set;
* <li> <p><b>{@link #ACTION_DIAL} <i>tel:123</i></b> -- Display
* the phone dialer with the given number filled in.</p>
* </li>
- * <li> <p><b>{@link #ACTION_EDIT} <i>content://contacts/1</i></b> -- Edit
+ * <li> <p><b>{@link #ACTION_EDIT} <i>content://contacts/people/1</i></b> -- Edit
* information about the person whose identifier is "1".</p>
* </li>
- * <li> <p><b>{@link #ACTION_VIEW} <i>content://contacts/</i></b> -- Display
+ * <li> <p><b>{@link #ACTION_VIEW} <i>content://contacts/people/</i></b> -- Display
* a list of people, which the user can browse through. This example is a
* typical top-level entry into the Contacts application, showing you the
* list of people. Selecting a particular person to view would result in a
@@ -156,7 +156,7 @@ import java.util.Set;
* defined in the Intent class, but applications can also define their own.
* These strings use java style scoping, to ensure they are unique -- for
* example, the standard {@link #ACTION_VIEW} is called
- * "android.app.action.VIEW".</p>
+ * "android.intent.action.VIEW".</p>
*
* <p>Put together, the set of actions, data types, categories, and extra data
* defines a language for the system allowing for the expression of phrases
@@ -347,7 +347,7 @@ import java.util.Set;
* <li> <p><b>{ action=android.app.action.MAIN,
* category=android.app.category.LAUNCHER }</b> is the actual intent
* used by the Launcher to populate its top-level list.</p>
- * <li> <p><b>{ action=android.app.action.VIEW
+ * <li> <p><b>{ action=android.intent.action.VIEW
* data=content://com.google.provider.NotePad/notes }</b>
* displays a list of all the notes under
* "content://com.google.provider.NotePad/notes", which
@@ -399,7 +399,7 @@ import java.util.Set;
* NoteEditor activity:</p>
*
* <ul>
- * <li> <p><b>{ action=android.app.action.VIEW
+ * <li> <p><b>{ action=android.intent.action.VIEW
* data=content://com.google.provider.NotePad/notes/<var>{ID}</var> }</b>
* shows the user the content of note <var>{ID}</var>.</p>
* <li> <p><b>{ action=android.app.action.EDIT
@@ -1394,13 +1394,14 @@ public class Intent implements Parcelable {
* by the system.
*/
@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.ACTION_POWER_DISCONNECTED";
/**
* Broadcast Action: Device is shutting down.
* This is broadcast when the device is being shut down (completely turned
* off, not sleeping). Once the broadcast is complete, the final shutdown
* will proceed and all unsaved data lost. Apps will not normally need
- * to handle this, since the forground activity will be paused as well.
+ * to handle this, since the foreground activity will be paused as well.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
@@ -1408,6 +1409,17 @@ public class Intent implements Parcelable {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
/**
+ * Activity Action: Start this activity to request system shutdown.
+ * The optional boolean extra field {@link #EXTRA_KEY_CONFIRM} can be set to true
+ * to request confirmation from the user before shutting down.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ *
+ * {@hide}
+ */
+ public static final String ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";
+ /**
* Broadcast Action: Indicates low memory condition on the device
*
* <p class="note">This is a protected intent that can only be sent
@@ -1684,6 +1696,31 @@ 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";
+
+ /**
+ * Broadcast Action: hook for permforming cleanup after a system update.
+ *
+ * The broadcast is sent when the system is booting, before the
+ * BOOT_COMPLETED broadcast. It is only sent to receivers in the system
+ * image. A receiver for this should do its work and then disable itself
+ * so that it does not get run again at the next boot.
+ * @hide
+ */
+ public static final String ACTION_PRE_BOOT_COMPLETED =
+ "android.intent.action.PRE_BOOT_COMPLETED";
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
@@ -1812,6 +1849,14 @@ public class Intent implements Parcelable {
*/
public static final String CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST =
"android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST";
+
+ /**
+ * Broadcast Action: The phone was docked or undocked. Includes the extra
+ * field {@link #EXTRA_DOCK_STATE}, containing the current dock state.
+ * @hide
+ */
+ public static final String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard extra data keys.
@@ -1878,6 +1923,14 @@ public class Intent implements Parcelable {
public static final String EXTRA_KEY_EVENT = "android.intent.extra.KEY_EVENT";
/**
+ * Set to true in {@link #ACTION_REQUEST_SHUTDOWN} to request confirmation from the user
+ * before shutting down.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_KEY_CONFIRM = "android.intent.extra.KEY_CONFIRM";
+
+ /**
* Used as an boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED} or
* {@link android.content.Intent#ACTION_PACKAGE_CHANGED} intents to override the default action
* of restarting the application.
@@ -1926,6 +1979,37 @@ public class Intent implements Parcelable {
public static final String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
/**
+ * Used as an int extra field in {@link android.content.Intent#ACTION_DOCK_EVENT}
+ * intents to request the dock state. Possible values are
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED},
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or
+ * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}.
+ * @hide
+ */
+ public static final String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
+
+ /**
+ * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
+ * to represent that the phone is not in any dock.
+ * @hide
+ */
+ public static final int EXTRA_DOCK_STATE_UNDOCKED = 0;
+
+ /**
+ * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
+ * to represent that the phone is in a desk dock.
+ * @hide
+ */
+ public static final int EXTRA_DOCK_STATE_DESK = 1;
+
+ /**
+ * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
+ * to represent that the phone is in a car dock.
+ * @hide
+ */
+ public static final int EXTRA_DOCK_STATE_CAR = 2;
+
+ /**
* Used as a parcelable extra field in {@link #ACTION_APP_ERROR}, containing
* the bug report.
*
@@ -1943,6 +2027,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).
@@ -2037,12 +2128,14 @@ public class Intent implements Parcelable {
* of activity B, then C and D will be finished and B receive the given
* Intent, resulting in the stack now being: A, B.
*
- * <p>The currently running instance of task B in the above example will
+ * <p>The currently running instance of activity B in the above example will
* either receive the new intent you are starting here in its
* onNewIntent() method, or be itself finished and restarted with the
* new intent. If it has declared its launch mode to be "multiple" (the
- * default) it will be finished and re-created; for all other launch modes
- * it will receive the Intent in the current instance.
+ * default) and you have not set {@link #FLAG_ACTIVITY_SINGLE_TOP} in
+ * the same intent, then it will be finished and re-created; for all other
+ * launch modes or if {@link #FLAG_ACTIVITY_SINGLE_TOP} is set then this
+ * Intent will be delivered to the current instance's onNewIntent().
*
* <p>This launch mode can also be used to good effect in conjunction with
* {@link #FLAG_ACTIVITY_NEW_TASK}: if used to start the root activity
@@ -2171,6 +2264,13 @@ public class Intent implements Parcelable {
* @hide
*/
public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x20000000;
+ /**
+ * Set when this broadcast is for a boot upgrade, a special mode that
+ * allows the broadcast to be sent before the system is ready and launches
+ * the app process with no providers running in it.
+ * @hide
+ */
+ public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x10000000;
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
diff --git a/core/java/android/content/OperationApplicationException.java b/core/java/android/content/OperationApplicationException.java
new file mode 100644
index 0000000..2fc19bb
--- /dev/null
+++ b/core/java/android/content/OperationApplicationException.java
@@ -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.
+ */
+
+package android.content;
+
+/**
+ * Thrown when an application of a {@link ContentProviderOperation} fails due the specified
+ * constraints.
+ */
+public class OperationApplicationException extends Exception {
+ private final int mNumSuccessfulYieldPoints;
+
+ public OperationApplicationException() {
+ super();
+ mNumSuccessfulYieldPoints = 0;
+ }
+ public OperationApplicationException(String message) {
+ super(message);
+ mNumSuccessfulYieldPoints = 0;
+ }
+ public OperationApplicationException(String message, Throwable cause) {
+ super(message, cause);
+ mNumSuccessfulYieldPoints = 0;
+ }
+ public OperationApplicationException(Throwable cause) {
+ super(cause);
+ mNumSuccessfulYieldPoints = 0;
+ }
+ public OperationApplicationException(int numSuccessfulYieldPoints) {
+ super();
+ mNumSuccessfulYieldPoints = numSuccessfulYieldPoints;
+ }
+ public OperationApplicationException(String message, int numSuccessfulYieldPoints) {
+ super(message);
+ mNumSuccessfulYieldPoints = numSuccessfulYieldPoints;
+ }
+
+ public int getNumSuccessfulYieldPoints() {
+ return mNumSuccessfulYieldPoints;
+ }
+}
diff --git a/core/java/android/content/SyncAdapter.java b/core/java/android/content/SyncAdapter.java
index 7826e50..88dc332 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,12 +30,12 @@ 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, String authority, Account account,
Bundle extras) throws RemoteException {
- SyncAdapter.this.startSync(new SyncContext(syncContext), account, extras);
+ SyncAdapter.this.startSync(new SyncContext(syncContext), account, authority, extras);
}
- public void cancelSync() throws RemoteException {
+ public void cancelSync(ISyncContext syncContext) throws RemoteException {
SyncAdapter.this.cancelSync();
}
}
@@ -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;
}
@@ -57,9 +58,11 @@ public abstract class SyncAdapter {
* @param syncContext the ISyncContext used to indicate the progress of the sync. When
* the sync is finished (successfully or not) ISyncContext.onFinished() must be called.
* @param account the account that should be synced
+ * @param authority the authority if the sync request
* @param extras SyncAdapter-specific parameters
*/
- public abstract void startSync(SyncContext syncContext, String account, Bundle extras);
+ public abstract void startSync(SyncContext syncContext, Account account, String authority,
+ Bundle extras);
/**
* Cancel the most recently initiated sync. Due to race conditions, this may arrive
diff --git a/core/java/android/content/SyncAdapterType.aidl b/core/java/android/content/SyncAdapterType.aidl
new file mode 100644
index 0000000..e67841f
--- /dev/null
+++ b/core/java/android/content/SyncAdapterType.aidl
@@ -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.content;
+
+parcelable SyncAdapterType;
+
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
new file mode 100644
index 0000000..25cbdb1
--- /dev/null
+++ b/core/java/android/content/SyncAdapterType.java
@@ -0,0 +1,145 @@
+/*
+ * 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;
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * 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 implements Parcelable {
+ public final String authority;
+ public final String accountType;
+ public final boolean isKey;
+ private final boolean userVisible;
+ private final boolean supportsUploading;
+
+ public SyncAdapterType(String authority, String accountType, boolean userVisible,
+ boolean supportsUploading) {
+ 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;
+ this.userVisible = userVisible;
+ this.supportsUploading = supportsUploading;
+ this.isKey = false;
+ }
+
+ private 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;
+ this.userVisible = true;
+ this.supportsUploading = true;
+ this.isKey = true;
+ }
+
+ public boolean supportsUploading() {
+ if (isKey) {
+ throw new IllegalStateException(
+ "this method is not allowed to be called when this is a key");
+ }
+ return supportsUploading;
+ }
+
+ public boolean isUserVisible() {
+ if (isKey) {
+ throw new IllegalStateException(
+ "this method is not allowed to be called when this is a key");
+ }
+ return userVisible;
+ }
+
+ public static SyncAdapterType newKey(String authority, String accountType) {
+ return new SyncAdapterType(authority, accountType);
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof SyncAdapterType)) return false;
+ final SyncAdapterType other = (SyncAdapterType)o;
+ // don't include userVisible or supportsUploading in the equality check
+ 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();
+ // don't include userVisible or supportsUploading the hash
+ return result;
+ }
+
+ public String toString() {
+ if (isKey) {
+ return "SyncAdapterType Key {name=" + authority
+ + ", type=" + accountType
+ + "}";
+ } else {
+ return "SyncAdapterType {name=" + authority
+ + ", type=" + accountType
+ + ", userVisible=" + userVisible
+ + ", supportsUploading=" + supportsUploading
+ + "}";
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ if (isKey) {
+ throw new IllegalStateException("keys aren't parcelable");
+ }
+
+ dest.writeString(authority);
+ dest.writeString(accountType);
+ dest.writeInt(userVisible ? 1 : 0);
+ dest.writeInt(supportsUploading ? 1 : 0);
+ }
+
+ public SyncAdapterType(Parcel source) {
+ this(
+ source.readString(),
+ source.readString(),
+ source.readInt() != 0,
+ source.readInt() != 0);
+ }
+
+ public static final Creator<SyncAdapterType> CREATOR = new Creator<SyncAdapterType>() {
+ public SyncAdapterType createFromParcel(Parcel source) {
+ return new SyncAdapterType(source);
+ }
+
+ public SyncAdapterType[] newArray(int size) {
+ return new SyncAdapterType[size];
+ }
+ };
+} \ 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..7d9f1de
--- /dev/null
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -0,0 +1,60 @@
+/*
+ * 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.RegisteredServicesCache;
+import android.content.res.TypedArray;
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * 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(String packageName, 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;
+ }
+ final boolean userVisible =
+ sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_userVisible, true);
+ final boolean supportsUploading =
+ sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_supportsUploading,
+ true);
+ return new SyncAdapterType(authority, accountType, userVisible, supportsUploading);
+ } 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..15144a2 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,11 +31,11 @@ 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.content.pm.ProviderInfo;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -48,7 +49,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Config;
@@ -72,11 +72,12 @@ import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Random;
+import java.util.Collection;
/**
* @hide
*/
-class SyncManager {
+class SyncManager implements OnAccountsUpdatedListener {
private static final String TAG = "SyncManager";
// used during dumping of the Sync history
@@ -117,14 +118,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,17 +149,18 @@ 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)) {
Log.v(TAG, "Internal storage is low.");
}
mStorageIsLow = true;
- cancelActiveSync(null /* no url */);
+ cancelActiveSync(null /* any account */, null /* any authority */);
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Internal storage is ok.");
@@ -172,6 +171,56 @@ 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) {
+ // remember if this was the first time this was called after an update
+ final boolean justBootedUp = 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 (accounts.length > 0) {
+ // If this is the first time this was called after a bootup then
+ // the accounts haven't really changed, instead they were just loaded
+ // from the AccountManager. Otherwise at least one of the accounts
+ // has a change.
+ //
+ // If there was a real account change then force a sync of all accounts.
+ // This is a bit of overkill, but at least it will end up retrying syncs
+ // that failed due to an authentication failure and thus will recover if the
+ // account change was a password update.
+ //
+ // If this was the bootup case then don't sync everything, instead only
+ // sync those that have an unknown syncable state, which will give them
+ // a chance to set their syncable state.
+ boolean onlyThoseWithUnkownSyncableState = !justBootedUp;
+ scheduleSync(null, null, null, 0 /* no delay */, onlyThoseWithUnkownSyncableState);
+ }
+ }
+
private BroadcastReceiver mConnectivityIntentReceiver =
new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
@@ -229,7 +278,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 +297,8 @@ class SyncManager {
mPackageManager = null;
+ mSyncAdapters = new SyncAdaptersCache(mContext);
+
mSyncAlarmIntent = PendingIntent.getBroadcast(
mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0);
@@ -253,6 +308,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);
@@ -282,48 +340,12 @@ class SyncManager {
mHandleAlarmWakeLock.setReferenceCounted(false);
mSyncStorageEngine.addStatusChangeListener(
- SyncStorageEngine.CHANGE_SETTINGS, new ISyncStatusObserver.Stub() {
+ ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, new ISyncStatusObserver.Stub() {
public void onStatusChanged(int which) {
// force the sync loop to run if the settings change
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() {
@@ -397,7 +419,8 @@ class SyncManager {
scheduleSyncPollAlarm(nextRelativePollTimeMs);
// perform a poll
- scheduleSync(null /* sync all syncable providers */, new Bundle(), 0 /* no delay */);
+ scheduleSync(null /* sync all syncable accounts */, null /* sync all syncable providers */,
+ new Bundle(), 0 /* no delay */, false /* onlyThoseWithUnkownSyncableState */);
}
private void writeSyncPollTime(long when) {
@@ -452,19 +475,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;
}
@@ -499,22 +516,17 @@ class SyncManager {
*
* <p>You'll start getting callbacks after this.
*
- * @param url The Uri of a specific provider to be synced, or
- * null to sync all providers.
+ * @param requestedAccount the account to sync, may be null to signify all accounts
+ * @param requestedAuthority the authority to sync, may be null to indicate all authorities
* @param extras a Map of SyncAdapter-specific information to control
* syncs of a specific provider. Can be null. Is ignored
* if the url is null.
* @param delay how many milliseconds in the future to wait before performing this
- * sync. -1 means to make this the next sync to perform.
+ * @param onlyThoseWithUnkownSyncableState
*/
- public void scheduleSync(Uri url, Bundle extras, long delay) {
+ public void scheduleSync(Account requestedAccount, String requestedAuthority,
+ Bundle extras, long delay, boolean onlyThoseWithUnkownSyncableState) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
- if (isLoggable) {
- Log.v(TAG, "scheduleSync:"
- + " delay " + delay
- + ", url " + ((url == null) ? "(null)" : url)
- + ", extras " + ((extras == null) ? "(null)" : extras));
- }
if (!isSyncEnabled()) {
if (isLoggable) {
@@ -535,10 +547,9 @@ 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;
+ if (requestedAccount != null) {
+ accounts = new Account[]{requestedAccount};
} else {
// if the accounts aren't configured yet then we can't support an account-less
// sync request
@@ -560,14 +571,14 @@ class SyncManager {
}
final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
- final boolean force = extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false);
+ final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
int source;
if (uploadOnly) {
source = SyncStorageEngine.SOURCE_LOCAL;
- } else if (force) {
+ } else if (manualSync) {
source = SyncStorageEngine.SOURCE_USER;
- } else if (url == null) {
+ } else if (requestedAuthority == null) {
source = SyncStorageEngine.SOURCE_POLL;
} else {
// this isn't strictly server, since arbitrary callers can (and do) request
@@ -575,20 +586,54 @@ 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.
+ final HashSet<String> syncableAuthorities = new HashSet<String>();
+ for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
+ mSyncAdapters.getAllServices()) {
+ syncableAuthorities.add(syncAdapter.type.authority);
+ }
+
+ // 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 (requestedAuthority != null) {
+ final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
+ syncableAuthorities.clear();
+ if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
+ }
- 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;
+ for (String authority : syncableAuthorities) {
+ for (Account account : accounts) {
+ int isSyncable = mSyncStorageEngine.getIsSyncable(account, authority);
+ if (isSyncable == 0) {
+ continue;
+ }
+ if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
+ continue;
+ }
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
+ mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(authority, account.type));
+ if (syncAdapterInfo != null) {
+ if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
+ continue;
+ }
+ // make this an initialization sync if the isSyncable state is unknown
+ Bundle extrasCopy = extras;
+ if (isSyncable < 0) {
+ extrasCopy = new Bundle(extras);
+ extrasCopy.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
+ }
+ if (isLoggable) {
+ Log.v(TAG, "scheduleSync:"
+ + " delay " + delay
+ + ", source " + source
+ + ", account " + account
+ + ", authority " + authority
+ + ", extras " + extrasCopy);
+ }
+ scheduleSyncOperation(
+ new SyncOperation(account, source, authority, extrasCopy, delay));
}
}
}
@@ -598,36 +643,11 @@ 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) {
+ public void scheduleLocalSync(Account account, String authority) {
final Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
- scheduleSync(url, extras, LOCAL_SYNC_DELAY);
+ scheduleSync(account, authority, extras, LOCAL_SYNC_DELAY,
+ false /* onlyThoseWithUnkownSyncableState */);
}
private IPackageManager getPackageManager() {
@@ -641,18 +661,16 @@ class SyncManager {
return mPackageManager;
}
- /**
- * Initiate a sync for this given URL, or pass null for a full sync.
- *
- * <p>You'll start getting callbacks after this.
- *
- * @param url The Uri of a specific provider to be synced, or
- * null to sync all providers.
- * @param extras a Map of SyncAdapter specific information to control
- * syncs of a specific provider. Can be null. Is ignored
- */
- public void startSync(Uri url, Bundle extras) {
- scheduleSync(url, extras, 0 /* no delay */);
+ public SyncAdapterType[] getSyncAdapterTypes() {
+ final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos =
+ mSyncAdapters.getAllServices();
+ SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
+ int i = 0;
+ for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
+ types[i] = serviceInfo.type;
+ ++i;
+ }
+ return types;
}
public void updateHeartbeatTime() {
@@ -721,8 +739,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) {
@@ -736,17 +753,22 @@ class SyncManager {
}
/**
- * Cancel the active sync if it matches the uri. The uri corresponds to the one passed
- * in to startSync().
- * @param uri If non-null, the active sync is only canceled if it matches the uri.
- * If null, any active sync is canceled.
+ * Cancel the active sync if it matches the authority and account.
+ * @param account limit the cancelations to syncs with this account, if non-null
+ * @param authority limit the cancelations to syncs with this authority, if non-null
*/
- public void cancelActiveSync(Uri uri) {
+ public void cancelActiveSync(Account account, String authority) {
ActiveSyncContext activeSyncContext = mActiveSyncContext;
if (activeSyncContext != null) {
- // if a Uri was specified then only cancel the sync if it matches the the uri
- if (uri != null) {
- if (!uri.getAuthority().equals(activeSyncContext.mSyncOperation.authority)) {
+ // if an authority was specified then only cancel the sync if it matches
+ if (account != null) {
+ if (!account.equals(activeSyncContext.mSyncOperation.account)) {
+ return;
+ }
+ }
+ // if an account was specified then only cancel the sync if it matches
+ if (authority != null) {
+ if (!authority.equals(activeSyncContext.mSyncOperation.authority)) {
return;
}
}
@@ -798,14 +820,13 @@ class SyncManager {
}
/**
- * Remove any scheduled sync operations that match uri. The uri corresponds to the one passed
- * in to startSync().
- * @param uri If non-null, only operations that match the uri are cleared.
- * If null, all operations are cleared.
+ * Remove scheduled sync operations.
+ * @param account limit the removals to operations with this account, if non-null
+ * @param authority limit the removals to operations with this authority, if non-null
*/
- public void clearScheduledSyncOperations(Uri uri) {
+ public void clearScheduledSyncOperations(Account account, String authority) {
synchronized (mSyncQueue) {
- mSyncQueue.clear(null, uri != null ? uri.getAuthority() : null);
+ mSyncQueue.clear(account, authority);
}
}
@@ -857,7 +878,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 +887,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 +958,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 +996,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 +1041,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 +1060,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 +1124,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.name); pw.print(":");
+ pw.print(op.account.type); pw.print(" authority=");
pw.println(op.authority);
if (op.extras != null && op.extras.size() > 0) {
sb.setLength(0);
@@ -1078,7 +1135,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 +1147,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 +1155,9 @@ class SyncManager {
processedAccounts.add(curAccount);
- pw.print(" Account "); pw.print(authority.account);
- pw.println(":");
+ pw.print(" Account "); pw.print(authority.account.name);
+ pw.print(" "); pw.print(authority.account.type);
+ pw.println(":");
for (int j=i; j<N; j++) {
status = statuses.get(j);
authority = mSyncStorageEngine.getAuthority(status.authorityId);
@@ -1219,9 +1277,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.name);
+ pw.print(":");
+ pw.print(authority.account.type);
+ 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 +1342,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 +1360,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 +1376,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 +1433,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(mActiveSyncContext);
+ } 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 +1578,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");
@@ -1468,14 +1590,14 @@ class SyncManager {
// Otherwise consume SyncOperations from the head of the SyncQueue until one is
// found that is runnable (not disabled, etc). If that one is ready to run then
// start it, otherwise just get out.
- SyncOperation syncOperation;
+ SyncOperation op;
final ConnectivityManager connManager = (ConnectivityManager)
mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- final boolean backgroundDataSetting = connManager.getBackgroundDataSetting();
+ final boolean backgroundDataUsageAllowed = connManager.getBackgroundDataSetting();
synchronized (mSyncQueue) {
while (true) {
- syncOperation = mSyncQueue.head();
- if (syncOperation == null) {
+ op = mSyncQueue.head();
+ if (op == null) {
if (isLoggable) {
Log.v(TAG, "runStateIdle: no more sync operations, returning");
}
@@ -1485,39 +1607,49 @@ class SyncManager {
// Sync is disabled, drop this operation.
if (!isSyncEnabled()) {
if (isLoggable) {
- Log.v(TAG, "runStateIdle: sync disabled, dropping " + syncOperation);
+ Log.v(TAG, "runStateIdle: sync disabled, dropping " + op);
}
mSyncQueue.popHead();
continue;
}
- // skip the sync if it isn't a force and the settings are off for this provider
- final boolean force = syncOperation.extras.getBoolean(
- ContentResolver.SYNC_EXTRAS_FORCE, false);
- if (!force && (!backgroundDataSetting
- || !mSyncStorageEngine.getListenForNetworkTickles()
- || !mSyncStorageEngine.getSyncProviderAutomatically(
- null, syncOperation.authority))) {
+ // skip the sync if it isn't manual and auto sync is disabled
+ final boolean manualSync = op.extras.getBoolean(
+ ContentResolver.SYNC_EXTRAS_MANUAL, false);
+ final boolean syncAutomatically =
+ mSyncStorageEngine.getSyncAutomatically(op.account, op.authority)
+ && mSyncStorageEngine.getMasterSyncAutomatically();
+ boolean syncAllowed =
+ manualSync || (backgroundDataUsageAllowed && syncAutomatically);
+ int isSyncable = mSyncStorageEngine.getIsSyncable(op.account, op.authority);
+ if (isSyncable == 0) {
+ // if not syncable, don't allow
+ syncAllowed = false;
+ } else if (isSyncable < 0) {
+ // if the syncable state is unknown, only allow initialization syncs
+ syncAllowed =
+ op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
+ }
+ if (!syncAllowed) {
if (isLoggable) {
- Log.v(TAG, "runStateIdle: sync off, dropping " + syncOperation);
+ Log.v(TAG, "runStateIdle: sync off, dropping " + op);
}
mSyncQueue.popHead();
continue;
}
// skip the sync if the account of this operation no longer exists
- if (!ArrayUtils.contains(accounts, syncOperation.account)) {
+ if (!ArrayUtils.contains(accounts, op.account)) {
mSyncQueue.popHead();
if (isLoggable) {
- Log.v(TAG, "runStateIdle: account not present, dropping "
- + syncOperation);
+ Log.v(TAG, "runStateIdle: account not present, dropping " + op);
}
continue;
}
// go ahead and try to sync this syncOperation
if (isLoggable) {
- Log.v(TAG, "runStateIdle: found sync candidate: " + syncOperation);
+ Log.v(TAG, "runStateIdle: found sync candidate: " + op);
}
break;
}
@@ -1525,11 +1657,10 @@ class SyncManager {
// If the first SyncOperation isn't ready to run schedule a wakeup and
// get out.
final long now = SystemClock.elapsedRealtime();
- if (syncOperation.earliestRunTime > now) {
+ if (op.earliestRunTime > now) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "runStateIdle: the time is " + now + " yet the next "
- + "sync operation is for " + syncOperation.earliestRunTime
- + ": " + syncOperation);
+ + "sync operation is for " + op.earliestRunTime + ": " + op);
}
return;
}
@@ -1537,72 +1668,72 @@ class SyncManager {
// We will do this sync. Remove it from the queue and run it outside of the
// synchronized block.
if (isLoggable) {
- Log.v(TAG, "runStateIdle: we are going to sync " + syncOperation);
+ Log.v(TAG, "runStateIdle: we are going to sync " + op);
}
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 = SyncAdapterType.newKey(op.authority, op.account.type);
+ RegisteredServicesCache.ServiceInfo<SyncAdapterType> 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(op, insertStartSyncEvent(op));
+ 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,
- syncOperation.extras);
- mActiveSyncContext = activeSyncContext;
- mSyncStorageEngine.setActiveSync(mActiveSyncContext);
+ syncAdapter.startSync(mActiveSyncContext, syncOperation.authority,
+ syncOperation.account, syncOperation.extras);
} 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 +1773,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(activeSyncContext);
+ } catch (RemoteException e) {
+ // we don't need to retry this in this case
+ }
}
historyMessage = SyncStorageEngine.MESG_CANCELED;
downstreamActivity = 0;
@@ -1655,7 +1788,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,
@@ -1683,21 +1816,21 @@ class SyncManager {
*/
private int syncResultToErrorNumber(SyncResult syncResult) {
if (syncResult.syncAlreadyInProgress)
- return SyncStorageEngine.ERROR_SYNC_ALREADY_IN_PROGRESS;
+ return ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
if (syncResult.stats.numAuthExceptions > 0)
- return SyncStorageEngine.ERROR_AUTHENTICATION;
+ return ContentResolver.SYNC_ERROR_AUTHENTICATION;
if (syncResult.stats.numIoExceptions > 0)
- return SyncStorageEngine.ERROR_IO;
+ return ContentResolver.SYNC_ERROR_IO;
if (syncResult.stats.numParseExceptions > 0)
- return SyncStorageEngine.ERROR_PARSE;
+ return ContentResolver.SYNC_ERROR_PARSE;
if (syncResult.stats.numConflictDetectedExceptions > 0)
- return SyncStorageEngine.ERROR_CONFLICT;
+ return ContentResolver.SYNC_ERROR_CONFLICT;
if (syncResult.tooManyDeletions)
- return SyncStorageEngine.ERROR_TOO_MANY_DELETIONS;
+ return ContentResolver.SYNC_ERROR_TOO_MANY_DELETIONS;
if (syncResult.tooManyRetries)
- return SyncStorageEngine.ERROR_TOO_MANY_RETRIES;
+ return ContentResolver.SYNC_ERROR_TOO_MANY_RETRIES;
if (syncResult.databaseError)
- return SyncStorageEngine.ERROR_INTERNAL;
+ return ContentResolver.SYNC_ERROR_INTERNAL;
throw new IllegalStateException("we are not in an error state, " + syncResult);
}
@@ -1738,9 +1871,10 @@ class SyncManager {
} else {
final boolean timeToShowNotification =
now > mSyncNotificationInfo.startTime + SYNC_NOTIFICATION_DELAY;
- final boolean syncIsForced = syncOperation.extras
- .getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false);
- shouldInstall = timeToShowNotification || syncIsForced;
+ // show the notification immediately if this is a manual sync
+ final boolean manualSync = syncOperation.extras
+ .getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
+ shouldInstall = timeToShowNotification || manualSync;
}
}
@@ -1860,14 +1994,22 @@ 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;
+
+ final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
+ authority, 0 /* flags */);
+ if (providerInfo == null) {
+ return;
+ }
+ CharSequence authorityName = providerInfo.loadLabel(mContext.getPackageManager());
+
Intent clickIntent = new Intent();
clickIntent.setClassName("com.android.providers.subscribedfeeds",
"com.android.settings.SyncActivityTooManyDeletes");
clickIntent.putExtra("account", account);
- clickIntent.putExtra("provider", authority);
+ clickIntent.putExtra("provider", authorityName.toString());
clickIntent.putExtra("numDeletes", numDeletes);
if (!isActivityAvailable(clickIntent)) {
@@ -1881,14 +2023,13 @@ class SyncManager {
CharSequence tooManyDeletesDescFormat = mContext.getResources().getText(
R.string.contentServiceTooManyDeletesNotificationDesc);
- String[] authorities = authority.split(";");
Notification notification =
new Notification(R.drawable.stat_notify_sync_error,
mContext.getString(R.string.contentServiceSync),
System.currentTimeMillis());
notification.setLatestEventInfo(mContext,
mContext.getString(R.string.contentServiceSyncNotificationTitle),
- String.format(tooManyDeletesDescFormat.toString(), authorities[0]),
+ String.format(tooManyDeletesDescFormat.toString(), authorityName),
pendingIntent);
notification.flags |= Notification.FLAG_ONGOING_EVENT;
mNotificationMgr.notify(account.hashCode() ^ authority.hashCode(), notification);
@@ -1995,9 +2136,9 @@ class SyncManager {
SyncOperation existingOperation = mOpsByKey.get(operationKey);
// if this operation matches an existing operation that is being retried (delay > 0)
- // and this operation isn't forced, ignore this operation
+ // and this isn't a manual sync operation, ignore this operation
if (existingOperation != null && existingOperation.delay > 0) {
- if (!operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)) {
+ if (!operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) {
return false;
}
}
@@ -2071,7 +2212,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/SyncResult.java b/core/java/android/content/SyncResult.java
index f3260f3..4c201e6 100644
--- a/core/java/android/content/SyncResult.java
+++ b/core/java/android/content/SyncResult.java
@@ -113,14 +113,19 @@ public final class SyncResult implements Parcelable {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append(" syncAlreadyInProgress: ").append(syncAlreadyInProgress);
- sb.append(" tooManyDeletions: ").append(tooManyDeletions);
- sb.append(" tooManyRetries: ").append(tooManyRetries);
- sb.append(" databaseError: ").append(databaseError);
- sb.append(" fullSyncRequested: ").append(fullSyncRequested);
- sb.append(" partialSyncUnavailable: ").append(partialSyncUnavailable);
- sb.append(" moreRecordsToGet: ").append(moreRecordsToGet);
- sb.append(" stats: ").append(stats);
+ sb.append("SyncResult:");
+ if (syncAlreadyInProgress) {
+ sb.append(" syncAlreadyInProgress: ").append(syncAlreadyInProgress);
+ }
+ if (tooManyDeletions) sb.append(" tooManyDeletions: ").append(tooManyDeletions);
+ if (tooManyRetries) sb.append(" tooManyRetries: ").append(tooManyRetries);
+ if (databaseError) sb.append(" databaseError: ").append(databaseError);
+ if (fullSyncRequested) sb.append(" fullSyncRequested: ").append(fullSyncRequested);
+ if (partialSyncUnavailable) {
+ sb.append(" partialSyncUnavailable: ").append(partialSyncUnavailable);
+ }
+ if (moreRecordsToGet) sb.append(" moreRecordsToGet: ").append(moreRecordsToGet);
+ sb.append(stats);
return sb.toString();
}
diff --git a/core/java/android/content/SyncStateContentProviderHelper.java b/core/java/android/content/SyncStateContentProviderHelper.java
index f503e6f..64bbe25 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.name, account.type};
+ 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.name, account.type});
} 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.name, account.type}, 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.name, account.type});
}
}
diff --git a/core/java/android/content/SyncStats.java b/core/java/android/content/SyncStats.java
index b561b05..cc544c0 100644
--- a/core/java/android/content/SyncStats.java
+++ b/core/java/android/content/SyncStats.java
@@ -60,15 +60,18 @@ public class SyncStats implements Parcelable {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("numAuthExceptions: ").append(numAuthExceptions);
- sb.append(" numIoExceptions: ").append(numIoExceptions);
- sb.append(" numParseExceptions: ").append(numParseExceptions);
- sb.append(" numConflictDetectedExceptions: ").append(numConflictDetectedExceptions);
- sb.append(" numInserts: ").append(numInserts);
- sb.append(" numUpdates: ").append(numUpdates);
- sb.append(" numDeletes: ").append(numDeletes);
- sb.append(" numEntries: ").append(numEntries);
- sb.append(" numSkippedEntries: ").append(numSkippedEntries);
+ sb.append(" stats [");
+ if (numAuthExceptions > 0) sb.append(" numAuthExceptions: ").append(numAuthExceptions);
+ if (numIoExceptions > 0) sb.append(" numIoExceptions: ").append(numIoExceptions);
+ if (numParseExceptions > 0) sb.append(" numParseExceptions: ").append(numParseExceptions);
+ if (numConflictDetectedExceptions > 0)
+ sb.append(" numConflictDetectedExceptions: ").append(numConflictDetectedExceptions);
+ if (numInserts > 0) sb.append(" numInserts: ").append(numInserts);
+ if (numUpdates > 0) sb.append(" numUpdates: ").append(numUpdates);
+ if (numDeletes > 0) sb.append(" numDeletes: ").append(numDeletes);
+ if (numEntries > 0) sb.append(" numEntries: ").append(numEntries);
+ if (numSkippedEntries > 0) sb.append(" numSkippedEntries: ").append(numSkippedEntries);
+ sb.append("]");
return sb.toString();
}
diff --git a/core/java/android/content/SyncStatusObserver.java b/core/java/android/content/SyncStatusObserver.java
new file mode 100644
index 0000000..663378a
--- /dev/null
+++ b/core/java/android/content/SyncStatusObserver.java
@@ -0,0 +1,21 @@
+/*
+ * 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;
+
+public interface SyncStatusObserver {
+ void onStatusChanged(int which);
+}
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 756f35c..3ff13ae 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.backup.IBackupManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
@@ -88,6 +89,9 @@ public class SyncStorageEngine extends Handler {
/** Enum value for a user-initiated sync. */
public static final int SOURCE_USER = 3;
+ private static final Intent SYNC_CONNECTION_SETTING_CHANGED_INTENT =
+ new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
+
// TODO: i18n -- grab these out of resources.
/** String names for the sync source types. */
public static final String[] SOURCES = { "SERVER",
@@ -95,26 +99,10 @@ public class SyncStorageEngine extends Handler {
"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";
- public static final int CHANGE_SETTINGS = 1<<0;
- public static final int CHANGE_PENDING = 1<<1;
- public static final int CHANGE_ACTIVE = 1<<2;
- public static final int CHANGE_STATUS = 1<<3;
- public static final int CHANGE_ALL = 0x7fffffff;
-
public static final int MAX_HISTORY = 15;
private static final int MSG_WRITE_STATUS = 1;
@@ -122,9 +110,11 @@ public class SyncStorageEngine extends Handler {
private static final int MSG_WRITE_STATISTICS = 2;
private static final long WRITE_STATISTICS_DELAY = 1000*60*30; // 1/2 hour
+
+ private static final boolean SYNC_ENABLED_DEFAULT = false;
public static class PendingOperation {
- final String account;
+ final Account account;
final int syncSource;
final String authority;
final Bundle extras; // note: read-only.
@@ -132,7 +122,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;
@@ -151,26 +141,28 @@ 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) {
+ int syncable;
+
+ AuthorityInfo(Account account, String authority, int ident) {
this.account = account;
this.authority = authority;
this.ident = ident;
- enabled = true;
+ enabled = SYNC_ENABLED_DEFAULT;
+ syncable = -1; // default to "unknown"
}
}
@@ -202,8 +194,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>();
@@ -258,7 +250,7 @@ public class SyncStorageEngine extends Handler {
private int mNumPendingFinished = 0;
private int mNextHistoryId = 0;
- private boolean mListenForTickles = true;
+ private boolean mMasterSyncAutomatically = true;
private SyncStorageEngine(Context context) {
mContext = context;
@@ -366,14 +358,14 @@ public class SyncStorageEngine extends Handler {
}
}
- public boolean getSyncProviderAutomatically(String account, String providerName) {
+ public boolean getSyncAutomatically(Account account, String providerName) {
synchronized (mAuthorities) {
if (account != null) {
AuthorityInfo authority = getAuthorityLocked(account, providerName,
- "getSyncProviderAutomatically");
- return authority != null ? authority.enabled : false;
+ "getSyncAutomatically");
+ return authority != null && authority.enabled;
}
-
+
int i = mAuthorities.size();
while (i > 0) {
i--;
@@ -387,45 +379,86 @@ public class SyncStorageEngine extends Handler {
}
}
- public void setSyncProviderAutomatically(String account, String providerName, boolean sync) {
+ public void setSyncAutomatically(Account account, String providerName, boolean sync) {
+ boolean wasEnabled;
+ synchronized (mAuthorities) {
+ AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
+ wasEnabled = authority.enabled;
+ authority.enabled = sync;
+ writeAccountInfoLocked();
+ }
+
+ if (!wasEnabled && sync) {
+ mContext.getContentResolver().requestSync(account, providerName, new Bundle());
+ }
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
+ }
+
+ public int getIsSyncable(Account account, String providerName) {
synchronized (mAuthorities) {
if (account != null) {
AuthorityInfo authority = getAuthorityLocked(account, providerName,
- "setSyncProviderAutomatically");
- if (authority != null) {
- authority.enabled = sync;
+ "getIsSyncable");
+ if (authority == null) {
+ return -1;
}
- } else {
- int i = mAuthorities.size();
- while (i > 0) {
- i--;
- AuthorityInfo authority = mAuthorities.get(i);
- if (authority.authority.equals(providerName)) {
- authority.enabled = sync;
- }
+ return authority.syncable;
+ }
+
+ int i = mAuthorities.size();
+ while (i > 0) {
+ i--;
+ AuthorityInfo authority = mAuthorities.get(i);
+ if (authority.authority.equals(providerName)) {
+ return authority.syncable;
}
}
+ return -1;
+ }
+ }
+
+ public void setIsSyncable(Account account, String providerName, int syncable) {
+ int oldState;
+ if (syncable > 1) {
+ syncable = 1;
+ } else if (syncable < -1) {
+ syncable = -1;
+ }
+ Log.d(TAG, "setIsSyncable: " + account + ", provider " + providerName + " -> " + syncable);
+ synchronized (mAuthorities) {
+ AuthorityInfo authority = getOrCreateAuthorityLocked(account, providerName, -1, false);
+ oldState = authority.syncable;
+ authority.syncable = syncable;
writeAccountInfoLocked();
}
-
- reportChange(CHANGE_SETTINGS);
+
+ if (oldState <= 0 && syncable > 0) {
+ mContext.getContentResolver().requestSync(account, providerName, new Bundle());
+ }
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- public void setListenForNetworkTickles(boolean flag) {
+ public void setMasterSyncAutomatically(boolean flag) {
+ boolean old;
synchronized (mAuthorities) {
- mListenForTickles = flag;
+ old = mMasterSyncAutomatically;
+ mMasterSyncAutomatically = flag;
writeAccountInfoLocked();
}
- reportChange(CHANGE_SETTINGS);
+ if (!old && flag) {
+ mContext.getContentResolver().requestSync(null, null, new Bundle());
+ }
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
+ mContext.sendBroadcast(SYNC_CONNECTION_SETTING_CHANGED_INTENT);
}
- public boolean getListenForNetworkTickles() {
+ public boolean getMasterSyncAutomatically() {
synchronized (mAuthorities) {
- return mListenForTickles;
+ return mMasterSyncAutomatically;
}
}
- public AuthorityInfo getAuthority(String account, String authority) {
+ public AuthorityInfo getAuthority(Account account, String authority) {
synchronized (mAuthorities) {
return getAuthorityLocked(account, authority, null);
}
@@ -441,7 +474,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) {
@@ -490,7 +523,7 @@ public class SyncStorageEngine extends Handler {
status.pending = true;
}
- reportChange(CHANGE_PENDING);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
return op;
}
@@ -536,7 +569,7 @@ public class SyncStorageEngine extends Handler {
}
}
- reportChange(CHANGE_PENDING);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
return res;
}
@@ -552,7 +585,7 @@ public class SyncStorageEngine extends Handler {
}
writePendingOperationsLocked();
}
- reportChange(CHANGE_PENDING);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
return num;
}
@@ -580,7 +613,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,20 +692,20 @@ public class SyncStorageEngine extends Handler {
}
}
- reportChange(CHANGE_ACTIVE);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE);
}
/**
* To allow others to send active change reports, to poke clients.
*/
public void reportActiveChange() {
- reportChange(CHANGE_ACTIVE);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE);
}
/**
* 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) {
@@ -698,7 +731,7 @@ public class SyncStorageEngine extends Handler {
if (DEBUG) Log.v(TAG, "returning historyId " + id);
}
- reportChange(CHANGE_STATUS);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS);
return id;
}
@@ -802,7 +835,7 @@ public class SyncStorageEngine extends Handler {
}
}
- reportChange(CHANGE_STATUS);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS);
}
/**
@@ -860,7 +893,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 isSyncPending(Account account, String authority) {
synchronized (mAuthorities) {
final int N = mSyncStatus.size();
for (int i=0; i<N; i++) {
@@ -916,7 +949,7 @@ public class SyncStorageEngine extends Handler {
*/
public long getInitialSyncFailureTime() {
synchronized (mAuthorities) {
- if (!mListenForTickles) {
+ if (!mMasterSyncAutomatically) {
return 0;
}
@@ -957,19 +990,23 @@ 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) {
if (tag != null) {
- Log.w(TAG, tag + ": unknown account " + accountName);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, tag + ": unknown account " + accountName);
+ }
}
return null;
}
AuthorityInfo authority = account.authorities.get(authorityName);
if (authority == null) {
if (tag != null) {
- Log.w(TAG, tag + ": unknown authority " + authorityName);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, tag + ": unknown authority " + authorityName);
+ }
}
return null;
}
@@ -977,7 +1014,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) {
@@ -997,6 +1034,8 @@ public class SyncStorageEngine extends Handler {
ident++;
}
}
+ Log.d(TAG, "created a new AuthorityInfo for " + accountName
+ + ", provider " + authorityName);
authority = new AuthorityInfo(accountName, authorityName, ident);
account.authorities.put(authorityName, authority);
mAuthorities.put(ident, authority);
@@ -1050,7 +1089,7 @@ public class SyncStorageEngine extends Handler {
if ("accounts".equals(tagName)) {
String listen = parser.getAttributeValue(
null, "listen-for-tickles");
- mListenForTickles = listen == null
+ mMasterSyncAutomatically = listen == null
|| Boolean.parseBoolean(listen);
eventType = parser.next();
do {
@@ -1068,26 +1107,43 @@ 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(
null, "enabled");
- AuthorityInfo authority = mAuthorities.get(id);
+ String syncable = parser.getAttributeValue(null, "syncable");
+ AuthorityInfo authority = mAuthorities.get(id);
if (DEBUG_FILE) Log.v(TAG, "Adding authority: account="
+ accountName + " auth=" + authorityName
- + " enabled=" + enabled);
+ + " enabled=" + enabled
+ + " syncable=" + syncable);
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
|| Boolean.parseBoolean(enabled);
+ if ("unknown".equals(syncable)) {
+ authority.syncable = -1;
+ } else {
+ authority.syncable =
+ (syncable == null || Boolean.parseBoolean(enabled))
+ ? 1
+ : 0;
+ }
} else {
Log.w(TAG, "Failure adding authority: account="
+ accountName + " auth=" + authorityName
- + " enabled=" + enabled);
+ + " enabled=" + enabled
+ + " syncable=" + syncable);
}
}
}
@@ -1125,7 +1181,7 @@ public class SyncStorageEngine extends Handler {
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
out.startTag(null, "accounts");
- if (!mListenForTickles) {
+ if (!mMasterSyncAutomatically) {
out.attribute(null, "listen-for-tickles", "false");
}
@@ -1134,11 +1190,17 @@ 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.name);
+ out.attribute(null, "type", authority.account.type);
out.attribute(null, "authority", authority.authority);
if (!authority.enabled) {
out.attribute(null, "enabled", "false");
}
+ if (authority.syncable < 0) {
+ out.attribute(null, "syncable", "unknown");
+ } else if (authority.syncable == 0) {
+ out.attribute(null, "syncable", "false");
+ }
out.endTag(null, "authority");
}
@@ -1183,6 +1245,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();
@@ -1190,6 +1254,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");
@@ -1208,9 +1275,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;
@@ -1253,13 +1326,19 @@ public class SyncStorageEngine extends Handler {
String value = c.getString(c.getColumnIndex("value"));
if (name == null) continue;
if (name.equals("listen_for_tickles")) {
- setListenForNetworkTickles(value == null
- || Boolean.parseBoolean(value));
+ setMasterSyncAutomatically(value == null || Boolean.parseBoolean(value));
} else if (name.startsWith("sync_provider_")) {
String provider = name.substring("sync_provider_".length(),
name.length());
- setSyncProviderAutomatically(null, provider,
- value == null || Boolean.parseBoolean(value));
+ int i = mAuthorities.size();
+ while (i > 0) {
+ i--;
+ AuthorityInfo authority = mAuthorities.get(i);
+ if (authority.authority.equals(provider)) {
+ authority.enabled = value == null || Boolean.parseBoolean(value);
+ authority.syncable = 1;
+ }
+ }
}
}
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..b46c545 100644
--- a/core/java/android/content/TempProviderSyncAdapter.java
+++ b/core/java/android/content/TempProviderSyncAdapter.java
@@ -12,6 +12,11 @@ import android.util.Config;
import android.util.EventLog;
import android.util.Log;
import android.util.TimingLogger;
+import android.accounts.Account;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+
+import java.io.IOException;
/**
* @hide
@@ -62,12 +67,10 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
*
* @param context allows you to publish status and interact with the
* @param account the account to sync
- * @param forced if true then the sync was forced
+ * @param manualSync true if this sync was requested manually by the user
* @param result information to track what happened during this sync attempt
- * @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 manualSync,
SyncResult result);
/**
@@ -85,6 +88,9 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
*/
public abstract boolean isReadOnly();
+ public abstract boolean getIsSyncable(Account account)
+ throws IOException, AuthenticatorException, OperationCanceledException;
+
/**
* Get diffs from the server since the last completed sync and put them
* into a temporary provider.
@@ -168,12 +174,13 @@ 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 String mAuthority;
private final Bundle mExtras;
private final SyncContext mSyncContext;
private volatile boolean mIsCanceled = false;
@@ -181,9 +188,10 @@ 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, String authority, Bundle extras) {
super("SyncThread");
mAccount = account;
+ mAuthority = authority;
mExtras = extras;
mSyncContext = syncContext;
mResult = new SyncResult();
@@ -207,7 +215,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
mInitialTxBytes = NetStat.getUidTxBytes(uid);
mInitialRxBytes = NetStat.getUidRxBytes(uid);
try {
- sync(mSyncContext, mAccount, mExtras);
+ sync(mSyncContext, mAccount, mAuthority, mExtras);
} catch (SQLException e) {
Log.e(TAG, "Sync failed", e);
mResult.databaseError = true;
@@ -221,19 +229,45 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
}
}
- private void sync(SyncContext syncContext, String account, Bundle extras) {
+ private void sync(SyncContext syncContext, Account account, String authority,
+ Bundle extras) {
mIsCanceled = false;
mProviderSyncStarted = false;
mAdapterSyncStarted = false;
String message = null;
- boolean syncForced = extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false);
+ // always attempt to initialize if the isSyncable state isn't set yet
+ int isSyncable = ContentResolver.getIsSyncable(account, authority);
+ if (isSyncable < 0) {
+ try {
+ isSyncable = (getIsSyncable(account)) ? 1 : 0;
+ ContentResolver.setIsSyncable(account, authority, isSyncable);
+ } catch (IOException e) {
+ ++mResult.stats.numIoExceptions;
+ } catch (AuthenticatorException e) {
+ ++mResult.stats.numParseExceptions;
+ } catch (OperationCanceledException e) {
+ // do nothing
+ }
+ }
+
+ // if this is an initialization request then our work is done here
+ if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) {
+ return;
+ }
+
+ // if we aren't syncable then get out
+ if (isSyncable <= 0) {
+ return;
+ }
+
+ boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
try {
mProvider.onSyncStart(syncContext, account);
mProviderSyncStarted = true;
- onSyncStarting(syncContext, account, syncForced, mResult);
+ onSyncStarting(syncContext, account, manualSync, mResult);
if (mResult.hasError()) {
message = "SyncAdapter failed while trying to start sync";
return;
@@ -273,7 +307,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,13 +552,14 @@ 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, String authority,
+ Bundle extras) {
if (mSyncThread != null) {
syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS);
return;
}
- mSyncThread = new SyncThread(syncContext, account, extras);
+ mSyncThread = new SyncThread(syncContext, account, authority, extras);
mSyncThread.start();
}
diff --git a/core/java/android/content/pm/ConfigurationInfo.java b/core/java/android/content/pm/ConfigurationInfo.java
index fb7a47f..8edd436 100755
--- a/core/java/android/content/pm/ConfigurationInfo.java
+++ b/core/java/android/content/pm/ConfigurationInfo.java
@@ -22,9 +22,9 @@ import android.os.Parcelable;
/**
* Information you can retrieve about hardware configuration preferences
* declared by an application. This corresponds to information collected from the
- * AndroidManifest.xml's &lt;uses-configuration&gt; and the &lt;uses-feature&gt;tags.
+ * AndroidManifest.xml's &lt;uses-configuration&gt; and &lt;uses-feature&gt; tags.
*/
-public class ConfigurationInfo implements Parcelable {
+public class ConfigurationInfo implements Parcelable {
/**
* The kind of touch screen attached to the device.
* One of: {@link android.content.res.Configuration#TOUCHSCREEN_NOTOUCH},
@@ -92,13 +92,13 @@ public class ConfigurationInfo implements Parcelable {
}
public String toString() {
- return "ApplicationHardwarePreferences{"
+ return "ConfigurationInfo{"
+ Integer.toHexString(System.identityHashCode(this))
- + ", touchscreen = " + reqTouchScreen + "}"
- + ", inputMethod = " + reqKeyboardType + "}"
- + ", navigation = " + reqNavigation + "}"
- + ", reqInputFeatures = " + reqInputFeatures + "}"
- + ", reqGlEsVersion = " + reqGlEsVersion + "}";
+ + " touchscreen = " + reqTouchScreen
+ + " inputMethod = " + reqKeyboardType
+ + " navigation = " + reqNavigation
+ + " reqInputFeatures = " + reqInputFeatures
+ + " reqGlEsVersion = " + reqGlEsVersion + "}";
}
public int describeContents() {
diff --git a/core/java/android/content/pm/FeatureInfo.aidl b/core/java/android/content/pm/FeatureInfo.aidl
new file mode 100755
index 0000000..d84a84c
--- /dev/null
+++ b/core/java/android/content/pm/FeatureInfo.aidl
@@ -0,0 +1,19 @@
+/*
+** 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.
+*/
+
+package android.content.pm;
+
+parcelable FeatureInfo;
diff --git a/core/java/android/content/pm/FeatureInfo.java b/core/java/android/content/pm/FeatureInfo.java
new file mode 100644
index 0000000..57d61fd
--- /dev/null
+++ b/core/java/android/content/pm/FeatureInfo.java
@@ -0,0 +1,101 @@
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.Parcelable.Creator;
+
+/**
+ * A single feature that can be requested by an application. This corresponds
+ * to information collected from the
+ * AndroidManifest.xml's &lt;uses-feature&gt; tag.
+ */
+public class FeatureInfo implements Parcelable {
+ /**
+ * The name of this feature, for example "android.hardware.camera". If
+ * this is null, then this is an OpenGL ES version feature as described
+ * in {@link #reqGlEsVersion}.
+ */
+ public String name;
+
+ /**
+ * Default value for {@link #reqGlEsVersion};
+ */
+ public static final int GL_ES_VERSION_UNDEFINED = 0;
+
+ /**
+ * The GLES version used by an application. The upper order 16 bits represent the
+ * major version and the lower order 16 bits the minor version. Only valid
+ * if {@link #name} is null.
+ */
+ public int reqGlEsVersion;
+
+ /**
+ * Set on {@link #flags} if this feature has been required by the application.
+ */
+ public static final int FLAG_REQUIRED = 0x0001;
+
+ /**
+ * Additional flags. May be zero or more of {@link #FLAG_REQUIRED}.
+ */
+ public int flags;
+
+ public FeatureInfo() {
+ }
+
+ public FeatureInfo(FeatureInfo orig) {
+ name = orig.name;
+ reqGlEsVersion = orig.reqGlEsVersion;
+ flags = orig.flags;
+ }
+
+ public String toString() {
+ if (name != null) {
+ return "FeatureInfo{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + name + " fl=0x" + Integer.toHexString(flags) + "}";
+ } else {
+ return "FeatureInfo{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " glEsVers=" + getGlEsVersion()
+ + " fl=0x" + Integer.toHexString(flags) + "}";
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
+ dest.writeString(name);
+ dest.writeInt(reqGlEsVersion);
+ dest.writeInt(flags);
+ }
+
+ public static final Creator<FeatureInfo> CREATOR =
+ new Creator<FeatureInfo>() {
+ public FeatureInfo createFromParcel(Parcel source) {
+ return new FeatureInfo(source);
+ }
+ public FeatureInfo[] newArray(int size) {
+ return new FeatureInfo[size];
+ }
+ };
+
+ private FeatureInfo(Parcel source) {
+ name = source.readString();
+ reqGlEsVersion = source.readInt();
+ flags = source.readInt();
+ }
+
+ /**
+ * This method extracts the major and minor version of reqGLEsVersion attribute
+ * and returns it as a string. Say reqGlEsVersion value of 0x00010002 is returned
+ * as 1.2
+ * @return String representation of the reqGlEsVersion attribute
+ */
+ public String getGlEsVersion() {
+ int major = ((reqGlEsVersion & 0xffff0000) >> 16);
+ int minor = reqGlEsVersion & 0x0000ffff;
+ return String.valueOf(major)+"."+String.valueOf(minor);
+ }
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index e587ca7..c322951 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.FeatureInfo;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDataObserver;
@@ -75,6 +76,8 @@ interface IPackageManager {
int checkSignatures(String pkg1, String pkg2);
+ int checkUidSignatures(int uid1, int uid2);
+
String[] getPackagesForUid(int uid);
String getNameForUid(int uid);
@@ -274,6 +277,12 @@ interface IPackageManager {
*/
String[] getSystemSharedLibraryNames();
+ /**
+ * Get a list of features that are available on the
+ * system.
+ */
+ FeatureInfo[] getSystemAvailableFeatures();
+
void enterSafeMode();
boolean isSafeMode();
void systemReady();
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index d9326f2..a8ce889 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -127,6 +127,11 @@ public class PackageInfo implements Parcelable {
*/
public ConfigurationInfo[] configPreferences;
+ /**
+ * The features that this application has said it requires.
+ */
+ public FeatureInfo[] reqFeatures;
+
public PackageInfo() {
}
@@ -162,6 +167,7 @@ public class PackageInfo implements Parcelable {
dest.writeStringArray(requestedPermissions);
dest.writeTypedArray(signatures, parcelableFlags);
dest.writeTypedArray(configPreferences, parcelableFlags);
+ dest.writeTypedArray(reqFeatures, parcelableFlags);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -195,5 +201,6 @@ public class PackageInfo implements Parcelable {
requestedPermissions = source.createStringArray();
signatures = source.createTypedArray(Signature.CREATOR);
configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
+ reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 67bd1ac..825eb85 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -159,8 +159,10 @@ public abstract class PackageManager {
/**
* {@link PackageInfo} flag: return information about
- * hardware preferences
- * {@link PackageInfo#configPreferences}
+ * hardware preferences in
+ * {@link PackageInfo#configPreferences PackageInfo.configPreferences} and
+ * requested features in {@link PackageInfo#reqFeatures
+ * PackageInfo.reqFeatures}.
*/
public static final int GET_CONFIGURATIONS = 0x00004000;
@@ -400,6 +402,14 @@ public abstract class PackageManager {
public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
/**
+ * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+ * the new package uses a feature that is not available.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_MISSING_FEATURE = -17;
+
+ /**
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
* if the parser was given a path that is not a file, or does not end with the expected
@@ -865,6 +875,7 @@ public abstract class PackageManager {
* {@link #SIGNATURE_SECOND_NOT_SIGNED}, {@link #SIGNATURE_NO_MATCH},
* or {@link #SIGNATURE_UNKNOWN_PACKAGE}.
*
+ * @see #checkSignatures(int, int)
* @see #SIGNATURE_MATCH
* @see #SIGNATURE_NEITHER_SIGNED
* @see #SIGNATURE_FIRST_NOT_SIGNED
@@ -875,6 +886,34 @@ public abstract class PackageManager {
public abstract int checkSignatures(String pkg1, String pkg2);
/**
+ * Like {@link #checkSignatures(String, String)}, but takes UIDs of
+ * the two packages to be checked. This can be useful, for example,
+ * when doing the check in an IPC, where the UID is the only identity
+ * available. It is functionally identical to determining the package
+ * associated with the UIDs and checking their signatures.
+ *
+ * @param uid1 First UID whose signature will be compared.
+ * @param uid2 Second UID whose signature will be compared.
+ * @return Returns an integer indicating whether there is a matching
+ * signature: the value is >= 0 if there is a match (or neither package
+ * is signed), or < 0 if there is not a match. The match result can be
+ * further distinguished with the success (>= 0) constants
+ * {@link #SIGNATURE_MATCH}, {@link #SIGNATURE_NEITHER_SIGNED}; or
+ * failure (< 0) constants {@link #SIGNATURE_FIRST_NOT_SIGNED},
+ * {@link #SIGNATURE_SECOND_NOT_SIGNED}, {@link #SIGNATURE_NO_MATCH},
+ * or {@link #SIGNATURE_UNKNOWN_PACKAGE}.
+ *
+ * @see #checkSignatures(int, int)
+ * @see #SIGNATURE_MATCH
+ * @see #SIGNATURE_NEITHER_SIGNED
+ * @see #SIGNATURE_FIRST_NOT_SIGNED
+ * @see #SIGNATURE_SECOND_NOT_SIGNED
+ * @see #SIGNATURE_NO_MATCH
+ * @see #SIGNATURE_UNKNOWN_PACKAGE
+ */
+ public abstract int checkSignatures(int uid1, int uid2);
+
+ /**
* Retrieve the names of all packages that are associated with a particular
* user id. In most cases, this will be a single package name, the package
* that has been assigned that user id. Where there are multiple packages
@@ -951,6 +990,16 @@ public abstract class PackageManager {
public abstract String[] getSystemSharedLibraryNames();
/**
+ * Get a list of features that are available on the
+ * system.
+ *
+ * @return An array of FeatureInfo classes describing the features
+ * that are available on the system, or null if there are none(!!).
+ *
+ */
+ public abstract FeatureInfo[] getSystemAvailableFeatures();
+
+ /**
* Determine the best action to perform for a given Intent. This is how
* {@link Intent#resolveActivity} finds an activity if a class has not
* been explicitly specified.
@@ -1429,8 +1478,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/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 33f4b52..4399df4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -184,9 +184,12 @@ public class PackageParser {
int N = p.configPreferences.size();
if (N > 0) {
pi.configPreferences = new ConfigurationInfo[N];
- for (int i=0; i<N; i++) {
- pi.configPreferences[i] = p.configPreferences.get(i);
- }
+ p.configPreferences.toArray(pi.configPreferences);
+ }
+ N = p.reqFeatures != null ? p.reqFeatures.size() : 0;
+ if (N > 0) {
+ pi.reqFeatures = new FeatureInfo[N];
+ p.reqFeatures.toArray(pi.reqFeatures);
}
}
if ((flags&PackageManager.GET_ACTIVITIES) != 0) {
@@ -268,10 +271,12 @@ public class PackageParser {
}
}
if ((flags&PackageManager.GET_SIGNATURES) != 0) {
- int N = p.mSignatures.length;
- if (N > 0) {
- pi.signatures = new Signature[N];
- System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
+ if (p.mSignatures != null) {
+ int N = p.mSignatures.length;
+ if (N > 0) {
+ pi.signatures = new Signature[N];
+ System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
+ }
}
}
return pi;
@@ -758,14 +763,32 @@ public class PackageParser {
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("uses-feature")) {
- ConfigurationInfo cPref = new ConfigurationInfo();
+ FeatureInfo fi = new FeatureInfo();
sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestUsesFeature);
- cPref.reqGlEsVersion = sa.getInt(
- com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
- ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
+ fi.name = sa.getNonResourceString(
+ com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
+ if (fi.name == null) {
+ fi.reqGlEsVersion = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
+ FeatureInfo.GL_ES_VERSION_UNDEFINED);
+ }
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestUsesFeature_required,
+ true)) {
+ fi.flags |= FeatureInfo.FLAG_REQUIRED;
+ }
sa.recycle();
- pkg.configPreferences.add(cPref);
+ if (pkg.reqFeatures == null) {
+ pkg.reqFeatures = new ArrayList<FeatureInfo>();
+ }
+ pkg.reqFeatures.add(fi);
+
+ if (fi.name == null) {
+ ConfigurationInfo cPref = new ConfigurationInfo();
+ cPref.reqGlEsVersion = fi.reqGlEsVersion;
+ pkg.configPreferences.add(cPref);
+ }
XmlUtils.skipCurrentTag(parser);
@@ -944,11 +967,6 @@ public class PackageParser {
}
}
- if (pkg.usesLibraries.size() > 0) {
- pkg.usesLibraryFiles = new String[pkg.usesLibraries.size()];
- pkg.usesLibraries.toArray(pkg.usesLibraryFiles);
- }
-
if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
&& pkg.applicationInfo.targetSdkVersion
>= android.os.Build.VERSION_CODES.DONUT)) {
@@ -1434,11 +1452,28 @@ public class PackageParser {
String lname = sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
+ boolean req = sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
+ true);
sa.recycle();
- if (lname != null && !owner.usesLibraries.contains(lname)) {
- owner.usesLibraries.add(lname.intern());
+ if (lname != null) {
+ if (req) {
+ if (owner.usesLibraries == null) {
+ owner.usesLibraries = new ArrayList<String>();
+ }
+ if (!owner.usesLibraries.contains(lname)) {
+ owner.usesLibraries.add(lname.intern());
+ }
+ } else {
+ if (owner.usesOptionalLibraries == null) {
+ owner.usesOptionalLibraries = new ArrayList<String>();
+ }
+ if (!owner.usesOptionalLibraries.contains(lname)) {
+ owner.usesOptionalLibraries.add(lname.intern());
+ }
+ }
}
XmlUtils.skipCurrentTag(parser);
@@ -2416,7 +2451,8 @@ public class PackageParser {
public ArrayList<String> protectedBroadcasts;
- public final ArrayList<String> usesLibraries = new ArrayList<String>();
+ public ArrayList<String> usesLibraries = null;
+ public ArrayList<String> usesOptionalLibraries = null;
public String[] usesLibraryFiles = null;
// We store the application meta-data independently to avoid multiple unwanted references
@@ -2464,6 +2500,11 @@ public class PackageParser {
public final ArrayList<ConfigurationInfo> configPreferences =
new ArrayList<ConfigurationInfo>();
+ /*
+ * Applications requested features
+ */
+ public ArrayList<FeatureInfo> reqFeatures = null;
+
public Package(String _name) {
packageName = _name;
applicationInfo.packageName = _name;
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index d01460e..ec01775 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -74,7 +74,12 @@ 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.
+ */
+ @Deprecated
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..342de2b
--- /dev/null
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -0,0 +1,238 @@
+/*
+ * 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;
+ public final int uid;
+
+ private ServiceInfo(V type, ComponentName componentName, int uid) {
+ this.type = type;
+ this.componentName = componentName;
+ this.uid = uid;
+ }
+
+ 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<V> 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(si.packageName, attrs);
+ if (v == null) {
+ return null;
+ }
+ final android.content.pm.ServiceInfo serviceInfo = service.serviceInfo;
+ final ApplicationInfo applicationInfo = serviceInfo.applicationInfo;
+ final int uid = applicationInfo.uid;
+ return new ServiceInfo<V>(v, componentName, uid);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ public abstract V parseServiceAttributes(String packageName, AttributeSet attrs);
+}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 5f44cc9..cbf8410 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -93,7 +93,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
/**
* The kind of keyboard attached to the device.
- * One of: {@link #KEYBOARD_QWERTY}, {@link #KEYBOARD_12KEY}.
+ * One of: {@link #KEYBOARD_NOKEYS}, {@link #KEYBOARD_QWERTY},
+ * {@link #KEYBOARD_12KEY}.
*/
public int keyboard;
@@ -132,8 +133,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
/**
* The kind of navigation method available on the device.
- * One of: {@link #NAVIGATION_DPAD}, {@link #NAVIGATION_TRACKBALL},
- * {@link #NAVIGATION_WHEEL}.
+ * One of: {@link #NAVIGATION_NONAV}, {@link #NAVIGATION_DPAD},
+ * {@link #NAVIGATION_TRACKBALL}, {@link #NAVIGATION_WHEEL}.
*/
public int navigation;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 2354519..7d412a7 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -23,6 +23,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.pm.ApplicationInfo;
+import android.graphics.BitmapFactory;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
@@ -1707,7 +1708,8 @@ public class Resources {
InputStream is = mAssets.openNonAsset(
value.assetCookie, file, AssetManager.ACCESS_BUFFER);
// System.out.println("Opened file " + file + ": " + is);
- dr = Drawable.createFromResourceStream(this, value, is, file);
+ dr = Drawable.createFromResourceStream(this, value, is,
+ file, null);
is.close();
// System.out.println("Created stream: " + dr);
} catch (Exception e) {
diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index e684cb8..8fb82be 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -202,7 +202,7 @@ final class StringBlock {
sub = subtag(tag, ";size=");
if (sub != null) {
int size = Integer.parseInt(sub);
- buffer.setSpan(new AbsoluteSizeSpan(size),
+ buffer.setSpan(new AbsoluteSizeSpan(size, true),
style[i+1], style[i+2]+1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
@@ -310,7 +310,7 @@ final class StringBlock {
* the ascent if possible, or the descent if shrinking the ascent further
* will make the text unreadable.
*/
- private static class Height implements LineHeightSpan {
+ private static class Height implements LineHeightSpan.WithDensity {
private int mSize;
private static float sProportion = 0;
@@ -321,9 +321,21 @@ final class StringBlock {
public void chooseHeight(CharSequence text, int start, int end,
int spanstartv, int v,
Paint.FontMetricsInt fm) {
- if (fm.bottom - fm.top < mSize) {
- fm.top = fm.bottom - mSize;
- fm.ascent = fm.ascent - mSize;
+ // Should not get called, at least not by StaticLayout.
+ chooseHeight(text, start, end, spanstartv, v, fm, null);
+ }
+
+ public void chooseHeight(CharSequence text, int start, int end,
+ int spanstartv, int v,
+ Paint.FontMetricsInt fm, TextPaint paint) {
+ int size = mSize;
+ if (paint != null) {
+ size *= paint.density;
+ }
+
+ if (fm.bottom - fm.top < size) {
+ fm.top = fm.bottom - size;
+ fm.ascent = fm.ascent - size;
} else {
if (sProportion == 0) {
/*
@@ -343,27 +355,27 @@ final class StringBlock {
int need = (int) Math.ceil(-fm.top * sProportion);
- if (mSize - fm.descent >= need) {
+ if (size - fm.descent >= need) {
/*
* It is safe to shrink the ascent this much.
*/
- fm.top = fm.bottom - mSize;
- fm.ascent = fm.descent - mSize;
- } else if (mSize >= need) {
+ fm.top = fm.bottom - size;
+ fm.ascent = fm.descent - size;
+ } else if (size >= need) {
/*
* We can't show all the descent, but we can at least
* show all the ascent.
*/
fm.top = fm.ascent = -need;
- fm.bottom = fm.descent = fm.top + mSize;
+ fm.bottom = fm.descent = fm.top + size;
} else {
/*
* Show as much of the ascent as we can, and no descent.
*/
- fm.top = fm.ascent = -mSize;
+ fm.top = fm.ascent = -size;
fm.bottom = fm.descent = 0;
}
}
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/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 184d6dc..5d7af69 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -517,8 +517,10 @@ public class SQLiteDatabase extends SQLiteClosable {
* @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
* will not be yielded. Use yieldIfContendedSafely instead.
*/
+ @Deprecated
public boolean yieldIfContended() {
- return yieldIfContendedHelper(false /* do not check yielding */);
+ return yieldIfContendedHelper(false /* do not check yielding */,
+ -1 /* sleepAfterYieldDelay */);
}
/**
@@ -526,14 +528,29 @@ public class SQLiteDatabase extends SQLiteClosable {
* successful so far. Do not call setTransactionSuccessful before calling this. When this
* returns a new transaction will have been created but not marked as successful. This assumes
* that there are no nested transactions (beginTransaction has only been called once) and will
- * through an exception if that is not the case.
+ * throw an exception if that is not the case.
* @return true if the transaction was yielded
*/
public boolean yieldIfContendedSafely() {
- return yieldIfContendedHelper(true /* check yielding */);
+ return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/);
}
- private boolean yieldIfContendedHelper(boolean checkFullyYielded) {
+ /**
+ * Temporarily end the transaction to let other threads run. The transaction is assumed to be
+ * successful so far. Do not call setTransactionSuccessful before calling this. When this
+ * returns a new transaction will have been created but not marked as successful. This assumes
+ * that there are no nested transactions (beginTransaction has only been called once) and will
+ * throw an exception if that is not the case.
+ * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if
+ * the lock was actually yielded. This will allow other background threads to make some
+ * more progress than they would if we started the transaction immediately.
+ * @return true if the transaction was yielded
+ */
+ public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) {
+ return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay);
+ }
+
+ private boolean yieldIfContendedHelper(boolean checkFullyYielded, long sleepAfterYieldDelay) {
if (mLock.getQueueLength() == 0) {
// Reset the lock acquire time since we know that the thread was willing to yield
// the lock at this time.
@@ -549,6 +566,13 @@ public class SQLiteDatabase extends SQLiteClosable {
"Db locked more than once. yielfIfContended cannot yield");
}
}
+ if (sleepAfterYieldDelay > 0) {
+ try {
+ Thread.sleep(sleepAfterYieldDelay);
+ } catch (InterruptedException e) {
+ Thread.interrupted();
+ }
+ }
beginTransaction();
return true;
}
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/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 091bc17..aa3b852 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -40,15 +40,16 @@ public class Camera {
private static final String TAG = "Camera";
// These match the enums in frameworks/base/include/ui/Camera.h
- private static final int CAMERA_MSG_ERROR = 0;
- private static final int CAMERA_MSG_SHUTTER = 1;
- private static final int CAMERA_MSG_FOCUS = 2;
- private static final int CAMERA_MSG_ZOOM = 3;
- private static final int CAMERA_MSG_PREVIEW_FRAME = 4;
- private static final int CAMERA_MSG_VIDEO_FRAME = 5;
- private static final int CAMERA_MSG_POSTVIEW_FRAME = 6;
- private static final int CAMERA_MSG_RAW_IMAGE = 7;
- private static final int CAMERA_MSG_COMPRESSED_IMAGE = 8;
+ private static final int CAMERA_MSG_ERROR = 0x001;
+ private static final int CAMERA_MSG_SHUTTER = 0x002;
+ private static final int CAMERA_MSG_FOCUS = 0x004;
+ private static final int CAMERA_MSG_ZOOM = 0x008;
+ private static final int CAMERA_MSG_PREVIEW_FRAME = 0x010;
+ private static final int CAMERA_MSG_VIDEO_FRAME = 0x020;
+ private static final int CAMERA_MSG_POSTVIEW_FRAME = 0x040;
+ private static final int CAMERA_MSG_RAW_IMAGE = 0x080;
+ private static final int CAMERA_MSG_COMPRESSED_IMAGE = 0x100;
+ private static final int CAMERA_MSG_ALL_MSGS = 0x1FF;
private int mNativeContext; // accessed by native methods
private EventHandler mEventHandler;
@@ -56,7 +57,9 @@ public class Camera {
private PictureCallback mRawImageCallback;
private PictureCallback mJpegCallback;
private PreviewCallback mPreviewCallback;
+ private PictureCallback mPostviewCallback;
private AutoFocusCallback mAutoFocusCallback;
+ private ZoomCallback mZoomCallback;
private ErrorCallback mErrorCallback;
private boolean mOneShot;
@@ -72,6 +75,8 @@ public class Camera {
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
+ mPostviewCallback = null;
+ mZoomCallback = null;
Looper looper;
if ((looper = Looper.myLooper()) != null) {
@@ -245,13 +250,15 @@ public class Camera {
return;
case CAMERA_MSG_RAW_IMAGE:
- if (mRawImageCallback != null)
+ if (mRawImageCallback != null) {
mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ }
return;
case CAMERA_MSG_COMPRESSED_IMAGE:
- if (mJpegCallback != null)
+ if (mJpegCallback != null) {
mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ }
return;
case CAMERA_MSG_PREVIEW_FRAME:
@@ -263,15 +270,29 @@ public class Camera {
}
return;
+ case CAMERA_MSG_POSTVIEW_FRAME:
+ if (mPostviewCallback != null) {
+ mPostviewCallback.onPictureTaken((byte[])msg.obj, mCamera);
+ }
+ return;
+
case CAMERA_MSG_FOCUS:
- if (mAutoFocusCallback != null)
+ if (mAutoFocusCallback != null) {
mAutoFocusCallback.onAutoFocus(msg.arg1 == 0 ? false : true, mCamera);
+ }
+ return;
+
+ case CAMERA_MSG_ZOOM:
+ if (mZoomCallback != null) {
+ mZoomCallback.onZoomUpdate(msg.arg1, mCamera);
+ }
return;
case CAMERA_MSG_ERROR :
Log.e(TAG, "Error " + msg.arg1);
- if (mErrorCallback != null)
+ if (mErrorCallback != null) {
mErrorCallback.onError(msg.arg1, mCamera);
+ }
return;
default:
@@ -364,13 +385,63 @@ public class Camera {
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback jpeg) {
+ takePicture(shutter, raw, null, jpeg);
+ }
+ private native final void native_takePicture();
+
+ /**
+ * Triggers an asynchronous image capture. The camera service
+ * will initiate a series of callbacks to the application as the
+ * image capture progresses. The shutter callback occurs after
+ * the image is captured. This can be used to trigger a sound
+ * to let the user know that image has been captured. The raw
+ * callback occurs when the raw image data is available. The
+ * postview callback occurs when a scaled, fully processed
+ * postview image is available (NOTE: not all hardware supports
+ * this). The jpeg callback occurs when the compressed image is
+ * available. If the application does not need a particular
+ * callback, a null can be passed instead of a callback method.
+ *
+ * @param shutter callback after the image is captured, may be null
+ * @param raw callback with raw image data, may be null
+ * @param postview callback with postview image data, may be null
+ * @param jpeg callback with jpeg image data, may be null
+ */
+ public final void takePicture(ShutterCallback shutter, PictureCallback raw,
+ PictureCallback postview, PictureCallback jpeg) {
mShutterCallback = shutter;
mRawImageCallback = raw;
+ mPostviewCallback = postview;
mJpegCallback = jpeg;
native_takePicture();
}
- private native final void native_takePicture();
+ /**
+ * Handles the zoom callback.
+ */
+ public interface ZoomCallback
+ {
+ /**
+ * Callback for zoom updates
+ * @param zoomLevel new zoom level in 1/1000 increments,
+ * e.g. a zoom of 3.2x is stored as 3200. Accuracy of the
+ * value is dependent on the hardware implementation. Not
+ * all devices will generate this callback.
+ * @param camera the Camera service object
+ */
+ void onZoomUpdate(int zoomLevel, Camera camera);
+ };
+
+ /**
+ * Registers a callback to be invoked when the zoom
+ * level is updated by the camera driver.
+ * @param cb the callback to run
+ */
+ public final void setZoomCallback(ZoomCallback cb)
+ {
+ mZoomCallback = cb;
+ }
+
// These match the enum in include/ui/Camera.h
/** Unspecified camerar error. @see #ErrorCallback */
public static final int CAMERA_ERROR_UNKNOWN = 1;
diff --git a/core/java/android/hardware/SensorListener.java b/core/java/android/hardware/SensorListener.java
index cfa184b..c71e968 100644
--- a/core/java/android/hardware/SensorListener.java
+++ b/core/java/android/hardware/SensorListener.java
@@ -20,9 +20,8 @@ package android.hardware;
* Used for receiving notifications from the SensorManager when
* sensor values have changed.
*
- * This interface is deprecated, use
+ * @deprecated Use
* {@link android.hardware.SensorEventListener SensorEventListener} instead.
- *
*/
@Deprecated
public interface SensorListener {
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index bf945ec..271f973 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -116,47 +116,67 @@ public class SensorManager
@Deprecated
public static final int SENSOR_ORIENTATION_RAW = 1 << 7;
- /** A constant that includes all sensors */
+ /** A constant that includes all sensors
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int SENSOR_ALL = 0x7F;
- /** Smallest sensor ID */
+ /** Smallest sensor ID
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int SENSOR_MIN = SENSOR_ORIENTATION;
- /** Largest sensor ID */
+ /** Largest sensor ID
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1);
/** Index of the X value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int DATA_X = 0;
/** Index of the Y value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int DATA_Y = 1;
/** Index of the Z value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int DATA_Z = 2;
/** Offset to the untransformed values in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int RAW_DATA_INDEX = 3;
/** Index of the untransformed X value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int RAW_DATA_X = 3;
/** Index of the untransformed Y value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int RAW_DATA_Y = 4;
/** Index of the untransformed Z value in the array returned by
- * {@link android.hardware.SensorListener#onSensorChanged} */
+ * {@link android.hardware.SensorListener#onSensorChanged}
+ * @deprecated use {@link android.hardware.Sensor Sensor} instead.
+ */
@Deprecated
public static final int RAW_DATA_Z = 5;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 6ee92ce..1f640ea 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1992,8 +1992,9 @@ public class InputMethodService extends AbstractInputMethodService {
req.flags = InputConnection.GET_TEXT_WITH_STYLES;
req.hintMaxLines = 10;
req.hintMaxChars = 10000;
- mExtractedText = getCurrentInputConnection().getExtractedText(req,
- InputConnection.GET_EXTRACTED_TEXT_MONITOR);
+ InputConnection ic = getCurrentInputConnection();
+ mExtractedText = ic == null? null
+ : ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
final EditorInfo ei = getCurrentInputEditorInfo();
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
index fea63be..4814b0a 100755
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -142,7 +142,7 @@ public class Keyboard {
private int[][] mGridNeighbors;
private int mProximityThreshold;
/** Number of key widths from current touch point to search for nearest keys. */
- private static float SEARCH_DISTANCE = 1.4f;
+ private static float SEARCH_DISTANCE = 1.8f;
/**
* Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 9c9c143..a141a2a 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -30,7 +30,6 @@ import android.graphics.drawable.Drawable;
import android.inputmethodservice.Keyboard.Key;
import android.os.Handler;
import android.os.Message;
-import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.GestureDetector;
@@ -38,6 +37,7 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewGroup.LayoutParams;
import android.widget.PopupWindow;
import android.widget.TextView;
@@ -163,8 +163,8 @@ public class KeyboardView extends View implements View.OnClickListener {
private static final int MSG_REPEAT = 3;
private static final int MSG_LONGPRESS = 4;
- private static final int DELAY_BEFORE_PREVIEW = 40;
- private static final int DELAY_AFTER_PREVIEW = 60;
+ private static final int DELAY_BEFORE_PREVIEW = 0;
+ private static final int DELAY_AFTER_PREVIEW = 70;
private int mVerticalCorrection;
private int mProximityThreshold;
@@ -202,13 +202,17 @@ public class KeyboardView extends View implements View.OnClickListener {
private boolean mAbortKey;
private Key mInvalidatedKey;
private Rect mClipRegion = new Rect(0, 0, 0, 0);
-
+
+ // Variables for dealing with multiple pointers
+ private int mOldPointerCount = 1;
+ private float mOldPointerX;
+ private float mOldPointerY;
+
private Drawable mKeyBackground;
private static final int REPEAT_INTERVAL = 50; // ~20 keys per second
private static final int REPEAT_START_DELAY = 400;
- private static final int LONGPRESS_TIMEOUT = 800;
- // Deemed to be too short : ViewConfiguration.getLongPressTimeout();
+ private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
private static int MAX_NEARBY_KEYS = 12;
private int[] mDistances = new int[MAX_NEARBY_KEYS];
@@ -227,6 +231,8 @@ public class KeyboardView extends View implements View.OnClickListener {
private Rect mDirtyRect = new Rect();
/** The keyboard bitmap for faster updates */
private Bitmap mBuffer;
+ /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */
+ private boolean mKeyboardChanged;
/** The canvas for the above mutable keyboard bitmap */
private Canvas mCanvas;
@@ -340,6 +346,7 @@ public class KeyboardView extends View implements View.OnClickListener {
mPaint.setAntiAlias(true);
mPaint.setTextSize(keyTextSize);
mPaint.setTextAlign(Align.CENTER);
+ mPaint.setAlpha(255);
mPadding = new Rect(0, 0, 0, 0);
mMiniKeyboardCache = new HashMap<Key,View>();
@@ -405,12 +412,14 @@ public class KeyboardView extends View implements View.OnClickListener {
List<Key> keys = mKeyboard.getKeys();
mKeys = keys.toArray(new Key[keys.size()]);
requestLayout();
- // Release buffer, just in case the new keyboard has a different size.
- // It will be reallocated on the next draw.
- mBuffer = null;
+ // Hint to reallocate the buffer if the size changed
+ mKeyboardChanged = true;
invalidateAllKeys();
computeProximityThreshold(keyboard);
mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views
+ // Switching to a different keyboard should abort any pending keys so that the key up
+ // doesn't get delivered to the old or new keyboard
+ mAbortKey = true; // Until the next ACTION_DOWN
}
/**
@@ -564,17 +573,21 @@ public class KeyboardView extends View implements View.OnClickListener {
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
- if (mDrawPending || mBuffer == null) {
+ if (mDrawPending || mBuffer == null || mKeyboardChanged) {
onBufferDraw();
}
canvas.drawBitmap(mBuffer, 0, 0, null);
}
-
+
private void onBufferDraw() {
- if (mBuffer == null) {
- mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
- mCanvas = new Canvas(mBuffer);
+ if (mBuffer == null || mKeyboardChanged) {
+ if (mBuffer == null || mKeyboardChanged &&
+ (mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) {
+ mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+ mCanvas = new Canvas(mBuffer);
+ }
invalidateAllKeys();
+ mKeyboardChanged = false;
}
final Canvas canvas = mCanvas;
canvas.clipRect(mDirtyRect, Op.REPLACE);
@@ -590,7 +603,6 @@ public class KeyboardView extends View implements View.OnClickListener {
final Key[] keys = mKeys;
final Key invalidKey = mInvalidatedKey;
- paint.setAlpha(255);
paint.setColor(mKeyTextColor);
boolean drawSingleKey = false;
if (invalidKey != null && canvas.getClipBounds(clipRegion)) {
@@ -611,7 +623,7 @@ public class KeyboardView extends View implements View.OnClickListener {
}
int[] drawableState = key.getCurrentDrawableState();
keyBackground.setState(drawableState);
-
+
// Switch the character to uppercase if shift is pressed
String label = key.label == null? null : adjustCase(key.label).toString();
@@ -680,7 +692,6 @@ public class KeyboardView extends View implements View.OnClickListener {
private int getKeyIndices(int x, int y, int[] allKeys) {
final Key[] keys = mKeys;
- final boolean shifted = mKeyboard.isShifted();
int primaryIndex = NOT_A_KEY;
int closestKey = NOT_A_KEY;
int closestKeyDist = mProximityThreshold + 1;
@@ -1011,19 +1022,56 @@ public class KeyboardView extends View implements View.OnClickListener {
}
return false;
}
-
+
@Override
public boolean onTouchEvent(MotionEvent me) {
+ // Convert multi-pointer up/down events to single up/down events to
+ // deal with the typical multi-pointer behavior of two-thumb typing
+ int pointerCount = me.getPointerCount();
+ boolean result = false;
+ if (pointerCount != mOldPointerCount) {
+ long now = me.getEventTime();
+ if (pointerCount == 1) {
+ // Send a down event for the latest pointer
+ MotionEvent down = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
+ me.getX(), me.getY(), me.getMetaState());
+ result = onModifiedTouchEvent(down);
+ down.recycle();
+ // If it's an up action, then deliver the up as well.
+ if (me.getAction() == MotionEvent.ACTION_UP) {
+ result = onModifiedTouchEvent(me);
+ }
+ } else {
+ // Send an up event for the last pointer
+ MotionEvent up = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP,
+ mOldPointerX, mOldPointerY, me.getMetaState());
+ result = onModifiedTouchEvent(up);
+ up.recycle();
+ }
+ } else {
+ if (pointerCount == 1) {
+ mOldPointerX = me.getX();
+ mOldPointerY = me.getY();
+ result = onModifiedTouchEvent(me);
+ } else {
+ // Don't do anything when 2 pointers are down and moving.
+ result = true;
+ }
+ }
+ mOldPointerCount = pointerCount;
+ return result;
+ }
+
+ private boolean onModifiedTouchEvent(MotionEvent me) {
int touchX = (int) me.getX() - mPaddingLeft;
int touchY = (int) me.getY() + mVerticalCorrection - mPaddingTop;
int action = me.getAction();
long eventTime = me.getEventTime();
int keyIndex = getKeyIndices(touchX, touchY, null);
-
if (mGestureDetector.onTouchEvent(me)) {
showPreview(NOT_A_KEY);
mHandler.removeMessages(MSG_REPEAT);
- mHandler.removeMessages(MSG_LONGPRESS);
+ mHandler.removeMessages(MSG_LONGPRESS);
return true;
}
@@ -1072,7 +1120,7 @@ public class KeyboardView extends View implements View.OnClickListener {
if (keyIndex == mCurrentKey) {
mCurrentKeyTime += eventTime - mLastMoveTime;
continueLongPress = true;
- } else {
+ } else if (mRepeatKeyIndex == NOT_A_KEY) {
resetMultiTap();
mLastKey = mCurrentKey;
mLastCodeX = mLastX;
@@ -1083,10 +1131,6 @@ public class KeyboardView extends View implements View.OnClickListener {
mCurrentKeyTime = 0;
}
}
- if (keyIndex != mRepeatKeyIndex) {
- mHandler.removeMessages(MSG_REPEAT);
- mRepeatKeyIndex = NOT_A_KEY;
- }
}
if (!continueLongPress) {
// Cancel old longpress
@@ -1097,7 +1141,7 @@ public class KeyboardView extends View implements View.OnClickListener {
mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT);
}
}
- showPreview(keyIndex);
+ showPreview(mCurrentKey);
break;
case MotionEvent.ACTION_UP:
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1429bc1..a127df0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -18,6 +18,7 @@ package android.net;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.os.Binder;
import android.os.RemoteException;
/**
@@ -114,15 +115,64 @@ public class ConnectivityManager
public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
"android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
- public static final int TYPE_MOBILE = 0;
- public static final int TYPE_WIFI = 1;
+ /**
+ * The Default Mobile data connection. When active, all data traffic
+ * will use this connection by default. Should not coexist with other
+ * default connections.
+ */
+ public static final int TYPE_MOBILE = 0;
+ /**
+ * The Default WIFI data connection. When active, all data traffic
+ * will use this connection by default. Should not coexist with other
+ * default connections.
+ */
+ public static final int TYPE_WIFI = 1;
+ /**
+ * An MMS-specific Mobile data connection. This connection may be the
+ * same as {@link #TYPEMOBILE} but it may be different. This is used
+ * by applications needing to talk to the carrier's Multimedia Messaging
+ * Service servers. It may coexist with default data connections.
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_MMS = 2;
+ /**
+ * A SUPL-specific Mobile data connection. This connection may be the
+ * same as {@link #TYPEMOBILE} but it may be different. This is used
+ * by applications needing to talk to the carrier's Secure User Plane
+ * Location servers for help locating the device. It may coexist with
+ * default data connections.
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_SUPL = 3;
+ /**
+ * A DUN-specific Mobile data connection. This connection may be the
+ * same as {@link #TYPEMOBILE} but it may be different. This is used
+ * by applicaitons performing a Dial Up Networking bridge so that
+ * the carrier is aware of DUN traffic. It may coexist with default data
+ * connections.
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_DUN = 4;
+ /**
+ * A High Priority Mobile data connection. This connection is typically
+ * the same as {@link #TYPEMOBILE} but the routing setup is different.
+ * Only requesting processes will have access to the Mobile DNS servers
+ * and only IP's explicitly requested via {@link #requestRouteToHost}
+ * will route over this interface.
+ *{@hide}
+ */
+ public static final int TYPE_MOBILE_HIPRI = 5;
+ /** {@hide} */
+ public static final int MAX_RADIO_TYPE = TYPE_WIFI;
+ /** {@hide} */
+ public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_HIPRI;
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
private IConnectivityManager mService;
static public boolean isNetworkTypeValid(int networkType) {
- return networkType == TYPE_WIFI || networkType == TYPE_MOBILE;
+ return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
}
public void setNetworkPreference(int preference) {
@@ -195,7 +245,8 @@ public class ConnectivityManager
*/
public int startUsingNetworkFeature(int networkType, String feature) {
try {
- return mService.startUsingNetworkFeature(networkType, feature);
+ return mService.startUsingNetworkFeature(networkType, feature,
+ new Binder());
} catch (RemoteException e) {
return -1;
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index de68598..9f59cce 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -17,6 +17,7 @@
package android.net;
import android.net.NetworkInfo;
+import android.os.IBinder;
/**
* Interface that answers queries about, and allows changing, the
@@ -39,7 +40,8 @@ interface IConnectivityManager
boolean setRadio(int networkType, boolean turnOn);
- int startUsingNetworkFeature(int networkType, in String feature);
+ int startUsingNetworkFeature(int networkType, in String feature,
+ in IBinder binder);
int stopUsingNetworkFeature(int networkType, in String feature);
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 1064fb6..f88fcdc 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -32,9 +32,6 @@ import android.telephony.TelephonyManager;
import android.util.Log;
import android.text.TextUtils;
-import java.util.List;
-import java.util.ArrayList;
-
/**
* Track the state of mobile data connectivity. This is done by
* receiving broadcast intents from the Phone process whenever
@@ -45,36 +42,48 @@ import java.util.ArrayList;
public class MobileDataStateTracker extends NetworkStateTracker {
private static final String TAG = "MobileDataStateTracker";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private Phone.DataState mMobileDataState;
private ITelephony mPhoneService;
- private static final String[] sDnsPropNames = {
- "net.rmnet0.dns1",
- "net.rmnet0.dns2",
- "net.eth0.dns1",
- "net.eth0.dns2",
- "net.eth0.dns3",
- "net.eth0.dns4",
- "net.gprs.dns1",
- "net.gprs.dns2"
- };
- private List<String> mDnsServers;
- private String mInterfaceName;
- private int mDefaultGatewayAddr;
- private int mLastCallingPid = -1;
+
+ private String mApnType;
+ private boolean mEnabled;
+ private BroadcastReceiver mStateReceiver;
/**
* Create a new MobileDataStateTracker
* @param context the application context of the caller
* @param target a message handler for getting callbacks about state changes
+ * @param netType the ConnectivityManager network type
+ * @param apnType the Phone apnType
+ * @param tag the name of this network
*/
- public MobileDataStateTracker(Context context, Handler target) {
- super(context, target, ConnectivityManager.TYPE_MOBILE,
- TelephonyManager.getDefault().getNetworkType(), "MOBILE",
- TelephonyManager.getDefault().getNetworkTypeName());
+ public MobileDataStateTracker(Context context, Handler target,
+ int netType, String apnType, String tag) {
+ super(context, target, netType,
+ TelephonyManager.getDefault().getNetworkType(), tag,
+ TelephonyManager.getDefault().getNetworkTypeName());
+ mApnType = apnType;
mPhoneService = null;
- mDnsServers = new ArrayList<String>();
+ if(netType == ConnectivityManager.TYPE_MOBILE) {
+ mEnabled = true;
+ } else {
+ mEnabled = false;
+ }
+
+ mDnsPropNames = new String[] {
+ "net.rmnet0.dns1",
+ "net.rmnet0.dns2",
+ "net.eth0.dns1",
+ "net.eth0.dns2",
+ "net.eth0.dns3",
+ "net.eth0.dns4",
+ "net.gprs.dns1",
+ "net.gprs.dns2",
+ "net.ppp0.dns1",
+ "net.ppp0.dns2"};
+
}
/**
@@ -86,105 +95,128 @@ public class MobileDataStateTracker extends NetworkStateTracker {
filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
- Intent intent = mContext.registerReceiver(new MobileDataStateReceiver(), filter);
+ mStateReceiver = new MobileDataStateReceiver();
+ Intent intent = mContext.registerReceiver(mStateReceiver, filter);
if (intent != null)
mMobileDataState = getMobileDataState(intent);
else
mMobileDataState = Phone.DataState.DISCONNECTED;
}
- private static Phone.DataState getMobileDataState(Intent intent) {
+ private Phone.DataState getMobileDataState(Intent intent) {
String str = intent.getStringExtra(Phone.STATE_KEY);
- if (str != null)
- return Enum.valueOf(Phone.DataState.class, str);
- else
- return Phone.DataState.DISCONNECTED;
- }
-
- private class MobileDataStateReceiver extends BroadcastReceiver {
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
- Phone.DataState state = getMobileDataState(intent);
- String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
- String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
- boolean unavailable = intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY, false);
- if (DBG) Log.d(TAG, "Received " + intent.getAction() +
- " broadcast - state = " + state
- + ", unavailable = " + unavailable
- + ", reason = " + (reason == null ? "(unspecified)" : reason));
- mNetworkInfo.setIsAvailable(!unavailable);
- if (mMobileDataState != state) {
- mMobileDataState = state;
-
- switch (state) {
- case DISCONNECTED:
- setDetailedState(DetailedState.DISCONNECTED, reason, apnName);
- if (mInterfaceName != null) {
- NetworkUtils.resetConnections(mInterfaceName);
- }
- mInterfaceName = null;
- mDefaultGatewayAddr = 0;
- break;
- case CONNECTING:
- setDetailedState(DetailedState.CONNECTING, reason, apnName);
- break;
- case SUSPENDED:
- setDetailedState(DetailedState.SUSPENDED, reason, apnName);
- break;
- case CONNECTED:
- mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY);
- if (mInterfaceName == null) {
- Log.d(TAG, "CONNECTED event did not supply interface name.");
- }
- setupDnsProperties();
- setDetailedState(DetailedState.CONNECTED, reason, apnName);
- break;
- }
- }
- } else if (intent.getAction().equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) {
- String reason = intent.getStringExtra(Phone.FAILURE_REASON_KEY);
- String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
- if (DBG) Log.d(TAG, "Received " + intent.getAction() + " broadcast" +
- reason == null ? "" : "(" + reason + ")");
- setDetailedState(DetailedState.FAILED, reason, apnName);
+ if (str != null) {
+ String apnTypeList =
+ intent.getStringExtra(Phone.DATA_APN_TYPES_KEY);
+ if (isApnTypeIncluded(apnTypeList)) {
+ return Enum.valueOf(Phone.DataState.class, str);
}
- TelephonyManager tm = TelephonyManager.getDefault();
- setRoamingStatus(tm.isNetworkRoaming());
- setSubtype(tm.getNetworkType(), tm.getNetworkTypeName());
}
+ return Phone.DataState.DISCONNECTED;
}
- /**
- * Make sure that route(s) exist to the carrier DNS server(s).
- */
- public void addPrivateRoutes() {
- if (mInterfaceName != null) {
- for (String addrString : mDnsServers) {
- int addr = NetworkUtils.lookupHost(addrString);
- if (addr != -1) {
- NetworkUtils.addHostRoute(mInterfaceName, addr);
- }
- }
- }
- }
+ private boolean isApnTypeIncluded(String typeList) {
+ /* comma seperated list - split and check */
+ if (typeList == null)
+ return false;
- public void removePrivateRoutes() {
- if(mInterfaceName != null) {
- NetworkUtils.removeHostRoutes(mInterfaceName);
+ String[] list = typeList.split(",");
+ for(int i=0; i< list.length; i++) {
+ if (TextUtils.equals(list[i], mApnType) ||
+ TextUtils.equals(list[i], Phone.APN_TYPE_ALL)) {
+ return true;
+ }
}
+ return false;
}
- public void removeDefaultRoute() {
- if(mInterfaceName != null) {
- mDefaultGatewayAddr = NetworkUtils.getDefaultRoute(mInterfaceName);
- NetworkUtils.removeDefaultRoute(mInterfaceName);
- }
- }
+ private class MobileDataStateReceiver extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ synchronized(this) {
+ if (intent.getAction().equals(TelephonyIntents.
+ ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
+ Phone.DataState state = getMobileDataState(intent);
+ String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
+ String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
+ String apnTypeList = intent.getStringExtra(Phone.DATA_APN_TYPES_KEY);
+
+ boolean unavailable = intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY,
+ false);
+ if (DBG) Log.d(TAG, mApnType + " Received " + intent.getAction() +
+ " broadcast - state = " + state + ", oldstate = " + mMobileDataState +
+ ", unavailable = " + unavailable + ", reason = " +
+ (reason == null ? "(unspecified)" : reason));
+
+
+ if (isApnTypeIncluded(apnTypeList)) {
+ // set this even if the apn isn't Enabled
+ mNetworkInfo.setIsAvailable(!unavailable);
+ if (mEnabled == false) {
+ // if we're not enabled but the APN Type is supported by this connection
+ // we should record the interface name if one's provided. If the user
+ // turns on this network we will need the interfacename but won't get
+ // a fresh connected message - TODO fix this..
+ if (state == Phone.DataState.CONNECTED) {
+ if (DBG) Log.d(TAG, "replacing old mInterfaceName (" +
+ mInterfaceName + ") with " +
+ intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY) +
+ " for " + mApnType);
+ mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY);
+ }
+ if (DBG) Log.d(TAG, " dropped - mEnabled = false");
+ return;
+ }
+ } else {
+ if (DBG) Log.d(TAG, " dropped - wrong Apn");
+ return;
+ }
- public void restoreDefaultRoute() {
- // 0 is not a valid address for a gateway
- if (mInterfaceName != null && mDefaultGatewayAddr != 0) {
- NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr);
+ if (mMobileDataState != state) {
+ mMobileDataState = state;
+ switch (state) {
+ case DISCONNECTED:
+ if(isTeardownRequested()) {
+ mEnabled = false;
+ setTeardownRequested(false);
+ }
+
+ setDetailedState(DetailedState.DISCONNECTED, reason, apnName);
+ if (mInterfaceName != null) {
+ NetworkUtils.resetConnections(mInterfaceName);
+ }
+ if (DBG) Log.d(TAG, "clearing mInterfaceName for "+ mApnType +
+ " as it DISCONNECTED");
+ mInterfaceName = null;
+ mDefaultGatewayAddr = 0;
+ break;
+ case CONNECTING:
+ setDetailedState(DetailedState.CONNECTING, reason, apnName);
+ break;
+ case SUSPENDED:
+ setDetailedState(DetailedState.SUSPENDED, reason, apnName);
+ break;
+ case CONNECTED:
+ mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY);
+ if (mInterfaceName == null) {
+ Log.d(TAG, "CONNECTED event did not supply interface name.");
+ }
+ setDetailedState(DetailedState.CONNECTED, reason, apnName);
+ break;
+ }
+ }
+ } else if (intent.getAction().
+ equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) {
+ mEnabled = false;
+ String reason = intent.getStringExtra(Phone.FAILURE_REASON_KEY);
+ String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
+ if (DBG) Log.d(TAG, "Received " + intent.getAction() + " broadcast" +
+ reason == null ? "" : "(" + reason + ")");
+ setDetailedState(DetailedState.FAILED, reason, apnName);
+ }
+ TelephonyManager tm = TelephonyManager.getDefault();
+ setRoamingStatus(tm.isNetworkRoaming());
+ setSubtype(tm.getNetworkType(), tm.getNetworkTypeName());
+ }
}
}
@@ -219,15 +251,6 @@ public class MobileDataStateTracker extends NetworkStateTracker {
}
/**
- * Return the IP addresses of the DNS servers available for the mobile data
- * network interface.
- * @return a list of DNS addresses, with no holes.
- */
- public String[] getNameServers() {
- return getNameServerList(sDnsPropNames);
- }
-
- /**
* {@inheritDoc}
* The mobile data network subtype indicates what generation network technology is in effect,
* e.g., GPRS, EDGE, UMTS, etc.
@@ -254,9 +277,21 @@ public class MobileDataStateTracker extends NetworkStateTracker {
case TelephonyManager.NETWORK_TYPE_UMTS:
networkTypeStr = "umts";
break;
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ networkTypeStr = "hsdpa";
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ networkTypeStr = "hsupa";
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ networkTypeStr = "hspa";
+ break;
case TelephonyManager.NETWORK_TYPE_CDMA:
networkTypeStr = "cdma";
break;
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ networkTypeStr = "1xrtt";
+ break;
case TelephonyManager.NETWORK_TYPE_EVDO_0:
networkTypeStr = "evdo";
break;
@@ -273,54 +308,51 @@ public class MobileDataStateTracker extends NetworkStateTracker {
*/
@Override
public boolean teardown() {
- getPhoneService(false);
- /*
- * If the phone process has crashed in the past, we'll get a
- * RemoteException and need to re-reference the service.
- */
- for (int retry = 0; retry < 2; retry++) {
- if (mPhoneService == null) {
- Log.w(TAG,
- "Ignoring mobile data teardown request because could not acquire PhoneService");
- break;
- }
-
- try {
- return mPhoneService.disableDataConnectivity();
- } catch (RemoteException e) {
- if (retry == 0) getPhoneService(true);
- }
- }
-
- Log.w(TAG, "Failed to tear down mobile data connectivity");
- return false;
+ setTeardownRequested(true);
+ return (setEnableApn(mApnType, false) != Phone.APN_REQUEST_FAILED);
}
/**
* Re-enable mobile data connectivity after a {@link #teardown()}.
*/
public boolean reconnect() {
- getPhoneService(false);
- /*
- * If the phone process has crashed in the past, we'll get a
- * RemoteException and need to re-reference the service.
- */
- for (int retry = 0; retry < 2; retry++) {
- if (mPhoneService == null) {
- Log.w(TAG,
- "Ignoring mobile data connect request because could not acquire PhoneService");
+ setTeardownRequested(false);
+ switch (setEnableApn(mApnType, true)) {
+ case Phone.APN_ALREADY_ACTIVE:
+ mEnabled = true;
+ // need to set self to CONNECTING so the below message is handled.
+ mMobileDataState = Phone.DataState.CONNECTING;
+ setDetailedState(DetailedState.CONNECTING, Phone.REASON_APN_CHANGED, null);
+ //send out a connected message
+ Intent intent = new Intent(TelephonyIntents.
+ ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
+ intent.putExtra(Phone.STATE_KEY, Phone.DataState.CONNECTED.toString());
+ intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, Phone.REASON_APN_CHANGED);
+ intent.putExtra(Phone.DATA_APN_TYPES_KEY, mApnType);
+ intent.putExtra(Phone.DATA_IFACE_NAME_KEY, mInterfaceName);
+ intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, false);
+ if (mStateReceiver != null) mStateReceiver.onReceive(mContext, intent);
+ break;
+ case Phone.APN_REQUEST_STARTED:
+ mEnabled = true;
+ // no need to do anything - we're already due some status update intents
+ break;
+ case Phone.APN_REQUEST_FAILED:
+ if (mPhoneService == null && mApnType == Phone.APN_TYPE_DEFAULT) {
+ // on startup we may try to talk to the phone before it's ready
+ // just leave mEnabled as it is for the default apn.
+ return false;
+ }
+ // else fall through
+ case Phone.APN_TYPE_NOT_AVAILABLE:
+ mEnabled = false;
+ break;
+ default:
+ Log.e(TAG, "Error in reconnect - unexpected response.");
+ mEnabled = false;
break;
- }
-
- try {
- return mPhoneService.enableDataConnectivity();
- } catch (RemoteException e) {
- if (retry == 0) getPhoneService(true);
- }
}
-
- Log.w(TAG, "Failed to set up mobile data connectivity");
- return false;
+ return mEnabled;
}
/**
@@ -374,14 +406,7 @@ public class MobileDataStateTracker extends NetworkStateTracker {
* </ul>
*/
public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
- if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
- mLastCallingPid = callingPid;
- return setEnableApn(Phone.APN_TYPE_MMS, true);
- } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
- return setEnableApn(Phone.APN_TYPE_SUPL, true);
- } else {
- return -1;
- }
+ return -1;
}
/**
@@ -397,13 +422,7 @@ public class MobileDataStateTracker extends NetworkStateTracker {
* the value {@code -1} always indicates failure.
*/
public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
- if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
- return setEnableApn(Phone.APN_TYPE_MMS, false);
- } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
- return setEnableApn(Phone.APN_TYPE_SUPL, false);
- } else {
- return -1;
- }
+ return -1;
}
/**
@@ -415,10 +434,11 @@ public class MobileDataStateTracker extends NetworkStateTracker {
*/
@Override
public boolean requestRouteToHost(int hostAddress) {
+ if (DBG) {
+ Log.d(TAG, "Requested host route to " + Integer.toHexString(hostAddress) +
+ " for " + mApnType + "(" + mInterfaceName + ")");
+ }
if (mInterfaceName != null && hostAddress != -1) {
- if (DBG) {
- Log.d(TAG, "Requested host route to " + Integer.toHexString(hostAddress));
- }
return NetworkUtils.addHostRoute(mInterfaceName, hostAddress) == 0;
} else {
return false;
@@ -433,43 +453,6 @@ public class MobileDataStateTracker extends NetworkStateTracker {
return sb.toString();
}
- private void setupDnsProperties() {
- mDnsServers.clear();
- // Set up per-process DNS server list on behalf of the MMS process
- int i = 1;
- if (mInterfaceName != null) {
- for (String propName : sDnsPropNames) {
- if (propName.indexOf(mInterfaceName) != -1) {
- String propVal = SystemProperties.get(propName);
- if (propVal != null && propVal.length() != 0 && !propVal.equals("0.0.0.0")) {
- mDnsServers.add(propVal);
- if (mLastCallingPid != -1) {
- SystemProperties.set("net.dns" + i + "." + mLastCallingPid, propVal);
- }
- ++i;
- }
- }
- }
- }
- if (i == 1) {
- Log.d(TAG, "DNS server addresses are not known.");
- } else if (mLastCallingPid != -1) {
- /*
- * Bump the property that tells the name resolver library
- * to reread the DNS server list from the properties.
- */
- String propVal = SystemProperties.get("net.dnschange");
- if (propVal.length() != 0) {
- try {
- int n = Integer.parseInt(propVal);
- SystemProperties.set("net.dnschange", "" + (n+1));
- } catch (NumberFormatException e) {
- }
- }
- }
- mLastCallingPid = -1;
- }
-
/**
* Internal method supporting the ENABLE_MMS feature.
* @param apnType the type of APN to be enabled or disabled (e.g., mms)
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index 37087ac..54529ae 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -27,6 +27,7 @@ import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
+
/**
* Each subclass of this class keeps track of the state of connectivity
* of a network interface. All state information for a network should
@@ -40,11 +41,16 @@ public abstract class NetworkStateTracker extends Handler {
protected NetworkInfo mNetworkInfo;
protected Context mContext;
protected Handler mTarget;
+ protected String mInterfaceName;
+ protected String[] mDnsPropNames;
+ private boolean mPrivateDnsRouteSet;
+ protected int mDefaultGatewayAddr;
+ private boolean mDefaultRouteSet;
private boolean mTeardownRequested;
- private static boolean DBG = Config.LOGV;
+ private static boolean DBG = true;
private static final String TAG = "NetworkStateTracker";
-
+
public static final int EVENT_STATE_CHANGED = 1;
public static final int EVENT_SCAN_RESULTS_AVAILABLE = 2;
/**
@@ -56,6 +62,7 @@ public abstract class NetworkStateTracker extends Handler {
public static final int EVENT_CONFIGURATION_CHANGED = 4;
public static final int EVENT_ROAMING_CHANGED = 5;
public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6;
+ public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7;
public NetworkStateTracker(Context context,
Handler target,
@@ -67,6 +74,7 @@ public abstract class NetworkStateTracker extends Handler {
mContext = context;
mTarget = target;
mTeardownRequested = false;
+
this.mNetworkInfo = new NetworkInfo(networkType, subType, typeName, subtypeName);
}
@@ -75,19 +83,21 @@ public abstract class NetworkStateTracker extends Handler {
}
/**
- * Return the list of DNS servers associated with this network.
- * @return a list of the IP addresses of the DNS servers available
- * for the network.
- */
- public abstract String[] getNameServers();
-
- /**
* Return the system properties name associated with the tcp buffer sizes
* for this network.
*/
public abstract String getTcpBufferSizesPropName();
/**
+ * Return the IP addresses of the DNS servers available for the mobile data
+ * network interface.
+ * @return a list of DNS addresses, with no holes.
+ */
+ public String[] getNameServers() {
+ return getNameServerList(mDnsPropNames);
+ }
+
+ /**
* Return the IP addresses of the DNS servers available for this
* network interface.
* @param propertyNames the names of the system properties whose values
@@ -112,6 +122,50 @@ public abstract class NetworkStateTracker extends Handler {
return dnsAddresses;
}
+ public void addPrivateDnsRoutes() {
+ if (DBG) Log.d(TAG, "addPrivateDnsRoutes for " + this +
+ "(" + mInterfaceName + ")");
+ if (mInterfaceName != null && !mPrivateDnsRouteSet) {
+ for (String addrString : getNameServers()) {
+ int addr = NetworkUtils.lookupHost(addrString);
+ if (addr != -1) {
+ NetworkUtils.addHostRoute(mInterfaceName, addr);
+ }
+ }
+ mPrivateDnsRouteSet = true;
+ }
+ }
+
+ public void removePrivateDnsRoutes() {
+ if (DBG) Log.d(TAG, "removePrivateDnsRoutes for " + this +
+ "(" + mInterfaceName + ")");
+ // TODO - we should do this explicitly but the NetUtils api doesnt
+ // support this yet - must remove all. No worse than before
+ if (mInterfaceName != null && mPrivateDnsRouteSet) {
+ NetworkUtils.removeHostRoutes(mInterfaceName);
+ mPrivateDnsRouteSet = false;
+ }
+ }
+
+ public void addDefaultRoute() {
+ if (DBG) Log.d(TAG, "addDefaultRoute for " + this + "(" +
+ mInterfaceName + "), GatewayAddr=" + mDefaultGatewayAddr);
+ if ((mInterfaceName != null) && (mDefaultGatewayAddr != 0) &&
+ mDefaultRouteSet == false) {
+ NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr);
+ mDefaultRouteSet = true;
+ }
+ }
+
+ public void removeDefaultRoute() {
+ if (DBG) Log.d(TAG, "removeDefaultRoute for " + this + "(" +
+ mInterfaceName + ")");
+ if (mInterfaceName != null && mDefaultRouteSet == true) {
+ NetworkUtils.removeDefaultRoute(mInterfaceName);
+ mDefaultRouteSet = false;
+ }
+ }
+
/**
* Reads the network specific TCP buffer sizes from SystemProperties
* net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
@@ -209,6 +263,7 @@ public abstract class NetworkStateTracker extends Handler {
* @param extraInfo optional {@code String} providing extra information about the state change
*/
public void setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo) {
+ if (DBG) Log.d(TAG, "setDetailed state, old ="+mNetworkInfo.getDetailedState()+" and new state="+state);
if (state != mNetworkInfo.getDetailedState()) {
boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING);
String lastReason = mNetworkInfo.getReason();
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 1153648..a3ae01b 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -25,6 +25,9 @@ import java.net.UnknownHostException;
* {@hide}
*/
public class NetworkUtils {
+ /** Bring the named network interface up. */
+ public native static int enableInterface(String interfaceName);
+
/** Bring the named network interface down. */
public native static int disableInterface(String interfaceName);
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 421d013..298be3b 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -374,7 +374,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
/**
* Creates a Uri which parses the given encoded URI string.
*
- * @param uriString an RFC 3296-compliant, encoded URI
+ * @param uriString an RFC 2396-compliant, encoded URI
* @throws NullPointerException if uriString is null
* @return Uri for this given uri string
*/
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/ConnectionThread.java b/core/java/android/net/http/ConnectionThread.java
index 8e759e2..0b30e58 100644
--- a/core/java/android/net/http/ConnectionThread.java
+++ b/core/java/android/net/http/ConnectionThread.java
@@ -32,8 +32,8 @@ class ConnectionThread extends Thread {
static final int WAIT_TICK = 1000;
// Performance probe
- long mStartThreadTime;
long mCurrentThreadTime;
+ long mTotalThreadTime;
private boolean mWaiting;
private volatile boolean mRunning = true;
@@ -69,12 +69,21 @@ class ConnectionThread extends Thread {
*/
public void run() {
android.os.Process.setThreadPriority(
+ android.os.Process.THREAD_PRIORITY_DEFAULT +
android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
- mStartThreadTime = -1;
- mCurrentThreadTime = SystemClock.currentThreadTimeMillis();
+ // these are used to get performance data. When it is not in the timing,
+ // mCurrentThreadTime is 0. When it starts timing, mCurrentThreadTime is
+ // first set to -1, it will be set to the current thread time when the
+ // next request starts.
+ mCurrentThreadTime = 0;
+ mTotalThreadTime = 0;
while (mRunning) {
+ if (mCurrentThreadTime == -1) {
+ mCurrentThreadTime = SystemClock.currentThreadTimeMillis();
+ }
+
Request request;
/* Get a request to process */
@@ -86,14 +95,14 @@ class ConnectionThread extends Thread {
if (HttpLog.LOGV) HttpLog.v("ConnectionThread: Waiting for work");
mWaiting = true;
try {
- if (mStartThreadTime != -1) {
- mCurrentThreadTime = SystemClock
- .currentThreadTimeMillis();
- }
mRequestFeeder.wait();
} catch (InterruptedException e) {
}
mWaiting = false;
+ if (mCurrentThreadTime != 0) {
+ mCurrentThreadTime = SystemClock
+ .currentThreadTimeMillis();
+ }
}
} else {
if (HttpLog.LOGV) HttpLog.v("ConnectionThread: new request " +
@@ -123,6 +132,12 @@ class ConnectionThread extends Thread {
mConnection.closeConnection();
}
mConnection = null;
+
+ if (mCurrentThreadTime > 0) {
+ long start = mCurrentThreadTime;
+ mCurrentThreadTime = SystemClock.currentThreadTimeMillis();
+ mTotalThreadTime += mCurrentThreadTime - start;
+ }
}
}
diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java
index df4fff0..1b6568e 100644
--- a/core/java/android/net/http/Request.java
+++ b/core/java/android/net/http/Request.java
@@ -67,9 +67,6 @@ class Request {
/** Set if I'm using a proxy server */
HttpHost mProxyHost;
- /** True if request is .html, .js, .css */
- boolean mHighPriority;
-
/** True if request has been cancelled */
volatile boolean mCancelled = false;
@@ -102,26 +99,29 @@ class Request {
* @param eventHandler request will make progress callbacks on
* this interface
* @param headers reqeust headers
- * @param highPriority true for .html, css, .cs
*/
Request(String method, HttpHost host, HttpHost proxyHost, String path,
InputStream bodyProvider, int bodyLength,
EventHandler eventHandler,
- Map<String, String> headers, boolean highPriority) {
+ Map<String, String> headers) {
mEventHandler = eventHandler;
mHost = host;
mProxyHost = proxyHost;
mPath = path;
- mHighPriority = highPriority;
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());
@@ -255,6 +255,8 @@ class Request {
// process gzip content encoding
Header contentEncoding = entity.getContentEncoding();
InputStream nis = null;
+ byte[] buf = null;
+ int count = 0;
try {
if (contentEncoding != null &&
contentEncoding.getValue().equals("gzip")) {
@@ -265,9 +267,8 @@ class Request {
/* accumulate enough data to make it worth pushing it
* up the stack */
- byte[] buf = mConnection.getBuf();
+ buf = mConnection.getBuf();
int len = 0;
- int count = 0;
int lowWater = buf.length / 2;
while (len != -1) {
len = nis.read(buf, count, buf.length - count);
@@ -284,6 +285,10 @@ class Request {
/* InflaterInputStream throws an EOFException when the
server truncates gzipped content. Handle this case
as we do truncated non-gzipped content: no error */
+ if (count > 0) {
+ // if there is uncommited content, we should commit them
+ mEventHandler.data(buf, count);
+ }
if (HttpLog.LOGV) HttpLog.v( "readResponse() handling " + e);
} catch(IOException e) {
// don't throw if we have a non-OK status code
@@ -346,7 +351,7 @@ class Request {
* for debugging
*/
public String toString() {
- return (mHighPriority ? "P*" : "") + mPath;
+ return mPath;
}
@@ -412,8 +417,7 @@ class Request {
}
return status >= HttpStatus.SC_OK
&& status != HttpStatus.SC_NO_CONTENT
- && status != HttpStatus.SC_NOT_MODIFIED
- && status != HttpStatus.SC_RESET_CONTENT;
+ && status != HttpStatus.SC_NOT_MODIFIED;
}
/**
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
index 6a97951..190ae7a 100644
--- a/core/java/android/net/http/RequestHandle.java
+++ b/core/java/android/net/http/RequestHandle.java
@@ -419,6 +419,6 @@ public class RequestHandle {
mRequest = mRequestQueue.queueRequest(
mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler,
mBodyProvider,
- mBodyLength, mRequest.mHighPriority).mRequest;
+ mBodyLength).mRequest;
}
}
diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java
index 66d5722..e14af66 100644
--- a/core/java/android/net/http/RequestQueue.java
+++ b/core/java/android/net/http/RequestQueue.java
@@ -57,9 +57,6 @@ public class RequestQueue implements RequestFeeder {
*/
private LinkedHashMap<HttpHost, LinkedList<Request>> mPending;
- /* Support for notifying a client when queue is empty */
- private boolean mClientWaiting = false;
-
/** true if connected */
boolean mNetworkConnected = true;
@@ -245,7 +242,9 @@ public class RequestQueue implements RequestFeeder {
public void startTiming() {
for (int i = 0; i < mConnectionCount; i++) {
- mThreads[i].mStartThreadTime = mThreads[i].mCurrentThreadTime;
+ ConnectionThread rt = mThreads[i];
+ rt.mCurrentThreadTime = -1;
+ rt.mTotalThreadTime = 0;
}
mTotalRequest = 0;
mTotalConnection = 0;
@@ -255,12 +254,14 @@ public class RequestQueue implements RequestFeeder {
int totalTime = 0;
for (int i = 0; i < mConnectionCount; i++) {
ConnectionThread rt = mThreads[i];
- totalTime += (rt.mCurrentThreadTime - rt.mStartThreadTime);
- rt.mStartThreadTime = -1;
+ if (rt.mCurrentThreadTime != -1) {
+ totalTime += rt.mTotalThreadTime;
+ }
+ rt.mCurrentThreadTime = 0;
}
Log.d("Http", "Http thread used " + totalTime + " ms " + " for "
+ mTotalRequest + " requests and " + mTotalConnection
- + " connections");
+ + " new connections");
}
void logState() {
@@ -434,16 +435,14 @@ public class RequestQueue implements RequestFeeder {
* data. Callbacks will be made on the supplied instance.
* @param bodyProvider InputStream providing HTTP body, null if none
* @param bodyLength length of body, must be 0 if bodyProvider is null
- * @param highPriority If true, queues before low priority
- * requests if possible
*/
public RequestHandle queueRequest(
String url, String method,
Map<String, String> headers, EventHandler eventHandler,
- InputStream bodyProvider, int bodyLength, boolean highPriority) {
+ InputStream bodyProvider, int bodyLength) {
WebAddress uri = new WebAddress(url);
return queueRequest(url, uri, method, headers, eventHandler,
- bodyProvider, bodyLength, highPriority);
+ bodyProvider, bodyLength);
}
/**
@@ -456,14 +455,11 @@ public class RequestQueue implements RequestFeeder {
* data. Callbacks will be made on the supplied instance.
* @param bodyProvider InputStream providing HTTP body, null if none
* @param bodyLength length of body, must be 0 if bodyProvider is null
- * @param highPriority If true, queues before low priority
- * requests if possible
*/
public RequestHandle queueRequest(
String url, WebAddress uri, String method, Map<String, String> headers,
EventHandler eventHandler,
- InputStream bodyProvider, int bodyLength,
- boolean highPriority) {
+ InputStream bodyProvider, int bodyLength) {
if (HttpLog.LOGV) HttpLog.v("RequestQueue.queueRequest " + uri);
@@ -478,9 +474,9 @@ public class RequestQueue implements RequestFeeder {
// set up request
req = new Request(method, httpHost, mProxyHost, uri.mPath, bodyProvider,
- bodyLength, eventHandler, headers, highPriority);
+ bodyLength, eventHandler, headers);
- queueRequest(req, highPriority);
+ queueRequest(req, false);
mActivePool.mTotalRequest++;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 1775a4b..6c2a27a 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -70,6 +70,7 @@ public class Build {
*
* @deprecated Use {@link #SDK_INT} to easily get this as an integer.
*/
+ @Deprecated
public static final String SDK = getString("ro.build.version.sdk");
/**
@@ -132,6 +133,19 @@ public class Build {
* </ul>
*/
public static final int DONUT = 4;
+ /**
+ * Current work on "Eclair" development branch.
+ *
+ * <p>Applications targeting this or a later release will get these
+ * new changes in behavior:</p>
+ * <ul>
+ * <li> The {@link android.app.Service#onStartCommand
+ * Service.onStartCommand} function will return the new
+ * {@link android.app.Service#START_STICKY} behavior instead of the
+ * old compatibility {@link android.app.Service#START_STICKY_COMPATIBILITY}.
+ * </ul>
+ */
+ public static final int ECLAIR = CUR_DEVELOPMENT;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index d40ea6b..b0fc78e 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -662,6 +662,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/FileObserver.java b/core/java/android/os/FileObserver.java
index d9804ea..38d252e 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -25,22 +25,35 @@ import java.util.ArrayList;
import java.util.HashMap;
public abstract class FileObserver {
- public static final int ACCESS = 0x00000001; /* File was accessed */
- public static final int MODIFY = 0x00000002; /* File was modified */
- public static final int ATTRIB = 0x00000004; /* Metadata changed */
- public static final int CLOSE_WRITE = 0x00000008; /* Writtable file was closed */
- public static final int CLOSE_NOWRITE = 0x00000010; /* Unwrittable file closed */
- public static final int OPEN = 0x00000020; /* File was opened */
- public static final int MOVED_FROM = 0x00000040; /* File was moved from X */
- public static final int MOVED_TO = 0x00000080; /* File was moved to Y */
- public static final int CREATE = 0x00000100; /* Subfile was created */
- public static final int DELETE = 0x00000200; /* Subfile was deleted */
- public static final int DELETE_SELF = 0x00000400; /* Self was deleted */
- public static final int MOVE_SELF = 0x00000800; /* Self was moved */
+ /** File was accessed */
+ public static final int ACCESS = 0x00000001;
+ /** File was modified */
+ public static final int MODIFY = 0x00000002;
+ /** Metadata changed */
+ public static final int ATTRIB = 0x00000004;
+ /** Writable file was closed */
+ public static final int CLOSE_WRITE = 0x00000008;
+ /** Unwrittable file closed */
+ public static final int CLOSE_NOWRITE = 0x00000010;
+ /** File was opened */
+ public static final int OPEN = 0x00000020;
+ /** File was moved from X */
+ public static final int MOVED_FROM = 0x00000040;
+ /** File was moved to Y */
+ public static final int MOVED_TO = 0x00000080;
+ /** Subfile was created */
+ public static final int CREATE = 0x00000100;
+ /** Subfile was deleted */
+ public static final int DELETE = 0x00000200;
+ /** Self was deleted */
+ public static final int DELETE_SELF = 0x00000400;
+ /** Self was moved */
+ public static final int MOVE_SELF = 0x00000800;
+
public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE
| CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE
| DELETE_SELF | MOVE_SELF;
-
+
private static final String LOG_TAG = "FileObserver";
private static class ObserverThread extends Thread {
diff --git a/core/java/android/os/HandlerStateMachine.java b/core/java/android/os/HandlerStateMachine.java
index d004a25..9e7902b 100644
--- a/core/java/android/os/HandlerStateMachine.java
+++ b/core/java/android/os/HandlerStateMachine.java
@@ -56,22 +56,22 @@ import android.util.LogPrinter;
}
class S1 extends HandlerState {
- @Override public void enter(Message message) {
+ &amp;#064;Override public void enter(Message message) {
}
- @Override public void processMessage(Message message) {
+ &amp;#064;Override public void processMessage(Message message) {
deferMessage(message);
if (message.what == TEST_WHAT_2) {
transitionTo(mS2);
}
}
- @Override public void exit(Message message) {
+ &amp;#064;Override public void exit(Message message) {
}
}
class S2 extends HandlerState {
- @Override public void processMessage(Message message) {
+ &amp;#064;Override public void processMessage(Message message) {
// Do some processing
if (message.what == TEST_WHAT_2) {
transtionTo(mS1);
diff --git a/core/java/android/os/IHardwareService.aidl b/core/java/android/os/IHardwareService.aidl
index fb121bb..aebcb3c 100755
--- a/core/java/android/os/IHardwareService.aidl
+++ b/core/java/android/os/IHardwareService.aidl
@@ -20,9 +20,9 @@ package android.os;
interface IHardwareService
{
// Vibrator support
- void vibrate(long milliseconds);
+ void vibrate(long milliseconds, IBinder token);
void vibratePattern(in long[] pattern, int repeat, IBinder token);
- void cancelVibrate();
+ void cancelVibrate(IBinder token);
// flashlight support
boolean getFlashlightEnabled();
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 5486920..188e7ff 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -26,6 +26,7 @@ interface IPowerManager
void userActivity(long when, boolean noChangeLights);
void userActivityWithForce(long when, boolean noChangeLights, boolean force);
void setPokeLock(int pokey, IBinder lock, String tag);
+ int getSupportedWakeLockFlags();
void setStayOnSetting(int val);
long getScreenOnTime();
void preventScreenOn(boolean prevent);
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/MemoryFile.java b/core/java/android/os/MemoryFile.java
index c14925c..03542dd 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -52,7 +52,7 @@ public class MemoryFile
private static native void native_write(FileDescriptor fd, int address, byte[] buffer,
int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
private static native void native_pin(FileDescriptor fd, boolean pin) throws IOException;
- private static native boolean native_is_ashmem_region(FileDescriptor fd) throws IOException;
+ private static native int native_get_mapped_size(FileDescriptor fd) throws IOException;
private FileDescriptor mFD; // ashmem file descriptor
private int mAddress; // address of ashmem memory
@@ -300,7 +300,20 @@ public class MemoryFile
* @hide
*/
public static boolean isMemoryFile(FileDescriptor fd) throws IOException {
- return native_is_ashmem_region(fd);
+ return (native_get_mapped_size(fd) >= 0);
+ }
+
+ /**
+ * Returns the size of the memory file, rounded up to a page boundary, that
+ * the file descriptor refers to, or -1 if the file descriptor does not
+ * refer to a memory file.
+ *
+ * @throws IOException If <code>fd</code> is not a valid file descriptor.
+ *
+ * @hide
+ */
+ public static int getMappedSize(FileDescriptor fd) throws IOException {
+ return native_get_mapped_size(fd);
}
/**
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index bfcf2fc..d5934102 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -114,12 +114,14 @@ public class PowerManager
private static final int WAKE_BIT_SCREEN_DIM = 4;
private static final int WAKE_BIT_SCREEN_BRIGHT = 8;
private static final int WAKE_BIT_KEYBOARD_BRIGHT = 16;
+ private static final int WAKE_BIT_PROXIMITY_SCREEN_OFF = 32;
private static final int LOCK_MASK = WAKE_BIT_CPU_STRONG
| WAKE_BIT_CPU_WEAK
| WAKE_BIT_SCREEN_DIM
| WAKE_BIT_SCREEN_BRIGHT
- | WAKE_BIT_KEYBOARD_BRIGHT;
+ | WAKE_BIT_KEYBOARD_BRIGHT
+ | WAKE_BIT_PROXIMITY_SCREEN_OFF;
/**
* Wake lock that ensures that the CPU is running. The screen might
@@ -147,6 +149,16 @@ public class PowerManager
public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;
/**
+ * Wake lock that turns the screen off when the proximity sensor activates.
+ * Since not all devices have proximity sensors, use
+ * {@link #getSupportedWakeLockFlags() getSupportedWakeLockFlags()} to determine if
+ * this wake lock mode is supported.
+ *
+ * {@hide}
+ */
+ public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;
+
+ /**
* Normally wake locks don't actually wake the device, they just cause
* it to remain on once it's already on. Think of the video player
* app as the normal behavior. Notifications that pop up and want
@@ -196,6 +208,7 @@ public class PowerManager
case SCREEN_DIM_WAKE_LOCK:
case SCREEN_BRIGHT_WAKE_LOCK:
case FULL_WAKE_LOCK:
+ case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException();
@@ -365,7 +378,33 @@ public class PowerManager
} catch (RemoteException e) {
}
}
-
+
+ /**
+ * Returns the set of flags for {@link #newWakeLock(int, String) newWakeLock()}
+ * that are supported on the device.
+ * For example, to test to see if the {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK}
+ * is supported:
+ *
+ * {@samplecode
+ * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ * int supportedFlags = pm.getSupportedWakeLockFlags();
+ * boolean proximitySupported = ((supportedFlags & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
+ * == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
+ * }
+ *
+ * @return the set of supported WakeLock flags.
+ *
+ * {@hide}
+ */
+ public int getSupportedWakeLockFlags()
+ {
+ try {
+ return mService.getSupportedWakeLockFlags();
+ } catch (RemoteException e) {
+ return 0;
+ }
+ }
+
private PowerManager()
{
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 4805193..980cff3 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -739,7 +739,7 @@ public class Process {
public static final native void sendSignal(int pid, int signal);
/** @hide */
- public static final native int getFreeMemory();
+ public static final native long getFreeMemory();
/** @hide */
public static final native void readProcLines(String path,
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 584224f..b74af16 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
@@ -52,7 +52,7 @@ public class RemoteCallbackList<E extends IInterface> {
private Object[] mActiveBroadcast;
private int mBroadcastCount = -1;
private boolean mKilled = false;
-
+
private final class Callback implements IBinder.DeathRecipient {
final E mCallback;
final Object mCookie;
@@ -61,7 +61,7 @@ public class RemoteCallbackList<E extends IInterface> {
mCallback = callback;
mCookie = cookie;
}
-
+
public void binderDied() {
synchronized (mCallbacks) {
mCallbacks.remove(mCallback.asBinder());
@@ -69,7 +69,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.
@@ -86,19 +86,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
@@ -119,7 +120,7 @@ public class RemoteCallbackList<E extends IInterface> {
}
}
}
-
+
/**
* Remove from the list a callback that was previously added with
* {@link #register}. This uses the
@@ -127,14 +128,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) {
@@ -147,13 +148,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() {
@@ -165,7 +166,7 @@ public class RemoteCallbackList<E extends IInterface> {
mKilled = true;
}
}
-
+
/**
* Old version of {@link #onCallbackDied(E, Object)} that
* does not provide a cookie.
@@ -190,7 +191,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
@@ -199,12 +200,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>
* int i = callbacks.beginBroadcast();
- * while (i > 0) {
+ * while (i &gt; 0) {
* i--;
* try {
* callbacks.getBroadcastItem(i).somethingHappened();
@@ -214,11 +215,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
*/
@@ -244,26 +245,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) {
@@ -279,12 +280,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/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 2b57b39..2dd6749 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -30,7 +30,13 @@ package android.os;
* backwards or forwards unpredictably. This clock should only be used
* when correspondence with real-world dates and times is important, such
* as in a calendar or alarm clock application. Interval or elapsed
- * time measurements should use a different clock.
+ * time measurements should use a different clock. If you are using
+ * System.currentTimeMillis(), consider listening to the
+ * {@link android.content.Intent#ACTION_TIME_TICK ACTION_TIME_TICK},
+ * {@link android.content.Intent#ACTION_TIME_CHANGED ACTION_TIME_CHANGED}
+ * and {@link android.content.Intent#ACTION_TIMEZONE_CHANGED
+ * ACTION_TIMEZONE_CHANGED} {@link android.content.Intent Intent}
+ * broadcasts to find out when the time changes.
*
* <li> <p> {@link #uptimeMillis} is counted in milliseconds since the
* system was booted. This clock stops when the system enters deep
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index c3ae3c2..4a036ec 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -30,6 +30,9 @@ public class SystemProperties
private static native String native_get(String key);
private static native String native_get(String key, String def);
+ private static native int native_get_int(String key, int def);
+ private static native long native_get_long(String key, long def);
+ private static native boolean native_get_boolean(String key, boolean def);
private static native void native_set(String key, String def);
/**
@@ -65,11 +68,10 @@ public class SystemProperties
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static int getInt(String key, int def) {
- try {
- return Integer.parseInt(get(key));
- } catch (NumberFormatException e) {
- return def;
+ if (key.length() > PROP_NAME_MAX) {
+ throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
+ return native_get_int(key, def);
}
/**
@@ -81,11 +83,10 @@ public class SystemProperties
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static long getLong(String key, long def) {
- try {
- return Long.parseLong(get(key));
- } catch (NumberFormatException e) {
- return def;
+ if (key.length() > PROP_NAME_MAX) {
+ throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
+ return native_get_long(key, def);
}
/**
@@ -102,27 +103,10 @@ public class SystemProperties
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static boolean getBoolean(String key, boolean def) {
- String value = get(key);
- // Deal with these quick cases first: not found, 0 and 1
- if (value.equals("")) {
- return def;
- } else if (value.equals("0")) {
- return false;
- } else if (value.equals("1")) {
- return true;
- // now for slower (and hopefully less common) cases
- } else if (value.equalsIgnoreCase("n") ||
- value.equalsIgnoreCase("no") ||
- value.equalsIgnoreCase("false") ||
- value.equalsIgnoreCase("off")) {
- return false;
- } else if (value.equalsIgnoreCase("y") ||
- value.equalsIgnoreCase("yes") ||
- value.equalsIgnoreCase("true") ||
- value.equalsIgnoreCase("on")) {
- return true;
+ if (key.length() > PROP_NAME_MAX) {
+ throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
}
- return def;
+ return native_get_boolean(key, def);
}
/**
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 0f75289..51dcff1 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -24,6 +24,7 @@ package android.os;
public class Vibrator
{
IHardwareService mService;
+ private final Binder mToken = new Binder();
/** @hide */
public Vibrator()
@@ -40,7 +41,7 @@ public class Vibrator
public void vibrate(long milliseconds)
{
try {
- mService.vibrate(milliseconds);
+ mService.vibrate(milliseconds, mToken);
} catch (RemoteException e) {
}
}
@@ -65,7 +66,7 @@ public class Vibrator
// anyway
if (repeat < pattern.length) {
try {
- mService.vibratePattern(pattern, repeat, new Binder());
+ mService.vibratePattern(pattern, repeat, mToken);
} catch (RemoteException e) {
}
} else {
@@ -79,7 +80,7 @@ public class Vibrator
public void cancel()
{
try {
- mService.cancelVibrate();
+ mService.cancelVibrate(mToken);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/pim/ContactsAsyncHelper.java b/core/java/android/pim/ContactsAsyncHelper.java
index a21281e..342d208 100644
--- a/core/java/android/pim/ContactsAsyncHelper.java
+++ b/core/java/android/pim/ContactsAsyncHelper.java
@@ -27,8 +27,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
-import android.provider.Contacts;
-import android.provider.Contacts.People;
+import android.provider.ContactsContract.Contacts;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
@@ -39,35 +38,35 @@ import java.io.InputStream;
* Helper class for async access of images.
*/
public class ContactsAsyncHelper extends Handler {
-
+
private static final boolean DBG = false;
private static final String LOG_TAG = "ContactsAsyncHelper";
-
+
/**
* Interface for a WorkerHandler result return.
*/
public interface OnImageLoadCompleteListener {
/**
* Called when the image load is complete.
- *
+ *
* @param imagePresent true if an image was found
- */
+ */
public void onImageLoadComplete(int token, Object cookie, ImageView iView,
boolean imagePresent);
}
-
+
// constants
private static final int EVENT_LOAD_IMAGE = 1;
private static final int DEFAULT_TOKEN = -1;
-
+
// static objects
private static Handler sThreadHandler;
private static ContactsAsyncHelper sInstance;
-
+
static {
sInstance = new ContactsAsyncHelper();
}
-
+
private static final class WorkerArgs {
public Context context;
public ImageView view;
@@ -78,12 +77,12 @@ public class ContactsAsyncHelper extends Handler {
public OnImageLoadCompleteListener listener;
public CallerInfo info;
}
-
+
/**
- * public inner class to help out the ContactsAsyncHelper callers
- * with tracking the state of the CallerInfo Queries and image
+ * public inner class to help out the ContactsAsyncHelper callers
+ * with tracking the state of the CallerInfo Queries and image
* loading.
- *
+ *
* Logic contained herein is used to remove the race conditions
* that exist as the CallerInfo queries run and mix with the image
* loads, which then mix with the Phone state changes.
@@ -94,11 +93,11 @@ public class ContactsAsyncHelper extends Handler {
public static final int DISPLAY_UNDEFINED = 0;
public static final int DISPLAY_IMAGE = -1;
public static final int DISPLAY_DEFAULT = -2;
-
+
// State of the image on the imageview.
private CallerInfo mCurrentCallerInfo;
private int displayMode;
-
+
public ImageTracker() {
mCurrentCallerInfo = null;
displayMode = DISPLAY_UNDEFINED;
@@ -107,17 +106,17 @@ public class ContactsAsyncHelper extends Handler {
/**
* Used to see if the requested call / connection has a
* different caller attached to it than the one we currently
- * have in the CallCard.
+ * have in the CallCard.
*/
public boolean isDifferentImageRequest(CallerInfo ci) {
// note, since the connections are around for the lifetime of the
- // call, and the CallerInfo-related items as well, we can
+ // call, and the CallerInfo-related items as well, we can
// definitely use a simple != comparison.
return (mCurrentCallerInfo != ci);
}
-
+
public boolean isDifferentImageRequest(Connection connection) {
- // if the connection does not exist, see if the
+ // if the connection does not exist, see if the
// mCurrentCallerInfo is also null to match.
if (connection == null) {
if (DBG) Log.d(LOG_TAG, "isDifferentImageRequest: connection is null");
@@ -133,57 +132,58 @@ public class ContactsAsyncHelper extends Handler {
}
return runQuery;
}
-
+
/**
- * Simple setter for the CallerInfo object.
+ * Simple setter for the CallerInfo object.
*/
public void setPhotoRequest(CallerInfo ci) {
- mCurrentCallerInfo = ci;
+ mCurrentCallerInfo = ci;
}
-
+
/**
- * Convenience method used to retrieve the URI
- * representing the Photo file recorded in the attached
- * CallerInfo Object.
+ * Convenience method used to retrieve the URI
+ * representing the Photo file recorded in the attached
+ * CallerInfo Object.
*/
public Uri getPhotoUri() {
if (mCurrentCallerInfo != null) {
- return ContentUris.withAppendedId(People.CONTENT_URI,
+ return ContentUris.withAppendedId(Contacts.CONTENT_URI,
mCurrentCallerInfo.person_id);
}
- return null;
+ return null;
}
-
+
/**
- * Simple setter for the Photo state.
+ * Simple setter for the Photo state.
*/
public void setPhotoState(int state) {
displayMode = state;
}
-
+
/**
- * Simple getter for the Photo state.
+ * Simple getter for the Photo state.
*/
public int getPhotoState() {
return displayMode;
}
}
-
+
/**
- * Thread worker class that handles the task of opening the stream and loading
+ * Thread worker class that handles the task of opening the stream and loading
* the images.
*/
private class WorkerHandler extends Handler {
public WorkerHandler(Looper looper) {
super(looper);
}
-
+
+ @Override
public void handleMessage(Message msg) {
WorkerArgs args = (WorkerArgs) msg.obj;
-
+
switch (msg.arg1) {
case EVENT_LOAD_IMAGE:
- InputStream inputStream = Contacts.People.openContactPhotoInputStream(
+ InputStream inputStream = Contacts.openContactPhotoInputStream(
args.context.getContentResolver(), args.uri);
if (inputStream != null) {
args.result = Drawable.createFromStream(inputStream, args.uri.toString());
@@ -192,22 +192,22 @@ public class ContactsAsyncHelper extends Handler {
" token: " + msg.what + " image URI: " + args.uri);
} else {
args.result = null;
- if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
- " token: " + msg.what + " image URI: " + args.uri +
+ if (DBG) Log.d(LOG_TAG, "Problem with image: " + msg.arg1 +
+ " token: " + msg.what + " image URI: " + args.uri +
", using default image.");
}
break;
default:
}
-
- // send the reply to the enclosing class.
+
+ // send the reply to the enclosing class.
Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
reply.arg1 = msg.arg1;
reply.obj = msg.obj;
reply.sendToTarget();
}
}
-
+
/**
* Private constructor for static class
*/
@@ -216,14 +216,14 @@ public class ContactsAsyncHelper extends Handler {
thread.start();
sThreadHandler = new WorkerHandler(thread.getLooper());
}
-
+
/**
* Convenience method for calls that do not want to deal with listeners and tokens.
*/
- public static final void updateImageViewWithContactPhotoAsync(Context context,
+ public static final void updateImageViewWithContactPhotoAsync(Context context,
ImageView imageView, Uri person, int placeholderImageResource) {
// Added additional Cookie field in the callee.
- updateImageViewWithContactPhotoAsync (null, DEFAULT_TOKEN, null, null, context,
+ updateImageViewWithContactPhotoAsync (null, DEFAULT_TOKEN, null, null, context,
imageView, person, placeholderImageResource);
}
@@ -231,24 +231,24 @@ public class ContactsAsyncHelper extends Handler {
* Convenience method for calls that do not want to deal with listeners and tokens, but have
* a CallerInfo object to cache the image to.
*/
- public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, Context context,
+ public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, Context context,
ImageView imageView, Uri person, int placeholderImageResource) {
// Added additional Cookie field in the callee.
- updateImageViewWithContactPhotoAsync (info, DEFAULT_TOKEN, null, null, context,
+ updateImageViewWithContactPhotoAsync (info, DEFAULT_TOKEN, null, null, context,
imageView, person, placeholderImageResource);
}
-
+
/**
* Start an image load, attach the result to the specified CallerInfo object.
* Note, when the query is started, we make the ImageView INVISIBLE if the
* placeholderImageResource value is -1. When we're given a valid (!= -1)
* placeholderImageResource value, we make sure the image is visible.
*/
- public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, int token,
- OnImageLoadCompleteListener listener, Object cookie, Context context,
+ public static final void updateImageViewWithContactPhotoAsync(CallerInfo info, int token,
+ OnImageLoadCompleteListener listener, Object cookie, Context context,
ImageView imageView, Uri person, int placeholderImageResource) {
-
+
// in case the source caller info is null, the URI will be null as well.
// just update using the placeholder image in this case.
if (person == null) {
@@ -257,10 +257,10 @@ public class ContactsAsyncHelper extends Handler {
imageView.setImageResource(placeholderImageResource);
return;
}
-
+
// Added additional Cookie field in the callee to handle arguments
// sent to the callback function.
-
+
// setup arguments
WorkerArgs args = new WorkerArgs();
args.cookie = cookie;
@@ -270,15 +270,15 @@ public class ContactsAsyncHelper extends Handler {
args.defaultResource = placeholderImageResource;
args.listener = listener;
args.info = info;
-
+
// setup message arguments
Message msg = sThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_LOAD_IMAGE;
msg.obj = args;
-
- if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
+
+ if (DBG) Log.d(LOG_TAG, "Begin loading image: " + args.uri +
", displaying default image for now.");
-
+
// set the default image first, when the query is complete, we will
// replace the image with the correct one.
if (placeholderImageResource != -1) {
@@ -287,11 +287,11 @@ public class ContactsAsyncHelper extends Handler {
} else {
imageView.setVisibility(View.INVISIBLE);
}
-
+
// notify the thread to begin working
sThreadHandler.sendMessage(msg);
}
-
+
/**
* Called when loading is done.
*/
@@ -316,21 +316,21 @@ public class ContactsAsyncHelper extends Handler {
args.view.setVisibility(View.VISIBLE);
args.view.setImageResource(args.defaultResource);
}
-
+
// Note that the data is cached.
if (args.info != null) {
args.info.isCachedPhotoCurrent = true;
}
-
+
// notify the listener if it is there.
if (args.listener != null) {
- if (DBG) Log.d(LOG_TAG, "Notifying listener: " + args.listener.toString() +
+ if (DBG) Log.d(LOG_TAG, "Notifying listener: " + args.listener.toString() +
" image: " + args.uri + " completed");
args.listener.onImageLoadComplete(msg.what, args.cookie, args.view,
imagePresent);
}
break;
- default:
+ default:
}
}
}
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index 1a287c8..bd7924a 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -223,6 +223,7 @@ public class RecurrenceSet {
return true;
}
+ // This can be removed when the old CalendarSyncAdapter is removed.
public static boolean populateComponent(Cursor cursor,
ICalendar.Component component) {
@@ -292,6 +293,64 @@ public class RecurrenceSet {
return true;
}
+public static boolean populateComponent(ContentValues values,
+ ICalendar.Component component) {
+ long dtstart = -1;
+ if (values.containsKey(Calendar.Events.DTSTART)) {
+ dtstart = values.getAsLong(Calendar.Events.DTSTART);
+ }
+ String duration = values.getAsString(Calendar.Events.DURATION);
+ String tzid = values.getAsString(Calendar.Events.EVENT_TIMEZONE);
+ String rruleStr = values.getAsString(Calendar.Events.RRULE);
+ String rdateStr = values.getAsString(Calendar.Events.RDATE);
+ String exruleStr = values.getAsString(Calendar.Events.EXRULE);
+ String exdateStr = values.getAsString(Calendar.Events.EXDATE);
+ boolean allDay = values.getAsInteger(Calendar.Events.ALL_DAY) == 1;
+
+ if ((dtstart == -1) ||
+ (TextUtils.isEmpty(duration))||
+ ((TextUtils.isEmpty(rruleStr))&&
+ (TextUtils.isEmpty(rdateStr)))) {
+ // no recurrence.
+ return false;
+ }
+
+ ICalendar.Property dtstartProp = new ICalendar.Property("DTSTART");
+ Time dtstartTime = null;
+ if (!TextUtils.isEmpty(tzid)) {
+ if (!allDay) {
+ dtstartProp.addParameter(new ICalendar.Parameter("TZID", tzid));
+ }
+ dtstartTime = new Time(tzid);
+ } else {
+ // use the "floating" timezone
+ dtstartTime = new Time(Time.TIMEZONE_UTC);
+ }
+
+ dtstartTime.set(dtstart);
+ // make sure the time is printed just as a date, if all day.
+ // TODO: android.pim.Time really should take care of this for us.
+ if (allDay) {
+ dtstartProp.addParameter(new ICalendar.Parameter("VALUE", "DATE"));
+ dtstartTime.allDay = true;
+ dtstartTime.hour = 0;
+ dtstartTime.minute = 0;
+ dtstartTime.second = 0;
+ }
+
+ dtstartProp.setValue(dtstartTime.format2445());
+ component.addProperty(dtstartProp);
+ ICalendar.Property durationProp = new ICalendar.Property("DURATION");
+ durationProp.setValue(duration);
+ component.addProperty(durationProp);
+
+ addPropertiesForRuleStr(component, "RRULE", rruleStr);
+ addPropertyForDateStr(component, "RDATE", rdateStr);
+ addPropertiesForRuleStr(component, "EXRULE", exruleStr);
+ addPropertyForDateStr(component, "EXDATE", exdateStr);
+ return true;
+ }
+
private static void addPropertiesForRuleStr(ICalendar.Component component,
String propertyName,
String ruleStr) {
@@ -351,10 +410,14 @@ public class RecurrenceSet {
Time end = new Time(endTzid);
end.parse(dtendProperty.getValue());
- long durationMillis = end.toMillis(false /* use isDst */)
+ long durationMillis = end.toMillis(false /* use isDst */)
- start.toMillis(false /* use isDst */);
long durationSeconds = (durationMillis / 1000);
- return "P" + durationSeconds + "S";
+ if (start.allDay && (durationSeconds % 86400) == 0) {
+ return "P" + (durationSeconds / 86400) + "D"; // Server wants this instead of P86400S
+ } else {
+ return "P" + durationSeconds + "S";
+ }
}
private static String flattenProperties(ICalendar.Component component,
diff --git a/core/java/android/pim/vcard/Constants.java b/core/java/android/pim/vcard/Constants.java
new file mode 100644
index 0000000..ca41ce5
--- /dev/null
+++ b/core/java/android/pim/vcard/Constants.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.pim.vcard;
+
+/**
+ * Constants used in both composer and parser.
+ */
+/* package */ class Constants {
+
+ public static final String ATTR_TYPE = "TYPE";
+
+ public static final String VERSION_V21 = "2.1";
+ public static final String VERSION_V30 = "3.0";
+
+ // Properties both the current (as of 2009-08-17) ContactsStruct and de-fact vCard extensions
+ // shown in http://en.wikipedia.org/wiki/VCard support are defined here.
+ public static final String PROPERTY_X_AIM = "X-AIM";
+ public static final String PROPERTY_X_MSN = "X-MSN";
+ public static final String PROPERTY_X_YAHOO = "X-YAHOO";
+ public static final String PROPERTY_X_ICQ = "X-ICQ";
+ public static final String PROPERTY_X_JABBER = "X-JABBER";
+ public static final String PROPERTY_X_GOOGLE_TALK = "X-GOOGLE-TALK";
+ public static final String PROPERTY_X_SKYPE_USERNAME = "X-SKYPE-USERNAME";
+ // Phone number for Skype, available as usual phone.
+ public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER";
+ // Some device emits this "X-" attribute, which is specifically invalid but should be
+ // always properly accepted, and emitted in some special case (for that device/application).
+ public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
+
+ // How more than one TYPE fields are expressed is different between vCard 2.1 and vCard 3.0
+ //
+ // e.g.
+ // 1) Probably valid in both vCard 2.1 and vCard 3.0: "ADR;TYPE=DOM;TYPE=HOME:..."
+ // 2) Valid in vCard 2.1 but not in vCard 3.0: "ADR;DOM;HOME:..."
+ // 3) Valid in vCard 3.0 but not in vCard 2.1: "ADR;TYPE=DOM,HOME:..."
+ //
+ // 2) has been the default of VCard exporter/importer in Android, but we can see the other
+ // formats in vCard data emitted by the other softwares/devices.
+ //
+ // So we are currently not sure which type is the best; probably we will have to change which
+ // type should be emitted depending on the device.
+ public static final String ATTR_TYPE_HOME = "HOME";
+ public static final String ATTR_TYPE_WORK = "WORK";
+ public static final String ATTR_TYPE_FAX = "FAX";
+ public static final String ATTR_TYPE_CELL = "CELL";
+ public static final String ATTR_TYPE_VOICE = "VOICE";
+ public static final String ATTR_TYPE_INTERNET = "INTERNET";
+
+ public static final String ATTR_TYPE_PREF = "PREF";
+
+ // Phone types valid in vCard and known to ContactsContract, but not so common.
+ public static final String ATTR_TYPE_CAR = "CAR";
+ public static final String ATTR_TYPE_ISDN = "ISDN";
+ public static final String ATTR_TYPE_PAGER = "PAGER";
+
+ // Phone types existing in vCard 2.1 but not known to ContactsContract.
+ // TODO: should make parser make these TYPE_CUSTOM.
+ public static final String ATTR_TYPE_MODEM = "MODEM";
+ public static final String ATTR_TYPE_MSG = "MSG";
+ public static final String ATTR_TYPE_BBS = "BBS";
+ public static final String ATTR_TYPE_VIDEO = "VIDEO";
+
+ // Phone types existing in the current Contacts structure but not valid in vCard (at least 2.1)
+ // These types are encoded to "X-" attributes when composing vCard for now.
+ // Parser passes these even if "X-" is added to the attribute.
+ public static final String ATTR_TYPE_PHONE_EXTRA_OTHER = "OTHER";
+ public static final String ATTR_TYPE_PHONE_EXTRA_CALLBACK = "CALLBACK";
+ // TODO: may be "TYPE=COMPANY,PREF", not "COMPANY-MAIN".
+ public static final String ATTR_TYPE_PHONE_EXTRA_COMPANY_MAIN = "COMPANY-MAIN";
+ public static final String ATTR_TYPE_PHONE_EXTRA_RADIO = "RADIO";
+ public static final String ATTR_TYPE_PHONE_EXTRA_TELEX = "TELEX";
+ public static final String ATTR_TYPE_PHONE_EXTRA_TTY_TDD = "TTY-TDD";
+ public static final String ATTR_TYPE_PHONE_EXTRA_ASSISTANT = "ASSISTANT";
+
+ // DoCoMo specific attribute. Used with "SOUND" property, which is alternate of SORT-STRING in
+ // vCard 3.0.
+ public static final String ATTR_TYPE_X_IRMC_N = "X-IRMC-N";
+
+ private Constants() {
+ }
+} \ No newline at end of file
diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java
new file mode 100644
index 0000000..0064bf2
--- /dev/null
+++ b/core/java/android/pim/vcard/ContactStruct.java
@@ -0,0 +1,1218 @@
+/*
+ * 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.pim.vcard;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.OperationApplicationException;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Miscellaneous;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.Note;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class bridges between data structure of Contact app and VCard data.
+ */
+public class ContactStruct {
+ private static final String LOG_TAG = "vcard.ContactStruct";
+
+ // Key: the name shown in VCard. e.g. "X-AIM", "X-ICQ"
+ // Value: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
+ private static final Map<String, Integer> sImMap = new HashMap<String, Integer>();
+
+ static {
+ sImMap.put(Constants.PROPERTY_X_AIM, Im.PROTOCOL_AIM);
+ sImMap.put(Constants.PROPERTY_X_MSN, Im.PROTOCOL_MSN);
+ sImMap.put(Constants.PROPERTY_X_YAHOO, Im.PROTOCOL_YAHOO);
+ sImMap.put(Constants.PROPERTY_X_ICQ, Im.PROTOCOL_ICQ);
+ sImMap.put(Constants.PROPERTY_X_JABBER, Im.PROTOCOL_JABBER);
+ sImMap.put(Constants.PROPERTY_X_SKYPE_USERNAME, Im.PROTOCOL_SKYPE);
+ sImMap.put(Constants.PROPERTY_X_GOOGLE_TALK, Im.PROTOCOL_GOOGLE_TALK);
+ sImMap.put(Constants.PROPERTY_X_GOOGLE_TALK_WITH_SPACE, Im.PROTOCOL_GOOGLE_TALK);
+ }
+
+ /**
+ * @hide only for testing
+ */
+ static public class PhoneData {
+ public final int type;
+ public final String data;
+ public final String label;
+ // isPrimary is changable only when there's no appropriate one existing in
+ // the original VCard.
+ public boolean isPrimary;
+ public PhoneData(int type, String data, String label, boolean isPrimary) {
+ this.type = type;
+ this.data = data;
+ this.label = label;
+ this.isPrimary = isPrimary;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof PhoneData) {
+ return false;
+ }
+ PhoneData phoneData = (PhoneData)obj;
+ return (type == phoneData.type && data.equals(phoneData.data) &&
+ label.equals(phoneData.label) && isPrimary == phoneData.isPrimary);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("type: %d, data: %s, label: %s, isPrimary: %s",
+ type, data, label, isPrimary);
+ }
+ }
+
+ /**
+ * @hide only for testing
+ */
+ static public class EmailData {
+ public final int type;
+ public final String data;
+ // Used only when TYPE is TYPE_CUSTOM.
+ public final String label;
+ // isPrimary is changable only when there's no appropriate one existing in
+ // the original VCard.
+ public boolean isPrimary;
+ public EmailData(int type, String data, String label, boolean isPrimary) {
+ this.type = type;
+ this.data = data;
+ this.label = label;
+ this.isPrimary = isPrimary;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof EmailData) {
+ return false;
+ }
+ EmailData emailData = (EmailData)obj;
+ return (type == emailData.type && data.equals(emailData.data) &&
+ label.equals(emailData.label) && isPrimary == emailData.isPrimary);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("type: %d, data: %s, label: %s, isPrimary: %s",
+ type, data, label, isPrimary);
+ }
+ }
+
+ static public class PostalData {
+ // Determined by vCard spec.
+ // PO Box, Extended Addr, Street, Locality, Region, Postal Code, Country Name
+ public static final int ADDR_MAX_DATA_SIZE = 7;
+ private final String[] dataArray;
+ public final String pobox;
+ public final String extendedAddress;
+ public final String street;
+ public final String localty;
+ public final String region;
+ public final String postalCode;
+ public final String country;
+
+ public final int type;
+
+ // Used only when type variable is TYPE_CUSTOM.
+ public final String label;
+
+ // isPrimary is changable only when there's no appropriate one existing in
+ // the original VCard.
+ public boolean isPrimary;
+ public PostalData(int type, List<String> propValueList,
+ String label, boolean isPrimary) {
+ this.type = type;
+ dataArray = new String[ADDR_MAX_DATA_SIZE];
+
+ int size = propValueList.size();
+ if (size > ADDR_MAX_DATA_SIZE) {
+ size = ADDR_MAX_DATA_SIZE;
+ }
+
+ // adr-value = 0*6(text-value ";") text-value
+ // ; PO Box, Extended Address, Street, Locality, Region, Postal
+ // ; Code, Country Name
+ //
+ // Use Iterator assuming List may be LinkedList, though actually it is
+ // always ArrayList in the current implementation.
+ int i = 0;
+ for (String addressElement : propValueList) {
+ dataArray[i] = addressElement;
+ if (++i >= size) {
+ break;
+ }
+ }
+ while (i < ADDR_MAX_DATA_SIZE) {
+ dataArray[i++] = null;
+ }
+
+ this.pobox = dataArray[0];
+ this.extendedAddress = dataArray[1];
+ this.street = dataArray[2];
+ this.localty = dataArray[3];
+ this.region = dataArray[4];
+ this.postalCode = dataArray[5];
+ this.country = dataArray[6];
+
+ this.label = label;
+ this.isPrimary = isPrimary;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof PostalData) {
+ return false;
+ }
+ PostalData postalData = (PostalData)obj;
+ return (Arrays.equals(dataArray, postalData.dataArray) &&
+ (type == postalData.type &&
+ (type == StructuredPostal.TYPE_CUSTOM ?
+ (label == postalData.label) : true)) &&
+ (isPrimary == postalData.isPrimary));
+ }
+
+ public String getFormattedAddress(int vcardType) {
+ StringBuilder builder = new StringBuilder();
+ boolean empty = true;
+ if (VCardConfig.isJapaneseDevice(vcardType)) {
+ // In Japan, the order is reversed.
+ for (int i = ADDR_MAX_DATA_SIZE - 1; i >= 0; i--) {
+ String addressPart = dataArray[i];
+ if (!TextUtils.isEmpty(addressPart)) {
+ if (!empty) {
+ builder.append(' ');
+ }
+ builder.append(addressPart);
+ empty = false;
+ }
+ }
+ } else {
+ for (int i = 0; i < ADDR_MAX_DATA_SIZE; i++) {
+ String addressPart = dataArray[i];
+ if (!TextUtils.isEmpty(addressPart)) {
+ if (!empty) {
+ builder.append(' ');
+ }
+ builder.append(addressPart);
+ empty = false;
+ }
+ }
+ }
+
+ return builder.toString().trim();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("type: %d, label: %s, isPrimary: %s",
+ type, label, isPrimary);
+ }
+ }
+
+ /**
+ * @hide only for testing.
+ */
+ static public class OrganizationData {
+ public final int type;
+ public final String companyName;
+ // can be changed in some VCard format.
+ public String positionName;
+ // isPrimary is changable only when there's no appropriate one existing in
+ // the original VCard.
+ public boolean isPrimary;
+ public OrganizationData(int type, String companyName, String positionName,
+ boolean isPrimary) {
+ this.type = type;
+ this.companyName = companyName;
+ this.positionName = positionName;
+ this.isPrimary = isPrimary;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof OrganizationData) {
+ return false;
+ }
+ OrganizationData organization = (OrganizationData)obj;
+ return (type == organization.type && companyName.equals(organization.companyName) &&
+ positionName.equals(organization.positionName) &&
+ isPrimary == organization.isPrimary);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("type: %d, company: %s, position: %s, isPrimary: %s",
+ type, companyName, positionName, isPrimary);
+ }
+ }
+
+ static public class ImData {
+ public final int type;
+ public final String data;
+ public final String label;
+ public final boolean isPrimary;
+
+ // TODO: ContactsConstant#PROTOCOL, ContactsConstant#CUSTOM_PROTOCOL should be used?
+ public ImData(int type, String data, String label, boolean isPrimary) {
+ this.type = type;
+ this.data = data;
+ this.label = label;
+ this.isPrimary = isPrimary;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ImData) {
+ return false;
+ }
+ ImData imData = (ImData)obj;
+ return (type == imData.type && data.equals(imData.data) &&
+ label.equals(imData.label) && isPrimary == imData.isPrimary);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("type: %d, data: %s, label: %s, isPrimary: %s",
+ type, data, label, isPrimary);
+ }
+ }
+
+ /**
+ * @hide only for testing.
+ */
+ static public class PhotoData {
+ public static final String FORMAT_FLASH = "SWF";
+ public final int type;
+ public final String formatName; // used when type is not defined in ContactsContract.
+ public final byte[] photoBytes;
+
+ public PhotoData(int type, String formatName, byte[] photoBytes) {
+ this.type = type;
+ this.formatName = formatName;
+ this.photoBytes = photoBytes;
+ }
+ }
+
+ static /* package */ class Property {
+ private String mPropertyName;
+ private Map<String, Collection<String>> mParameterMap =
+ new HashMap<String, Collection<String>>();
+ private List<String> mPropertyValueList = new ArrayList<String>();
+ private byte[] mPropertyBytes;
+
+ public Property() {
+ clear();
+ }
+
+ public void setPropertyName(final String propertyName) {
+ mPropertyName = propertyName;
+ }
+
+ public void addParameter(final String paramName, final String paramValue) {
+ Collection<String> values;
+ if (!mParameterMap.containsKey(paramName)) {
+ if (paramName.equals("TYPE")) {
+ values = new HashSet<String>();
+ } else {
+ values = new ArrayList<String>();
+ }
+ mParameterMap.put(paramName, values);
+ } else {
+ values = mParameterMap.get(paramName);
+ }
+ values.add(paramValue);
+ }
+
+ public void addToPropertyValueList(final String propertyValue) {
+ mPropertyValueList.add(propertyValue);
+ }
+
+ public void setPropertyBytes(final byte[] propertyBytes) {
+ mPropertyBytes = propertyBytes;
+ }
+
+ public final Collection<String> getParameters(String type) {
+ return mParameterMap.get(type);
+ }
+
+ public final List<String> getPropertyValueList() {
+ return mPropertyValueList;
+ }
+
+ public void clear() {
+ mPropertyName = null;
+ mParameterMap.clear();
+ mPropertyValueList.clear();
+ }
+ }
+
+ private String mFamilyName;
+ private String mGivenName;
+ private String mMiddleName;
+ private String mPrefix;
+ private String mSuffix;
+
+ // Used only when no family nor given name is found.
+ private String mFullName;
+
+ private String mPhoneticFamilyName;
+ private String mPhoneticGivenName;
+ private String mPhoneticMiddleName;
+
+ private String mPhoneticFullName;
+
+ private List<String> mNickNameList;
+
+ private String mDisplayName;
+
+ private String mBirthday;
+
+ private List<String> mNoteList;
+ private List<PhoneData> mPhoneList;
+ private List<EmailData> mEmailList;
+ private List<PostalData> mPostalList;
+ private List<OrganizationData> mOrganizationList;
+ private List<ImData> mImList;
+ private List<PhotoData> mPhotoList;
+ private List<String> mWebsiteList;
+
+ private final int mVCardType;
+
+ // Each Column of four properties has ISPRIMARY field
+ // (See android.provider.Contacts)
+ // If false even after the parsing loop, we choose the first entry as a "primary"
+ // entry.
+ private boolean mPrefIsSet_Address;
+ private boolean mPrefIsSet_Phone;
+ private boolean mPrefIsSet_Email;
+ private boolean mPrefIsSet_Organization;
+
+ public ContactStruct() {
+ this(VCardConfig.VCARD_TYPE_V21_GENERIC);
+ }
+
+ public ContactStruct(int vcardType) {
+ mVCardType = vcardType;
+ }
+
+ /**
+ * @hide only for testing.
+ */
+ public ContactStruct(String givenName,
+ String familyName,
+ String middleName,
+ String prefix,
+ String suffix,
+ String phoneticGivenName,
+ String pheneticFamilyName,
+ String phoneticMiddleName,
+ List<byte[]> photoBytesList,
+ List<String> notes,
+ List<PhoneData> phoneList,
+ List<EmailData> emailList,
+ List<PostalData> postalList,
+ List<OrganizationData> organizationList,
+ List<PhotoData> photoList,
+ List<String> websiteList) {
+ this(VCardConfig.VCARD_TYPE_DEFAULT);
+ mGivenName = givenName;
+ mFamilyName = familyName;
+ mPrefix = prefix;
+ mSuffix = suffix;
+ mPhoneticGivenName = givenName;
+ mPhoneticFamilyName = familyName;
+ mPhoneticMiddleName = middleName;
+ mEmailList = emailList;
+ mPostalList = postalList;
+ mOrganizationList = organizationList;
+ mPhotoList = photoList;
+ mWebsiteList = websiteList;
+ }
+
+ /**
+ * @hide only for testing.
+ */
+ public final List<PhotoData> getPhotoList() {
+ return mPhotoList;
+ }
+
+ /**
+ * @hide only for testing.
+ */
+ public final List<String> getNotes() {
+ return mNoteList;
+ }
+
+ /**
+ * @hide only for testing.
+ */
+ public final List<PhoneData> getPhoneList() {
+ return mPhoneList;
+ }
+
+ /**
+ * @hide only for testing.
+ */
+ public final List<EmailData> getEmailList() {
+ return mEmailList;
+ }
+
+ /**
+ * @hide only for testing.
+ */
+ public final List<PostalData> getPostalList() {
+ return mPostalList;
+ }
+
+ /**
+ * @hide only for testing.
+ */
+ public final List<OrganizationData> getOrganizationList() {
+ return mOrganizationList;
+ }
+
+ /**
+ * Add a phone info to phoneList.
+ * @param data phone number
+ * @param type type col of content://contacts/phones
+ * @param label lable col of content://contacts/phones
+ */
+ private void addPhone(int type, String data, String label, boolean isPrimary){
+ if (mPhoneList == null) {
+ mPhoneList = new ArrayList<PhoneData>();
+ }
+ StringBuilder builder = new StringBuilder();
+ String trimed = data.trim();
+ int length = trimed.length();
+ for (int i = 0; i < length; i++) {
+ char ch = trimed.charAt(i);
+ if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {
+ builder.append(ch);
+ }
+ }
+
+ PhoneData phoneData = new PhoneData(type,
+ PhoneNumberUtils.formatNumber(builder.toString()),
+ label, isPrimary);
+
+ mPhoneList.add(phoneData);
+ }
+
+ private void addNickName(final String nickName) {
+ if (mNickNameList == null) {
+ mNickNameList = new ArrayList<String>();
+ }
+ mNickNameList.add(nickName);
+ }
+
+ private void addEmail(int type, String data, String label, boolean isPrimary){
+ if (mEmailList == null) {
+ mEmailList = new ArrayList<EmailData>();
+ }
+ mEmailList.add(new EmailData(type, data, label, isPrimary));
+ }
+
+ private void addPostal(int type, List<String> propValueList, String label, boolean isPrimary){
+ if (mPostalList == null) {
+ mPostalList = new ArrayList<PostalData>();
+ }
+ mPostalList.add(new PostalData(type, propValueList, label, isPrimary));
+ }
+
+ private void addOrganization(int type, final String companyName,
+ final String positionName, boolean isPrimary) {
+ if (mOrganizationList == null) {
+ mOrganizationList = new ArrayList<OrganizationData>();
+ }
+ mOrganizationList.add(new OrganizationData(type, companyName, positionName, isPrimary));
+ }
+
+ private void addIm(int type, String data, String label, boolean isPrimary) {
+ if (mImList == null) {
+ mImList = new ArrayList<ImData>();
+ }
+ mImList.add(new ImData(type, data, label, isPrimary));
+ }
+
+ private void addNote(final String note) {
+ if (mNoteList == null) {
+ mNoteList = new ArrayList<String>(1);
+ }
+ mNoteList.add(note);
+ }
+
+ private void addPhotoBytes(String formatName, byte[] photoBytes) {
+ if (mPhotoList == null) {
+ mPhotoList = new ArrayList<PhotoData>(1);
+ }
+ final PhotoData photoData = new PhotoData(0, null, photoBytes);
+ }
+
+ /**
+ * Set "position" value to the appropriate data. If there's more than one
+ * OrganizationData objects, the value is set to the last one. If there's no
+ * OrganizationData object, a new OrganizationData is created, whose company name is
+ * empty.
+ *
+ * TODO: incomplete logic. fix this:
+ *
+ * e.g. This assumes ORG comes earlier, but TITLE may come earlier like this, though we do not
+ * know how to handle it in general cases...
+ * ----
+ * TITLE:Software Engineer
+ * ORG:Google
+ * ----
+ */
+ private void setPosition(String positionValue) {
+ if (mOrganizationList == null) {
+ mOrganizationList = new ArrayList<OrganizationData>();
+ }
+ int size = mOrganizationList.size();
+ if (size == 0) {
+ addOrganization(ContactsContract.CommonDataKinds.Organization.TYPE_OTHER,
+ "", null, false);
+ size = 1;
+ }
+ OrganizationData lastData = mOrganizationList.get(size - 1);
+ lastData.positionName = positionValue;
+ }
+
+ @SuppressWarnings("fallthrough")
+ private void handleNProperty(List<String> elems) {
+ // Family, Given, Middle, Prefix, Suffix. (1 - 5)
+ int size;
+ if (elems == null || (size = elems.size()) < 1) {
+ return;
+ }
+ if (size > 5) {
+ size = 5;
+ }
+
+ switch (size) {
+ // fallthrough
+ case 5:
+ mSuffix = elems.get(4);
+ case 4:
+ mPrefix = elems.get(3);
+ case 3:
+ mMiddleName = elems.get(2);
+ case 2:
+ mGivenName = elems.get(1);
+ default:
+ mFamilyName = elems.get(0);
+ }
+ }
+
+ /**
+ * Some Japanese mobile phones use this field for phonetic name,
+ * since vCard 2.1 does not have "SORT-STRING" type.
+ * Also, in some cases, the field has some ';'s in it.
+ * Assume the ';' means the same meaning in N property
+ */
+ @SuppressWarnings("fallthrough")
+ private void handlePhoneticNameFromSound(List<String> elems) {
+ // Family, Given, Middle. (1-3)
+ // This is not from specification but mere assumption. Some Japanese phones use this order.
+ int size;
+ if (elems == null || (size = elems.size()) < 1) {
+ return;
+ }
+ if (size > 3) {
+ size = 3;
+ }
+
+ switch (size) {
+ // fallthrough
+ case 3:
+ mPhoneticMiddleName = elems.get(2);
+ case 2:
+ mPhoneticGivenName = elems.get(1);
+ default:
+ mPhoneticFamilyName = elems.get(0);
+ }
+ }
+
+ public void addProperty(Property property) {
+ String propName = property.mPropertyName;
+ final Map<String, Collection<String>> paramMap = property.mParameterMap;
+ final List<String> propValueList = property.mPropertyValueList;
+ byte[] propBytes = property.mPropertyBytes;
+
+ if (propValueList.size() == 0) {
+ return;
+ }
+ final String propValue = listToString(propValueList).trim();
+
+ if (propName.equals("VERSION")) {
+ // vCard version. Ignore this.
+ } else if (propName.equals("FN")) {
+ mFullName = propValue;
+ } else if (propName.equals("NAME") && mFullName == null) {
+ // Only in vCard 3.0. Use this if FN, which must exist in vCard 3.0 but may not
+ // actually exist in the real vCard data, does not exist.
+ mFullName = propValue;
+ } else if (propName.equals("N")) {
+ handleNProperty(propValueList);
+ } else if (propName.equals("SORT-STRING")) {
+ mPhoneticFullName = propValue;
+ } else if (propName.equals("NICKNAME") || propName.equals("X-NICKNAME")) {
+ addNickName(propValue);
+ } else if (propName.equals("SOUND")) {
+ if (Constants.ATTR_TYPE_X_IRMC_N.equals(paramMap.get(Constants.ATTR_TYPE))) {
+ handlePhoneticNameFromSound(propValueList);
+ } else {
+ // Ignore this field since Android cannot understand what it is.
+ }
+ } else if (propName.equals("ADR")) {
+ boolean valuesAreAllEmpty = true;
+ for (String value : propValueList) {
+ if (value.length() > 0) {
+ valuesAreAllEmpty = false;
+ break;
+ }
+ }
+ if (valuesAreAllEmpty) {
+ return;
+ }
+
+ int type = -1;
+ String label = "";
+ boolean isPrimary = false;
+ Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
+ if (typeCollection != null) {
+ for (String typeString : typeCollection) {
+ typeString = typeString.toUpperCase();
+ if (typeString.equals(Constants.ATTR_TYPE_PREF) && !mPrefIsSet_Address) {
+ // Only first "PREF" is considered.
+ mPrefIsSet_Address = true;
+ isPrimary = true;
+ } else if (typeString.equals(Constants.ATTR_TYPE_HOME)) {
+ type = StructuredPostal.TYPE_HOME;
+ label = "";
+ } else if (typeString.equals(Constants.ATTR_TYPE_WORK) ||
+ typeString.equalsIgnoreCase("COMPANY")) {
+ // "COMPANY" seems emitted by Windows Mobile, which is not
+ // specifically supported by vCard 2.1. We assume this is same
+ // as "WORK".
+ type = StructuredPostal.TYPE_WORK;
+ label = "";
+ } else if (typeString.equals("PARCEL") ||
+ typeString.equals("DOM") ||
+ typeString.equals("INTL")) {
+ // We do not have any appropriate way to store this information.
+ } else {
+ if (typeString.startsWith("X-") && type < 0) {
+ typeString = typeString.substring(2);
+ }
+ // vCard 3.0 allows iana-token. Also some vCard 2.1 exporters
+ // emit non-standard types. We do not handle their values now.
+ type = StructuredPostal.TYPE_CUSTOM;
+ label = typeString;
+ }
+ }
+ }
+ // We use "HOME" as default
+ if (type < 0) {
+ type = StructuredPostal.TYPE_HOME;
+ }
+
+ addPostal(type, propValueList, label, isPrimary);
+ } else if (propName.equals("EMAIL")) {
+ int type = -1;
+ String label = null;
+ boolean isPrimary = false;
+ Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
+ if (typeCollection != null) {
+ for (String typeString : typeCollection) {
+ typeString = typeString.toUpperCase();
+ if (typeString.equals(Constants.ATTR_TYPE_PREF) && !mPrefIsSet_Email) {
+ // Only first "PREF" is considered.
+ mPrefIsSet_Email = true;
+ isPrimary = true;
+ } else if (typeString.equals(Constants.ATTR_TYPE_HOME)) {
+ type = Email.TYPE_HOME;
+ } else if (typeString.equals(Constants.ATTR_TYPE_WORK)) {
+ type = Email.TYPE_WORK;
+ } else if (typeString.equals(Constants.ATTR_TYPE_CELL)) {
+ type = Email.TYPE_MOBILE;
+ } else {
+ if (typeString.startsWith("X-") && type < 0) {
+ typeString = typeString.substring(2);
+ }
+ // vCard 3.0 allows iana-token.
+ // We may have INTERNET (specified in vCard spec),
+ // SCHOOL, etc.
+ type = Email.TYPE_CUSTOM;
+ label = typeString;
+ }
+ }
+ }
+ if (type < 0) {
+ type = Email.TYPE_OTHER;
+ }
+ addEmail(type, propValue, label, isPrimary);
+ } else if (propName.equals("ORG")) {
+ // vCard specification does not specify other types.
+ int type = Organization.TYPE_WORK;
+ boolean isPrimary = false;
+
+ Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
+ if (typeCollection != null) {
+ for (String typeString : typeCollection) {
+ if (typeString.equals(Constants.ATTR_TYPE_PREF) && !mPrefIsSet_Organization) {
+ // vCard specification officially does not have PREF in ORG.
+ // This is just for safety.
+ mPrefIsSet_Organization = true;
+ isPrimary = true;
+ }
+ }
+ }
+
+ StringBuilder builder = new StringBuilder();
+ for (Iterator<String> iter = propValueList.iterator(); iter.hasNext();) {
+ builder.append(iter.next());
+ if (iter.hasNext()) {
+ builder.append(' ');
+ }
+ }
+ addOrganization(type, builder.toString(), "", isPrimary);
+ } else if (propName.equals("TITLE")) {
+ setPosition(propValue);
+ } else if (propName.equals("ROLE")) {
+ setPosition(propValue);
+ } else if (propName.equals("PHOTO") || propName.equals("LOGO")) {
+ String formatName = null;
+ Collection<String> typeCollection = paramMap.get("TYPE");
+ if (typeCollection != null) {
+ formatName = typeCollection.iterator().next();
+ }
+ Collection<String> paramMapValue = paramMap.get("VALUE");
+ if (paramMapValue != null && paramMapValue.contains("URL")) {
+ // Currently we do not have appropriate example for testing this case.
+ } else {
+ addPhotoBytes(formatName, propBytes);
+ }
+ } else if (propName.equals("TEL")) {
+ Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
+ Object typeObject = VCardUtils.getPhoneTypeFromStrings(typeCollection);
+ final int type;
+ final String label;
+ if (typeObject instanceof Integer) {
+ type = (Integer)typeObject;
+ label = null;
+ } else {
+ type = Phone.TYPE_CUSTOM;
+ label = typeObject.toString();
+ }
+
+ final boolean isPrimary;
+ if (!mPrefIsSet_Phone && typeCollection != null &&
+ typeCollection.contains(Constants.ATTR_TYPE_PREF)) {
+ mPrefIsSet_Phone = true;
+ isPrimary = true;
+ } else {
+ isPrimary = false;
+ }
+ addPhone(type, propValue, label, isPrimary);
+ } else if (propName.equals(Constants.PROPERTY_X_SKYPE_PSTNNUMBER)) {
+ // The phone number available via Skype.
+ Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
+ // XXX: should use TYPE_CUSTOM + the label "Skype"? (which may need localization)
+ int type = Phone.TYPE_OTHER;
+ final String label = null;
+ final boolean isPrimary;
+ if (!mPrefIsSet_Phone && typeCollection != null &&
+ typeCollection.contains(Constants.ATTR_TYPE_PREF)) {
+ mPrefIsSet_Phone = true;
+ isPrimary = true;
+ } else {
+ isPrimary = false;
+ }
+ addPhone(type, propValue, label, isPrimary);
+ } else if (sImMap.containsKey(propName)){
+ int type = sImMap.get(propName);
+ boolean isPrimary = false;
+ final Collection<String> typeCollection = paramMap.get(Constants.ATTR_TYPE);
+ if (typeCollection != null) {
+ for (String typeString : typeCollection) {
+ if (typeString.equals(Constants.ATTR_TYPE_PREF)) {
+ isPrimary = true;
+ } else if (typeString.equalsIgnoreCase(Constants.ATTR_TYPE_HOME)) {
+ type = Phone.TYPE_HOME;
+ } else if (typeString.equalsIgnoreCase(Constants.ATTR_TYPE_WORK)) {
+ type = Phone.TYPE_WORK;
+ }
+ }
+ }
+ if (type < 0) {
+ type = Phone.TYPE_HOME;
+ }
+ addIm(type, propValue, null, isPrimary);
+ } else if (propName.equals("NOTE")) {
+ addNote(propValue);
+ } else if (propName.equals("URL")) {
+ if (mWebsiteList == null) {
+ mWebsiteList = new ArrayList<String>(1);
+ }
+ mWebsiteList.add(propValue);
+ } else if (propName.equals("X-PHONETIC-FIRST-NAME")) {
+ mPhoneticGivenName = propValue;
+ } else if (propName.equals("X-PHONETIC-MIDDLE-NAME")) {
+ mPhoneticMiddleName = propValue;
+ } else if (propName.equals("X-PHONETIC-LAST-NAME")) {
+ mPhoneticFamilyName = propValue;
+ } else if (propName.equals("BDAY")) {
+ mBirthday = propValue;
+ /*} else if (propName.equals("REV")) {
+ // Revision of this VCard entry. I think we can ignore this.
+ } else if (propName.equals("UID")) {
+ } else if (propName.equals("KEY")) {
+ // Type is X509 or PGP? I don't know how to handle this...
+ } else if (propName.equals("MAILER")) {
+ } else if (propName.equals("TZ")) {
+ } else if (propName.equals("GEO")) {
+ } else if (propName.equals("CLASS")) {
+ // vCard 3.0 only.
+ // e.g. CLASS:CONFIDENTIAL
+ } else if (propName.equals("PROFILE")) {
+ // VCard 3.0 only. Must be "VCARD". I think we can ignore this.
+ } else if (propName.equals("CATEGORIES")) {
+ // VCard 3.0 only.
+ // e.g. CATEGORIES:INTERNET,IETF,INDUSTRY,INFORMATION TECHNOLOGY
+ } else if (propName.equals("SOURCE")) {
+ // VCard 3.0 only.
+ } else if (propName.equals("PRODID")) {
+ // VCard 3.0 only.
+ // To specify the identifier for the product that created
+ // the vCard object.*/
+ } else {
+ // Unknown X- words and IANA token.
+ }
+ }
+
+ public String getDisplayName() {
+ if (mDisplayName == null) {
+ constructDisplayName();
+ }
+ return mDisplayName;
+ }
+
+ /**
+ * Construct the display name. The constructed data must not be null.
+ */
+ private void constructDisplayName() {
+ if (!(TextUtils.isEmpty(mFamilyName) && TextUtils.isEmpty(mGivenName))) {
+ StringBuilder builder = new StringBuilder();
+ List<String> nameList;
+ switch (VCardConfig.getNameOrderType(mVCardType)) {
+ case VCardConfig.NAME_ORDER_JAPANESE:
+ if (VCardUtils.containsOnlyAscii(mFamilyName) &&
+ VCardUtils.containsOnlyAscii(mGivenName)) {
+ nameList = Arrays.asList(mPrefix, mGivenName, mMiddleName, mFamilyName, mSuffix);
+ } else {
+ nameList = Arrays.asList(mPrefix, mFamilyName, mMiddleName, mGivenName, mSuffix);
+ }
+ break;
+ case VCardConfig.NAME_ORDER_EUROPE:
+ nameList = Arrays.asList(mPrefix, mMiddleName, mGivenName, mFamilyName, mSuffix);
+ break;
+ default:
+ nameList = Arrays.asList(mPrefix, mGivenName, mMiddleName, mFamilyName, mSuffix);
+ break;
+ }
+ boolean first = true;
+ for (String namePart : nameList) {
+ if (!TextUtils.isEmpty(namePart)) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(' ');
+ }
+ builder.append(namePart);
+ }
+ }
+ mDisplayName = builder.toString();
+ } else if (!TextUtils.isEmpty(mFullName)) {
+ mDisplayName = mFullName;
+ } else if (!(TextUtils.isEmpty(mPhoneticFamilyName) &&
+ TextUtils.isEmpty(mPhoneticGivenName))) {
+ mDisplayName = VCardUtils.constructNameFromElements(mVCardType,
+ mPhoneticFamilyName, mPhoneticMiddleName, mPhoneticGivenName);
+ } else if (mEmailList != null && mEmailList.size() > 0) {
+ mDisplayName = mEmailList.get(0).data;
+ } else if (mPhoneList != null && mPhoneList.size() > 0) {
+ mDisplayName = mPhoneList.get(0).data;
+ } else if (mPostalList != null && mPostalList.size() > 0) {
+ mDisplayName = mPostalList.get(0).getFormattedAddress(mVCardType);
+ }
+
+ if (mDisplayName == null) {
+ mDisplayName = "";
+ }
+ }
+
+ /**
+ * Consolidate several fielsds (like mName) using name candidates,
+ */
+ public void consolidateFields() {
+ constructDisplayName();
+
+ if (mPhoneticFullName != null) {
+ mPhoneticFullName = mPhoneticFullName.trim();
+ }
+
+ // If there is no "PREF", we choose the first entries as primary.
+ if (!mPrefIsSet_Phone && mPhoneList != null && mPhoneList.size() > 0) {
+ mPhoneList.get(0).isPrimary = true;
+ }
+
+ if (!mPrefIsSet_Address && mPostalList != null && mPostalList.size() > 0) {
+ mPostalList.get(0).isPrimary = true;
+ }
+ if (!mPrefIsSet_Email && mEmailList != null && mEmailList.size() > 0) {
+ mEmailList.get(0).isPrimary = true;
+ }
+ if (!mPrefIsSet_Organization && mOrganizationList != null && mOrganizationList.size() > 0) {
+ mOrganizationList.get(0).isPrimary = true;
+ }
+ }
+
+ public void pushIntoContentResolver(ContentResolver resolver) {
+ ArrayList<ContentProviderOperation> operationList =
+ new ArrayList<ContentProviderOperation>();
+ ContentProviderOperation.Builder builder =
+ ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
+ builder.withValues(new ContentValues());
+ operationList.add(builder.build());
+
+ {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+
+ builder.withValue(StructuredName.GIVEN_NAME, mGivenName);
+ builder.withValue(StructuredName.FAMILY_NAME, mFamilyName);
+ builder.withValue(StructuredName.MIDDLE_NAME, mMiddleName);
+ builder.withValue(StructuredName.PREFIX, mPrefix);
+ builder.withValue(StructuredName.SUFFIX, mSuffix);
+
+ builder.withValue(StructuredName.PHONETIC_GIVEN_NAME, mPhoneticGivenName);
+ builder.withValue(StructuredName.PHONETIC_FAMILY_NAME, mPhoneticFamilyName);
+ builder.withValue(StructuredName.PHONETIC_MIDDLE_NAME, mPhoneticMiddleName);
+
+ builder.withValue(StructuredName.DISPLAY_NAME, getDisplayName());
+ operationList.add(builder.build());
+ }
+
+ if (mNickNameList != null && mNickNameList.size() > 0) {
+ boolean first = true;
+ for (String nickName : mNickNameList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Nickname.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE);
+
+ builder.withValue(Nickname.TYPE, Nickname.TYPE_DEFAULT);
+ builder.withValue(Nickname.NAME, nickName);
+ if (first) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ first = false;
+ }
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mPhoneList != null) {
+ for (PhoneData phoneData : mPhoneList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+
+ builder.withValue(Phone.TYPE, phoneData.type);
+ if (phoneData.type == Phone.TYPE_CUSTOM) {
+ builder.withValue(Phone.LABEL, phoneData.label);
+ }
+ builder.withValue(Phone.NUMBER, phoneData.data);
+ if (phoneData.isPrimary) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ }
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mOrganizationList != null) {
+ boolean first = true;
+ for (OrganizationData organizationData : mOrganizationList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Organization.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
+
+ // Currently, we do not use TYPE_CUSTOM.
+ builder.withValue(Organization.TYPE, organizationData.type);
+ builder.withValue(Organization.COMPANY, organizationData.companyName);
+ builder.withValue(Organization.TITLE, organizationData.positionName);
+ if (first) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ }
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mEmailList != null) {
+ for (EmailData emailData : mEmailList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Email.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+
+ builder.withValue(Email.TYPE, emailData.type);
+ if (emailData.type == Email.TYPE_CUSTOM) {
+ builder.withValue(Email.LABEL, emailData.label);
+ }
+ builder.withValue(Email.DATA, emailData.data);
+ if (emailData.isPrimary) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ }
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mPostalList != null) {
+ for (PostalData postalData : mPostalList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ VCardUtils.insertStructuredPostalDataUsingContactsStruct(
+ mVCardType, builder, postalData);
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mImList != null) {
+ for (ImData imData : mImList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Im.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+
+ builder.withValue(Im.TYPE, imData.type);
+ if (imData.type == Im.TYPE_CUSTOM) {
+ builder.withValue(Im.LABEL, imData.label);
+ }
+ builder.withValue(Im.DATA, imData.data);
+ if (imData.isPrimary) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ }
+ }
+ }
+
+ if (mNoteList != null) {
+ for (String note : mNoteList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Note.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
+
+ builder.withValue(Note.NOTE, note);
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mPhotoList != null) {
+ boolean first = true;
+ for (PhotoData photoData : mPhotoList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Photo.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
+ builder.withValue(Photo.PHOTO, photoData.photoBytes);
+ if (first) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ first = false;
+ }
+ operationList.add(builder.build());
+ }
+ }
+
+ if (mWebsiteList != null) {
+ for (String website : mWebsiteList) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Website.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Website.CONTENT_ITEM_TYPE);
+ builder.withValue(Website.URL, website);
+ operationList.add(builder.build());
+ }
+ }
+
+ if (!TextUtils.isEmpty(mBirthday)) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Miscellaneous.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Miscellaneous.CONTENT_ITEM_TYPE);
+ builder.withValue(Miscellaneous.BIRTHDAY, mBirthday);
+ operationList.add(builder.build());
+ }
+
+ try {
+ resolver.applyBatch(ContactsContract.AUTHORITY, operationList);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
+ } catch (OperationApplicationException e) {
+ Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
+ }
+ }
+
+ public boolean isIgnorable() {
+ return getDisplayName().length() == 0;
+ }
+
+ private String listToString(List<String> list){
+ final int size = list.size();
+ if (size > 1) {
+ StringBuilder builder = new StringBuilder();
+ int i = 0;
+ for (String type : list) {
+ builder.append(type);
+ if (i < size - 1) {
+ builder.append(";");
+ }
+ }
+ return builder.toString();
+ } else if (size == 1) {
+ return list.get(0);
+ } else {
+ return "";
+ }
+ }
+}
diff --git a/core/java/android/pim/vcard/EntryCommitter.java b/core/java/android/pim/vcard/EntryCommitter.java
new file mode 100644
index 0000000..3f1655d
--- /dev/null
+++ b/core/java/android/pim/vcard/EntryCommitter.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.pim.vcard;
+
+import android.content.ContentResolver;
+import android.util.Log;
+
+/**
+ * EntryHandler implementation which commits the entry to Contacts Provider
+ */
+public class EntryCommitter implements EntryHandler {
+ public static String LOG_TAG = "vcard.EntryComitter";
+
+ private ContentResolver mContentResolver;
+ private long mTimeToCommit;
+
+ public EntryCommitter(ContentResolver resolver) {
+ mContentResolver = resolver;
+ }
+
+ public void onParsingStart() {
+ }
+
+ public void onParsingEnd() {
+ if (VCardConfig.showPerformanceLog()) {
+ Log.d(LOG_TAG, String.format("time to commit entries: %d ms", mTimeToCommit));
+ }
+ }
+
+ public void onEntryCreated(final ContactStruct contactStruct) {
+ long start = System.currentTimeMillis();
+ contactStruct.pushIntoContentResolver(mContentResolver);
+ mTimeToCommit += System.currentTimeMillis() - start;
+ }
+} \ No newline at end of file
diff --git a/core/java/android/pim/vcard/EntryHandler.java b/core/java/android/pim/vcard/EntryHandler.java
new file mode 100644
index 0000000..7fb8114
--- /dev/null
+++ b/core/java/android/pim/vcard/EntryHandler.java
@@ -0,0 +1,38 @@
+/*
+ * 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.pim.vcard;
+
+/**
+ * Unlike {@link VCardBuilder}, this (and {@link VCardDataBuilder}) assumes
+ * "each VCard entry should be correctly parsed and passed to each EntryHandler object",
+ */
+public interface EntryHandler {
+ /**
+ * Called when the parsing started.
+ */
+ public void onParsingStart();
+
+ /**
+ * The method called when one VCard entry is successfully created
+ */
+ public void onEntryCreated(final ContactStruct entry);
+
+ /**
+ * Called when the parsing ended.
+ * Able to be use this method for showing performance log, etc.
+ */
+ public void onParsingEnd();
+}
diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java
new file mode 100644
index 0000000..e1c4b33
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardBuilder.java
@@ -0,0 +1,64 @@
+/*
+ * 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.pim.vcard;
+
+import java.util.List;
+
+public interface VCardBuilder {
+ void start();
+
+ void end();
+
+ /**
+ * BEGIN:VCARD
+ */
+ void startRecord(String type);
+
+ /** END:VXX */
+ void endRecord();
+
+ void startProperty();
+
+ void endProperty();
+
+ /**
+ * @param group
+ */
+ void propertyGroup(String group);
+
+ /**
+ * @param name
+ * N <br>
+ * N
+ */
+ void propertyName(String name);
+
+ /**
+ * @param type
+ * LANGUAGE \ ENCODING <br>
+ * ;LANGUage= \ ;ENCODING=
+ */
+ void propertyParamType(String type);
+
+ /**
+ * @param value
+ * FR-EN \ GBK <br>
+ * FR-EN \ GBK
+ */
+ void propertyParamValue(String value);
+
+ void propertyValues(List<String> values);
+}
diff --git a/core/java/android/pim/vcard/VCardBuilderCollection.java b/core/java/android/pim/vcard/VCardBuilderCollection.java
new file mode 100644
index 0000000..e3985b6
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardBuilderCollection.java
@@ -0,0 +1,99 @@
+/*
+ * 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.pim.vcard;
+
+import java.util.Collection;
+import java.util.List;
+
+public class VCardBuilderCollection implements VCardBuilder {
+
+ private final Collection<VCardBuilder> mVCardBuilderCollection;
+
+ public VCardBuilderCollection(Collection<VCardBuilder> vBuilderCollection) {
+ mVCardBuilderCollection = vBuilderCollection;
+ }
+
+ public Collection<VCardBuilder> getVCardBuilderBaseCollection() {
+ return mVCardBuilderCollection;
+ }
+
+ public void start() {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.start();
+ }
+ }
+
+ public void end() {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.end();
+ }
+ }
+
+ public void startRecord(String type) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.startRecord(type);
+ }
+ }
+
+ public void endRecord() {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.endRecord();
+ }
+ }
+
+ public void startProperty() {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.startProperty();
+ }
+ }
+
+
+ public void endProperty() {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.endProperty();
+ }
+ }
+
+ public void propertyGroup(String group) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.propertyGroup(group);
+ }
+ }
+
+ public void propertyName(String name) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.propertyName(name);
+ }
+ }
+
+ public void propertyParamType(String type) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.propertyParamType(type);
+ }
+ }
+
+ public void propertyParamValue(String value) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.propertyParamValue(value);
+ }
+ }
+
+ public void propertyValues(List<String> values) {
+ for (VCardBuilder builder : mVCardBuilderCollection) {
+ builder.propertyValues(values);
+ }
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
new file mode 100644
index 0000000..5a09c64
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -0,0 +1,1436 @@
+/*
+ * 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.pim.vcard;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Entity;
+import android.content.EntityIterator;
+import android.content.Entity.NamedContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
+import android.os.RemoteException;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Miscellaneous;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.Note;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.text.TextUtils;
+import android.util.CharsetUtils;
+import android.util.Log;
+
+import java.io.BufferedWriter;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * The class for composing VCard from Contacts information. Note that this is
+ * completely differnt implementation from
+ * android.syncml.pim.vcard.VCardComposer, which is not maintained anymore.
+ * </p>
+ *
+ * <p>
+ * Usually, this class should be used like this.
+ * </p>
+ *
+ * <pre class="prettyprint"> VCardComposer composer = null; try { composer = new
+ * VCardComposer(context); composer.addHandler(composer.new
+ * HandlerForOutputStream(outputStream)); if (!composer.init()) { // Do
+ * something handling the situation. return; } while (!composer.isAfterLast()) {
+ * if (mCanceled) { // Assume a user may cancel this operation during the
+ * export. return; } if (!composer.createOneEntry()) { // Do something handling
+ * the error situation. return; } } } finally { if (composer != null) {
+ * composer.terminate(); } } </pre>
+ */
+public class VCardComposer {
+ private static final String LOG_TAG = "vcard.VCardComposer";
+
+ public static interface OneEntryHandler {
+ public boolean onInit(Context context);
+
+ public boolean onEntryCreated(String vcard);
+
+ public void onTerminate();
+ }
+
+ /**
+ * <p>
+ * An useful example handler, which emits VCard String to outputstream one
+ * by one.
+ * </p>
+ * <p>
+ * The input OutputStream object is closed() on {{@link #onTerminate()}.
+ * Must not close the stream outside.
+ * </p>
+ */
+ public class HandlerForOutputStream implements OneEntryHandler {
+ @SuppressWarnings("hiding")
+ private static final String LOG_TAG = "vcard.VCardComposer.HandlerForOutputStream";
+
+ private OutputStream mOutputStream; // mWriter will close this.
+ private Writer mWriter;
+
+ private boolean mFinishIsCalled = false;
+
+ /**
+ * Input stream will be closed on the detruction of this object.
+ */
+ public HandlerForOutputStream(OutputStream outputStream) {
+ mOutputStream = outputStream;
+ }
+
+ public boolean onInit(Context context) {
+ try {
+ mWriter = new BufferedWriter(new OutputStreamWriter(
+ mOutputStream, mCharsetString));
+ } catch (UnsupportedEncodingException e1) {
+ Log.e(LOG_TAG, "Unsupported charset: " + mCharsetString);
+ mErrorReason = "Encoding is not supported (usually this does not happen!): "
+ + mCharsetString;
+ return false;
+ }
+
+ if (mIsDoCoMo) {
+ try {
+ // Create one empty entry.
+ mWriter.write(createOneEntryInternal("-1"));
+ } catch (IOException e) {
+ Log.e(LOG_TAG,
+ "IOException occurred during exportOneContactData: "
+ + e.getMessage());
+ mErrorReason = "IOException occurred: " + e.getMessage();
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean onEntryCreated(String vcard) {
+ try {
+ mWriter.write(vcard);
+ } catch (IOException e) {
+ Log.e(LOG_TAG,
+ "IOException occurred during exportOneContactData: "
+ + e.getMessage());
+ mErrorReason = "IOException occurred: " + e.getMessage();
+ return false;
+ }
+ return true;
+ }
+
+ public void onTerminate() {
+ if (mWriter != null) {
+ try {
+ // Flush and sync the data so that a user is able to pull
+ // the SDCard just after
+ // the export.
+ mWriter.flush();
+ if (mOutputStream != null
+ && mOutputStream instanceof FileOutputStream) {
+ ((FileOutputStream) mOutputStream).getFD().sync();
+ }
+ } catch (IOException e) {
+ Log.d(LOG_TAG,
+ "IOException during closing the output stream: "
+ + e.getMessage());
+ } finally {
+ try {
+ mWriter.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public void finalize() {
+ if (!mFinishIsCalled) {
+ onTerminate();
+ }
+ }
+ }
+
+ public static final String VCARD_TYPE_STRING_DOCOMO = "docomo";
+
+ private static final String VCARD_PROPERTY_ADR = "ADR";
+ private static final String VCARD_PROPERTY_BEGIN = "BEGIN";
+ private static final String VCARD_PROPERTY_EMAIL = "EMAIL";
+ private static final String VCARD_PROPERTY_END = "END";
+ private static final String VCARD_PROPERTY_NAME = "N";
+ private static final String VCARD_PROPERTY_FULL_NAME = "FN";
+ private static final String VCARD_PROPERTY_NOTE = "NOTE";
+ private static final String VCARD_PROPERTY_ORG = "ORG";
+ private static final String VCARD_PROPERTY_SOUND = "SOUND";
+ private static final String VCARD_PROPERTY_SORT_STRING = "SORT-STRING";
+ private static final String VCARD_PROPERTY_NICKNAME = "NICKNAME";
+ private static final String VCARD_PROPERTY_TEL = "TEL";
+ private static final String VCARD_PROPERTY_TITLE = "TITLE";
+ private static final String VCARD_PROPERTY_PHOTO = "PHOTO";
+ private static final String VCARD_PROPERTY_VERSION = "VERSION";
+ private static final String VCARD_PROPERTY_URL = "URL";
+ private static final String VCARD_PROPERTY_BIRTHDAY = "BDAY";
+
+ private static final String VCARD_PROPERTY_X_PHONETIC_FIRST_NAME = "X-PHONETIC-FIRST-NAME";
+ private static final String VCARD_PROPERTY_X_PHONETIC_MIDDLE_NAME = "X-PHONETIC-MIDDLE-NAME";
+ private static final String VCARD_PROPERTY_X_PHONETIC_LAST_NAME = "X-PHONETIC-LAST-NAME";
+
+ // Android specific properties
+ private static final String VCARD_PROPERTY_X_PHONETIC_NAME = "X-PHONETIC-NAME";
+ private static final String VCARD_PROPERTY_X_NICKNAME = "X-NICKNAME";
+ // TODO: add properties like X-LATITUDE
+
+ // Properties for DoCoMo vCard.
+ private static final String VCARD_PROPERTY_X_CLASS = "X-CLASS";
+ private static final String VCARD_PROPERTY_X_REDUCTION = "X-REDUCTION";
+ private static final String VCARD_PROPERTY_X_NO = "X-NO";
+ private static final String VCARD_PROPERTY_X_DCM_HMN_MODE = "X-DCM-HMN-MODE";
+
+ private static final String VCARD_DATA_VCARD = "VCARD";
+ private static final String VCARD_DATA_PUBLIC = "PUBLIC";
+
+ private static final String VCARD_ATTR_SEPARATOR = ";";
+ private static final String VCARD_COL_SEPARATOR = "\r\n";
+ private static final String VCARD_DATA_SEPARATOR = ":";
+ private static final String VCARD_ITEM_SEPARATOR = ";";
+ private static final String VCARD_WS = " ";
+
+ // Type strings are now in VCardConstants.java.
+
+ private static final String VCARD_ATTR_ENCODING_QP = "ENCODING=QUOTED-PRINTABLE";
+
+ private static final String VCARD_ATTR_ENCODING_BASE64_V21 = "ENCODING=BASE64";
+ private static final String VCARD_ATTR_ENCODING_BASE64_V30 = "ENCODING=b";
+
+ private static final String SHIFT_JIS = "SHIFT_JIS";
+
+ private final Context mContext;
+ private final int mVCardType;
+ private final boolean mCareHandlerErrors;
+ private final ContentResolver mContentResolver;
+
+ // Convenient member variables about the restriction of the vCard format.
+ // Used for not calling the same methods returning same results.
+ private final boolean mIsV30;
+ private final boolean mIsJapaneseMobilePhone;
+ private final boolean mOnlyOneNoteFieldIsAvailable;
+ private final boolean mIsDoCoMo;
+ private final boolean mUsesQuotedPrintable;
+ private final boolean mUsesAndroidProperty;
+ private final boolean mUsesDefactProperty;
+ private final boolean mUsesShiftJis;
+
+ private Cursor mCursor;
+ private int mIdColumn;
+
+ private String mCharsetString;
+ private static String mVCardAttributeCharset;
+ private boolean mTerminateIsCalled;
+ private List<OneEntryHandler> mHandlerList;
+
+ private String mErrorReason = "No error";
+
+ private static final Map<Integer, String> sImMap;
+
+ static {
+ sImMap = new HashMap<Integer, String>();
+ sImMap.put(Im.PROTOCOL_AIM, Constants.PROPERTY_X_AIM);
+ sImMap.put(Im.PROTOCOL_MSN, Constants.PROPERTY_X_MSN);
+ sImMap.put(Im.PROTOCOL_YAHOO, Constants.PROPERTY_X_YAHOO);
+ sImMap.put(Im.PROTOCOL_ICQ, Constants.PROPERTY_X_ICQ);
+ sImMap.put(Im.PROTOCOL_JABBER, Constants.PROPERTY_X_JABBER);
+ sImMap.put(Im.PROTOCOL_SKYPE, Constants.PROPERTY_X_SKYPE_USERNAME);
+ // Google talk is a special case.
+ }
+
+
+ public VCardComposer(Context context) {
+ this(context, VCardConfig.VCARD_TYPE_DEFAULT, true);
+ }
+
+ public VCardComposer(Context context, String vcardTypeStr,
+ boolean careHandlerErrors) {
+ this(context, VCardConfig.getVCardTypeFromString(vcardTypeStr),
+ careHandlerErrors);
+ }
+
+ public VCardComposer(Context context, int vcardType, boolean careHandlerErrors) {
+ mContext = context;
+ mVCardType = vcardType;
+ mCareHandlerErrors = careHandlerErrors;
+ mContentResolver = context.getContentResolver();
+
+ mIsV30 = VCardConfig.isV30(vcardType);
+ mUsesQuotedPrintable = VCardConfig.usesQuotedPrintable(vcardType);
+ mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
+ mIsJapaneseMobilePhone = VCardConfig
+ .needsToConvertPhoneticString(vcardType);
+ mOnlyOneNoteFieldIsAvailable = VCardConfig
+ .onlyOneNoteFieldIsAvailable(vcardType);
+ mUsesAndroidProperty = VCardConfig
+ .usesAndroidSpecificProperty(vcardType);
+ mUsesDefactProperty = VCardConfig.usesDefactProperty(vcardType);
+ mUsesShiftJis = VCardConfig.usesShiftJis(vcardType);
+
+ if (mIsDoCoMo) {
+ mCharsetString = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
+ // Do not use mCharsetString bellow since it is different from "SHIFT_JIS" but
+ // may be "DOCOMO_SHIFT_JIS" or something like that (internal expression used in
+ // Android, not shown to the public).
+ mVCardAttributeCharset = "CHARSET=" + SHIFT_JIS;
+ } else if (mUsesShiftJis) {
+ mCharsetString = CharsetUtils.charsetForVendor(SHIFT_JIS).name();
+ mVCardAttributeCharset = "CHARSET=" + SHIFT_JIS;
+ } else {
+ mCharsetString = "UTF-8";
+ mVCardAttributeCharset = "CHARSET=UTF-8";
+ }
+ }
+
+ /**
+ * Must call before {{@link #init()}.
+ */
+ public void addHandler(OneEntryHandler handler) {
+ if (mHandlerList == null) {
+ mHandlerList = new ArrayList<OneEntryHandler>();
+ }
+ mHandlerList.add(handler);
+ }
+
+ public boolean init() {
+ return init(null, null);
+ }
+
+ /**
+ * @return Returns true when initialization is successful and all the other
+ * methods are available. Returns false otherwise.
+ */
+ public boolean init(final String selection, final String[] selectionArgs) {
+ if (mCareHandlerErrors) {
+ List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
+ mHandlerList.size());
+ for (OneEntryHandler handler : mHandlerList) {
+ if (!handler.onInit(mContext)) {
+ for (OneEntryHandler finished : finishedList) {
+ finished.onTerminate();
+ }
+ return false;
+ }
+ }
+ } else {
+ // Just ignore the false returned from onInit().
+ for (OneEntryHandler handler : mHandlerList) {
+ handler.onInit(mContext);
+ }
+ }
+
+ final String[] projection = new String[] {Contacts._ID,};
+
+ // TODO: thorow an appropriate exception!
+ mCursor = mContentResolver.query(RawContacts.CONTENT_URI, projection,
+ selection, selectionArgs, null);
+ if (mCursor == null || !mCursor.moveToFirst()) {
+ if (mCursor != null) {
+ try {
+ mCursor.close();
+ } catch (SQLiteException e) {
+ Log.e(LOG_TAG, "SQLiteException on Cursor#close(): "
+ + e.getMessage());
+ }
+ mCursor = null;
+ }
+ mErrorReason = "Getting database information failed.";
+ return false;
+ }
+
+ mIdColumn = mCursor.getColumnIndex(Contacts._ID);
+
+ return true;
+ }
+
+ public boolean createOneEntry() {
+ if (mCursor == null || mCursor.isAfterLast()) {
+ // TODO: ditto
+ mErrorReason = "Not initialized or database has some problem.";
+ return false;
+ }
+ String name = null;
+ String vcard;
+ try {
+ vcard = createOneEntryInternal(mCursor.getString(mIdColumn));
+ } catch (OutOfMemoryError error) {
+ // Maybe some data (e.g. photo) is too big to have in memory. But it
+ // should be rare.
+ Log.e(LOG_TAG, "OutOfMemoryError occured. Ignore the entry: "
+ + name);
+ System.gc();
+ // TODO: should tell users what happened?
+ return true;
+ } finally {
+ mCursor.moveToNext();
+ }
+
+ // This function does not care the OutOfMemoryError on the handler side
+ // :-P
+ if (mCareHandlerErrors) {
+ List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
+ mHandlerList.size());
+ for (OneEntryHandler handler : mHandlerList) {
+ if (!handler.onEntryCreated(vcard)) {
+ return false;
+ }
+ }
+ } else {
+ for (OneEntryHandler handler : mHandlerList) {
+ handler.onEntryCreated(vcard);
+ }
+ }
+
+ return true;
+ }
+
+ private String createOneEntryInternal(final String contactId) {
+ final StringBuilder builder = new StringBuilder();
+ appendVCardLine(builder, VCARD_PROPERTY_BEGIN, VCARD_DATA_VCARD);
+ if (mIsV30) {
+ appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V30);
+ } else {
+ appendVCardLine(builder, VCARD_PROPERTY_VERSION, Constants.VERSION_V21);
+ }
+
+ final Map<String, List<ContentValues>> contentValuesListMap =
+ new HashMap<String, List<ContentValues>>();
+
+ final String selection = Data.RAW_CONTACT_ID + "=?";
+ final String[] selectionArgs = new String[] {contactId};
+ EntityIterator entityIterator = null;
+ try {
+ entityIterator = mContentResolver.queryEntities(
+ RawContacts.CONTENT_URI, selection, selectionArgs, null);
+ while (entityIterator.hasNext()) {
+ Entity entity = entityIterator.next();
+ for (NamedContentValues namedContentValues : entity
+ .getSubValues()) {
+ ContentValues contentValues = namedContentValues.values;
+ String key = contentValues.getAsString(Data.MIMETYPE);
+ if (key != null) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(key);
+ if (contentValuesList == null) {
+ contentValuesList = new ArrayList<ContentValues>();
+ contentValuesListMap.put(key, contentValuesList);
+ }
+ contentValuesList.add(contentValues);
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, String.format("RemoteException at id %s (%s)",
+ contactId, e.getMessage()));
+ return "";
+ } finally {
+ if (entityIterator != null) {
+ entityIterator.close();
+ }
+ }
+
+ // TODO: consolidate order? (low priority)
+ appendStructuredNames(builder, contentValuesListMap);
+ appendNickNames(builder, contentValuesListMap);
+ appendPhones(builder, contentValuesListMap);
+ appendEmails(builder, contentValuesListMap);
+ appendPostals(builder, contentValuesListMap);
+ appendIms(builder, contentValuesListMap);
+ appendWebsites(builder, contentValuesListMap);
+ appendBirthday(builder, contentValuesListMap);
+ appendOrganizations(builder, contentValuesListMap);
+ appendPhotos(builder, contentValuesListMap);
+ appendNotes(builder, contentValuesListMap);
+ // TODO: GroupMembership... What?
+
+ if (mIsDoCoMo) {
+ appendVCardLine(builder, VCARD_PROPERTY_X_CLASS, VCARD_DATA_PUBLIC);
+ appendVCardLine(builder, VCARD_PROPERTY_X_REDUCTION, "");
+ appendVCardLine(builder, VCARD_PROPERTY_X_NO, "");
+ appendVCardLine(builder, VCARD_PROPERTY_X_DCM_HMN_MODE, "");
+ }
+
+ appendVCardLine(builder, VCARD_PROPERTY_END, VCARD_DATA_VCARD);
+
+ return builder.toString();
+ }
+
+ public void terminate() {
+ for (OneEntryHandler handler : mHandlerList) {
+ handler.onTerminate();
+ }
+
+ if (mCursor != null) {
+ try {
+ mCursor.close();
+ } catch (SQLiteException e) {
+ Log.e(LOG_TAG, "SQLiteException on Cursor#close(): "
+ + e.getMessage());
+ }
+ mCursor = null;
+ }
+
+ mTerminateIsCalled = true;
+ }
+
+ @Override
+ public void finalize() {
+ if (!mTerminateIsCalled) {
+ terminate();
+ }
+ }
+
+ public int getCount() {
+ if (mCursor == null) {
+ return 0;
+ }
+ return mCursor.getCount();
+ }
+
+ public boolean isAfterLast() {
+ if (mCursor == null) {
+ return false;
+ }
+ return mCursor.isAfterLast();
+ }
+
+ /**
+ * @return Return the error reason if possible.
+ */
+ public String getErrorReason() {
+ return mErrorReason;
+ }
+
+ private void appendStructuredNames(StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(StructuredName.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ appendStructuredNamesInternal(builder, contentValuesList);
+ } else if (mIsDoCoMo) {
+ appendVCardLine(builder, VCARD_PROPERTY_NAME, "");
+ }
+ }
+
+ private void appendStructuredNamesInternal(final StringBuilder builder,
+ final List<ContentValues> contentValuesList) {
+ for (ContentValues contentValues : contentValuesList) {
+ final String familyName = contentValues
+ .getAsString(StructuredName.FAMILY_NAME);
+ final String middleName = contentValues
+ .getAsString(StructuredName.MIDDLE_NAME);
+ final String givenName = contentValues
+ .getAsString(StructuredName.GIVEN_NAME);
+ final String prefix = contentValues
+ .getAsString(StructuredName.PREFIX);
+ final String suffix = contentValues
+ .getAsString(StructuredName.SUFFIX);
+ final String displayName = contentValues
+ .getAsString(StructuredName.DISPLAY_NAME);
+
+ // For now, some primary element is not encoded into Quoted-Printable, which is not
+ // valid in vCard spec strictly. In the future, we may have to have some flag to
+ // enable composer to encode these primary field into Quoted-Printable.
+ if (!TextUtils.isEmpty(familyName) || !TextUtils.isEmpty(givenName)) {
+ final String encodedFamily = escapeCharacters(familyName);
+ final String encodedGiven = escapeCharacters(givenName);
+ final String encodedMiddle = escapeCharacters(middleName);
+ final String encodedPrefix = escapeCharacters(prefix);
+ final String encodedSuffix = escapeCharacters(suffix);
+
+ // N property. This order is specified by vCard spec and does not depend on countries.
+ builder.append(VCARD_PROPERTY_NAME);
+ if (!(VCardUtils.containsOnlyAscii(familyName) &&
+ VCardUtils.containsOnlyAscii(givenName) &&
+ VCardUtils.containsOnlyAscii(middleName) &&
+ VCardUtils.containsOnlyAscii(prefix) &&
+ VCardUtils.containsOnlyAscii(suffix))) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(encodedFamily);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(encodedGiven);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(encodedMiddle);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(encodedPrefix);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(encodedSuffix);
+ builder.append(VCARD_COL_SEPARATOR);
+
+ final String encodedFullname = VCardUtils.constructNameFromElements(
+ VCardConfig.getNameOrderType(mVCardType),
+ encodedFamily, encodedMiddle, encodedGiven, encodedPrefix, encodedSuffix);
+
+ // FN property
+ builder.append(VCARD_PROPERTY_FULL_NAME);
+ builder.append(VCARD_ATTR_SEPARATOR);
+ if (!VCardUtils.containsOnlyAscii(encodedFullname)) {
+ builder.append(mVCardAttributeCharset);
+ builder.append(VCARD_DATA_SEPARATOR);
+ }
+ builder.append(encodedFullname);
+ builder.append(VCARD_COL_SEPARATOR);
+ } else if (!TextUtils.isEmpty(displayName)) {
+ builder.append(VCARD_PROPERTY_NAME);
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(escapeCharacters(displayName));
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_COL_SEPARATOR);
+ } else if (mIsDoCoMo) {
+ appendVCardLine(builder, VCARD_PROPERTY_NAME, "");
+ }
+
+ String phoneticFamilyName = contentValues
+ .getAsString(StructuredName.PHONETIC_FAMILY_NAME);
+ String phoneticMiddleName = contentValues
+ .getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
+ String phoneticGivenName = contentValues
+ .getAsString(StructuredName.PHONETIC_GIVEN_NAME);
+ if (!(TextUtils.isEmpty(phoneticFamilyName)
+ && TextUtils.isEmpty(phoneticMiddleName) && TextUtils
+ .isEmpty(phoneticGivenName))) { // if not empty
+ if (mIsJapaneseMobilePhone) {
+ phoneticFamilyName = VCardUtils
+ .toHalfWidthString(phoneticFamilyName);
+ phoneticMiddleName = VCardUtils
+ .toHalfWidthString(phoneticMiddleName);
+ phoneticGivenName = VCardUtils
+ .toHalfWidthString(phoneticGivenName);
+ }
+
+ if (mIsV30) {
+ final String sortString = VCardUtils
+ .constructNameFromElements(mVCardType,
+ phoneticFamilyName, phoneticMiddleName,
+ phoneticGivenName);
+ builder.append(VCARD_PROPERTY_SORT_STRING);
+
+ if (!VCardUtils.containsOnlyAscii(sortString)) {
+ // Strictly, adding charset information is NOT valid in
+ // VCard 3.0,
+ // but we'll add this info since parser side may be able to
+ // use the charset via
+ // this attribute field.
+ //
+ // e.g. Japanese mobile phones use Shift_Jis while RFC 2426
+ // recommends
+ // UTF-8. By adding this field, parsers may be able to know
+ // this text
+ // is NOT UTF-8 but Shift_Jis.
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(sortString);
+ builder.append(VCARD_COL_SEPARATOR);
+ } else {
+ // Note: There is no appropriate property for expressing
+ // phonetic name in
+ // VCard 2.1, while there is in VCard 3.0 (SORT-STRING).
+ // We chose to use DoCoMo's way since it is supported by a
+ // lot of
+ // Japanese mobile phones.
+ //
+ // TODO: should use Quoted-Pritable?
+ builder.append(VCARD_PROPERTY_SOUND);
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(Constants.ATTR_TYPE_X_IRMC_N);
+ builder.append(VCARD_ATTR_SEPARATOR);
+
+ if (!(VCardUtils.containsOnlyAscii(phoneticFamilyName) &&
+ VCardUtils.containsOnlyAscii(phoneticMiddleName) &&
+ VCardUtils.containsOnlyAscii(phoneticGivenName))) {
+ builder.append(mVCardAttributeCharset);
+ builder.append(VCARD_DATA_SEPARATOR);
+ }
+
+ builder.append(escapeCharacters(phoneticFamilyName));
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(escapeCharacters(phoneticMiddleName));
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(escapeCharacters(phoneticGivenName));
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_COL_SEPARATOR);
+
+ if (mUsesAndroidProperty) {
+ final String phoneticName = VCardUtils
+ .constructNameFromElements(mVCardType,
+ phoneticFamilyName, phoneticMiddleName,
+ phoneticGivenName);
+ builder.append(VCARD_PROPERTY_X_PHONETIC_NAME);
+
+ if (!VCardUtils.containsOnlyAscii(phoneticName)) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ // TODO: may need to make the text quoted-printable.
+ builder.append(phoneticName);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ }
+ } else if (mIsDoCoMo) {
+ builder.append(VCARD_PROPERTY_SOUND);
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(Constants.ATTR_TYPE_X_IRMC_N);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ if (mUsesDefactProperty) {
+ if (!TextUtils.isEmpty(phoneticGivenName)) {
+ builder.append(VCARD_PROPERTY_X_PHONETIC_FIRST_NAME);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(phoneticGivenName);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ if (!TextUtils.isEmpty(phoneticMiddleName)) {
+ builder.append(VCARD_PROPERTY_X_PHONETIC_MIDDLE_NAME);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(phoneticMiddleName);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ if (!TextUtils.isEmpty(phoneticFamilyName)) {
+ builder.append(VCARD_PROPERTY_X_PHONETIC_LAST_NAME);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(phoneticFamilyName);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ }
+ }
+ }
+
+ private void appendNickNames(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Nickname.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ final String propertyNickname;
+ if (mIsV30) {
+ propertyNickname = VCARD_PROPERTY_NICKNAME;
+ } else if (mUsesAndroidProperty) {
+ propertyNickname = VCARD_PROPERTY_X_NICKNAME;
+ } else {
+ // There's no way to add this field.
+ return;
+ }
+
+ for (ContentValues contentValues : contentValuesList) {
+ final String nickname = contentValues
+ .getAsString(Nickname.NAME);
+ if (TextUtils.isEmpty(nickname)) {
+ continue;
+ }
+ builder.append(propertyNickname);
+
+ if (!VCardUtils.containsOnlyAscii(propertyNickname)) {
+ // Strictly, this is not valid in vCard 3.0. See above.
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(escapeCharacters(nickname));
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ }
+ }
+
+ private void appendPhones(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Phone.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ appendVCardTelephoneLine(builder, contentValues
+ .getAsInteger(Phone.TYPE), contentValues
+ .getAsString(Phone.LABEL), contentValues
+ .getAsString(Phone.NUMBER));
+ }
+ } else if (mIsDoCoMo) {
+ appendVCardTelephoneLine(builder, Phone.TYPE_HOME, "", "");
+ }
+ }
+
+ private void appendEmails(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Email.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ appendVCardEmailLine(builder, contentValues
+ .getAsInteger(Email.TYPE), contentValues
+ .getAsString(Email.LABEL), contentValues
+ .getAsString(Email.DATA));
+ }
+ } else if (mIsDoCoMo) {
+ appendVCardEmailLine(builder, Email.TYPE_HOME, "", "");
+ }
+ }
+
+ private void appendPostals(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(StructuredPostal.CONTENT_ITEM_TYPE);
+
+ if (contentValuesList != null) {
+ if (mIsDoCoMo) {
+ appendPostalsForDoCoMo(builder, contentValuesList);
+ } else {
+ appendPostalsForGeneric(builder, contentValuesList);
+ }
+ } else if (mIsDoCoMo) {
+ builder.append(VCARD_PROPERTY_ADR);
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(Constants.ATTR_TYPE_HOME);
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+ }
+
+ /**
+ * Try to append just one line. If there's no appropriate address
+ * information, append an empty line.
+ */
+ private void appendPostalsForDoCoMo(final StringBuilder builder,
+ final List<ContentValues> contentValuesList) {
+ // TODO: from old, inefficient code. fix this.
+ if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
+ StructuredPostal.TYPE_HOME)) {
+ return;
+ }
+ if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
+ StructuredPostal.TYPE_WORK)) {
+ return;
+ }
+ if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
+ StructuredPostal.TYPE_OTHER)) {
+ return;
+ }
+ if (appendPostalsForDoCoMoInternal(builder, contentValuesList,
+ StructuredPostal.TYPE_CUSTOM)) {
+ return;
+ }
+
+ Log.w(LOG_TAG,
+ "Should not come here. Must have at least one postal data.");
+ }
+
+ private boolean appendPostalsForDoCoMoInternal(final StringBuilder builder,
+ final List<ContentValues> contentValuesList, int preferedType) {
+ for (ContentValues contentValues : contentValuesList) {
+ final int type = contentValues.getAsInteger(StructuredPostal.TYPE);
+ final String label = contentValues
+ .getAsString(StructuredPostal.LABEL);
+ if (type == preferedType) {
+ appendVCardPostalLine(builder, type, label, contentValues);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void appendPostalsForGeneric(final StringBuilder builder,
+ final List<ContentValues> contentValuesList) {
+ for (ContentValues contentValues : contentValuesList) {
+ final int type = contentValues.getAsInteger(StructuredPostal.TYPE);
+ final String label = contentValues
+ .getAsString(StructuredPostal.LABEL);
+ appendVCardPostalLine(builder, type, label, contentValues);
+ }
+ }
+
+ private void appendIms(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Im.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ int type = contentValues.getAsInteger(Im.PROTOCOL);
+ String data = contentValues.getAsString(Im.DATA);
+
+ Log.d("@@@", "Im information. protocol=\"" + type +
+ "\", data=\"" + data + "\", protocol=\"" +
+ contentValues.getAsString(Im.PROTOCOL) + "\", custom_protocol=\"" +
+ contentValues.getAsString(Im.CUSTOM_PROTOCOL) + "\"");
+
+ if (type == Im.PROTOCOL_GOOGLE_TALK) {
+ if (VCardConfig.usesAndroidSpecificProperty(mVCardType)) {
+ appendVCardLine(builder, Constants.PROPERTY_X_GOOGLE_TALK, data);
+ }
+ // TODO: add "X-GOOGLE TALK" case...
+ }
+ }
+ }
+ }
+
+ private void appendWebsites(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Website.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ final String website = contentValues.getAsString(Website.URL);
+ appendVCardLine(builder, VCARD_PROPERTY_URL, website);
+ }
+ }
+ }
+
+ private void appendBirthday(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Website.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null && contentValuesList.size() > 0) {
+ // Theoretically, there must be only one birthday for each vCard data and
+ // we are afraid of some parse error occuring in some devices, so
+ // we emit only one birthday entry for now.
+ final String birthday = contentValuesList.get(0).getAsString(Miscellaneous.BIRTHDAY);
+ appendVCardLine(builder, VCARD_PROPERTY_BIRTHDAY, birthday);
+ }
+ }
+
+ private void appendOrganizations(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Organization.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ final String company = contentValues
+ .getAsString(Organization.COMPANY);
+ final String title = contentValues
+ .getAsString(Organization.TITLE);
+ appendVCardLine(builder, VCARD_PROPERTY_ORG, company, true,
+ mUsesQuotedPrintable);
+ appendVCardLine(builder, VCARD_PROPERTY_TITLE, title, true,
+ mUsesQuotedPrintable);
+ }
+ }
+ }
+
+ private void appendPhotos(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ List<ContentValues> contentValuesList = contentValuesListMap
+ .get(Photo.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ for (ContentValues contentValues : contentValuesList) {
+ byte[] data = contentValues.getAsByteArray(Photo.PHOTO);
+ if (data == null) {
+ continue;
+ }
+ final String photoType;
+ // Use some heuristics for guessing the format of the image.
+ // TODO: there should be some general API for detecting the file format.
+ if (data.length >= 3 && data[0] == 'G' && data[1] == 'I'
+ && data[2] == 'F') {
+ photoType = "GIF";
+ } else if (data.length >= 4 && data[0] == (byte) 0x89
+ && data[1] == 'P' && data[2] == 'N' && data[3] == 'G') {
+ // Note: vCard 2.1 officially does not support PNG, but we
+ // may have it
+ // and using X- word like "X-PNG" may not let importers know
+ // it is
+ // PNG. So we use the String "PNG" as is...
+ photoType = "PNG";
+ } else if (data.length >= 2 && data[0] == (byte) 0xff
+ && data[1] == (byte) 0xd8) {
+ photoType = "JPEG";
+ } else {
+ Log.d(LOG_TAG, "Unknown photo type. Ignore.");
+ continue;
+ }
+ String photoString = VCardUtils.encodeBase64(data);
+ if (photoString.length() > 0) {
+ appendVCardPhotoLine(builder, photoString, photoType);
+ }
+ }
+ }
+ }
+
+ private void appendNotes(final StringBuilder builder,
+ final Map<String, List<ContentValues>> contentValuesListMap) {
+ final List<ContentValues> contentValuesList =
+ contentValuesListMap.get(Note.CONTENT_ITEM_TYPE);
+ if (contentValuesList != null) {
+ if (mOnlyOneNoteFieldIsAvailable) {
+ StringBuilder noteBuilder = new StringBuilder();
+ boolean first = true;
+ for (ContentValues contentValues : contentValuesList) {
+ final String note = contentValues.getAsString(Note.NOTE);
+ if (note.length() > 0) {
+ if (first) {
+ first = false;
+ } else {
+ noteBuilder.append('\n');
+ }
+ noteBuilder.append(note);
+ }
+ }
+ appendVCardLine(builder, VCARD_PROPERTY_NOTE, noteBuilder.toString(),
+ true, mUsesQuotedPrintable);
+ } else {
+ for (ContentValues contentValues : contentValuesList) {
+ final String note = contentValues.getAsString(Note.NOTE);
+ if (!TextUtils.isEmpty(note)) {
+ appendVCardLine(builder, VCARD_PROPERTY_NOTE, note, true,
+ mUsesQuotedPrintable);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Append '\' to the characters which should be escaped. The character set is different
+ * not only between vCard 2.1 and vCard 3.0 but also among each device.
+ *
+ * Note that Quoted-Printable string must not be input here.
+ */
+ @SuppressWarnings("fallthrough")
+ private String escapeCharacters(String unescaped) {
+ if (TextUtils.isEmpty(unescaped)) {
+ return "";
+ }
+
+ StringBuilder builder = new StringBuilder();
+ final int length = unescaped.length();
+ for (int i = 0; i < length; i++) {
+ char ch = unescaped.charAt(i);
+ switch (ch) {
+ case ';':
+ builder.append('\\');
+ builder.append(';');
+ break;
+ case '\r':
+ if (i + 1 < length) {
+ char nextChar = unescaped.charAt(i);
+ if (nextChar == '\n') {
+ continue;
+ } else {
+ // fall through
+ }
+ } else {
+ // fall through
+ }
+ case '\n':
+ // In vCard 2.1, there's no specification about this, while
+ // vCard 3.0 explicitly
+ // requires this should be encoded to "\n".
+ builder.append("\\n");
+ break;
+ case '\\':
+ if (mIsV30) {
+ builder.append("\\\\");
+ break;
+ }
+ case '<':
+ case '>':
+ if (mIsDoCoMo) {
+ builder.append('\\');
+ builder.append(ch);
+ }
+ break;
+ case ',':
+ if (mIsV30) {
+ builder.append("\\,");
+ break;
+ }
+ default:
+ builder.append(ch);
+ break;
+ }
+ }
+ return builder.toString();
+ }
+
+ private void appendVCardPhotoLine(StringBuilder builder,
+ String encodedData, String type) {
+ StringBuilder tmpBuilder = new StringBuilder();
+ tmpBuilder.append(VCARD_PROPERTY_PHOTO);
+ tmpBuilder.append(VCARD_ATTR_SEPARATOR);
+ if (mIsV30) {
+ tmpBuilder.append(VCARD_ATTR_ENCODING_BASE64_V30);
+ } else {
+ tmpBuilder.append(VCARD_ATTR_ENCODING_BASE64_V21);
+ }
+ tmpBuilder.append(VCARD_ATTR_SEPARATOR);
+ tmpBuilder.append("TYPE=");
+ tmpBuilder.append(type);
+ tmpBuilder.append(VCARD_DATA_SEPARATOR);
+ tmpBuilder.append(encodedData);
+
+ String tmpStr = tmpBuilder.toString();
+ tmpBuilder = new StringBuilder();
+ int lineCount = 0;
+ for (int i = 0; i < tmpStr.length(); i++) {
+ tmpBuilder.append(tmpStr.charAt(i));
+ lineCount++;
+ if (lineCount > 72) {
+ tmpBuilder.append(VCARD_COL_SEPARATOR);
+ tmpBuilder.append(VCARD_WS);
+ lineCount = 0;
+ }
+ }
+ builder.append(tmpBuilder.toString());
+ builder.append(VCARD_COL_SEPARATOR);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ private void appendVCardPostalLine(StringBuilder builder, int type,
+ String label, final ContentValues contentValues) {
+ builder.append(VCARD_PROPERTY_ADR);
+ builder.append(VCARD_ATTR_SEPARATOR);
+
+ boolean dataExists = false;
+ String[] dataArray = VCardUtils.getVCardPostalElements(contentValues);
+ int length = dataArray.length;
+ final boolean useQuotedPrintable = mUsesQuotedPrintable;
+ for (int i = 0; i < length; i++) {
+ String data = dataArray[i];
+ if (!TextUtils.isEmpty(data)) {
+ dataExists = true;
+ if (useQuotedPrintable) {
+ dataArray[i] = encodeQuotedPrintable(data);
+ } else {
+ dataArray[i] = escapeCharacters(data);
+ }
+ }
+ }
+
+ boolean typeIsAppended = false;
+ switch (type) {
+ case StructuredPostal.TYPE_HOME:
+ builder.append(Constants.ATTR_TYPE_HOME);
+ typeIsAppended = true;
+ break;
+ case StructuredPostal.TYPE_WORK:
+ builder.append(Constants.ATTR_TYPE_WORK);
+ typeIsAppended = true;
+ break;
+ case StructuredPostal.TYPE_CUSTOM:
+ if (mUsesAndroidProperty && VCardUtils.containsOnlyAlphaDigitHyphen(label)){
+ // We're not sure whether the label is valid in the spec ("IANA-token" in the vCard 3.1
+ // is unclear...)
+ // Just for safety, we add "X-" at the beggining of each label.
+ // Also checks the label obeys with vCard 3.0 spec.
+ builder.append("X-");
+ builder.append(label);
+ builder.append(VCARD_DATA_SEPARATOR);
+ }
+ break;
+ case StructuredPostal.TYPE_OTHER:
+ break;
+ default:
+ Log.e(LOG_TAG, "Unknown StructuredPostal type: " + type);
+ break;
+ }
+
+ if (dataExists) {
+ if (typeIsAppended) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ }
+ // Strictly, vCard 3.0 does not allow this, but we add this since
+ // this information
+ // should be useful, Assume no parser does not emit error with this
+ // attribute.
+ builder.append(mVCardAttributeCharset);
+ if (useQuotedPrintable) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(VCARD_ATTR_ENCODING_QP);
+ }
+ }
+ builder.append(VCARD_DATA_SEPARATOR);
+ if (dataExists) {
+ // The elements in dataArray are already encoded to quoted printable
+ // if needed.
+ // See above.
+ //
+ // TODO: in vCard 3.0, one line may become too huge. Fix this.
+ builder.append(dataArray[0]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[1]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[2]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[3]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[4]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[5]);
+ builder.append(VCARD_ITEM_SEPARATOR);
+ builder.append(dataArray[6]);
+ }
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ private void appendVCardEmailLine(StringBuilder builder, int type,
+ String label, String data) {
+ builder.append(VCARD_PROPERTY_EMAIL);
+ builder.append(VCARD_ATTR_SEPARATOR);
+
+ switch (type) {
+ case Email.TYPE_CUSTOM:
+ if (label.equals(
+ android.provider.Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME)) {
+ builder.append(Constants.ATTR_TYPE_CELL);
+ } else if (mUsesAndroidProperty && VCardUtils.containsOnlyAlphaDigitHyphen(label)){
+ builder.append("X-");
+ builder.append(label);
+ } else {
+ // Default to INTERNET.
+ builder.append(Constants.ATTR_TYPE_INTERNET);
+ }
+ break;
+ case Email.TYPE_HOME:
+ builder.append(Constants.ATTR_TYPE_HOME);
+ break;
+ case Email.TYPE_WORK:
+ builder.append(Constants.ATTR_TYPE_WORK);
+ break;
+ case Email.TYPE_OTHER:
+ builder.append(Constants.ATTR_TYPE_INTERNET);
+ break;
+ default:
+ Log.e(LOG_TAG, "Unknown Email type: " + type);
+ builder.append(Constants.ATTR_TYPE_INTERNET);
+ break;
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(data);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ private void appendVCardTelephoneLine(StringBuilder builder, int type,
+ String label, String encodedData) {
+ builder.append(VCARD_PROPERTY_TEL);
+ builder.append(VCARD_ATTR_SEPARATOR);
+
+ switch (type) {
+ case Phone.TYPE_HOME:
+ appendTypeAttributes(builder, Arrays.asList(
+ Constants.ATTR_TYPE_HOME, Constants.ATTR_TYPE_VOICE));
+ break;
+ case Phone.TYPE_WORK:
+ appendTypeAttributes(builder, Arrays.asList(
+ Constants.ATTR_TYPE_WORK, Constants.ATTR_TYPE_VOICE));
+ break;
+ case Phone.TYPE_FAX_HOME:
+ appendTypeAttributes(builder, Arrays.asList(
+ Constants.ATTR_TYPE_HOME, Constants.ATTR_TYPE_FAX));
+ break;
+ case Phone.TYPE_FAX_WORK:
+ appendTypeAttributes(builder, Arrays.asList(
+ Constants.ATTR_TYPE_WORK, Constants.ATTR_TYPE_FAX));
+ break;
+ case Phone.TYPE_MOBILE:
+ builder.append(Constants.ATTR_TYPE_CELL);
+ break;
+ case Phone.TYPE_PAGER:
+ if (mIsDoCoMo) {
+ // Not sure about the reason, but previous implementation had
+ // used "VOICE" instead of "PAGER"
+ builder.append(Constants.ATTR_TYPE_VOICE);
+ } else {
+ builder.append(Constants.ATTR_TYPE_PAGER);
+ }
+ break;
+ case Phone.TYPE_OTHER:
+ builder.append(Constants.ATTR_TYPE_VOICE);
+ break;
+ case Phone.TYPE_CUSTOM:
+ if (mUsesAndroidProperty) {
+ VCardUtils.containsOnlyAlphaDigitHyphen(label);
+ builder.append("X-" + label);
+ } else {
+ // Just ignore the custom type.
+ builder.append(Constants.ATTR_TYPE_VOICE);
+ }
+ break;
+ default:
+ appendUncommonPhoneType(builder, type);
+ break;
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(encodedData);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ /**
+ * Appends phone type string which may not be available in some devices.
+ */
+ private void appendUncommonPhoneType(StringBuilder builder, int type) {
+ if (mIsDoCoMo) {
+ // The previous implementation for DoCoMo had been conservative
+ // about
+ // miscellaneous types.
+ builder.append(Constants.ATTR_TYPE_VOICE);
+ } else {
+ String phoneAttribute = VCardUtils.getPhoneAttributeString(type);
+ if (phoneAttribute != null) {
+ builder.append(phoneAttribute);
+ } else {
+ Log.e(LOG_TAG, "Unknown or unsupported (by vCard) Phone type: " + type);
+ }
+ }
+ }
+
+ private void appendVCardLine(final StringBuilder builder,
+ final String propertyName, final String rawData) {
+ appendVCardLine(builder, propertyName, rawData, false, false);
+ }
+
+ private void appendVCardLine(final StringBuilder builder,
+ final String field, final String rawData, boolean needCharset,
+ boolean needQuotedPrintable) {
+ builder.append(field);
+ if (needCharset) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(mVCardAttributeCharset);
+ }
+
+ final String encodedData;
+ if (needQuotedPrintable) {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ builder.append(VCARD_ATTR_ENCODING_QP);
+ encodedData = encodeQuotedPrintable(rawData);
+ } else {
+ // TODO: one line may be too huge, which may be invalid in vCard spec, though
+ // several (even well-known) applications do not care this.
+ encodedData = escapeCharacters(rawData);
+ }
+
+ builder.append(VCARD_DATA_SEPARATOR);
+ builder.append(encodedData);
+ builder.append(VCARD_COL_SEPARATOR);
+ }
+
+ private void appendTypeAttributes(final StringBuilder builder,
+ final List<String> types) {
+ // We may have to make this comma separated form like "TYPE=DOM,WORK" in the future,
+ // which would be recommended way in vcard 3.0 though not valid in vCard 2.1.
+ boolean first = true;
+ for (String type : types) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(VCARD_ATTR_SEPARATOR);
+ }
+ if (mIsV30) {
+ builder.append(Constants.ATTR_TYPE);
+ builder.append('=');
+ }
+ builder.append(type);
+ }
+ }
+
+ private String encodeQuotedPrintable(String str) {
+ if (TextUtils.isEmpty(str)) {
+ return "";
+ }
+ {
+ // Replace "\n" and "\r" with "\r\n".
+ StringBuilder tmpBuilder = new StringBuilder();
+ int length = str.length();
+ for (int i = 0; i < length; i++) {
+ char ch = str.charAt(i);
+ if (ch == '\r') {
+ if (i + 1 < length && str.charAt(i + 1) == '\n') {
+ i++;
+ }
+ tmpBuilder.append("\r\n");
+ } else if (ch == '\n') {
+ tmpBuilder.append("\r\n");
+ } else {
+ tmpBuilder.append(ch);
+ }
+ }
+ str = tmpBuilder.toString();
+ }
+
+ StringBuilder builder = new StringBuilder();
+ int index = 0;
+ int lineCount = 0;
+ byte[] strArray = null;
+
+ try {
+ strArray = str.getBytes(mCharsetString);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Charset " + mCharsetString + " cannot be used. "
+ + "Try default charset");
+ strArray = str.getBytes();
+ }
+ while (index < strArray.length) {
+ builder.append(String.format("=%02X", strArray[index]));
+ index += 1;
+ lineCount += 3;
+
+ if (lineCount >= 67) {
+ // Specification requires CRLF must be inserted before the
+ // length of the line
+ // becomes more than 76.
+ // Assuming that the next character is a multi-byte character,
+ // it will become
+ // 6 bytes.
+ // 76 - 6 - 3 = 67
+ builder.append("=\r\n");
+ lineCount = 0;
+ }
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java
new file mode 100644
index 0000000..d87b002
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardConfig.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.pim.vcard;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The class representing VCard related configurations. Useful static methods are not in this class
+ * but in VCardUtils.
+ */
+public class VCardConfig {
+ // TODO: may be better to make the instance of this available and stop using static methods and
+ // one integer.
+
+ /* package */ static final int LOG_LEVEL_NONE = 0;
+ /* package */ static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1;
+ /* package */ static final int LOG_LEVEL_SHOW_WARNING = 0x2;
+ /* package */ static final int LOG_LEVEL_VERBOSE =
+ LOG_LEVEL_PERFORMANCE_MEASUREMENT | LOG_LEVEL_SHOW_WARNING;
+
+ /* package */ static final int LOG_LEVEL = LOG_LEVEL_PERFORMANCE_MEASUREMENT;
+
+ // Assumes that "iso-8859-1" is able to map "all" 8bit characters to some unicode and
+ // decode the unicode to the original charset. If not, this setting will cause some bug.
+ public static final String DEFAULT_CHARSET = "iso-8859-1";
+
+ // TODO: make the other codes use this flag
+ public static final boolean IGNORE_CASE_EXCEPT_VALUE = true;
+
+ private static final int FLAG_V21 = 0;
+ private static final int FLAG_V30 = 1;
+
+ // 0x2 is reserved for the future use ...
+
+ public static final int NAME_ORDER_DEFAULT = 0;
+ public static final int NAME_ORDER_EUROPE = 0x4;
+ public static final int NAME_ORDER_JAPANESE = 0x8;
+ private static final int NAME_ORDER_MASK = 0xC;
+
+ // 0x10 is reserved for safety
+
+ private static final int FLAG_CHARSET_UTF8 = 0;
+ private static final int FLAG_CHARSET_SHIFT_JIS = 0x20;
+
+ /**
+ * The flag indicating the vCard composer will add some "X-" properties used only in Android
+ * when the formal vCard specification does not have appropriate fields for that data.
+ *
+ * For example, Android accepts nickname information while vCard 2.1 does not.
+ * When this flag is on, vCard composer emits alternative "X-" property (like "X-NICKNAME")
+ * instead of just dropping it.
+ *
+ * vCard parser code automatically parses the field emitted even when this flag is off.
+ *
+ * Note that this flag does not assure all the information must be hold in the emitted vCard.
+ */
+ private static final int FLAG_USE_ANDROID_PROPERTY = 0x80000000;
+
+ /**
+ * The flag indicating the vCard composer will add some "X-" properties seen in the
+ * vCard data emitted by the other softwares/devices when the formal vCard specification
+ * does not have appropriate field(s) for that data.
+ *
+ * One example is X-PHONETIC-FIRST-NAME/X-PHONETIC-MIDDLE-NAME/X-PHONETIC-LAST-NAME, which are
+ * for phonetic name (how the name is pronounced), seen in the vCard emitted by some other
+ * non-Android devices/softwares. We chose to enable the vCard composer to use those
+ * defact properties since they are also useful for Android devices.
+ *
+ * Note for developers: only "X-" properties should be added with this flag. vCard 2.1/3.0
+ * allows any kind of "X-" properties but does not allow non-"X-" properties (except IANA tokens
+ * in vCard 3.0). Some external parsers may get confused with non-valid, non-"X-" properties.
+ */
+ private static final int FLAG_USE_DEFACT_PROPERTY = 0x40000000;
+
+ /**
+ * The flag indicating some specific dialect seen in vcard of DoCoMo (one of Japanese
+ * mobile careers) should be used. This flag does not include any other information like
+ * that "the vCard is for Japanese". So it is "possible" that "the vCard should have DoCoMo's
+ * dialect but the name order should be European", but it is not recommended.
+ */
+ private static final int FLAG_DOCOMO = 0x20000000;
+
+
+ // VCard types
+
+
+ /**
+ * General vCard format with the version 2.1. Uses UTF-8 for the charset.
+ * When composing a vCard entry, the US convension will be used.
+ *
+ * e.g. The order of the display name would be "Prefix Given Middle Family Suffix",
+ * while in Japan, it should be "Prefix Family Middle Given Suffix".
+ */
+ public static final int VCARD_TYPE_V21_GENERIC =
+ (FLAG_V21 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static String VCARD_TYPE_V21_GENERIC_STR = "v21_generic";
+
+ /**
+ * General vCard format with the version 3.0. Uses UTF-8 for the charset.
+ *
+ * Note that this type is not fully implemented, so probably some bugs remain especially
+ * in parsing part.
+ *
+ * TODO: implement this type.
+ */
+ public static final int VCARD_TYPE_V30_GENERIC =
+ (FLAG_V30 | NAME_ORDER_DEFAULT | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V30_GENERIC_STR = "v30_generic";
+
+ /**
+ * General vCard format with the version 2.1 with some Europe convension. Uses Utf-8.
+ * Currently, only name order is considered ("Prefix Middle Given Family Suffix")
+ */
+ public static final int VCARD_TYPE_V21_EUROPE =
+ (FLAG_V21 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V21_EUROPE_STR = "v21_europe";
+
+ /**
+ * General vCard format with the version 3.0 with some Europe convension. Uses UTF-8
+ */
+ public static final int VCARD_TYPE_V30_EUROPE =
+ (FLAG_V30 | NAME_ORDER_EUROPE | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V30_EUROPE_STR = "v30_europe";
+
+ /**
+ * vCard 2.1 format for miscellaneous Japanese devices. Shift_Jis is used for
+ * parsing/composing the vCard data.
+ */
+ public static final int VCARD_TYPE_V21_JAPANESE =
+ (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V21_JAPANESE_STR = "v21_japanese";
+
+ /**
+ * vCard 2.1 format for miscellaneous Japanese devices, using UTF-8 as default charset.
+ */
+ public static final int VCARD_TYPE_V21_JAPANESE_UTF8 =
+ (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V21_JAPANESE_UTF8_STR = "v21_japanese_utf8";
+
+ /**
+ * vCard format for miscellaneous Japanese devices, using Shift_Jis for
+ * parsing/composing the vCard data.
+ */
+ public static final int VCARD_TYPE_V30_JAPANESE =
+ (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V30_JAPANESE_STR = "v30_japanese";
+
+ /**
+ * vCard 3.0 format for miscellaneous Japanese devices, using UTF-8 as default charset.
+ */
+ public static final int VCARD_TYPE_V30_JAPANESE_UTF8 =
+ (FLAG_V30 | NAME_ORDER_JAPANESE | FLAG_CHARSET_UTF8 |
+ FLAG_USE_DEFACT_PROPERTY | FLAG_USE_ANDROID_PROPERTY);
+
+ /* package */ static final String VCARD_TYPE_V30_JAPANESE_UTF8_STR = "v30_japanese_utf8";
+
+ /**
+ * VCard format used in DoCoMo, which is one of Japanese mobile phone careers.
+ * Base version is vCard 2.1, but the data has several DoCoMo-specific convensions.
+ * No Android-specific property nor defact property is included.
+ */
+ public static final int VCARD_TYPE_DOCOMO =
+ (FLAG_V21 | NAME_ORDER_JAPANESE | FLAG_CHARSET_SHIFT_JIS | FLAG_DOCOMO);
+
+ private static final String VCARD_TYPE_DOCOMO_STR = "docomo";
+
+ public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC;
+
+ private static final Map<String, Integer> VCARD_TYPES_MAP;
+
+ static {
+ VCARD_TYPES_MAP = new HashMap<String, Integer>();
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V21_GENERIC_STR, VCARD_TYPE_V21_GENERIC);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V30_GENERIC_STR, VCARD_TYPE_V30_GENERIC);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V21_EUROPE_STR, VCARD_TYPE_V21_EUROPE);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V30_EUROPE_STR, VCARD_TYPE_V30_EUROPE);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V21_JAPANESE_STR, VCARD_TYPE_V21_JAPANESE);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V21_JAPANESE_UTF8_STR, VCARD_TYPE_V21_JAPANESE_UTF8);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V30_JAPANESE_STR, VCARD_TYPE_V30_JAPANESE);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_V30_JAPANESE_UTF8_STR, VCARD_TYPE_V30_JAPANESE_UTF8);
+ VCARD_TYPES_MAP.put(VCARD_TYPE_DOCOMO_STR, VCARD_TYPE_DOCOMO);
+ }
+
+ public static int getVCardTypeFromString(String vcardTypeString) {
+ String loweredKey = vcardTypeString.toLowerCase();
+ if (VCARD_TYPES_MAP.containsKey(loweredKey)) {
+ return VCARD_TYPES_MAP.get(loweredKey);
+ } else {
+ // XXX: should return the value indicating the input is invalid?
+ return VCARD_TYPE_DEFAULT;
+ }
+ }
+
+ public static boolean isV30(int vcardType) {
+ return ((vcardType & FLAG_V30) != 0);
+ }
+
+ public static boolean usesQuotedPrintable(int vcardType) {
+ return !isV30(vcardType);
+ }
+
+ public static boolean isDoCoMo(int vcardType) {
+ return ((vcardType & FLAG_DOCOMO) != 0);
+ }
+
+ /**
+ * @return true if the device is Japanese and some Japanese convension is
+ * applied to creating "formatted" something like FORMATTED_ADDRESS.
+ */
+ public static boolean isJapaneseDevice(int vcardType) {
+ return ((vcardType == VCARD_TYPE_V21_JAPANESE) ||
+ (vcardType == VCARD_TYPE_V21_JAPANESE_UTF8) ||
+ (vcardType == VCARD_TYPE_V30_JAPANESE) ||
+ (vcardType == VCARD_TYPE_V30_JAPANESE_UTF8) ||
+ (vcardType == VCARD_TYPE_DOCOMO));
+ }
+
+ public static boolean usesShiftJis(int vcardType) {
+ return ((vcardType & FLAG_CHARSET_SHIFT_JIS) != 0);
+ }
+
+ /**
+ * @return true when Japanese phonetic string must be converted to a string
+ * containing only half-width katakana. This method exists since Japanese mobile
+ * phones usually use only half-width katakana for expressing phonetic names and
+ * some devices are not ready for parsing other phonetic strings like hiragana and
+ * full-width katakana.
+ */
+ public static boolean needsToConvertPhoneticString(int vcardType) {
+ return (vcardType == VCARD_TYPE_DOCOMO);
+ }
+
+ public static int getNameOrderType(int vcardType) {
+ return vcardType & NAME_ORDER_MASK;
+ }
+
+ public static boolean usesAndroidSpecificProperty(int vcardType) {
+ return ((vcardType & FLAG_USE_ANDROID_PROPERTY) != 0);
+ }
+
+ public static boolean usesDefactProperty(int vcardType) {
+ return ((vcardType & FLAG_USE_DEFACT_PROPERTY) != 0);
+ }
+
+ public static boolean onlyOneNoteFieldIsAvailable(int vcardType) {
+ return vcardType == VCARD_TYPE_DOCOMO;
+ }
+
+ public static boolean showPerformanceLog() {
+ return (VCardConfig.LOG_LEVEL & VCardConfig.LOG_LEVEL_PERFORMANCE_MEASUREMENT) != 0;
+ }
+
+ private VCardConfig() {
+ }
+} \ No newline at end of file
diff --git a/core/java/android/pim/vcard/VCardDataBuilder.java b/core/java/android/pim/vcard/VCardDataBuilder.java
new file mode 100644
index 0000000..fd165e9
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardDataBuilder.java
@@ -0,0 +1,320 @@
+/*
+ * 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.pim.vcard;
+
+import android.util.CharsetUtils;
+import android.util.Log;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.net.QuotedPrintableCodec;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * VBuilder for VCard. VCard may contain big photo images encoded by BASE64,
+ * If we store all VNode entries in memory like VDataBuilder.java,
+ * OutOfMemoryError may be thrown. Thus, this class push each VCard entry into
+ * ContentResolver immediately.
+ */
+public class VCardDataBuilder implements VCardBuilder {
+ static private String LOG_TAG = "VCardDataBuilder";
+
+ /**
+ * If there's no other information available, this class uses this charset for encoding
+ * byte arrays.
+ */
+ static public String TARGET_CHARSET = "UTF-8";
+
+ private ContactStruct.Property mCurrentProperty = new ContactStruct.Property();
+ private ContactStruct mCurrentContactStruct;
+ private String mParamType;
+
+ /**
+ * The charset using which VParser parses the text.
+ */
+ private String mSourceCharset;
+
+ /**
+ * The charset with which byte array is encoded to String.
+ */
+ private String mTargetCharset;
+ private boolean mStrictLineBreakParsing;
+
+ private int mVCardType;
+
+ // Just for testing.
+ private long mTimePushIntoContentResolver;
+
+ private List<EntryHandler> mEntryHandlers = new ArrayList<EntryHandler>();
+
+ public VCardDataBuilder() {
+ this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC);
+ }
+
+ /**
+ * @hide
+ */
+ public VCardDataBuilder(int vcardType) {
+ this(null, null, false, vcardType);
+ }
+
+ /**
+ * @hide
+ */
+ public VCardDataBuilder(String charset, boolean strictLineBreakParsing, int vcardType) {
+ this(null, charset, strictLineBreakParsing, vcardType);
+ }
+
+ /**
+ * @hide
+ */
+ public VCardDataBuilder(String sourceCharset,
+ String targetCharset,
+ boolean strictLineBreakParsing,
+ int vcardType) {
+ if (sourceCharset != null) {
+ mSourceCharset = sourceCharset;
+ } else {
+ mSourceCharset = VCardConfig.DEFAULT_CHARSET;
+ }
+ if (targetCharset != null) {
+ mTargetCharset = targetCharset;
+ } else {
+ mTargetCharset = TARGET_CHARSET;
+ }
+ mStrictLineBreakParsing = strictLineBreakParsing;
+ mVCardType = vcardType;
+ }
+
+ public void addEntryHandler(EntryHandler entryHandler) {
+ mEntryHandlers.add(entryHandler);
+ }
+
+ public void start() {
+ for (EntryHandler entryHandler : mEntryHandlers) {
+ entryHandler.onParsingStart();
+ }
+ }
+
+ public void end() {
+ for (EntryHandler entryHandler : mEntryHandlers) {
+ entryHandler.onParsingEnd();
+ }
+ }
+
+ /**
+ * Assume that VCard is not nested. In other words, this code does not accept
+ */
+ public void startRecord(String type) {
+ // TODO: add the method clear() instead of using null for reducing GC?
+ if (mCurrentContactStruct != null) {
+ // This means startRecord() is called inside startRecord() - endRecord() block.
+ // TODO: should throw some Exception
+ Log.e(LOG_TAG, "Nested VCard code is not supported now.");
+ }
+ if (!type.equalsIgnoreCase("VCARD")) {
+ // TODO: add test case for this
+ Log.e(LOG_TAG, "This is not VCARD!");
+ }
+
+ mCurrentContactStruct = new ContactStruct(mVCardType);
+ }
+
+ public void endRecord() {
+ mCurrentContactStruct.consolidateFields();
+ for (EntryHandler entryHandler : mEntryHandlers) {
+ entryHandler.onEntryCreated(mCurrentContactStruct);
+ }
+ mCurrentContactStruct = null;
+ }
+
+ public void startProperty() {
+ mCurrentProperty.clear();
+ }
+
+ public void endProperty() {
+ mCurrentContactStruct.addProperty(mCurrentProperty);
+ }
+
+ public void propertyName(String name) {
+ mCurrentProperty.setPropertyName(name);
+ }
+
+ public void propertyGroup(String group) {
+ // ContactStruct does not support Group.
+ }
+
+ public void propertyParamType(String type) {
+ if (mParamType != null) {
+ Log.e(LOG_TAG, "propertyParamType() is called more than once " +
+ "before propertyParamValue() is called");
+ }
+ mParamType = type;
+ }
+
+ public void propertyParamValue(String value) {
+ if (mParamType == null) {
+ // From vCard 2.1 specification. vCard 3.0 formally does not allow this case.
+ mParamType = "TYPE";
+ }
+ mCurrentProperty.addParameter(mParamType, value);
+ mParamType = null;
+ }
+
+ private String encodeString(String originalString, String targetCharset) {
+ if (mSourceCharset.equalsIgnoreCase(targetCharset)) {
+ return originalString;
+ }
+ Charset charset = Charset.forName(mSourceCharset);
+ ByteBuffer byteBuffer = charset.encode(originalString);
+ // byteBuffer.array() "may" return byte array which is larger than
+ // byteBuffer.remaining(). Here, we keep on the safe side.
+ byte[] bytes = new byte[byteBuffer.remaining()];
+ byteBuffer.get(bytes);
+ try {
+ return new String(bytes, targetCharset);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
+ return null;
+ }
+ }
+
+ private String handleOneValue(String value, String targetCharset, String encoding) {
+ if (encoding != null) {
+ if (encoding.equals("BASE64") || encoding.equals("B")) {
+ mCurrentProperty.setPropertyBytes(Base64.decodeBase64(value.getBytes()));
+ return value;
+ } else if (encoding.equals("QUOTED-PRINTABLE")) {
+ // "= " -> " ", "=\t" -> "\t".
+ // Previous code had done this replacement. Keep on the safe side.
+ StringBuilder builder = new StringBuilder();
+ int length = value.length();
+ for (int i = 0; i < length; i++) {
+ char ch = value.charAt(i);
+ if (ch == '=' && i < length - 1) {
+ char nextCh = value.charAt(i + 1);
+ if (nextCh == ' ' || nextCh == '\t') {
+
+ builder.append(nextCh);
+ i++;
+ continue;
+ }
+ }
+ builder.append(ch);
+ }
+ String quotedPrintable = builder.toString();
+
+ String[] lines;
+ if (mStrictLineBreakParsing) {
+ lines = quotedPrintable.split("\r\n");
+ } else {
+ builder = new StringBuilder();
+ length = quotedPrintable.length();
+ ArrayList<String> list = new ArrayList<String>();
+ for (int i = 0; i < length; i++) {
+ char ch = quotedPrintable.charAt(i);
+ if (ch == '\n') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ } else if (ch == '\r') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ if (i < length - 1) {
+ char nextCh = quotedPrintable.charAt(i + 1);
+ if (nextCh == '\n') {
+ i++;
+ }
+ }
+ } else {
+ builder.append(ch);
+ }
+ }
+ String finalLine = builder.toString();
+ if (finalLine.length() > 0) {
+ list.add(finalLine);
+ }
+ lines = list.toArray(new String[0]);
+ }
+
+ builder = new StringBuilder();
+ for (String line : lines) {
+ if (line.endsWith("=")) {
+ line = line.substring(0, line.length() - 1);
+ }
+ builder.append(line);
+ }
+ byte[] bytes;
+ try {
+ bytes = builder.toString().getBytes(mSourceCharset);
+ } catch (UnsupportedEncodingException e1) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + mSourceCharset);
+ bytes = builder.toString().getBytes();
+ }
+
+ try {
+ bytes = QuotedPrintableCodec.decodeQuotedPrintable(bytes);
+ } catch (DecoderException e) {
+ Log.e(LOG_TAG, "Failed to decode quoted-printable: " + e);
+ return "";
+ }
+
+ try {
+ return new String(bytes, targetCharset);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
+ return new String(bytes);
+ }
+ }
+ // Unknown encoding. Fall back to default.
+ }
+ return encodeString(value, targetCharset);
+ }
+
+ public void propertyValues(List<String> values) {
+ if (values == null || values.size() == 0) {
+ return;
+ }
+
+ final Collection<String> charsetCollection = mCurrentProperty.getParameters("CHARSET");
+ String charset =
+ ((charsetCollection != null) ? charsetCollection.iterator().next() : null);
+ String targetCharset = CharsetUtils.nameForDefaultVendor(charset);
+
+ final Collection<String> encodingCollection = mCurrentProperty.getParameters("ENCODING");
+ String encoding =
+ ((encodingCollection != null) ? encodingCollection.iterator().next() : null);
+
+ if (targetCharset == null || targetCharset.length() == 0) {
+ targetCharset = mTargetCharset;
+ }
+
+ for (String value : values) {
+ mCurrentProperty.addToPropertyValueList(
+ handleOneValue(value, targetCharset, encoding));
+ }
+ }
+
+ public void showPerformanceInfo() {
+ Log.d(LOG_TAG, "time for insert ContactStruct to database: " +
+ mTimePushIntoContentResolver + " ms");
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardEntryCounter.java b/core/java/android/pim/vcard/VCardEntryCounter.java
new file mode 100644
index 0000000..f99b46c
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardEntryCounter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.pim.vcard;
+
+import java.util.List;
+
+public class VCardEntryCounter implements VCardBuilder {
+ private int mCount;
+
+ public int getCount() {
+ return mCount;
+ }
+
+ public void start() {
+ }
+
+ public void end() {
+ }
+
+ public void startRecord(String type) {
+ }
+
+ public void endRecord() {
+ mCount++;
+ }
+
+ public void startProperty() {
+ }
+
+ public void endProperty() {
+ }
+
+ public void propertyGroup(String group) {
+ }
+
+ public void propertyName(String name) {
+ }
+
+ public void propertyParamType(String type) {
+ }
+
+ public void propertyParamValue(String value) {
+ }
+
+ public void propertyValues(List<String> values) {
+ }
+} \ No newline at end of file
diff --git a/core/java/android/pim/vcard/VCardParser.java b/core/java/android/pim/vcard/VCardParser.java
new file mode 100644
index 0000000..b5e5049
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardParser.java
@@ -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.
+ */
+package android.pim.vcard;
+
+import android.pim.vcard.exception.VCardException;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public abstract class VCardParser {
+
+ protected boolean mCanceled;
+
+ /**
+ * Parses the given stream and send the VCard data into VCardBuilderBase object.
+ *
+ * Note that vCard 2.1 specification allows "CHARSET" parameter, and some career sets
+ * local encoding to it. For example, Japanese phone career uses Shift_JIS, which is
+ * formally allowed in VCard 2.1, but not recommended in VCard 3.0. In VCard 2.1,
+ * In some exreme case, some VCard may have different charsets in one VCard (though
+ * we do not see any device which emits such kind of malicious data)
+ *
+ * In order to avoid "misunderstanding" charset as much as possible, this method
+ * use "ISO-8859-1" for reading the stream. When charset is specified in some property
+ * (with "CHARSET=..." attribute), the string is decoded to raw bytes and encoded to
+ * the charset. This method assumes that "ISO-8859-1" has 1 to 1 mapping in all 8bit
+ * characters, which is not completely sure. In some cases, this "decoding-encoding"
+ * scheme may fail. To avoid the case,
+ *
+ * We recommend you to use VCardSourceDetector and detect which kind of source the
+ * VCard comes from and explicitly specify a charset using the result.
+ *
+ * @param is The source to parse.
+ * @param builder The VCardBuilderBase object which used to construct data. If you want to
+ * include multiple VCardBuilderBase objects in this field, consider using
+ * {#link VCardBuilderCollection} class.
+ * @return Returns true for success. Otherwise returns false.
+ * @throws IOException, VCardException
+ */
+ public abstract boolean parse(InputStream is, VCardBuilder builder)
+ throws IOException, VCardException;
+
+ /**
+ * The method variants which accept charset.
+ *
+ * RFC 2426 "recommends" (not forces) to use UTF-8, so it may be OK to use
+ * UTF-8 as an encoding when parsing vCard 3.0. But note that some Japanese
+ * phone uses Shift_JIS as a charset (e.g. W61SH), and another uses
+ * "CHARSET=SHIFT_JIS", which is explicitly prohibited in vCard 3.0 specification
+ * (e.g. W53K).
+ *
+ * @param is The source to parse.
+ * @param charset Charset to be used.
+ * @param builder The VCardBuilderBase object.
+ * @return Returns true when successful. Otherwise returns false.
+ * @throws IOException, VCardException
+ */
+ public abstract boolean parse(InputStream is, String charset, VCardBuilder builder)
+ throws IOException, VCardException;
+
+ /**
+ * The method variants which tells this object the operation is already canceled.
+ * XXX: Is this really necessary?
+ * @hide
+ */
+ public abstract void parse(InputStream is, String charset,
+ VCardBuilder builder, boolean canceled)
+ throws IOException, VCardException;
+
+ /**
+ * Cancel parsing.
+ * Actual cancel is done after the end of the current one vcard entry parsing.
+ */
+ public void cancel() {
+ mCanceled = true;
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java
new file mode 100644
index 0000000..974fca8
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardParser_V21.java
@@ -0,0 +1,928 @@
+/*
+ * 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.pim.vcard;
+
+import android.pim.vcard.exception.VCardException;
+import android.pim.vcard.exception.VCardNestedException;
+import android.pim.vcard.exception.VCardNotSupportedException;
+import android.pim.vcard.exception.VCardVersionException;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+
+/**
+ * This class is used to parse vcard. Please refer to vCard Specification 2.1.
+ */
+public class VCardParser_V21 extends VCardParser {
+ private static final String LOG_TAG = "vcard.VCardParser_V21";
+
+ /** Store the known-type */
+ private static final HashSet<String> sKnownTypeSet = new HashSet<String>(
+ Arrays.asList("DOM", "INTL", "POSTAL", "PARCEL", "HOME", "WORK",
+ "PREF", "VOICE", "FAX", "MSG", "CELL", "PAGER", "BBS",
+ "MODEM", "CAR", "ISDN", "VIDEO", "AOL", "APPLELINK",
+ "ATTMAIL", "CIS", "EWORLD", "INTERNET", "IBMMAIL",
+ "MCIMAIL", "POWERSHARE", "PRODIGY", "TLX", "X400", "GIF",
+ "CGM", "WMF", "BMP", "MET", "PMB", "DIB", "PICT", "TIFF",
+ "PDF", "PS", "JPEG", "QTIME", "MPEG", "MPEG2", "AVI",
+ "WAVE", "AIFF", "PCM", "X509", "PGP"));
+
+ /** Store the known-value */
+ private static final HashSet<String> sKnownValueSet = new HashSet<String>(
+ Arrays.asList("INLINE", "URL", "CONTENT-ID", "CID"));
+
+ /** Store the property names available in vCard 2.1 */
+ private static final HashSet<String> sAvailablePropertyNameV21 =
+ new HashSet<String>(Arrays.asList(
+ "BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
+ "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
+ "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER"));
+
+ /**
+ * Though vCard 2.1 specification does not allow "B" encoding, some data may have it.
+ * We allow it for safety...
+ */
+ private static final HashSet<String> sAvailableEncodingV21 =
+ new HashSet<String>(Arrays.asList(
+ "7BIT", "8BIT", "QUOTED-PRINTABLE", "BASE64", "B"));
+
+ // Used only for parsing END:VCARD.
+ private String mPreviousLine;
+
+ /** The builder to build parsed data */
+ protected VCardBuilder mBuilder = null;
+
+ /**
+ * The encoding type. "Encoding" in vCard is different from "Charset".
+ * e.g. 7BIT, 8BIT, QUOTED-PRINTABLE.
+ */
+ protected String mEncoding = null;
+
+ protected final String sDefaultEncoding = "8BIT";
+
+ // Should not directly read a line from this. Use getLine() instead.
+ protected BufferedReader mReader;
+
+ // In some cases, vCard is nested. Currently, we only consider the most interior vCard data.
+ // See v21_foma_1.vcf in test directory for more information.
+ private int mNestCount;
+
+ // In order to reduce warning message as much as possible, we hold the value which made Logger
+ // emit a warning message.
+ protected HashSet<String> mWarningValueMap = new HashSet<String>();
+
+ // Just for debugging
+ private long mTimeTotal;
+ private long mTimeReadStartRecord;
+ private long mTimeReadEndRecord;
+ private long mTimeStartProperty;
+ private long mTimeEndProperty;
+ private long mTimeParseItems;
+ private long mTimeParseLineAndHandleGroup;
+ private long mTimeParsePropertyValues;
+ private long mTimeParseAdrOrgN;
+ private long mTimeHandleMiscPropertyValue;
+ private long mTimeHandleQuotedPrintable;
+ private long mTimeHandleBase64;
+
+ /**
+ * Create a new VCard parser.
+ */
+ public VCardParser_V21() {
+ super();
+ }
+
+ public VCardParser_V21(VCardSourceDetector detector) {
+ super();
+ if (detector != null && detector.getType() == VCardSourceDetector.TYPE_FOMA) {
+ mNestCount = 1;
+ }
+ }
+
+ /**
+ * Parse the file at the given position
+ * vcard_file = [wsls] vcard [wsls]
+ */
+ protected void parseVCardFile() throws IOException, VCardException {
+ boolean firstReading = true;
+ while (true) {
+ if (mCanceled) {
+ break;
+ }
+ if (!parseOneVCard(firstReading)) {
+ break;
+ }
+ firstReading = false;
+ }
+
+ if (mNestCount > 0) {
+ boolean useCache = true;
+ for (int i = 0; i < mNestCount; i++) {
+ readEndVCard(useCache, true);
+ useCache = false;
+ }
+ }
+ }
+
+ protected String getVersion() {
+ return "2.1";
+ }
+
+ /**
+ * @return true when the propertyName is a valid property name.
+ */
+ protected boolean isValidPropertyName(String propertyName) {
+ if (!(sAvailablePropertyNameV21.contains(propertyName.toUpperCase()) ||
+ propertyName.startsWith("X-")) &&
+ !mWarningValueMap.contains(propertyName)) {
+ mWarningValueMap.add(propertyName);
+ Log.w(LOG_TAG, "Property name unsupported by vCard 2.1: " + propertyName);
+ }
+ return true;
+ }
+
+ /**
+ * @return true when the encoding is a valid encoding.
+ */
+ protected boolean isValidEncoding(String encoding) {
+ return sAvailableEncodingV21.contains(encoding.toUpperCase());
+ }
+
+ /**
+ * @return String. It may be null, or its length may be 0
+ * @throws IOException
+ */
+ protected String getLine() throws IOException {
+ return mReader.readLine();
+ }
+
+ /**
+ * @return String with it's length > 0
+ * @throws IOException
+ * @throws VCardException when the stream reached end of line
+ */
+ protected String getNonEmptyLine() throws IOException, VCardException {
+ String line;
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ throw new VCardException("Reached end of buffer.");
+ } else if (line.trim().length() > 0) {
+ return line;
+ }
+ }
+ }
+
+ /**
+ * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
+ * items *CRLF
+ * "END" [ws] ":" [ws] "VCARD"
+ */
+ private boolean parseOneVCard(boolean firstReading) throws IOException, VCardException {
+ boolean allowGarbage = false;
+ if (firstReading) {
+ if (mNestCount > 0) {
+ for (int i = 0; i < mNestCount; i++) {
+ if (!readBeginVCard(allowGarbage)) {
+ return false;
+ }
+ allowGarbage = true;
+ }
+ }
+ }
+
+ if (!readBeginVCard(allowGarbage)) {
+ return false;
+ }
+ long start;
+ if (mBuilder != null) {
+ start = System.currentTimeMillis();
+ mBuilder.startRecord("VCARD");
+ mTimeReadStartRecord += System.currentTimeMillis() - start;
+ }
+ start = System.currentTimeMillis();
+ parseItems();
+ mTimeParseItems += System.currentTimeMillis() - start;
+ readEndVCard(true, false);
+ if (mBuilder != null) {
+ start = System.currentTimeMillis();
+ mBuilder.endRecord();
+ mTimeReadEndRecord += System.currentTimeMillis() - start;
+ }
+ return true;
+ }
+
+ /**
+ * @return True when successful. False when reaching the end of line
+ * @throws IOException
+ * @throws VCardException
+ */
+ protected boolean readBeginVCard(boolean allowGarbage)
+ throws IOException, VCardException {
+ String line;
+ do {
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ return false;
+ } else if (line.trim().length() > 0) {
+ break;
+ }
+ }
+ String[] strArray = line.split(":", 2);
+ int length = strArray.length;
+
+ // Though vCard 2.1/3.0 specification does not allow lower cases,
+ // some data may have them, so we allow it (Actually, previous code
+ // had explicitly allowed "BEGIN:vCard" though there's no example).
+ if (length == 2 &&
+ strArray[0].trim().equalsIgnoreCase("BEGIN") &&
+ strArray[1].trim().equalsIgnoreCase("VCARD")) {
+ return true;
+ } else if (!allowGarbage) {
+ if (mNestCount > 0) {
+ mPreviousLine = line;
+ return false;
+ } else {
+ throw new VCardException(
+ "Expected String \"BEGIN:VCARD\" did not come "
+ + "(Instead, \"" + line + "\" came)");
+ }
+ }
+ } while(allowGarbage);
+
+ throw new VCardException("Reached where must not be reached.");
+ }
+
+ /**
+ * The arguments useCache and allowGarbase are usually true and false accordingly when
+ * this function is called outside this function itself.
+ *
+ * @param useCache When true, line is obtained from mPreviousline. Otherwise, getLine()
+ * is used.
+ * @param allowGarbage When true, ignore non "END:VCARD" line.
+ * @throws IOException
+ * @throws VCardException
+ */
+ protected void readEndVCard(boolean useCache, boolean allowGarbage)
+ throws IOException, VCardException {
+ String line;
+ do {
+ if (useCache) {
+ // Though vCard specification does not allow lower cases,
+ // some data may have them, so we allow it.
+ line = mPreviousLine;
+ } else {
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ throw new VCardException("Expected END:VCARD was not found.");
+ } else if (line.trim().length() > 0) {
+ break;
+ }
+ }
+ }
+
+ String[] strArray = line.split(":", 2);
+ if (strArray.length == 2 &&
+ strArray[0].trim().equalsIgnoreCase("END") &&
+ strArray[1].trim().equalsIgnoreCase("VCARD")) {
+ return;
+ } else if (!allowGarbage) {
+ throw new VCardException("END:VCARD != \"" + mPreviousLine + "\"");
+ }
+ useCache = false;
+ } while (allowGarbage);
+ }
+
+ /**
+ * items = *CRLF item
+ * / item
+ */
+ protected void parseItems() throws IOException, VCardException {
+ /* items *CRLF item / item */
+ boolean ended = false;
+
+ if (mBuilder != null) {
+ long start = System.currentTimeMillis();
+ mBuilder.startProperty();
+ mTimeStartProperty += System.currentTimeMillis() - start;
+ }
+ ended = parseItem();
+ if (mBuilder != null && !ended) {
+ long start = System.currentTimeMillis();
+ mBuilder.endProperty();
+ mTimeEndProperty += System.currentTimeMillis() - start;
+ }
+
+ while (!ended) {
+ // follow VCARD ,it wont reach endProperty
+ if (mBuilder != null) {
+ long start = System.currentTimeMillis();
+ mBuilder.startProperty();
+ mTimeStartProperty += System.currentTimeMillis() - start;
+ }
+ ended = parseItem();
+ if (mBuilder != null && !ended) {
+ long start = System.currentTimeMillis();
+ mBuilder.endProperty();
+ mTimeEndProperty += System.currentTimeMillis() - start;
+ }
+ }
+ }
+
+ /**
+ * item = [groups "."] name [params] ":" value CRLF
+ * / [groups "."] "ADR" [params] ":" addressparts CRLF
+ * / [groups "."] "ORG" [params] ":" orgparts CRLF
+ * / [groups "."] "N" [params] ":" nameparts CRLF
+ * / [groups "."] "AGENT" [params] ":" vcard CRLF
+ */
+ protected boolean parseItem() throws IOException, VCardException {
+ mEncoding = sDefaultEncoding;
+
+ String line = getNonEmptyLine();
+ long start = System.currentTimeMillis();
+
+ String[] propertyNameAndValue = separateLineAndHandleGroup(line);
+ if (propertyNameAndValue == null) {
+ return true;
+ }
+ if (propertyNameAndValue.length != 2) {
+ throw new VCardException("Invalid line \"" + line + "\"");
+ }
+ String propertyName = propertyNameAndValue[0].toUpperCase();
+ String propertyValue = propertyNameAndValue[1];
+
+ mTimeParseLineAndHandleGroup += System.currentTimeMillis() - start;
+
+ if (propertyName.equals("ADR") || propertyName.equals("ORG") ||
+ propertyName.equals("N")) {
+ start = System.currentTimeMillis();
+ handleMultiplePropertyValue(propertyName, propertyValue);
+ mTimeParseAdrOrgN += System.currentTimeMillis() - start;
+ return false;
+ } else if (propertyName.equals("AGENT")) {
+ handleAgent(propertyValue);
+ return false;
+ } else if (isValidPropertyName(propertyName)) {
+ if (propertyName.equals("BEGIN")) {
+ if (propertyValue.equals("VCARD")) {
+ throw new VCardNestedException("This vCard has nested vCard data in it.");
+ } else {
+ throw new VCardException("Unknown BEGIN type: " + propertyValue);
+ }
+ } else if (propertyName.equals("VERSION") && !propertyValue.equals(getVersion())) {
+ throw new VCardVersionException("Incompatible version: " +
+ propertyValue + " != " + getVersion());
+ }
+ start = System.currentTimeMillis();
+ handlePropertyValue(propertyName, propertyValue);
+ mTimeParsePropertyValues += System.currentTimeMillis() - start;
+ return false;
+ }
+
+ throw new VCardException("Unknown property name: \"" +
+ propertyName + "\"");
+ }
+
+ static private final int STATE_GROUP_OR_PROPNAME = 0;
+ static private final int STATE_PARAMS = 1;
+ // vCard 3.1 specification allows double-quoted param-value, while vCard 2.1 does not.
+ // This is just for safety.
+ static private final int STATE_PARAMS_IN_DQUOTE = 2;
+
+ protected String[] separateLineAndHandleGroup(String line) throws VCardException {
+ int length = line.length();
+ int state = STATE_GROUP_OR_PROPNAME;
+ int nameIndex = 0;
+
+ String[] propertyNameAndValue = new String[2];
+
+ for (int i = 0; i < length; i++) {
+ char ch = line.charAt(i);
+ switch (state) {
+ case STATE_GROUP_OR_PROPNAME:
+ if (ch == ':') {
+ String propertyName = line.substring(nameIndex, i);
+ if (propertyName.equalsIgnoreCase("END")) {
+ mPreviousLine = line;
+ return null;
+ }
+ if (mBuilder != null) {
+ mBuilder.propertyName(propertyName);
+ }
+ propertyNameAndValue[0] = propertyName;
+ if (i < length - 1) {
+ propertyNameAndValue[1] = line.substring(i + 1);
+ } else {
+ propertyNameAndValue[1] = "";
+ }
+ return propertyNameAndValue;
+ } else if (ch == '.') {
+ String groupName = line.substring(nameIndex, i);
+ if (mBuilder != null) {
+ mBuilder.propertyGroup(groupName);
+ }
+ nameIndex = i + 1;
+ } else if (ch == ';') {
+ String propertyName = line.substring(nameIndex, i);
+ if (propertyName.equalsIgnoreCase("END")) {
+ mPreviousLine = line;
+ return null;
+ }
+ if (mBuilder != null) {
+ mBuilder.propertyName(propertyName);
+ }
+ propertyNameAndValue[0] = propertyName;
+ nameIndex = i + 1;
+ state = STATE_PARAMS;
+ }
+ break;
+ case STATE_PARAMS:
+ if (ch == '"') {
+ state = STATE_PARAMS_IN_DQUOTE;
+ } else if (ch == ';') {
+ handleParams(line.substring(nameIndex, i));
+ nameIndex = i + 1;
+ } else if (ch == ':') {
+ handleParams(line.substring(nameIndex, i));
+ if (i < length - 1) {
+ propertyNameAndValue[1] = line.substring(i + 1);
+ } else {
+ propertyNameAndValue[1] = "";
+ }
+ return propertyNameAndValue;
+ }
+ break;
+ case STATE_PARAMS_IN_DQUOTE:
+ if (ch == '"') {
+ state = STATE_PARAMS;
+ }
+ break;
+ }
+ }
+
+ throw new VCardException("Invalid line: \"" + line + "\"");
+ }
+
+
+ /**
+ * params = ";" [ws] paramlist
+ * paramlist = paramlist [ws] ";" [ws] param
+ * / param
+ * param = "TYPE" [ws] "=" [ws] ptypeval
+ * / "VALUE" [ws] "=" [ws] pvalueval
+ * / "ENCODING" [ws] "=" [ws] pencodingval
+ * / "CHARSET" [ws] "=" [ws] charsetval
+ * / "LANGUAGE" [ws] "=" [ws] langval
+ * / "X-" word [ws] "=" [ws] word
+ * / knowntype
+ */
+ protected void handleParams(String params) throws VCardException {
+ String[] strArray = params.split("=", 2);
+ if (strArray.length == 2) {
+ String paramName = strArray[0].trim();
+ String paramValue = strArray[1].trim();
+ if (paramName.equals("TYPE")) {
+ handleType(paramValue);
+ } else if (paramName.equals("VALUE")) {
+ handleValue(paramValue);
+ } else if (paramName.equals("ENCODING")) {
+ handleEncoding(paramValue);
+ } else if (paramName.equals("CHARSET")) {
+ handleCharset(paramValue);
+ } else if (paramName.equals("LANGUAGE")) {
+ handleLanguage(paramValue);
+ } else if (paramName.startsWith("X-")) {
+ handleAnyParam(paramName, paramValue);
+ } else {
+ throw new VCardException("Unknown type \"" + paramName + "\"");
+ }
+ } else {
+ handleType(strArray[0]);
+ }
+ }
+
+ /**
+ * ptypeval = knowntype / "X-" word
+ */
+ protected void handleType(String ptypeval) {
+ String upperTypeValue = ptypeval;
+ if (!(sKnownTypeSet.contains(upperTypeValue) || upperTypeValue.startsWith("X-")) &&
+ !mWarningValueMap.contains(ptypeval)) {
+ mWarningValueMap.add(ptypeval);
+ Log.w(LOG_TAG, "Type unsupported by vCard 2.1: " + ptypeval);
+ }
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("TYPE");
+ mBuilder.propertyParamValue(upperTypeValue);
+ }
+ }
+
+ /**
+ * pvalueval = "INLINE" / "URL" / "CONTENT-ID" / "CID" / "X-" word
+ */
+ protected void handleValue(String pvalueval) throws VCardException {
+ if (sKnownValueSet.contains(pvalueval.toUpperCase()) ||
+ pvalueval.startsWith("X-")) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("VALUE");
+ mBuilder.propertyParamValue(pvalueval);
+ }
+ } else {
+ throw new VCardException("Unknown value \"" + pvalueval + "\"");
+ }
+ }
+
+ /**
+ * pencodingval = "7BIT" / "8BIT" / "QUOTED-PRINTABLE" / "BASE64" / "X-" word
+ */
+ protected void handleEncoding(String pencodingval) throws VCardException {
+ if (isValidEncoding(pencodingval) ||
+ pencodingval.startsWith("X-")) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("ENCODING");
+ mBuilder.propertyParamValue(pencodingval);
+ }
+ mEncoding = pencodingval;
+ } else {
+ throw new VCardException("Unknown encoding \"" + pencodingval + "\"");
+ }
+ }
+
+ /**
+ * vCard specification only allows us-ascii and iso-8859-xxx (See RFC 1521),
+ * but some vCard contains other charset, so we allow them.
+ */
+ protected void handleCharset(String charsetval) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("CHARSET");
+ mBuilder.propertyParamValue(charsetval);
+ }
+ }
+
+ /**
+ * See also Section 7.1 of RFC 1521
+ */
+ protected void handleLanguage(String langval) throws VCardException {
+ String[] strArray = langval.split("-");
+ if (strArray.length != 2) {
+ throw new VCardException("Invalid Language: \"" + langval + "\"");
+ }
+ String tmp = strArray[0];
+ int length = tmp.length();
+ for (int i = 0; i < length; i++) {
+ if (!isLetter(tmp.charAt(i))) {
+ throw new VCardException("Invalid Language: \"" + langval + "\"");
+ }
+ }
+ tmp = strArray[1];
+ length = tmp.length();
+ for (int i = 0; i < length; i++) {
+ if (!isLetter(tmp.charAt(i))) {
+ throw new VCardException("Invalid Language: \"" + langval + "\"");
+ }
+ }
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("LANGUAGE");
+ mBuilder.propertyParamValue(langval);
+ }
+ }
+
+ /**
+ * Mainly for "X-" type. This accepts any kind of type without check.
+ */
+ protected void handleAnyParam(String paramName, String paramValue) {
+ if (mBuilder != null) {
+ mBuilder.propertyParamType(paramName);
+ mBuilder.propertyParamValue(paramValue);
+ }
+ }
+
+ protected void handlePropertyValue(String propertyName, String propertyValue) throws
+ IOException, VCardException {
+ if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
+ long start = System.currentTimeMillis();
+ String result = getQuotedPrintable(propertyValue);
+ if (mBuilder != null) {
+ ArrayList<String> v = new ArrayList<String>();
+ v.add(result);
+ mBuilder.propertyValues(v);
+ }
+ mTimeHandleQuotedPrintable += System.currentTimeMillis() - start;
+ } else if (mEncoding.equalsIgnoreCase("BASE64") ||
+ mEncoding.equalsIgnoreCase("B")) {
+ long start = System.currentTimeMillis();
+ // It is very rare, but some BASE64 data may be so big that
+ // OutOfMemoryError occurs. To ignore such cases, use try-catch.
+ try {
+ String result = getBase64(propertyValue);
+ if (mBuilder != null) {
+ ArrayList<String> v = new ArrayList<String>();
+ v.add(result);
+ mBuilder.propertyValues(v);
+ }
+ } catch (OutOfMemoryError error) {
+ Log.e(LOG_TAG, "OutOfMemoryError happened during parsing BASE64 data!");
+ if (mBuilder != null) {
+ mBuilder.propertyValues(null);
+ }
+ }
+ mTimeHandleBase64 += System.currentTimeMillis() - start;
+ } else {
+ if (!(mEncoding == null || mEncoding.equalsIgnoreCase("7BIT")
+ || mEncoding.equalsIgnoreCase("8BIT")
+ || mEncoding.toUpperCase().startsWith("X-"))) {
+ Log.w(LOG_TAG, "The encoding unsupported by vCard spec: \"" + mEncoding + "\".");
+ }
+
+ long start = System.currentTimeMillis();
+ if (mBuilder != null) {
+ ArrayList<String> v = new ArrayList<String>();
+ v.add(maybeUnescapeText(propertyValue));
+ mBuilder.propertyValues(v);
+ }
+ mTimeHandleMiscPropertyValue += System.currentTimeMillis() - start;
+ }
+ }
+
+ protected String getQuotedPrintable(String firstString) throws IOException, VCardException {
+ // Specifically, there may be some padding between = and CRLF.
+ // See the following:
+ //
+ // qp-line := *(qp-segment transport-padding CRLF)
+ // qp-part transport-padding
+ // qp-segment := qp-section *(SPACE / TAB) "="
+ // ; Maximum length of 76 characters
+ //
+ // e.g. (from RFC 2045)
+ // Now's the time =
+ // for all folk to come=
+ // to the aid of their country.
+ if (firstString.trim().endsWith("=")) {
+ // remove "transport-padding"
+ int pos = firstString.length() - 1;
+ while(firstString.charAt(pos) != '=') {
+ }
+ StringBuilder builder = new StringBuilder();
+ builder.append(firstString.substring(0, pos + 1));
+ builder.append("\r\n");
+ String line;
+ while (true) {
+ line = getLine();
+ if (line == null) {
+ throw new VCardException(
+ "File ended during parsing quoted-printable String");
+ }
+ if (line.trim().endsWith("=")) {
+ // remove "transport-padding"
+ pos = line.length() - 1;
+ while(line.charAt(pos) != '=') {
+ }
+ builder.append(line.substring(0, pos + 1));
+ builder.append("\r\n");
+ } else {
+ builder.append(line);
+ break;
+ }
+ }
+ return builder.toString();
+ } else {
+ return firstString;
+ }
+ }
+
+ protected String getBase64(String firstString) throws IOException, VCardException {
+ StringBuilder builder = new StringBuilder();
+ builder.append(firstString);
+
+ while (true) {
+ String line = getLine();
+ if (line == null) {
+ throw new VCardException(
+ "File ended during parsing BASE64 binary");
+ }
+ if (line.length() == 0) {
+ break;
+ }
+ builder.append(line);
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Mainly for "ADR", "ORG", and "N"
+ * We do not care the number of strnosemi here.
+ *
+ * addressparts = 0*6(strnosemi ";") strnosemi
+ * ; PO Box, Extended Addr, Street, Locality, Region,
+ * Postal Code, Country Name
+ * orgparts = *(strnosemi ";") strnosemi
+ * ; First is Organization Name,
+ * remainder are Organization Units.
+ * nameparts = 0*4(strnosemi ";") strnosemi
+ * ; Family, Given, Middle, Prefix, Suffix.
+ * ; Example:Public;John;Q.;Reverend Dr.;III, Esq.
+ * strnosemi = *(*nonsemi ("\;" / "\" CRLF)) *nonsemi
+ * ; To include a semicolon in this string, it must be escaped
+ * ; with a "\" character.
+ *
+ * We are not sure whether we should add "\" CRLF to each value.
+ * For now, we exclude them.
+ */
+ protected void handleMultiplePropertyValue(String propertyName, String propertyValue)
+ throws IOException, VCardException {
+ // vCard 2.1 does not allow QUOTED-PRINTABLE here,
+ // but some softwares/devices emit such data.
+ if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
+ propertyValue = getQuotedPrintable(propertyValue);
+ }
+
+ if (mBuilder != null) {
+ StringBuilder builder = new StringBuilder();
+ ArrayList<String> list = new ArrayList<String>();
+ int length = propertyValue.length();
+ for (int i = 0; i < length; i++) {
+ char ch = propertyValue.charAt(i);
+ if (ch == '\\' && i < length - 1) {
+ char nextCh = propertyValue.charAt(i + 1);
+ String unescapedString = maybeUnescapeCharacter(nextCh);
+ if (unescapedString != null) {
+ builder.append(unescapedString);
+ i++;
+ } else {
+ builder.append(ch);
+ }
+ } else if (ch == ';') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ } else {
+ builder.append(ch);
+ }
+ }
+ list.add(builder.toString());
+ mBuilder.propertyValues(list);
+ }
+ }
+
+ /**
+ * vCard 2.1 specifies AGENT allows one vcard entry. It is not encoded at all.
+ *
+ * item = ...
+ * / [groups "."] "AGENT"
+ * [params] ":" vcard CRLF
+ * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
+ * items *CRLF "END" [ws] ":" [ws] "VCARD"
+ *
+ */
+ protected void handleAgent(String propertyValue) throws VCardException {
+ throw new VCardNotSupportedException("AGENT Property is not supported now.");
+ /* This is insufficient support. Also, AGENT Property is very rare.
+ Ignore it for now.
+
+ String[] strArray = propertyValue.split(":", 2);
+ if (!(strArray.length == 2 ||
+ strArray[0].trim().equalsIgnoreCase("BEGIN") &&
+ strArray[1].trim().equalsIgnoreCase("VCARD"))) {
+ throw new VCardException("BEGIN:VCARD != \"" + propertyValue + "\"");
+ }
+ parseItems();
+ readEndVCard();
+ */
+ }
+
+ /**
+ * For vCard 3.0.
+ */
+ protected String maybeUnescapeText(String text) {
+ return text;
+ }
+
+ /**
+ * Returns unescaped String if the character should be unescaped. Return null otherwise.
+ * e.g. In vCard 2.1, "\;" should be unescaped into ";" while "\x" should not be.
+ */
+ protected String maybeUnescapeCharacter(char ch) {
+ // Original vCard 2.1 specification does not allow transformation
+ // "\:" -> ":", "\," -> ",", and "\\" -> "\", but previous implementation of
+ // this class allowed them, so keep it as is.
+ if (ch == '\\' || ch == ';' || ch == ':' || ch == ',') {
+ return String.valueOf(ch);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean parse(InputStream is, VCardBuilder builder)
+ throws IOException, VCardException {
+ return parse(is, VCardConfig.DEFAULT_CHARSET, builder);
+ }
+
+ @Override
+ public boolean parse(InputStream is, String charset, VCardBuilder builder)
+ throws IOException, VCardException {
+ final InputStreamReader tmpReader = new InputStreamReader(is, charset);
+ if (VCardConfig.showPerformanceLog()) {
+ mReader = new CustomBufferedReader(tmpReader);
+ } else {
+ mReader = new BufferedReader(tmpReader);
+ }
+
+ mBuilder = builder;
+
+ long start = System.currentTimeMillis();
+ if (mBuilder != null) {
+ mBuilder.start();
+ }
+ parseVCardFile();
+ if (mBuilder != null) {
+ mBuilder.end();
+ }
+ mTimeTotal += System.currentTimeMillis() - start;
+
+ if (VCardConfig.showPerformanceLog()) {
+ showPerformanceInfo();
+ }
+
+ return true;
+ }
+
+ @Override
+ public void parse(InputStream is, String charset, VCardBuilder builder, boolean canceled)
+ throws IOException, VCardException {
+ mCanceled = canceled;
+ parse(is, charset, builder);
+ }
+
+ private void showPerformanceInfo() {
+ Log.d(LOG_TAG, "Total parsing time: " + mTimeTotal + " ms");
+ if (mReader instanceof CustomBufferedReader) {
+ Log.d(LOG_TAG, "Total readLine time: " +
+ ((CustomBufferedReader)mReader).getTotalmillisecond() + " ms");
+ }
+ Log.d(LOG_TAG, "Time for handling the beggining of the record: " +
+ mTimeReadStartRecord + " ms");
+ Log.d(LOG_TAG, "Time for handling the end of the record: " +
+ mTimeReadEndRecord + " ms");
+ Log.d(LOG_TAG, "Time for parsing line, and handling group: " +
+ mTimeParseLineAndHandleGroup + " ms");
+ Log.d(LOG_TAG, "Time for parsing ADR, ORG, and N fields:" + mTimeParseAdrOrgN + " ms");
+ Log.d(LOG_TAG, "Time for parsing property values: " + mTimeParsePropertyValues + " ms");
+ Log.d(LOG_TAG, "Time for handling normal property values: " +
+ mTimeHandleMiscPropertyValue + " ms");
+ Log.d(LOG_TAG, "Time for handling Quoted-Printable: " +
+ mTimeHandleQuotedPrintable + " ms");
+ Log.d(LOG_TAG, "Time for handling Base64: " + mTimeHandleBase64 + " ms");
+ }
+
+ private boolean isLetter(char ch) {
+ if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
+ return true;
+ }
+ return false;
+ }
+}
+
+class CustomBufferedReader extends BufferedReader {
+ private long mTime;
+
+ public CustomBufferedReader(Reader in) {
+ super(in);
+ }
+
+ @Override
+ public String readLine() throws IOException {
+ long start = System.currentTimeMillis();
+ String ret = super.readLine();
+ long end = System.currentTimeMillis();
+ mTime += end - start;
+ return ret;
+ }
+
+ public long getTotalmillisecond() {
+ return mTime;
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardParser_V30.java b/core/java/android/pim/vcard/VCardParser_V30.java
new file mode 100644
index 0000000..475be4e
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardParser_V30.java
@@ -0,0 +1,306 @@
+/*
+ * 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.pim.vcard;
+
+import android.pim.vcard.exception.VCardException;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+
+/**
+ * This class is used to parse vcard3.0. <br>
+ * Please refer to vCard Specification 3.0 (http://tools.ietf.org/html/rfc2426)
+ */
+public class VCardParser_V30 extends VCardParser_V21 {
+ private static final String LOG_TAG = "vcard.VCardParser_V30";
+
+ private static final HashSet<String> sAcceptablePropsWithParam = new HashSet<String>(
+ Arrays.asList(
+ "BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
+ "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
+ "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER", // 2.1
+ "NAME", "PROFILE", "SOURCE", "NICKNAME", "CLASS",
+ "SORT-STRING", "CATEGORIES", "PRODID")); // 3.0
+
+ // Although "7bit" and "BASE64" is not allowed in vCard 3.0, we allow it for safety.
+ private static final HashSet<String> sAcceptableEncodingV30 = new HashSet<String>(
+ Arrays.asList("7BIT", "8BIT", "BASE64", "B"));
+
+ // Although RFC 2426 specifies some property must not have parameters, we allow it,
+ // since there may be some careers which violates the RFC...
+ private static final HashSet<String> acceptablePropsWithoutParam = new HashSet<String>();
+
+ private String mPreviousLine;
+
+ @Override
+ protected String getVersion() {
+ return Constants.VERSION_V30;
+ }
+
+ @Override
+ protected boolean isValidPropertyName(String propertyName) {
+ if (!(sAcceptablePropsWithParam.contains(propertyName) ||
+ acceptablePropsWithoutParam.contains(propertyName) ||
+ propertyName.startsWith("X-")) &&
+ !mWarningValueMap.contains(propertyName)) {
+ mWarningValueMap.add(propertyName);
+ Log.w(LOG_TAG, "Property name unsupported by vCard 3.0: " + propertyName);
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean isValidEncoding(String encoding) {
+ return sAcceptableEncodingV30.contains(encoding.toUpperCase());
+ }
+
+ @Override
+ protected String getLine() throws IOException {
+ if (mPreviousLine != null) {
+ String ret = mPreviousLine;
+ mPreviousLine = null;
+ return ret;
+ } else {
+ return mReader.readLine();
+ }
+ }
+
+ /**
+ * vCard 3.0 requires that the line with space at the beginning of the line
+ * must be combined with previous line.
+ */
+ @Override
+ protected String getNonEmptyLine() throws IOException, VCardException {
+ String line;
+ StringBuilder builder = null;
+ while (true) {
+ line = mReader.readLine();
+ if (line == null) {
+ if (builder != null) {
+ return builder.toString();
+ } else if (mPreviousLine != null) {
+ String ret = mPreviousLine;
+ mPreviousLine = null;
+ return ret;
+ }
+ throw new VCardException("Reached end of buffer.");
+ } else if (line.length() == 0) {
+ if (builder != null) {
+ return builder.toString();
+ } else if (mPreviousLine != null) {
+ String ret = mPreviousLine;
+ mPreviousLine = null;
+ return ret;
+ }
+ } else if (line.charAt(0) == ' ' || line.charAt(0) == '\t') {
+ if (builder != null) {
+ // See Section 5.8.1 of RFC 2425 (MIME-DIR document).
+ // Following is the excerpts from it.
+ //
+ // DESCRIPTION:This is a long description that exists on a long line.
+ //
+ // Can be represented as:
+ //
+ // DESCRIPTION:This is a long description
+ // that exists on a long line.
+ //
+ // It could also be represented as:
+ //
+ // DESCRIPTION:This is a long descrip
+ // tion that exists o
+ // n a long line.
+ builder.append(line.substring(1));
+ } else if (mPreviousLine != null) {
+ builder = new StringBuilder();
+ builder.append(mPreviousLine);
+ mPreviousLine = null;
+ builder.append(line.substring(1));
+ } else {
+ throw new VCardException("Space exists at the beginning of the line");
+ }
+ } else {
+ if (mPreviousLine == null) {
+ mPreviousLine = line;
+ if (builder != null) {
+ return builder.toString();
+ }
+ } else {
+ String ret = mPreviousLine;
+ mPreviousLine = line;
+ return ret;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * vcard = [group "."] "BEGIN" ":" "VCARD" 1*CRLF
+ * 1*(contentline)
+ * ;A vCard object MUST include the VERSION, FN and N types.
+ * [group "."] "END" ":" "VCARD" 1*CRLF
+ */
+ @Override
+ protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
+ // TODO: vCard 3.0 supports group.
+ return super.readBeginVCard(allowGarbage);
+ }
+
+ @Override
+ protected void readEndVCard(boolean useCache, boolean allowGarbage)
+ throws IOException, VCardException {
+ // TODO: vCard 3.0 supports group.
+ super.readEndVCard(useCache, allowGarbage);
+ }
+
+ /**
+ * vCard 3.0 allows iana-token as paramType, while vCard 2.1 does not.
+ */
+ @Override
+ protected void handleParams(String params) throws VCardException {
+ try {
+ super.handleParams(params);
+ } catch (VCardException e) {
+ // maybe IANA type
+ String[] strArray = params.split("=", 2);
+ if (strArray.length == 2) {
+ handleAnyParam(strArray[0], strArray[1]);
+ } else {
+ // Must not come here in the current implementation.
+ throw new VCardException(
+ "Unknown params value: " + params);
+ }
+ }
+ }
+
+ @Override
+ protected void handleAnyParam(String paramName, String paramValue) {
+ // vCard 3.0 accept comma-separated multiple values, but
+ // current PropertyNode does not accept it.
+ // For now, we do not split the values.
+ //
+ // TODO: fix this.
+ super.handleAnyParam(paramName, paramValue);
+ }
+
+ /**
+ * vCard 3.0 defines
+ *
+ * param = param-name "=" param-value *("," param-value)
+ * param-name = iana-token / x-name
+ * param-value = ptext / quoted-string
+ * quoted-string = DQUOTE QSAFE-CHAR DQUOTE
+ */
+ @Override
+ protected void handleType(String ptypevalues) {
+ String[] ptypeArray = ptypevalues.split(",");
+ mBuilder.propertyParamType("TYPE");
+ for (String value : ptypeArray) {
+ int length = value.length();
+ if (length >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
+ mBuilder.propertyParamValue(value.substring(1, value.length() - 1));
+ } else {
+ mBuilder.propertyParamValue(value);
+ }
+ }
+ }
+
+ @Override
+ protected void handleAgent(String propertyValue) throws VCardException {
+ // The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.0.
+ //
+ // e.g.
+ // AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n
+ // TITLE:Area Administrator\, Assistant\n EMAIL\;TYPE=INTERN\n
+ // ET:jfriday@host.com\nEND:VCARD\n
+ //
+ // TODO: fix this.
+ //
+ // issue:
+ // vCard 3.0 also allows this as an example.
+ //
+ // AGENT;VALUE=uri:
+ // CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com
+ //
+ // This is not VCARD. Should we support this?
+ throw new VCardException("AGENT in vCard 3.0 is not supported yet.");
+ }
+
+ /**
+ * vCard 3.0 does not require two CRLF at the last of BASE64 data.
+ * It only requires that data should be MIME-encoded.
+ */
+ @Override
+ protected String getBase64(String firstString) throws IOException, VCardException {
+ StringBuilder builder = new StringBuilder();
+ builder.append(firstString);
+
+ while (true) {
+ String line = getLine();
+ if (line == null) {
+ throw new VCardException(
+ "File ended during parsing BASE64 binary");
+ }
+ if (line.length() == 0) {
+ break;
+ } else if (!line.startsWith(" ") && !line.startsWith("\t")) {
+ mPreviousLine = line;
+ break;
+ }
+ builder.append(line);
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * ESCAPED-CHAR = "\\" / "\;" / "\," / "\n" / "\N")
+ * ; \\ encodes \, \n or \N encodes newline
+ * ; \; encodes ;, \, encodes ,
+ *
+ * Note: Apple escape ':' into '\:' while does not escape '\'
+ */
+ @Override
+ protected String maybeUnescapeText(String text) {
+ StringBuilder builder = new StringBuilder();
+ int length = text.length();
+ for (int i = 0; i < length; i++) {
+ char ch = text.charAt(i);
+ if (ch == '\\' && i < length - 1) {
+ char next_ch = text.charAt(++i);
+ if (next_ch == 'n' || next_ch == 'N') {
+ builder.append("\n");
+ } else {
+ builder.append(next_ch);
+ }
+ } else {
+ builder.append(ch);
+ }
+ }
+ return builder.toString();
+ }
+
+ @Override
+ protected String maybeUnescapeCharacter(char ch) {
+ if (ch == 'n' || ch == 'N') {
+ return "\n";
+ } else {
+ return String.valueOf(ch);
+ }
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardSourceDetector.java b/core/java/android/pim/vcard/VCardSourceDetector.java
new file mode 100644
index 0000000..7e2be2b
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardSourceDetector.java
@@ -0,0 +1,137 @@
+/*
+ * 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.pim.vcard;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Class which tries to detects the source of the vCard from its properties.
+ * Currently this implementation is very premature.
+ * @hide
+ */
+public class VCardSourceDetector implements VCardBuilder {
+ // Should only be used in package.
+ static final int TYPE_UNKNOWN = 0;
+ static final int TYPE_APPLE = 1;
+ static final int TYPE_JAPANESE_MOBILE_PHONE = 2; // Used in Japanese mobile phones.
+ static final int TYPE_FOMA = 3; // Used in some Japanese FOMA mobile phones.
+ static final int TYPE_WINDOWS_MOBILE_JP = 4;
+ // TODO: Excel, etc.
+
+ private static Set<String> APPLE_SIGNS = new HashSet<String>(Arrays.asList(
+ "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", "X-PHONETIC-LAST-NAME",
+ "X-ABADR", "X-ABUID"));
+
+ private static Set<String> JAPANESE_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
+ "X-GNO", "X-GN", "X-REDUCTION"));
+
+ private static Set<String> WINDOWS_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
+ "X-MICROSOFT-ASST_TEL", "X-MICROSOFT-ASSISTANT", "X-MICROSOFT-OFFICELOC"));
+
+ // Note: these signes appears before the signs of the other type (e.g. "X-GN").
+ // In other words, Japanese FOMA mobile phones are detected as FOMA, not JAPANESE_MOBILE_PHONES.
+ private static Set<String> FOMA_SIGNS = new HashSet<String>(Arrays.asList(
+ "X-SD-VERN", "X-SD-FORMAT_VER", "X-SD-CATEGORIES", "X-SD-CLASS", "X-SD-DCREATED",
+ "X-SD-DESCRIPTION"));
+ private static String TYPE_FOMA_CHARSET_SIGN = "X-SD-CHAR_CODE";
+
+ private int mType = TYPE_UNKNOWN;
+ // Some mobile phones (like FOMA) tells us the charset of the data.
+ private boolean mNeedParseSpecifiedCharset;
+ private String mSpecifiedCharset;
+
+ public void start() {
+ }
+
+ public void end() {
+ }
+
+ public void startRecord(String type) {
+ }
+
+ public void startProperty() {
+ mNeedParseSpecifiedCharset = false;
+ }
+
+ public void endProperty() {
+ }
+
+ public void endRecord() {
+ }
+
+ public void propertyGroup(String group) {
+ }
+
+ public void propertyName(String name) {
+ if (name.equalsIgnoreCase(TYPE_FOMA_CHARSET_SIGN)) {
+ mType = TYPE_FOMA;
+ mNeedParseSpecifiedCharset = true;
+ return;
+ }
+ if (mType != TYPE_UNKNOWN) {
+ return;
+ }
+ if (WINDOWS_MOBILE_PHONE_SIGNS.contains(name)) {
+ mType = TYPE_WINDOWS_MOBILE_JP;
+ } else if (FOMA_SIGNS.contains(name)) {
+ mType = TYPE_FOMA;
+ } else if (JAPANESE_MOBILE_PHONE_SIGNS.contains(name)) {
+ mType = TYPE_JAPANESE_MOBILE_PHONE;
+ } else if (APPLE_SIGNS.contains(name)) {
+ mType = TYPE_APPLE;
+ }
+ }
+
+ public void propertyParamType(String type) {
+ }
+
+ public void propertyParamValue(String value) {
+ }
+
+ public void propertyValues(List<String> values) {
+ if (mNeedParseSpecifiedCharset && values.size() > 0) {
+ mSpecifiedCharset = values.get(0);
+ }
+ }
+
+ int getType() {
+ return mType;
+ }
+
+ /**
+ * Return charset String guessed from the source's properties.
+ * This method must be called after parsing target file(s).
+ * @return Charset String. Null is returned if guessing the source fails.
+ */
+ public String getEstimatedCharset() {
+ if (mSpecifiedCharset != null) {
+ return mSpecifiedCharset;
+ }
+ switch (mType) {
+ case TYPE_WINDOWS_MOBILE_JP:
+ case TYPE_FOMA:
+ case TYPE_JAPANESE_MOBILE_PHONE:
+ return "SHIFT_JIS";
+ case TYPE_APPLE:
+ return "UTF-8";
+ default:
+ return null;
+ }
+ }
+}
diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java
new file mode 100644
index 0000000..b7b706f
--- /dev/null
+++ b/core/java/android/pim/vcard/VCardUtils.java
@@ -0,0 +1,764 @@
+/*
+ * 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.pim.vcard;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.text.TextUtils;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utilities for VCard handling codes.
+ */
+public class VCardUtils {
+ /*
+ * TODO: some of methods in this class should be placed to the more appropriate place...
+ */
+
+ // Note that not all types are included in this map/set, since, for example, TYPE_HOME_FAX is
+ // converted to two attribute Strings. These only contain some minor fields valid in both
+ // vCard and current (as of 2009-08-07) Contacts structure.
+ private static final Map<Integer, String> sKnownPhoneTypesMap_ItoS;
+ private static final Set<String> sPhoneTypesSetUnknownToContacts;
+
+ private static final Map<String, Integer> sKnownPhoneTypesMap_StoI;
+
+ static {
+ sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>();
+ sKnownPhoneTypesMap_StoI = new HashMap<String, Integer>();
+
+ sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_CAR, Constants.ATTR_TYPE_CAR);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_CAR, Phone.TYPE_CAR);
+ sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_PAGER, Constants.ATTR_TYPE_PAGER);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PAGER, Phone.TYPE_PAGER);
+ sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_ISDN, Constants.ATTR_TYPE_ISDN);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_ISDN, Phone.TYPE_ISDN);
+
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_HOME, Phone.TYPE_HOME);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_WORK, Phone.TYPE_WORK);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_CELL, Phone.TYPE_MOBILE);
+
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_OTHER, Phone.TYPE_OTHER);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_CALLBACK, Phone.TYPE_CALLBACK);
+ sKnownPhoneTypesMap_StoI.put(
+ Constants.ATTR_TYPE_PHONE_EXTRA_COMPANY_MAIN, Phone.TYPE_COMPANY_MAIN);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_RADIO, Phone.TYPE_RADIO);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_TELEX, Phone.TYPE_TELEX);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_TTY_TDD, Phone.TYPE_TTY_TDD);
+ sKnownPhoneTypesMap_StoI.put(Constants.ATTR_TYPE_PHONE_EXTRA_ASSISTANT, Phone.TYPE_ASSISTANT);
+
+ sPhoneTypesSetUnknownToContacts = new HashSet<String>();
+ sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_MODEM);
+ sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_MSG);
+ sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_BBS);
+ sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_VIDEO);
+ }
+
+ public static String getPhoneAttributeString(int type) {
+ return sKnownPhoneTypesMap_ItoS.get(type);
+ }
+
+ /**
+ * Returns Interger when the given types can be parsed as known type. Returns String object
+ * when not, which should be set to label.
+ */
+ public static Object getPhoneTypeFromStrings(Collection<String> types) {
+ int type = -1;
+ String label = null;
+ boolean isFax = false;
+ boolean hasPref = false;
+
+ if (types != null) {
+ for (String typeString : types) {
+ typeString = typeString.toUpperCase();
+ if (typeString.equals(Constants.ATTR_TYPE_PREF)) {
+ hasPref = true;
+ } else if (typeString.equals(Constants.ATTR_TYPE_FAX)) {
+ isFax = true;
+ } else {
+ if (typeString.startsWith("X-") && type < 0) {
+ typeString = typeString.substring(2);
+ }
+ Integer tmp = sKnownPhoneTypesMap_StoI.get(typeString);
+ if (tmp != null) {
+ type = tmp;
+ } else if (type < 0) {
+ type = Phone.TYPE_CUSTOM;
+ label = typeString;
+ }
+ }
+ }
+ }
+ if (type < 0) {
+ if (hasPref) {
+ type = Phone.TYPE_MAIN;
+ } else {
+ // default to TYPE_HOME
+ type = Phone.TYPE_HOME;
+ }
+ }
+ if (isFax) {
+ if (type == Phone.TYPE_HOME) {
+ type = Phone.TYPE_FAX_HOME;
+ } else if (type == Phone.TYPE_WORK) {
+ type = Phone.TYPE_FAX_WORK;
+ } else if (type == Phone.TYPE_OTHER) {
+ type = Phone.TYPE_OTHER_FAX;
+ }
+ }
+ if (type == Phone.TYPE_CUSTOM) {
+ return label;
+ } else {
+ return type;
+ }
+ }
+
+ public static boolean isValidPhoneAttribute(String phoneAttribute, int vcardType) {
+ // TODO: check the following.
+ // - it may violate vCard spec
+ // - it may contain non-ASCII characters
+ //
+ // TODO: use vcardType
+ return (phoneAttribute.startsWith("X-") || phoneAttribute.startsWith("x-") ||
+ sPhoneTypesSetUnknownToContacts.contains(phoneAttribute));
+ }
+
+ public static String[] sortNameElements(int vcardType,
+ String familyName, String middleName, String givenName) {
+ String[] list = new String[3];
+ switch (VCardConfig.getNameOrderType(vcardType)) {
+ case VCardConfig.NAME_ORDER_JAPANESE:
+ // TODO: Should handle Ascii case?
+ list[0] = familyName;
+ list[1] = middleName;
+ list[2] = givenName;
+ break;
+ case VCardConfig.NAME_ORDER_EUROPE:
+ list[0] = middleName;
+ list[1] = givenName;
+ list[2] = familyName;
+ break;
+ default:
+ list[0] = givenName;
+ list[1] = middleName;
+ list[2] = familyName;
+ break;
+ }
+ return list;
+ }
+
+ /**
+ * Inserts postal data into the builder object.
+ *
+ * Note that the data structure of ContactsContract is different from that defined in vCard.
+ * So some conversion may be performed in this method. See also
+ * {{@link #getVCardPostalElements(ContentValues)}
+ */
+ public static void insertStructuredPostalDataUsingContactsStruct(int vcardType,
+ final ContentProviderOperation.Builder builder,
+ final ContactStruct.PostalData postalData) {
+ builder.withValueBackReference(StructuredPostal.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
+
+ builder.withValue(StructuredPostal.TYPE, postalData.type);
+ if (postalData.type == StructuredPostal.TYPE_CUSTOM) {
+ builder.withValue(StructuredPostal.LABEL, postalData.label);
+ }
+
+ builder.withValue(StructuredPostal.POBOX, postalData.pobox);
+ // Extended address is dropped since there's no relevant entry in ContactsContract.
+ builder.withValue(StructuredPostal.STREET, postalData.street);
+ builder.withValue(StructuredPostal.CITY, postalData.localty);
+ builder.withValue(StructuredPostal.REGION, postalData.region);
+ builder.withValue(StructuredPostal.POSTCODE, postalData.postalCode);
+ builder.withValue(StructuredPostal.COUNTRY, postalData.country);
+
+ builder.withValue(StructuredPostal.FORMATTED_ADDRESS,
+ postalData.getFormattedAddress(vcardType));
+ if (postalData.isPrimary) {
+ builder.withValue(Data.IS_PRIMARY, 1);
+ }
+ }
+
+ /**
+ * Returns String[] containing address information based on vCard spec
+ * (PO Box, Extended Address, Street, Locality, Region, Postal Code, Country Name).
+ * All String objects are non-null ("" is used when the relevant data is empty).
+ *
+ * Note that the data structure of ContactsContract is different from that defined in vCard.
+ * So some conversion may be performed in this method. See also
+ * {{@link #insertStructuredPostalDataUsingContactsStruct(int,
+ * android.content.ContentProviderOperation.Builder,
+ * android.pim.vcard.ContactStruct.PostalData)}
+ */
+ public static String[] getVCardPostalElements(ContentValues contentValues) {
+ String[] dataArray = new String[7];
+ dataArray[0] = contentValues.getAsString(StructuredPostal.POBOX);
+ if (dataArray[0] == null) {
+ dataArray[0] = "";
+ }
+ // Extended addr. There's no relevant data in ContactsContract.
+ dataArray[1] = "";
+ dataArray[2] = contentValues.getAsString(StructuredPostal.STREET);
+ if (dataArray[2] == null) {
+ dataArray[2] = "";
+ }
+ // Assume that localty == city
+ dataArray[3] = contentValues.getAsString(StructuredPostal.CITY);
+ if (dataArray[3] == null) {
+ dataArray[3] = "";
+ }
+ String region = contentValues.getAsString(StructuredPostal.REGION);
+ if (!TextUtils.isEmpty(region)) {
+ dataArray[4] = region;
+ } else {
+ dataArray[4] = "";
+ }
+ dataArray[5] = contentValues.getAsString(StructuredPostal.POSTCODE);
+ if (dataArray[5] == null) {
+ dataArray[5] = "";
+ }
+ dataArray[6] = contentValues.getAsString(StructuredPostal.COUNTRY);
+ if (dataArray[6] == null) {
+ dataArray[6] = "";
+ }
+
+ return dataArray;
+ }
+
+ public static String constructNameFromElements(int nameOrderType,
+ String familyName, String middleName, String givenName) {
+ return constructNameFromElements(nameOrderType, familyName, middleName, givenName,
+ null, null);
+ }
+
+ public static String constructNameFromElements(int nameOrderType,
+ String familyName, String middleName, String givenName,
+ String prefix, String suffix) {
+ StringBuilder builder = new StringBuilder();
+ String[] nameList = sortNameElements(nameOrderType,
+ familyName, middleName, givenName);
+ boolean first = true;
+ if (!TextUtils.isEmpty(prefix)) {
+ first = false;
+ builder.append(prefix);
+ }
+ for (String namePart : nameList) {
+ if (!TextUtils.isEmpty(namePart)) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(' ');
+ }
+ builder.append(namePart);
+ }
+ }
+ if (!TextUtils.isEmpty(suffix)) {
+ if (!first) {
+ builder.append(' ');
+ }
+ builder.append(suffix);
+ }
+ return builder.toString();
+ }
+
+ public static boolean containsOnlyAscii(String str) {
+ if (TextUtils.isEmpty(str)) {
+ return true;
+ }
+
+ final int length = str.length();
+ final int asciiFirst = 0x20;
+ final int asciiLast = 0x126;
+ for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
+ int c = str.codePointAt(i);
+ if (c < asciiFirst || asciiLast < c) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * This is useful since vCard 3.0 often requires the ("X-") properties and groups
+ * should contain only alphabets, digits, and hyphen.
+ *
+ * Note: It is already known some devices (wrongly) outputs properties with characters
+ * which should not be in the field. One example is "X-GOOGLE TALK". We appreciate
+ * such kind of input but must never output it unless the target is very specific
+ * to the device which is able to parse the malformed input.
+ */
+ public static boolean containsOnlyAlphaDigitHyphen(String str) {
+ if (TextUtils.isEmpty(str)) {
+ return true;
+ }
+
+ final int lowerAlphabetFirst = 0x41; // included ('A')
+ final int lowerAlphabetLast = 0x5b; // not included ('[')
+ final int upperAlphabetFirst = 0x61; // included ('a')
+ final int upperAlphabetLast = 0x7b; // included ('{')
+ final int digitFirst = 0x30; // included ('0')
+ final int digitLast = 0x39; // included ('9')
+ final int hyphen = '-';
+ final int length = str.length();
+ for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
+ int codepoint = str.codePointAt(i);
+ if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetLast) ||
+ (upperAlphabetFirst <= codepoint && codepoint < upperAlphabetLast) ||
+ (digitFirst <= codepoint && codepoint < digitLast) ||
+ (codepoint == hyphen))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // TODO: Replace wth the method in Base64 class.
+ private static char PAD = '=';
+ private static final char[] ENCODE64 = {
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+ };
+
+ static public String encodeBase64(byte[] data) {
+ if (data == null) {
+ return "";
+ }
+
+ char[] charBuffer = new char[(data.length + 2) / 3 * 4];
+ int position = 0;
+ int _3byte = 0;
+ for (int i=0; i<data.length-2; i+=3) {
+ _3byte = ((data[i] & 0xFF) << 16) + ((data[i+1] & 0xFF) << 8) + (data[i+2] & 0xFF);
+ charBuffer[position++] = ENCODE64[_3byte >> 18];
+ charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
+ charBuffer[position++] = ENCODE64[(_3byte >> 6) & 0x3F];
+ charBuffer[position++] = ENCODE64[_3byte & 0x3F];
+ }
+ switch(data.length % 3) {
+ case 1: // [111111][11 0000][0000 00][000000]
+ _3byte = ((data[data.length-1] & 0xFF) << 16);
+ charBuffer[position++] = ENCODE64[_3byte >> 18];
+ charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
+ charBuffer[position++] = PAD;
+ charBuffer[position++] = PAD;
+ break;
+ case 2: // [111111][11 1111][1111 00][000000]
+ _3byte = ((data[data.length-2] & 0xFF) << 16) + ((data[data.length-1] & 0xFF) << 8);
+ charBuffer[position++] = ENCODE64[_3byte >> 18];
+ charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
+ charBuffer[position++] = ENCODE64[(_3byte >> 6) & 0x3F];
+ charBuffer[position++] = PAD;
+ break;
+ }
+
+ return new String(charBuffer);
+ }
+
+ static public String toHalfWidthString(String orgString) {
+ if (TextUtils.isEmpty(orgString)) {
+ return null;
+ }
+ StringBuilder builder = new StringBuilder();
+ int length = orgString.length();
+ for (int i = 0; i < length; i++) {
+ // All Japanese character is able to be expressed by char.
+ // Do not need to use String#codepPointAt().
+ char ch = orgString.charAt(i);
+ CharSequence halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch);
+ if (halfWidthText != null) {
+ builder.append(halfWidthText);
+ } else {
+ builder.append(ch);
+ }
+ }
+ return builder.toString();
+ }
+
+ private VCardUtils() {
+ }
+}
+
+/**
+ * TextUtils especially for Japanese.
+ * TODO: make this in android.text in the future
+ */
+class JapaneseUtils {
+ static private final Map<Character, String> sHalfWidthMap =
+ new HashMap<Character, String>();
+
+ static {
+ // There's no logical mapping rule in Unicode. Sigh.
+ sHalfWidthMap.put('\u3001', "\uFF64");
+ sHalfWidthMap.put('\u3002', "\uFF61");
+ sHalfWidthMap.put('\u300C', "\uFF62");
+ sHalfWidthMap.put('\u300D', "\uFF63");
+ sHalfWidthMap.put('\u301C', "~");
+ sHalfWidthMap.put('\u3041', "\uFF67");
+ sHalfWidthMap.put('\u3042', "\uFF71");
+ sHalfWidthMap.put('\u3043', "\uFF68");
+ sHalfWidthMap.put('\u3044', "\uFF72");
+ sHalfWidthMap.put('\u3045', "\uFF69");
+ sHalfWidthMap.put('\u3046', "\uFF73");
+ sHalfWidthMap.put('\u3047', "\uFF6A");
+ sHalfWidthMap.put('\u3048', "\uFF74");
+ sHalfWidthMap.put('\u3049', "\uFF6B");
+ sHalfWidthMap.put('\u304A', "\uFF75");
+ sHalfWidthMap.put('\u304B', "\uFF76");
+ sHalfWidthMap.put('\u304C', "\uFF76\uFF9E");
+ sHalfWidthMap.put('\u304D', "\uFF77");
+ sHalfWidthMap.put('\u304E', "\uFF77\uFF9E");
+ sHalfWidthMap.put('\u304F', "\uFF78");
+ sHalfWidthMap.put('\u3050', "\uFF78\uFF9E");
+ sHalfWidthMap.put('\u3051', "\uFF79");
+ sHalfWidthMap.put('\u3052', "\uFF79\uFF9E");
+ sHalfWidthMap.put('\u3053', "\uFF7A");
+ sHalfWidthMap.put('\u3054', "\uFF7A\uFF9E");
+ sHalfWidthMap.put('\u3055', "\uFF7B");
+ sHalfWidthMap.put('\u3056', "\uFF7B\uFF9E");
+ sHalfWidthMap.put('\u3057', "\uFF7C");
+ sHalfWidthMap.put('\u3058', "\uFF7C\uFF9E");
+ sHalfWidthMap.put('\u3059', "\uFF7D");
+ sHalfWidthMap.put('\u305A', "\uFF7D\uFF9E");
+ sHalfWidthMap.put('\u305B', "\uFF7E");
+ sHalfWidthMap.put('\u305C', "\uFF7E\uFF9E");
+ sHalfWidthMap.put('\u305D', "\uFF7F");
+ sHalfWidthMap.put('\u305E', "\uFF7F\uFF9E");
+ sHalfWidthMap.put('\u305F', "\uFF80");
+ sHalfWidthMap.put('\u3060', "\uFF80\uFF9E");
+ sHalfWidthMap.put('\u3061', "\uFF81");
+ sHalfWidthMap.put('\u3062', "\uFF81\uFF9E");
+ sHalfWidthMap.put('\u3063', "\uFF6F");
+ sHalfWidthMap.put('\u3064', "\uFF82");
+ sHalfWidthMap.put('\u3065', "\uFF82\uFF9E");
+ sHalfWidthMap.put('\u3066', "\uFF83");
+ sHalfWidthMap.put('\u3067', "\uFF83\uFF9E");
+ sHalfWidthMap.put('\u3068', "\uFF84");
+ sHalfWidthMap.put('\u3069', "\uFF84\uFF9E");
+ sHalfWidthMap.put('\u306A', "\uFF85");
+ sHalfWidthMap.put('\u306B', "\uFF86");
+ sHalfWidthMap.put('\u306C', "\uFF87");
+ sHalfWidthMap.put('\u306D', "\uFF88");
+ sHalfWidthMap.put('\u306E', "\uFF89");
+ sHalfWidthMap.put('\u306F', "\uFF8A");
+ sHalfWidthMap.put('\u3070', "\uFF8A\uFF9E");
+ sHalfWidthMap.put('\u3071', "\uFF8A\uFF9F");
+ sHalfWidthMap.put('\u3072', "\uFF8B");
+ sHalfWidthMap.put('\u3073', "\uFF8B\uFF9E");
+ sHalfWidthMap.put('\u3074', "\uFF8B\uFF9F");
+ sHalfWidthMap.put('\u3075', "\uFF8C");
+ sHalfWidthMap.put('\u3076', "\uFF8C\uFF9E");
+ sHalfWidthMap.put('\u3077', "\uFF8C\uFF9F");
+ sHalfWidthMap.put('\u3078', "\uFF8D");
+ sHalfWidthMap.put('\u3079', "\uFF8D\uFF9E");
+ sHalfWidthMap.put('\u307A', "\uFF8D\uFF9F");
+ sHalfWidthMap.put('\u307B', "\uFF8E");
+ sHalfWidthMap.put('\u307C', "\uFF8E\uFF9E");
+ sHalfWidthMap.put('\u307D', "\uFF8E\uFF9F");
+ sHalfWidthMap.put('\u307E', "\uFF8F");
+ sHalfWidthMap.put('\u307F', "\uFF90");
+ sHalfWidthMap.put('\u3080', "\uFF91");
+ sHalfWidthMap.put('\u3081', "\uFF92");
+ sHalfWidthMap.put('\u3082', "\uFF93");
+ sHalfWidthMap.put('\u3083', "\uFF6C");
+ sHalfWidthMap.put('\u3084', "\uFF94");
+ sHalfWidthMap.put('\u3085', "\uFF6D");
+ sHalfWidthMap.put('\u3086', "\uFF95");
+ sHalfWidthMap.put('\u3087', "\uFF6E");
+ sHalfWidthMap.put('\u3088', "\uFF96");
+ sHalfWidthMap.put('\u3089', "\uFF97");
+ sHalfWidthMap.put('\u308A', "\uFF98");
+ sHalfWidthMap.put('\u308B', "\uFF99");
+ sHalfWidthMap.put('\u308C', "\uFF9A");
+ sHalfWidthMap.put('\u308D', "\uFF9B");
+ sHalfWidthMap.put('\u308E', "\uFF9C");
+ sHalfWidthMap.put('\u308F', "\uFF9C");
+ sHalfWidthMap.put('\u3090', "\uFF72");
+ sHalfWidthMap.put('\u3091', "\uFF74");
+ sHalfWidthMap.put('\u3092', "\uFF66");
+ sHalfWidthMap.put('\u3093', "\uFF9D");
+ sHalfWidthMap.put('\u309B', "\uFF9E");
+ sHalfWidthMap.put('\u309C', "\uFF9F");
+ sHalfWidthMap.put('\u30A1', "\uFF67");
+ sHalfWidthMap.put('\u30A2', "\uFF71");
+ sHalfWidthMap.put('\u30A3', "\uFF68");
+ sHalfWidthMap.put('\u30A4', "\uFF72");
+ sHalfWidthMap.put('\u30A5', "\uFF69");
+ sHalfWidthMap.put('\u30A6', "\uFF73");
+ sHalfWidthMap.put('\u30A7', "\uFF6A");
+ sHalfWidthMap.put('\u30A8', "\uFF74");
+ sHalfWidthMap.put('\u30A9', "\uFF6B");
+ sHalfWidthMap.put('\u30AA', "\uFF75");
+ sHalfWidthMap.put('\u30AB', "\uFF76");
+ sHalfWidthMap.put('\u30AC', "\uFF76\uFF9E");
+ sHalfWidthMap.put('\u30AD', "\uFF77");
+ sHalfWidthMap.put('\u30AE', "\uFF77\uFF9E");
+ sHalfWidthMap.put('\u30AF', "\uFF78");
+ sHalfWidthMap.put('\u30B0', "\uFF78\uFF9E");
+ sHalfWidthMap.put('\u30B1', "\uFF79");
+ sHalfWidthMap.put('\u30B2', "\uFF79\uFF9E");
+ sHalfWidthMap.put('\u30B3', "\uFF7A");
+ sHalfWidthMap.put('\u30B4', "\uFF7A\uFF9E");
+ sHalfWidthMap.put('\u30B5', "\uFF7B");
+ sHalfWidthMap.put('\u30B6', "\uFF7B\uFF9E");
+ sHalfWidthMap.put('\u30B7', "\uFF7C");
+ sHalfWidthMap.put('\u30B8', "\uFF7C\uFF9E");
+ sHalfWidthMap.put('\u30B9', "\uFF7D");
+ sHalfWidthMap.put('\u30BA', "\uFF7D\uFF9E");
+ sHalfWidthMap.put('\u30BB', "\uFF7E");
+ sHalfWidthMap.put('\u30BC', "\uFF7E\uFF9E");
+ sHalfWidthMap.put('\u30BD', "\uFF7F");
+ sHalfWidthMap.put('\u30BE', "\uFF7F\uFF9E");
+ sHalfWidthMap.put('\u30BF', "\uFF80");
+ sHalfWidthMap.put('\u30C0', "\uFF80\uFF9E");
+ sHalfWidthMap.put('\u30C1', "\uFF81");
+ sHalfWidthMap.put('\u30C2', "\uFF81\uFF9E");
+ sHalfWidthMap.put('\u30C3', "\uFF6F");
+ sHalfWidthMap.put('\u30C4', "\uFF82");
+ sHalfWidthMap.put('\u30C5', "\uFF82\uFF9E");
+ sHalfWidthMap.put('\u30C6', "\uFF83");
+ sHalfWidthMap.put('\u30C7', "\uFF83\uFF9E");
+ sHalfWidthMap.put('\u30C8', "\uFF84");
+ sHalfWidthMap.put('\u30C9', "\uFF84\uFF9E");
+ sHalfWidthMap.put('\u30CA', "\uFF85");
+ sHalfWidthMap.put('\u30CB', "\uFF86");
+ sHalfWidthMap.put('\u30CC', "\uFF87");
+ sHalfWidthMap.put('\u30CD', "\uFF88");
+ sHalfWidthMap.put('\u30CE', "\uFF89");
+ sHalfWidthMap.put('\u30CF', "\uFF8A");
+ sHalfWidthMap.put('\u30D0', "\uFF8A\uFF9E");
+ sHalfWidthMap.put('\u30D1', "\uFF8A\uFF9F");
+ sHalfWidthMap.put('\u30D2', "\uFF8B");
+ sHalfWidthMap.put('\u30D3', "\uFF8B\uFF9E");
+ sHalfWidthMap.put('\u30D4', "\uFF8B\uFF9F");
+ sHalfWidthMap.put('\u30D5', "\uFF8C");
+ sHalfWidthMap.put('\u30D6', "\uFF8C\uFF9E");
+ sHalfWidthMap.put('\u30D7', "\uFF8C\uFF9F");
+ sHalfWidthMap.put('\u30D8', "\uFF8D");
+ sHalfWidthMap.put('\u30D9', "\uFF8D\uFF9E");
+ sHalfWidthMap.put('\u30DA', "\uFF8D\uFF9F");
+ sHalfWidthMap.put('\u30DB', "\uFF8E");
+ sHalfWidthMap.put('\u30DC', "\uFF8E\uFF9E");
+ sHalfWidthMap.put('\u30DD', "\uFF8E\uFF9F");
+ sHalfWidthMap.put('\u30DE', "\uFF8F");
+ sHalfWidthMap.put('\u30DF', "\uFF90");
+ sHalfWidthMap.put('\u30E0', "\uFF91");
+ sHalfWidthMap.put('\u30E1', "\uFF92");
+ sHalfWidthMap.put('\u30E2', "\uFF93");
+ sHalfWidthMap.put('\u30E3', "\uFF6C");
+ sHalfWidthMap.put('\u30E4', "\uFF94");
+ sHalfWidthMap.put('\u30E5', "\uFF6D");
+ sHalfWidthMap.put('\u30E6', "\uFF95");
+ sHalfWidthMap.put('\u30E7', "\uFF6E");
+ sHalfWidthMap.put('\u30E8', "\uFF96");
+ sHalfWidthMap.put('\u30E9', "\uFF97");
+ sHalfWidthMap.put('\u30EA', "\uFF98");
+ sHalfWidthMap.put('\u30EB', "\uFF99");
+ sHalfWidthMap.put('\u30EC', "\uFF9A");
+ sHalfWidthMap.put('\u30ED', "\uFF9B");
+ sHalfWidthMap.put('\u30EE', "\uFF9C");
+ sHalfWidthMap.put('\u30EF', "\uFF9C");
+ sHalfWidthMap.put('\u30F0', "\uFF72");
+ sHalfWidthMap.put('\u30F1', "\uFF74");
+ sHalfWidthMap.put('\u30F2', "\uFF66");
+ sHalfWidthMap.put('\u30F3', "\uFF9D");
+ sHalfWidthMap.put('\u30F4', "\uFF73\uFF9E");
+ sHalfWidthMap.put('\u30F5', "\uFF76");
+ sHalfWidthMap.put('\u30F6', "\uFF79");
+ sHalfWidthMap.put('\u30FB', "\uFF65");
+ sHalfWidthMap.put('\u30FC', "\uFF70");
+ sHalfWidthMap.put('\uFF01', "!");
+ sHalfWidthMap.put('\uFF02', "\"");
+ sHalfWidthMap.put('\uFF03', "#");
+ sHalfWidthMap.put('\uFF04', "$");
+ sHalfWidthMap.put('\uFF05', "%");
+ sHalfWidthMap.put('\uFF06', "&");
+ sHalfWidthMap.put('\uFF07', "'");
+ sHalfWidthMap.put('\uFF08', "(");
+ sHalfWidthMap.put('\uFF09', ")");
+ sHalfWidthMap.put('\uFF0A', "*");
+ sHalfWidthMap.put('\uFF0B', "+");
+ sHalfWidthMap.put('\uFF0C', ",");
+ sHalfWidthMap.put('\uFF0D', "-");
+ sHalfWidthMap.put('\uFF0E', ".");
+ sHalfWidthMap.put('\uFF0F', "/");
+ sHalfWidthMap.put('\uFF10', "0");
+ sHalfWidthMap.put('\uFF11', "1");
+ sHalfWidthMap.put('\uFF12', "2");
+ sHalfWidthMap.put('\uFF13', "3");
+ sHalfWidthMap.put('\uFF14', "4");
+ sHalfWidthMap.put('\uFF15', "5");
+ sHalfWidthMap.put('\uFF16', "6");
+ sHalfWidthMap.put('\uFF17', "7");
+ sHalfWidthMap.put('\uFF18', "8");
+ sHalfWidthMap.put('\uFF19', "9");
+ sHalfWidthMap.put('\uFF1A', ":");
+ sHalfWidthMap.put('\uFF1B', ";");
+ sHalfWidthMap.put('\uFF1C', "<");
+ sHalfWidthMap.put('\uFF1D', "=");
+ sHalfWidthMap.put('\uFF1E', ">");
+ sHalfWidthMap.put('\uFF1F', "?");
+ sHalfWidthMap.put('\uFF20', "@");
+ sHalfWidthMap.put('\uFF21', "A");
+ sHalfWidthMap.put('\uFF22', "B");
+ sHalfWidthMap.put('\uFF23', "C");
+ sHalfWidthMap.put('\uFF24', "D");
+ sHalfWidthMap.put('\uFF25', "E");
+ sHalfWidthMap.put('\uFF26', "F");
+ sHalfWidthMap.put('\uFF27', "G");
+ sHalfWidthMap.put('\uFF28', "H");
+ sHalfWidthMap.put('\uFF29', "I");
+ sHalfWidthMap.put('\uFF2A', "J");
+ sHalfWidthMap.put('\uFF2B', "K");
+ sHalfWidthMap.put('\uFF2C', "L");
+ sHalfWidthMap.put('\uFF2D', "M");
+ sHalfWidthMap.put('\uFF2E', "N");
+ sHalfWidthMap.put('\uFF2F', "O");
+ sHalfWidthMap.put('\uFF30', "P");
+ sHalfWidthMap.put('\uFF31', "Q");
+ sHalfWidthMap.put('\uFF32', "R");
+ sHalfWidthMap.put('\uFF33', "S");
+ sHalfWidthMap.put('\uFF34', "T");
+ sHalfWidthMap.put('\uFF35', "U");
+ sHalfWidthMap.put('\uFF36', "V");
+ sHalfWidthMap.put('\uFF37', "W");
+ sHalfWidthMap.put('\uFF38', "X");
+ sHalfWidthMap.put('\uFF39', "Y");
+ sHalfWidthMap.put('\uFF3A', "Z");
+ sHalfWidthMap.put('\uFF3B', "[");
+ sHalfWidthMap.put('\uFF3C', "\\");
+ sHalfWidthMap.put('\uFF3D', "]");
+ sHalfWidthMap.put('\uFF3E', "^");
+ sHalfWidthMap.put('\uFF3F', "_");
+ sHalfWidthMap.put('\uFF41', "a");
+ sHalfWidthMap.put('\uFF42', "b");
+ sHalfWidthMap.put('\uFF43', "c");
+ sHalfWidthMap.put('\uFF44', "d");
+ sHalfWidthMap.put('\uFF45', "e");
+ sHalfWidthMap.put('\uFF46', "f");
+ sHalfWidthMap.put('\uFF47', "g");
+ sHalfWidthMap.put('\uFF48', "h");
+ sHalfWidthMap.put('\uFF49', "i");
+ sHalfWidthMap.put('\uFF4A', "j");
+ sHalfWidthMap.put('\uFF4B', "k");
+ sHalfWidthMap.put('\uFF4C', "l");
+ sHalfWidthMap.put('\uFF4D', "m");
+ sHalfWidthMap.put('\uFF4E', "n");
+ sHalfWidthMap.put('\uFF4F', "o");
+ sHalfWidthMap.put('\uFF50', "p");
+ sHalfWidthMap.put('\uFF51', "q");
+ sHalfWidthMap.put('\uFF52', "r");
+ sHalfWidthMap.put('\uFF53', "s");
+ sHalfWidthMap.put('\uFF54', "t");
+ sHalfWidthMap.put('\uFF55', "u");
+ sHalfWidthMap.put('\uFF56', "v");
+ sHalfWidthMap.put('\uFF57', "w");
+ sHalfWidthMap.put('\uFF58', "x");
+ sHalfWidthMap.put('\uFF59', "y");
+ sHalfWidthMap.put('\uFF5A', "z");
+ sHalfWidthMap.put('\uFF5B', "{");
+ sHalfWidthMap.put('\uFF5C', "|");
+ sHalfWidthMap.put('\uFF5D', "}");
+ sHalfWidthMap.put('\uFF5E', "~");
+ sHalfWidthMap.put('\uFF61', "\uFF61");
+ sHalfWidthMap.put('\uFF62', "\uFF62");
+ sHalfWidthMap.put('\uFF63', "\uFF63");
+ sHalfWidthMap.put('\uFF64', "\uFF64");
+ sHalfWidthMap.put('\uFF65', "\uFF65");
+ sHalfWidthMap.put('\uFF66', "\uFF66");
+ sHalfWidthMap.put('\uFF67', "\uFF67");
+ sHalfWidthMap.put('\uFF68', "\uFF68");
+ sHalfWidthMap.put('\uFF69', "\uFF69");
+ sHalfWidthMap.put('\uFF6A', "\uFF6A");
+ sHalfWidthMap.put('\uFF6B', "\uFF6B");
+ sHalfWidthMap.put('\uFF6C', "\uFF6C");
+ sHalfWidthMap.put('\uFF6D', "\uFF6D");
+ sHalfWidthMap.put('\uFF6E', "\uFF6E");
+ sHalfWidthMap.put('\uFF6F', "\uFF6F");
+ sHalfWidthMap.put('\uFF70', "\uFF70");
+ sHalfWidthMap.put('\uFF71', "\uFF71");
+ sHalfWidthMap.put('\uFF72', "\uFF72");
+ sHalfWidthMap.put('\uFF73', "\uFF73");
+ sHalfWidthMap.put('\uFF74', "\uFF74");
+ sHalfWidthMap.put('\uFF75', "\uFF75");
+ sHalfWidthMap.put('\uFF76', "\uFF76");
+ sHalfWidthMap.put('\uFF77', "\uFF77");
+ sHalfWidthMap.put('\uFF78', "\uFF78");
+ sHalfWidthMap.put('\uFF79', "\uFF79");
+ sHalfWidthMap.put('\uFF7A', "\uFF7A");
+ sHalfWidthMap.put('\uFF7B', "\uFF7B");
+ sHalfWidthMap.put('\uFF7C', "\uFF7C");
+ sHalfWidthMap.put('\uFF7D', "\uFF7D");
+ sHalfWidthMap.put('\uFF7E', "\uFF7E");
+ sHalfWidthMap.put('\uFF7F', "\uFF7F");
+ sHalfWidthMap.put('\uFF80', "\uFF80");
+ sHalfWidthMap.put('\uFF81', "\uFF81");
+ sHalfWidthMap.put('\uFF82', "\uFF82");
+ sHalfWidthMap.put('\uFF83', "\uFF83");
+ sHalfWidthMap.put('\uFF84', "\uFF84");
+ sHalfWidthMap.put('\uFF85', "\uFF85");
+ sHalfWidthMap.put('\uFF86', "\uFF86");
+ sHalfWidthMap.put('\uFF87', "\uFF87");
+ sHalfWidthMap.put('\uFF88', "\uFF88");
+ sHalfWidthMap.put('\uFF89', "\uFF89");
+ sHalfWidthMap.put('\uFF8A', "\uFF8A");
+ sHalfWidthMap.put('\uFF8B', "\uFF8B");
+ sHalfWidthMap.put('\uFF8C', "\uFF8C");
+ sHalfWidthMap.put('\uFF8D', "\uFF8D");
+ sHalfWidthMap.put('\uFF8E', "\uFF8E");
+ sHalfWidthMap.put('\uFF8F', "\uFF8F");
+ sHalfWidthMap.put('\uFF90', "\uFF90");
+ sHalfWidthMap.put('\uFF91', "\uFF91");
+ sHalfWidthMap.put('\uFF92', "\uFF92");
+ sHalfWidthMap.put('\uFF93', "\uFF93");
+ sHalfWidthMap.put('\uFF94', "\uFF94");
+ sHalfWidthMap.put('\uFF95', "\uFF95");
+ sHalfWidthMap.put('\uFF96', "\uFF96");
+ sHalfWidthMap.put('\uFF97', "\uFF97");
+ sHalfWidthMap.put('\uFF98', "\uFF98");
+ sHalfWidthMap.put('\uFF99', "\uFF99");
+ sHalfWidthMap.put('\uFF9A', "\uFF9A");
+ sHalfWidthMap.put('\uFF9B', "\uFF9B");
+ sHalfWidthMap.put('\uFF9C', "\uFF9C");
+ sHalfWidthMap.put('\uFF9D', "\uFF9D");
+ sHalfWidthMap.put('\uFF9E', "\uFF9E");
+ sHalfWidthMap.put('\uFF9F', "\uFF9F");
+ sHalfWidthMap.put('\uFFE5', "\u005C\u005C");
+ }
+
+ /**
+ * Return half-width version of that character if possible. Return null if not possible
+ * @param ch input character
+ * @return CharSequence object if the mapping for ch exists. Return null otherwise.
+ */
+ public static CharSequence tryGetHalfWidthText(char ch) {
+ if (sHalfWidthMap.containsKey(ch)) {
+ return sHalfWidthMap.get(ch);
+ } else {
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/core/java/android/pim/vcard/exception/VCardException.java b/core/java/android/pim/vcard/exception/VCardException.java
new file mode 100644
index 0000000..e557219
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/VCardException.java
@@ -0,0 +1,35 @@
+/*
+ * 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.pim.vcard.exception;
+
+public class VCardException extends java.lang.Exception {
+ /**
+ * Constructs a VCardException object
+ */
+ public VCardException() {
+ super();
+ }
+
+ /**
+ * Constructs a VCardException object
+ *
+ * @param message the error message
+ */
+ public VCardException(String message) {
+ super(message);
+ }
+
+}
diff --git a/core/java/android/pim/vcard/exception/VCardNestedException.java b/core/java/android/pim/vcard/exception/VCardNestedException.java
new file mode 100644
index 0000000..503c2fb
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/VCardNestedException.java
@@ -0,0 +1,29 @@
+/*
+ * 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.pim.vcard.exception;
+
+/**
+ * VCardException thrown when VCard is nested without VCardParser's being notified.
+ */
+public class VCardNestedException extends VCardNotSupportedException {
+ public VCardNestedException() {
+ super();
+ }
+ public VCardNestedException(String message) {
+ super(message);
+ }
+}
diff --git a/core/java/android/pim/vcard/exception/VCardNotSupportedException.java b/core/java/android/pim/vcard/exception/VCardNotSupportedException.java
new file mode 100644
index 0000000..616aa77
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/VCardNotSupportedException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.pim.vcard.exception;
+
+/**
+ * The exception which tells that the input VCard is probably valid from the view of
+ * specification but not supported in the current framework for now.
+ *
+ * This is a kind of a good news from the view of development.
+ * It may be good to ask users to send a report with the VCard example
+ * for the future development.
+ */
+public class VCardNotSupportedException extends VCardException {
+ public VCardNotSupportedException() {
+ super();
+ }
+ public VCardNotSupportedException(String message) {
+ super(message);
+ }
+} \ No newline at end of file
diff --git a/core/java/android/pim/vcard/exception/VCardVersionException.java b/core/java/android/pim/vcard/exception/VCardVersionException.java
new file mode 100644
index 0000000..9fe8b7f
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/VCardVersionException.java
@@ -0,0 +1,29 @@
+/*
+ * 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.pim.vcard.exception;
+
+/**
+ * VCardException used only when the version of the vCard is different.
+ */
+public class VCardVersionException extends VCardException {
+ public VCardVersionException() {
+ super();
+ }
+ public VCardVersionException(String message) {
+ super(message);
+ }
+}
diff --git a/core/java/android/pim/vcard/exception/package.html b/core/java/android/pim/vcard/exception/package.html
new file mode 100644
index 0000000..26b8a32
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+{@hide}
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/core/java/android/pim/vcard/package.html b/core/java/android/pim/vcard/package.html
new file mode 100644
index 0000000..26b8a32
--- /dev/null
+++ b/core/java/android/pim/vcard/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+{@hide}
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/core/java/android/preference/CheckBoxPreference.java b/core/java/android/preference/CheckBoxPreference.java
index cf5664c..f16a7e4 100644
--- a/core/java/android/preference/CheckBoxPreference.java
+++ b/core/java/android/preference/CheckBoxPreference.java
@@ -149,14 +149,12 @@ public class CheckBoxPreference extends Preference {
* @param checked The checked state.
*/
public void setChecked(boolean checked) {
-
- mChecked = checked;
-
- persistBoolean(checked);
-
- notifyDependencyChange(shouldDisableDependents());
-
- notifyChanged();
+ if (mChecked != checked) {
+ mChecked = checked;
+ persistBoolean(checked);
+ notifyDependencyChange(shouldDisableDependents());
+ notifyChanged();
+ }
}
/**
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..b337d28 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -16,17 +16,21 @@
package android.preference;
+import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.ContentObserver;
+import android.media.AudioManager;
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.os.Parcel;
+import android.os.Parcelable;
import android.provider.Settings;
import android.provider.Settings.System;
import android.util.AttributeSet;
+import android.view.KeyEvent;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
@@ -35,12 +39,12 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
* @hide
*/
public class VolumePreference extends SeekBarPreference implements
- PreferenceManager.OnActivityStopListener {
+ PreferenceManager.OnActivityStopListener, View.OnKeyListener {
private static final String TAG = "VolumePreference";
private int mStreamType;
-
+
/** May be null if the dialog isn't visible. */
private SeekBarVolumizer mSeekBarVolumizer;
@@ -52,7 +56,7 @@ public class VolumePreference extends SeekBarPreference implements
mStreamType = a.getInt(android.R.styleable.VolumePreference_streamType, 0);
a.recycle();
}
-
+
public void setStreamType(int streamType) {
mStreamType = streamType;
}
@@ -63,8 +67,34 @@ public class VolumePreference extends SeekBarPreference implements
final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType);
-
+
getPreferenceManager().registerOnActivityStopListener(this);
+
+ // grab focus and key events so that pressing the volume buttons in the
+ // dialog doesn't also show the normal volume adjust toast.
+ view.setOnKeyListener(this);
+ view.setFocusableInTouchMode(true);
+ view.requestFocus();
+ }
+
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ // If key arrives immediately after the activity has been cleaned up.
+ if (mSeekBarVolumizer == null) return true;
+ boolean isdown = (event.getAction() == KeyEvent.ACTION_DOWN);
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ if (isdown) {
+ mSeekBarVolumizer.changeVolumeBy(-1);
+ }
+ return true;
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ if (isdown) {
+ mSeekBarVolumizer.changeVolumeBy(1);
+ }
+ return true;
+ default:
+ return false;
+ }
}
@Override
@@ -74,7 +104,7 @@ public class VolumePreference extends SeekBarPreference implements
if (!positiveResult && mSeekBarVolumizer != null) {
mSeekBarVolumizer.revertVolume();
}
-
+
cleanup();
}
@@ -87,19 +117,96 @@ public class VolumePreference extends SeekBarPreference implements
*/
private void cleanup() {
getPreferenceManager().unregisterOnActivityStopListener(this);
-
+
if (mSeekBarVolumizer != null) {
+ Dialog dialog = getDialog();
+ if (dialog != null && dialog.isShowing()) {
+ // Stopped while dialog was showing, revert changes
+ mSeekBarVolumizer.revertVolume();
+ }
mSeekBarVolumizer.stop();
mSeekBarVolumizer = null;
}
+
}
-
+
protected void onSampleStarting(SeekBarVolumizer volumizer) {
if (mSeekBarVolumizer != null && volumizer != mSeekBarVolumizer) {
mSeekBarVolumizer.stopSample();
}
}
-
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state since it's persistent
+ return superState;
+ }
+
+ final SavedState myState = new SavedState(superState);
+ if (mSeekBarVolumizer != null) {
+ mSeekBarVolumizer.onSaveInstanceState(myState.getVolumeStore());
+ }
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ if (mSeekBarVolumizer != null) {
+ mSeekBarVolumizer.onRestoreInstanceState(myState.getVolumeStore());
+ }
+ }
+
+ public static class VolumeStore {
+ public int volume = -1;
+ public int originalVolume = -1;
+ }
+
+ private static class SavedState extends BaseSavedState {
+ VolumeStore mVolumeStore = new VolumeStore();
+
+ public SavedState(Parcel source) {
+ super(source);
+ mVolumeStore.volume = source.readInt();
+ mVolumeStore.originalVolume = source.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(mVolumeStore.volume);
+ dest.writeInt(mVolumeStore.originalVolume);
+ }
+
+ VolumeStore getVolumeStore() {
+ return mVolumeStore;
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
/**
* Turns a {@link SeekBar} into a volume control.
*/
@@ -113,7 +220,7 @@ public class VolumePreference extends SeekBarPreference implements
private int mOriginalStreamVolume;
private Ringtone mRingtone;
- private int mLastProgress;
+ private int mLastProgress = -1;
private SeekBar mSeekBar;
private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
@@ -127,7 +234,7 @@ public class VolumePreference extends SeekBarPreference implements
}
}
};
-
+
public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType) {
mContext = context;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -147,11 +254,19 @@ 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);
- mRingtone.setStreamType(mStreamType);
+ 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);
+ if (mRingtone != null) {
+ mRingtone.setStreamType(mStreamType);
+ }
}
public void stop() {
@@ -173,7 +288,7 @@ public class VolumePreference extends SeekBarPreference implements
postSetVolume(progress);
}
- private void postSetVolume(int progress) {
+ void postSetVolume(int progress) {
// Do the volume changing separately to give responsive UI
mLastProgress = progress;
mHandler.removeCallbacks(this);
@@ -208,5 +323,27 @@ public class VolumePreference extends SeekBarPreference implements
return mSeekBar;
}
+ public void changeVolumeBy(int amount) {
+ mSeekBar.incrementProgressBy(amount);
+ if (mRingtone != null && !mRingtone.isPlaying()) {
+ sample();
+ }
+ postSetVolume(mSeekBar.getProgress());
+ }
+
+ public void onSaveInstanceState(VolumeStore volumeStore) {
+ if (mLastProgress >= 0) {
+ volumeStore.volume = mLastProgress;
+ volumeStore.originalVolume = mOriginalStreamVolume;
+ }
+ }
+
+ public void onRestoreInstanceState(VolumeStore volumeStore) {
+ if (volumeStore.volume != -1) {
+ mOriginalStreamVolume = volumeStore.originalVolume;
+ mLastProgress = volumeStore.volume;
+ postSetVolume(mLastProgress);
+ }
+ }
}
}
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 1ba5e25..92bc814 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -107,7 +107,8 @@ public class Browser {
public static final String[] HISTORY_PROJECTION = new String[] {
BookmarkColumns._ID, BookmarkColumns.URL, BookmarkColumns.VISITS,
BookmarkColumns.DATE, BookmarkColumns.BOOKMARK, BookmarkColumns.TITLE,
- BookmarkColumns.FAVICON };
+ BookmarkColumns.FAVICON, BookmarkColumns.THUMBNAIL,
+ BookmarkColumns.TOUCH_ICON };
/* these indices dependent on HISTORY_PROJECTION */
public static final int HISTORY_PROJECTION_ID_INDEX = 0;
@@ -117,6 +118,14 @@ public class Browser {
public static final int HISTORY_PROJECTION_BOOKMARK_INDEX = 4;
public static final int HISTORY_PROJECTION_TITLE_INDEX = 5;
public static final int HISTORY_PROJECTION_FAVICON_INDEX = 6;
+ /**
+ * @hide
+ */
+ public static final int HISTORY_PROJECTION_THUMBNAIL_INDEX = 7;
+ /**
+ * @hide
+ */
+ public static final int HISTORY_PROJECTION_TOUCH_ICON_INDEX = 8;
/* columns needed to determine whether to truncate history */
public static final String[] TRUNCATE_HISTORY_PROJECTION = new String[] {
@@ -513,6 +522,14 @@ public class Browser {
public static final String TITLE = "title";
public static final String CREATED = "created";
public static final String FAVICON = "favicon";
+ /**
+ * @hide
+ */
+ public static final String THUMBNAIL = "thumbnail";
+ /**
+ * @hide
+ */
+ public static final String TOUCH_ICON = "touch_icon";
}
public static class SearchColumns implements BaseColumns {
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 4a709f6..d57155c 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;
@@ -80,6 +81,11 @@ public final class Calendar {
public interface CalendarsColumns
{
/**
+ * A string that uniquely identifies this contact to its source
+ */
+ public static final String SOURCE_ID = "sourceid";
+
+ /**
* The color of the calendar
* <P>Type: INTEGER (color value)</P>
*/
@@ -124,6 +130,12 @@ public final class Calendar {
* <p>Type: INTEGER (boolean)</p>
*/
public static final String SYNC_EVENTS = "sync_events";
+
+ /**
+ * Sync state data.
+ * <p>Type: String (blob)</p>
+ */
+ public static final String SYNC_STATE = "sync_state";
}
/**
@@ -157,11 +169,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.name, account.type});
}
/**
@@ -170,9 +183,6 @@ public final class Calendar {
public static final Uri CONTENT_URI =
Uri.parse("content://calendar/calendars");
- public static final Uri LIVE_CONTENT_URI =
- Uri.parse("content://calendar/calendars?update=1");
-
/**
* The default sort order for this table
*/
@@ -207,6 +217,13 @@ public final class Calendar {
* <P>Type: INTEGER (boolean)</P>
*/
public static final String HIDDEN = "hidden";
+
+ /**
+ * The owner account for this calendar, based on the calendar feed.
+ * This will be different from the _SYNC_ACCOUNT for delegated calendars.
+ * <P>Type: String</P>
+ */
+ public static final String OWNER_ACCOUNT = "ownerAccount";
}
public interface AttendeesColumns {
@@ -448,6 +465,47 @@ public final class Calendar {
* <P>Type: INTEGER (long; millis since epoch)</P>
*/
public static final String LAST_DATE = "lastDate";
+
+ /**
+ * Whether the event has attendee information. True if the event
+ * has full attendee data, false if the event has information about
+ * self only.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String HAS_ATTENDEE_DATA = "hasAttendeeData";
+
+ /**
+ * Whether guests can modify the event.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String GUESTS_CAN_MODIFY = "guestsCanModify";
+
+ /**
+ * Whether guests can invite other guests.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String GUESTS_CAN_INVITE_OTHERS = "guestsCanInviteOthers";
+
+ /**
+ * Whether guests can see the list of attendees.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String GUESTS_CAN_SEE_GUESTS = "guestsCanSeeGuests";
+
+ /**
+ * Email of the organizer (owner) of the event.
+ * <P>Type: STRING</P>
+ */
+ public static final String ORGANIZER = "organizer";
+
+ /**
+ * Whether the user can invite others to the event.
+ * The GUESTS_CAN_INVITE_OTHERS is a setting that applies to an arbitrary guest,
+ * while CAN_INVITE_OTHERS indicates if the user can invite others (either through
+ * GUESTS_CAN_INVITE_OTHERS or because the user has modify access to the event).
+ * <P>Type: INTEGER (boolean, readonly)</P>
+ */
+ public static final String CAN_INVITE_OTHERS = "canInviteOthers";
}
/**
@@ -694,6 +752,8 @@ public final class Calendar {
* The content:// style URL for this table
*/
public static final Uri CONTENT_URI = Uri.parse("content://calendar/instances/when");
+ public static final Uri CONTENT_BY_DAY_URI =
+ Uri.parse("content://calendar/instances/whenbyday");
/**
* The default sort order for this table.
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index afe219c..b54ad5d 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -73,7 +73,7 @@ public class CallLog {
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
/**
- * The type of the the phone number.
+ * The type of the call (incoming, outgoing or missed).
* <P>Type: INTEGER (int)</P>
*/
public static final String TYPE = "type";
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 84fe184..181a529 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -22,11 +22,11 @@ import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
+import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
@@ -37,26 +37,34 @@ import java.io.InputStream;
/**
* The Contacts provider stores all information about contacts.
*/
+@Deprecated
public class Contacts {
private static final String TAG = "Contacts";
-
+
+ @Deprecated
public static final String AUTHORITY = "contacts";
/**
* The content:// style URL for this provider
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://" + AUTHORITY);
/** Signifies an email address row that is stored in the ContactMethods table */
+ @Deprecated
public static final int KIND_EMAIL = 1;
/** Signifies a postal address row that is stored in the ContactMethods table */
+ @Deprecated
public static final int KIND_POSTAL = 2;
/** Signifies an IM address row that is stored in the ContactMethods table */
+ @Deprecated
public static final int KIND_IM = 3;
/** Signifies an Organization row that is stored in the Organizations table */
+ @Deprecated
public static final int KIND_ORGANIZATION = 4;
/** Signifies an Phone row that is stored in the Phones table */
+ @Deprecated
public static final int KIND_PHONE = 5;
/**
@@ -67,29 +75,41 @@ public class Contacts {
/**
* Columns from the Settings table that other columns join into themselves.
*/
+ @Deprecated
public interface SettingsColumns {
/**
* The _SYNC_ACCOUNT to which this setting corresponds. This may be null.
* <P>Type: TEXT</P>
*/
+ @Deprecated
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>
+ */
+ @Deprecated
+ public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
+
+ /**
* The key of this setting.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String KEY = "key";
/**
* The value of this setting.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String VALUE = "value";
}
/**
* The settings over all of the people
*/
+ @Deprecated
public static final class Settings implements BaseColumns, SettingsColumns {
/**
* no public constructor since this is a utility class
@@ -99,17 +119,20 @@ public class Contacts {
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/settings");
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "settings";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "key ASC";
/**
@@ -121,8 +144,10 @@ public class Contacts {
* This is a boolean setting. It is true if it is set and it is anything other than the
* emptry string or "0".
*/
+ @Deprecated
public static final String SYNC_EVERYTHING = "syncEverything";
+ @Deprecated
public static String getSetting(ContentResolver cr, String account, String key) {
// For now we only support a single account and the UI doesn't know what
// the account name is, so we're using a global setting for SYNC_EVERYTHING.
@@ -134,6 +159,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};
@@ -151,6 +177,7 @@ public class Contacts {
}
}
+ @Deprecated
public static void setSetting(ContentResolver cr, String account, String key,
String value) {
ContentValues values = new ContentValues();
@@ -158,7 +185,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);
@@ -168,11 +196,13 @@ public class Contacts {
/**
* Columns from the People table that other tables join into themselves.
*/
+ @Deprecated
public interface PeopleColumns {
/**
* The person's name.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NAME = "name";
/**
@@ -181,13 +211,15 @@ public class Contacts {
* Used for pronunciation and/or collation in some languages.
* <p>Type: TEXT</P>
*/
+ @Deprecated
public static final String PHONETIC_NAME = "phonetic_name";
-
+
/**
* The display name. If name is not null name, else if number is not null number,
* else if email is not null email.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String DISPLAY_NAME = "display_name";
/**
@@ -196,30 +228,35 @@ public class Contacts {
* <P>Type: TEXT</p>
* @hide Used only in Contacts application for now.
*/
+ @Deprecated
public static final String SORT_STRING = "sort_string";
-
+
/**
* Notes about the person.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NOTES = "notes";
/**
* The number of times a person has been contacted
* <P>Type: INTEGER</P>
*/
+ @Deprecated
public static final String TIMES_CONTACTED = "times_contacted";
/**
* The last time a person was contacted.
* <P>Type: INTEGER</P>
*/
+ @Deprecated
public static final String LAST_TIME_CONTACTED = "last_time_contacted";
/**
* A custom ringtone associated with a person. Not always present.
* <P>Type: TEXT (URI to the ringtone)</P>
*/
+ @Deprecated
public static final String CUSTOM_RINGTONE = "custom_ringtone";
/**
@@ -227,24 +264,28 @@ public class Contacts {
* present.
* <P>Type: INTEGER (0 for false, 1 for true)</P>
*/
+ @Deprecated
public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
/**
* Is the contact starred?
* <P>Type: INTEGER (boolean)</P>
*/
+ @Deprecated
public static final String STARRED = "starred";
/**
* The server version of the photo
* <P>Type: TEXT (the version number portion of the photo URI)</P>
*/
- public static final String PHOTO_VERSION = "photo_version";
+ @Deprecated
+ public static final String PHOTO_VERSION = "photo_version";
}
/**
* This table contains people.
*/
+ @Deprecated
public static final class People implements BaseColumns, SyncConstValue, PeopleColumns,
PhonesColumns, PresenceColumns {
/**
@@ -255,6 +296,7 @@ public class Contacts {
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/people");
@@ -262,6 +304,7 @@ public class Contacts {
* The content:// style URL for filtering people by name. The filter
* argument should be passed as an additional path segment after this URI.
*/
+ @Deprecated
public static final Uri CONTENT_FILTER_URI =
Uri.parse("content://contacts/people/filter");
@@ -269,6 +312,7 @@ public class Contacts {
* The content:// style URL for the table that holds the deleted
* contacts.
*/
+ @Deprecated
public static final Uri DELETED_CONTENT_URI =
Uri.parse("content://contacts/deleted_people");
@@ -278,35 +322,40 @@ public class Contacts {
* additional path segment after this URI. This matches any people with
* at least one E-mail or IM {@link ContactMethods} that match the
* filter.
- *
+ *
* Not exposed because we expect significant changes in the contacts
* schema and do not want to have to support this.
* @hide
*/
+ @Deprecated
public static final Uri WITH_EMAIL_OR_IM_FILTER_URI =
Uri.parse("content://contacts/people/with_email_or_im_filter");
-
+
/**
* The MIME type of {@link #CONTENT_URI} providing a directory of
* people.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* person.
*/
+ @Deprecated
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = People.NAME + " ASC";
/**
* The ID of the persons preferred phone number.
* <P>Type: INTEGER (foreign key to phones table on the _ID field)</P>
*/
+ @Deprecated
public static final String PRIMARY_PHONE_ID = "primary_phone";
/**
@@ -314,6 +363,7 @@ public class Contacts {
* <P>Type: INTEGER (foreign key to contact_methods table on the
* _ID field)</P>
*/
+ @Deprecated
public static final String PRIMARY_EMAIL_ID = "primary_email";
/**
@@ -321,6 +371,7 @@ public class Contacts {
* <P>Type: INTEGER (foreign key to organizations table on the
* _ID field)</P>
*/
+ @Deprecated
public static final String PRIMARY_ORGANIZATION_ID = "primary_organization";
/**
@@ -329,6 +380,7 @@ public class Contacts {
* @param resolver the ContentResolver to use
* @param personId the person who was contacted
*/
+ @Deprecated
public static void markAsContacted(ContentResolver resolver, long personId) {
Uri uri = ContentUris.withAppendedId(CONTENT_URI, personId);
uri = Uri.withAppendedPath(uri, "update_contact_time");
@@ -342,6 +394,7 @@ public class Contacts {
/**
* @hide Used in vCard parser code.
*/
+ @Deprecated
public static long tryGetMyContactsGroupId(ContentResolver resolver) {
Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION,
Groups.SYSTEM_ID + "='" + Groups.GROUP_MY_CONTACTS + "'", null, null);
@@ -365,24 +418,26 @@ public class Contacts {
* @return the URI of the group membership row
* @throws IllegalStateException if the My Contacts group can't be found
*/
+ @Deprecated
public static Uri addToMyContactsGroup(ContentResolver resolver, long personId) {
long groupId = tryGetMyContactsGroupId(resolver);
if (groupId == 0) {
throw new IllegalStateException("Failed to find the My Contacts group");
}
-
+
return addToGroup(resolver, personId, groupId);
}
/**
* Adds a person to a group referred to by name.
- *
+ *
* @param resolver the resolver to use
* @param personId the person to add to the group
* @param groupName the name of the group to add the contact to
* @return the URI of the group membership row
* @throws IllegalStateException if the group can't be found
*/
+ @Deprecated
public static Uri addToGroup(ContentResolver resolver, long personId, String groupName) {
long groupId = 0;
Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION,
@@ -400,36 +455,38 @@ public class Contacts {
if (groupId == 0) {
throw new IllegalStateException("Failed to find the My Contacts group");
}
-
+
return addToGroup(resolver, personId, groupId);
}
/**
* Adds a person to a group.
- *
+ *
* @param resolver the resolver to use
* @param personId the person to add to the group
* @param groupId the group to add the person to
* @return the URI of the group membership row
*/
+ @Deprecated
public static Uri addToGroup(ContentResolver resolver, long personId, long groupId) {
ContentValues values = new ContentValues();
values.put(GroupMembership.PERSON_ID, personId);
values.put(GroupMembership.GROUP_ID, groupId);
return resolver.insert(GroupMembership.CONTENT_URI, values);
}
-
+
private static final String[] GROUPS_PROJECTION = new String[] {
Groups._ID,
};
/**
* Creates a new contacts and adds it to the "My Contacts" group.
- *
+ *
* @param resolver the ContentResolver to use
* @param values the values to use when creating the contact
* @return the URI of the contact, or null if the operation fails
*/
+ @Deprecated
public static Uri createPersonInMyContactsGroup(ContentResolver resolver,
ContentValues values) {
@@ -446,6 +503,7 @@ public class Contacts {
return contactUri;
}
+ @Deprecated
public static Cursor queryGroups(ContentResolver resolver, long person) {
return resolver.query(GroupMembership.CONTENT_URI, null, "person=?",
new String[]{String.valueOf(person)}, Groups.DEFAULT_SORT_ORDER);
@@ -457,18 +515,20 @@ public class Contacts {
* @param person the Uri of the person whose photo is to be updated
* @param data the byte[] that represents the photo
*/
+ @Deprecated
public static void setPhotoData(ContentResolver cr, Uri person, byte[] data) {
Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
ContentValues values = new ContentValues();
values.put(Photos.DATA, data);
cr.update(photoUri, values, null, null);
}
-
+
/**
* Opens an InputStream for the person's photo and returns the photo as a Bitmap.
* If the person's photo isn't present returns the placeholderImageResource instead.
* @param person the person whose photo should be used
*/
+ @Deprecated
public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri person) {
Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
Cursor cursor = cr.query(photoUri, new String[]{Photos.DATA}, null, null, null);
@@ -495,6 +555,7 @@ public class Contacts {
* have a photo
* @param options the decoding options, can be set to null
*/
+ @Deprecated
public static Bitmap loadContactPhoto(Context context, Uri person,
int placeholderImageResource, BitmapFactory.Options options) {
if (person == null) {
@@ -521,6 +582,7 @@ public class Contacts {
/**
* A sub directory of a single person that contains all of their Phones.
*/
+ @Deprecated
public static final class Phones implements BaseColumns, PhonesColumns,
PeopleColumns {
/**
@@ -531,11 +593,13 @@ public class Contacts {
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "phones";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "number ASC";
}
@@ -543,6 +607,7 @@ public class Contacts {
* A subdirectory of a single person that contains all of their
* ContactMethods.
*/
+ @Deprecated
public static final class ContactMethods
implements BaseColumns, ContactMethodsColumns, PeopleColumns {
/**
@@ -553,17 +618,20 @@ public class Contacts {
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "contact_methods";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "data ASC";
}
/**
* The extensions for a person
*/
+ @Deprecated
public static class Extensions implements BaseColumns, ExtensionsColumns {
/**
* no public constructor since this is a utility class
@@ -573,17 +641,20 @@ public class Contacts {
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "extensions";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "name ASC";
/**
* The ID of the person this phone number is assigned to.
* <P>Type: INTEGER (long)</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
}
}
@@ -591,17 +662,20 @@ public class Contacts {
/**
* Columns from the groups table.
*/
+ @Deprecated
public interface GroupsColumns {
/**
* The group name.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NAME = "name";
/**
* Notes about the group.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NOTES = "notes";
/**
@@ -609,18 +683,21 @@ public class Contacts {
* for this group's account.
* <P>Type: INTEGER (boolean)</P>
*/
+ @Deprecated
public static final String SHOULD_SYNC = "should_sync";
/**
* The ID of this group if it is a System Group, null otherwise.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String SYSTEM_ID = "system_id";
}
/**
* This table contains the groups for an account.
*/
+ @Deprecated
public static final class Groups
implements BaseColumns, SyncConstValue, GroupsColumns {
/**
@@ -631,6 +708,7 @@ public class Contacts {
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/groups");
@@ -638,6 +716,7 @@ public class Contacts {
* The content:// style URL for the table that holds the deleted
* groups.
*/
+ @Deprecated
public static final Uri DELETED_CONTENT_URI =
Uri.parse("content://contacts/deleted_groups");
@@ -645,71 +724,90 @@ public class Contacts {
* The MIME type of {@link #CONTENT_URI} providing a directory of
* groups.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroup";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* group.
*/
+ @Deprecated
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroup";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = NAME + " ASC";
/**
*
*/
+ @Deprecated
public static final String GROUP_ANDROID_STARRED = "Starred in Android";
/**
* The "My Contacts" system group.
*/
+ @Deprecated
public static final String GROUP_MY_CONTACTS = "Contacts";
}
/**
* Columns from the Phones table that other columns join into themselves.
*/
+ @Deprecated
public interface PhonesColumns {
/**
* The type of the the phone number.
* <P>Type: INTEGER (one of the constants below)</P>
*/
+ @Deprecated
public static final String TYPE = "type";
+ @Deprecated
public static final int TYPE_CUSTOM = 0;
+ @Deprecated
public static final int TYPE_HOME = 1;
+ @Deprecated
public static final int TYPE_MOBILE = 2;
+ @Deprecated
public static final int TYPE_WORK = 3;
+ @Deprecated
public static final int TYPE_FAX_WORK = 4;
+ @Deprecated
public static final int TYPE_FAX_HOME = 5;
+ @Deprecated
public static final int TYPE_PAGER = 6;
+ @Deprecated
public static final int TYPE_OTHER = 7;
/**
* The user provided label for the phone number, only used if TYPE is TYPE_CUSTOM.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String LABEL = "label";
/**
* The phone number as the user entered it.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NUMBER = "number";
/**
* The normalized phone number
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NUMBER_KEY = "number_key";
/**
* Whether this is the primary phone number
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
+ @Deprecated
public static final String ISPRIMARY = "isprimary";
}
@@ -718,6 +816,7 @@ public class Contacts {
* contact method belongs to. Phone numbers are stored separately from
* other contact methods to make caller ID lookup more efficient.
*/
+ @Deprecated
public static final class Phones
implements BaseColumns, PhonesColumns, PeopleColumns {
/**
@@ -725,12 +824,13 @@ public class Contacts {
*/
private Phones() {}
+ @Deprecated
public static final CharSequence getDisplayLabel(Context context, int type,
CharSequence label, CharSequence[] labelArray) {
CharSequence display = "";
if (type != People.Phones.TYPE_CUSTOM) {
- CharSequence[] labels = labelArray != null? labelArray
+ CharSequence[] labels = labelArray != null? labelArray
: context.getResources().getTextArray(
com.android.internal.R.array.phoneTypes);
try {
@@ -746,20 +846,23 @@ public class Contacts {
return display;
}
+ @Deprecated
public static final CharSequence getDisplayLabel(Context context, int type,
CharSequence label) {
return getDisplayLabel(context, type, label, null);
}
-
+
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/phones");
/**
* The content:// style URL for filtering phone numbers
*/
+ @Deprecated
public static final Uri CONTENT_FILTER_URL =
Uri.parse("content://contacts/phones/filter");
@@ -767,26 +870,31 @@ public class Contacts {
* The MIME type of {@link #CONTENT_URI} providing a directory of
* phones.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* phone.
*/
+ @Deprecated
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "name ASC";
/**
* The ID of the person this phone number is assigned to.
* <P>Type: INTEGER (long)</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
}
+ @Deprecated
public static final class GroupMembership implements BaseColumns, GroupsColumns {
/**
* no public constructor since this is a utility class
@@ -796,59 +904,77 @@ public class Contacts {
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/groupmembership");
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri RAW_CONTENT_URI =
Uri.parse("content://contacts/groupmembershipraw");
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "groupmembership";
+
/**
* The MIME type of {@link #CONTENT_URI} providing a directory of all
* person groups.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroupmembership";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* person group.
*/
+ @Deprecated
public static final String CONTENT_ITEM_TYPE =
"vnd.android.cursor.item/contactsgroupmembership";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "group_id ASC";
/**
* The row id of the accounts group.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String GROUP_ID = "group_id";
/**
* The sync id of the group.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String GROUP_SYNC_ID = "group_sync_id";
/**
* The account of the group.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String GROUP_SYNC_ACCOUNT = "group_sync_account";
/**
+ * The account type of the group.
+ * <P>Type: TEXT</P>
+ */
+ @Deprecated
+ public static final String GROUP_SYNC_ACCOUNT_TYPE = "group_sync_account_type";
+
+ /**
* The row id of the person.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
}
@@ -856,57 +982,70 @@ public class Contacts {
* Columns from the ContactMethods table that other tables join into
* themseleves.
*/
+ @Deprecated
public interface ContactMethodsColumns {
/**
* The kind of the the contact method. For example, email address,
* postal address, etc.
* <P>Type: INTEGER (one of the values below)</P>
*/
+ @Deprecated
public static final String KIND = "kind";
/**
* The type of the contact method, must be one of the types below.
* <P>Type: INTEGER (one of the values below)</P>
*/
+ @Deprecated
public static final String TYPE = "type";
+ @Deprecated
public static final int TYPE_CUSTOM = 0;
+ @Deprecated
public static final int TYPE_HOME = 1;
+ @Deprecated
public static final int TYPE_WORK = 2;
+ @Deprecated
public static final int TYPE_OTHER = 3;
/**
* @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future.
*/
+ @Deprecated
public static final int MOBILE_EMAIL_TYPE_INDEX = 2;
/**
* @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future.
* This is not "mobile" but "CELL" since vCard uses it for identifying mobile phone.
*/
+ @Deprecated
public static final String MOBILE_EMAIL_TYPE_NAME = "_AUTO_CELL";
/**
* The user defined label for the the contact method.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String LABEL = "label";
/**
* The data for the contact method.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String DATA = "data";
/**
* Auxiliary data for the contact method.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String AUX_DATA = "aux_data";
/**
* Whether this is the primary organization
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
+ @Deprecated
public static final String ISPRIMARY = "isprimary";
}
@@ -914,18 +1053,21 @@ public class Contacts {
* This table stores all non-phone contact methods and a reference to the
* person that the contact method belongs to.
*/
+ @Deprecated
public static final class ContactMethods
implements BaseColumns, ContactMethodsColumns, PeopleColumns {
/**
* The column with latitude data for postal locations
* <P>Type: REAL</P>
*/
+ @Deprecated
public static final String POSTAL_LOCATION_LATITUDE = DATA;
/**
* The column with longitude data for postal locations
* <P>Type: REAL</P>
*/
+ @Deprecated
public static final String POSTAL_LOCATION_LONGITUDE = AUX_DATA;
/**
@@ -936,23 +1078,34 @@ public class Contacts {
* - pre:<an integer, one of the protocols below>
* - custom:<a string>
*/
+ @Deprecated
public static final int PROTOCOL_AIM = 0;
+ @Deprecated
public static final int PROTOCOL_MSN = 1;
+ @Deprecated
public static final int PROTOCOL_YAHOO = 2;
+ @Deprecated
public static final int PROTOCOL_SKYPE = 3;
+ @Deprecated
public static final int PROTOCOL_QQ = 4;
+ @Deprecated
public static final int PROTOCOL_GOOGLE_TALK = 5;
+ @Deprecated
public static final int PROTOCOL_ICQ = 6;
+ @Deprecated
public static final int PROTOCOL_JABBER = 7;
+ @Deprecated
public static String encodePredefinedImProtocol(int protocol) {
return "pre:" + protocol;
}
+ @Deprecated
public static String encodeCustomImProtocol(String protocolString) {
return "custom:" + protocolString;
}
+ @Deprecated
public static Object decodeImProtocol(String encodedString) {
if (encodedString == null) {
return null;
@@ -969,7 +1122,7 @@ public class Contacts {
throw new IllegalArgumentException(
"the value is not a valid encoded protocol, " + encodedString);
}
-
+
/**
* This looks up the provider name defined in
* {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
@@ -980,6 +1133,7 @@ public class Contacts {
* provider is defined for the given protocol
* @hide
*/
+ @Deprecated
public static String lookupProviderNameFromId(int protocol) {
switch (protocol) {
case PROTOCOL_GOOGLE_TALK:
@@ -1007,6 +1161,7 @@ public class Contacts {
*/
private ContactMethods() {}
+ @Deprecated
public static final CharSequence getDisplayLabel(Context context, int kind,
int type, CharSequence label) {
CharSequence display = "";
@@ -1022,13 +1177,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;
@@ -1065,6 +1214,7 @@ public class Contacts {
* @param latitude the latitude for the address
* @param longitude the longitude for the address
*/
+ @Deprecated
public void addPostalLocation(Context context, long postalId,
double latitude, double longitude) {
final ContentResolver resolver = context.getContentResolver();
@@ -1084,12 +1234,14 @@ public class Contacts {
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/contact_methods");
/**
* The content:// style URL for sub-directory of e-mail addresses.
*/
+ @Deprecated
public static final Uri CONTENT_EMAIL_URI =
Uri.parse("content://contacts/contact_methods/email");
@@ -1097,30 +1249,35 @@ public class Contacts {
* The MIME type of {@link #CONTENT_URI} providing a directory of
* phones.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact-methods";
/**
* The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\
* multiple {@link Contacts#KIND_EMAIL} entries.
*/
+ @Deprecated
public static final String CONTENT_EMAIL_TYPE = "vnd.android.cursor.dir/email";
/**
* The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\
* multiple {@link Contacts#KIND_POSTAL} entries.
*/
+ @Deprecated
public static final String CONTENT_POSTAL_TYPE = "vnd.android.cursor.dir/postal-address";
/**
* The MIME type of a {@link #CONTENT_URI} sub-directory of a single
* {@link Contacts#KIND_EMAIL} entry.
*/
+ @Deprecated
public static final String CONTENT_EMAIL_ITEM_TYPE = "vnd.android.cursor.item/email";
/**
* The MIME type of a {@link #CONTENT_URI} sub-directory of a single
* {@link Contacts#KIND_POSTAL} entry.
*/
+ @Deprecated
public static final String CONTENT_POSTAL_ITEM_TYPE
= "vnd.android.cursor.item/postal-address";
@@ -1128,23 +1285,27 @@ public class Contacts {
* The MIME type of a {@link #CONTENT_URI} sub-directory of a single
* {@link Contacts#KIND_IM} entry.
*/
+ @Deprecated
public static final String CONTENT_IM_ITEM_TYPE = "vnd.android.cursor.item/jabber-im";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "name ASC";
/**
* The ID of the person this contact method is assigned to.
* <P>Type: INTEGER (long)</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
}
/**
* The IM presence columns with some contacts specific columns mixed in.
*/
+ @Deprecated
public interface PresenceColumns extends Im.CommonPresenceColumns {
/**
* The IM service the presence is coming from. Formatted using either
@@ -1152,6 +1313,7 @@ public class Contacts {
* {@link Contacts.ContactMethods#encodeCustomImProtocol}.
* <P>Type: STRING</P>
*/
+ @Deprecated
public static final String IM_PROTOCOL = "im_protocol";
/**
@@ -1159,12 +1321,14 @@ public class Contacts {
* the {@link #IM_PROTOCOL}.
* <P>Type: STRING</P>
*/
+ @Deprecated
public static final String IM_HANDLE = "im_handle";
/**
* The IM account for the local user that the presence data came from.
* <P>Type: STRING</P>
*/
+ @Deprecated
public static final String IM_ACCOUNT = "im_account";
}
@@ -1172,11 +1336,13 @@ public class Contacts {
* Contains presence information about contacts.
* @hide
*/
+ @Deprecated
public static final class Presence
implements BaseColumns, PresenceColumns, PeopleColumns {
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/presence");
@@ -1184,29 +1350,31 @@ public class Contacts {
* The ID of the person this presence item is assigned to.
* <P>Type: INTEGER (long)</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
/**
* Gets the resource ID for the proper presence icon.
- *
+ *
* @param status the status to get the icon for
* @return the resource ID for the proper presence icon
*/
+ @Deprecated
public static final int getPresenceIconResourceId(int status) {
switch (status) {
case Contacts.People.AVAILABLE:
return com.android.internal.R.drawable.presence_online;
-
+
case Contacts.People.IDLE:
case Contacts.People.AWAY:
return com.android.internal.R.drawable.presence_away;
-
+
case Contacts.People.DO_NOT_DISTURB:
return com.android.internal.R.drawable.presence_busy;
-
+
case Contacts.People.INVISIBLE:
return com.android.internal.R.drawable.presence_invisible;
-
+
case Contacts.People.OFFLINE:
default:
return com.android.internal.R.drawable.presence_offline;
@@ -1219,6 +1387,7 @@ public class Contacts {
* @param icon the icon to to set
* @param serverStatus that status
*/
+ @Deprecated
public static final void setPresenceIcon(ImageView icon, int serverStatus) {
icon.setImageResource(getPresenceIconResourceId(serverStatus));
}
@@ -1227,57 +1396,69 @@ public class Contacts {
/**
* Columns from the Organizations table that other columns join into themselves.
*/
+ @Deprecated
public interface OrganizationColumns {
/**
- * The type of the the phone number.
+ * The type of the organizations.
* <P>Type: INTEGER (one of the constants below)</P>
*/
+ @Deprecated
public static final String TYPE = "type";
+ @Deprecated
public static final int TYPE_CUSTOM = 0;
+ @Deprecated
public static final int TYPE_WORK = 1;
+ @Deprecated
public static final int TYPE_OTHER = 2;
/**
* The user provided label, only used if TYPE is TYPE_CUSTOM.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String LABEL = "label";
/**
* The name of the company for this organization.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String COMPANY = "company";
/**
* The title within this organization.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String TITLE = "title";
/**
* The person this organization is tied to.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
/**
* Whether this is the primary organization
* <P>Type: INTEGER (if set, non-0 means true)</P>
*/
+ @Deprecated
public static final String ISPRIMARY = "isprimary";
}
/**
* A sub directory of a single person that contains all of their Phones.
*/
+ @Deprecated
public static final class Organizations implements BaseColumns, OrganizationColumns {
/**
* no public constructor since this is a utility class
*/
private Organizations() {}
+ @Deprecated
public static final CharSequence getDisplayLabel(Context context, int type,
CharSequence label) {
CharSequence display = "";
@@ -1301,34 +1482,40 @@ public class Contacts {
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/organizations");
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "organizations";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "company, title, isprimary ASC";
}
/**
* Columns from the Photos table that other columns join into themselves.
*/
+ @Deprecated
public interface PhotosColumns {
/**
* The _SYNC_VERSION of the photo that was last downloaded
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String LOCAL_VERSION = "local_version";
/**
* The person this photo is associated with.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
/**
@@ -1336,12 +1523,14 @@ public class Contacts {
* You must specify this in the columns in order to use it in the where clause.
* <P>Type: INTEGER(boolean)</P>
*/
+ @Deprecated
public static final String DOWNLOAD_REQUIRED = "download_required";
/**
* non-zero if this photo is known to exist on the server
* <P>Type: INTEGER(boolean)</P>
*/
+ @Deprecated
public static final String EXISTS_ON_SERVER = "exists_on_server";
/**
@@ -1349,12 +1538,14 @@ public class Contacts {
* the previous attempt. If null then the previous attempt succeeded.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String SYNC_ERROR = "sync_error";
/**
* The image data, or null if there is no image.
* <P>Type: BLOB</P>
*/
+ @Deprecated
public static final String DATA = "data";
}
@@ -1362,6 +1553,7 @@ public class Contacts {
/**
* The photos over all of the people
*/
+ @Deprecated
public static final class Photos implements BaseColumns, PhotosColumns, SyncConstValue {
/**
* no public constructor since this is a utility class
@@ -1371,37 +1563,44 @@ public class Contacts {
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/photos");
/**
* The directory twig for this sub-table
*/
+ @Deprecated
public static final String CONTENT_DIRECTORY = "photo";
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "person ASC";
}
+ @Deprecated
public interface ExtensionsColumns {
/**
* The name of this extension. May not be null. There may be at most one row for each name.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String NAME = "name";
/**
* The value of this extension. May not be null.
* <P>Type: TEXT</P>
*/
+ @Deprecated
public static final String VALUE = "value";
}
/**
* The extensions for a person
*/
+ @Deprecated
public static final class Extensions implements BaseColumns, ExtensionsColumns {
/**
* no public constructor since this is a utility class
@@ -1411,6 +1610,7 @@ public class Contacts {
/**
* The content:// style URL for this table
*/
+ @Deprecated
public static final Uri CONTENT_URI =
Uri.parse("content://contacts/extensions");
@@ -1418,22 +1618,27 @@ public class Contacts {
* The MIME type of {@link #CONTENT_URI} providing a directory of
* phones.
*/
+ @Deprecated
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_extensions";
/**
* The MIME type of a {@link #CONTENT_URI} subdirectory of a single
* phone.
*/
+ @Deprecated
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_extensions";
+
/**
* The default sort order for this table
*/
+ @Deprecated
public static final String DEFAULT_SORT_ORDER = "person, name ASC";
/**
* The ID of the person this phone number is assigned to.
* <P>Type: INTEGER (long)</P>
*/
+ @Deprecated
public static final String PERSON_ID = "person";
}
@@ -1441,33 +1646,41 @@ public class Contacts {
* Contains helper classes used to create or manage {@link android.content.Intent Intents}
* that involve contacts.
*/
+ @Deprecated
public static final class Intents {
+ @Deprecated
+ public Intents() {
+ }
+
/**
* This is the intent that is fired when a search suggestion is clicked on.
*/
+ @Deprecated
public static final String SEARCH_SUGGESTION_CLICKED =
- "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
+ ContactsContract.Intents.SEARCH_SUGGESTION_CLICKED;
/**
- * This is the intent that is fired when a search suggestion for dialing a number
+ * This is the intent that is fired when a search suggestion for dialing a number
* is clicked on.
*/
+ @Deprecated
public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
- "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
+ ContactsContract.Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED;
/**
* This is the intent that is fired when a search suggestion for creating a contact
* is clicked on.
*/
+ @Deprecated
public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
- "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
+ ContactsContract.Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED;
/**
* Starts an Activity that lets the user pick a contact to attach an image to.
* After picking the contact it launches the image cropper in face detection mode.
*/
- public static final String ATTACH_IMAGE =
- "com.android.contacts.action.ATTACH_IMAGE";
+ @Deprecated
+ public static final String ATTACH_IMAGE = ContactsContract.Intents.ATTACH_IMAGE;
/**
* Takes as input a data URI with a mailto: or tel: scheme. If a single
@@ -1492,8 +1705,9 @@ public class Contacts {
* Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
* prompting the user when the contact doesn't exist.
*/
+ @Deprecated
public static final String SHOW_OR_CREATE_CONTACT =
- "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
+ ContactsContract.Intents.SHOW_OR_CREATE_CONTACT;
/**
* Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
@@ -1502,9 +1716,9 @@ public class Contacts {
* <p>
* Type: BOOLEAN
*/
- public static final String EXTRA_FORCE_CREATE =
- "com.android.contacts.action.FORCE_CREATE";
-
+ @Deprecated
+ public static final String EXTRA_FORCE_CREATE = ContactsContract.Intents.EXTRA_FORCE_CREATE;
+
/**
* Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
* description to be shown when prompting user about creating a new
@@ -1512,69 +1726,93 @@ public class Contacts {
* <p>
* Type: STRING
*/
+ @Deprecated
public static final String EXTRA_CREATE_DESCRIPTION =
- "com.android.contacts.action.CREATE_DESCRIPTION";
+ ContactsContract.Intents.EXTRA_CREATE_DESCRIPTION;
+
+ /**
+ * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
+ * dialog location using screen coordinates. When not specified, the
+ * dialog will be centered.
+ *
+ * @hide pending API council review
+ */
+ @Deprecated
+ public static final String EXTRA_TARGET_RECT = ContactsContract.Intents.EXTRA_TARGET_RECT;
/**
* Intents related to the Contacts app UI.
*/
+ @Deprecated
public static final class UI {
+ @Deprecated
+ public UI() {
+ }
+
/**
* The action for the default contacts list tab.
*/
- public static final String LIST_DEFAULT =
- "com.android.contacts.action.LIST_DEFAULT";
+ @Deprecated
+ public static final String LIST_DEFAULT = ContactsContract.Intents.UI.LIST_DEFAULT;
/**
* The action for the contacts list tab.
*/
+ @Deprecated
public static final String LIST_GROUP_ACTION =
- "com.android.contacts.action.LIST_GROUP";
+ ContactsContract.Intents.UI.LIST_GROUP_ACTION;
/**
* When in LIST_GROUP_ACTION mode, this is the group to display.
*/
- public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
-
+ @Deprecated
+ public static final String GROUP_NAME_EXTRA_KEY =
+ ContactsContract.Intents.UI.GROUP_NAME_EXTRA_KEY;
/**
* The action for the all contacts list tab.
*/
+ @Deprecated
public static final String LIST_ALL_CONTACTS_ACTION =
- "com.android.contacts.action.LIST_ALL_CONTACTS";
+ ContactsContract.Intents.UI.LIST_ALL_CONTACTS_ACTION;
/**
* The action for the contacts with phone numbers list tab.
*/
+ @Deprecated
public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
- "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
+ ContactsContract.Intents.UI.LIST_CONTACTS_WITH_PHONES_ACTION;
/**
* The action for the starred contacts list tab.
*/
+ @Deprecated
public static final String LIST_STARRED_ACTION =
- "com.android.contacts.action.LIST_STARRED";
+ ContactsContract.Intents.UI.LIST_STARRED_ACTION;
/**
* The action for the frequent contacts list tab.
*/
+ @Deprecated
public static final String LIST_FREQUENT_ACTION =
- "com.android.contacts.action.LIST_FREQUENT";
+ ContactsContract.Intents.UI.LIST_FREQUENT_ACTION;
/**
* The action for the "strequent" contacts list tab. It first lists the starred
* contacts in alphabetical order and then the frequent contacts in descending
* order of the number of times they have been contacted.
*/
+ @Deprecated
public static final String LIST_STREQUENT_ACTION =
- "com.android.contacts.action.LIST_STREQUENT";
+ ContactsContract.Intents.UI.LIST_STREQUENT_ACTION;
/**
* A key for to be used as an intent extra to set the activity
* title to a custom String value.
*/
+ @Deprecated
public static final String TITLE_EXTRA_KEY =
- "com.android.contacts.extra.TITLE_EXTRA";
-
+ ContactsContract.Intents.UI.TITLE_EXTRA_KEY;
+
/**
* Activity Action: Display a filtered list of contacts
* <p>
@@ -1583,187 +1821,232 @@ public class Contacts {
* <p>
* Output: Nothing.
*/
- public static final String FILTER_CONTACTS_ACTION =
- "com.android.contacts.action.FILTER_CONTACTS";
-
+ @Deprecated
+ public static final String FILTER_CONTACTS_ACTION =
+ ContactsContract.Intents.UI.FILTER_CONTACTS_ACTION;
+
/**
* Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
* intents to supply the text on which to filter.
*/
- public static final String FILTER_TEXT_EXTRA_KEY =
- "com.android.contacts.extra.FILTER_TEXT";
+ @Deprecated
+ public static final String FILTER_TEXT_EXTRA_KEY =
+ ContactsContract.Intents.UI.FILTER_TEXT_EXTRA_KEY;
}
/**
* Convenience class that contains string constants used
* to create contact {@link android.content.Intent Intents}.
*/
+ @Deprecated
public static final class Insert {
+ @Deprecated
+ public Insert() {
+ }
+
/** The action code to use when adding a contact */
- public static final String ACTION = Intent.ACTION_INSERT;
+ @Deprecated
+ public static final String ACTION = ContactsContract.Intents.Insert.ACTION;
/**
* If present, forces a bypass of quick insert mode.
*/
- public static final String FULL_MODE = "full_mode";
+ @Deprecated
+ public static final String FULL_MODE = ContactsContract.Intents.Insert.FULL_MODE;
/**
* The extra field for the contact name.
* <P>Type: String</P>
*/
- public static final String NAME = "name";
+ @Deprecated
+ public static final String NAME = ContactsContract.Intents.Insert.NAME;
/**
* The extra field for the contact phonetic name.
* <P>Type: String</P>
*/
- public static final String PHONETIC_NAME = "phonetic_name";
+ @Deprecated
+ public static final String PHONETIC_NAME =
+ ContactsContract.Intents.Insert.PHONETIC_NAME;
/**
* The extra field for the contact company.
* <P>Type: String</P>
*/
- public static final String COMPANY = "company";
+ @Deprecated
+ public static final String COMPANY = ContactsContract.Intents.Insert.COMPANY;
/**
* The extra field for the contact job title.
* <P>Type: String</P>
*/
- public static final String JOB_TITLE = "job_title";
+ @Deprecated
+ public static final String JOB_TITLE = ContactsContract.Intents.Insert.JOB_TITLE;
/**
* The extra field for the contact notes.
* <P>Type: String</P>
*/
- public static final String NOTES = "notes";
+ @Deprecated
+ public static final String NOTES = ContactsContract.Intents.Insert.NOTES;
/**
* The extra field for the contact phone number.
* <P>Type: String</P>
*/
- public static final String PHONE = "phone";
+ @Deprecated
+ public static final String PHONE = ContactsContract.Intents.Insert.PHONE;
/**
* The extra field for the contact phone number type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
* or a string specifying a custom label.</P>
*/
- public static final String PHONE_TYPE = "phone_type";
+ @Deprecated
+ public static final String PHONE_TYPE = ContactsContract.Intents.Insert.PHONE_TYPE;
/**
* The extra field for the phone isprimary flag.
* <P>Type: boolean</P>
*/
- public static final String PHONE_ISPRIMARY = "phone_isprimary";
+ @Deprecated
+ public static final String PHONE_ISPRIMARY =
+ ContactsContract.Intents.Insert.PHONE_ISPRIMARY;
/**
* The extra field for an optional second contact phone number.
* <P>Type: String</P>
*/
- public static final String SECONDARY_PHONE = "secondary_phone";
+ @Deprecated
+ public static final String SECONDARY_PHONE =
+ ContactsContract.Intents.Insert.SECONDARY_PHONE;
/**
* The extra field for an optional second contact phone number type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
* or a string specifying a custom label.</P>
*/
- public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
+ @Deprecated
+ public static final String SECONDARY_PHONE_TYPE =
+ ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE;
/**
* The extra field for an optional third contact phone number.
* <P>Type: String</P>
*/
- public static final String TERTIARY_PHONE = "tertiary_phone";
+ @Deprecated
+ public static final String TERTIARY_PHONE =
+ ContactsContract.Intents.Insert.TERTIARY_PHONE;
/**
* The extra field for an optional third contact phone number type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
* or a string specifying a custom label.</P>
*/
- public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
+ @Deprecated
+ public static final String TERTIARY_PHONE_TYPE =
+ ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE;
/**
* The extra field for the contact email address.
* <P>Type: String</P>
*/
- public static final String EMAIL = "email";
+ @Deprecated
+ public static final String EMAIL = ContactsContract.Intents.Insert.EMAIL;
/**
* The extra field for the contact email type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
- public static final String EMAIL_TYPE = "email_type";
+ @Deprecated
+ public static final String EMAIL_TYPE = ContactsContract.Intents.Insert.EMAIL_TYPE;
/**
* The extra field for the email isprimary flag.
* <P>Type: boolean</P>
*/
- public static final String EMAIL_ISPRIMARY = "email_isprimary";
+ @Deprecated
+ public static final String EMAIL_ISPRIMARY =
+ ContactsContract.Intents.Insert.EMAIL_ISPRIMARY;
/**
* The extra field for an optional second contact email address.
* <P>Type: String</P>
*/
- public static final String SECONDARY_EMAIL = "secondary_email";
+ @Deprecated
+ public static final String SECONDARY_EMAIL =
+ ContactsContract.Intents.Insert.SECONDARY_EMAIL;
/**
* The extra field for an optional second contact email type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
- public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
+ @Deprecated
+ public static final String SECONDARY_EMAIL_TYPE =
+ ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE;
/**
* The extra field for an optional third contact email address.
* <P>Type: String</P>
*/
- public static final String TERTIARY_EMAIL = "tertiary_email";
+ @Deprecated
+ public static final String TERTIARY_EMAIL =
+ ContactsContract.Intents.Insert.TERTIARY_EMAIL;
/**
* The extra field for an optional third contact email type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
- public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
+ @Deprecated
+ public static final String TERTIARY_EMAIL_TYPE =
+ ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE;
/**
* The extra field for the contact postal address.
* <P>Type: String</P>
*/
- public static final String POSTAL = "postal";
+ @Deprecated
+ public static final String POSTAL = ContactsContract.Intents.Insert.POSTAL;
/**
* The extra field for the contact postal address type.
* <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
* or a string specifying a custom label.</P>
*/
- public static final String POSTAL_TYPE = "postal_type";
+ @Deprecated
+ public static final String POSTAL_TYPE = ContactsContract.Intents.Insert.POSTAL_TYPE;
/**
* The extra field for the postal isprimary flag.
* <P>Type: boolean</P>
*/
- public static final String POSTAL_ISPRIMARY = "postal_isprimary";
+ @Deprecated
+ public static final String POSTAL_ISPRIMARY = ContactsContract.Intents.Insert.POSTAL_ISPRIMARY;
/**
* The extra field for an IM handle.
* <P>Type: String</P>
*/
- public static final String IM_HANDLE = "im_handle";
+ @Deprecated
+ public static final String IM_HANDLE = ContactsContract.Intents.Insert.IM_HANDLE;
/**
* The extra field for the IM protocol
* <P>Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
* or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</P>
*/
- public static final String IM_PROTOCOL = "im_protocol";
+ @Deprecated
+ public static final String IM_PROTOCOL = ContactsContract.Intents.Insert.IM_PROTOCOL;
/**
* The extra field for the IM isprimary flag.
* <P>Type: boolean</P>
*/
- public static final String IM_ISPRIMARY = "im_isprimary";
+ @Deprecated
+ public static final String IM_ISPRIMARY = ContactsContract.Intents.Insert.IM_ISPRIMARY;
}
}
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
new file mode 100644
index 0000000..e48f539
--- /dev/null
+++ b/core/java/android/provider/ContactsContract.java
@@ -0,0 +1,2123 @@
+/*
+ * 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.accounts.Account;
+import android.content.ContentProviderClient;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.text.TextUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+/**
+ * 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 SyncStateColumns extends SyncStateContract.Columns {
+ }
+
+ public static final class SyncState {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private SyncState() {}
+
+ public static final String CONTENT_DIRECTORY =
+ SyncStateContract.Constants.CONTENT_DIRECTORY;
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, CONTENT_DIRECTORY);
+
+ /**
+ * @see android.provider.SyncStateContract.Helpers#get
+ */
+ public static byte[] get(ContentProviderClient provider, Account account)
+ throws RemoteException {
+ return SyncStateContract.Helpers.get(provider, CONTENT_URI, account);
+ }
+
+ /**
+ * @see android.provider.SyncStateContract.Helpers#set
+ */
+ public static void set(ContentProviderClient provider, Account account, byte[] data)
+ throws RemoteException {
+ SyncStateContract.Helpers.set(provider, CONTENT_URI, account, data);
+ }
+
+ /**
+ * @see android.provider.SyncStateContract.Helpers#newSetOperation
+ */
+ public static ContentProviderOperation newSetOperation(Account account, byte[] data) {
+ return SyncStateContract.Helpers.newSetOperation(CONTENT_URI, account, data);
+ }
+ }
+
+ /**
+ * Generic columns for use by sync adapters. The specific functions of
+ * these columns are private to the sync adapter. Other clients of the API
+ * should not attempt to either read or write this column.
+ */
+ private interface BaseSyncColumns {
+
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC1 = "sync1";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC2 = "sync2";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC3 = "sync3";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC4 = "sync4";
+ }
+
+ /**
+ * Columns that appear when each row of a table belongs to a specific
+ * account, including sync information that an account may need.
+ */
+ private interface SyncColumns extends BaseSyncColumns {
+ /**
+ * The name of the account instance to which this row belongs.
+ * <P>Type: TEXT</P>
+ */
+ public static final String ACCOUNT_NAME = "account_name";
+
+ /**
+ * The type of account to which this row belongs, which when paired with
+ * {@link #ACCOUNT_NAME} identifies a specific account.
+ * <P>Type: TEXT</P>
+ */
+ public static final String ACCOUNT_TYPE = "account_type";
+
+ /**
+ * String that uniquely identifies this row to its source account.
+ * <P>Type: TEXT</P>
+ */
+ public static final String SOURCE_ID = "sourceid";
+
+ /**
+ * Version number that is updated whenever this row or its related data
+ * changes.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String VERSION = "version";
+
+ /**
+ * Flag indicating that {@link #VERSION} has changed, and this row needs
+ * to be synchronized by its owning account.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String DIRTY = "dirty";
+ }
+
+ public interface ContactOptionsColumns {
+ /**
+ * 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";
+
+ /**
+ * A custom ringtone associated with a person. Not always present.
+ * <P>Type: TEXT (URI to the ringtone)</P>
+ */
+ public static final String CUSTOM_RINGTONE = "custom_ringtone";
+
+ /**
+ * Whether the person should always be sent to voicemail. Not always
+ * present.
+ * <P>Type: INTEGER (0 for false, 1 for true)</P>
+ */
+ public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
+ }
+
+ private interface ContactsColumns {
+ /**
+ * The display name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DISPLAY_NAME = "display_name";
+
+ /**
+ * 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";
+
+ /**
+ * Lookup value that reflects the {@link Groups#GROUP_VISIBLE} state of
+ * any {@link CommonDataKinds.GroupMembership} for this contact.
+ */
+ public static final String IN_VISIBLE_GROUP = "in_visible_group";
+
+ /**
+ * Contact presence status. See {@link android.provider.Im.CommonPresenceColumns}
+ * for individual status definitions. This column is only returned if explicitly
+ * requested in the query projection.
+ * <p>Type: NUMBER</p>
+ */
+ public static final String PRESENCE_STATUS = Presence.PRESENCE_STATUS;
+
+ /**
+ * Contact presence custom status. This column is only returned if explicitly
+ * requested in the query projection.
+ * <p>Type: TEXT</p>
+ */
+ public static final String PRESENCE_CUSTOM_STATUS = Presence.PRESENCE_CUSTOM_STATUS;
+
+ /**
+ * An indicator of whether this contact has at least one phone number. "1" if there is
+ * at least one phone number, "0" otherwise.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String HAS_PHONE_NUMBER = "has_phone_number";
+
+ /**
+ * An opaque value that contains hints on how to find the contact if
+ * its row id changed as a result of a sync or aggregation.
+ */
+ public static final String LOOKUP_KEY = "lookup";
+ }
+
+ /**
+ * Constants for the contacts table, which contains a record per group
+ * of raw contact representing the same person.
+ */
+ public static class Contacts implements BaseColumns, ContactsColumns,
+ ContactOptionsColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Contacts() {}
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contacts");
+
+ /**
+ * A content:// style URI for this table that should be used to create
+ * shortcuts or otherwise create long-term links to contacts. This URI
+ * should always be followed by a "/" and the contact's {@link #LOOKUP_KEY}.
+ * It can optionally also have a "/" and last known contact ID appended after
+ * that. This "complete" format is an important optimization and is highly recommended.
+ * <p>
+ * As long as the contact's row ID remains the same, this URI is
+ * equivalent to {@link #CONTENT_URI}. If the contact's row ID changes
+ * as a result of a sync or aggregation, this URI will look up the
+ * contact using indirect information (sync IDs or constituent raw
+ * contacts).
+ * <p>
+ * Lookup key should be appended unencoded - it is stored in the encoded
+ * form, ready for use in a URI.
+ */
+ public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI,
+ "lookup");
+
+ /**
+ * Computes a complete lookup URI (see {@link #CONTENT_LOOKUP_URI}).
+ * Pass either a basic content URI with a contact ID to obtain an
+ * equivalent lookup URI. Pass a possibly stale lookup URI to get a fresh
+ * lookup URI for the same contact.
+ * <p>
+ * Returns null if the contact cannot be found.
+ */
+ public static Uri getLookupUri(ContentResolver resolver, Uri contentUri) {
+ Cursor c = resolver.query(contentUri,
+ new String[]{Contacts.LOOKUP_KEY, Contacts._ID}, null, null, null);
+ if (c == null) {
+ return null;
+ }
+
+ try {
+ if (c.moveToFirst()) {
+ String lookupKey = c.getString(0);
+ long contactId = c.getLong(1);
+ return ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey),
+ contactId);
+ }
+ } finally {
+ c.close();
+ }
+ return null;
+ }
+
+ /**
+ * The content:// style URI for this table joined with useful data from
+ * {@link Data}.
+ *
+ * @deprecated Please use plain CONTENT_URI for the same result
+ */
+ @Deprecated
+ public static final Uri CONTENT_SUMMARY_URI = CONTENT_URI;
+
+ /**
+ * The content:// style URI used for "type-to-filter" functionality on the
+ * {@link #CONTENT_URI} URI. The filter string will be used to match
+ * various parts of the contact name. The filter argument should be passed
+ * as an additional path segment after this URI.
+ */
+ public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(
+ CONTENT_URI, "filter");
+
+ @Deprecated
+ public static final Uri CONTENT_SUMMARY_FILTER_URI = CONTENT_FILTER_URI;
+
+ /**
+ * The content:// style URI for this table joined with useful data from
+ * {@link Data}, filtered to include only starred contacts
+ * and the most frequently contacted contacts.
+ */
+ public static final Uri CONTENT_STREQUENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "strequent");
+
+ @Deprecated
+ public static final Uri CONTENT_SUMMARY_STREQUENT_URI = CONTENT_STREQUENT_URI;
+
+ /**
+ * The content:// style URI used for "type-to-filter" functionality on the
+ * {@link #CONTENT_STREQUENT_URI} URI. The filter string will be used to match
+ * various parts of the contact name. The filter argument should be passed
+ * as an additional path segment after this URI.
+ */
+ public static final Uri CONTENT_STREQUENT_FILTER_URI = Uri.withAppendedPath(
+ CONTENT_STREQUENT_URI, "filter");
+
+ @Deprecated
+ public static final Uri CONTENT_SUMMARY_STREQUENT_FILTER_URI = CONTENT_STREQUENT_FILTER_URI;
+
+ public static final Uri CONTENT_GROUP_URI = Uri.withAppendedPath(
+ CONTENT_URI, "group");
+
+ @Deprecated
+ public static final Uri CONTENT_SUMMARY_GROUP_URI = CONTENT_GROUP_URI;
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * people.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * person.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact";
+
+ /**
+ * A sub-directory of a single contact that contains all of the constituent raw contact
+ * {@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";
+ }
+
+ /**
+ * A sub-directory of a single contact aggregate that contains all aggregation suggestions
+ * (other contacts). The aggregation suggestions are computed based on approximate
+ * data matches with this contact.
+ */
+ public static final class AggregationSuggestions implements BaseColumns, ContactsColumns {
+ /**
+ * No public constructor since this is a utility class
+ */
+ private AggregationSuggestions() {}
+
+ /**
+ * The directory twig for this sub-table
+ */
+ public static final String CONTENT_DIRECTORY = "suggestions";
+ }
+
+ /**
+ * A sub-directory of a single contact that contains the contact's primary photo.
+ */
+ public static final class Photo implements BaseColumns, DataColumns {
+ /**
+ * no public constructor since this is a utility class
+ */
+ private Photo() {}
+
+ /**
+ * The directory twig for this sub-table
+ */
+ public static final String CONTENT_DIRECTORY = "photo";
+ }
+
+ /**
+ * Opens an InputStream for the person's default photo and returns the
+ * photo as a Bitmap stream.
+ *
+ * @param contactUri the contact whose photo should be used
+ */
+ public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
+ Uri photoUri = Uri.withAppendedPath(contactUri, Photo.CONTENT_DIRECTORY);
+ if (photoUri == null) {
+ return null;
+ }
+ Cursor cursor = cr.query(photoUri,
+ new String[]{ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
+ try {
+ if (cursor == null || !cursor.moveToNext()) {
+ return null;
+ }
+ byte[] data = cursor.getBlob(0);
+ if (data == null) {
+ return null;
+ }
+ return new ByteArrayInputStream(data);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+ }
+
+ private interface RawContactsColumns {
+ /**
+ * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} that this
+ * data belongs to.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String CONTACT_ID = "contact_id";
+
+ /**
+ * Flag indicating that this {@link RawContacts} entry and its children has
+ * been restricted to specific platform apps.
+ * <P>Type: INTEGER (boolean)</P>
+ *
+ * @hide until finalized in future platform release
+ */
+ public static final String IS_RESTRICTED = "is_restricted";
+
+ /**
+ * The aggregation mode for this contact.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String AGGREGATION_MODE = "aggregation_mode";
+
+ /**
+ * The "deleted" flag: "0" by default, "1" if the row has been marked
+ * for deletion. When {@link android.content.ContentResolver#delete} is
+ * called on a raw contact, it is marked for deletion and removed from its
+ * aggregate contact. The sync adaptor deletes the raw contact on the server and
+ * then calls ContactResolver.delete once more, this time passing the
+ * {@link RawContacts#DELETE_PERMANENTLY} query parameter to finalize the data removal.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DELETED = "deleted";
+ }
+
+ /**
+ * Constants for the raw_contacts table, which contains the base contact
+ * information per sync source. Sync adapters and contact management apps
+ * are the primary consumers of this API.
+ */
+ public static final class RawContacts implements BaseColumns, RawContactsColumns,
+ ContactOptionsColumns, SyncColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private RawContacts() {
+ }
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "raw_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
+ */
+ @Deprecated
+ 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/raw_contact";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * person.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact";
+
+ /**
+ * Query parameter that can be passed with the {@link #CONTENT_URI} URI
+ * to the {@link android.content.ContentResolver#delete} method to
+ * indicate that the raw contact can be deleted physically, rather than
+ * merely marked as deleted.
+ */
+ public static final String DELETE_PERMANENTLY = "delete_permanently";
+
+ /**
+ * Aggregation mode: aggregate asynchronously.
+ */
+ public static final int AGGREGATION_MODE_DEFAULT = 0;
+
+ /**
+ * Aggregation mode: aggregate at the time the raw contact is inserted/updated.
+ */
+ public static final int AGGREGATION_MODE_IMMEDITATE = 1;
+
+ /**
+ * If {@link #AGGREGATION_MODE} is {@link #AGGREGATION_MODE_SUSPENDED}, changes
+ * to the raw contact do not cause its aggregation to be revisited. Note that changing
+ * {@link #AGGREGATION_MODE} from {@link #AGGREGATION_MODE_SUSPENDED} to
+ * {@link #AGGREGATION_MODE_DEFAULT} does not trigger an aggregation pass. Any subsequent
+ * change to the raw contact's data will.
+ */
+ public static final int AGGREGATION_MODE_SUSPENDED = 2;
+
+ /**
+ * Aggregation mode: never aggregate this raw contact (note that the raw contact will not
+ * have a corresponding Aggregate and therefore will not be included in Aggregates
+ * query results.)
+ */
+ public static final int AGGREGATION_MODE_DISABLED = 3;
+
+ /**
+ * A sub-directory of a single raw contact that contains all of their {@link Data} rows.
+ * To access this directory append {@link Data#CONTENT_DIRECTORY} to the contact URI.
+ */
+ 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 to use when creating {@link Resources} objects for
+ * this data row. This value is only designed for use when building user
+ * interfaces, and should not be used to infer the owner.
+ */
+ public static final String RES_PACKAGE = "res_package";
+
+ /**
+ * The MIME type of the item represented by this row.
+ */
+ public static final String MIMETYPE = "mimetype";
+
+ /**
+ * A reference to the {@link RawContacts#_ID}
+ * that this data belongs to.
+ */
+ public static final String RAW_CONTACT_ID = "raw_contact_id";
+
+ /**
+ * Whether this is the primary entry of its kind for the raw 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
+ * contact 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";
+
+ /**
+ * The version of this data record. This is a read-only value. The data column is
+ * guaranteed to not change without the version going up. This value is monotonically
+ * increasing.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATA_VERSION = "data_version";
+
+ /** 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";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA11 = "data11";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA12 = "data12";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA13 = "data13";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA14 = "data14";
+ /** Generic data column, the meaning is {@link #MIMETYPE} specific */
+ public static final String DATA15 = "data15";
+
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC1 = "data_sync1";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC2 = "data_sync2";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC3 = "data_sync3";
+ /** Generic column for use by sync adapters. */
+ public static final String SYNC4 = "data_sync4";
+
+ /**
+ * An optional insert, update or delete URI parameter that determines if
+ * the corresponding raw contact should be marked as dirty. The default
+ * value is true.
+ */
+ public static final String MARK_AS_DIRTY = "mark_as_dirty";
+ }
+
+ /**
+ * Constants for the data table, which contains data points tied to a raw 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";
+ }
+
+ private interface PhoneLookupColumns {
+ /**
+ * The phone number as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NUMBER = "number";
+
+ /**
+ * The type of phone number, for example Home or Work.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TYPE = "type";
+
+ /**
+ * The user defined label for the phone number.
+ * <P>Type: TEXT</P>
+ */
+ public static final String LABEL = "label";
+ }
+
+ /**
+ * A table that represents the result of looking up a phone number, for
+ * example for caller ID. To perform a lookup you must append the number you
+ * want to find to {@link #CONTENT_FILTER_URI}.
+ */
+ public static final class PhoneLookup implements BaseColumns, PhoneLookupColumns,
+ ContactsColumns, ContactOptionsColumns {
+ /**
+ * 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_FILTER_URI = Uri.withAppendedPath(AUTHORITY_URI,
+ "phone_lookup");
+ }
+
+ /**
+ * Additional data mixed in with {@link Im.CommonPresenceColumns} to link
+ * back to specific {@link ContactsContract.Contacts#_ID} entries.
+ */
+ private interface PresenceColumns {
+
+ /**
+ * The unique ID for a row.
+ * <P>Type: INTEGER (long)</P>
+ */
+ public static final String _ID = "presence_id";
+
+ /**
+ * Reference to the {@link RawContacts#_ID} this presence references.
+ * <P>Type: INTEGER</P>
+ *
+ * TODO remove this from public API
+ * @hide
+ */
+ @Deprecated
+ public static final String RAW_CONTACT_ID = "presence_raw_contact_id";
+
+ /**
+ * Reference to the {@link Data#_ID} entry that owns this presence.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATA_ID = "presence_data_id";
+
+ @Deprecated
+ public static final String IM_PROTOCOL = "im_protocol";
+
+ /**
+ * <p>Type: NUMBER</p>
+ */
+ public static final String PROTOCOL = "protocol";
+
+ /**
+ * Name of the custom protocol. Should be supplied along with the {@link #PROTOCOL} value
+ * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}. Should be null or
+ * omitted if {@link #PROTOCOL} value is not
+ * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.
+ *
+ * <p>Type: NUMBER</p>
+ */
+ public static final String CUSTOM_PROTOCOL = "custom_protocol";
+
+ /**
+ * The IM handle the presence item is for. The handle is scoped to
+ * {@link #PROTOCOL}.
+ * <P>Type: TEXT</P>
+ */
+ public static final String IM_HANDLE = "im_handle";
+
+ /**
+ * The IM account for the local user that the presence data came from.
+ * <P>Type: TEXT</P>
+ */
+ public static final String IM_ACCOUNT = "im_account";
+ }
+
+ public static final class Presence implements PresenceColumns, Im.CommonPresenceColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Presence() {
+ }
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "presence");
+
+ /**
+ * Gets the resource ID for the proper presence icon.
+ *
+ * @param status the status to get the icon for
+ * @return the resource ID for the proper presence icon
+ */
+ public static final int getPresenceIconResourceId(int status) {
+ switch (status) {
+ case AVAILABLE:
+ return android.R.drawable.presence_online;
+ case IDLE:
+ case AWAY:
+ return android.R.drawable.presence_away;
+ case DO_NOT_DISTURB:
+ return android.R.drawable.presence_busy;
+ case INVISIBLE:
+ return android.R.drawable.presence_invisible;
+ case OFFLINE:
+ default:
+ return android.R.drawable.presence_offline;
+ }
+ }
+
+ /**
+ * Returns the precedence of the status code the higher number being the higher precedence.
+ *
+ * @param status The status code.
+ * @return An integer representing the precedence, 0 being the lowest.
+ */
+ public static final int getPresencePrecedence(int status) {
+ // Keep this function here incase we want to enforce a different precedence than the
+ // natural order of the status constants.
+ return status;
+ }
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * presence details.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-presence";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * presence detail.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im-presence";
+ }
+
+ /**
+ * Container for definitions of common data types stored in the {@link Data} table.
+ */
+ public static final class CommonDataKinds {
+ /**
+ * The {@link Data#RES_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 to use when creating {@link Resources} objects for
+ * this data row. This value is only designed for use when building user
+ * interfaces, and should not be used to infer the owner.
+ */
+ public static final String RES_PACKAGE = "res_package";
+
+ /**
+ * The MIME type of the item represented by this row.
+ */
+ public static final String MIMETYPE = "mimetype";
+
+ /**
+ * The {@link RawContacts#_ID} that this data belongs to.
+ */
+ public static final String RAW_CONTACT_ID = "raw_contact_id";
+ }
+
+ /**
+ * The base types that all "Typed" data kinds support.
+ */
+ public interface BaseTypes {
+
+ /**
+ * A custom type. The custom label should be supplied by user.
+ */
+ public static int TYPE_CUSTOM = 0;
+ }
+
+ /**
+ * Columns common across the specific types.
+ */
+ private interface CommonColumns extends BaseTypes{
+ /**
+ * 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 implements BaseCommonColumns {
+ 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.
+ * <i>Unstructured component of the name should be consistent with
+ * its structured representation.</i>
+ * <p>
+ * Type: TEXT
+ */
+ public static final String DISPLAY_NAME = "data9";
+ }
+
+ /**
+ * A nickname.
+ */
+ public static final class Nickname implements CommonColumns, BaseCommonColumns {
+ private Nickname() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/nickname";
+
+ public static final int TYPE_DEFAULT = 1;
+ public static final int TYPE_OTHER_NAME = 2;
+ public static final int TYPE_MAINDEN_NAME = 3;
+ public static final int TYPE_SHORT_NAME = 4;
+ public static final int TYPE_INITIALS = 5;
+
+ /**
+ * The name itself
+ */
+ public static final String NAME = DATA;
+ }
+
+ /**
+ * 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";
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * phones.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone";
+
+ /**
+ * The content:// style URI for all data records of the
+ * {@link Phone#CONTENT_ITEM_TYPE} MIME type, combined with the
+ * associated raw contact and aggregate contact data.
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
+ "phones");
+
+ /**
+ * The content:// style URI for filtering data records of the
+ * {@link Phone#CONTENT_ITEM_TYPE} MIME type, combined with the
+ * associated raw contact and aggregate contact data. The filter argument should
+ * be passed as an additional path segment after this URI.
+ */
+ public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
+ "filter");
+
+ 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;
+ public static final int TYPE_CALLBACK = 8;
+ public static final int TYPE_CAR = 9;
+ public static final int TYPE_COMPANY_MAIN = 10;
+ public static final int TYPE_ISDN = 11;
+ public static final int TYPE_MAIN = 12;
+ public static final int TYPE_OTHER_FAX = 13;
+ public static final int TYPE_RADIO = 14;
+ public static final int TYPE_TELEX = 15;
+ public static final int TYPE_TTY_TDD = 16;
+ public static final int TYPE_WORK_MOBILE = 17;
+ public static final int TYPE_WORK_PAGER = 18;
+ public static final int TYPE_ASSISTANT = 19;
+
+ /**
+ * The phone number as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NUMBER = DATA;
+
+ public static final CharSequence getDisplayLabel(Context context, int type,
+ CharSequence label, CharSequence[] labelArray) {
+ CharSequence display = "";
+
+ if (type != Phone.TYPE_CUSTOM) {
+ CharSequence[] labels = labelArray != null? labelArray
+ : context.getResources().getTextArray(
+ com.android.internal.R.array.phoneTypes);
+ try {
+ display = labels[type - 1];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ display = labels[Phone.TYPE_CUSTOM];
+ }
+ } else {
+ if (!TextUtils.isEmpty(label)) {
+ display = label;
+ }
+ }
+ return display;
+ }
+
+ public static final CharSequence getDisplayLabel(Context context, int type,
+ CharSequence label) {
+ return getDisplayLabel(context, type, label, null);
+ }
+ }
+
+ /**
+ * 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";
+
+ /**
+ * The content:// style URI for all data records of the
+ * {@link Email#CONTENT_ITEM_TYPE} MIME type, combined with the
+ * associated raw contact and aggregate contact data.
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
+ "emails");
+
+ /**
+ * The content:// style URL for filtering data rows by email address. The
+ * filter argument should be passed as an additional path segment after
+ * this URI.
+ */
+ public static final Uri CONTENT_FILTER_EMAIL_URI = Uri.withAppendedPath(CONTENT_URI,
+ "filter");
+
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_WORK = 2;
+ public static final int TYPE_OTHER = 3;
+ public static final int TYPE_MOBILE = 4;
+
+ /**
+ * The display name for the email address
+ * <P>Type: TEXT</P>
+ */
+ public static final String DISPLAY_NAME = "data4";
+ }
+
+ /**
+ * Common data definition for postal addresses.
+ */
+ public static final class StructuredPostal implements BaseCommonColumns, CommonColumns {
+ private StructuredPostal() {
+ }
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/postal-address";
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * postal addresses.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/postal-address";
+
+ /**
+ * The content:// style URI for all data records of the
+ * {@link StructuredPostal#CONTENT_ITEM_TYPE} MIME type.
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
+ "postals");
+
+ public static final int TYPE_HOME = 1;
+ public static final int TYPE_WORK = 2;
+ public static final int TYPE_OTHER = 3;
+
+ /**
+ * The full, unstructured postal address. <i>This field must be
+ * consistent with any structured data.</i>
+ * <p>
+ * Type: TEXT
+ */
+ public static final String FORMATTED_ADDRESS = DATA;
+
+ /**
+ * The agent who actually receives the mail. Used in work addresses.
+ * Also for 'in care of' or 'c/o'.
+ * <p>
+ * Type: TEXT
+ * @deprecated since this isn't supported by gd:structuredPostalAddress
+ */
+ @Deprecated
+ public static final String AGENT = "data4";
+
+ /**
+ * Used in places where houses or buildings have names (and not
+ * necessarily numbers), eg. "The Pillars".
+ * <p>
+ * Type: TEXT
+ * @deprecated since this isn't supported by gd:structuredPostalAddress
+ */
+ @Deprecated
+ public static final String HOUSENAME = "data5";
+
+ /**
+ * Can be street, avenue, road, etc. This element also includes the
+ * house number and room/apartment/flat/floor number.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String STREET = "data6";
+
+ /**
+ * Covers actual P.O. boxes, drawers, locked bags, etc. This is
+ * usually but not always mutually exclusive with street.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String POBOX = "data7";
+
+ /**
+ * This is used to disambiguate a street address when a city
+ * contains more than one street with the same name, or to specify a
+ * small place whose mail is routed through a larger postal town. In
+ * China it could be a county or a minor city.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String NEIGHBORHOOD = "data8";
+
+ /**
+ * Can be city, village, town, borough, etc. This is the postal town
+ * and not necessarily the place of residence or place of business.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String CITY = "data9";
+
+ /**
+ * Handles administrative districts such as U.S. or U.K. counties
+ * that are not used for mail addressing purposes. Subregion is not
+ * intended for delivery addresses.
+ * <p>
+ * Type: TEXT
+ * @deprecated since this isn't supported by gd:structuredPostalAddress
+ */
+ @Deprecated
+ public static final String SUBREGION = "data10";
+
+ /**
+ * A state, province, county (in Ireland), Land (in Germany),
+ * departement (in France), etc.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String REGION = "data11";
+
+ /**
+ * Postal code. Usually country-wide, but sometimes specific to the
+ * city (e.g. "2" in "Dublin 2, Ireland" addresses).
+ * <p>
+ * Type: TEXT
+ */
+ public static final String POSTCODE = "data12";
+
+ /**
+ * The name or code of the country.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String COUNTRY = "data13";
+ }
+
+ /**
+ * 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_HOME = 1;
+ public static final int TYPE_WORK = 2;
+ public static final int TYPE_OTHER = 3;
+
+ /**
+ * This column should be populated with one of the defined
+ * constants, e.g. {@link #PROTOCOL_YAHOO}. If the value of this
+ * column is {@link #PROTOCOL_CUSTOM}, the {@link #CUSTOM_PROTOCOL}
+ * should contain the name of the custom protocol.
+ */
+ public static final String PROTOCOL = "data5";
+
+ public static final String CUSTOM_PROTOCOL = "data6";
+
+ /*
+ * The predefined IM protocol types.
+ */
+ public static final int PROTOCOL_CUSTOM = -1;
+ 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 final int PROTOCOL_NETMEETING = 8;
+ }
+
+ /**
+ * Common data definition for organizations.
+ */
+ public static final class Organization implements BaseCommonColumns, CommonColumns {
+ private Organization() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization";
+
+ public static final int TYPE_WORK = 1;
+ public static final int TYPE_OTHER = 2;
+
+ /**
+ * The company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String COMPANY = DATA;
+
+ /**
+ * The position title at this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String TITLE = "data4";
+
+ /**
+ * The department at this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DEPARTMENT = "data5";
+
+ /**
+ * The job description at this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String JOB_DESCRIPTION = "data6";
+
+ /**
+ * The symbol of this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String SYMBOL = "data7";
+
+ /**
+ * The phonetic name of this company as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_NAME = "data8";
+ }
+
+ /**
+ * Common data definition for miscellaneous information.
+ */
+ public static final class Miscellaneous implements BaseCommonColumns {
+ private Miscellaneous() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/misc";
+
+ /**
+ * The birthday as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String BIRTHDAY = "data1";
+
+ /**
+ * The nickname as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NICKNAME = "data2";
+ }
+
+ /**
+ * Common data definition for relations.
+ */
+ public static final class Relation implements BaseCommonColumns, CommonColumns {
+ private Relation() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation";
+
+ public static final int TYPE_ASSISTANT = 1;
+ public static final int TYPE_BROTHER = 2;
+ public static final int TYPE_CHILD = 3;
+ public static final int TYPE_DOMESTIC_PARTNER = 4;
+ public static final int TYPE_FATHER = 5;
+ public static final int TYPE_FRIEND = 6;
+ public static final int TYPE_MANAGER = 7;
+ public static final int TYPE_MOTHER = 8;
+ public static final int TYPE_PARENT = 9;
+ public static final int TYPE_PARTNER = 10;
+ public static final int TYPE_REFERRED_BY = 11;
+ public static final int TYPE_RELATIVE = 12;
+ public static final int TYPE_SISTER = 13;
+ public static final int TYPE_SPOUSE = 14;
+
+ /**
+ * The name of the relative as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String NAME = DATA;
+ }
+
+ /**
+ * Common data definition for events.
+ */
+ public static final class Event implements BaseCommonColumns, CommonColumns {
+ private Event() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/event";
+
+ public static final int TYPE_ANNIVERSARY = 1;
+ public static final int TYPE_OTHER = 2;
+
+ /**
+ * The event start date as the user entered it.
+ * <P>Type: TEXT</P>
+ */
+ public static final String START_DATE = DATA;
+ }
+
+ /**
+ * 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 raw 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";
+ }
+
+ /**
+ * 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. Exactly one of
+ * this or {@link #GROUP_SOURCE_ID} must be set when inserting a row.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String GROUP_ROW_ID = "data1";
+
+ /**
+ * The sourceid of the group that this group membership refers to. Exactly one of
+ * this or {@link #GROUP_ROW_ID} must be set when inserting a row.
+ * <P>Type: TEXT</P>
+ */
+ public static final String GROUP_SOURCE_ID = "group_sourceid";
+ }
+
+ /**
+ * Website related to the contact.
+ */
+ public static final class Website implements BaseCommonColumns, CommonColumns {
+ private Website() {}
+
+ /** MIME type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/website";
+
+ public static final int TYPE_HOMEPAGE = 1;
+ public static final int TYPE_BLOG = 2;
+ public static final int TYPE_PROFILE = 3;
+ public static final int TYPE_HOME = 4;
+ public static final int TYPE_WORK = 5;
+ public static final int TYPE_FTP = 6;
+ public static final int TYPE_OTHER = 7;
+
+ /**
+ * The website URL string.
+ * <P>Type: TEXT</P>
+ */
+ public static final String URL = "data1";
+ }
+ }
+
+ // TODO: make this private before unhiding
+ public interface GroupsColumns {
+ /**
+ * The display title of this group.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String TITLE = "title";
+
+ /**
+ * The package name to use when creating {@link Resources} objects for
+ * this group. This value is only designed for use when building user
+ * interfaces, and should not be used to infer the owner.
+ */
+ public static final String RES_PACKAGE = "res_package";
+
+ /**
+ * The display title of this group to load as a resource from
+ * {@link #RES_PACKAGE}, which may be localized.
+ * <P>Type: TEXT</P>
+ */
+ public static final String TITLE_RES = "title_res";
+
+ /**
+ * Notes about the group.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String NOTES = "notes";
+
+ /**
+ * The ID of this group if it is a System Group, i.e. a group that has a special meaning
+ * to the sync adapter, null otherwise.
+ * <P>Type: TEXT</P>
+ */
+ public static final String SYSTEM_ID = "system_id";
+
+ /**
+ * The total number of {@link Contacts} that have
+ * {@link CommonDataKinds.GroupMembership} in this group. Read-only value that is only
+ * present when querying {@link Groups#CONTENT_SUMMARY_URI}.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String SUMMARY_COUNT = "summ_count";
+
+ /**
+ * The total number of {@link Contacts} that have both
+ * {@link CommonDataKinds.GroupMembership} in this group, and also have phone numbers.
+ * Read-only value that is only present when querying
+ * {@link Groups#CONTENT_SUMMARY_URI}.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String SUMMARY_WITH_PHONES = "summ_phones";
+
+ /**
+ * Flag indicating if the contacts belonging to this group should be
+ * visible in any user interface.
+ * <p>
+ * Type: INTEGER (boolean)
+ */
+ public static final String GROUP_VISIBLE = "group_visible";
+
+ /**
+ * The "deleted" flag: "0" by default, "1" if the row has been marked
+ * for deletion. When {@link android.content.ContentResolver#delete} is
+ * called on a raw contact, it is marked for deletion and removed from its
+ * aggregate contact. The sync adaptor deletes the raw contact on the server and
+ * then calls ContactResolver.delete once more, this time passing the
+ * {@link RawContacts#DELETE_PERMANENTLY} query parameter to finalize the data removal.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DELETED = "deleted";
+
+ /**
+ * Whether this group should be synced if the SYNC_EVERYTHING settings
+ * is false for this group's account.
+ * <p>
+ * Type: INTEGER (boolean)
+ */
+ public static final String SHOULD_SYNC = "should_sync";
+ }
+
+ /**
+ * Constants for the groups table.
+ */
+ public static final class Groups implements BaseColumns, GroupsColumns, SyncColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Groups() {
+ }
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "groups");
+
+ /**
+ * The content:// style URI for this table joined with details data from
+ * {@link Data}.
+ */
+ public static final Uri CONTENT_SUMMARY_URI = Uri.withAppendedPath(AUTHORITY_URI,
+ "groups_summary");
+
+ /**
+ * The MIME type of a directory of groups.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/group";
+
+ /**
+ * The MIME type of a single group.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group";
+
+ /**
+ * Query parameter that can be passed with the {@link #CONTENT_URI} URI
+ * to the {@link android.content.ContentResolver#delete} method to
+ * indicate that the raw contact can be deleted physically, rather than
+ * merely marked as deleted.
+ */
+ public static final String DELETE_PERMANENTLY = "delete_permanently";
+
+ /**
+ * An optional update or insert URI parameter that determines if the
+ * group should be marked as dirty. The default value is true.
+ */
+ public static final String MARK_AS_DIRTY = "mark_as_dirty";
+ }
+
+ /**
+ * Constants for the contact aggregation exceptions table, which contains
+ * aggregation rules overriding those used by automatic aggregation. This type only
+ * supports query and update. Neither insert nor delete are supported.
+ */
+ public static final class AggregationExceptions implements BaseColumns {
+ /**
+ * 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 MIME type of a {@link #CONTENT_URI} subdirectory of an aggregation exception
+ */
+ public static final String CONTENT_ITEM_TYPE =
+ "vnd.android.cursor.item/aggregation_exception";
+
+ /**
+ * The type of exception: {@link #TYPE_KEEP_IN}, {@link #TYPE_KEEP_OUT} or
+ * {@link #TYPE_AUTOMATIC}.
+ *
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TYPE = "type";
+
+ /**
+ * Allows the provider to automatically decide whether the aggregate
+ * contact should include a particular raw contact or not.
+ */
+ public static final int TYPE_AUTOMATIC = 0;
+
+ /**
+ * Makes sure that the specified raw contact is included in the
+ * specified aggregate contact.
+ */
+ public static final int TYPE_KEEP_IN = 1;
+
+ /**
+ * Makes sure that the specified raw contact is NOT included in the
+ * specified aggregate contact.
+ */
+ public static final int TYPE_KEEP_OUT = 2;
+
+ /**
+ * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} of the
+ * aggregate contact that the rule applies to.
+ */
+ public static final String CONTACT_ID = "contact_id";
+
+ /**
+ * A reference to the {@link RawContacts#_ID} of the raw contact that the rule applies to.
+ */
+ public static final String RAW_CONTACT_ID = "raw_contact_id";
+ }
+
+ private interface SettingsColumns {
+ /**
+ * The name of the account instance to which this row belongs.
+ * <P>Type: TEXT</P>
+ */
+ public static final String ACCOUNT_NAME = "account_name";
+
+ /**
+ * The type of account to which this row belongs, which when paired with
+ * {@link #ACCOUNT_NAME} identifies a specific account.
+ * <P>Type: TEXT</P>
+ */
+ public static final String ACCOUNT_TYPE = "account_type";
+
+ /**
+ * Depending on the mode defined by the sync-adapter, this flag controls
+ * the top-level sync behavior for this data source.
+ * <p>
+ * Type: INTEGER (boolean)
+ */
+ public static final String SHOULD_SYNC = "should_sync";
+
+ /**
+ * Flag indicating if contacts without any {@link CommonDataKinds.GroupMembership}
+ * entries should be visible in any user interface.
+ * <p>
+ * Type: INTEGER (boolean)
+ */
+ public static final String UNGROUPED_VISIBLE = "ungrouped_visible";
+
+ /**
+ * Read-only count of {@link Contacts} from a specific source that have
+ * no {@link CommonDataKinds.GroupMembership} entries.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String UNGROUPED_COUNT = "summ_count";
+
+ /**
+ * Read-only count of {@link Contacts} from a specific source that have
+ * no {@link CommonDataKinds.GroupMembership} entries, and also have phone numbers.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String UNGROUPED_WITH_PHONES = "summ_phones";
+ }
+
+ /**
+ * Contacts-specific settings for various {@link Account}.
+ */
+ public static final class Settings implements SettingsColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Settings() {
+ }
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "settings");
+
+ /**
+ * The MIME-type of {@link #CONTENT_URI} providing a directory of
+ * settings.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/setting";
+
+ /**
+ * The MIME-type of {@link #CONTENT_URI} providing a single setting.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/setting";
+ }
+
+ /**
+ * Contains helper classes used to create or manage {@link android.content.Intent Intents}
+ * that involve contacts.
+ */
+ public static final class Intents {
+ /**
+ * This is the intent that is fired when a search suggestion is clicked on.
+ */
+ public static final String SEARCH_SUGGESTION_CLICKED =
+ "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
+
+ /**
+ * This is the intent that is fired when a search suggestion for dialing a number
+ * is clicked on.
+ */
+ public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
+ "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
+
+ /**
+ * This is the intent that is fired when a search suggestion for creating a contact
+ * is clicked on.
+ */
+ public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
+ "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
+
+ /**
+ * Starts an Activity that lets the user pick a contact to attach an image to.
+ * After picking the contact it launches the image cropper in face detection mode.
+ */
+ public static final String ATTACH_IMAGE =
+ "com.android.contacts.action.ATTACH_IMAGE";
+
+ /**
+ * Takes as input a data URI with a mailto: or tel: scheme. If a single
+ * contact exists with the given data it will be shown. If no contact
+ * exists, a dialog will ask the user if they want to create a new
+ * contact with the provided details filled in. If multiple contacts
+ * share the data the user will be prompted to pick which contact they
+ * want to view.
+ * <p>
+ * For <code>mailto:</code> URIs, the scheme specific portion must be a
+ * raw email address, such as one built using
+ * {@link Uri#fromParts(String, String, String)}.
+ * <p>
+ * For <code>tel:</code> URIs, the scheme specific portion is compared
+ * to existing numbers using the standard caller ID lookup algorithm.
+ * The number must be properly encoded, for example using
+ * {@link Uri#fromParts(String, String, String)}.
+ * <p>
+ * Any extras from the {@link Insert} class will be passed along to the
+ * create activity if there are no contacts to show.
+ * <p>
+ * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
+ * prompting the user when the contact doesn't exist.
+ */
+ public static final String SHOW_OR_CREATE_CONTACT =
+ "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
+
+ /**
+ * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
+ * contact if no matching contact found. Otherwise, default behavior is
+ * to prompt user with dialog before creating.
+ * <p>
+ * Type: BOOLEAN
+ */
+ public static final String EXTRA_FORCE_CREATE =
+ "com.android.contacts.action.FORCE_CREATE";
+
+ /**
+ * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
+ * description to be shown when prompting user about creating a new
+ * contact.
+ * <p>
+ * Type: STRING
+ */
+ public static final String EXTRA_CREATE_DESCRIPTION =
+ "com.android.contacts.action.CREATE_DESCRIPTION";
+
+ /**
+ * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
+ * dialog location using screen coordinates. When not specified, the
+ * dialog will be centered.
+ */
+ public static final String EXTRA_TARGET_RECT = "target_rect";
+
+ /**
+ * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
+ * desired dialog style, usually a variation on size. One of
+ * {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or {@link #MODE_LARGE}.
+ */
+ public static final String EXTRA_MODE = "mode";
+
+ /**
+ * Value for {@link #EXTRA_MODE} to show a small-sized dialog.
+ */
+ public static final int MODE_SMALL = 1;
+
+ /**
+ * Value for {@link #EXTRA_MODE} to show a medium-sized dialog.
+ */
+ public static final int MODE_MEDIUM = 2;
+
+ /**
+ * Value for {@link #EXTRA_MODE} to show a large-sized dialog.
+ */
+ public static final int MODE_LARGE = 3;
+
+ /**
+ * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to indicate
+ * a list of specific MIME-types to exclude and not display. Stored as a
+ * {@link String} array.
+ */
+ public static final String EXTRA_EXCLUDE_MIMES = "exclude_mimes";
+
+ /**
+ * Intents related to the Contacts app UI.
+ */
+ public static final class UI {
+ /**
+ * The action for the default contacts list tab.
+ */
+ public static final String LIST_DEFAULT =
+ "com.android.contacts.action.LIST_DEFAULT";
+
+ /**
+ * The action for the contacts list tab.
+ */
+ public static final String LIST_GROUP_ACTION =
+ "com.android.contacts.action.LIST_GROUP";
+
+ /**
+ * When in LIST_GROUP_ACTION mode, this is the group to display.
+ */
+ public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
+
+ /**
+ * The action for the all contacts list tab.
+ */
+ public static final String LIST_ALL_CONTACTS_ACTION =
+ "com.android.contacts.action.LIST_ALL_CONTACTS";
+
+ /**
+ * The action for the contacts with phone numbers list tab.
+ */
+ public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
+ "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
+
+ /**
+ * The action for the starred contacts list tab.
+ */
+ public static final String LIST_STARRED_ACTION =
+ "com.android.contacts.action.LIST_STARRED";
+
+ /**
+ * The action for the frequent contacts list tab.
+ */
+ public static final String LIST_FREQUENT_ACTION =
+ "com.android.contacts.action.LIST_FREQUENT";
+
+ /**
+ * The action for the "strequent" contacts list tab. It first lists the starred
+ * contacts in alphabetical order and then the frequent contacts in descending
+ * order of the number of times they have been contacted.
+ */
+ public static final String LIST_STREQUENT_ACTION =
+ "com.android.contacts.action.LIST_STREQUENT";
+
+ /**
+ * A key for to be used as an intent extra to set the activity
+ * title to a custom String value.
+ */
+ public static final String TITLE_EXTRA_KEY =
+ "com.android.contacts.extra.TITLE_EXTRA";
+
+ /**
+ * Activity Action: Display a filtered list of contacts
+ * <p>
+ * Input: Extra field {@link #FILTER_TEXT_EXTRA_KEY} is the text to use for
+ * filtering
+ * <p>
+ * Output: Nothing.
+ */
+ public static final String FILTER_CONTACTS_ACTION =
+ "com.android.contacts.action.FILTER_CONTACTS";
+
+ /**
+ * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
+ * intents to supply the text on which to filter.
+ */
+ public static final String FILTER_TEXT_EXTRA_KEY =
+ "com.android.contacts.extra.FILTER_TEXT";
+ }
+
+ /**
+ * Convenience class that contains string constants used
+ * to create contact {@link android.content.Intent Intents}.
+ */
+ public static final class Insert {
+ /** The action code to use when adding a contact */
+ public static final String ACTION = Intent.ACTION_INSERT;
+
+ /**
+ * If present, forces a bypass of quick insert mode.
+ */
+ public static final String FULL_MODE = "full_mode";
+
+ /**
+ * The extra field for the contact name.
+ * <P>Type: String</P>
+ */
+ public static final String NAME = "name";
+
+ // TODO add structured name values here.
+
+ /**
+ * The extra field for the contact phonetic name.
+ * <P>Type: String</P>
+ */
+ public static final String PHONETIC_NAME = "phonetic_name";
+
+ /**
+ * The extra field for the contact company.
+ * <P>Type: String</P>
+ */
+ public static final String COMPANY = "company";
+
+ /**
+ * The extra field for the contact job title.
+ * <P>Type: String</P>
+ */
+ public static final String JOB_TITLE = "job_title";
+
+ /**
+ * The extra field for the contact notes.
+ * <P>Type: String</P>
+ */
+ public static final String NOTES = "notes";
+
+ /**
+ * The extra field for the contact phone number.
+ * <P>Type: String</P>
+ */
+ public static final String PHONE = "phone";
+
+ /**
+ * The extra field for the contact phone number type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+ * or a string specifying a custom label.</P>
+ */
+ public static final String PHONE_TYPE = "phone_type";
+
+ /**
+ * The extra field for the phone isprimary flag.
+ * <P>Type: boolean</P>
+ */
+ public static final String PHONE_ISPRIMARY = "phone_isprimary";
+
+ /**
+ * The extra field for an optional second contact phone number.
+ * <P>Type: String</P>
+ */
+ public static final String SECONDARY_PHONE = "secondary_phone";
+
+ /**
+ * The extra field for an optional second contact phone number type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+ * or a string specifying a custom label.</P>
+ */
+ public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
+
+ /**
+ * The extra field for an optional third contact phone number.
+ * <P>Type: String</P>
+ */
+ public static final String TERTIARY_PHONE = "tertiary_phone";
+
+ /**
+ * The extra field for an optional third contact phone number type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.PhonesColumns PhonesColumns},
+ * or a string specifying a custom label.</P>
+ */
+ public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
+
+ /**
+ * The extra field for the contact email address.
+ * <P>Type: String</P>
+ */
+ public static final String EMAIL = "email";
+
+ /**
+ * The extra field for the contact email type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+ * or a string specifying a custom label.</P>
+ */
+ public static final String EMAIL_TYPE = "email_type";
+
+ /**
+ * The extra field for the email isprimary flag.
+ * <P>Type: boolean</P>
+ */
+ public static final String EMAIL_ISPRIMARY = "email_isprimary";
+
+ /**
+ * The extra field for an optional second contact email address.
+ * <P>Type: String</P>
+ */
+ public static final String SECONDARY_EMAIL = "secondary_email";
+
+ /**
+ * The extra field for an optional second contact email type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+ * or a string specifying a custom label.</P>
+ */
+ public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
+
+ /**
+ * The extra field for an optional third contact email address.
+ * <P>Type: String</P>
+ */
+ public static final String TERTIARY_EMAIL = "tertiary_email";
+
+ /**
+ * The extra field for an optional third contact email type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+ * or a string specifying a custom label.</P>
+ */
+ public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
+
+ /**
+ * The extra field for the contact postal address.
+ * <P>Type: String</P>
+ */
+ public static final String POSTAL = "postal";
+
+ /**
+ * The extra field for the contact postal address type.
+ * <P>Type: Either an integer value from
+ * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
+ * or a string specifying a custom label.</P>
+ */
+ public static final String POSTAL_TYPE = "postal_type";
+
+ /**
+ * The extra field for the postal isprimary flag.
+ * <P>Type: boolean</P>
+ */
+ public static final String POSTAL_ISPRIMARY = "postal_isprimary";
+
+ /**
+ * The extra field for an IM handle.
+ * <P>Type: String</P>
+ */
+ public static final String IM_HANDLE = "im_handle";
+
+ /**
+ * The extra field for the IM protocol
+ * <P>Type: the result of {@link CommonDataKinds.Im#encodePredefinedImProtocol(int)}
+ * or {@link CommonDataKinds.Im#encodeCustomImProtocol(String)}.</P>
+ */
+ public static final String IM_PROTOCOL = "im_protocol";
+
+ /**
+ * The extra field for the IM isprimary flag.
+ * <P>Type: boolean</P>
+ */
+ public static final String IM_ISPRIMARY = "im_isprimary";
+ }
+ }
+
+}
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/DrmStore.java b/core/java/android/provider/DrmStore.java
index db71854..c438ac4 100644
--- a/core/java/android/provider/DrmStore.java
+++ b/core/java/android/provider/DrmStore.java
@@ -35,7 +35,7 @@ import java.io.OutputStream;
/**
* The DRM provider contains forward locked DRM content.
- *
+ *
* @hide
*/
public final class DrmStore
@@ -43,13 +43,13 @@ public final class DrmStore
private static final String TAG = "DrmStore";
public static final String AUTHORITY = "drm";
-
+
/**
* This is in the Manifest class of the drm provider, but that isn't visible
* in the framework.
*/
private static final String ACCESS_DRM_PERMISSION = "android.permission.ACCESS_DRM";
-
+
/**
* Fields for DRM database
*/
@@ -82,18 +82,18 @@ public final class DrmStore
}
public interface Images extends Columns {
-
+
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/images");
}
-
+
public interface Audio extends Columns {
-
+
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/audio");
}
/**
* Utility function for inserting a file into the DRM content provider.
- *
+ *
* @param cr The content resolver to use
* @param file The file to insert
* @param title The title for the content (or null)
@@ -101,12 +101,46 @@ public final class DrmStore
*/
public static final Intent addDrmFile(ContentResolver cr, File file, String title) {
FileInputStream fis = null;
- OutputStream os = null;
Intent result = null;
try {
fis = new FileInputStream(file);
- DrmRawContent content = new DrmRawContent(fis, (int) file.length(),
+ if (title == null) {
+ title = file.getName();
+ int lastDot = title.lastIndexOf('.');
+ if (lastDot > 0) {
+ title = title.substring(0, lastDot);
+ }
+ }
+ result = addDrmFile(cr, fis, title);
+ } catch (Exception e) {
+ Log.e(TAG, "pushing file failed", e);
+ } finally {
+ try {
+ if (fis != null)
+ fis.close();
+ } catch (IOException e) {
+ Log.e(TAG, "IOException in DrmStore.addDrmFile()", e);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Utility function for inserting a file stream into the DRM content provider.
+ *
+ * @param cr The content resolver to use
+ * @param fileStream The FileInputStream to insert
+ * @param title The title for the content (or null)
+ * @return uri to the DRM record or null
+ */
+ public static final Intent addDrmFile(ContentResolver cr, FileInputStream fis, String title) {
+ OutputStream os = null;
+ Intent result = null;
+
+ try {
+ DrmRawContent content = new DrmRawContent(fis, (int) fis.available(),
DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING);
String mimeType = content.getContentType();
@@ -126,14 +160,6 @@ public final class DrmStore
if (contentUri != null) {
ContentValues values = new ContentValues(3);
- // compute title from file name, if it is not specified
- if (title == null) {
- title = file.getName();
- int lastDot = title.lastIndexOf('.');
- if (lastDot > 0) {
- title = title.substring(0, lastDot);
- }
- }
values.put(DrmStore.Columns.TITLE, title);
values.put(DrmStore.Columns.SIZE, size);
values.put(DrmStore.Columns.MIME_TYPE, mimeType);
@@ -162,7 +188,7 @@ public final class DrmStore
if (os != null)
os.close();
} catch (IOException e) {
- Log.e(TAG, "IOException in DrmTest.onCreate()", e);
+ Log.e(TAG, "IOException in DrmStore.addDrmFile()", e);
}
}
@@ -172,7 +198,7 @@ public final class DrmStore
/**
* Utility function to enforce any permissions required to access DRM
* content.
- *
+ *
* @param context A context used for checking calling permission.
*/
public static void enforceAccessDrmPermission(Context context) {
@@ -181,5 +207,5 @@ public final class DrmStore
throw new SecurityException("Requires DRM permission");
}
}
-
+
}
diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java
index c4b29ae..4425e51 100644
--- a/core/java/android/provider/Gmail.java
+++ b/core/java/android/provider/Gmail.java
@@ -83,7 +83,7 @@ public final class Gmail {
public static final String LABEL_OUTBOX = "^^out";
public static final String AUTHORITY = "gmail-ls";
- private static final String TAG = "gmail-ls";
+ private static final String TAG = "Gmail";
private static final String AUTHORITY_PLUS_CONVERSATIONS =
"content://" + AUTHORITY + "/conversations/";
private static final String AUTHORITY_PLUS_LABELS =
@@ -1521,8 +1521,9 @@ public final class Gmail {
/**
* Returns the number of conversation with a given label.
- * @deprecated
+ * @deprecated Use {@link #getLabelId} instead.
*/
+ @Deprecated
public int getNumConversations(String label) {
return getNumConversations(getLabelId(label));
}
@@ -1534,8 +1535,9 @@ public final class Gmail {
/**
* Returns the number of unread conversation with a given label.
- * @deprecated
+ * @deprecated Use {@link #getLabelId} instead.
*/
+ @Deprecated
public int getNumUnreadConversations(String label) {
return getNumUnreadConversations(getLabelId(label));
}
@@ -2040,8 +2042,9 @@ public final class Gmail {
}
/**
- * @deprecated
+ * @deprecated Always returns true.
*/
+ @Deprecated
public boolean getExpanded() {
return true;
}
diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java
index 19ad158..f126c4d 100644
--- a/core/java/android/provider/Im.java
+++ b/core/java/android/provider/Im.java
@@ -138,6 +138,7 @@ public class Im {
public static final String ACTIVE_ACCOUNT_USERNAME = "account_username";
public static final String ACTIVE_ACCOUNT_PW = "account_pw";
public static final String ACTIVE_ACCOUNT_LOCKED = "account_locked";
+ public static final String ACTIVE_ACCOUNT_KEEP_SIGNED_IN = "account_keepSignedIn";
public static final String ACCOUNT_PRESENCE_STATUS = "account_presenceStatus";
public static final String ACCOUNT_CONNECTION_STATUS = "account_connStatus";
@@ -871,14 +872,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 +926,199 @@ 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>
+ * Is groupchat message or not
+ * <P>Type: INTEGER</P>
*/
- String PROVIDER = "provider";
+ String IS_GROUP_CHAT = "is_muc";
/**
- * The account id
- * <P> Type: INTEGER </P>
+ * A hint that the UI should show the sent time of this message
+ * <P>Type: INTEGER</P>
*/
- String ACCOUNT = "account";
+ String DISPLAY_SENT_TIME = "show_ts";
}
/**
* 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 off the record messages by thread id
+ */
+ 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 messages by provider and account
+ * The content:// style URL for off the record messages by provider
*/
- public static final Uri CONTENT_URI_MESSAGES_BY =
- Uri.parse("content://im/messagesBy");
+ 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 +1132,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 +1264,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 {
@@ -1384,7 +1468,7 @@ public class Im {
* <P>Type: TEXT</P>
*/
String UNSENT_COMPOSED_MESSAGE = "unsent_composed_message";
-
+
/**
* A value from 0-9 indicating which quick-switch chat screen slot this
* chat is occupying. If none (for instance, this is the 12th active chat)
@@ -1534,6 +1618,18 @@ public class Im {
/** specifies whether or not to show mobile indicator to friends */
public static final String SETTING_SHOW_MOBILE_INDICATOR = "mobile_indicator";
+ /** specifies whether or not to show as away when device is idle */
+ public static final String SETTING_SHOW_AWAY_ON_IDLE = "show_away_on_idle";
+
+ /** specifies whether or not to upload heartbeat stat upon login */
+ public static final String SETTING_UPLOAD_HEARTBEAT_STAT = "upload_heartbeat_stat";
+
+ /** specifies the last heartbeat interval received from the server */
+ public static final String SETTING_HEARTBEAT_INTERVAL = "heartbeat_interval";
+
+ /** specifiy the JID resource used for Google Talk connection */
+ public static final String SETTING_JID_RESOURCE = "jid_resource";
+
/**
* Used for reliable message queue (RMQ). This is for storing the last rmq id received
* from the GTalk server
@@ -1742,6 +1838,47 @@ public class Im {
showMobileIndicator);
}
+ /**
+ * A convenience method to set whether or not to show as away when device is idle.
+ *
+ * @param contentResolver The ContentResolver to use to access the setting table.
+ * @param showAway Whether or not to show as away when device is idle.
+ */
+ public static void setShowAwayOnIdle(ContentResolver contentResolver,
+ long providerId, boolean showAway) {
+ putBooleanValue(contentResolver, providerId, SETTING_SHOW_AWAY_ON_IDLE, showAway);
+ }
+
+ /**
+ * A convenience method to set whether or not to upload heartbeat stat.
+ *
+ * @param contentResolver The ContentResolver to use to access the setting table.
+ * @param uploadStat Whether or not to upload heartbeat stat.
+ */
+ public static void setUploadHeartbeatStat(ContentResolver contentResolver,
+ long providerId, boolean uploadStat) {
+ putBooleanValue(contentResolver, providerId, SETTING_UPLOAD_HEARTBEAT_STAT, uploadStat);
+ }
+
+ /**
+ * A convenience method to set the heartbeat interval last received from the server.
+ *
+ * @param contentResolver The ContentResolver to use to access the setting table.
+ * @param interval The heartbeat interval last received from the server.
+ */
+ public static void setHeartbeatInterval(ContentResolver contentResolver,
+ long providerId, long interval) {
+ putLongValue(contentResolver, providerId, SETTING_HEARTBEAT_INTERVAL, interval);
+ }
+
+ /**
+ * A convenience method to set the jid resource.
+ */
+ public static void setJidResource(ContentResolver contentResolver,
+ long providerId, String jidResource) {
+ putStringValue(contentResolver, providerId, SETTING_JID_RESOURCE, jidResource);
+ }
+
public static class QueryMap extends ContentQueryMap {
private ContentResolver mContentResolver;
private long mProviderId;
@@ -1872,6 +2009,79 @@ public class Im {
}
/**
+ * Set whether or not to show as away when device is idle.
+ *
+ * @param showAway whether or not to show as away when device is idle.
+ */
+ public void setShowAwayOnIdle(boolean showAway) {
+ ProviderSettings.setShowAwayOnIdle(mContentResolver, mProviderId, showAway);
+ }
+
+ /**
+ * Get whether or not to show as away when device is idle.
+ *
+ * @return Whether or not to show as away when device is idle.
+ */
+ public boolean getShowAwayOnIdle() {
+ return getBoolean(SETTING_SHOW_AWAY_ON_IDLE,
+ true /* by default show as away on idle*/);
+ }
+
+ /**
+ * Set whether or not to upload heartbeat stat.
+ *
+ * @param uploadStat whether or not to upload heartbeat stat.
+ */
+ public void setUploadHeartbeatStat(boolean uploadStat) {
+ ProviderSettings.setUploadHeartbeatStat(mContentResolver, mProviderId, uploadStat);
+ }
+
+ /**
+ * Get whether or not to upload heartbeat stat.
+ *
+ * @return Whether or not to upload heartbeat stat.
+ */
+ public boolean getUploadHeartbeatStat() {
+ return getBoolean(SETTING_UPLOAD_HEARTBEAT_STAT,
+ false /* by default do not upload */);
+ }
+
+ /**
+ * Set the last received heartbeat interval from the server.
+ *
+ * @param interval the last received heartbeat interval from the server.
+ */
+ public void setHeartbeatInterval(long interval) {
+ ProviderSettings.setHeartbeatInterval(mContentResolver, mProviderId, interval);
+ }
+
+ /**
+ * Get the last received heartbeat interval from the server.
+ *
+ * @return the last received heartbeat interval from the server.
+ */
+ public long getHeartbeatInterval() {
+ return getLong(SETTING_HEARTBEAT_INTERVAL, 0L /* an invalid default interval */);
+ }
+
+ /**
+ * Set the JID resource.
+ *
+ * @param jidResource the jid resource to be stored.
+ */
+ public void setJidResource(String jidResource) {
+ ProviderSettings.setJidResource(mContentResolver, mProviderId, jidResource);
+ }
+ /**
+ * Get the JID resource used for the Google Talk connection
+ *
+ * @return the JID resource stored.
+ */
+ public String getJidResource() {
+ return getString(SETTING_JID_RESOURCE, null);
+ }
+
+ /**
* Convenience function for retrieving a single settings value
* as a boolean.
*
@@ -1909,21 +2119,77 @@ public class Im {
ContentValues values = getValues(name);
return values != null ? values.getAsInteger(VALUE) : def;
}
+
+ /**
+ * Convenience function for retrieving a single settings value
+ * as a Long.
+ *
+ * @param name The name of the setting to retrieve.
+ * @param def The value to return if the setting is not defined.
+ * @return The setting's current value or 'def' if it is not defined.
+ */
+ private long getLong(String name, long def) {
+ ContentValues values = getValues(name);
+ return values != null ? values.getAsLong(VALUE) : def;
+ }
}
}
+
+ /**
+ * Columns for IM branding resource map cache table. This table caches the result of
+ * loading the branding resources to speed up IM landing page start.
+ */
+ public interface BrandingResourceMapCacheColumns {
+ /**
+ * The provider ID
+ * <P>Type: INTEGER</P>
+ */
+ String PROVIDER_ID = "provider_id";
+ /**
+ * The application resource ID
+ * <P>Type: INTEGER</P>
+ */
+ String APP_RES_ID = "app_res_id";
+ /**
+ * The plugin resource ID
+ * <P>Type: INTEGER</P>
+ */
+ String PLUGIN_RES_ID = "plugin_res_id";
+ }
+
+ /**
+ * The table for caching the result of loading IM branding resources.
+ */
+ public static final class BrandingResourceMapCache
+ implements BaseColumns, BrandingResourceMapCacheColumns {
+ /**
+ * The content:// style URL for this table.
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://im/brandingResMapCache");
+ }
+
+
+
+ /**
+ * //TODO: move these to MCS specific provider.
+ * The following are MCS stuff, and should really live in a separate provider specific to
+ * MCS code.
+ */
+
/**
* Columns from OutgoingRmq table
*/
public interface OutgoingRmqColumns {
String RMQ_ID = "rmq_id";
- String TYPE = "type";
String TIMESTAMP = "ts";
String DATA = "data";
+ String PROTOBUF_TAG = "type";
}
/**
+ * //TODO: we should really move these to their own provider and database.
* The table for storing outgoing rmq packets.
*/
public static final class OutgoingRmq implements BaseColumns, OutgoingRmqColumns {
@@ -1986,6 +2252,7 @@ public class Im {
}
/**
+ * //TODO: move these out into their own provider and database
* The table for storing the last client rmq id sent to the server.
*/
public static final class LastRmqId implements BaseColumns, LastRmqIdColumns {
@@ -2046,35 +2313,21 @@ public class Im {
}
/**
- * Columns for IM branding resource map cache table. This table caches the result of
- * loading the branding resources to speed up IM landing page start.
+ * Columns for the s2dRmqIds table, which stores the server-to-device message
+ * persistent ids. These are used in the RMQ2 protocol, where in the login request, the
+ * client selective acks these s2d ids to the server.
*/
- public interface BrandingResourceMapCacheColumns {
- /**
- * The provider ID
- * <P>Type: INTEGER</P>
- */
- String PROVIDER_ID = "provider_id";
- /**
- * The application resource ID
- * <P>Type: INTEGER</P>
- */
- String APP_RES_ID = "app_res_id";
- /**
- * The plugin resource ID
- * <P>Type: INTEGER</P>
- */
- String PLUGIN_RES_ID = "plugin_res_id";
+ public interface ServerToDeviceRmqIdsColumn {
+ String RMQ_ID = "rmq_id";
}
- /**
- * The table for caching the result of loading IM branding resources.
- */
- public static final class BrandingResourceMapCache
- implements BaseColumns, BrandingResourceMapCacheColumns {
+ public static final class ServerToDeviceRmqIds implements BaseColumns,
+ ServerToDeviceRmqIdsColumn {
+
/**
* The content:// style URL for this table.
*/
- public static final Uri CONTENT_URI = Uri.parse("content://im/brandingResMapCache");
+ public static final Uri CONTENT_URI = Uri.parse("content://im/s2dids");
}
+
}
diff --git a/core/java/android/provider/LiveFolders.java b/core/java/android/provider/LiveFolders.java
index 6e95fb7..19f361b 100644
--- a/core/java/android/provider/LiveFolders.java
+++ b/core/java/android/provider/LiveFolders.java
@@ -45,7 +45,7 @@ import android.annotation.SdkConstant;
* public static class MyLiveFolder extends Activity {
* public static final Uri CONTENT_URI = Uri.parse("content://my.app/live");
*
- * @Override
+ * &amp;#064;Override
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
*
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 21e5865..49b5bb1 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -164,6 +164,12 @@ public final class MediaStore
public final static String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
/**
+ * Specify the maximum allowed recording duration in seconds.
+ * @hide
+ */
+ public final static String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
+
+ /**
* The name of the Intent-extra used to indicate a content resolver Uri to be used to
* store the requested image or video.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4a4d2de..77d1740 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -413,8 +413,6 @@ public final class Settings {
private static final String TAG = "Settings";
- private static String sJidResource = null;
-
public static class SettingNotFoundException extends AndroidException {
public SettingNotFoundException(String msg) {
super(msg);
@@ -879,6 +877,17 @@ public final class Settings {
public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
/**
+ * A comma separated list of radios that should to be disabled when airplane mode
+ * is on, but can be manually reenabled by the user. For example, if RADIO_WIFI is
+ * added to both AIRPLANE_MODE_RADIOS and AIRPLANE_MODE_TOGGLEABLE_RADIOS, then Wifi
+ * will be turned off when entering airplane mode, but the user will be able to reenable
+ * Wifi in the Settings app.
+ *
+ * {@hide}
+ */
+ public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
+
+ /**
* The policy for deciding when Wi-Fi should go to sleep (which will in
* turn switch to using the mobile data as an Internet connection).
* <p>
@@ -1182,6 +1191,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";
@@ -1497,18 +1522,17 @@ public final class Settings {
@Deprecated
public static final String USE_GOOGLE_MAIL = Secure.USE_GOOGLE_MAIL;
-// /**
-// * @deprecated Use {@link android.provider.Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}
-// * instead
-// */
+ /**
+ * @deprecated Use
+ * {@link android.provider.Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT} instead
+ */
@Deprecated
public static final String WIFI_MAX_DHCP_RETRY_COUNT = Secure.WIFI_MAX_DHCP_RETRY_COUNT;
-// /**
-// * @deprecated Use
-// * {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}
-// * instead
-// */
+ /**
+ * @deprecated Use
+ * {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead
+ */
@Deprecated
public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS;
@@ -1968,6 +1992,12 @@ public final class Settings {
public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
/**
+ * Whether assisted GPS should be enabled or not.
+ * @hide
+ */
+ public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled";
+
+ /**
* The Logging ID (a unique 64-bit value) as a hex string.
* Used as a pseudonymous identifier for logging.
* @deprecated This identifier is poorly initialized and has
@@ -2695,7 +2725,14 @@ public final class Settings {
* Controls how many attempts Gmail will try to upload an uphill operations before it
* abandons the operation. Defaults to 20.
*/
- public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_discard_error_uphill_op";
+ public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_num_retry_uphill_op";
+
+ /**
+ * How much time in seconds Gmail will try to upload an uphill operations before it
+ * abandons the operation. Defaults to 36400 (one day).
+ */
+ public static final String GMAIL_WAIT_TIME_RETRY_UPHILL_OP =
+ "gmail_wait_time_retry_uphill_op";
/**
* Controls if the protocol buffer version of the protocol will use a multipart request for
@@ -2804,6 +2841,12 @@ 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";
+
+ /**
* How long we wait to receive a heartbeat ping acknowledgement (or another packet)
* from the GTalk server, before deeming the connection dead.
*/
@@ -2856,6 +2899,104 @@ public final class Settings {
public static final String GTALK_USE_BARE_JID_TIMEOUT_MS = "gtalk_use_barejid_timeout_ms";
/**
+ * This is the threshold of retry number when there is an authentication expired failure
+ * for Google Talk. In some situation, e.g. when a Google Apps account is disabled chat
+ * service, the connection keeps failing. This threshold controls when we should stop
+ * the retrying.
+ */
+ public static final String GTALK_MAX_RETRIES_FOR_AUTH_EXPIRED =
+ "gtalk_max_retries_for_auth_expired";
+
+ /**
+ * a boolean setting indicating whether the GTalkService should use RMQ2 protocol or not.
+ */
+ public static final String GTALK_USE_RMQ2_PROTOCOL =
+ "gtalk_use_rmq2";
+
+ /**
+ * a boolean setting indicating whether the GTalkService should support both RMQ and
+ * RMQ2 protocols. This setting is true for the transitional period when we need to
+ * support both protocols.
+ */
+ public static final String GTALK_SUPPORT_RMQ_AND_RMQ2_PROTOCOLS =
+ "gtalk_support_rmq_and_rmq2";
+
+ /**
+ * a boolean setting controlling whether the rmq2 protocol will include stream ids in
+ * the protobufs. This is used for debugging.
+ */
+ public static final String GTALK_RMQ2_INCLUDE_STREAM_ID =
+ "gtalk_rmq2_include_stream_id";
+
+ /**
+ * when receiving a chat message from the server, the message could be an older message
+ * whose "time sent" is x seconds from now. If x is significant enough, we want to flag
+ * it so the UI can give it some special treatment when displaying the "time sent" for
+ * it. This setting is to control what x is.
+ */
+ public static final String GTALK_OLD_CHAT_MESSAGE_THRESHOLD_IN_SEC =
+ "gtalk_old_chat_msg_threshold_in_sec";
+
+ /**
+ * a setting to control the max connection history record GTalkService stores.
+ */
+ public static final String GTALK_MAX_CONNECTION_HISTORY_RECORDS =
+ "gtalk_max_conn_history_records";
+
+ /**
+ * This is gdata url to lookup album and picture info from picasa web.
+ */
+ public static final String GTALK_PICASA_ALBUM_URL =
+ "gtalk_picasa_album_url";
+
+ /**
+ * This is the url to lookup picture info from flickr.
+ */
+ public static final String GTALK_FLICKR_PHOTO_INFO_URL =
+ "gtalk_flickr_photo_info_url";
+
+ /**
+ * This is the url to lookup an actual picture from flickr.
+ */
+ public static final String GTALK_FLICKR_PHOTO_URL =
+ "gtalk_flickr_photo_url";
+
+ /**
+ * This is the gdata url to lookup info on a youtube video.
+ */
+ public static final String GTALK_YOUTUBE_VIDEO_URL =
+ "gtalk_youtube_video_url";
+
+ /**
+ * Chat message lifetime (for pruning old chat messages).
+ */
+ public static final String GTALK_CHAT_MESSAGE_LIFETIME =
+ "gtalk_chat_message_lifetime";
+
+ /**
+ * OTR message lifetime (for pruning old otr messages).
+ */
+ public static final String GTALK_OTR_MESSAGE_LIFETIME =
+ "gtalk_otr_message_lifetime";
+
+ /**
+ * Chat expiration time, i.e., time since last message in the chat (for pruning old chats).
+ */
+ public static final String GTALK_CHAT_EXPIRATION_TIME =
+ "gtalk_chat_expiration_time";
+
+ /**
+ * This is the url for getting the app token for server-to-device push messaging.
+ */
+ public static final String PUSH_MESSAGING_REGISTRATION_URL =
+ "push_messaging_registration_url";
+
+ /**
+ * Use android://&lt;it&gt; routing infos for Google Sync Server subcriptions.
+ */
+ public static final String GSYNC_USE_RMQ2_ROUTING_INFO = "gsync_use_rmq2_routing_info";
+
+ /**
* Enable use of ssl session caching.
* 'db' - save each session in a (per process) database
* 'file' - save each session in a (per process) file
@@ -2907,6 +3048,12 @@ public final class Settings {
"vending_require_sim_for_purchase";
/**
+ * Indicates the Vending Machine backup state. It is set if the
+ * Vending application has been backed up at least once.
+ */
+ public static final String VENDING_BACKUP_STATE = "vending_backup_state";
+
+ /**
* The current version id of the Vending Machine terms of service.
*/
public static final String VENDING_TOS_VERSION = "vending_tos_version";
@@ -2992,6 +3139,13 @@ public final class Settings {
"vending_promo_refresh_freq_ms";
/**
+ * Frequency in milliseconds when we should refresh the provisioning information from
+ * the carrier backend.
+ */
+ public static final String VENDING_CARRIER_PROVISIONING_REFRESH_FREQUENCY_MS =
+ "vending_carrier_ref_freq_ms";
+
+ /**
* URL that points to the legal terms of service to display in Settings.
* <p>
* This should be a https URL. For a pretty user-friendly URL, use
@@ -3225,39 +3379,6 @@ public final class Settings {
"short_keylight_delay_ms";
/**
- * URL that points to the voice search servers. To be factored out of this class.
- */
- public static final String VOICE_SEARCH_URL = "voice_search_url";
-
- /**
- * Speech encoding used with voice search on 3G networks. To be factored out of this class.
- */
- public static final String VOICE_SEARCH_ENCODING_THREE_G = "voice_search_encoding_three_g";
-
- /**
- * Speech encoding used with voice search on WIFI networks. To be factored out of this class.
- */
- public static final String VOICE_SEARCH_ENCODING_WIFI = "voice_search_encoding_wifi";
-
- /**
- * Whether to use automatic gain control in voice search (0 = disable, 1 = enable).
- * To be factored out of this class.
- */
- public static final String VOICE_SEARCH_ENABLE_AGC = "voice_search_enable_agc";
-
- /**
- * Whether to use noise suppression in voice search (0 = disable, 1 = enable).
- * To be factored out of this class.
- */
- public static final String VOICE_SEARCH_ENABLE_NS = "voice_search_enable_ns";
-
- /**
- * Whether to use the IIR filter in voice search (0 = disable, 1 = enable).
- * To be factored out of this class.
- */
- public static final String VOICE_SEARCH_ENABLE_IIR = "voice_search_enable_iir";
-
- /**
* List of test suites (local disk filename) for the automatic instrumentation test runner.
* The file format is similar to automated_suites.xml, see AutoTesterService.
* If this setting is missing or empty, the automatic test runner will not start.
@@ -3300,6 +3421,21 @@ public final class Settings {
public static final String USE_LOCATION_FOR_SERVICES = "use_location";
/**
+ * The length of the calendar sync window into the future.
+ * This specifies the number of days into the future for the sliding window sync.
+ * Setting this to zero will disable sliding sync.
+ */
+ public static final String GOOGLE_CALENDAR_SYNC_WINDOW_DAYS =
+ "google_calendar_sync_window_days";
+
+ /**
+ * How often to update the calendar sync window.
+ * The window will be advanced every n days.
+ */
+ public static final String GOOGLE_CALENDAR_SYNC_WINDOW_UPDATE_DAYS =
+ "google_calendar_sync_window_update_days";
+
+ /**
* @deprecated
* @hide
*/
@@ -3542,42 +3678,6 @@ public final class Settings {
}
/**
- * Returns the GTalk JID resource associated with this device.
- *
- * @return String the JID resource of the device. It uses the device IMEI in the computation
- * of the JID resource. If IMEI is not ready (i.e. telephony module not ready), we'll return
- * an empty string.
- * @hide
- */
- // TODO: we shouldn't not have a permenant Jid resource, as that's an easy target for
- // spams. We should change it once a while, like when we resubscribe to the subscription feeds
- // server.
- // (also, should this live in GTalkService?)
- public static synchronized String getJidResource() {
- if (sJidResource != null) {
- return sJidResource;
- }
-
- MessageDigest digest;
- try {
- digest = MessageDigest.getInstance("SHA-1");
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("this should never happen");
- }
-
- String deviceId = TelephonyManager.getDefault().getDeviceId();
- if (TextUtils.isEmpty(deviceId)) {
- return "";
- }
-
- byte[] hashedDeviceId = digest.digest(deviceId.getBytes());
- String id = new String(Base64.encodeBase64(hashedDeviceId), 0, 12);
- id = id.replaceAll("/", "_");
- sJidResource = JID_RESOURCE_PREFIX + id;
- return sJidResource;
- }
-
- /**
* Returns the device ID that we should use when connecting to the mobile gtalk server.
* This is a string like "android-0x1242", where the hex string is the Android ID obtained
* from the GoogleLoginService.
diff --git a/core/java/android/provider/SocialContract.java b/core/java/android/provider/SocialContract.java
new file mode 100644
index 0000000..ee271ba
--- /dev/null
+++ b/core/java/android/provider/SocialContract.java
@@ -0,0 +1,187 @@
+/*
+ * 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.content.res.Resources;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+
+/**
+ * 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 to use when creating {@link Resources} objects for
+ * this data row. This value is only designed for use when building user
+ * interfaces, and should not be used to infer the owner.
+ * <p>
+ * Type: TEXT
+ */
+ public static final String RES_PACKAGE = "res_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:// 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 {@link Uri} for the latest social activity performed by any
+ * raw contact aggregated under the specified {@link Contacts#_ID}. Will
+ * also join with most-present {@link Presence} for this aggregate.
+ */
+ public static final Uri CONTENT_CONTACT_STATUS_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "contact_status");
+
+ /**
+ * 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..8e9f402 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.name);
+ values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, account.type);
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.name, account.type, 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.name, account.type, 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/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/SyncStateContract.java b/core/java/android/provider/SyncStateContract.java
new file mode 100644
index 0000000..5c93af0
--- /dev/null
+++ b/core/java/android/provider/SyncStateContract.java
@@ -0,0 +1,125 @@
+/*
+ * 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.net.Uri;
+import android.content.ContentProviderClient;
+import android.content.ContentValues;
+import android.content.ContentProviderOperation;
+import android.accounts.Account;
+import android.database.Cursor;
+import android.os.RemoteException;
+
+/**
+ * The ContentProvider contract for associating data with ana data array account.
+ * This may be used by providers that want to store this data in a standard way.
+ */
+public class SyncStateContract {
+ public interface Columns extends BaseColumns {
+ /**
+ * A reference to the name of the account to which this data belongs
+ * <P>Type: STRING</P>
+ */
+ public static final String ACCOUNT_NAME = "account_name";
+
+ /**
+ * A reference to the type of the account to which this data belongs
+ * <P>Type: STRING</P>
+ */
+ public static final String ACCOUNT_TYPE = "account_type";
+
+ /**
+ * The sync data associated with this account.
+ * <P>Type: NONE</P>
+ */
+ public static final String DATA = "data";
+ }
+
+ public static class Constants implements Columns {
+ public static final String CONTENT_DIRECTORY = "syncstate";
+ }
+
+ public static final class Helpers {
+ private static final String[] DATA_PROJECTION = new String[]{Columns.DATA};
+ private static final String SELECT_BY_ACCOUNT =
+ Columns.ACCOUNT_NAME + "=? AND " + Columns.ACCOUNT_TYPE + "=?";
+
+ /**
+ * Get the sync state that is associated with the account or null.
+ * @param provider the {@link ContentProviderClient} that is to be used to communicate
+ * with the {@link android.content.ContentProvider} that contains the sync state.
+ * @param uri the uri of the sync state
+ * @param account the {@link Account} whose sync state should be returned
+ * @return the sync state or null if there is no sync state associated with the account
+ * @throws RemoteException if there is a failure communicating with the remote
+ * {@link android.content.ContentProvider}
+ */
+ public static byte[] get(ContentProviderClient provider, Uri uri,
+ Account account) throws RemoteException {
+ Cursor c = provider.query(uri, DATA_PROJECTION, SELECT_BY_ACCOUNT,
+ new String[]{account.name, account.type}, null);
+ try {
+ if (c.moveToNext()) {
+ return c.getBlob(c.getColumnIndexOrThrow(Columns.DATA));
+ }
+ } finally {
+ c.close();
+ }
+ return null;
+ }
+
+ /**
+ * Assigns the data array as the sync state for the given account.
+ * @param provider the {@link ContentProviderClient} that is to be used to communicate
+ * with the {@link android.content.ContentProvider} that contains the sync state.
+ * @param uri the uri of the sync state
+ * @param account the {@link Account} whose sync state should be set
+ * @param data the byte[] that contains the sync state
+ * @throws RemoteException if there is a failure communicating with the remote
+ * {@link android.content.ContentProvider}
+ */
+ public static void set(ContentProviderClient provider, Uri uri,
+ Account account, byte[] data) throws RemoteException {
+ ContentValues values = new ContentValues();
+ values.put(Columns.DATA, data);
+ values.put(Columns.ACCOUNT_NAME, account.name);
+ values.put(Columns.ACCOUNT_TYPE, account.type);
+ provider.insert(uri, values);
+ }
+
+ /**
+ * Creates and returns a ContentProviderOperation that assigns the data array as the
+ * sync state for the given account.
+ * @param uri the uri of the sync state
+ * @param account the {@link Account} whose sync state should be set
+ * @param data the byte[] that contains the sync state
+ * @return the new ContentProviderOperation that assigns the data array as the
+ * account's sync state
+ */
+ public static ContentProviderOperation newSetOperation(Uri uri,
+ Account account, byte[] data) {
+ ContentValues values = new ContentValues();
+ values.put(Columns.DATA, data);
+ return ContentProviderOperation
+ .newInsert(uri)
+ .withValue(Columns.ACCOUNT_NAME, account.name)
+ .withValue(Columns.ACCOUNT_TYPE, account.type)
+ .withValues(values)
+ .build();
+ }
+ }
+}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index c292c53..0207330 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";
}
/**
@@ -1252,6 +1264,21 @@ public final class Telephony {
}
/**
+ * Returns true if the number is a Phone number
+ *
+ * @param number the input number to be tested
+ * @return true if number is a Phone number
+ */
+ public static boolean isPhoneNumber(String number) {
+ if (TextUtils.isEmpty(number)) {
+ return false;
+ }
+
+ Matcher match = Regex.PHONE_PATTERN.matcher(number);
+ return match.matches();
+ }
+
+ /**
* Contains all MMS messages in the MMS app's inbox.
*/
public static final class Inbox implements BaseMmsColumns {
@@ -1416,6 +1443,8 @@ public final class Telephony {
*/
public static final String _DATA = "_data";
+ public static final String TEXT = "text";
+
}
public static final class Rate {
@@ -1493,6 +1522,14 @@ public final class Telephony {
public static final Uri CONTENT_DRAFT_URI = Uri.parse(
"content://mms-sms/draft");
+ /***
+ * Pass in a query parameter called "pattern" which is the text
+ * to search for.
+ * The sort order is fixed to be thread_id ASC,date DESC.
+ */
+ public static final Uri SEARCH_URI = Uri.parse(
+ "content://mms-sms/search");
+
// Constants for message protocol types.
public static final int SMS_PROTO = 0;
public static final int MMS_PROTO = 1;
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 5c4e56d..d9fcb53 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -23,17 +23,17 @@
package android.server;
import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothIntent;
+import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothA2dp;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
import android.media.AudioManager;
-import android.os.Binder;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
@@ -41,9 +41,10 @@ import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private static final String TAG = "BluetoothA2dpService";
@@ -54,75 +55,40 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
- private static final String A2DP_SINK_ADDRESS = "a2dp_sink_address";
private static final String BLUETOOTH_ENABLED = "bluetooth_enabled";
private static final int MESSAGE_CONNECT_TO = 1;
- private static final int MESSAGE_DISCONNECT = 2;
- private final Context mContext;
- private final IntentFilter mIntentFilter;
- private HashMap<String, SinkState> mAudioDevices;
- private final AudioManager mAudioManager;
- private final BluetoothDevice mBluetooth;
-
- // list of disconnected sinks to process after a delay
- private final ArrayList<String> mPendingDisconnects = new ArrayList<String>();
- // number of active sinks
- private int mSinkCount = 0;
-
- private class SinkState {
- public String address;
- public int state;
- public SinkState(String a, int s) {address = a; state = s;}
- }
+ private static final String PROPERTY_STATE = "State";
- public BluetoothA2dpService(Context context) {
- mContext = context;
+ private static final String SINK_STATE_DISCONNECTED = "disconnected";
+ private static final String SINK_STATE_CONNECTING = "connecting";
+ private static final String SINK_STATE_CONNECTED = "connected";
+ private static final String SINK_STATE_PLAYING = "playing";
- mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ private static int mSinkCount;
- mBluetooth = (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
- if (mBluetooth == null) {
- throw new RuntimeException("Platform does not support Bluetooth");
- }
-
- if (!initNative()) {
- throw new RuntimeException("Could not init BluetoothA2dpService");
- }
-
- mIntentFilter = new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
- mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
- mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
- mContext.registerReceiver(mReceiver, mIntentFilter);
-
- if (mBluetooth.isEnabled()) {
- onBluetoothEnable();
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- cleanupNative();
- } finally {
- super.finalize();
- }
- }
+ private final Context mContext;
+ private final IntentFilter mIntentFilter;
+ private HashMap<BluetoothDevice, Integer> mAudioDevices;
+ private final AudioManager mAudioManager;
+ private final BluetoothService mBluetoothService;
+ private final BluetoothAdapter mAdapter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
+ BluetoothDevice device =
+ intent.getParcelableExtra(BluetoothIntent.DEVICE);
if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
BluetoothError.ERROR);
switch (state) {
- case BluetoothDevice.BLUETOOTH_STATE_ON:
+ case BluetoothAdapter.BLUETOOTH_STATE_ON:
onBluetoothEnable();
break;
- case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
+ case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF:
onBluetoothDisable();
break;
}
@@ -131,99 +97,187 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
BluetoothError.ERROR);
switch(bondState) {
case BluetoothDevice.BOND_BONDED:
- setSinkPriority(address, BluetoothA2dp.PRIORITY_AUTO);
+ setSinkPriority(device, BluetoothA2dp.PRIORITY_AUTO);
break;
case BluetoothDevice.BOND_BONDING:
case BluetoothDevice.BOND_NOT_BONDED:
- setSinkPriority(address, BluetoothA2dp.PRIORITY_OFF);
+ setSinkPriority(device, BluetoothA2dp.PRIORITY_OFF);
break;
}
} else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION)) {
- if (getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF) {
+ if (getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF &&
+ isSinkDevice(device)) {
// This device is a preferred sink. Make an A2DP connection
// after a delay. We delay to avoid connection collisions,
// and to give other profiles such as HFP a chance to
// connect first.
- Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, address);
+ Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, device);
mHandler.sendMessageDelayed(msg, 6000);
}
}
}
};
+ public BluetoothA2dpService(Context context, BluetoothService bluetoothService) {
+ mContext = context;
+
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+
+ mBluetoothService = bluetoothService;
+ if (mBluetoothService == null) {
+ throw new RuntimeException("Platform does not support Bluetooth");
+ }
+
+ if (!initNative()) {
+ throw new RuntimeException("Could not init BluetoothA2dpService");
+ }
+
+ mAdapter = (BluetoothAdapter) context.getSystemService(Context.BLUETOOTH_SERVICE);
+
+ mIntentFilter = new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
+ mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
+ mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
+ mContext.registerReceiver(mReceiver, mIntentFilter);
+
+ mAudioDevices = new HashMap<BluetoothDevice, Integer>();
+
+ if (mBluetoothService.isEnabled())
+ onBluetoothEnable();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ cleanupNative();
+ } finally {
+ super.finalize();
+ }
+ }
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_CONNECT_TO:
- String address = (String)msg.obj;
+ BluetoothDevice device = (BluetoothDevice) msg.obj;
// check bluetooth is still on, device is still preferred, and
// nothing is currently connected
- if (mBluetooth.isEnabled() &&
- getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF &&
+ if (mBluetoothService.isEnabled() &&
+ getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF &&
lookupSinksMatchingStates(new int[] {
BluetoothA2dp.STATE_CONNECTING,
BluetoothA2dp.STATE_CONNECTED,
BluetoothA2dp.STATE_PLAYING,
BluetoothA2dp.STATE_DISCONNECTING}).size() == 0) {
- log("Auto-connecting A2DP to sink " + address);
- connectSink(address);
+ log("Auto-connecting A2DP to sink " + device);
+ connectSink(device);
}
break;
- case MESSAGE_DISCONNECT:
- handleDeferredDisconnect((String)msg.obj);
- break;
}
}
};
+ private int convertBluezSinkStringtoState(String value) {
+ if (value.equalsIgnoreCase("disconnected"))
+ return BluetoothA2dp.STATE_DISCONNECTED;
+ if (value.equalsIgnoreCase("connecting"))
+ return BluetoothA2dp.STATE_CONNECTING;
+ if (value.equalsIgnoreCase("connected"))
+ return BluetoothA2dp.STATE_CONNECTED;
+ if (value.equalsIgnoreCase("playing"))
+ return BluetoothA2dp.STATE_PLAYING;
+ return -1;
+ }
+
+ private boolean isSinkDevice(BluetoothDevice device) {
+ String uuids[] = mBluetoothService.getRemoteUuids(device.getAddress());
+ UUID uuid;
+ if (uuids != null) {
+ for (String deviceUuid: uuids) {
+ uuid = UUID.fromString(deviceUuid);
+ if (BluetoothUuid.isAudioSink(uuid)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private synchronized boolean addAudioSink (BluetoothDevice device) {
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
+ String propValues[] = (String []) getSinkPropertiesNative(path);
+ if (propValues == null) {
+ Log.e(TAG, "Error while getting AudioSink properties for device: " + device);
+ return false;
+ }
+ Integer state = null;
+ // Properties are name-value pairs
+ for (int i = 0; i < propValues.length; i+=2) {
+ if (propValues[i].equals(PROPERTY_STATE)) {
+ state = new Integer(convertBluezSinkStringtoState(propValues[i+1]));
+ break;
+ }
+ }
+ mAudioDevices.put(device, state);
+ handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTED, state);
+ return true;
+ }
+
private synchronized void onBluetoothEnable() {
- mAudioDevices = new HashMap<String, SinkState>();
- String[] paths = (String[])listHeadsetsNative();
- if (paths != null) {
- for (String path : paths) {
- mAudioDevices.put(path, new SinkState(getAddressNative(path),
- isSinkConnectedNative(path) ? BluetoothA2dp.STATE_CONNECTED :
- BluetoothA2dp.STATE_DISCONNECTED));
+ String devices = mBluetoothService.getProperty("Devices");
+ mSinkCount = 0;
+ if (devices != null) {
+ String [] paths = devices.split(",");
+ for (String path: paths) {
+ String address = mBluetoothService.getAddressFromObjectPath(path);
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ String []uuids = mBluetoothService.getRemoteUuids(address);
+ if (uuids != null)
+ for (String uuid: uuids) {
+ UUID remoteUuid = UUID.fromString(uuid);
+ if (BluetoothUuid.isAudioSink(remoteUuid) ||
+ BluetoothUuid.isAudioSource(remoteUuid) ||
+ BluetoothUuid.isAdvAudioDist(remoteUuid)) {
+ addAudioSink(device);
+ break;
+ }
+ }
}
}
- mAudioManager.setParameter(BLUETOOTH_ENABLED, "true");
+ mAudioManager.setParameters(BLUETOOTH_ENABLED+"=true");
}
private synchronized void onBluetoothDisable() {
- if (mAudioDevices != null) {
- // copy to allow modification during iteration
- String[] paths = new String[mAudioDevices.size()];
- paths = mAudioDevices.keySet().toArray(paths);
- for (String path : paths) {
- switch (mAudioDevices.get(path).state) {
+ if (!mAudioDevices.isEmpty()) {
+ BluetoothDevice[] devices = new BluetoothDevice[mAudioDevices.size()];
+ devices = mAudioDevices.keySet().toArray(devices);
+ for (BluetoothDevice device : devices) {
+ int state = getSinkState(device);
+ switch (state) {
case BluetoothA2dp.STATE_CONNECTING:
case BluetoothA2dp.STATE_CONNECTED:
case BluetoothA2dp.STATE_PLAYING:
- disconnectSinkNative(path);
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+ disconnectSinkNative(mBluetoothService.getObjectPathFromAddress(
+ device.getAddress()));
+ handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED);
break;
case BluetoothA2dp.STATE_DISCONNECTING:
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+ handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTING,
+ BluetoothA2dp.STATE_DISCONNECTED);
break;
}
}
- mAudioDevices = null;
+ mAudioDevices.clear();
}
- mAudioManager.setBluetoothA2dpOn(false);
- mAudioManager.setParameter(BLUETOOTH_ENABLED, "false");
+
+ mAudioManager.setParameters(BLUETOOTH_ENABLED + "=false");
}
- public synchronized int connectSink(String address) {
+ public synchronized int connectSink(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- if (DBG) log("connectSink(" + address + ")");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return BluetoothError.ERROR;
- }
- if (mAudioDevices == null) {
- return BluetoothError.ERROR;
- }
+ if (DBG) log("connectSink(" + device + ")");
+
// ignore if there are any active sinks
if (lookupSinksMatchingStates(new int[] {
BluetoothA2dp.STATE_CONNECTING,
@@ -233,20 +287,11 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return BluetoothError.ERROR;
}
- String path = lookupPath(address);
- if (path == null) {
- path = createHeadsetNative(address);
- if (DBG) log("new bluez sink: " + address + " (" + path + ")");
- }
- if (path == null) {
+ if (mAudioDevices.get(device) == null && !addAudioSink(device))
return BluetoothError.ERROR;
- }
- SinkState sink = mAudioDevices.get(path);
- int state = BluetoothA2dp.STATE_DISCONNECTED;
- if (sink != null) {
- state = sink.state;
- }
+ int state = mAudioDevices.get(device);
+
switch (state) {
case BluetoothA2dp.STATE_CONNECTED:
case BluetoothA2dp.STATE_PLAYING:
@@ -256,29 +301,28 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return BluetoothError.SUCCESS;
}
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
+ if (path == null)
+ return BluetoothError.ERROR;
+
// State is DISCONNECTED
if (!connectSinkNative(path)) {
return BluetoothError.ERROR;
}
- updateState(path, BluetoothA2dp.STATE_CONNECTING);
return BluetoothError.SUCCESS;
}
- public synchronized int disconnectSink(String address) {
+ public synchronized int disconnectSink(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- if (DBG) log("disconnectSink(" + address + ")");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return BluetoothError.ERROR;
- }
- if (mAudioDevices == null) {
- return BluetoothError.ERROR;
- }
- String path = lookupPath(address);
+ if (DBG) log("disconnectSink(" + device + ")");
+
+ String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (path == null) {
return BluetoothError.ERROR;
}
- switch (mAudioDevices.get(path).state) {
+
+ switch (getSinkState(device)) {
case BluetoothA2dp.STATE_DISCONNECTED:
return BluetoothError.ERROR;
case BluetoothA2dp.STATE_DISCONNECTING:
@@ -289,151 +333,106 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
if (!disconnectSinkNative(path)) {
return BluetoothError.ERROR;
} else {
- updateState(path, BluetoothA2dp.STATE_DISCONNECTING);
return BluetoothError.SUCCESS;
}
}
- public synchronized List<String> listConnectedSinks() {
+ public synchronized BluetoothDevice[] getConnectedSinks() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return lookupSinksMatchingStates(new int[] {BluetoothA2dp.STATE_CONNECTED,
- BluetoothA2dp.STATE_PLAYING});
+ Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
+ new int[] {BluetoothA2dp.STATE_CONNECTED, BluetoothA2dp.STATE_PLAYING});
+ return sinks.toArray(new BluetoothDevice[sinks.size()]);
}
- public synchronized int getSinkState(String address) {
+ public synchronized int getSinkState(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return BluetoothError.ERROR;
- }
- if (mAudioDevices == null) {
+ Integer state = mAudioDevices.get(device);
+ if (state == null)
return BluetoothA2dp.STATE_DISCONNECTED;
- }
- for (SinkState sink : mAudioDevices.values()) {
- if (address.equals(sink.address)) {
- return sink.state;
- }
- }
- return BluetoothA2dp.STATE_DISCONNECTED;
+ return state;
}
- public synchronized int getSinkPriority(String address) {
+ public synchronized int getSinkPriority(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return BluetoothError.ERROR;
- }
return Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.getBluetoothA2dpSinkPriorityKey(address),
+ Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
BluetoothA2dp.PRIORITY_OFF);
}
- public synchronized int setSinkPriority(String address, int priority) {
+ public synchronized int setSinkPriority(BluetoothDevice device, int priority) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ if (!BluetoothDevice.checkBluetoothAddress(device.getAddress())) {
return BluetoothError.ERROR;
}
return Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.getBluetoothA2dpSinkPriorityKey(address), priority) ?
+ Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority) ?
BluetoothError.SUCCESS : BluetoothError.ERROR;
}
- private synchronized void onHeadsetCreated(String path) {
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
- }
-
- private synchronized void onHeadsetRemoved(String path) {
- if (mAudioDevices == null) return;
- mAudioDevices.remove(path);
- }
-
- private synchronized void onSinkConnected(String path) {
- // if we are reconnected, do not process previous disconnect event.
- mPendingDisconnects.remove(path);
-
- if (mAudioDevices == null) return;
- // bluez 3.36 quietly disconnects the previous sink when a new sink
- // is connected, so we need to mark all previously connected sinks as
- // disconnected
-
- // copy to allow modification during iteration
- String[] paths = new String[mAudioDevices.size()];
- paths = mAudioDevices.keySet().toArray(paths);
- for (String oldPath : paths) {
- if (path.equals(oldPath)) {
- continue;
- }
- int state = mAudioDevices.get(oldPath).state;
- if (state == BluetoothA2dp.STATE_CONNECTED || state == BluetoothA2dp.STATE_PLAYING) {
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
- }
+ private synchronized void onSinkPropertyChanged(String path, String []propValues) {
+ if (!mBluetoothService.isEnabled()) {
+ return;
}
- updateState(path, BluetoothA2dp.STATE_CONNECTING);
- mAudioManager.setParameter(A2DP_SINK_ADDRESS, lookupAddress(path));
- mAudioManager.setBluetoothA2dpOn(true);
- updateState(path, BluetoothA2dp.STATE_CONNECTED);
- }
+ String name = propValues[0];
+ String address = mBluetoothService.getAddressFromObjectPath(path);
+ if (address == null) {
+ Log.e(TAG, "onSinkPropertyChanged: Address of the remote device in null");
+ return;
+ }
- private synchronized void onSinkDisconnected(String path) {
- // This is to work around a problem in bluez that results
- // sink disconnect events being sent, immediately followed by a reconnect.
- // To avoid unnecessary audio routing changes, we defer handling
- // sink disconnects until after a short delay.
- mPendingDisconnects.add(path);
- Message msg = Message.obtain(mHandler, MESSAGE_DISCONNECT, path);
- mHandler.sendMessageDelayed(msg, 2000);
- }
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
- private synchronized void handleDeferredDisconnect(String path) {
- if (mPendingDisconnects.contains(path)) {
- mPendingDisconnects.remove(path);
- if (mSinkCount == 1) {
- mAudioManager.setBluetoothA2dpOn(false);
+ if (name.equals(PROPERTY_STATE)) {
+ int state = convertBluezSinkStringtoState(propValues[1]);
+ if (mAudioDevices.get(device) == null) {
+ // This is for an incoming connection for a device not known to us.
+ // We have authorized it and bluez state has changed.
+ addAudioSink(device);
+ } else {
+ int prevState = mAudioDevices.get(device);
+ handleSinkStateChange(device, prevState, state);
}
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
}
}
- private synchronized void onSinkPlaying(String path) {
- updateState(path, BluetoothA2dp.STATE_PLAYING);
- }
+ private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) {
+ if (state != prevState) {
+ if (state == BluetoothA2dp.STATE_DISCONNECTED ||
+ state == BluetoothA2dp.STATE_DISCONNECTING) {
+ if (prevState == BluetoothA2dp.STATE_CONNECTED ||
+ prevState == BluetoothA2dp.STATE_PLAYING) {
+ // disconnecting or disconnected
+ Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+ }
+ mSinkCount--;
+ } else if (state == BluetoothA2dp.STATE_CONNECTED) {
+ mSinkCount ++;
+ }
+ mAudioDevices.put(device, state);
- private synchronized void onSinkStopped(String path) {
- updateState(path, BluetoothA2dp.STATE_CONNECTED);
- }
+ Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.DEVICE, device);
+ intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState);
+ intent.putExtra(BluetoothA2dp.SINK_STATE, state);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- private synchronized final String lookupAddress(String path) {
- if (mAudioDevices == null) return null;
- SinkState sink = mAudioDevices.get(path);
- if (sink == null) {
- Log.w(TAG, "lookupAddress() called for unknown device " + path);
- updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+ if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state);
}
- String address = mAudioDevices.get(path).address;
- if (address == null) Log.e(TAG, "Can't find address for " + path);
- return address;
}
- private synchronized final String lookupPath(String address) {
- if (mAudioDevices == null) return null;
-
- for (String path : mAudioDevices.keySet()) {
- if (address.equals(mAudioDevices.get(path).address)) {
- return path;
- }
- }
- return null;
- }
-
- private synchronized List<String> lookupSinksMatchingStates(int[] states) {
- List<String> sinks = new ArrayList<String>();
- if (mAudioDevices == null) {
+ private synchronized Set<BluetoothDevice> lookupSinksMatchingStates(int[] states) {
+ Set<BluetoothDevice> sinks = new HashSet<BluetoothDevice>();
+ if (mAudioDevices.isEmpty()) {
return sinks;
}
- for (SinkState sink : mAudioDevices.values()) {
+ for (BluetoothDevice device: mAudioDevices.keySet()) {
+ int sinkState = getSinkState(device);
for (int state : states) {
- if (sink.state == state) {
- sinks.add(sink.address);
+ if (state == sinkState) {
+ sinks.add(device);
break;
}
}
@@ -441,57 +440,13 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return sinks;
}
- private synchronized void updateState(String path, int state) {
- if (mAudioDevices == null) return;
-
- SinkState s = mAudioDevices.get(path);
- int prevState;
- String address;
- if (s == null) {
- address = getAddressNative(path);
- mAudioDevices.put(path, new SinkState(address, state));
- prevState = BluetoothA2dp.STATE_DISCONNECTED;
- } else {
- address = lookupAddress(path);
- prevState = s.state;
- s.state = state;
- }
-
- if (state != prevState) {
- if (DBG) log("state " + address + " (" + path + ") " + prevState + "->" + state);
-
- // keep track of the number of active sinks
- if (prevState == BluetoothA2dp.STATE_DISCONNECTED) {
- mSinkCount++;
- } else if (state == BluetoothA2dp.STATE_DISCONNECTED) {
- mSinkCount--;
- }
-
- Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState);
- intent.putExtra(BluetoothA2dp.SINK_STATE, state);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
-
- if ((prevState == BluetoothA2dp.STATE_CONNECTED ||
- prevState == BluetoothA2dp.STATE_PLAYING) &&
- (state != BluetoothA2dp.STATE_CONNECTING &&
- state != BluetoothA2dp.STATE_CONNECTED &&
- state != BluetoothA2dp.STATE_PLAYING)) {
- // disconnected
- intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- mContext.sendBroadcast(intent);
- }
- }
- }
-
@Override
protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mAudioDevices == null) return;
+ if (mAudioDevices.isEmpty()) return;
pw.println("Cached audio devices:");
- for (String path : mAudioDevices.keySet()) {
- SinkState sink = mAudioDevices.get(path);
- pw.println(path + " " + sink.address + " " + BluetoothA2dp.stateToString(sink.state));
+ for (BluetoothDevice device : mAudioDevices.keySet()) {
+ int state = mAudioDevices.get(device);
+ pw.println(device + " " + BluetoothA2dp.stateToString(state));
}
}
@@ -501,11 +456,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private native boolean initNative();
private native void cleanupNative();
- private synchronized native String[] listHeadsetsNative();
- private synchronized native String createHeadsetNative(String address);
- private synchronized native boolean removeHeadsetNative(String path);
- private synchronized native String getAddressNative(String path);
private synchronized native boolean connectSinkNative(String path);
private synchronized native boolean disconnectSinkNative(String path);
- private synchronized native boolean isSinkConnectedNative(String path);
+ private synchronized native Object []getSinkPropertiesNative(String path);
}
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
deleted file mode 100644
index 8c843ef..0000000
--- a/core/java/android/server/BluetoothDeviceService.java
+++ /dev/null
@@ -1,1263 +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.
- */
-
-/**
- * TODO: Move this to
- * java/services/com/android/server/BluetoothDeviceService.java
- * and make the contructor package private again.
- *
- * @hide
- */
-
-package android.server;
-
-import android.bluetooth.BluetoothClass;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothError;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothIntent;
-import android.bluetooth.IBluetoothDevice;
-import android.bluetooth.IBluetoothDeviceCallback;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemService;
-import android.provider.Settings;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import com.android.internal.app.IBatteryStats;
-
-public class BluetoothDeviceService extends IBluetoothDevice.Stub {
- private static final String TAG = "BluetoothDeviceService";
- private static final boolean DBG = true;
-
- private int mNativeData;
- private BluetoothEventLoop mEventLoop;
- private IntentFilter mIntentFilter;
- private boolean mIsAirplaneSensitive;
- private int mBluetoothState;
- private boolean mRestart = false; // need to call enable() after disable()
-
- private final BondState mBondState = new BondState(); // local cache of bondings
- private boolean mIsDiscovering;
- private final IBatteryStats mBatteryStats;
-
- private final Context mContext;
-
- private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
- private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
-
- private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
- private static final int MESSAGE_FINISH_DISABLE = 2;
-
- static {
- classInitNative();
- }
- private native static void classInitNative();
-
- public BluetoothDeviceService(Context context) {
- mContext = context;
-
- // Need to do this in place of:
- // mBatteryStats = BatteryStatsService.getService();
- // Since we can not import BatteryStatsService from here. This class really needs to be
- // moved to java/services/com/android/server/
- mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
- }
-
- /** Must be called after construction, and before any other method.
- */
- public synchronized void init() {
- initializeNativeDataNative();
-
- if (isEnabledNative() == 1) {
- Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
- disableNative();
- }
-
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF);
- mIsDiscovering = false;
- mEventLoop = new BluetoothEventLoop(mContext, this);
- registerForAirplaneMode();
- }
- private native void initializeNativeDataNative();
-
- @Override
- protected void finalize() throws Throwable {
- if (mIsAirplaneSensitive) {
- mContext.unregisterReceiver(mReceiver);
- }
- try {
- cleanupNativeDataNative();
- } finally {
- super.finalize();
- }
- }
- private native void cleanupNativeDataNative();
-
- public boolean isEnabled() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothState == BluetoothDevice.BLUETOOTH_STATE_ON;
- }
- private native int isEnabledNative();
-
- public int getBluetoothState() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothState;
- }
-
-
- /**
- * Bring down bluetooth and disable BT in settings. Returns true on success.
- */
- public boolean disable() {
- return disable(true);
- }
-
- /**
- * Bring down bluetooth. Returns true on success.
- *
- * @param saveSetting If true, disable BT in settings
- */
- public synchronized boolean disable(boolean saveSetting) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
-
- switch (mBluetoothState) {
- case BluetoothDevice.BLUETOOTH_STATE_OFF:
- return true;
- case BluetoothDevice.BLUETOOTH_STATE_ON:
- break;
- default:
- return false;
- }
- if (mEnableThread != null && mEnableThread.isAlive()) {
- return false;
- }
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF);
-
- // Allow 3 seconds for profiles to gracefully disconnect
- // TODO: Introduce a callback mechanism so that each profile can notify
- // BluetoothDeviceService when it is done shutting down
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
- return true;
- }
-
-
- private synchronized void finishDisable(boolean saveSetting) {
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) {
- return;
- }
- mEventLoop.stop();
- disableNative();
-
- // mark in progress bondings as cancelled
- for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
- mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
- BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
- }
-
- // Remove remoteServiceChannelCallbacks
- HashMap<String, IBluetoothDeviceCallback> callbacksMap =
- mEventLoop.getRemoteServiceChannelCallbacks();
-
- for (Iterator<String> i = callbacksMap.keySet().iterator(); i.hasNext();) {
- String address = i.next();
- IBluetoothDeviceCallback callback = callbacksMap.get(address);
- try {
- callback.onGetRemoteServiceChannelResult(address, BluetoothError.ERROR_DISABLED);
- } catch (RemoteException e) {}
- i.remove();
- }
-
- // update mode
- Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothDevice.SCAN_MODE_NONE);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
-
- mIsDiscovering = false;
-
- if (saveSetting) {
- persistBluetoothOnSetting(false);
- }
-
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_OFF);
-
- // Log bluetooth off to battery stats.
- long ident = Binder.clearCallingIdentity();
- try {
- mBatteryStats.noteBluetoothOff();
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- if (mRestart) {
- mRestart = false;
- enable();
- }
- }
-
- /** Bring up BT and persist BT on in settings */
- public boolean enable() {
- return enable(true);
- }
-
- /**
- * Enable this Bluetooth device, asynchronously.
- * This turns on/off the underlying hardware.
- *
- * @param saveSetting If true, persist the new state of BT in settings
- * @return True on success (so far)
- */
- public synchronized boolean enable(boolean saveSetting) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
-
- // Airplane mode can prevent Bluetooth radio from being turned on.
- if (mIsAirplaneSensitive && isAirplaneModeOn()) {
- return false;
- }
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_OFF) {
- return false;
- }
- if (mEnableThread != null && mEnableThread.isAlive()) {
- return false;
- }
- setBluetoothState(BluetoothDevice.BLUETOOTH_STATE_TURNING_ON);
- mEnableThread = new EnableThread(saveSetting);
- mEnableThread.start();
- return true;
- }
-
- /** Forcibly restart Bluetooth if it is on */
- /* package */ synchronized void restart() {
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_ON) {
- return;
- }
- mRestart = true;
- if (!disable(false)) {
- mRestart = false;
- }
- }
-
- private synchronized void setBluetoothState(int state) {
- if (state == mBluetoothState) {
- return;
- }
-
- if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
-
- Intent intent = new Intent(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.BLUETOOTH_PREVIOUS_STATE, mBluetoothState);
- intent.putExtra(BluetoothIntent.BLUETOOTH_STATE, state);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-
- mBluetoothState = state;
-
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_REGISTER_SDP_RECORDS:
- //TODO: Don't assume HSP/HFP is running, don't use sdptool,
- if (isEnabled()) {
- SystemService.start("hsag");
- SystemService.start("hfag");
- }
- break;
- case MESSAGE_FINISH_DISABLE:
- finishDisable(msg.arg1 != 0);
- break;
- }
- }
- };
-
- private EnableThread mEnableThread;
-
- private class EnableThread extends Thread {
- private final boolean mSaveSetting;
- public EnableThread(boolean saveSetting) {
- mSaveSetting = saveSetting;
- }
- public void run() {
- boolean res = (enableNative() == 0);
- if (res) {
- int retryCount = 2;
- boolean running = false;
- while ((retryCount-- > 0) && !running) {
- mEventLoop.start();
- // it may take a momement for the other thread to do its
- // thing. Check periodically for a while.
- int pollCount = 5;
- while ((pollCount-- > 0) && !running) {
- if (mEventLoop.isEventLoopRunning()) {
- running = true;
- break;
- }
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {}
- }
- }
- if (!running) {
- log("bt EnableThread giving up");
- res = false;
- disableNative();
- }
- }
-
-
- if (res) {
- if (mSaveSetting) {
- persistBluetoothOnSetting(true);
- }
- mIsDiscovering = false;
- mBondState.loadBondState();
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS),
- 3000);
-
- // Log bluetooth on to battery stats.
- long ident = Binder.clearCallingIdentity();
- try {
- mBatteryStats.noteBluetoothOn();
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- mEnableThread = null;
-
- setBluetoothState(res ?
- BluetoothDevice.BLUETOOTH_STATE_ON :
- BluetoothDevice.BLUETOOTH_STATE_OFF);
-
- if (res) {
- // Update mode
- mEventLoop.onModeChanged(getModeNative());
- }
-
- if (mIsAirplaneSensitive && isAirplaneModeOn()) {
- disable(false);
- }
-
- }
- }
-
- private void persistBluetoothOnSetting(boolean bluetoothOn) {
- long origCallerIdentityToken = Binder.clearCallingIdentity();
- Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
- bluetoothOn ? 1 : 0);
- Binder.restoreCallingIdentity(origCallerIdentityToken);
- }
-
- private native int enableNative();
- private native int disableNative();
-
- /* package */ BondState getBondState() {
- return mBondState;
- }
-
- /** local cache of bonding state.
- /* we keep our own state to track the intermediate state BONDING, which
- /* bluez does not track.
- * All addreses must be passed in upper case.
- */
- public class BondState {
- private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
- private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
- private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>();
- // List of all the vendor_id prefix of Bluetooth addresses for
- // which auto pairing is not attempted.
- // The following companies are included in the list below:
- // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi),
- // Parrot, Zhongshan General K-mate Electronics, Great Well
- // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi,
- // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura),
- // Continental Automotive, Harman/Becker
- private final ArrayList<String> mAutoPairingBlacklisted =
- new ArrayList<String>(Arrays.asList(
- "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F",
- "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8",
- "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04",
- "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59",
- "00:0A:30", "00:1E:AE", "00:1C:D7"
- ));
-
- public synchronized void loadBondState() {
- if (mBluetoothState != BluetoothDevice.BLUETOOTH_STATE_TURNING_ON) {
- return;
- }
- String[] bonds = listBondingsNative();
- if (bonds == null) {
- return;
- }
- mState.clear();
- if (DBG) log("found " + bonds.length + " bonded devices");
- for (String address : bonds) {
- mState.put(address.toUpperCase(), BluetoothDevice.BOND_BONDED);
- }
- }
-
- public synchronized void setBondState(String address, int state) {
- setBondState(address, state, 0);
- }
-
- /** reason is ignored unless state == BOND_NOT_BONDED */
- public synchronized void setBondState(String address, int state, int reason) {
- int oldState = getBondState(address);
- if (oldState == state) {
- return;
- }
- if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
- reason + ")");
- Intent intent = new Intent(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothIntent.BOND_STATE, state);
- intent.putExtra(BluetoothIntent.BOND_PREVIOUS_STATE, oldState);
- if (state == BluetoothDevice.BOND_NOT_BONDED) {
- if (reason <= 0) {
- Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
- "invalid. Overriding reason code with BOND_RESULT_REMOVED");
- reason = BluetoothDevice.UNBOND_REASON_REMOVED;
- }
- intent.putExtra(BluetoothIntent.REASON, reason);
- mState.remove(address);
- } else {
- mState.put(address, state);
- }
-
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
-
- public boolean isAutoPairingBlacklisted(String address) {
- for (String blacklistAddress : mAutoPairingBlacklisted) {
- if (address.startsWith(blacklistAddress)) return true;
- }
- return false;
- }
-
- public synchronized int getBondState(String address) {
- Integer state = mState.get(address);
- if (state == null) {
- return BluetoothDevice.BOND_NOT_BONDED;
- }
- return state.intValue();
- }
-
- private synchronized String[] listInState(int state) {
- ArrayList<String> result = new ArrayList<String>(mState.size());
- for (Map.Entry<String, Integer> e : mState.entrySet()) {
- if (e.getValue().intValue() == state) {
- result.add(e.getKey());
- }
- }
- return result.toArray(new String[result.size()]);
- }
-
- public synchronized void addAutoPairingFailure(String address) {
- if (!mAutoPairingFailures.contains(address)) {
- mAutoPairingFailures.add(address);
- }
- }
-
- public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
- return getAttempt(address) != 0;
- }
-
- public synchronized void clearPinAttempts(String address) {
- mPinAttempt.remove(address);
- }
-
- public synchronized boolean hasAutoPairingFailed(String address) {
- return mAutoPairingFailures.contains(address);
- }
-
- public synchronized int getAttempt(String address) {
- Integer attempt = mPinAttempt.get(address);
- if (attempt == null) {
- return 0;
- }
- return attempt.intValue();
- }
-
- public synchronized void attempt(String address) {
- Integer attempt = mPinAttempt.get(address);
- int newAttempt;
- if (attempt == null) {
- newAttempt = 1;
- } else {
- newAttempt = attempt.intValue() + 1;
- }
- mPinAttempt.put(address, new Integer(newAttempt));
- }
-
- }
- private native String[] listBondingsNative();
-
- private static String toBondStateString(int bondState) {
- switch (bondState) {
- case BluetoothDevice.BOND_NOT_BONDED:
- return "not bonded";
- case BluetoothDevice.BOND_BONDING:
- return "bonding";
- case BluetoothDevice.BOND_BONDED:
- return "bonded";
- default:
- return "??????";
- }
- }
-
- public synchronized String getAddress() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getAddressNative();
- }
- private native String getAddressNative();
-
- public synchronized String getName() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getNameNative();
- }
- private native String getNameNative();
-
- public synchronized boolean setName(String name) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (name == null) {
- return false;
- }
- // hcid handles persistance of the bluetooth name
- return setNameNative(name);
- }
- private native boolean setNameNative(String name);
-
- /**
- * Returns the user-friendly name of a remote device. This value is
- * retrned from our local cache, which is updated during device discovery.
- * Do not expect to retrieve the updated remote name immediately after
- * changing the name on the remote device.
- *
- * @param address Bluetooth address of remote device.
- *
- * @return The user-friendly name of the specified remote device.
- */
- public synchronized String getRemoteName(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteNameNative(address);
- }
- private native String getRemoteNameNative(String address);
-
- /* pacakge */ native String getAdapterPathNative();
-
- public synchronized boolean startDiscovery(boolean resolveNames) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- return startDiscoveryNative(resolveNames);
- }
- private native boolean startDiscoveryNative(boolean resolveNames);
-
- public synchronized boolean cancelDiscovery() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- return cancelDiscoveryNative();
- }
- private native boolean cancelDiscoveryNative();
-
- public synchronized boolean isDiscovering() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mIsDiscovering;
- }
-
- /* package */ void setIsDiscovering(boolean isDiscovering) {
- mIsDiscovering = isDiscovering;
- }
-
- public synchronized boolean startPeriodicDiscovery() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- return startPeriodicDiscoveryNative();
- }
- private native boolean startPeriodicDiscoveryNative();
-
- public synchronized boolean stopPeriodicDiscovery() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- return stopPeriodicDiscoveryNative();
- }
- private native boolean stopPeriodicDiscoveryNative();
-
- public synchronized boolean isPeriodicDiscovery() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return isPeriodicDiscoveryNative();
- }
- private native boolean isPeriodicDiscoveryNative();
-
- /**
- * Set the discoverability window for the device. A timeout of zero
- * makes the device permanently discoverable (if the device is
- * discoverable). Setting the timeout to a nonzero value does not make
- * a device discoverable; you need to call setMode() to make the device
- * explicitly discoverable.
- *
- * @param timeout_s The discoverable timeout in seconds.
- */
- public synchronized boolean setDiscoverableTimeout(int timeout) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- return setDiscoverableTimeoutNative(timeout);
- }
- private native boolean setDiscoverableTimeoutNative(int timeout_s);
-
- /**
- * Get the discoverability window for the device. A timeout of zero
- * means that the device is permanently discoverable (if the device is
- * in the discoverable mode).
- *
- * @return The discoverability window of the device, in seconds. A negative
- * value indicates an error.
- */
- public synchronized int getDiscoverableTimeout() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getDiscoverableTimeoutNative();
- }
- private native int getDiscoverableTimeoutNative();
-
- public synchronized boolean isAclConnected(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- return isConnectedNative(address);
- }
- private native boolean isConnectedNative(String address);
-
- public synchronized int getScanMode() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return bluezStringToScanMode(getModeNative());
- }
- private native String getModeNative();
-
- public synchronized boolean setScanMode(int mode) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- String bluezMode = scanModeToBluezString(mode);
- if (bluezMode != null) {
- return setModeNative(bluezMode);
- }
- return false;
- }
- private native boolean setModeNative(String mode);
-
- public synchronized boolean disconnectRemoteDeviceAcl(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- return disconnectRemoteDeviceNative(address);
- }
- private native boolean disconnectRemoteDeviceNative(String address);
-
- public synchronized boolean createBond(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- address = address.toUpperCase();
-
- String[] bonding = mBondState.listInState(BluetoothDevice.BOND_BONDING);
- if (bonding.length > 0 && !bonding[0].equals(address)) {
- log("Ignoring createBond(): another device is bonding");
- // a different device is currently bonding, fail
- return false;
- }
-
- // Check for bond state only if we are not performing auto
- // pairing exponential back-off attempts.
- if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
- mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
- log("Ignoring createBond(): this device is already bonding or bonded");
- return false;
- }
-
- if (!createBondingNative(address, 60000 /* 1 minute */)) {
- return false;
- }
-
- mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
- return true;
- }
- private native boolean createBondingNative(String address, int timeout_ms);
-
- public synchronized boolean cancelBondProcess(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- address = address.toUpperCase();
- if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
- return false;
- }
-
- mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
- BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
- cancelBondingProcessNative(address);
- return true;
- }
- private native boolean cancelBondingProcessNative(String address);
-
- public synchronized boolean removeBond(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- return removeBondingNative(address);
- }
- private native boolean removeBondingNative(String address);
-
- public synchronized String[] listBonds() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBondState.listInState(BluetoothDevice.BOND_BONDED);
- }
-
- public synchronized int getBondState(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return BluetoothError.ERROR;
- }
- return mBondState.getBondState(address.toUpperCase());
- }
-
- public synchronized String[] listAclConnections() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return listConnectionsNative();
- }
- private native String[] listConnectionsNative();
-
- /**
- * This method lists all remote devices that this adapter is aware of.
- * This is a list not only of all most-recently discovered devices, but of
- * all devices discovered by this adapter up to some point in the past.
- * Note that many of these devices may not be in the neighborhood anymore,
- * and attempting to connect to them will result in an error.
- *
- * @return An array of strings representing the Bluetooth addresses of all
- * remote devices that this adapter is aware of.
- */
- public synchronized String[] listRemoteDevices() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return listRemoteDevicesNative();
- }
- private native String[] listRemoteDevicesNative();
-
- /**
- * Returns the version of the Bluetooth chip. This version is compiled from
- * the LMP version. In case of EDR the features attribute must be checked.
- * Example: "Bluetooth 2.0 + EDR".
- *
- * @return a String representation of the this Adapter's underlying
- * Bluetooth-chip version.
- */
- public synchronized String getVersion() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getVersionNative();
- }
- private native String getVersionNative();
-
- /**
- * Returns the revision of the Bluetooth chip. This is a vendor-specific
- * value and in most cases it represents the firmware version. This might
- * derive from the HCI revision and LMP subversion values or via extra
- * vendord specific commands.
- * In case the revision of a chip is not available. This method should
- * return the LMP subversion value as a string.
- * Example: "HCI 19.2"
- *
- * @return The HCI revision of this adapter.
- */
- public synchronized String getRevision() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getRevisionNative();
- }
- private native String getRevisionNative();
-
- /**
- * Returns the manufacturer of the Bluetooth chip. If the company id is not
- * known the sting "Company ID %d" where %d should be replaced with the
- * numeric value from the manufacturer field.
- * Example: "Cambridge Silicon Radio"
- *
- * @return Manufacturer name.
- */
- public synchronized String getManufacturer() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getManufacturerNative();
- }
- private native String getManufacturerNative();
-
- /**
- * Returns the company name from the OUI database of the Bluetooth device
- * address. This function will need a valid and up-to-date oui.txt from
- * the IEEE. This value will be different from the manufacturer string in
- * the most cases.
- * If the oui.txt file is not present or the OUI part of the Bluetooth
- * address is not listed, it should return the string "OUI %s" where %s is
- * the actual OUI.
- *
- * Example: "Apple Computer"
- *
- * @return company name
- */
- public synchronized String getCompany() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getCompanyNative();
- }
- private native String getCompanyNative();
-
- /**
- * Like getVersion(), but for a remote device.
- *
- * @param address The Bluetooth address of the remote device.
- *
- * @return remote-device Bluetooth version
- *
- * @see #getVersion
- */
- public synchronized String getRemoteVersion(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteVersionNative(address);
- }
- private native String getRemoteVersionNative(String address);
-
- /**
- * Like getRevision(), but for a remote device.
- *
- * @param address The Bluetooth address of the remote device.
- *
- * @return remote-device HCI revision
- *
- * @see #getRevision
- */
- public synchronized String getRemoteRevision(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteRevisionNative(address);
- }
- private native String getRemoteRevisionNative(String address);
-
- /**
- * Like getManufacturer(), but for a remote device.
- *
- * @param address The Bluetooth address of the remote device.
- *
- * @return remote-device Bluetooth chip manufacturer
- *
- * @see #getManufacturer
- */
- public synchronized String getRemoteManufacturer(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteManufacturerNative(address);
- }
- private native String getRemoteManufacturerNative(String address);
-
- /**
- * Like getCompany(), but for a remote device.
- *
- * @param address The Bluetooth address of the remote device.
- *
- * @return remote-device company
- *
- * @see #getCompany
- */
- public synchronized String getRemoteCompany(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteCompanyNative(address);
- }
- private native String getRemoteCompanyNative(String address);
-
- /**
- * Returns the date and time when the specified remote device has been seen
- * by a discover procedure.
- * Example: "2006-02-08 12:00:00 GMT"
- *
- * @return a String with the timestamp.
- */
- public synchronized String lastSeen(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return lastSeenNative(address);
- }
- private native String lastSeenNative(String address);
-
- /**
- * Returns the date and time when the specified remote device has last been
- * connected to
- * Example: "2006-02-08 12:00:00 GMT"
- *
- * @return a String with the timestamp.
- */
- public synchronized String lastUsed(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return lastUsedNative(address);
- }
- private native String lastUsedNative(String address);
-
- /**
- * Gets the remote major, minor, and service classes encoded as a 32-bit
- * integer.
- *
- * Note: this value is retrieved from cache, because we get it during
- * remote-device discovery.
- *
- * @return 32-bit integer encoding the remote major, minor, and service
- * classes.
- *
- * @see #getRemoteMajorClass
- * @see #getRemoteMinorClass
- * @see #getRemoteServiceClasses
- */
- public synchronized int getRemoteClass(String address) {
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return BluetoothClass.ERROR;
- }
- return getRemoteClassNative(address);
- }
- private native int getRemoteClassNative(String address);
-
- /**
- * Gets the remote features encoded as bit mask.
- *
- * Note: This method may be obsoleted soon.
- *
- * @return byte array of features.
- */
- public synchronized byte[] getRemoteFeatures(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteFeaturesNative(address);
- }
- private native byte[] getRemoteFeaturesNative(String address);
-
- /**
- * This method and {@link #getRemoteServiceRecord} query the SDP service
- * on a remote device. They do not interpret the data, but simply return
- * it raw to the user. To read more about SDP service handles and records,
- * consult the Bluetooth core documentation (www.bluetooth.com).
- *
- * @param address Bluetooth address of remote device.
- * @param match a String match to narrow down the service-handle search.
- * The only supported value currently is "hsp" for the headset
- * profile. To retrieve all service handles, simply pass an empty
- * match string.
- *
- * @return all service handles corresponding to the string match.
- *
- * @see #getRemoteServiceRecord
- */
- public synchronized int[] getRemoteServiceHandles(String address, String match) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- if (match == null) {
- match = "";
- }
- return getRemoteServiceHandlesNative(address, match);
- }
- private native int[] getRemoteServiceHandlesNative(String address, String match);
-
- /**
- * This method retrieves the service records corresponding to a given
- * service handle (method {@link #getRemoteServiceHandles} retrieves the
- * service handles.)
- *
- * This method and {@link #getRemoteServiceHandles} do not interpret their
- * data, but simply return it raw to the user. To read more about SDP
- * service handles and records, consult the Bluetooth core documentation
- * (www.bluetooth.com).
- *
- * @param address Bluetooth address of remote device.
- * @param handle Service handle returned by {@link #getRemoteServiceHandles}
- *
- * @return a byte array of all service records corresponding to the
- * specified service handle.
- *
- * @see #getRemoteServiceHandles
- */
- public synchronized byte[] getRemoteServiceRecord(String address, int handle) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteServiceRecordNative(address, handle);
- }
- private native byte[] getRemoteServiceRecordNative(String address, int handle);
-
- private static final int MAX_OUTSTANDING_ASYNC = 32;
-
- // AIDL does not yet support short's
- public synchronized boolean getRemoteServiceChannel(String address, int uuid16,
- IBluetoothDeviceCallback callback) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- HashMap<String, IBluetoothDeviceCallback> callbacks =
- mEventLoop.getRemoteServiceChannelCallbacks();
- if (callbacks.containsKey(address)) {
- Log.w(TAG, "SDP request already in progress for " + address);
- return false;
- }
- // Protect from malicious clients - only allow 32 bonding requests per minute.
- if (callbacks.size() > MAX_OUTSTANDING_ASYNC) {
- Log.w(TAG, "Too many outstanding SDP requests, dropping request for " + address);
- return false;
- }
- callbacks.put(address, callback);
-
- if (!getRemoteServiceChannelNative(address, (short)uuid16)) {
- callbacks.remove(address);
- return false;
- }
- return true;
- }
- private native boolean getRemoteServiceChannelNative(String address, short uuid16);
-
- public synchronized boolean setPin(String address, byte[] pin) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (pin == null || pin.length <= 0 || pin.length > 16 ||
- !BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- address = address.toUpperCase();
- Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
- if (data == null) {
- Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
- "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
- " or by bluez.\n");
- return false;
- }
- // bluez API wants pin as a string
- String pinString;
- try {
- pinString = new String(pin, "UTF8");
- } catch (UnsupportedEncodingException uee) {
- Log.e(TAG, "UTF8 not supported?!?");
- return false;
- }
- return setPinNative(address, pinString, data.intValue());
- }
- private native boolean setPinNative(String address, String pin, int nativeData);
-
- public synchronized boolean cancelPin(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- address = address.toUpperCase();
- Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
- if (data == null) {
- Log.w(TAG, "cancelPin(" + address + ") called but no native data available, " +
- "ignoring. Maybe the PasskeyAgent Request was already cancelled by the remote " +
- "or by bluez.\n");
- return false;
- }
- return cancelPinNative(address, data.intValue());
- }
- private native boolean cancelPinNative(String address, int natveiData);
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
- ContentResolver resolver = context.getContentResolver();
- // Query the airplane mode from Settings.System just to make sure that
- // some random app is not sending this intent and disabling bluetooth
- boolean enabled = !isAirplaneModeOn();
- // If bluetooth is currently expected to be on, then enable or disable bluetooth
- if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
- if (enabled) {
- enable(false);
- } else {
- disable(false);
- }
- }
- }
- }
- };
-
- private void registerForAirplaneMode() {
- String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
- Settings.System.AIRPLANE_MODE_RADIOS);
- mIsAirplaneSensitive = airplaneModeRadios == null
- ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
- if (mIsAirplaneSensitive) {
- mIntentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- mContext.registerReceiver(mReceiver, mIntentFilter);
- }
- }
-
- /* Returns true if airplane mode is currently on */
- private final boolean isAirplaneModeOn() {
- return Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.AIRPLANE_MODE_ON, 0) == 1;
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
-
- switch(mBluetoothState) {
- case BluetoothDevice.BLUETOOTH_STATE_OFF:
- pw.println("\nBluetooth OFF\n");
- return;
- case BluetoothDevice.BLUETOOTH_STATE_TURNING_ON:
- pw.println("\nBluetooth TURNING ON\n");
- return;
- case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
- pw.println("\nBluetooth TURNING OFF\n");
- return;
- case BluetoothDevice.BLUETOOTH_STATE_ON:
- pw.println("\nBluetooth ON\n");
- }
-
- pw.println("\nLocal address = " + getAddress());
- pw.println("\nLocal name = " + getName());
- pw.println("\nisDiscovering() = " + isDiscovering());
-
- BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
-
- String[] addresses = listRemoteDevices();
-
- pw.println("\n--Known devices--");
- for (String address : addresses) {
- pw.printf("%s %10s (%d) %s\n", address,
- toBondStateString(mBondState.getBondState(address)),
- mBondState.getAttempt(address),
- getRemoteName(address));
- }
-
- addresses = listAclConnections();
- pw.println("\n--ACL connected devices--");
- for (String address : addresses) {
- pw.println(address);
- }
-
- // Rather not do this from here, but no-where else and I need this
- // dump
- pw.println("\n--Headset Service--");
- switch (headset.getState()) {
- case BluetoothHeadset.STATE_DISCONNECTED:
- pw.println("getState() = STATE_DISCONNECTED");
- break;
- case BluetoothHeadset.STATE_CONNECTING:
- pw.println("getState() = STATE_CONNECTING");
- break;
- case BluetoothHeadset.STATE_CONNECTED:
- pw.println("getState() = STATE_CONNECTED");
- break;
- case BluetoothHeadset.STATE_ERROR:
- pw.println("getState() = STATE_ERROR");
- break;
- }
- pw.println("getHeadsetAddress() = " + headset.getHeadsetAddress());
- pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
-
- headset.close();
- }
-
- /* package */ static int bluezStringToScanMode(String mode) {
- if (mode == null) {
- return BluetoothError.ERROR;
- }
- mode = mode.toLowerCase();
- if (mode.equals("off")) {
- return BluetoothDevice.SCAN_MODE_NONE;
- } else if (mode.equals("connectable")) {
- return BluetoothDevice.SCAN_MODE_CONNECTABLE;
- } else if (mode.equals("discoverable")) {
- return BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
- } else {
- return BluetoothError.ERROR;
- }
- }
-
- /* package */ static String scanModeToBluezString(int mode) {
- switch (mode) {
- case BluetoothDevice.SCAN_MODE_NONE:
- return "off";
- case BluetoothDevice.SCAN_MODE_CONNECTABLE:
- return "connectable";
- case BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
- return "discoverable";
- }
- return null;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 8cc229b..79a7cf8 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -18,18 +18,19 @@ package android.server;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothIntent;
-import android.bluetooth.IBluetoothDeviceCallback;
+import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
-import android.os.RemoteException;
import android.util.Log;
import java.util.HashMap;
+import java.util.UUID;
/**
* TODO: Move this to
@@ -46,9 +47,10 @@ class BluetoothEventLoop {
private Thread mThread;
private boolean mStarted;
private boolean mInterrupted;
+
private final HashMap<String, Integer> mPasskeyAgentRequestData;
- private final HashMap<String, IBluetoothDeviceCallback> mGetRemoteServiceChannelCallbacks;
- private final BluetoothDeviceService mBluetoothService;
+ private final BluetoothService mBluetoothService;
+ private final BluetoothAdapter mAdapter;
private final Context mContext;
private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
@@ -85,14 +87,14 @@ class BluetoothEventLoop {
static { classInitNative(); }
private static native void classInitNative();
- /* pacakge */ BluetoothEventLoop(Context context, BluetoothDeviceService bluetoothService) {
+ /* pacakge */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
+ BluetoothService bluetoothService) {
mBluetoothService = bluetoothService;
mContext = context;
mPasskeyAgentRequestData = new HashMap();
- mGetRemoteServiceChannelCallbacks = new HashMap();
+ mAdapter = adapter;
initializeNativeDataNative();
}
- private native void initializeNativeDataNative();
protected void finalize() throws Throwable {
try {
@@ -101,20 +103,11 @@ class BluetoothEventLoop {
super.finalize();
}
}
- private native void cleanupNativeDataNative();
-
- /* pacakge */ HashMap<String, IBluetoothDeviceCallback> getRemoteServiceChannelCallbacks() {
- return mGetRemoteServiceChannelCallbacks;
- }
- /* pacakge */ HashMap<String, Integer> getPasskeyAgentRequestData() {
+ /* package */ HashMap<String, Integer> getPasskeyAgentRequestData() {
return mPasskeyAgentRequestData;
}
- private native void startEventLoopNative();
- private native void stopEventLoopNative();
- private native boolean isEventLoopRunningNative();
-
/* package */ void start() {
if (!isEventLoopRunningNative()) {
@@ -134,79 +127,47 @@ class BluetoothEventLoop {
return isEventLoopRunningNative();
}
- /*package*/ void onModeChanged(String bluezMode) {
- int mode = BluetoothDeviceService.bluezStringToScanMode(bluezMode);
- if (mode >= 0) {
- Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.SCAN_MODE, mode);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ private void addDevice(String address, String[] properties) {
+ mBluetoothService.addRemoteDeviceProperties(address, properties);
+ String rssi = mBluetoothService.getRemoteDeviceProperty(address, "RSSI");
+ String classValue = mBluetoothService.getRemoteDeviceProperty(address, "Class");
+ String name = mBluetoothService.getRemoteDeviceProperty(address, "Name");
+ short rssiValue;
+ // For incoming connections, we don't get the RSSI value. Use a default of MIN_VALUE.
+ // If we accept the pairing, we will automatically show it at the top of the list.
+ if (rssi != null) {
+ rssiValue = (short)Integer.valueOf(rssi).intValue();
+ } else {
+ rssiValue = Short.MIN_VALUE;
+ }
+ if (classValue != null) {
+ Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothIntent.CLASS, Integer.valueOf(classValue));
+ intent.putExtra(BluetoothIntent.RSSI, rssiValue);
+ intent.putExtra(BluetoothIntent.NAME, name);
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ } else {
+ log ("ClassValue: " + classValue + " for remote device: " + address + " is null");
}
}
- private void onDiscoveryStarted() {
- mBluetoothService.setIsDiscovering(true);
- Intent intent = new Intent(BluetoothIntent.DISCOVERY_STARTED_ACTION);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onDiscoveryCompleted() {
- mBluetoothService.setIsDiscovering(false);
- Intent intent = new Intent(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ private void onDeviceFound(String address, String[] properties) {
+ if (properties == null) {
+ Log.e(TAG, "ERROR: Remote device properties are null");
+ return;
+ }
+ addDevice(address, properties);
}
- private void onRemoteDeviceFound(String address, int deviceClass, short rssi) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothIntent.CLASS, deviceClass);
- intent.putExtra(BluetoothIntent.RSSI, rssi);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteDeviceDisappeared(String address) {
+ private void onDeviceDisappeared(String address) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteClassUpdated(String address, int deviceClass) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothIntent.CLASS, deviceClass);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteDeviceConnected(String address) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteDeviceDisconnectRequested(String address) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECT_REQUESTED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteDeviceDisconnected(String address) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteNameUpdated(String address, String name) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothIntent.NAME, name);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteNameFailed(String address) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_FAILED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- private void onRemoteNameChanged(String address, String name) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothIntent.NAME, name);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- private void onCreateBondingResult(String address, int result) {
+ private void onCreatePairedDeviceResult(String address, int result) {
address = address.toUpperCase();
if (result == BluetoothError.SUCCESS) {
mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
@@ -259,31 +220,182 @@ class BluetoothEventLoop {
mBluetoothService.getBondState().attempt(address);
}
- private void onBondingCreated(String address) {
- mBluetoothService.getBondState().setBondState(address.toUpperCase(),
- BluetoothDevice.BOND_BONDED);
+ private void onDeviceCreated(String deviceObjectPath) {
+ String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+ if (!mBluetoothService.isRemoteDeviceInCache(address)) {
+ // Incoming connection, we haven't seen this device, add to cache.
+ String[] properties = mBluetoothService.getRemoteDeviceProperties(address);
+ if (properties != null) {
+ addDevice(address, properties);
+ }
+ }
+ return;
}
- private void onBondingRemoved(String address) {
- mBluetoothService.getBondState().setBondState(address.toUpperCase(),
- BluetoothDevice.BOND_NOT_BONDED, BluetoothDevice.UNBOND_REASON_REMOVED);
+ private void onDeviceRemoved(String deviceObjectPath) {
+ String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+ if (address != null)
+ mBluetoothService.getBondState().setBondState(address.toUpperCase(),
+ BluetoothDevice.BOND_NOT_BONDED, BluetoothDevice.UNBOND_REASON_REMOVED);
}
- private void onNameChanged(String name) {
- Intent intent = new Intent(BluetoothIntent.NAME_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.NAME, name);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ /*package*/ void onPropertyChanged(String[] propValues) {
+ String name = propValues[0];
+ if (name.equals("Name")) {
+ Intent intent = new Intent(BluetoothIntent.NAME_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.NAME, propValues[1]);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ mBluetoothService.setProperty(name, propValues[1]);
+ } else if (name.equals("Pairable") || name.equals("Discoverable")) {
+ String pairable = name.equals("Pairable") ? propValues[1] :
+ mBluetoothService.getProperty("Pairable");
+ String discoverable = name.equals("Discoverable") ? propValues[1] :
+ mBluetoothService.getProperty("Discoverable");
+
+ // This shouldn't happen, unless Adapter Properties are null.
+ if (pairable == null || discoverable == null)
+ return;
+
+ int mode = BluetoothService.bluezStringToScanMode(
+ pairable.equals("true"),
+ discoverable.equals("true"));
+ if (mode >= 0) {
+ Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.SCAN_MODE, mode);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ }
+ mBluetoothService.setProperty(name, propValues[1]);
+ } else if (name.equals("Discovering")) {
+ Intent intent;
+ if (propValues[1].equals("true")) {
+ mBluetoothService.setIsDiscovering(true);
+ intent = new Intent(BluetoothIntent.DISCOVERY_STARTED_ACTION);
+ } else {
+ // Stop the discovery.
+ mBluetoothService.cancelDiscovery();
+ mBluetoothService.setIsDiscovering(false);
+ intent = new Intent(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
+ }
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ mBluetoothService.setProperty(name, propValues[1]);
+ } else if (name.equals("Devices")) {
+ String value = null;
+ int len = Integer.valueOf(propValues[1]);
+ if (len > 0) {
+ StringBuilder str = new StringBuilder();
+ for (int i = 2; i < propValues.length; i++) {
+ str.append(propValues[i]);
+ str.append(",");
+ }
+ value = str.toString();
+ }
+ mBluetoothService.setProperty(name, value);
+ } else if (name.equals("Powered")) {
+ // bluetoothd has restarted, re-read all our properties.
+ // Note: bluez only sends this property change when it restarts.
+ if (propValues[1].equals("true"))
+ onRestartRequired();
+ }
}
- private void onPasskeyAgentRequest(String address, int nativeData) {
+ private void onDevicePropertyChanged(String deviceObjectPath, String[] propValues) {
+ String name = propValues[0];
+ String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+ if (address == null) {
+ Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
+ return;
+ }
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ if (name.equals("Name")) {
+ Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
+ intent.putExtra(BluetoothIntent.DEVICE, device);
+ intent.putExtra(BluetoothIntent.NAME, propValues[1]);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
+ } else if (name.equals("Class")) {
+ Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
+ intent.putExtra(BluetoothIntent.DEVICE, device);
+ intent.putExtra(BluetoothIntent.CLASS, propValues[1]);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
+ } else if (name.equals("Connected")) {
+ Intent intent = null;
+ if (propValues[1].equals("true")) {
+ intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
+ } else {
+ intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
+ }
+ intent.putExtra(BluetoothIntent.DEVICE, device);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
+ } else if (name.equals("UUIDs")) {
+ String uuid = null;
+ int len = Integer.valueOf(propValues[1]);
+ if (len > 0) {
+ StringBuilder str = new StringBuilder();
+ for (int i = 2; i < propValues.length; i++) {
+ str.append(propValues[i]);
+ str.append(",");
+ }
+ uuid = str.toString();
+ }
+ mBluetoothService.setRemoteDeviceProperty(address, name, uuid);
+ } else if (name.equals("Paired")) {
+ if (propValues[1].equals("true")) {
+ mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
+ } else {
+ mBluetoothService.getBondState().setBondState(address,
+ BluetoothDevice.BOND_NOT_BONDED);
+ }
+ }
+ }
+
+ private String checkPairingRequestAndGetAddress(String objectPath, int nativeData) {
+ String address = mBluetoothService.getAddressFromObjectPath(objectPath);
+ if (address == null) {
+ Log.e(TAG, "Unable to get device address in checkPairingRequestAndGetAddress, " +
+ "returning null");
+ return null;
+ }
address = address.toUpperCase();
mPasskeyAgentRequestData.put(address, new Integer(nativeData));
- if (mBluetoothService.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) {
+ if (mBluetoothService.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) {
// shutdown path
- mBluetoothService.cancelPin(address);
- return;
+ mBluetoothService.cancelPairingUserInput(address);
+ return null;
}
+ return address;
+ }
+
+ private void onRequestConfirmation(String objectPath, int passkey, int nativeData) {
+ String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+ if (address == null) return;
+
+ Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothIntent.PASSKEY, passkey);
+ intent.putExtra(BluetoothIntent.PAIRING_VARIANT,
+ BluetoothDevice.PAIRING_VARIANT_CONFIRMATION);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ return;
+ }
+
+ private void onRequestPasskey(String objectPath, int nativeData) {
+ String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+ if (address == null) return;
+
+ Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PASSKEY);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ return;
+ }
+
+ private void onRequestPinCode(String objectPath, int nativeData) {
+ String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+ if (address == null) return;
if (mBluetoothService.getBondState().getBondState(address) ==
BluetoothDevice.BOND_BONDING) {
@@ -307,55 +419,51 @@ class BluetoothEventLoop {
}
}
Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ return;
}
- private void onPasskeyAgentCancel(String address) {
- address = address.toUpperCase();
- mBluetoothService.cancelPin(address);
- Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
- BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
- }
+ private boolean onAgentAuthorize(String objectPath, String deviceUuid) {
+ String address = mBluetoothService.getAddressFromObjectPath(objectPath);
+ if (address == null) {
+ Log.e(TAG, "Unable to get device address in onAuthAgentAuthorize");
+ return false;
+ }
- private boolean onAuthAgentAuthorize(String address, String service, String uuid) {
boolean authorized = false;
- if (mBluetoothService.isEnabled() && service.endsWith("service_audio")) {
+ UUID uuid = UUID.fromString(deviceUuid);
+ // Bluez sends the UUID of the local service being accessed, _not_ the
+ // remote service
+ if (mBluetoothService.isEnabled() &&
+ (BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
+ || BluetoothUuid.isAdvAudioDist(uuid))) {
BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
- authorized = a2dp.getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF;
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF;
if (authorized) {
- Log.i(TAG, "Allowing incoming A2DP connection from " + address);
+ Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address);
} else {
- Log.i(TAG, "Rejecting incoming A2DP connection from " + address);
+ Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address);
}
} else {
- Log.i(TAG, "Rejecting incoming " + service + " connection from " + address);
+ Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
}
+ log("onAgentAuthorize(" + objectPath + ", " + deviceUuid + ") = " + authorized);
return authorized;
}
- private void onAuthAgentCancel(String address, String service, String uuid) {
- // We immediately response to DBUS Authorize() so this should not
- // usually happen
- log("onAuthAgentCancel(" + address + ", " + service + ", " + uuid + ")");
- }
-
- private void onGetRemoteServiceChannelResult(String address, int channel) {
- IBluetoothDeviceCallback callback = mGetRemoteServiceChannelCallbacks.get(address);
- if (callback != null) {
- mGetRemoteServiceChannelCallbacks.remove(address);
- try {
- callback.onGetRemoteServiceChannelResult(address, channel);
- } catch (RemoteException e) {}
- }
+ private void onAgentCancel() {
+ Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ return;
}
private void onRestartRequired() {
if (mBluetoothService.isEnabled()) {
- Log.e(TAG, "*** A serious error occured (did hcid crash?) - restarting Bluetooth ***");
+ Log.e(TAG, "*** A serious error occured (did bluetoothd crash?) - " +
+ "restarting Bluetooth ***");
mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH);
}
}
@@ -363,4 +471,10 @@ class BluetoothEventLoop {
private static void log(String msg) {
Log.d(TAG, msg);
}
+
+ private native void initializeNativeDataNative();
+ private native void startEventLoopNative();
+ private native void stopEventLoopNative();
+ private native boolean isEventLoopRunningNative();
+ private native void cleanupNativeDataNative();
}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
new file mode 100644
index 0000000..21104c8
--- /dev/null
+++ b/core/java/android/server/BluetoothService.java
@@ -0,0 +1,1224 @@
+/*
+ * 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.
+ */
+
+/**
+ * TODO: Move this to
+ * java/services/com/android/server/BluetoothService.java
+ * and make the contructor package private again.
+ *
+ * @hide
+ */
+
+package android.server;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothError;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothIntent;
+import android.bluetooth.IBluetooth;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemService;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.app.IBatteryStats;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class BluetoothService extends IBluetooth.Stub {
+ private static final String TAG = "BluetoothService";
+ private static final boolean DBG = true;
+
+ private int mNativeData;
+ private BluetoothEventLoop mEventLoop;
+ private IntentFilter mIntentFilter;
+ private boolean mIsAirplaneSensitive;
+ private int mBluetoothState;
+ private boolean mRestart = false; // need to call enable() after disable()
+ private boolean mIsDiscovering;
+
+ private BluetoothAdapter mAdapter; // constant after init()
+ private final BondState mBondState = new BondState(); // local cache of bondings
+ private final IBatteryStats mBatteryStats;
+ private final Context mContext;
+
+ private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
+ private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+
+ private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
+ private static final int MESSAGE_FINISH_DISABLE = 2;
+
+ private final Map<String, String> mAdapterProperties;
+ private final HashMap <String, Map<String, String>> mDeviceProperties;
+
+ static {
+ classInitNative();
+ }
+
+ public BluetoothService(Context context) {
+ mContext = context;
+
+ // Need to do this in place of:
+ // mBatteryStats = BatteryStatsService.getService();
+ // Since we can not import BatteryStatsService from here. This class really needs to be
+ // moved to java/services/com/android/server/
+ mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
+
+ initializeNativeDataNative();
+
+ if (isEnabledNative() == 1) {
+ Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
+ disableNative();
+ }
+
+ mBluetoothState = BluetoothAdapter.BLUETOOTH_STATE_OFF;
+ mIsDiscovering = false;
+ mAdapterProperties = new HashMap<String, String>();
+ mDeviceProperties = new HashMap<String, Map<String,String>>();
+ registerForAirplaneMode();
+ }
+
+ public synchronized void initAfterRegistration() {
+ mAdapter = (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mIsAirplaneSensitive) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ try {
+ cleanupNativeDataNative();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ public boolean isEnabled() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mBluetoothState == BluetoothAdapter.BLUETOOTH_STATE_ON;
+ }
+
+ public int getBluetoothState() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mBluetoothState;
+ }
+
+
+ /**
+ * Bring down bluetooth and disable BT in settings. Returns true on success.
+ */
+ public boolean disable() {
+ return disable(true);
+ }
+
+ /**
+ * Bring down bluetooth. Returns true on success.
+ *
+ * @param saveSetting If true, disable BT in settings
+ */
+ public synchronized boolean disable(boolean saveSetting) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+
+ switch (mBluetoothState) {
+ case BluetoothAdapter.BLUETOOTH_STATE_OFF:
+ return true;
+ case BluetoothAdapter.BLUETOOTH_STATE_ON:
+ break;
+ default:
+ return false;
+ }
+ if (mEnableThread != null && mEnableThread.isAlive()) {
+ return false;
+ }
+ setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF);
+
+ // Allow 3 seconds for profiles to gracefully disconnect
+ // TODO: Introduce a callback mechanism so that each profile can notify
+ // BluetoothService when it is done shutting down
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
+ return true;
+ }
+
+
+ private synchronized void finishDisable(boolean saveSetting) {
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) {
+ return;
+ }
+ mEventLoop.stop();
+ tearDownNativeDataNative();
+ disableNative();
+
+ // mark in progress bondings as cancelled
+ for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
+ mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
+ BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
+ }
+
+ // update mode
+ Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+
+ mIsDiscovering = false;
+ mAdapterProperties.clear();
+
+ if (saveSetting) {
+ persistBluetoothOnSetting(false);
+ }
+
+ setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_OFF);
+
+ // Log bluetooth off to battery stats.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteBluetoothOff();
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ if (mRestart) {
+ mRestart = false;
+ enable();
+ }
+ }
+
+ /** Bring up BT and persist BT on in settings */
+ public boolean enable() {
+ return enable(true);
+ }
+
+ /**
+ * Enable this Bluetooth device, asynchronously.
+ * This turns on/off the underlying hardware.
+ *
+ * @param saveSetting If true, persist the new state of BT in settings
+ * @return True on success (so far)
+ */
+ public synchronized boolean enable(boolean saveSetting) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+
+ // Airplane mode can prevent Bluetooth radio from being turned on.
+ if (mIsAirplaneSensitive && isAirplaneModeOn()) {
+ return false;
+ }
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_OFF) {
+ return false;
+ }
+ if (mEnableThread != null && mEnableThread.isAlive()) {
+ return false;
+ }
+ setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON);
+ mEnableThread = new EnableThread(saveSetting);
+ mEnableThread.start();
+ return true;
+ }
+
+ /** Forcibly restart Bluetooth if it is on */
+ /* package */ synchronized void restart() {
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_ON) {
+ return;
+ }
+ mRestart = true;
+ if (!disable(false)) {
+ mRestart = false;
+ }
+ }
+
+ private synchronized void setBluetoothState(int state) {
+ if (state == mBluetoothState) {
+ return;
+ }
+
+ if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
+
+ Intent intent = new Intent(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.BLUETOOTH_PREVIOUS_STATE, mBluetoothState);
+ intent.putExtra(BluetoothIntent.BLUETOOTH_STATE, state);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
+ mBluetoothState = state;
+
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ }
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_REGISTER_SDP_RECORDS:
+ //TODO: Don't assume HSP/HFP is running, don't use sdptool,
+ if (isEnabled()) {
+ SystemService.start("hsag");
+ SystemService.start("hfag");
+ SystemService.start("opush");
+ SystemService.start("pbap");
+ }
+ break;
+ case MESSAGE_FINISH_DISABLE:
+ finishDisable(msg.arg1 != 0);
+ break;
+ }
+ }
+ };
+
+ private EnableThread mEnableThread;
+
+ private class EnableThread extends Thread {
+ private final boolean mSaveSetting;
+ public EnableThread(boolean saveSetting) {
+ mSaveSetting = saveSetting;
+ }
+ public void run() {
+ boolean res = (enableNative() == 0);
+ if (res) {
+ int retryCount = 2;
+ boolean running = false;
+ while ((retryCount-- > 0) && !running) {
+ mEventLoop.start();
+ // it may take a momement for the other thread to do its
+ // thing. Check periodically for a while.
+ int pollCount = 5;
+ while ((pollCount-- > 0) && !running) {
+ if (mEventLoop.isEventLoopRunning()) {
+ running = true;
+ break;
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {}
+ }
+ }
+ if (!running) {
+ log("bt EnableThread giving up");
+ res = false;
+ disableNative();
+ }
+ }
+
+
+ if (res) {
+ if (!setupNativeDataNative()) {
+ return;
+ }
+ if (mSaveSetting) {
+ persistBluetoothOnSetting(true);
+ }
+ mIsDiscovering = false;
+ mBondState.loadBondState();
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS),
+ 3000);
+
+ // Log bluetooth on to battery stats.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteBluetoothOn();
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ mEnableThread = null;
+
+ setBluetoothState(res ?
+ BluetoothAdapter.BLUETOOTH_STATE_ON :
+ BluetoothAdapter.BLUETOOTH_STATE_OFF);
+
+ if (res) {
+ // Update mode
+ String[] propVal = {"Pairable", getProperty("Pairable")};
+ mEventLoop.onPropertyChanged(propVal);
+ }
+
+ if (mIsAirplaneSensitive && isAirplaneModeOn()) {
+ disable(false);
+ }
+
+ }
+ }
+
+ private void persistBluetoothOnSetting(boolean bluetoothOn) {
+ long origCallerIdentityToken = Binder.clearCallingIdentity();
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
+ bluetoothOn ? 1 : 0);
+ Binder.restoreCallingIdentity(origCallerIdentityToken);
+ }
+
+ /* package */ BondState getBondState() {
+ return mBondState;
+ }
+
+ /** local cache of bonding state.
+ /* we keep our own state to track the intermediate state BONDING, which
+ /* bluez does not track.
+ * All addreses must be passed in upper case.
+ */
+ public class BondState {
+ private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
+ private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
+ private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>();
+ // List of all the vendor_id prefix of Bluetooth addresses for
+ // which auto pairing is not attempted.
+ // The following companies are included in the list below:
+ // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi),
+ // Parrot, Zhongshan General K-mate Electronics, Great Well
+ // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi,
+ // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura),
+ // Continental Automotive, Harman/Becker
+ private final ArrayList<String> mAutoPairingBlacklisted =
+ new ArrayList<String>(Arrays.asList(
+ "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F",
+ "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8",
+ "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04",
+ "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59",
+ "00:0A:30", "00:1E:AE", "00:1C:D7"
+ ));
+
+ public synchronized void loadBondState() {
+ if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON) {
+ return;
+ }
+ String []bonds = null;
+ String val = getProperty("Devices");
+ if (val != null) {
+ bonds = val.split(",");
+ }
+ if (bonds == null) {
+ return;
+ }
+ mState.clear();
+ if (DBG) log("found " + bonds.length + " bonded devices");
+ for (String device : bonds) {
+ mState.put(getAddressFromObjectPath(device).toUpperCase(),
+ BluetoothDevice.BOND_BONDED);
+ }
+ }
+
+ public synchronized void setBondState(String address, int state) {
+ setBondState(address, state, 0);
+ }
+
+ /** reason is ignored unless state == BOND_NOT_BONDED */
+ public synchronized void setBondState(String address, int state, int reason) {
+ int oldState = getBondState(address);
+ if (oldState == state) {
+ return;
+ }
+ if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
+ reason + ")");
+ Intent intent = new Intent(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothIntent.BOND_STATE, state);
+ intent.putExtra(BluetoothIntent.BOND_PREVIOUS_STATE, oldState);
+ if (state == BluetoothDevice.BOND_NOT_BONDED) {
+ if (reason <= 0) {
+ Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
+ "invalid. Overriding reason code with BOND_RESULT_REMOVED");
+ reason = BluetoothDevice.UNBOND_REASON_REMOVED;
+ }
+ intent.putExtra(BluetoothIntent.REASON, reason);
+ mState.remove(address);
+ } else {
+ mState.put(address, state);
+ }
+
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ }
+
+ public boolean isAutoPairingBlacklisted(String address) {
+ for (String blacklistAddress : mAutoPairingBlacklisted) {
+ if (address.startsWith(blacklistAddress)) return true;
+ }
+ return false;
+ }
+
+ public synchronized int getBondState(String address) {
+ Integer state = mState.get(address);
+ if (state == null) {
+ return BluetoothDevice.BOND_NOT_BONDED;
+ }
+ return state.intValue();
+ }
+
+ private synchronized String[] listInState(int state) {
+ ArrayList<String> result = new ArrayList<String>(mState.size());
+ for (Map.Entry<String, Integer> e : mState.entrySet()) {
+ if (e.getValue().intValue() == state) {
+ result.add(e.getKey());
+ }
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ public synchronized void addAutoPairingFailure(String address) {
+ if (!mAutoPairingFailures.contains(address)) {
+ mAutoPairingFailures.add(address);
+ }
+ }
+
+ public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
+ return getAttempt(address) != 0;
+ }
+
+ public synchronized void clearPinAttempts(String address) {
+ mPinAttempt.remove(address);
+ }
+
+ public synchronized boolean hasAutoPairingFailed(String address) {
+ return mAutoPairingFailures.contains(address);
+ }
+
+ public synchronized int getAttempt(String address) {
+ Integer attempt = mPinAttempt.get(address);
+ if (attempt == null) {
+ return 0;
+ }
+ return attempt.intValue();
+ }
+
+ public synchronized void attempt(String address) {
+ Integer attempt = mPinAttempt.get(address);
+ int newAttempt;
+ if (attempt == null) {
+ newAttempt = 1;
+ } else {
+ newAttempt = attempt.intValue() + 1;
+ }
+ mPinAttempt.put(address, new Integer(newAttempt));
+ }
+
+ }
+
+ private static String toBondStateString(int bondState) {
+ switch (bondState) {
+ case BluetoothDevice.BOND_NOT_BONDED:
+ return "not bonded";
+ case BluetoothDevice.BOND_BONDING:
+ return "bonding";
+ case BluetoothDevice.BOND_BONDED:
+ return "bonded";
+ default:
+ return "??????";
+ }
+ }
+
+ /*package*/synchronized void getAllProperties() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ mAdapterProperties.clear();
+
+ String properties[] = (String [])getAdapterPropertiesNative();
+ // The String Array consists of key-value pairs.
+ if (properties == null) {
+ Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
+ return;
+ }
+
+ for (int i = 0; i < properties.length; i++) {
+ String name = properties[i];
+ String newValue = null;
+ int len;
+ if (name == null) {
+ Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
+ continue;
+ }
+ if (name.equals("Devices")) {
+ StringBuilder str = new StringBuilder();
+ len = Integer.valueOf(properties[++i]);
+ for (int j = 0; j < len; j++) {
+ str.append(properties[++i]);
+ str.append(",");
+ }
+ if (len > 0) {
+ newValue = str.toString();
+ }
+ } else {
+ newValue = properties[++i];
+ }
+ mAdapterProperties.put(name, newValue);
+ }
+
+ // Add adapter object path property.
+ String adapterPath = getAdapterPathNative();
+ if (adapterPath != null)
+ mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
+ }
+
+ /* package */ synchronized void setProperty(String name, String value) {
+ mAdapterProperties.put(name, value);
+ }
+
+ public synchronized boolean setName(String name) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (name == null) {
+ return false;
+ }
+ return setPropertyString("Name", name);
+ }
+
+ //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
+ // Either have a single property function with Object as the parameter
+ // or have a function for each property and then obfuscate in the JNI layer.
+ // The following looks dirty.
+ private boolean setPropertyString(String key, String value) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return setAdapterPropertyStringNative(key, value);
+ }
+
+ private boolean setPropertyInteger(String key, int value) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return setAdapterPropertyIntegerNative(key, value);
+ }
+
+ private boolean setPropertyBoolean(String key, boolean value) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
+ }
+
+ /**
+ * Set the discoverability window for the device. A timeout of zero
+ * makes the device permanently discoverable (if the device is
+ * discoverable). Setting the timeout to a nonzero value does not make
+ * a device discoverable; you need to call setMode() to make the device
+ * explicitly discoverable.
+ *
+ * @param timeout_s The discoverable timeout in seconds.
+ */
+ public synchronized boolean setDiscoverableTimeout(int timeout) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ return setPropertyInteger("DiscoverableTimeout", timeout);
+ }
+
+ public synchronized boolean setScanMode(int mode) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ boolean pairable = false, discoverable = false;
+ String modeString = scanModeToBluezString(mode);
+ if (modeString.equals("off")) {
+ pairable = false;
+ discoverable = false;
+ } else if (modeString.equals("pariable")) {
+ pairable = true;
+ discoverable = false;
+ } else if (modeString.equals("discoverable")) {
+ pairable = true;
+ discoverable = true;
+ }
+ setPropertyBoolean("Pairable", pairable);
+ setPropertyBoolean("Discoverable", discoverable);
+
+ return true;
+ }
+
+ /*package*/ synchronized String getProperty (String name) {
+ if (!mAdapterProperties.isEmpty())
+ return mAdapterProperties.get(name);
+ getAllProperties();
+ return mAdapterProperties.get(name);
+ }
+
+ public synchronized String getAddress() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return getProperty("Address");
+ }
+
+ public synchronized String getName() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return getProperty("Name");
+ }
+
+ /**
+ * Returns the user-friendly name of a remote device. This value is
+ * returned from our local cache, which is updated when onPropertyChange
+ * event is received.
+ * Do not expect to retrieve the updated remote name immediately after
+ * changing the name on the remote device.
+ *
+ * @param address Bluetooth address of remote device.
+ *
+ * @return The user-friendly name of the specified remote device.
+ */
+ public synchronized String getRemoteName(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return null;
+ }
+ Map <String, String> properties = mDeviceProperties.get(address);
+ if (properties != null) return properties.get("Name");
+ return null;
+ }
+
+ /**
+ * Get the discoverability window for the device. A timeout of zero
+ * means that the device is permanently discoverable (if the device is
+ * in the discoverable mode).
+ *
+ * @return The discoverability window of the device, in seconds. A negative
+ * value indicates an error.
+ */
+ public synchronized int getDiscoverableTimeout() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ String timeout = getProperty("DiscoverableTimeout");
+ if (timeout != null)
+ return Integer.valueOf(timeout);
+ else
+ return -1;
+ }
+
+ public synchronized int getScanMode() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!isEnabled())
+ return BluetoothError.ERROR;
+
+ boolean pairable = getProperty("Pairable").equals("true");
+ boolean discoverable = getProperty("Discoverable").equals("true");
+ return bluezStringToScanMode (pairable, discoverable);
+ }
+
+ public synchronized boolean startDiscovery() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!isEnabled()) {
+ return false;
+ }
+ return startDiscoveryNative();
+ }
+
+ public synchronized boolean cancelDiscovery() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ return stopDiscoveryNative();
+ }
+
+ public synchronized boolean isDiscovering() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mIsDiscovering;
+ }
+
+ /* package */ void setIsDiscovering(boolean isDiscovering) {
+ mIsDiscovering = isDiscovering;
+ }
+
+ public synchronized boolean createBond(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ address = address.toUpperCase();
+
+ String[] bonding = mBondState.listInState(BluetoothDevice.BOND_BONDING);
+ if (bonding.length > 0 && !bonding[0].equals(address)) {
+ log("Ignoring createBond(): another device is bonding");
+ // a different device is currently bonding, fail
+ return false;
+ }
+
+ // Check for bond state only if we are not performing auto
+ // pairing exponential back-off attempts.
+ if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
+ mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
+ log("Ignoring createBond(): this device is already bonding or bonded");
+ return false;
+ }
+
+ if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) {
+ return false;
+ }
+
+ mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
+ return true;
+ }
+
+ public synchronized boolean cancelBondProcess(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ address = address.toUpperCase();
+ if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
+ return false;
+ }
+
+ mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
+ BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
+ cancelDeviceCreationNative(address);
+ return true;
+ }
+
+ public synchronized boolean removeBond(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ return removeDeviceNative(getObjectPathFromAddress(address));
+ }
+
+ public synchronized String[] listBonds() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mBondState.listInState(BluetoothDevice.BOND_BONDED);
+ }
+
+ public synchronized int getBondState(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return BluetoothError.ERROR;
+ }
+ return mBondState.getBondState(address.toUpperCase());
+ }
+
+ /*package*/ boolean isRemoteDeviceInCache(String address) {
+ return (mDeviceProperties.get(address) != null);
+ }
+
+ /*package*/ String[] getRemoteDeviceProperties(String address) {
+ String objectPath = getObjectPathFromAddress(address);
+ return (String [])getDevicePropertiesNative(objectPath);
+ }
+
+ /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
+ Map<String, String> properties = mDeviceProperties.get(address);
+ if (properties != null) {
+ return properties.get(property);
+ } else {
+ // Query for remote device properties, again.
+ // We will need to reload the cache when we switch Bluetooth on / off
+ // or if we crash.
+ String[] propValues = getRemoteDeviceProperties(address);
+ if (propValues != null) {
+ addRemoteDeviceProperties(address, propValues);
+ return getRemoteDeviceProperty(address, property);
+ }
+ }
+ Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
+ return null;
+ }
+
+ /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
+ /*
+ * We get a DeviceFound signal every time RSSI changes or name changes.
+ * Don't create a new Map object every time */
+ Map<String, String> propertyValues = mDeviceProperties.get(address);
+ if (propertyValues == null) {
+ propertyValues = new HashMap<String, String>();
+ }
+
+ for (int i = 0; i < properties.length; i++) {
+ String name = properties[i];
+ String newValue = null;
+ int len;
+ if (name == null) {
+ Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
+ continue;
+ }
+ if (name.equals("UUIDs") || name.equals("Nodes")) {
+ StringBuilder str = new StringBuilder();
+ len = Integer.valueOf(properties[++i]);
+ for (int j = 0; j < len; j++) {
+ str.append(properties[++i]);
+ str.append(",");
+ }
+ if (len > 0) {
+ newValue = str.toString();
+ }
+ } else {
+ newValue = properties[++i];
+ }
+
+ propertyValues.put(name, newValue);
+ }
+ mDeviceProperties.put(address, propertyValues);
+ }
+
+ /* package */ void removeRemoteDeviceProperties(String address) {
+ mDeviceProperties.remove(address);
+ }
+
+ /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
+ String value) {
+ Map <String, String> propVal = mDeviceProperties.get(address);
+ if (propVal != null) {
+ propVal.put(name, value);
+ mDeviceProperties.put(address, propVal);
+ } else {
+ Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
+ }
+ }
+
+ /**
+ * Gets the remote major, minor classes encoded as a 32-bit
+ * integer.
+ *
+ * Note: this value is retrieved from cache, because we get it during
+ * remote-device discovery.
+ *
+ * @return 32-bit integer encoding the remote major, minor, and service
+ * classes.
+ */
+ public synchronized int getRemoteClass(String address) {
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return BluetoothClass.ERROR;
+ }
+ String val = getRemoteDeviceProperty(address, "Class");
+ if (val == null)
+ return BluetoothClass.ERROR;
+ else {
+ return Integer.valueOf(val);
+ }
+ }
+
+
+ /**
+ * Gets the remote features encoded as bit mask.
+ *
+ * Note: This method may be obsoleted soon.
+ *
+ * @return String array of 128bit UUIDs
+ */
+ public synchronized String[] getRemoteUuids(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return null;
+ }
+ String value = getRemoteDeviceProperty(address, "UUIDs");
+ String[] uuids = null;
+ // The UUIDs are stored as a "," separated string.
+ if (value != null)
+ uuids = value.split(",");
+ return uuids;
+ }
+
+ /**
+ * Gets the rfcomm channel associated with the UUID.
+ *
+ * @param address Address of the remote device
+ * @param uuid UUID of the service attribute
+ *
+ * @return rfcomm channel associated with the service attribute
+ */
+ public int getRemoteServiceChannel(String address, String uuid) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return BluetoothError.ERROR_IPC;
+ }
+ return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid, 0x0004);
+ }
+
+ public synchronized boolean setPin(String address, byte[] pin) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (pin == null || pin.length <= 0 || pin.length > 16 ||
+ !BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ address = address.toUpperCase();
+ Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
+ if (data == null) {
+ Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
+ "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
+ " or by bluez.\n");
+ return false;
+ }
+ // bluez API wants pin as a string
+ String pinString;
+ try {
+ pinString = new String(pin, "UTF8");
+ } catch (UnsupportedEncodingException uee) {
+ Log.e(TAG, "UTF8 not supported?!?");
+ return false;
+ }
+ return setPinNative(address, pinString, data.intValue());
+ }
+
+ public synchronized boolean setPasskey(String address, int passkey) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (passkey < 0 || passkey > 999999 || !BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ address = address.toUpperCase();
+ Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
+ if (data == null) {
+ Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
+ "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
+ " or by bluez.\n");
+ return false;
+ }
+ return setPasskeyNative(address, passkey, data.intValue());
+ }
+
+ public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ address = address.toUpperCase();
+ Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
+ if (data == null) {
+ Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
+ "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
+ " or by bluez.\n");
+ return false;
+ }
+ return setPairingConfirmationNative(address, confirm, data.intValue());
+ }
+
+ public synchronized boolean cancelPairingUserInput(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!BluetoothDevice.checkBluetoothAddress(address)) {
+ return false;
+ }
+ mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
+ BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
+ address = address.toUpperCase();
+ Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
+ if (data == null) {
+ Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
+ "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
+ "by the remote or by bluez.\n");
+ return false;
+ }
+ return cancelPairingUserInputNative(address, data.intValue());
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+ ContentResolver resolver = context.getContentResolver();
+ // Query the airplane mode from Settings.System just to make sure that
+ // some random app is not sending this intent and disabling bluetooth
+ boolean enabled = !isAirplaneModeOn();
+ // If bluetooth is currently expected to be on, then enable or disable bluetooth
+ if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
+ if (enabled) {
+ enable(false);
+ } else {
+ disable(false);
+ }
+ }
+ }
+ }
+ };
+
+ private void registerForAirplaneMode() {
+ String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_RADIOS);
+ mIsAirplaneSensitive = airplaneModeRadios == null
+ ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
+ if (mIsAirplaneSensitive) {
+ mIntentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ mContext.registerReceiver(mReceiver, mIntentFilter);
+ }
+ }
+
+ /* Returns true if airplane mode is currently on */
+ private final boolean isAirplaneModeOn() {
+ return Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_ON, 0) == 1;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
+
+ switch(mBluetoothState) {
+ case BluetoothAdapter.BLUETOOTH_STATE_OFF:
+ pw.println("\nBluetooth OFF\n");
+ return;
+ case BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON:
+ pw.println("\nBluetooth TURNING ON\n");
+ return;
+ case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF:
+ pw.println("\nBluetooth TURNING OFF\n");
+ return;
+ case BluetoothAdapter.BLUETOOTH_STATE_ON:
+ pw.println("\nBluetooth ON\n");
+ }
+
+ pw.println("\nLocal address = " + getAddress());
+ pw.println("\nLocal name = " + getName());
+ pw.println("\nisDiscovering() = " + isDiscovering());
+
+ BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
+
+ pw.println("\n--Known devices--");
+ for (String address : mDeviceProperties.keySet()) {
+ int bondState = mBondState.getBondState(address);
+ pw.printf("%s %10s (%d) %s\n", address,
+ toBondStateString(bondState),
+ mBondState.getAttempt(address),
+ getRemoteName(address));
+ if (bondState == BluetoothDevice.BOND_BONDED) {
+ String[] uuids = getRemoteUuids(address);
+ if (uuids == null) {
+ pw.printf("\tuuids = null\n");
+ } else {
+ for (String uuid : uuids) {
+ pw.printf("\t" + uuid + "\n");
+ }
+ }
+ }
+ }
+
+ String value = getProperty("Devices");
+ String[] devicesObjectPath = null;
+ if (value != null) {
+ devicesObjectPath = value.split(",");
+ }
+ pw.println("\n--ACL connected devices--");
+ for (String device : devicesObjectPath) {
+ pw.println(getAddressFromObjectPath(device));
+ }
+
+ // Rather not do this from here, but no-where else and I need this
+ // dump
+ pw.println("\n--Headset Service--");
+ switch (headset.getState()) {
+ case BluetoothHeadset.STATE_DISCONNECTED:
+ pw.println("getState() = STATE_DISCONNECTED");
+ break;
+ case BluetoothHeadset.STATE_CONNECTING:
+ pw.println("getState() = STATE_CONNECTING");
+ break;
+ case BluetoothHeadset.STATE_CONNECTED:
+ pw.println("getState() = STATE_CONNECTED");
+ break;
+ case BluetoothHeadset.STATE_ERROR:
+ pw.println("getState() = STATE_ERROR");
+ break;
+ }
+ pw.println("getCurrentHeadset() = " + headset.getCurrentHeadset());
+ pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
+
+ headset.close();
+ }
+
+ /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
+ if (pairable && discoverable)
+ return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
+ else if (pairable && !discoverable)
+ return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
+ else
+ return BluetoothAdapter.SCAN_MODE_NONE;
+ }
+
+ /* package */ static String scanModeToBluezString(int mode) {
+ switch (mode) {
+ case BluetoothAdapter.SCAN_MODE_NONE:
+ return "off";
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
+ return "connectable";
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ return "discoverable";
+ }
+ return null;
+ }
+
+ /*package*/ String getAddressFromObjectPath(String objectPath) {
+ String adapterObjectPath = getProperty("ObjectPath");
+ if (adapterObjectPath == null || objectPath == null) {
+ Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
+ " or deviceObjectPath:" + objectPath + " is null");
+ return null;
+ }
+ if (!objectPath.startsWith(adapterObjectPath)) {
+ Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
+ " is not a prefix of deviceObjectPath:" + objectPath +
+ "bluetoothd crashed ?");
+ return null;
+ }
+ String address = objectPath.substring(adapterObjectPath.length());
+ if (address != null) return address.replace('_', ':');
+
+ Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
+ return null;
+ }
+
+ /*package*/ String getObjectPathFromAddress(String address) {
+ String path = getProperty("ObjectPath");
+ if (path == null) {
+ Log.e(TAG, "Error: Object Path is null");
+ return null;
+ }
+ path = path + address.replace(":", "_");
+ return path;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+
+ private native static void classInitNative();
+ private native void initializeNativeDataNative();
+ private native boolean setupNativeDataNative();
+ private native boolean tearDownNativeDataNative();
+ private native void cleanupNativeDataNative();
+ private native String getAdapterPathNative();
+
+ private native int isEnabledNative();
+ private native int enableNative();
+ private native int disableNative();
+
+ private native Object[] getAdapterPropertiesNative();
+ private native Object[] getDevicePropertiesNative(String objectPath);
+ private native boolean setAdapterPropertyStringNative(String key, String value);
+ private native boolean setAdapterPropertyIntegerNative(String key, int value);
+ private native boolean setAdapterPropertyBooleanNative(String key, int value);
+
+ private native boolean startDiscoveryNative();
+ private native boolean stopDiscoveryNative();
+
+ private native boolean createPairedDeviceNative(String address, int timeout_ms);
+ private native boolean cancelDeviceCreationNative(String address);
+ private native boolean removeDeviceNative(String objectPath);
+ private native int getDeviceServiceChannelNative(String objectPath, String uuid,
+ int attributeId);
+
+ private native boolean cancelPairingUserInputNative(String address, int nativeData);
+ private native boolean setPinNative(String address, String pin, int nativeData);
+ private native boolean setPasskeyNative(String address, int passkey, int nativeData);
+ private native boolean setPairingConfirmationNative(String address, boolean confirm,
+ int nativeData);
+
+}
diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java
index 49718cb..9ee64af 100644
--- a/core/java/android/server/search/SearchDialogWrapper.java
+++ b/core/java/android/server/search/SearchDialogWrapper.java
@@ -58,6 +58,7 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
// data[KEY_INITIAL_QUERY]: initial query
// data[KEY_LAUNCH_ACTIVITY]: launch activity
// data[KEY_APP_SEARCH_DATA]: app search data
+ // data[KEY_TRIGGER]: 0 = false, 1 = true
private static final int MSG_START_SEARCH = 1;
// Takes no arguments
private static final int MSG_STOP_SEARCH = 2;
@@ -69,7 +70,8 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
private static final String KEY_INITIAL_QUERY = "q";
private static final String KEY_LAUNCH_ACTIVITY = "a";
private static final String KEY_APP_SEARCH_DATA = "d";
- private static final String KEY_IDENT= "i";
+ private static final String KEY_IDENT = "i";
+ private static final String KEY_TRIGGER = "t";
// Context used for getting search UI resources
private final Context mContext;
@@ -173,7 +175,8 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
final Bundle appSearchData,
final boolean globalSearch,
final ISearchManagerCallback searchManagerCallback,
- int ident) {
+ int ident,
+ boolean trigger) {
if (DBG) debug("startSearch()");
Message msg = Message.obtain();
msg.what = MSG_START_SEARCH;
@@ -185,6 +188,7 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
msgData.putParcelable(KEY_LAUNCH_ACTIVITY, launchActivity);
msgData.putBundle(KEY_APP_SEARCH_DATA, appSearchData);
msgData.putInt(KEY_IDENT, ident);
+ msgData.putInt(KEY_TRIGGER, trigger ? 1 : 0);
mSearchUiThread.sendMessage(msg);
// be a little more eager in setting this so isVisible will return the correct value if
// called immediately after startSearch
@@ -268,8 +272,9 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
boolean globalSearch = msg.arg2 != 0;
ISearchManagerCallback searchManagerCallback = (ISearchManagerCallback) msg.obj;
int ident = msgData.getInt(KEY_IDENT);
+ boolean trigger = msgData.getInt(KEY_TRIGGER) != 0;
performStartSearch(initialQuery, selectInitialQuery, launchActivity,
- appSearchData, globalSearch, searchManagerCallback, ident);
+ appSearchData, globalSearch, searchManagerCallback, ident, trigger);
}
}
@@ -284,7 +289,8 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
Bundle appSearchData,
boolean globalSearch,
ISearchManagerCallback searchManagerCallback,
- int ident) {
+ int ident,
+ boolean trigger) {
if (DBG) debug("performStartSearch()");
registerBroadcastReceiver();
@@ -301,6 +307,9 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
globalSearch);
mVisible = true;
+ if (trigger) {
+ mSearchDialog.launchQuerySearch();
+ }
}
/**
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index afed4a4..5e0b3d2 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -233,7 +233,31 @@ public class SearchManagerService extends ISearchManager.Stub {
appSearchData,
globalSearch,
searchManagerCallback,
- ident);
+ ident,
+ false); // don't trigger
+ }
+
+ /**
+ * Launches the search UI and triggers the search, as if the user had clicked on the
+ * search button within the dialog.
+ *
+ * @see SearchManager#triggerSearch(String, android.content.ComponentName, android.os.Bundle)
+ */
+ public void triggerSearch(String query,
+ ComponentName launchActivity,
+ Bundle appSearchData,
+ ISearchManagerCallback searchManagerCallback,
+ boolean globalSearch,
+ int ident) {
+ getSearchDialog().startSearch(
+ query,
+ false,
+ launchActivity,
+ appSearchData,
+ globalSearch,
+ searchManagerCallback,
+ ident,
+ true); // triger search after launching
}
/**
diff --git a/core/java/android/service/wallpaper/IWallpaperConnection.aidl b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
new file mode 100644
index 0000000..b09ccab
--- /dev/null
+++ b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.service.wallpaper;
+
+import android.os.ParcelFileDescriptor;
+import android.service.wallpaper.IWallpaperEngine;
+
+/**
+ * @hide
+ */
+interface IWallpaperConnection {
+ void attachEngine(IWallpaperEngine engine);
+ ParcelFileDescriptor setWallpaper(String name);
+}
diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
new file mode 100644
index 0000000..bbd9dde
--- /dev/null
+++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.service.wallpaper;
+
+/**
+ * @hide
+ */
+oneway interface IWallpaperEngine {
+ void setDesiredSize(int width, int height);
+ void setVisibility(boolean visible);
+ void destroy();
+}
diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl
new file mode 100644
index 0000000..bc7a1d7
--- /dev/null
+++ b/core/java/android/service/wallpaper/IWallpaperService.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.service.wallpaper;
+
+import android.service.wallpaper.IWallpaperConnection;
+
+/**
+ * @hide
+ */
+oneway interface IWallpaperService {
+ void attach(IWallpaperConnection connection,
+ IBinder windowToken, int windowType, boolean isPreview,
+ int reqWidth, int reqHeight);
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
new file mode 100644
index 0000000..2cdfc66
--- /dev/null
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -0,0 +1,698 @@
+/*
+ * 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.service.wallpaper;
+
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.view.BaseIWindow;
+import com.android.internal.view.BaseSurfaceHolder;
+
+import android.app.Service;
+import android.app.WallpaperManager;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.IWindowSession;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewRoot;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+
+/**
+ * A wallpaper service is responsible for showing a live wallpaper behind
+ * applications that would like to sit on top of it.
+ * @hide Live Wallpaper
+ */
+public abstract class WallpaperService extends Service {
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ public static final String SERVICE_INTERFACE =
+ "android.service.wallpaper.WallpaperService";
+
+ static final String TAG = "WallpaperService";
+ static final boolean DEBUG = false;
+
+ private static final int DO_ATTACH = 10;
+ private static final int DO_DETACH = 20;
+ private static final int DO_SET_DESIRED_SIZE = 30;
+
+ private static final int MSG_UPDATE_SURFACE = 10000;
+ private static final int MSG_VISIBILITY_CHANGED = 10010;
+ private static final int MSG_WALLPAPER_OFFSETS = 10020;
+ private static final int MSG_WINDOW_RESIZED = 10030;
+ private static final int MSG_TOUCH_EVENT = 10040;
+
+ /**
+ * The actual implementation of a wallpaper. A wallpaper service may
+ * have multiple instances running (for example as a real wallpaper
+ * and as a preview), each of which is represented by its own Engine
+ * instance. You must implement {@link WallpaperService#onCreateEngine()}
+ * to return your concrete Engine implementation.
+ */
+ public class Engine {
+ IWallpaperEngineWrapper mIWallpaperEngine;
+
+ // Copies from mIWallpaperEngine.
+ HandlerCaller mCaller;
+ IWallpaperConnection mConnection;
+ IBinder mWindowToken;
+
+ boolean mInitializing = true;
+ boolean mVisible;
+ boolean mDestroyed;
+
+ // Current window state.
+ boolean mCreated;
+ boolean mIsCreating;
+ boolean mDrawingAllowed;
+ int mWidth;
+ int mHeight;
+ int mFormat;
+ int mType;
+ int mCurWidth;
+ int mCurHeight;
+ int mWindowFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ int mCurWindowFlags = mWindowFlags;
+ boolean mDestroyReportNeeded;
+ final Rect mVisibleInsets = new Rect();
+ final Rect mWinFrame = new Rect();
+ final Rect mContentInsets = new Rect();
+
+ final WindowManager.LayoutParams mLayout
+ = new WindowManager.LayoutParams();
+ IWindowSession mSession;
+
+ final Object mLock = new Object();
+ boolean mOffsetMessageEnqueued;
+ float mPendingXOffset;
+ float mPendingYOffset;
+ MotionEvent mPendingMove;
+
+ final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
+
+ @Override
+ public boolean onAllowLockCanvas() {
+ return mDrawingAllowed;
+ }
+
+ @Override
+ public void onRelayoutContainer() {
+ Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
+ mCaller.sendMessage(msg);
+ }
+
+ @Override
+ public void onUpdateSurface() {
+ Message msg = mCaller.obtainMessage(MSG_UPDATE_SURFACE);
+ mCaller.sendMessage(msg);
+ }
+
+ public boolean isCreating() {
+ return mIsCreating;
+ }
+
+ @Override
+ public void setFixedSize(int width, int height) {
+ throw new UnsupportedOperationException(
+ "Wallpapers currently only support sizing from layout");
+ }
+
+ public void setKeepScreenOn(boolean screenOn) {
+ throw new UnsupportedOperationException(
+ "Wallpapers do not support keep screen on");
+ }
+
+ };
+
+ final BaseIWindow mWindow = new BaseIWindow() {
+ @Override
+ public boolean onDispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
+ synchronized (mLock) {
+ if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (mPendingMove != null) {
+ mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
+ mPendingMove.recycle();
+ }
+ mPendingMove = event;
+ } else {
+ mPendingMove = null;
+ }
+ Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
+ event);
+ mCaller.sendMessage(msg);
+ }
+ return false;
+ }
+
+ @Override
+ public void resized(int w, int h, Rect coveredInsets,
+ Rect visibleInsets, boolean reportDraw) {
+ Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
+ reportDraw ? 1 : 0);
+ mCaller.sendMessage(msg);
+ }
+
+ @Override
+ public void dispatchAppVisibility(boolean visible) {
+ // We don't do this in preview mode; we'll let the preview
+ // activity tell us when to run.
+ if (!mIWallpaperEngine.mIsPreview) {
+ Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
+ visible ? 1 : 0);
+ mCaller.sendMessage(msg);
+ }
+ }
+
+ @Override
+ public void dispatchWallpaperOffsets(float x, float y) {
+ synchronized (mLock) {
+ mPendingXOffset = x;
+ mPendingYOffset = y;
+ if (!mOffsetMessageEnqueued) {
+ mOffsetMessageEnqueued = true;
+ Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS);
+ mCaller.sendMessage(msg);
+ }
+ }
+ }
+
+ };
+
+ /**
+ * Provides access to the surface in which this wallpaper is drawn.
+ */
+ public SurfaceHolder getSurfaceHolder() {
+ return mSurfaceHolder;
+ }
+
+ /**
+ * Convenience for {@link WallpaperManager#getDesiredMinimumWidth()
+ * WallpaperManager.getDesiredMinimumWidth()}, returning the width
+ * that the system would like this wallpaper to run in.
+ */
+ public int getDesiredMinimumWidth() {
+ return mIWallpaperEngine.mReqWidth;
+ }
+
+ /**
+ * Convenience for {@link WallpaperManager#getDesiredMinimumHeight()
+ * WallpaperManager.getDesiredMinimumHeight()}, returning the height
+ * that the system would like this wallpaper to run in.
+ */
+ public int getDesiredMinimumHeight() {
+ return mIWallpaperEngine.mReqHeight;
+ }
+
+ /**
+ * Return whether the wallpaper is currently visible to the user,
+ * this is the last value supplied to
+ * {@link #onVisibilityChanged(boolean)}.
+ */
+ public boolean isVisible() {
+ return mVisible;
+ }
+
+ /**
+ * Returns true if this engine is running in preview mode -- that is,
+ * it is being shown to the user before they select it as the actual
+ * wallpaper.
+ */
+ public boolean isPreview() {
+ return mIWallpaperEngine.mIsPreview;
+ }
+
+ /**
+ * Control whether this wallpaper will receive raw touch events
+ * from the window manager as the user interacts with the window
+ * that is currently displaying the wallpaper. By default they
+ * are turned off. If enabled, the events will be received in
+ * {@link #onTouchEvent(MotionEvent)}.
+ */
+ public void setTouchEventsEnabled(boolean enabled) {
+ mWindowFlags = enabled
+ ? (mWindowFlags&~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
+ : (mWindowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ if (mCreated) {
+ updateSurface(false, false);
+ }
+ }
+
+ /**
+ * Called once to initialize the engine. After returning, the
+ * engine's surface will be created by the framework.
+ */
+ public void onCreate(SurfaceHolder surfaceHolder) {
+ }
+
+ /**
+ * Called right before the engine is going away. After this the
+ * surface will be destroyed and this Engine object is no longer
+ * valid.
+ */
+ public void onDestroy() {
+ }
+
+ /**
+ * Called to inform you of the wallpaper becoming visible or
+ * hidden. <em>It is very important that a wallpaper only use
+ * CPU while it is visible.</em>.
+ */
+ public void onVisibilityChanged(boolean visible) {
+ }
+
+ /**
+ * Called as the user performs touch-screen interaction with the
+ * window that is currently showing this wallpaper. Note that the
+ * events you receive here are driven by the actual application the
+ * user is interacting with, so if it is slow you will get viewer
+ * move events.
+ */
+ public void onTouchEvent(MotionEvent event) {
+ }
+
+ /**
+ * Called to inform you of the wallpaper's offsets changing
+ * within its contain, corresponding to the container's
+ * call to {@link WallpaperManager#setWallpaperOffsets(IBinder, float, float)
+ * WallpaperManager.setWallpaperOffsets()}.
+ */
+ public void onOffsetsChanged(float xOffset, float yOffset,
+ int xPixelOffset, int yPixelOffset) {
+ }
+
+ /**
+ * Called when an application has changed the desired virtual size of
+ * the wallpaper.
+ */
+ public void onDesiredSizeChanged(int desiredWidth, int desiredHeight) {
+ }
+
+ /**
+ * Convenience for {@link SurfaceHolder.Callback#surfaceChanged
+ * SurfaceHolder.Callback.surfaceChanged()}.
+ */
+ public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ }
+
+ /**
+ * Convenience for {@link SurfaceHolder.Callback#surfaceCreated
+ * SurfaceHolder.Callback.surfaceCreated()}.
+ */
+ public void onSurfaceCreated(SurfaceHolder holder) {
+ }
+
+ /**
+ * Convenience for {@link SurfaceHolder.Callback#surfaceDestroyed
+ * SurfaceHolder.Callback.surfaceDestroyed()}.
+ */
+ public void onSurfaceDestroyed(SurfaceHolder holder) {
+ }
+
+ void updateSurface(boolean forceRelayout, boolean forceReport) {
+ if (mDestroyed) {
+ Log.w(TAG, "Ignoring updateSurface: destroyed");
+ }
+
+ int myWidth = mSurfaceHolder.getRequestedWidth();
+ if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.FILL_PARENT;
+ int myHeight = mSurfaceHolder.getRequestedHeight();
+ if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.FILL_PARENT;
+
+ final boolean creating = !mCreated;
+ final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
+ boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
+ final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
+ final boolean flagsChanged = mCurWindowFlags != mWindowFlags;
+ if (forceRelayout || creating || formatChanged || sizeChanged
+ || typeChanged || flagsChanged) {
+
+ if (DEBUG) Log.v(TAG, "Changes: creating=" + creating
+ + " format=" + formatChanged + " size=" + sizeChanged);
+
+ try {
+ mWidth = myWidth;
+ mHeight = myHeight;
+ mFormat = mSurfaceHolder.getRequestedFormat();
+ mType = mSurfaceHolder.getRequestedType();
+
+ mLayout.x = 0;
+ mLayout.y = 0;
+ mLayout.width = myWidth;
+ mLayout.height = myHeight;
+
+ mLayout.format = mFormat;
+
+ mCurWindowFlags = mWindowFlags;
+ mLayout.flags = mWindowFlags
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ ;
+
+ mLayout.memoryType = mType;
+ mLayout.token = mWindowToken;
+
+ if (!mCreated) {
+ mLayout.type = mIWallpaperEngine.mWindowType;
+ mLayout.gravity = Gravity.LEFT|Gravity.TOP;
+ mLayout.windowAnimations =
+ com.android.internal.R.style.Animation_Wallpaper;
+ mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets);
+ }
+
+ mSurfaceHolder.mSurfaceLock.lock();
+ mDrawingAllowed = true;
+
+ final int relayoutResult = mSession.relayout(
+ mWindow, mLayout, mWidth, mHeight,
+ View.VISIBLE, false, mWinFrame, mContentInsets,
+ mVisibleInsets, mSurfaceHolder.mSurface);
+
+ if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
+ + ", frame=" + mWinFrame);
+
+ int w = mWinFrame.width();
+ if (mCurWidth != w) {
+ sizeChanged = true;
+ mCurWidth = w;
+ }
+ int h = mWinFrame.height();
+ if (mCurHeight != h) {
+ sizeChanged = true;
+ mCurHeight = h;
+ }
+
+ mSurfaceHolder.mSurfaceLock.unlock();
+
+ try {
+ mDestroyReportNeeded = true;
+
+ SurfaceHolder.Callback callbacks[] = null;
+ synchronized (mSurfaceHolder.mCallbacks) {
+ final int N = mSurfaceHolder.mCallbacks.size();
+ if (N > 0) {
+ callbacks = new SurfaceHolder.Callback[N];
+ mSurfaceHolder.mCallbacks.toArray(callbacks);
+ }
+ }
+
+ if (!mCreated) {
+ mIsCreating = true;
+ if (DEBUG) Log.v(TAG, "onSurfaceCreated("
+ + mSurfaceHolder + "): " + this);
+ onSurfaceCreated(mSurfaceHolder);
+ if (callbacks != null) {
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceCreated(mSurfaceHolder);
+ }
+ }
+ }
+ if (forceReport || creating || formatChanged || sizeChanged) {
+ if (DEBUG) {
+ RuntimeException e = new RuntimeException();
+ e.fillInStackTrace();
+ Log.w(TAG, "forceReport=" + forceReport + " creating=" + creating
+ + " formatChanged=" + formatChanged
+ + " sizeChanged=" + sizeChanged, e);
+ }
+ if (DEBUG) Log.v(TAG, "onSurfaceChanged("
+ + mSurfaceHolder + ", " + mFormat
+ + ", " + mCurWidth + ", " + mCurHeight
+ + "): " + this);
+ onSurfaceChanged(mSurfaceHolder, mFormat,
+ mCurWidth, mCurHeight);
+ if (callbacks != null) {
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceChanged(mSurfaceHolder, mFormat,
+ mCurWidth, mCurHeight);
+ }
+ }
+ }
+ } finally {
+ mIsCreating = false;
+ mCreated = true;
+ if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+ mSession.finishDrawing(mWindow);
+ }
+ }
+ } catch (RemoteException ex) {
+ }
+ if (DEBUG) Log.v(
+ TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
+ " w=" + mLayout.width + " h=" + mLayout.height);
+ }
+ }
+
+ void attach(IWallpaperEngineWrapper wrapper) {
+ if (DEBUG) Log.v(TAG, "attach: " + this + " wrapper=" + wrapper);
+ if (mDestroyed) {
+ return;
+ }
+
+ mIWallpaperEngine = wrapper;
+ mCaller = wrapper.mCaller;
+ mConnection = wrapper.mConnection;
+ mWindowToken = wrapper.mWindowToken;
+ mSurfaceHolder.setSizeFromLayout();
+ mInitializing = true;
+ mSession = ViewRoot.getWindowSession(getMainLooper());
+ mWindow.setSession(mSession);
+
+ if (DEBUG) Log.v(TAG, "onCreate(): " + this);
+ onCreate(mSurfaceHolder);
+
+ mInitializing = false;
+ updateSurface(false, false);
+ }
+
+ void doDesiredSizeChanged(int desiredWidth, int desiredHeight) {
+ if (!mDestroyed) {
+ if (DEBUG) Log.v(TAG, "onDesiredSizeChanged("
+ + desiredWidth + "," + desiredHeight + "): " + this);
+ onDesiredSizeChanged(desiredWidth, desiredHeight);
+ }
+ }
+
+ void doVisibilityChanged(boolean visible) {
+ if (!mDestroyed) {
+ mVisible = visible;
+ if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible
+ + "): " + this);
+ onVisibilityChanged(visible);
+ }
+ }
+
+ void doOffsetsChanged() {
+ if (mDestroyed) {
+ return;
+ }
+
+ float xOffset;
+ float yOffset;
+ synchronized (mLock) {
+ xOffset = mPendingXOffset;
+ yOffset = mPendingYOffset;
+ mOffsetMessageEnqueued = false;
+ }
+ if (DEBUG) Log.v(TAG, "Offsets change in " + this
+ + ": " + xOffset + "," + yOffset);
+ final int availw = mIWallpaperEngine.mReqWidth-mCurWidth;
+ final int xPixels = availw > 0 ? -(int)(availw*xOffset+.5f) : 0;
+ final int availh = mIWallpaperEngine.mReqHeight-mCurHeight;
+ final int yPixels = availh > 0 ? -(int)(availh*yOffset+.5f) : 0;
+ onOffsetsChanged(xOffset, yOffset, xPixels, yPixels);
+ }
+
+ void detach() {
+ mDestroyed = true;
+
+ if (mVisible) {
+ mVisible = false;
+ if (DEBUG) Log.v(TAG, "onVisibilityChanged(false): " + this);
+ onVisibilityChanged(false);
+ }
+
+ if (mDestroyReportNeeded) {
+ mDestroyReportNeeded = false;
+ SurfaceHolder.Callback callbacks[];
+ synchronized (mSurfaceHolder.mCallbacks) {
+ callbacks = new SurfaceHolder.Callback[
+ mSurfaceHolder.mCallbacks.size()];
+ mSurfaceHolder.mCallbacks.toArray(callbacks);
+ }
+ for (SurfaceHolder.Callback c : callbacks) {
+ c.surfaceDestroyed(mSurfaceHolder);
+ }
+ if (DEBUG) Log.v(TAG, "onSurfaceDestroyed("
+ + mSurfaceHolder + "): " + this);
+ onSurfaceDestroyed(mSurfaceHolder);
+ }
+
+ if (DEBUG) Log.v(TAG, "onDestroy(): " + this);
+ onDestroy();
+
+ if (mCreated) {
+ try {
+ mSession.remove(mWindow);
+ } catch (RemoteException e) {
+ }
+ mSurfaceHolder.mSurface.clear();
+ mCreated = false;
+ }
+ }
+ }
+
+ class IWallpaperEngineWrapper extends IWallpaperEngine.Stub
+ implements HandlerCaller.Callback {
+ private final HandlerCaller mCaller;
+
+ final IWallpaperConnection mConnection;
+ final IBinder mWindowToken;
+ final int mWindowType;
+ final boolean mIsPreview;
+ int mReqWidth;
+ int mReqHeight;
+
+ Engine mEngine;
+
+ IWallpaperEngineWrapper(WallpaperService context,
+ IWallpaperConnection conn, IBinder windowToken,
+ int windowType, boolean isPreview, int reqWidth, int reqHeight) {
+ mCaller = new HandlerCaller(context, this);
+ mConnection = conn;
+ mWindowToken = windowToken;
+ mWindowType = windowType;
+ mIsPreview = isPreview;
+ mReqWidth = reqWidth;
+ mReqHeight = reqHeight;
+
+ Message msg = mCaller.obtainMessage(DO_ATTACH);
+ mCaller.sendMessage(msg);
+ }
+
+ public void setDesiredSize(int width, int height) {
+ Message msg = mCaller.obtainMessageII(DO_SET_DESIRED_SIZE, width, height);
+ mCaller.sendMessage(msg);
+ }
+
+ public void setVisibility(boolean visible) {
+ Message msg = mCaller.obtainMessageI(MSG_VISIBILITY_CHANGED,
+ visible ? 1 : 0);
+ mCaller.sendMessage(msg);
+ }
+
+ public void destroy() {
+ Message msg = mCaller.obtainMessage(DO_DETACH);
+ mCaller.sendMessage(msg);
+ }
+
+ public void executeMessage(Message message) {
+ switch (message.what) {
+ case DO_ATTACH: {
+ try {
+ mConnection.attachEngine(this);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Wallpaper host disappeared", e);
+ return;
+ }
+ Engine engine = onCreateEngine();
+ mEngine = engine;
+ engine.attach(this);
+ return;
+ }
+ case DO_DETACH: {
+ mEngine.detach();
+ return;
+ }
+ case DO_SET_DESIRED_SIZE: {
+ mEngine.doDesiredSizeChanged(message.arg1, message.arg2);
+ return;
+ }
+ case MSG_UPDATE_SURFACE:
+ mEngine.updateSurface(true, false);
+ break;
+ case MSG_VISIBILITY_CHANGED:
+ if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
+ + ": " + message.arg1);
+ mEngine.doVisibilityChanged(message.arg1 != 0);
+ break;
+ case MSG_WALLPAPER_OFFSETS: {
+ mEngine.doOffsetsChanged();
+ } break;
+ case MSG_WINDOW_RESIZED: {
+ final boolean reportDraw = message.arg1 != 0;
+ mEngine.updateSurface(true, false);
+ if (reportDraw) {
+ try {
+ mEngine.mSession.finishDrawing(mEngine.mWindow);
+ } catch (RemoteException e) {
+ }
+ }
+ } break;
+ case MSG_TOUCH_EVENT: {
+ MotionEvent ev = (MotionEvent)message.obj;
+ synchronized (mEngine.mLock) {
+ if (mEngine.mPendingMove == ev) {
+ mEngine.mPendingMove = null;
+ }
+ }
+ mEngine.onTouchEvent(ev);
+ ev.recycle();
+ } break;
+ default :
+ Log.w(TAG, "Unknown message type " + message.what);
+ }
+ }
+ }
+
+ /**
+ * Implements the internal {@link IWallpaperService} interface to convert
+ * incoming calls to it back to calls on an {@link WallpaperService}.
+ */
+ class IWallpaperServiceWrapper extends IWallpaperService.Stub {
+ private final WallpaperService mTarget;
+
+ public IWallpaperServiceWrapper(WallpaperService context) {
+ mTarget = context;
+ }
+
+ public void attach(IWallpaperConnection conn, IBinder windowToken,
+ int windowType, boolean isPreview, int reqWidth, int reqHeight) {
+ new IWallpaperEngineWrapper(mTarget, conn, windowToken,
+ windowType, isPreview, reqWidth, reqHeight);
+ }
+ }
+
+ /**
+ * Implement to return the implementation of the internal accessibility
+ * service interface. Subclasses should not override.
+ */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return new IWallpaperServiceWrapper(this);
+ }
+
+ public abstract Engine onCreateEngine();
+}
diff --git a/core/java/android/speech/IRecognitionListener.aidl b/core/java/android/speech/IRecognitionListener.aidl
deleted file mode 100644
index 2da2258..0000000
--- a/core/java/android/speech/IRecognitionListener.aidl
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.speech;
-
-import android.os.Bundle;
-import android.speech.RecognitionResult;
-
-/**
- * Listener for speech recognition events, used with RecognitionService.
- * This gives you both the final recognition results, as well as various
- * intermediate events that can be used to show visual feedback to the user.
- * {@hide}
- */
-interface IRecognitionListener {
- /** Called when the endpointer is ready for the user to start speaking. */
- void onReadyForSpeech(in Bundle noiseParams);
-
- /** The user has started to speak. */
- void onBeginningOfSpeech();
-
- /** The sound level in the audio stream has changed. */
- void onRmsChanged(in float rmsdB);
-
- /**
- * More sound has been received. Buffer is a byte buffer containing
- * a sequence of 16-bit shorts.
- */
- void onBufferReceived(in byte[] buffer);
-
- /** Called after the user stops speaking. */
- void onEndOfSpeech();
-
- /**
- * A network or recognition error occurred. The code is defined in
- * {@link android.speech.RecognitionResult}
- */
- void onError(in int error);
-
- /**
- * Called when recognition results are ready.
- * @param results: an ordered list of the most likely results (N-best list).
- * @param key: a key associated with the results. The same results can
- * be retrieved asynchronously later using the key, if available.
- */
- void onResults(in List<RecognitionResult> results, long key);
-}
diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl
deleted file mode 100644
index a18c380..0000000
--- a/core/java/android/speech/IRecognitionService.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.speech;
-
-import android.content.Intent;
-import android.speech.IRecognitionListener;
-import android.speech.RecognitionResult;
-
-// A Service interface to speech recognition. Call startListening when
-// you want to begin capturing audio; RecognitionService will automatically
-// determine when the user has finished speaking, stream the audio to the
-// recognition servers, and notify you when results are ready.
-/** {@hide} */
-interface IRecognitionService {
- // Start listening for speech. Can only call this from one thread at once.
- // see RecognizerIntent.java for constants used to specify the intent.
- void startListening(in Intent recognizerIntent,
- in IRecognitionListener listener);
-
- List<RecognitionResult> getRecognitionResults(in long key);
-
- void cancel();
-}
diff --git a/core/java/android/speech/RecognitionResult.aidl b/core/java/android/speech/RecognitionResult.aidl
deleted file mode 100644
index 59e53ab..0000000
--- a/core/java/android/speech/RecognitionResult.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.speech;
-
-parcelable RecognitionResult;
diff --git a/core/java/android/speech/RecognitionResult.java b/core/java/android/speech/RecognitionResult.java
deleted file mode 100644
index 978106b..0000000
--- a/core/java/android/speech/RecognitionResult.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.speech;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * RecognitionResult is a passive object that stores a single recognized
- * query and its search result.
- * TODO: revisit and improve. May be we should have a separate result
- * object for each type, and put them (type/value) in bundle?
- *
- * {@hide}
- */
-public class RecognitionResult implements Parcelable {
- /**
- * Status of the recognize request.
- */
- public static final int NETWORK_TIMEOUT = 1; // Network operation timed out.
- public static final int NETWORK_ERROR = 2; // Other networkrelated errors.
- public static final int AUDIO_ERROR = 3; // Audio recording error.
- public static final int SERVER_ERROR = 4; // Server sends error status.
- public static final int CLIENT_ERROR = 5; // Other client side errors.
- public static final int SPEECH_TIMEOUT = 6; // No speech input
- public static final int NO_MATCH = 7; // No recognition result matched.
- public static final int SERVICE_BUSY = 8; // RecognitionService busy.
-
- /**
- * Type of the recognition results.
- */
- public static final int RAW_RECOGNITION_RESULT = 0;
- public static final int WEB_SEARCH_RESULT = 1;
- public static final int CONTACT_RESULT = 2;
-
- /**
- * A factory method to create a raw RecognitionResult
- *
- * @param sentence the recognized text.
- */
- public static RecognitionResult newRawRecognitionResult(String sentence) {
- return new RecognitionResult(RAW_RECOGNITION_RESULT, sentence, null, null);
- }
-
- /**
- * A factory method to create RecognitionResult for contacts.
- *
- * @param contact the contact name.
- * @param phoneType the phone type.
- * @param callAction whether this result included a command to "call", or just the contact name.
- */
- public static RecognitionResult newContactResult(String contact, int phoneType,
- boolean callAction) {
- return new RecognitionResult(CONTACT_RESULT, contact, phoneType, callAction);
- }
-
- /**
- * A factory method to create a RecognitionResult for Web Search Query.
- *
- * @param query the query string.
- * @param html the html page of the search result.
- * @param url the url that performs the search with the query.
- */
- public static RecognitionResult newWebResult(String query, String html, String url) {
- return new RecognitionResult(WEB_SEARCH_RESULT, query, html, url);
- }
-
- public static final Parcelable.Creator<RecognitionResult> CREATOR
- = new Parcelable.Creator<RecognitionResult>() {
-
- public RecognitionResult createFromParcel(Parcel in) {
- return new RecognitionResult(in);
- }
-
- public RecognitionResult[] newArray(int size) {
- return new RecognitionResult[size];
- }
- };
-
- /**
- * Result type.
- */
- public final int mResultType;
-
- /**
- * The recognized string when mResultType is WEB_SEARCH_RESULT.
- * The name of the contact when mResultType is CONTACT_RESULT.
- */
- public final String mText;
-
- /**
- * The HTML result page for the query. If this is null, then the
- * application must use the url field to get the HTML result page.
- */
- public final String mHtml;
-
- /**
- * The url to get the result page for the query string. The
- * application must use this url instead of performing the search
- * with the query.
- */
- public final String mUrl;
-
- /**
- * Phone number type. This is valid only when mResultType == CONTACT_RESULT.
- */
- public final int mPhoneType;
-
- /**
- * Whether a contact recognition result included a command to "call". This is valid only
- * when mResultType == CONTACT_RESULT.
- */
- public final boolean mCallAction;
-
- private RecognitionResult(int type, String query, String html, String url) {
- mResultType = type;
- mText = query;
- mHtml = html;
- mUrl = url;
- mPhoneType = -1;
- mCallAction = false;
- }
-
- private RecognitionResult(int type, String query, int phoneType, boolean callAction) {
- mResultType = type;
- mText = query;
- mPhoneType = phoneType;
- mHtml = null;
- mUrl = null;
- mCallAction = callAction;
- }
-
- private RecognitionResult(Parcel in) {
- mResultType = in.readInt();
- mText = in.readString();
- mHtml= in.readString();
- mUrl= in.readString();
- mPhoneType = in.readInt();
- mCallAction = (in.readInt() == 1);
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mResultType);
- out.writeString(mText);
- out.writeString(mHtml);
- out.writeString(mUrl);
- out.writeInt(mPhoneType);
- out.writeInt(mCallAction ? 1 : 0);
- }
-
-
- @Override
- public String toString() {
- String resultType[] = { "RAW", "WEB", "CONTACT" };
- return "[type=" + resultType[mResultType] +
- ", text=" + mText+ ", mUrl=" + mUrl + ", html=" + mHtml + "]";
- }
-
- public int describeContents() {
- // no special description
- return 0;
- }
-}
diff --git a/core/java/android/speech/RecognitionServiceUtil.java b/core/java/android/speech/RecognitionServiceUtil.java
deleted file mode 100644
index a8c7868..0000000
--- a/core/java/android/speech/RecognitionServiceUtil.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.speech;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.speech.RecognitionResult;
-import android.util.Log;
-
-import java.util.List;
-
-/**
- * Utils for Google's network-based speech recognizer, which lets you perform
- * speech-to-text translation through RecognitionService. IRecognitionService
- * and IRecognitionListener are the core interfaces; you begin recognition
- * through IRecognitionService and subscribe to callbacks about when the user
- * stopped speaking, results come in, errors, etc. through IRecognitionListener.
- * RecognitionServiceUtil includes default IRecognitionListener and
- * ServiceConnection implementations to reduce the amount of boilerplate.
- *
- * The Service provides no user interface. See RecognitionActivity if you
- * want the standard voice search UI.
- *
- * Below is a small skeleton of how to use the recognizer:
- *
- * ServiceConnection conn = new RecognitionServiceUtil.Connection();
- * mContext.bindService(RecognitionServiceUtil.sDefaultIntent,
- * conn, Context.BIND_AUTO_CREATE);
- * IRecognitionListener listener = new RecognitionServiceWrapper.NullListener() {
- * public void onResults(List<String> results) {
- * // Do something with recognition transcripts
- * }
- * }
- *
- * // Must wait for conn.mService to be populated, then call below
- * conn.mService.startListening(null, listener);
- *
- * {@hide}
- */
-public class RecognitionServiceUtil {
- public static final Intent sDefaultIntent = new Intent(
- RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
-
- // Recognize request parameters
- public static final String USE_LOCATION = "useLocation";
- public static final String CONTACT_AUTH_TOKEN = "contactAuthToken";
-
- // Bundles
- public static final String NOISE_LEVEL = "NoiseLevel";
- public static final String SIGNAL_NOISE_RATIO = "SignalNoiseRatio";
-
- private RecognitionServiceUtil() {}
-
- /**
- * IRecognitionListener which does nothing in response to recognition
- * callbacks. You can subclass from this and override only the methods
- * whose events you want to respond to.
- */
- public static class NullListener extends IRecognitionListener.Stub {
- public void onReadyForSpeech(Bundle bundle) {}
- public void onBeginningOfSpeech() {}
- public void onRmsChanged(float rmsdB) {}
- public void onBufferReceived(byte[] buf) {}
- public void onEndOfSpeech() {}
- public void onError(int error) {}
- public void onResults(List<RecognitionResult> results, long key) {}
- }
-
- /**
- * Basic ServiceConnection which just records mService variable.
- */
- public static class Connection implements ServiceConnection {
- public IRecognitionService mService;
-
- public synchronized void onServiceConnected(ComponentName name, IBinder service) {
- mService = IRecognitionService.Stub.asInterface(service);
- }
-
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
- }
-}
diff --git a/core/java/android/syncml/pim/vcard/ContactStruct.java b/core/java/android/syncml/pim/vcard/ContactStruct.java
index ecd719d..4b4c394 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;
@@ -780,17 +781,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;
}
}
@@ -830,7 +830,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());
@@ -856,8 +856,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());
@@ -883,8 +882,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());
@@ -893,8 +891,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);
}
}
}
@@ -918,7 +915,7 @@ public class ContactStruct {
if (resolver != null) {
contentValuesArray.add(values);
} else {
- provider.nonTransactionalInsert(Extensions.CONTENT_URI, values);
+ provider.insert(Extensions.CONTENT_URI, values);
}
}
}
@@ -942,7 +939,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);
}
}
}
@@ -960,12 +957,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/syncml/pim/vcard/VCardDataBuilder.java b/core/java/android/syncml/pim/vcard/VCardDataBuilder.java
index a0513f1..f2a2733 100644
--- a/core/java/android/syncml/pim/vcard/VCardDataBuilder.java
+++ b/core/java/android/syncml/pim/vcard/VCardDataBuilder.java
@@ -28,6 +28,7 @@ import android.syncml.pim.PropertyNode;
import android.syncml.pim.VBuilder;
import android.syncml.pim.VNode;
import android.syncml.pim.VParser;
+import android.text.TextUtils;
import android.util.CharsetUtils;
import android.util.Log;
@@ -403,7 +404,10 @@ public class VCardDataBuilder implements VBuilder {
String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET"));
String encoding = paramMap.getAsString("ENCODING");
- if (targetCharset == null || targetCharset.length() == 0) {
+ Log.d("@@@", String.format("targetCharset: \"%s\", encoding: \"%s\"",
+ targetCharset, encoding));
+
+ if (TextUtils.isEmpty(targetCharset)) {
targetCharset = mTargetCharset;
}
diff --git a/core/java/android/syncml/pim/vcard/VCardParser.java b/core/java/android/syncml/pim/vcard/VCardParser.java
index 6dad852d..9a590dd 100644
--- a/core/java/android/syncml/pim/vcard/VCardParser.java
+++ b/core/java/android/syncml/pim/vcard/VCardParser.java
@@ -17,7 +17,6 @@
package android.syncml.pim.vcard;
import android.syncml.pim.VDataBuilder;
-import android.syncml.pim.VParser;
import android.util.Config;
import android.util.Log;
diff --git a/core/java/android/test/AndroidTestCase.java b/core/java/android/test/AndroidTestCase.java
index de0587a..1015506 100644
--- a/core/java/android/test/AndroidTestCase.java
+++ b/core/java/android/test/AndroidTestCase.java
@@ -30,6 +30,7 @@ import java.lang.reflect.Field;
public class AndroidTestCase extends TestCase {
protected Context mContext;
+ private Context mTestContext;
@Override
protected void setUp() throws Exception {
@@ -43,7 +44,7 @@ public class AndroidTestCase extends TestCase {
public void testAndroidTestCaseSetupProperly() {
assertNotNull("Context is null. setContext should be called before tests are run",
- mContext);
+ mContext);
}
public void setContext(Context context) {
@@ -55,6 +56,25 @@ public class AndroidTestCase extends TestCase {
}
/**
+ * Test context can be used to access resources from the test's own package
+ * as opposed to the resources from the test target package. Access to the
+ * latter is provided by the context set with the {@link #setContext}
+ * method.
+ *
+ * @hide
+ */
+ public void setTestContext(Context context) {
+ mTestContext = context;
+ }
+
+ /**
+ * @hide
+ */
+ public Context getTestContext() {
+ return mTestContext;
+ }
+
+ /**
* Asserts that launching a given activity is protected by a particular permission by
* attempting to start the activity and validating that a {@link SecurityException}
* is thrown that mentions the permission in its error message.
@@ -125,9 +145,9 @@ public class AndroidTestCase extends TestCase {
* to scrub out any class variables. This protects against memory leaks in the case where a
* test case creates a non-static inner class (thus referencing the test case) and gives it to
* someone else to hold onto.
- *
+ *
* @param testCaseClass The class of the derived TestCase implementation.
- *
+ *
* @throws IllegalAccessException
*/
protected void scrubClass(final Class<?> testCaseClass)
diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java
index 2145d7c..22d95d1 100644
--- a/core/java/android/test/InstrumentationTestCase.java
+++ b/core/java/android/test/InstrumentationTestCase.java
@@ -43,11 +43,25 @@ public class InstrumentationTestCase extends TestCase {
*
* @param instrumentation the instrumentation to use with this instance
*/
- public void injectInsrumentation(Instrumentation instrumentation) {
+ public void injectInstrumentation(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
}
/**
+ * Injects instrumentation into this test case. This method is
+ * called by the test runner during test setup.
+ *
+ * @param instrumentation the instrumentation to use with this instance
+ *
+ * @deprecated Incorrect spelling,
+ * use {@link #injectInstrumentation(android.app.Instrumentation) instead.
+ */
+ @Deprecated
+ public void injectInsrumentation(Instrumentation instrumentation) {
+ injectInstrumentation(instrumentation);
+ }
+
+ /**
* Inheritors can access the instrumentation using this.
* @return instrumentation
*/
diff --git a/core/java/android/test/InstrumentationTestSuite.java b/core/java/android/test/InstrumentationTestSuite.java
index 2ab949e..7a78ffb 100644
--- a/core/java/android/test/InstrumentationTestSuite.java
+++ b/core/java/android/test/InstrumentationTestSuite.java
@@ -65,7 +65,7 @@ public class InstrumentationTestSuite extends TestSuite {
public void runTest(Test test, TestResult result) {
if (test instanceof InstrumentationTestCase) {
- ((InstrumentationTestCase) test).injectInsrumentation(mInstrumentation);
+ ((InstrumentationTestCase) test).injectInstrumentation(mInstrumentation);
}
// run the test as usual
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 843754b..944f735 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -19,6 +19,7 @@ package android.text;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
+import android.text.style.ParagraphStyle;
import android.util.FloatMath;
/**
@@ -262,6 +263,14 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
TextUtils.recycle(temp);
+ if (boring && text instanceof Spanned) {
+ Spanned sp = (Spanned) text;
+ Object[] styles = sp.getSpans(0, text.length(), ParagraphStyle.class);
+ if (styles.length > 0) {
+ boring = false;
+ }
+ }
+
if (boring) {
Metrics fm = metrics;
if (fm == null) {
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index c133cf2..f0a5ffd 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -968,7 +968,13 @@ extends Layout
fm.bottom = bottom;
for (int i = 0; i < chooseht.length; i++) {
- chooseht[i].chooseHeight(text, start, end, choosehtv[i], v, fm);
+ if (chooseht[i] instanceof LineHeightSpan.WithDensity) {
+ ((LineHeightSpan.WithDensity) chooseht[i]).
+ chooseHeight(text, start, end, choosehtv[i], v, fm, paint);
+
+ } else {
+ chooseht[i].chooseHeight(text, start, end, choosehtv[i], v, fm);
+ }
}
above = fm.ascent;
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index f13820d..f9e7cac 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -27,6 +27,7 @@ public class TextPaint extends Paint {
public int baselineShift;
public int linkColor;
public int[] drawableState;
+ public float density = 1.0f;
public TextPaint() {
super();
@@ -51,5 +52,6 @@ public class TextPaint extends Paint {
baselineShift = tp.baselineShift;
linkColor = tp.linkColor;
drawableState = tp.drawableState;
+ density = tp.density;
}
}
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index 1a4eb69..9dd8ceb 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -25,7 +25,9 @@ import android.pim.DateException;
import java.util.Calendar;
import java.util.Date;
+import java.util.Formatter;
import java.util.GregorianCalendar;
+import java.util.Locale;
import java.util.TimeZone;
/**
@@ -1040,6 +1042,31 @@ public class DateUtils
/**
* Formats a date or a time range according to the local conventions.
+ * <p>
+ * Note that this is a convenience method. Using it involves creating an
+ * internal {@link java.util.Formatter} instance on-the-fly, which is
+ * somewhat costly in terms of memory and time. This is probably acceptable
+ * if you use the method only rarely, but if you rely on it for formatting a
+ * large number of dates, consider creating and reusing your own
+ * {@link java.util.Formatter} instance and use the version of
+ * {@link #formatDateRange(Context, long, long, int) formatDateRange}
+ * that takes a {@link java.util.Formatter}.
+ *
+ * @param context the context is required only if the time is shown
+ * @param startMillis the start time in UTC milliseconds
+ * @param endMillis the end time in UTC milliseconds
+ * @param flags a bit mask of options See
+ * {@link #formatDateRange(Context, long, long, int) formatDateRange}
+ * @return a string containing the formatted date/time range.
+ */
+ public static String formatDateRange(Context context, long startMillis,
+ long endMillis, int flags) {
+ Formatter f = new Formatter(new StringBuilder(50), Locale.getDefault());
+ return formatDateRange(context, f, startMillis, endMillis, flags).toString();
+ }
+
+ /**
+ * Formats a date or a time range according to the local conventions.
*
* <p>
* Example output strings (date formats in these examples are shown using
@@ -1181,14 +1208,17 @@ public class DateUtils
* instead of "December 31, 2008".
*
* @param context the context is required only if the time is shown
+ * @param formatter the Formatter used for formatting the date range.
+ * Note: be sure to call setLength(0) on StringBuilder passed to
+ * the Formatter constructor unless you want the results to accumulate.
* @param startMillis the start time in UTC milliseconds
* @param endMillis the end time in UTC milliseconds
* @param flags a bit mask of options
*
- * @return a string containing the formatted date/time range.
+ * @return the formatter with the formatted date/time range appended to the string buffer.
*/
- public static String formatDateRange(Context context, long startMillis,
- long endMillis, int flags) {
+ public static Formatter formatDateRange(Context context, Formatter formatter, long startMillis,
+ long endMillis, int flags) {
Resources res = Resources.getSystem();
boolean showTime = (flags & FORMAT_SHOW_TIME) != 0;
boolean showWeekDay = (flags & FORMAT_SHOW_WEEKDAY) != 0;
@@ -1423,8 +1453,7 @@ public class DateUtils
if (noMonthDay && startMonthNum == endMonthNum) {
// Example: "January, 2008"
- String startDateString = startDate.format(defaultDateFormat);
- return startDateString;
+ return formatter.format("%s", startDate.format(defaultDateFormat));
}
if (startYear != endYear || noMonthDay) {
@@ -1436,10 +1465,9 @@ public class DateUtils
// The values that are used in a fullFormat string are specified
// by position.
- dateRange = String.format(fullFormat,
+ return formatter.format(fullFormat,
startWeekDayString, startDateString, startTimeString,
endWeekDayString, endDateString, endTimeString);
- return dateRange;
}
// Get the month, day, and year strings for the start and end dates
@@ -1476,12 +1504,11 @@ public class DateUtils
// The values that are used in a fullFormat string are specified
// by position.
- dateRange = String.format(fullFormat,
+ return formatter.format(fullFormat,
startWeekDayString, startMonthString, startMonthDayString,
startYearString, startTimeString,
endWeekDayString, endMonthString, endMonthDayString,
endYearString, endTimeString);
- return dateRange;
}
if (startDay != endDay) {
@@ -1496,12 +1523,11 @@ public class DateUtils
// The values that are used in a fullFormat string are specified
// by position.
- dateRange = String.format(fullFormat,
+ return formatter.format(fullFormat,
startWeekDayString, startMonthString, startMonthDayString,
startYearString, startTimeString,
endWeekDayString, endMonthString, endMonthDayString,
endYearString, endTimeString);
- return dateRange;
}
// Same start and end day
@@ -1522,6 +1548,7 @@ public class DateUtils
} else {
// Example: "10:00 - 11:00 am"
String timeFormat = res.getString(com.android.internal.R.string.time1_time2);
+ // Don't use the user supplied Formatter because the result will pollute the buffer.
timeString = String.format(timeFormat, startTimeString, endTimeString);
}
}
@@ -1545,7 +1572,7 @@ public class DateUtils
fullFormat = res.getString(com.android.internal.R.string.time_date);
} else {
// Example: "Oct 9"
- return dateString;
+ return formatter.format("%s", dateString);
}
}
} else if (showWeekDay) {
@@ -1554,16 +1581,15 @@ public class DateUtils
fullFormat = res.getString(com.android.internal.R.string.time_wday);
} else {
// Example: "Tue"
- return startWeekDayString;
+ return formatter.format("%s", startWeekDayString);
}
} else if (showTime) {
- return timeString;
+ return formatter.format("%s", timeString);
}
// The values that are used in a fullFormat string are specified
// by position.
- dateRange = String.format(fullFormat, timeString, startWeekDayString, dateString);
- return dateRange;
+ return formatter.format(fullFormat, timeString, startWeekDayString, dateString);
}
/**
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 92f6289..ab33cb3 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -22,6 +22,7 @@ import android.graphics.Rect;
import android.text.*;
import android.widget.TextView;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.MotionEvent;
// XXX this doesn't extend MetaKeyKeyListener because the signatures
@@ -256,8 +257,32 @@ implements MovementMethod
(MetaKeyKeyListener.getMetaState(buffer,
MetaKeyKeyListener.META_SELECTING) != 0);
+ DoubleTapState[] tap = buffer.getSpans(0, buffer.length(),
+ DoubleTapState.class);
+ boolean doubletap = false;
+
+ if (tap.length > 0) {
+ if (event.getEventTime() - tap[0].mWhen <=
+ ViewConfiguration.getDoubleTapTimeout()) {
+ if (sameWord(buffer, off, Selection.getSelectionEnd(buffer))) {
+ doubletap = true;
+ }
+ }
+
+ tap[0].mWhen = event.getEventTime();
+ } else {
+ DoubleTapState newtap = new DoubleTapState();
+ newtap.mWhen = event.getEventTime();
+ buffer.setSpan(newtap, 0, buffer.length(),
+ Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
if (cap) {
Selection.extendSelection(buffer, off);
+ } else if (doubletap) {
+ Selection.setSelection(buffer,
+ findWordStart(buffer, off),
+ findWordEnd(buffer, off));
} else {
Selection.setSelection(buffer, off);
}
@@ -272,6 +297,62 @@ implements MovementMethod
return handled;
}
+ private static class DoubleTapState implements NoCopySpan {
+ long mWhen;
+ }
+
+ private static boolean sameWord(CharSequence text, int one, int two) {
+ int start = findWordStart(text, one);
+ int end = findWordEnd(text, one);
+
+ if (end == start) {
+ return false;
+ }
+
+ return start == findWordStart(text, two) &&
+ end == findWordEnd(text, two);
+ }
+
+ // TODO: Unify with TextView.getWordForDictionary()
+ private static int findWordStart(CharSequence text, int start) {
+ for (; start > 0; start--) {
+ char c = text.charAt(start - 1);
+ int type = Character.getType(c);
+
+ if (c != '\'' &&
+ type != Character.UPPERCASE_LETTER &&
+ type != Character.LOWERCASE_LETTER &&
+ type != Character.TITLECASE_LETTER &&
+ type != Character.MODIFIER_LETTER &&
+ type != Character.DECIMAL_DIGIT_NUMBER) {
+ break;
+ }
+ }
+
+ return start;
+ }
+
+ // TODO: Unify with TextView.getWordForDictionary()
+ private static int findWordEnd(CharSequence text, int end) {
+ int len = text.length();
+
+ for (; end < len; end++) {
+ char c = text.charAt(end);
+ int type = Character.getType(c);
+
+ if (c != '\'' &&
+ type != Character.UPPERCASE_LETTER &&
+ type != Character.LOWERCASE_LETTER &&
+ type != Character.TITLECASE_LETTER &&
+ type != Character.MODIFIER_LETTER &&
+ type != Character.DECIMAL_DIGIT_NUMBER) {
+ break;
+ }
+ }
+
+ return end;
+ }
+
public boolean canSelectArbitrarily() {
return true;
}
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index e420c27..172e9ac 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -434,7 +434,7 @@ public class QwertyKeyListener extends BaseKeyListener {
PICKER_SETS.put('y', "\u00FD\u00FF");
PICKER_SETS.put('z', "\u017A\u017C\u017E");
PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT,
- "\u2026\u00A5\u2022\u00AE\u00A9\u00B1");
+ "\u2026\u00A5\u2022\u00AE\u00A9\u00B1[]{}\\");
};
private boolean showCharacterPicker(View view, Editable content, char c,
diff --git a/core/java/android/text/style/AbsoluteSizeSpan.java b/core/java/android/text/style/AbsoluteSizeSpan.java
index 484f8ce..1214040 100644
--- a/core/java/android/text/style/AbsoluteSizeSpan.java
+++ b/core/java/android/text/style/AbsoluteSizeSpan.java
@@ -24,13 +24,28 @@ import android.text.TextUtils;
public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableSpan {
private final int mSize;
+ private boolean mDip;
+ /**
+ * Set the text size to <code>size</code> physical pixels.
+ */
public AbsoluteSizeSpan(int size) {
mSize = size;
}
+ /**
+ * Set the text size to <code>size</code> physical pixels,
+ * or to <code>size</code> device-independent pixels if
+ * <code>dip</code> is true.
+ */
+ public AbsoluteSizeSpan(int size, boolean dip) {
+ mSize = size;
+ mDip = dip;
+ }
+
public AbsoluteSizeSpan(Parcel src) {
mSize = src.readInt();
+ mDip = src.readInt() != 0;
}
public int getSpanTypeId() {
@@ -43,19 +58,32 @@ public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableS
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mSize);
+ dest.writeInt(mDip ? 1 : 0);
}
public int getSize() {
return mSize;
}
+ public boolean getDip() {
+ return mDip;
+ }
+
@Override
public void updateDrawState(TextPaint ds) {
- ds.setTextSize(mSize);
+ if (mDip) {
+ ds.setTextSize(mSize * ds.density);
+ } else {
+ ds.setTextSize(mSize);
+ }
}
@Override
public void updateMeasureState(TextPaint ds) {
- ds.setTextSize(mSize);
+ if (mDip) {
+ ds.setTextSize(mSize * ds.density);
+ } else {
+ ds.setTextSize(mSize);
+ }
}
}
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 86ef5f6..74b9463 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -36,6 +36,7 @@ public class ImageSpan extends DynamicDrawableSpan {
/**
* @deprecated Use {@link #ImageSpan(Context, Bitmap)} instead.
*/
+ @Deprecated
public ImageSpan(Bitmap b) {
this(null, b, ALIGN_BOTTOM);
}
@@ -43,6 +44,7 @@ public class ImageSpan extends DynamicDrawableSpan {
/**
* @deprecated Use {@link #ImageSpan(Context, Bitmap, int) instead.
*/
+ @Deprecated
public ImageSpan(Bitmap b, int verticalAlignment) {
this(null, b, verticalAlignment);
}
diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java
index c0ef97c..44a1706 100644
--- a/core/java/android/text/style/LineHeightSpan.java
+++ b/core/java/android/text/style/LineHeightSpan.java
@@ -19,6 +19,7 @@ package android.text.style;
import android.graphics.Paint;
import android.graphics.Canvas;
import android.text.Layout;
+import android.text.TextPaint;
public interface LineHeightSpan
extends ParagraphStyle, WrapTogetherSpan
@@ -26,4 +27,10 @@ extends ParagraphStyle, WrapTogetherSpan
public void chooseHeight(CharSequence text, int start, int end,
int spanstartv, int v,
Paint.FontMetricsInt fm);
+
+ public interface WithDensity extends LineHeightSpan {
+ public void chooseHeight(CharSequence text, int start, int end,
+ int spanstartv, int v,
+ Paint.FontMetricsInt fm, TextPaint paint);
+ }
}
diff --git a/core/java/android/util/Config.java b/core/java/android/util/Config.java
index 9571041..924b49d 100644
--- a/core/java/android/util/Config.java
+++ b/core/java/android/util/Config.java
@@ -34,25 +34,25 @@ public final class Config
*/
/**
- * Always the inverse of DEBUG.
+ * @deprecated Use {@link #DEBUG} instead.
*/
@Deprecated
public static final boolean RELEASE = !DEBUG;
/**
- * Always false.
+ * @deprecated Always false.
*/
@Deprecated
public static final boolean PROFILE = false;
/**
- * Always false.
+ * @deprecated Always false.
*/
@Deprecated
public static final boolean LOGV = false;
/**
- * Always true.
+ * @deprecated Always true.
*/
@Deprecated
public static final boolean LOGD = true;
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 24b4f73..81dd96e 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -73,7 +73,7 @@ import java.util.List;
* </ul>
* </li>
* <li> '\n': 1 byte - an automatically generated newline, used to help detect and recover from log
- * corruption and enable stansard unix tools like grep, tail and wc to operate
+ * corruption and enable standard unix tools like grep, tail and wc to operate
* on event logs. </li>
* </ul>
*
@@ -124,10 +124,6 @@ public class EventLog {
"A List must have fewer than "
+ Byte.MAX_VALUE + " items in it.");
}
- if (items.length < 1) {
- throw new IllegalArgumentException(
- "A List must have at least one item in it.");
- }
for (int i = 0; i < items.length; i++) {
final Object item = items[i];
if (item == null) {
@@ -192,17 +188,21 @@ public class EventLog {
return decodeObject();
}
+ public byte[] getRawData() {
+ return mBuffer.array();
+ }
+
/** @return the loggable item at the current position in mBuffer. */
private Object decodeObject() {
if (mBuffer.remaining() < 1) return null;
switch (mBuffer.get()) {
case INT:
if (mBuffer.remaining() < 4) return null;
- return mBuffer.getInt();
+ return (Integer) mBuffer.getInt();
case LONG:
if (mBuffer.remaining() < 8) return null;
- return mBuffer.getLong();
+ return (Long) mBuffer.getLong();
case STRING:
try {
@@ -219,7 +219,7 @@ public class EventLog {
case LIST:
if (mBuffer.remaining() < 1) return null;
int length = mBuffer.get();
- if (length <= 0) return null;
+ if (length < 0) return null;
Object[] array = new Object[length];
for (int i = 0; i < length; ++i) {
array[i] = decodeObject();
@@ -285,4 +285,13 @@ public class EventLog {
*/
public static native void readEvents(int[] tags, Collection<Event> output)
throws IOException;
+
+ /**
+ * Read events from a file.
+ * @param path to read from
+ * @param output container to add events into
+ * @throws IOException if something goes wrong reading events
+ */
+ public static native void readEvents(String path, Collection<Event> output)
+ throws IOException;
}
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
new file mode 100644
index 0000000..b35dd1e
--- /dev/null
+++ b/core/java/android/util/MathUtils.java
@@ -0,0 +1,176 @@
+/*
+ * 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.util;
+
+import java.util.Random;
+
+/**
+ * A class that contains utility methods related to numbers.
+ *
+ * @hide Pending API council approval
+ */
+public final class MathUtils {
+ private static final Random sRandom = new Random();
+ private static final float DEG_TO_RAD = 3.1415926f / 180.0f;
+ private static final float RAD_TO_DEG = 180.0f / 3.1415926f;
+
+ private MathUtils() {
+ }
+
+ public static float abs(float v) {
+ return v > 0 ? v : -v;
+ }
+
+ public static int constrain(int amount, int low, int high) {
+ return amount < low ? low : (amount > high ? high : amount);
+ }
+
+ public static float constrain(float amount, float low, float high) {
+ return amount < low ? low : (amount > high ? high : amount);
+ }
+
+ public static float log(float a) {
+ return (float) Math.log(a);
+ }
+
+ public static float exp(float a) {
+ return (float) Math.exp(a);
+ }
+
+ public static float pow(float a, float b) {
+ return (float) Math.pow(a, b);
+ }
+
+ public static float max(float a, float b) {
+ return a > b ? a : b;
+ }
+
+ public static float max(int a, int b) {
+ return a > b ? a : b;
+ }
+
+ public static float max(float a, float b, float c) {
+ return a > b ? (a > c ? a : c) : (b > c ? b : c);
+ }
+
+ public static float max(int a, int b, int c) {
+ return a > b ? (a > c ? a : c) : (b > c ? b : c);
+ }
+
+ public static float min(float a, float b) {
+ return a < b ? a : b;
+ }
+
+ public static float min(int a, int b) {
+ return a < b ? a : b;
+ }
+
+ public static float min(float a, float b, float c) {
+ return a < b ? (a < c ? a : c) : (b < c ? b : c);
+ }
+
+ public static float min(int a, int b, int c) {
+ return a < b ? (a < c ? a : c) : (b < c ? b : c);
+ }
+
+ public static float dist(float x1, float y1, float x2, float y2) {
+ final float x = (x2 - x1);
+ final float y = (y2 - y1);
+ return (float) Math.sqrt(x * x + y * y);
+ }
+
+ public static float dist(float x1, float y1, float z1, float x2, float y2, float z2) {
+ final float x = (x2 - x1);
+ final float y = (y2 - y1);
+ final float z = (z2 - z1);
+ return (float) Math.sqrt(x * x + y * y + z * z);
+ }
+
+ public static float mag(float a, float b) {
+ return (float) Math.sqrt(a * a + b * b);
+ }
+
+ public static float mag(float a, float b, float c) {
+ return (float) Math.sqrt(a * a + b * b + c * c);
+ }
+
+ public static float sq(float v) {
+ return v * v;
+ }
+
+ public static float radians(float degrees) {
+ return degrees * DEG_TO_RAD;
+ }
+
+ public static float degrees(float radians) {
+ return radians * RAD_TO_DEG;
+ }
+
+ public static float acos(float value) {
+ return (float) Math.acos(value);
+ }
+
+ public static float asin(float value) {
+ return (float) Math.asin(value);
+ }
+
+ public static float atan(float value) {
+ return (float) Math.atan(value);
+ }
+
+ public static float atan2(float a, float b) {
+ return (float) Math.atan2(a, b);
+ }
+
+ public static float tan(float angle) {
+ return (float) Math.tan(angle);
+ }
+
+ public static float lerp(float start, float stop, float amount) {
+ return start + (stop - start) * amount;
+ }
+
+ public static float norm(float start, float stop, float value) {
+ return (value - start) / (stop - start);
+ }
+
+ public static float map(float minStart, float minStop, float maxStart, float maxStop, float value) {
+ return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
+ }
+
+ public static int random(int howbig) {
+ return (int) (sRandom.nextFloat() * howbig);
+ }
+
+ public static int random(int howsmall, int howbig) {
+ if (howsmall >= howbig) return howsmall;
+ return (int) (sRandom.nextFloat() * (howbig - howsmall) + howsmall);
+ }
+
+ public static float random(float howbig) {
+ return sRandom.nextFloat() * howbig;
+ }
+
+ public static float random(float howsmall, float howbig) {
+ if (howsmall >= howbig) return howsmall;
+ return sRandom.nextFloat() * (howbig - howsmall) + howsmall;
+ }
+
+ public static void randomSeed(long seed) {
+ sRandom.setSeed(seed);
+ }
+}
diff --git a/core/java/android/util/Pair.java b/core/java/android/util/Pair.java
new file mode 100644
index 0000000..bf25306
--- /dev/null
+++ b/core/java/android/util/Pair.java
@@ -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.
+ */
+
+package android.util;
+
+/**
+ * Container to ease passing around a tuple of two objects. This object provides a sensible
+ * implementation of equals(), returning true if equals() is true on each of the contained
+ * objects.
+ */
+public class Pair<F, S> {
+ public final F first;
+ public final S second;
+
+ /**
+ * Constructor for a Pair. If either are null then equals() and hashCode() will throw
+ * a NullPointerException.
+ * @param first the first object in the Pair
+ * @param second the second object in the pair
+ */
+ public Pair(F first, S second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ /**
+ * Checks the two objects for equality by delegating to their respective equals() methods.
+ * @param o the Pair to which this one is to be checked for equality
+ * @return true if the underlying objects of the Pair are both considered equals()
+ */
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof Pair)) return false;
+ final Pair<F, S> other;
+ try {
+ other = (Pair<F, S>) o;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ return first.equals(other.first) && second.equals(other.second);
+ }
+
+ /**
+ * Compute a hash code using the hash codes of the underlying objects
+ * @return a hashcode of the Pair
+ */
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + first.hashCode();
+ result = 31 * result + second.hashCode();
+ return result;
+ }
+
+ /**
+ * Convenience method for creating an appropriately typed pair.
+ * @param a the first object in the Pair
+ * @param b the second object in the pair
+ * @return a Pair that is templatized with the types of a and b
+ */
+ public static <A, B> Pair <A, B> create(A a, B b) {
+ return new Pair<A, B>(a, b);
+ }
+}
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index 841066c..f936f65 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -24,9 +24,18 @@ public class HapticFeedbackConstants {
private HapticFeedbackConstants() {}
+ /**
+ * The user has performed a long press on an object that is resulting
+ * in an action being performed.
+ */
public static final int LONG_PRESS = 0;
/**
+ * The user has pressed on a virtual on-screen key.
+ */
+ public static final int VIRTUAL_KEY = 1;
+
+ /**
* Flag for {@link View#performHapticFeedback(int, int)
* View.performHapticFeedback(int, int)}: Ignore the setting in the
* view for whether to perform haptic feedback, do it always.
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 99d5c0c..ebc5f7b 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -46,8 +46,8 @@ oneway interface IWindow {
void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets,
boolean reportDraw);
void dispatchKey(in KeyEvent event);
- void dispatchPointer(in MotionEvent event, long eventTime);
- void dispatchTrackball(in MotionEvent event, long eventTime);
+ void dispatchPointer(in MotionEvent event, long eventTime, boolean callWhenDone);
+ void dispatchTrackball(in MotionEvent event, long eventTime, boolean callWhenDone);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
@@ -56,4 +56,9 @@ oneway interface IWindow {
* to date on the current state showing navigational focus (touch mode) too.
*/
void windowFocusChanged(boolean hasFocus, boolean inTouchMode);
+
+ /**
+ * Called for wallpaper windows when their offsets change.
+ */
+ void dispatchWallpaperOffsets(float x, float y);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5607d4b..3e6cdc2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -90,7 +90,6 @@ interface IWindowManager
void exitKeyguardSecurely(IOnKeyguardExitResult callback);
boolean inKeyguardRestrictedInputMode();
-
// These can only be called with the SET_ANIMATON_SCALE permission.
float getAnimationScale(int which);
float[] getAnimationScales();
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1156856..4d662d2 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -108,4 +108,10 @@ interface IWindowSession {
boolean getInTouchMode();
boolean performHapticFeedback(IWindow window, int effectId, boolean always);
+
+ /**
+ * For windows with the wallpaper behind them, and the wallpaper is
+ * larger than the screen, set the offset within the screen.
+ */
+ void setWallpaperPosition(IBinder windowToken, float x, float y);
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 6349288..f9b16fc 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -258,6 +258,25 @@ public class KeyEvent implements Parcelable {
public static final int FLAG_EDITOR_ACTION = 0x10;
/**
+ * When associated with up key events, this indicates that the key press
+ * has been canceled. Typically this is used with virtual touch screen
+ * keys, where the user can slide from the virtual key area on to the
+ * display: in that case, the application will receive a canceled up
+ * event and should not perform the action normally associated with the
+ * key. Note that for this to work, the application can not perform an
+ * action for a key until it receives an up or the long press timeout has
+ * expired.
+ */
+ public static final int FLAG_CANCELED = 0x20;
+
+ /**
+ * This key event was generated by a virtual (on-screen) hard key area.
+ * Typically this is an area of the touchscreen, outside of the regular
+ * display, dedicated to "hardware" buttons.
+ */
+ public static final int FLAG_VIRTUAL_HARD_KEY = 0x40;
+
+ /**
* Returns the maximum keycode.
*/
public static int getMaxKeyCode() {
@@ -694,6 +713,14 @@ public class KeyEvent implements Parcelable {
}
/**
+ * For {@link #ACTION_UP} events, indicates that the event has been
+ * canceled as per {@link #FLAG_CANCELED}.
+ */
+ public final boolean isCanceled() {
+ return (mFlags&FLAG_CANCELED) != 0;
+ }
+
+ /**
* Retrieve the key code of the key event. This is the physical key that
* was pressed, <em>not</em> the Unicode character.
*
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index a224ed3..b2f0c60 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -19,7 +19,7 @@ package android.view;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
-import android.util.Config;
+import android.util.Log;
/**
* Object used to report movement (mouse, pen, finger, trackball) events. This
@@ -27,17 +27,26 @@ import android.util.Config;
* it is being used for.
*/
public final class MotionEvent implements Parcelable {
+ static final boolean DEBUG_POINTERS = false;
+
+ /**
+ * Bit mask of the parts of the action code that are the action itself.
+ */
+ public static final int ACTION_MASK = 0xff;
+
/**
* Constant for {@link #getAction}: A pressed gesture has started, the
* motion contains the initial starting location.
*/
public static final int ACTION_DOWN = 0;
+
/**
* Constant for {@link #getAction}: A pressed gesture has finished, the
* motion contains the final release location as well as any intermediate
* points since the last down or move event.
*/
public static final int ACTION_UP = 1;
+
/**
* Constant for {@link #getAction}: A change has happened during a
* press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}).
@@ -45,12 +54,14 @@ public final class MotionEvent implements Parcelable {
* points since the last down or move event.
*/
public static final int ACTION_MOVE = 2;
+
/**
* Constant for {@link #getAction}: The current gesture has been aborted.
* You will not receive any more points in it. You should treat this as
* an up event, but not perform any action that you normally would.
*/
public static final int ACTION_CANCEL = 3;
+
/**
* Constant for {@link #getAction}: A movement has happened outside of the
* normal bounds of the UI element. This does not provide a full gesture,
@@ -58,6 +69,70 @@ public final class MotionEvent implements Parcelable {
*/
public static final int ACTION_OUTSIDE = 4;
+ /**
+ * A non-primary pointer has gone down. The bits in
+ * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed.
+ */
+ public static final int ACTION_POINTER_DOWN = 5;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_DOWN} with
+ * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone done.
+ */
+ public static final int ACTION_POINTER_1_DOWN = ACTION_POINTER_DOWN | 0x0000;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_DOWN} with
+ * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone done.
+ */
+ public static final int ACTION_POINTER_2_DOWN = ACTION_POINTER_DOWN | 0x0100;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_DOWN} with
+ * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone done.
+ */
+ public static final int ACTION_POINTER_3_DOWN = ACTION_POINTER_DOWN | 0x0200;
+
+ /**
+ * A non-primary pointer has gone up. The bits in
+ * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed.
+ */
+ public static final int ACTION_POINTER_UP = 6;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_UP} with
+ * {@link #ACTION_POINTER_ID_MASK} of 0: the primary pointer has gone up.
+ */
+ public static final int ACTION_POINTER_1_UP = ACTION_POINTER_UP | 0x0000;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_UP} with
+ * {@link #ACTION_POINTER_ID_MASK} of 1: the secondary pointer has gone up.
+ */
+ public static final int ACTION_POINTER_2_UP = ACTION_POINTER_UP | 0x0100;
+
+ /**
+ * Synonym for {@link #ACTION_POINTER_UP} with
+ * {@link #ACTION_POINTER_ID_MASK} of 2: the tertiary pointer has gone up.
+ */
+ public static final int ACTION_POINTER_3_UP = ACTION_POINTER_UP | 0x0200;
+
+ /**
+ * Bits in the action code that represent a pointer ID, used with
+ * {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Pointer IDs
+ * start at 0, with 0 being the primary (first) pointer in the motion. Note
+ * that this not <em>not</em> an index into the array of pointer values,
+ * which is compacted to only contain pointers that are down; the pointer
+ * ID for a particular index can be found with {@link #findPointerIndex}.
+ */
+ public static final int ACTION_POINTER_ID_MASK = 0xff00;
+
+ /**
+ * Bit shift for the action bits holding the pointer identifier as
+ * defined by {@link #ACTION_POINTER_ID_MASK}.
+ */
+ public static final int ACTION_POINTER_ID_SHIFT = 8;
+
private static final boolean TRACK_RECYCLED_LOCATION = false;
/**
@@ -80,34 +155,83 @@ public final class MotionEvent implements Parcelable {
*/
public static final int EDGE_RIGHT = 0x00000008;
+ /**
+ * Offset for the sample's X coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_X = 0;
+
+ /**
+ * Offset for the sample's Y coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_Y = 1;
+
+ /**
+ * Offset for the sample's X coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_PRESSURE = 2;
+
+ /**
+ * Offset for the sample's X coordinate.
+ * @hide
+ */
+ static public final int SAMPLE_SIZE = 3;
+
+ /**
+ * Number of data items for each sample.
+ * @hide
+ */
+ static public final int NUM_SAMPLE_DATA = 4;
+
+ /**
+ * Number of possible pointers.
+ * @hide
+ */
+ static public final int BASE_AVAIL_POINTERS = 5;
+
+ static private final int BASE_AVAIL_SAMPLES = 8;
+
static private final int MAX_RECYCLED = 10;
static private Object gRecyclerLock = new Object();
static private int gRecyclerUsed = 0;
static private MotionEvent gRecyclerTop = null;
private long mDownTime;
- private long mEventTime;
+ private long mEventTimeNano;
private int mAction;
- private float mX;
- private float mY;
private float mRawX;
private float mRawY;
- private float mPressure;
- private float mSize;
- private int mMetaState;
- private int mNumHistory;
- private float[] mHistory;
- private long[] mHistoryTimes;
private float mXPrecision;
private float mYPrecision;
private int mDeviceId;
private int mEdgeFlags;
+ private int mMetaState;
+
+ // Here is the actual event data. Note that the order of the array
+ // is a little odd: the first entry is the most recent, and the ones
+ // following it are the historical data from oldest to newest. This
+ // allows us to easily retrieve the most recent data, without having
+ // to copy the arrays every time a new sample is added.
+
+ private int mNumPointers;
+ private int mNumSamples;
+ // Array of mNumPointers size of identifiers for each pointer of data.
+ private int[] mPointerIdentifiers;
+ // Array of (mNumSamples * mNumPointers * NUM_SAMPLE_DATA) size of event data.
+ private float[] mDataSamples;
+ // Array of mNumSamples size of time stamps.
+ private long[] mTimeSamples;
private MotionEvent mNext;
private RuntimeException mRecycledLocation;
private boolean mRecycled;
private MotionEvent() {
+ mPointerIdentifiers = new int[BASE_AVAIL_POINTERS];
+ mDataSamples = new float[BASE_AVAIL_POINTERS*BASE_AVAIL_SAMPLES*NUM_SAMPLE_DATA];
+ mTimeSamples = new long[BASE_AVAIL_SAMPLES];
}
static private MotionEvent obtain() {
@@ -127,6 +251,86 @@ public final class MotionEvent implements Parcelable {
/**
* 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 pointers The number of points that will be in this event.
+ * @param inPointerIds An array of <em>pointers</em> values providing
+ * an identifier for each pointer.
+ * @param inData An array of <em>pointers*NUM_SAMPLE_DATA</em> of initial
+ * data samples for the event.
+ * @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, int pointers, int[] inPointerIds, float[] inData, int metaState,
+ float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
+ MotionEvent ev = obtain();
+ ev.mDeviceId = deviceId;
+ ev.mEdgeFlags = edgeFlags;
+ ev.mDownTime = downTime;
+ ev.mEventTimeNano = eventTimeNano;
+ ev.mAction = action;
+ ev.mMetaState = metaState;
+ ev.mRawX = inData[SAMPLE_X];
+ ev.mRawY = inData[SAMPLE_Y];
+ ev.mXPrecision = xPrecision;
+ ev.mYPrecision = yPrecision;
+ ev.mNumPointers = pointers;
+ ev.mNumSamples = 1;
+
+ int[] pointerIdentifiers = ev.mPointerIdentifiers;
+ if (pointerIdentifiers.length < pointers) {
+ ev.mPointerIdentifiers = pointerIdentifiers = new int[pointers];
+ }
+ System.arraycopy(inPointerIds, 0, pointerIdentifiers, 0, pointers);
+
+ final int ND = pointers * NUM_SAMPLE_DATA;
+ float[] dataSamples = ev.mDataSamples;
+ if (dataSamples.length < ND) {
+ ev.mDataSamples = dataSamples = new float[ND];
+ }
+ System.arraycopy(inData, 0, dataSamples, 0, ND);
+
+ ev.mTimeSamples[0] = eventTime;
+
+ if (DEBUG_POINTERS) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("New:");
+ for (int i=0; i<pointers; i++) {
+ sb.append(" #");
+ sb.append(ev.mPointerIdentifiers[i]);
+ sb.append("(");
+ sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]);
+ sb.append(",");
+ sb.append(ev.mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]);
+ sb.append(")");
+ }
+ Log.v("MotionEvent", sb.toString());
+ }
+
+ 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()}.
@@ -162,16 +366,83 @@ public final class MotionEvent implements Parcelable {
ev.mDeviceId = deviceId;
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;
- ev.mPressure = pressure;
- ev.mSize = size;
ev.mMetaState = metaState;
ev.mXPrecision = xPrecision;
ev.mYPrecision = yPrecision;
+ ev.mNumPointers = 1;
+ ev.mNumSamples = 1;
+ int[] pointerIds = ev.mPointerIdentifiers;
+ pointerIds[0] = 0;
+ float[] data = ev.mDataSamples;
+ data[SAMPLE_X] = ev.mRawX = x;
+ data[SAMPLE_Y] = ev.mRawY = y;
+ data[SAMPLE_PRESSURE] = pressure;
+ data[SAMPLE_SIZE] = size;
+ ev.mTimeSamples[0] = eventTime;
+
+ 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 action The kind of action being performed -- one of either
+ * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
+ * {@link #ACTION_CANCEL}.
+ * @param pointers The number of pointers that are active in this event.
+ * @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.
+ */
+ static public MotionEvent obtain(long downTime, long eventTime, int action,
+ int pointers, 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.mEventTimeNano = eventTime * 1000000;
+ ev.mAction = action;
+ ev.mNumPointers = pointers;
+ ev.mMetaState = metaState;
+ ev.mXPrecision = xPrecision;
+ ev.mYPrecision = yPrecision;
+
+ ev.mNumPointers = 1;
+ ev.mNumSamples = 1;
+ int[] pointerIds = ev.mPointerIdentifiers;
+ pointerIds[0] = 0;
+ float[] data = ev.mDataSamples;
+ data[SAMPLE_X] = ev.mRawX = x;
+ data[SAMPLE_Y] = ev.mRawY = y;
+ data[SAMPLE_PRESSURE] = pressure;
+ data[SAMPLE_SIZE] = size;
+ ev.mTimeSamples[0] = eventTime;
+
return ev;
}
@@ -198,16 +469,24 @@ public final class MotionEvent implements Parcelable {
ev.mDeviceId = 0;
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;
- ev.mPressure = 1.0f;
- ev.mSize = 1.0f;
+ ev.mNumPointers = 1;
ev.mMetaState = metaState;
ev.mXPrecision = 1.0f;
ev.mYPrecision = 1.0f;
+ ev.mNumPointers = 1;
+ ev.mNumSamples = 1;
+ int[] pointerIds = ev.mPointerIdentifiers;
+ pointerIds[0] = 0;
+ float[] data = ev.mDataSamples;
+ data[SAMPLE_X] = ev.mRawX = x;
+ data[SAMPLE_Y] = ev.mRawY = y;
+ data[SAMPLE_PRESSURE] = 1.0f;
+ data[SAMPLE_SIZE] = 1.0f;
+ ev.mTimeSamples[0] = eventTime;
+
return ev;
}
@@ -217,72 +496,96 @@ public final class MotionEvent implements Parcelable {
* @hide
*/
public void scale(float scale) {
- mX *= scale;
- mY *= scale;
mRawX *= scale;
mRawY *= scale;
- mSize *= scale;
mXPrecision *= scale;
mYPrecision *= scale;
- if (mHistory != null) {
- float[] history = mHistory;
- int length = history.length;
- for (int i = 0; i < length; i += 4) {
- history[i] *= scale; // X
- history[i + 1] *= scale; // Y
- // no need to scale pressure ([i+2])
- history[i + 3] *= scale; // Size, TODO: square this?
- }
+ float[] history = mDataSamples;
+ final int length = mNumPointers * mNumSamples * NUM_SAMPLE_DATA;
+ for (int i = 0; i < length; i += NUM_SAMPLE_DATA) {
+ history[i + SAMPLE_X] *= scale;
+ history[i + SAMPLE_Y] *= scale;
+ // no need to scale pressure
+ history[i + SAMPLE_SIZE] *= scale; // TODO: square this?
}
}
/**
- * Translate the coordination of the event by given x and y.
- *
- * @hide
+ * Create a new MotionEvent, copying from an existing one.
*/
- public void translate(float dx, float dy) {
- mX += dx;
- mY += dy;
- mRawX += dx;
- mRawY += dx;
- if (mHistory != null) {
- float[] history = mHistory;
- int length = history.length;
- for (int i = 0; i < length; i += 4) {
- history[i] += dx; // X
- history[i + 1] += dy; // Y
- // no need to translate pressure (i+2) and size (i+3)
- }
+ static public MotionEvent obtain(MotionEvent o) {
+ MotionEvent ev = obtain();
+ ev.mDeviceId = o.mDeviceId;
+ ev.mEdgeFlags = o.mEdgeFlags;
+ ev.mDownTime = o.mDownTime;
+ ev.mEventTimeNano = o.mEventTimeNano;
+ ev.mAction = o.mAction;
+ ev.mNumPointers = o.mNumPointers;
+ ev.mRawX = o.mRawX;
+ ev.mRawY = o.mRawY;
+ ev.mMetaState = o.mMetaState;
+ ev.mXPrecision = o.mXPrecision;
+ ev.mYPrecision = o.mYPrecision;
+
+ final int NS = ev.mNumSamples = o.mNumSamples;
+ if (ev.mTimeSamples.length >= NS) {
+ System.arraycopy(o.mTimeSamples, 0, ev.mTimeSamples, 0, NS);
+ } else {
+ ev.mTimeSamples = (long[])o.mTimeSamples.clone();
}
+
+ final int NP = (ev.mNumPointers=o.mNumPointers);
+ if (ev.mPointerIdentifiers.length >= NP) {
+ System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP);
+ } else {
+ ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone();
+ }
+
+ final int ND = NP * NS * NUM_SAMPLE_DATA;
+ if (ev.mDataSamples.length >= ND) {
+ System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND);
+ } else {
+ ev.mDataSamples = (float[])o.mDataSamples.clone();
+ }
+
+ return ev;
}
/**
- * Create a new MotionEvent, copying from an existing one.
+ * Create a new MotionEvent, copying from an existing one, but not including
+ * any historical point information.
*/
- static public MotionEvent obtain(MotionEvent o) {
+ static public MotionEvent obtainNoHistory(MotionEvent o) {
MotionEvent ev = obtain();
ev.mDeviceId = o.mDeviceId;
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.mNumPointers = o.mNumPointers;
ev.mRawX = o.mRawX;
- ev.mY = o.mY;
ev.mRawY = o.mRawY;
- ev.mPressure = o.mPressure;
- ev.mSize = o.mSize;
ev.mMetaState = o.mMetaState;
ev.mXPrecision = o.mXPrecision;
ev.mYPrecision = o.mYPrecision;
- final int N = o.mNumHistory;
- ev.mNumHistory = N;
- if (N > 0) {
- // could be more efficient about this...
- ev.mHistory = (float[])o.mHistory.clone();
- ev.mHistoryTimes = (long[])o.mHistoryTimes.clone();
+
+ ev.mNumSamples = 1;
+ ev.mTimeSamples[0] = o.mTimeSamples[0];
+
+ final int NP = (ev.mNumPointers=o.mNumPointers);
+ if (ev.mPointerIdentifiers.length >= NP) {
+ System.arraycopy(o.mPointerIdentifiers, 0, ev.mPointerIdentifiers, 0, NP);
+ } else {
+ ev.mPointerIdentifiers = (int[])o.mPointerIdentifiers.clone();
}
+
+ final int ND = NP * NUM_SAMPLE_DATA;
+ if (ev.mDataSamples.length >= ND) {
+ System.arraycopy(o.mDataSamples, 0, ev.mDataSamples, 0, ND);
+ } else {
+ ev.mDataSamples = (float[])o.mDataSamples.clone();
+ }
+
return ev;
}
@@ -305,7 +608,7 @@ public final class MotionEvent implements Parcelable {
synchronized (gRecyclerLock) {
if (gRecyclerUsed < MAX_RECYCLED) {
gRecyclerUsed++;
- mNumHistory = 0;
+ mNumSamples = 0;
mNext = gRecyclerTop;
gRecyclerTop = this;
}
@@ -333,44 +636,145 @@ public final class MotionEvent implements Parcelable {
* Returns the time (in ms) when this specific event was generated.
*/
public final long getEventTime() {
- return mEventTime;
+ return mTimeSamples[0];
}
/**
- * 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.
+ * 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;
+ }
+
+ /**
+ * {@link #getX(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
*/
public final float getX() {
- return mX;
+ return mDataSamples[SAMPLE_X];
}
/**
- * Returns the Y coordinate of this event. Whole numbers are pixels; the
- * value may have a fraction for input devices that are sub-pixel precise.
+ * {@link #getY(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
*/
public final float getY() {
- return mY;
+ return mDataSamples[SAMPLE_Y];
+ }
+
+ /**
+ * {@link #getPressure(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getPressure() {
+ return mDataSamples[SAMPLE_PRESSURE];
+ }
+
+ /**
+ * {@link #getSize(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getSize() {
+ return mDataSamples[SAMPLE_SIZE];
+ }
+
+ /**
+ * The number of pointers of data contained in this event. Always
+ * >= 1.
+ */
+ public final int getPointerCount() {
+ return mNumPointers;
+ }
+
+ /**
+ * Return the pointer identifier associated with a particular pointer
+ * data index is this event. The identifier tells you the actual pointer
+ * number associated with the data, accounting for individual pointers
+ * going up and down since the start of the current gesture.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ */
+ public final int getPointerId(int pointerIndex) {
+ return mPointerIdentifiers[pointerIndex];
+ }
+
+ /**
+ * Given a pointer identifier, find the index of its data in the event.
+ *
+ * @param pointerId The identifier of the pointer to be found.
+ * @return Returns either the index of the pointer (for use with
+ * {@link #getX(int) et al.), or -1 if there is no data available for
+ * that pointer identifier.
+ */
+ public final int findPointerIndex(int pointerId) {
+ int i = mNumPointers;
+ while (i > 0) {
+ i--;
+ if (mPointerIdentifiers[i] == pointerId) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the X coordinate of this event for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * Whole numbers are pixels; the
+ * value may have a fraction for input devices that are sub-pixel precise.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ */
+ public final float getX(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_X];
}
/**
- * Returns the current pressure of this event. The pressure generally
+ * Returns the Y coordinate of this event for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * Whole numbers are pixels; the
+ * value may have a fraction for input devices that are sub-pixel precise.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
+ */
+ public final float getY(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_Y];
+ }
+
+ /**
+ * Returns the current pressure of this event for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * 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 pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
*/
- public final float getPressure() {
- return mPressure;
+ public final float getPressure(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_PRESSURE];
}
/**
- * Returns 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 the device specific range of values
+ * Returns a scaled value of the approximate size for the given pointer
+ * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+ * identifier for this index).
+ * This represents some approximation of the area of the screen being
+ * pressed; the actual value in pixels corresponding to the
+ * touch is normalized with the device specific range of values
* and scaled to a value between 0 and 1. The value of size can be used to
* determine fat touch events.
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
*/
- public final float getSize() {
- return mSize;
+ public final float getSize(int pointerIndex) {
+ return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_SIZE];
}
/**
@@ -436,7 +840,7 @@ public final class MotionEvent implements Parcelable {
* @return Returns the number of historical points in the event.
*/
public final int getHistorySize() {
- return mNumHistory;
+ return mNumSamples - 1;
}
/**
@@ -450,63 +854,111 @@ public final class MotionEvent implements Parcelable {
* @see #getEventTime
*/
public final long getHistoricalEventTime(int pos) {
- return mHistoryTimes[pos];
+ return mTimeSamples[pos + 1];
}
/**
- * Returns a historical X coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * {@link #getHistoricalX(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalX(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_X];
+ }
+
+ /**
+ * {@link #getHistoricalY(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalY(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_Y];
+ }
+
+ /**
+ * {@link #getHistoricalPressure(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalPressure(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_PRESSURE];
+ }
+
+ /**
+ * {@link #getHistoricalSize(int)} for the first pointer index (may be an
+ * arbitrary pointer identifier).
+ */
+ public final float getHistoricalSize(int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers) + SAMPLE_SIZE];
+ }
+
+ /**
+ * Returns a historical X coordinate, as per {@link #getX(int)}, that
+ * occurred between this event and the previous event for the given pointer.
+ * Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
*
* @see #getHistorySize
* @see #getX
*/
- public final float getHistoricalX(int pos) {
- return mHistory[pos*4];
+ public final float getHistoricalX(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_X];
}
/**
- * Returns a historical Y coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * Returns a historical Y coordinate, as per {@link #getY(int)}, that
+ * occurred between this event and the previous event for the given pointer.
+ * Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
*
* @see #getHistorySize
* @see #getY
*/
- public final float getHistoricalY(int pos) {
- return mHistory[pos*4 + 1];
+ public final float getHistoricalY(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_Y];
}
/**
- * Returns a historical pressure coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * Returns a historical pressure coordinate, as per {@link #getPressure(int)},
+ * that occurred between this event and the previous event for the given
+ * pointer. Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
- *
+ *
* @see #getHistorySize
* @see #getPressure
*/
- public final float getHistoricalPressure(int pos) {
- return mHistory[pos*4 + 2];
+ public final float getHistoricalPressure(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_PRESSURE];
}
/**
- * Returns a historical size coordinate that occurred between this event
- * and the previous event. Only applies to ACTION_MOVE events.
+ * Returns a historical size coordinate, as per {@link #getSize(int)}, that
+ * occurred between this event and the previous event for the given pointer.
+ * Only applies to ACTION_MOVE events.
*
+ * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0
+ * (the first pointer that is down) to {@link #getPointerCount()}-1.
* @param pos Which historical value to return; must be less than
* {@link #getHistorySize}
- *
+ *
* @see #getHistorySize
* @see #getSize
*/
- public final float getHistoricalSize(int pos) {
- return mHistory[pos*4 + 3];
+ public final float getHistoricalSize(int pointerIndex, int pos) {
+ return mDataSamples[((pos + 1) * NUM_SAMPLE_DATA * mNumPointers)
+ + (pointerIndex * NUM_SAMPLE_DATA) + SAMPLE_SIZE];
}
/**
@@ -556,16 +1008,11 @@ public final class MotionEvent implements Parcelable {
* @param deltaY Amount to add to the current Y coordinate of the event.
*/
public final void offsetLocation(float deltaX, float deltaY) {
- mX += deltaX;
- mY += deltaY;
- final int N = mNumHistory*4;
- if (N <= 0) {
- return;
- }
- final float[] pos = mHistory;
- for (int i=0; i<N; i+=4) {
- pos[i] += deltaX;
- pos[i+1] += deltaY;
+ final int N = mNumPointers*mNumSamples*4;
+ final float[] pos = mDataSamples;
+ for (int i=0; i<N; i+=NUM_SAMPLE_DATA) {
+ pos[i+SAMPLE_X] += deltaX;
+ pos[i+SAMPLE_Y] += deltaY;
}
}
@@ -577,8 +1024,8 @@ public final class MotionEvent implements Parcelable {
* @param y New absolute Y location.
*/
public final void setLocation(float x, float y) {
- float deltaX = x-mX;
- float deltaY = y-mY;
+ float deltaX = x-mDataSamples[SAMPLE_X];
+ float deltaY = y-mDataSamples[SAMPLE_Y];
if (deltaX != 0 || deltaY != 0) {
offsetLocation(deltaX, deltaY);
}
@@ -590,58 +1037,119 @@ public final class MotionEvent implements Parcelable {
* the future, the current values in the event will be added to a list of
* historic values.
*
+ * @param eventTime The time stamp for this data.
* @param x The new X position.
* @param y The new Y position.
* @param pressure The new pressure.
* @param size The new size.
+ * @param metaState Meta key state.
*/
public final void addBatch(long eventTime, float x, float y,
float pressure, float size, int metaState) {
- float[] history = mHistory;
- long[] historyTimes = mHistoryTimes;
- int N;
- int avail;
- if (history == null) {
- mHistory = history = new float[8*4];
- mHistoryTimes = historyTimes = new long[8];
- mNumHistory = N = 0;
- avail = 8;
- } else {
- N = mNumHistory;
- avail = history.length/4;
- if (N == avail) {
- avail += 8;
- float[] newHistory = new float[avail*4];
- System.arraycopy(history, 0, newHistory, 0, N*4);
- mHistory = history = newHistory;
- long[] newHistoryTimes = new long[avail];
- System.arraycopy(historyTimes, 0, newHistoryTimes, 0, N);
- mHistoryTimes = historyTimes = newHistoryTimes;
- }
+ float[] data = mDataSamples;
+ long[] times = mTimeSamples;
+
+ final int NP = mNumPointers;
+ final int NS = mNumSamples;
+ final int NI = NP*NS;
+ final int ND = NI * NUM_SAMPLE_DATA;
+ if (data.length <= ND) {
+ final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA));
+ float[] newData = new float[NEW_ND];
+ System.arraycopy(data, 0, newData, 0, ND);
+ mDataSamples = data = newData;
+ }
+ if (times.length <= NS) {
+ final int NEW_NS = NS + BASE_AVAIL_SAMPLES;
+ long[] newHistoryTimes = new long[NEW_NS];
+ System.arraycopy(times, 0, newHistoryTimes, 0, NS);
+ mTimeSamples = times = newHistoryTimes;
}
+
+ times[NS] = times[0];
+ times[0] = eventTime;
+
+ final int pos = NS*NUM_SAMPLE_DATA;
+ data[pos+SAMPLE_X] = data[SAMPLE_X];
+ data[pos+SAMPLE_Y] = data[SAMPLE_Y];
+ data[pos+SAMPLE_PRESSURE] = data[SAMPLE_PRESSURE];
+ data[pos+SAMPLE_SIZE] = data[SAMPLE_SIZE];
+ data[SAMPLE_X] = x;
+ data[SAMPLE_Y] = y;
+ data[SAMPLE_PRESSURE] = pressure;
+ data[SAMPLE_SIZE] = size;
+ mNumSamples = NS+1;
- historyTimes[N] = mEventTime;
+ mRawX = x;
+ mRawY = y;
+ mMetaState |= metaState;
+ }
- final int pos = N*4;
- history[pos] = mX;
- history[pos+1] = mY;
- history[pos+2] = mPressure;
- history[pos+3] = mSize;
- mNumHistory = N+1;
+ /**
+ * Add a new movement to the batch of movements in this event. The
+ * input data must contain (NUM_SAMPLE_DATA * {@link #getPointerCount()})
+ * samples of data.
+ *
+ * @param eventTime The time stamp for this data.
+ * @param inData The actual data.
+ * @param metaState Meta key state.
+ *
+ * @hide
+ */
+ public final void addBatch(long eventTime, float[] inData, int metaState) {
+ float[] data = mDataSamples;
+ long[] times = mTimeSamples;
+
+ final int NP = mNumPointers;
+ final int NS = mNumSamples;
+ final int NI = NP*NS;
+ final int ND = NI * NUM_SAMPLE_DATA;
+ if (data.length <= ND) {
+ final int NEW_ND = ND + (NP * (BASE_AVAIL_SAMPLES * NUM_SAMPLE_DATA));
+ float[] newData = new float[NEW_ND];
+ System.arraycopy(data, 0, newData, 0, ND);
+ mDataSamples = data = newData;
+ }
+ if (times.length <= NS) {
+ final int NEW_NS = NS + BASE_AVAIL_SAMPLES;
+ long[] newHistoryTimes = new long[NEW_NS];
+ System.arraycopy(times, 0, newHistoryTimes, 0, NS);
+ mTimeSamples = times = newHistoryTimes;
+ }
+
+ times[NS] = times[0];
+ times[0] = eventTime;
+
+ System.arraycopy(data, 0, data, ND, mNumPointers*NUM_SAMPLE_DATA);
+ System.arraycopy(inData, 0, data, 0, mNumPointers*NUM_SAMPLE_DATA);
+
+ mNumSamples = NS+1;
- mEventTime = eventTime;
- mX = mRawX = x;
- mY = mRawY = y;
- mPressure = pressure;
- mSize = size;
+ mRawX = inData[SAMPLE_X];
+ mRawY = inData[SAMPLE_Y];
mMetaState |= metaState;
+
+ if (DEBUG_POINTERS) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Add:");
+ for (int i=0; i<mNumPointers; i++) {
+ sb.append(" #");
+ sb.append(mPointerIdentifiers[i]);
+ sb.append("(");
+ sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_X]);
+ sb.append(",");
+ sb.append(mDataSamples[(i*NUM_SAMPLE_DATA) + SAMPLE_Y]);
+ sb.append(")");
+ }
+ Log.v("MotionEvent", sb.toString());
+ }
}
@Override
public String toString() {
return "MotionEvent{" + Integer.toHexString(System.identityHashCode(this))
- + " action=" + mAction + " x=" + mX
- + " y=" + mY + " pressure=" + mPressure + " size=" + mSize + "}";
+ + " action=" + mAction + " x=" + getX()
+ + " y=" + getY() + " pressure=" + getPressure() + " size=" + getSize() + "}";
}
public static final Parcelable.Creator<MotionEvent> CREATOR
@@ -663,26 +1171,29 @@ 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);
- out.writeFloat(mPressure);
- out.writeFloat(mSize);
out.writeInt(mMetaState);
out.writeFloat(mRawX);
out.writeFloat(mRawY);
- final int N = mNumHistory;
- out.writeInt(N);
- if (N > 0) {
- final int N4 = N*4;
+ final int NP = mNumPointers;
+ out.writeInt(NP);
+ final int NS = mNumSamples;
+ out.writeInt(NS);
+ final int NI = NP*NS;
+ if (NI > 0) {
int i;
- float[] history = mHistory;
- for (i=0; i<N4; i++) {
+ int[] state = mPointerIdentifiers;
+ for (i=0; i<NP; i++) {
+ out.writeInt(state[i]);
+ }
+ final int ND = NI*NUM_SAMPLE_DATA;
+ float[] history = mDataSamples;
+ for (i=0; i<ND; i++) {
out.writeFloat(history[i]);
}
- long[] times = mHistoryTimes;
- for (i=0; i<N; i++) {
+ long[] times = mTimeSamples;
+ for (i=0; i<NS; i++) {
out.writeLong(times[i]);
}
}
@@ -694,30 +1205,37 @@ 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();
- mPressure = in.readFloat();
- mSize = in.readFloat();
mMetaState = in.readInt();
mRawX = in.readFloat();
mRawY = in.readFloat();
- final int N = in.readInt();
- if ((mNumHistory=N) > 0) {
- final int N4 = N*4;
- float[] history = mHistory;
- if (history == null || history.length < N4) {
- mHistory = history = new float[N4 + (4*4)];
+ final int NP = in.readInt();
+ mNumPointers = NP;
+ final int NS = in.readInt();
+ mNumSamples = NS;
+ final int NI = NP*NS;
+ if (NI > 0) {
+ int[] ids = mPointerIdentifiers;
+ if (ids.length < NP) {
+ mPointerIdentifiers = ids = new int[NP];
+ }
+ for (int i=0; i<NP; i++) {
+ ids[i] = in.readInt();
+ }
+ float[] history = mDataSamples;
+ final int ND = NI*NUM_SAMPLE_DATA;
+ if (history.length < ND) {
+ mDataSamples = history = new float[ND];
}
- for (int i=0; i<N4; i++) {
+ for (int i=0; i<ND; i++) {
history[i] = in.readFloat();
}
- long[] times = mHistoryTimes;
- if (times == null || times.length < N) {
- mHistoryTimes = times = new long[N + 4];
+ long[] times = mTimeSamples;
+ if (times == null || times.length < NS) {
+ mTimeSamples = times = new long[NS];
}
- for (int i=0; i<N; i++) {
+ for (int i=0; i<NS; i++) {
times[i] = in.readLong();
}
}
diff --git a/core/java/android/view/RawInputEvent.java b/core/java/android/view/RawInputEvent.java
index 30da83e..8b3cdd4 100644
--- a/core/java/android/view/RawInputEvent.java
+++ b/core/java/android/view/RawInputEvent.java
@@ -13,6 +13,8 @@ public class RawInputEvent {
public static final int CLASS_ALPHAKEY = 0x00000002;
public static final int CLASS_TOUCHSCREEN = 0x00000004;
public static final int CLASS_TRACKBALL = 0x00000008;
+ public static final int CLASS_TOUCHSCREEN_MT = 0x00000010;
+ public static final int CLASS_DPAD = 0x00000020;
// More special classes for QueuedEvent below.
public static final int CLASS_CONFIGURATION_CHANGED = 0x10000000;
@@ -158,8 +160,24 @@ public class RawInputEvent {
public static final int ABS_TOOL_WIDTH = 0x1c;
public static final int ABS_VOLUME = 0x20;
public static final int ABS_MISC = 0x28;
+ public static final int ABS_MT_TOUCH_MAJOR = 0x30;
+ public static final int ABS_MT_TOUCH_MINOR = 0x31;
+ public static final int ABS_MT_WIDTH_MAJOR = 0x32;
+ public static final int ABS_MT_WIDTH_MINOR = 0x33;
+ public static final int ABS_MT_ORIENTATION = 0x34;
+ public static final int ABS_MT_POSITION_X = 0x35;
+ public static final int ABS_MT_POSITION_Y = 0x36;
+ public static final int ABS_MT_TOOL_TYPE = 0x37;
+ public static final int ABS_MT_BLOB_ID = 0x38;
public static final int ABS_MAX = 0x3f;
+ // Switch events
+ public static final int SW_LID = 0x00;
+
+ public static final int SYN_REPORT = 0;
+ public static final int SYN_CONFIG = 1;
+ public static final int SYN_MT_REPORT = 2;
+
public int deviceId;
public int type;
public int scancode;
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 5100fff..5cecac3 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -34,12 +34,18 @@ public class Surface implements Parcelable {
/** Surface is created hidden */
public static final int HIDDEN = 0x00000004;
- /** The surface is to be used by hardware accelerators or DMA engines */
+ /** The surface is to be used by hardware accelerators or DMA engines
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int HARDWARE = 0x00000010;
/** Implies "HARDWARE", the surface is to be used by the GPU
* additionally the backbuffer is never preserved for these
- * surfaces. */
+ * surfaces.
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int GPU = 0x00000028;
/** The surface contains secure content, special measures will
@@ -135,6 +141,8 @@ public class Surface implements Parcelable {
@SuppressWarnings("unused")
private int mSurface;
@SuppressWarnings("unused")
+ private int mSurfaceControl;
+ @SuppressWarnings("unused")
private int mSaveCount;
@SuppressWarnings("unused")
private Canvas mCanvas;
@@ -238,7 +246,7 @@ public class Surface implements Parcelable {
};
/**
- * Sets the display metrics used to provide canva's width/height in comaptibility mode.
+ * Sets the display metrics used to provide canva's width/height in compatibility mode.
*/
void setCompatibleDisplayMetrics(DisplayMetrics metrics, Translator translator) {
mCompatibleDisplayMetrics = metrics;
@@ -267,7 +275,8 @@ public class Surface implements Parcelable {
public native void clear();
/** draw into a surface */
- public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException {
+ public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException, IllegalArgumentException
+ {
/* the dirty rectangle may be expanded to the surface's size, if
* for instance it has been resized or if the bits were lost, since
* the last call.
@@ -349,7 +358,7 @@ public class Surface implements Parcelable {
@Override
public String toString() {
- return "Surface(native-token=" + mSurface + ")";
+ return "Surface(native-token=" + mSurfaceControl + ")";
}
private Surface(Parcel source) throws OutOfResourcesException {
@@ -362,7 +371,7 @@ public class Surface implements Parcelable {
public native void readFromParcel(Parcel source);
public native void writeToParcel(Parcel dest, int flags);
-
+
public static final Parcelable.Creator<Surface> CREATOR
= new Parcelable.Creator<Surface>()
{
@@ -383,7 +392,7 @@ public class Surface implements Parcelable {
/* no user serviceable parts here ... */
@Override
protected void finalize() throws Throwable {
- clear();
+ release();
}
private native void init(SurfaceSession s,
@@ -391,4 +400,6 @@ public class Surface implements Parcelable {
throws OutOfResourcesException;
private native void init(Parcel source);
+
+ private native void release();
}
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index 3d0dda3..64a10d1 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -38,8 +38,6 @@ public interface SurfaceHolder {
* Surface type.
*
* @see #SURFACE_TYPE_NORMAL
- * @see #SURFACE_TYPE_HARDWARE
- * @see #SURFACE_TYPE_GPU
* @see #SURFACE_TYPE_PUSH_BUFFERS
*/
@@ -47,9 +45,15 @@ public interface SurfaceHolder {
* contiguous, cached/buffered RAM. */
public static final int SURFACE_TYPE_NORMAL = MEMORY_TYPE_NORMAL;
/** Surface type: creates a suited to be used with DMA engines and
- * hardware accelerators. */
+ * hardware accelerators.
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int SURFACE_TYPE_HARDWARE = MEMORY_TYPE_HARDWARE;
- /** Surface type: creates a surface suited to be used with the GPU */
+ /** Surface type: creates a surface suited to be used with the GPU
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int SURFACE_TYPE_GPU = MEMORY_TYPE_GPU;
/** Surface type: creates a "push" surface, that is a surface that
* doesn't owns its buffers. With such a surface lockCanvas will fail. */
@@ -139,11 +143,7 @@ public interface SurfaceHolder {
public boolean isCreating();
/**
- * Sets the surface's type. Surfaces intended to be used with OpenGL ES
- * should be of SURFACE_TYPE_GPU, surfaces accessed by DMA engines and
- * hardware accelerators should be of type SURFACE_TYPE_HARDWARE.
- * Failing to set the surface's type appropriately could result in
- * degraded performance or failure.
+ * Sets the surface's type.
*
* @param type The surface's memory type.
*/
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 9cf7092..ea879ed9 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,6 +16,8 @@
package android.view;
+import com.android.internal.view.BaseIWindow;
+
import android.content.Context;
import android.content.res.Resources;
import android.content.res.CompatibilityInfo.Translator;
@@ -32,8 +34,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;
@@ -279,7 +282,9 @@ public class SurfaceView extends View {
return;
}
ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
- mTranslator = viewRoot.mTranslator;
+ if (viewRoot != null) {
+ mTranslator = viewRoot.mTranslator;
+ }
Resources res = getContext().getResources();
if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) {
@@ -434,7 +439,7 @@ public class SurfaceView extends View {
updateWindow(false);
}
- private static class MyWindow extends IWindow.Stub {
+ private static class MyWindow extends BaseIWindow {
private final WeakReference<SurfaceView> mSurfaceView;
public MyWindow(SurfaceView surfaceView) {
@@ -476,7 +481,8 @@ public class SurfaceView extends View {
}
}
- public void dispatchPointer(MotionEvent event, long eventTime) {
+ public void dispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
//if (mSession != null && mSurface != null) {
// try {
@@ -486,7 +492,8 @@ public class SurfaceView extends View {
//}
}
- public void dispatchTrackball(MotionEvent event, long eventTime) {
+ public void dispatchTrackball(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
//if (mSession != null && mSurface != null) {
// try {
@@ -568,9 +575,14 @@ public class SurfaceView extends View {
public void setType(int type) {
switch (type) {
- case SURFACE_TYPE_NORMAL:
case SURFACE_TYPE_HARDWARE:
case SURFACE_TYPE_GPU:
+ // these are deprecated, treat as "NORMAL"
+ type = SURFACE_TYPE_NORMAL;
+ break;
+ }
+ switch (type) {
+ case SURFACE_TYPE_NORMAL:
case SURFACE_TYPE_PUSH_BUFFERS:
mRequestedType = type;
if (mWindow != null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7ed2712..d569220 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -46,7 +46,6 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.AttributeSet;
import android.util.Config;
-import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.Pool;
@@ -2983,6 +2982,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @param enabled True if this view is enabled, false otherwise.
*/
public void setEnabled(boolean enabled) {
+ if (enabled == isEnabled()) return;
+
setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK);
/*
@@ -6911,7 +6912,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* Set the background to a given resource. The resource should refer to
- * a Drawable object.
+ * a Drawable object or 0 to remove the background.
* @param resid The identifier of the resource.
* @attr ref android.R.styleable#View_background
*/
@@ -8740,7 +8741,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
mLastColor = color;
color |= 0xFF000000;
- shader = new LinearGradient(0, 0, 0, 1, color, 0, Shader.TileMode.CLAMP);
+ shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000,
+ color & 0x00FFFFFF, Shader.TileMode.CLAMP);
paint.setShader(shader);
// Restore the default transfer mode (src_over)
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 0c5d853..fafe00f 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.
@@ -148,7 +151,8 @@ public final class ViewRoot extends Handler implements ViewParent,
boolean mWindowAttributesChanged = false;
// These can be accessed by any thread, must be protected with a lock.
- Surface mSurface;
+ // Surface can never be reassigned or cleared (use Surface.clear()).
+ private final Surface mSurface = new Surface();
boolean mAdded;
boolean mAddedTouchMode;
@@ -188,18 +192,11 @@ public final class ViewRoot extends Handler implements ViewParent,
private final int mDensity;
- public ViewRoot(Context context) {
- super();
-
- ++sInstanceCount;
-
- // Initialize the statics when this class is first instantiated. This is
- // done here instead of in the static block because Zygote does not
- // allow the spawning of threads.
+ public static IWindowSession getWindowSession(Looper mainLooper) {
synchronized (mStaticInit) {
if (!mInitialized) {
try {
- InputMethodManager imm = InputMethodManager.getInstance(context);
+ InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"))
.openSession(imm.getClient(), imm.getInputContext());
@@ -207,8 +204,24 @@ public final class ViewRoot extends Handler implements ViewParent,
} catch (RemoteException e) {
}
}
+ return sWindowSession;
}
+ }
+
+ 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
+ // done here instead of in the static block because Zygote does not
+ // allow the spawning of threads.
+ getWindowSession(context.getMainLooper());
+
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
@@ -224,7 +237,6 @@ public final class ViewRoot extends Handler implements ViewParent,
mTransparentRegion = new Region();
mPreviousTransparentRegion = new Region();
mFirst = true; // true for the first time the view is added
- mSurface = new Surface();
mAdded = false;
mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
mViewConfiguration = ViewConfiguration.get(context);
@@ -674,7 +686,6 @@ public final class ViewRoot extends Handler implements ViewParent,
attachInfo.mKeepScreenOn = false;
viewVisibilityChanged = false;
host.dispatchAttachedToWindow(attachInfo, 0);
- getRunQueue().executeActions(attachInfo.mHandler);
//Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
} else {
@@ -707,6 +718,10 @@ public final class ViewRoot extends Handler implements ViewParent,
boolean insetsChanged = false;
if (mLayoutRequested) {
+ // Execute enqueued actions on every layout in case a view that was detached
+ // enqueued an action after being detached
+ getRunQueue().executeActions(attachInfo.mHandler);
+
if (mFirst) {
host.fitSystemWindows(mAttachInfo.mContentInsets);
// make sure touch mode code executes by setting cached value
@@ -1555,10 +1570,12 @@ public final class ViewRoot extends Handler implements ViewParent,
mView = null;
mAttachInfo.mRootView = null;
+ mAttachInfo.mSurface = null;
if (mUseGL) {
destroyGL();
}
+ mSurface.clear();
try {
sWindowSession.remove(mWindow);
@@ -1628,16 +1645,24 @@ public final class ViewRoot extends Handler implements ViewParent,
break;
case DISPATCH_POINTER: {
MotionEvent event = (MotionEvent)msg.obj;
-
- boolean didFinish;
+ boolean callWhenDone = msg.arg1 != 0;
+
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;
- } else {
- didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
+ callWhenDone = false;
}
if (event != null && mTranslator != null) {
mTranslator.translateEventInScreenToAppWindow(event);
@@ -1654,8 +1679,16 @@ public final class ViewRoot extends Handler implements ViewParent,
if(Config.LOGV) {
captureMotionLog("captureDispatchPointer", event);
}
- event.offsetLocation(0, mCurScrollY);
+ if (mCurScrollY != 0) {
+ 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();
@@ -1701,7 +1734,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
} finally {
- if (!didFinish) {
+ if (callWhenDone) {
try {
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
@@ -1716,7 +1749,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
} break;
case DISPATCH_TRACKBALL:
- deliverTrackballEvent((MotionEvent)msg.obj);
+ deliverTrackballEvent((MotionEvent)msg.obj, msg.arg1 != 0);
break;
case DISPATCH_APP_VISIBILITY:
handleAppVisibility(msg.arg1 != 0);
@@ -1958,16 +1991,13 @@ public final class ViewRoot extends Handler implements ViewParent,
}
- private void deliverTrackballEvent(MotionEvent event) {
- boolean didFinish;
+ private void deliverTrackballEvent(MotionEvent event, boolean callWhenDone) {
if (event == null) {
try {
event = sWindowSession.getPendingTrackballMove(mWindow);
} catch (RemoteException e) {
}
- didFinish = true;
- } else {
- didFinish = false;
+ callWhenDone = false;
}
if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
@@ -1985,7 +2015,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
} finally {
if (handled) {
- if (!didFinish) {
+ if (callWhenDone) {
try {
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
@@ -2101,7 +2131,7 @@ public final class ViewRoot extends Handler implements ViewParent,
mLastTrackballTime = curTime;
}
} finally {
- if (!didFinish) {
+ if (callWhenDone) {
try {
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
@@ -2502,7 +2532,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
- mSurface = null;
+ mSurface.clear();
}
if (mAdded) {
mAdded = false;
@@ -2564,15 +2594,19 @@ public final class ViewRoot extends Handler implements ViewParent,
sendMessageAtTime(msg, event.getEventTime());
}
- public void dispatchPointer(MotionEvent event, long eventTime) {
+ public void dispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
Message msg = obtainMessage(DISPATCH_POINTER);
msg.obj = event;
+ msg.arg1 = callWhenDone ? 1 : 0;
sendMessageAtTime(msg, eventTime);
}
- public void dispatchTrackball(MotionEvent event, long eventTime) {
+ public void dispatchTrackball(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
Message msg = obtainMessage(DISPATCH_TRACKBALL);
msg.obj = event;
+ msg.arg1 = callWhenDone ? 1 : 0;
sendMessageAtTime(msg, eventTime);
}
@@ -2745,19 +2779,25 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
- public void dispatchPointer(MotionEvent event, long eventTime) {
+ public void dispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
final ViewRoot viewRoot = mViewRoot.get();
- if (viewRoot != null) {
- viewRoot.dispatchPointer(event, eventTime);
+ 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, callWhenDone);
} else {
new EventCompletion(mMainLooper, this, null, true, event);
}
}
- public void dispatchTrackball(MotionEvent event, long eventTime) {
+ public void dispatchTrackball(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
- viewRoot.dispatchTrackball(event, eventTime);
+ viewRoot.dispatchTrackball(event, eventTime, callWhenDone);
} else {
new EventCompletion(mMainLooper, this, null, false, event);
}
@@ -2827,6 +2867,9 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
}
+
+ public void dispatchWallpaperOffsets(float x, float y) {
+ }
}
/**
@@ -3107,7 +3150,7 @@ public final class ViewRoot extends Handler implements ViewParent,
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
- mActions.clear();
+ actions.clear();
}
}
@@ -3121,7 +3164,6 @@ public final class ViewRoot extends Handler implements ViewParent,
if (o == null || getClass() != o.getClass()) return false;
HandlerAction that = (HandlerAction) o;
-
return !(action != null ? !action.equals(that.action) : that.action != null);
}
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/VolumePanel.java b/core/java/android/view/VolumePanel.java
index a573983..e21824e 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -23,7 +23,9 @@ import android.content.res.Resources;
import android.media.AudioManager;
import android.media.AudioService;
import android.media.AudioSystem;
+import android.media.RingtoneManager;
import android.media.ToneGenerator;
+import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
@@ -44,7 +46,7 @@ import android.widget.Toast;
public class VolumePanel extends Handler
{
private static final String TAG = "VolumePanel";
- private static boolean LOGD = false || Config.LOGD;
+ private static boolean LOGD = false;
/**
* The delay before playing a sound. This small period exists so the user
@@ -86,6 +88,7 @@ public class VolumePanel extends Handler
protected Context mContext;
private AudioManager mAudioManager;
protected AudioService mAudioService;
+ private boolean mRingIsSilent;
private final Toast mToast;
private final View mView;
@@ -138,7 +141,7 @@ public class VolumePanel extends Handler
onShowVolumeChanged(streamType, flags);
}
- if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0) {
+ if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
removeMessages(MSG_PLAY_SOUND);
sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
}
@@ -157,6 +160,7 @@ public class VolumePanel extends Handler
int index = mAudioService.getStreamVolume(streamType);
int message = UNKNOWN_VOLUME_TEXT;
int additionalMessage = 0;
+ mRingIsSilent = false;
if (LOGD) {
Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
@@ -169,8 +173,15 @@ public class VolumePanel extends Handler
switch (streamType) {
case AudioManager.STREAM_RING: {
+ setRingerIcon();
message = RINGTONE_VOLUME_TEXT;
- setRingerIcon(index);
+ Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
+ mContext, RingtoneManager.TYPE_RINGTONE);
+ if (ringuri == null) {
+ additionalMessage =
+ com.android.internal.R.string.volume_music_hint_silent_ringtone_selected;
+ mRingIsSilent = true;
+ }
break;
}
@@ -208,6 +219,13 @@ public class VolumePanel extends Handler
case AudioManager.STREAM_NOTIFICATION: {
message = NOTIFICATION_VOLUME_TEXT;
setSmallIcon(index);
+ Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
+ mContext, RingtoneManager.TYPE_NOTIFICATION);
+ if (ringuri == null) {
+ additionalMessage =
+ com.android.internal.R.string.volume_music_hint_silent_ringtone_selected;
+ mRingIsSilent = true;
+ }
break;
}
@@ -254,7 +272,6 @@ public class VolumePanel extends Handler
mAudioService.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) {
sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
}
-
}
protected void onPlaySound(int streamType, int flags) {
@@ -337,17 +354,15 @@ public class VolumePanel extends Handler
/**
* Makes the ringer icon visible with an icon that is chosen
* based on the current ringer mode.
- *
- * @param index
*/
- private void setRingerIcon(int index) {
+ private void setRingerIcon() {
mSmallStreamIcon.setVisibility(View.GONE);
mLargeStreamIcon.setVisibility(View.VISIBLE);
int ringerMode = mAudioService.getRingerMode();
int icon;
- if (LOGD) Log.d(TAG, "setRingerIcon(index: " + index+ "), ringerMode: " + ringerMode);
+ if (LOGD) Log.d(TAG, "setRingerIcon(), ringerMode: " + ringerMode);
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
icon = com.android.internal.R.drawable.ic_volume_off;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 576c8c1..1932765 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 */
@@ -237,7 +237,6 @@ public abstract class Window {
/**
* This is called whenever the current window attributes change.
*
-
*/
public void onWindowAttributesChanged(WindowManager.LayoutParams attrs);
@@ -252,13 +251,29 @@ public abstract class Window {
public void onContentChanged();
/**
- * This hook is called whenever the window focus changes.
+ * This hook is called whenever the window focus changes. See
+ * {@link View#onWindowFocusChanged(boolean)
+ * View.onWindowFocusChanged(boolean)} for more information.
*
* @param hasFocus Whether the window now has focus.
*/
public void onWindowFocusChanged(boolean hasFocus);
/**
+ * Called when the window has been attached to the window manager.
+ * See {@link View#onAttachedToWindow() View.onAttachedToWindow()}
+ * for more information.
+ */
+ public void onAttachedToWindow();
+
+ /**
+ * Called when the window has been attached to the window manager.
+ * See {@link View#onDetachedFromWindow() View.onDetachedFromWindow()}
+ * for more information.
+ */
+ public void onDetachedFromWindow();
+
+ /**
* Called when a panel is being closed. If another logical subsequent
* panel is being opened (and this panel is being closed to make room for the subsequent
* panel), this method will NOT be called.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c0be9e8..8c12656 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -314,6 +314,12 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
/**
+ * Window type: wallpaper window, placed behind any window that wants
+ * to sit on top of the wallpaper.
+ */
+ public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
@@ -323,8 +329,6 @@ public interface WindowManager extends ViewManager {
* Default is normal.
*
* @see #MEMORY_TYPE_NORMAL
- * @see #MEMORY_TYPE_HARDWARE
- * @see #MEMORY_TYPE_GPU
* @see #MEMORY_TYPE_PUSH_BUFFERS
*/
public int memoryType;
@@ -332,10 +336,16 @@ public interface WindowManager extends ViewManager {
/** Memory type: The window's surface is allocated in main memory. */
public static final int MEMORY_TYPE_NORMAL = 0;
/** Memory type: The window's surface is configured to be accessible
- * by DMA engines and hardware accelerators. */
+ * by DMA engines and hardware accelerators.
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int MEMORY_TYPE_HARDWARE = 1;
/** Memory type: The window's surface is configured to be accessible
- * by graphics accelerators. */
+ * by graphics accelerators.
+ * @deprecated this is ignored, this value is set automatically when needed.
+ */
+ @Deprecated
public static final int MEMORY_TYPE_GPU = 2;
/** Memory type: The window's surface doesn't own its buffers and
* therefore cannot be locked. Instead the buffers are pushed to
@@ -479,16 +489,23 @@ public interface WindowManager extends ViewManager {
* key guard or any other lock screens. Can be used with
* {@link #FLAG_KEEP_SCREEN_ON} to turn screen on and display windows
* directly before showing the key guard window
- *
- * {@hide} */
+ */
public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
+ /** Window flag: ask that the system wallpaper be shown behind
+ * your window. The window surface must be translucent to be able
+ * to actually see the wallpaper behind it; this flag just ensures
+ * that the wallpaper surface will be there if this window actually
+ * has translucent regions.
+ */
+ public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
+
/** Window flag: special flag to limit the size of the window to be
* original size ([320x480] x density). Used to create window for applications
* running under compatibility mode.
*
* {@hide} */
- public static final int FLAG_COMPATIBLE_WINDOW = 0x00100000;
+ public static final int FLAG_COMPATIBLE_WINDOW = 0x20000000;
/** Window flag: a special option intended for system dialogs. When
* this flag is set, the window will demand focus unconditionally when
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 1371932..dd4b65f 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -344,11 +344,19 @@ public interface WindowManagerPolicy {
public final int TRANSIT_TASK_TO_FRONT = 10;
/** A window in an existing task is being put below all other tasks. */
public final int TRANSIT_TASK_TO_BACK = 11;
+ /** A window in a new activity is being opened on top of an existing one,
+ * and both are on top of the wallpaper. */
+ public final int TRANSIT_WALLPAPER_ACTIVITY_OPEN = 12;
+ /** The window in the top-most activity is being closed to reveal the
+ * previous activity, and both are on top of he wallpaper. */
+ public final int TRANSIT_WALLPAPER_ACTIVITY_CLOSE = 13;
/** Screen turned off because of power button */
public final int OFF_BECAUSE_OF_USER = 1;
/** Screen turned off because of timeout */
public final int OFF_BECAUSE_OF_TIMEOUT = 2;
+ /** Screen turned off because of proximity sensor */
+ public final int OFF_BECAUSE_OF_PROXIMITY_SENSOR = 3;
/**
* Magic constant to {@link IWindowManager#setRotation} to not actually
@@ -533,14 +541,15 @@ public interface WindowManagerPolicy {
* @param win The window that currently has focus. This is where the key
* event will normally go.
* @param code Key code.
- * @param metaKeys TODO
+ * @param metaKeys bit mask of meta keys that are held.
* @param down Is this a key press (true) or release (false)?
* @param repeatCount Number of times a key down has repeated.
+ * @param flags event's flags.
* @return Returns true if the policy consumed the event and it should
* not be further dispatched.
*/
public boolean interceptKeyTi(WindowState win, int code,
- int metaKeys, boolean down, int repeatCount);
+ int metaKeys, boolean down, int repeatCount, int flags);
/**
* Called when layout of the windows is about to start.
@@ -792,6 +801,13 @@ public interface WindowManagerPolicy {
public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always);
/**
+ * A special function that is called from the very low-level input queue
+ * to provide feedback to the user. Currently only called for virtual
+ * keys.
+ */
+ public void keyFeedbackFromInput(KeyEvent event);
+
+ /**
* Called when we have stopped keeping the screen on because a window
* requesting this is no longer visible.
*/
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index a662760..2f5e601 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -319,7 +319,7 @@ public abstract class Animation implements Cloneable {
*
* @param durationMillis Duration in milliseconds
*
- * @throw java.lang.IllegalArgumentException if the duration is < 0
+ * @throws java.lang.IllegalArgumentException if the duration is < 0
*
* @attr ref android.R.styleable#Animation_duration
*/
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index d797890..e30687f 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -446,13 +446,22 @@ public final class InputMethodManager {
* @hide
*/
static public InputMethodManager getInstance(Context context) {
+ return getInstance(context.getMainLooper());
+ }
+
+ /**
+ * Internally, the input method manager can't be context-dependent, so
+ * we have this here for the places that need it.
+ * @hide
+ */
+ static public InputMethodManager getInstance(Looper mainLooper) {
synchronized (mInstanceSync) {
if (mInstance != null) {
return mInstance;
}
IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
- mInstance = new InputMethodManager(service, context.getMainLooper());
+ mInstance = new InputMethodManager(service, mainLooper);
}
return mInstance;
}
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index dbd2682..ce27fd7 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);
}
}
@@ -341,17 +343,16 @@ class BrowserFrame extends Handler {
switch (msg.what) {
case FRAME_COMPLETED: {
if (mSettings.getSavePassword() && hasPasswordField()) {
- if (WebView.DEBUG) {
- Assert.assertNotNull(mCallbackProxy.getBackForwardList()
- .getCurrentItem());
- }
- WebAddress uri = new WebAddress(
- mCallbackProxy.getBackForwardList().getCurrentItem()
- .getUrl());
- String schemePlusHost = uri.mScheme + uri.mHost;
- String[] up = mDatabase.getUsernamePassword(schemePlusHost);
- if (up != null && up[0] != null) {
- setUsernamePassword(up[0], up[1]);
+ WebHistoryItem item = mCallbackProxy.getBackForwardList()
+ .getCurrentItem();
+ if (item != null) {
+ WebAddress uri = new WebAddress(item.getUrl());
+ String schemePlusHost = uri.mScheme + uri.mHost;
+ String[] up =
+ mDatabase.getUsernamePassword(schemePlusHost);
+ if (up != null && up[0] != null) {
+ setUsernamePassword(up[0], up[1]);
+ }
}
}
CacheManager.trimCacheIfNeeded();
@@ -463,8 +464,6 @@ class BrowserFrame extends Handler {
* @param postData If the method is "POST" postData is sent as the request
* body. Is null when empty.
* @param cacheMode The cache mode to use when loading this resource.
- * @param isHighPriority True if this resource needs to be put at the front
- * of the network queue.
* @param synchronous True if the load is synchronous.
* @return A newly created LoadListener object.
*/
@@ -474,7 +473,6 @@ class BrowserFrame extends Handler {
HashMap headers,
byte[] postData,
int cacheMode,
- boolean isHighPriority,
boolean synchronous) {
PerfChecker checker = new PerfChecker();
@@ -490,7 +488,7 @@ class BrowserFrame extends Handler {
}
if (mSettings.getSavePassword() && hasPasswordField()) {
try {
- if (WebView.DEBUG) {
+ if (DebugFlags.BROWSER_FRAME) {
Assert.assertNotNull(mCallbackProxy.getBackForwardList()
.getCurrentItem());
}
@@ -538,10 +536,10 @@ 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);
+ + method + ", postData=" + postData + ", isMainFramePage="
+ + isMainFramePage);
}
// Create a LoadListener
@@ -551,23 +549,17 @@ class BrowserFrame extends Handler {
mCallbackProxy.onLoadResource(url);
if (LoadListener.getNativeLoaderCount() > MAX_OUTSTANDING_REQUESTS) {
+ // send an error message, so that loadListener can be deleted
+ // after this is returned. This is important as LoadListener's
+ // nativeError will remove the request from its DocLoader's request
+ // list. But the set up is not done until this method is returned.
loadListener.error(
android.net.http.EventHandler.ERROR, mContext.getString(
com.android.internal.R.string.httpErrorTooManyRequests));
- loadListener.notifyError();
- loadListener.tearDown();
- return null;
+ return loadListener;
}
- // during synchronous load, the WebViewCore thread is blocked, so we
- // need to endCacheTransaction first so that http thread won't be
- // blocked in setupFile() when createCacheFile.
- if (synchronous) {
- CacheManager.endCacheTransaction();
- }
-
- FrameLoader loader = new FrameLoader(loadListener, mSettings,
- method, isHighPriority);
+ FrameLoader loader = new FrameLoader(loadListener, mSettings, method);
loader.setHeaders(headers);
loader.setPostData(postData);
// Set the load mode to the mode used for the current page.
@@ -581,10 +573,6 @@ class BrowserFrame extends Handler {
}
checker.responseAlert("startLoadingResource succeed");
- if (synchronous) {
- CacheManager.startCacheTransaction();
- }
-
return !synchronous ? loadListener : null;
}
@@ -615,6 +603,11 @@ class BrowserFrame extends Handler {
mCallbackProxy.onReceivedIcon(icon);
}
+ // Called by JNI when an apple-touch-icon attribute was found.
+ private void didReceiveTouchIconUrl(String url) {
+ mCallbackProxy.onReceivedTouchIconUrl(url);
+ }
+
/**
* Request a new window from the client.
* @return The BrowserFrame object stored in the new WebView.
@@ -691,7 +684,7 @@ class BrowserFrame extends Handler {
default:
Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
- return new String();
+ return "";
}
TypedValue value = new TypedValue();
mContext.getResources().getValue(resid, value, true);
diff --git a/core/java/android/webkit/CacheLoader.java b/core/java/android/webkit/CacheLoader.java
index 3e1b602..de8f888 100644
--- a/core/java/android/webkit/CacheLoader.java
+++ b/core/java/android/webkit/CacheLoader.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.net.http.Headers;
+import android.text.TextUtils;
/**
* This class is a concrete implementation of StreamLoader that uses a
@@ -49,17 +50,22 @@ class CacheLoader extends StreamLoader {
@Override
protected void buildHeaders(Headers headers) {
StringBuilder sb = new StringBuilder(mCacheResult.mimeType);
- if (mCacheResult.encoding != null &&
- mCacheResult.encoding.length() > 0) {
+ if (!TextUtils.isEmpty(mCacheResult.encoding)) {
sb.append(';');
sb.append(mCacheResult.encoding);
}
headers.setContentType(sb.toString());
- if (mCacheResult.location != null &&
- mCacheResult.location.length() > 0) {
+ if (!TextUtils.isEmpty(mCacheResult.location)) {
headers.setLocation(mCacheResult.location);
}
- }
+ if (!TextUtils.isEmpty(mCacheResult.expiresString)) {
+ headers.setExpires(mCacheResult.expiresString);
+ }
+
+ if (!TextUtils.isEmpty(mCacheResult.contentdisposition)) {
+ headers.setContentDisposition(mCacheResult.contentdisposition);
+ }
+ }
}
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 7897435..02e8d6f 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;
@@ -80,12 +79,14 @@ public final class CacheManager {
int httpStatusCode;
long contentLength;
long expires;
+ String expiresString;
String localPath;
String lastModified;
String etag;
String mimeType;
String location;
String encoding;
+ String contentdisposition;
// these fields are NOT saved to the database
InputStream inStream;
@@ -108,6 +109,13 @@ public final class CacheManager {
return expires;
}
+ /**
+ * @hide Pending API council approval
+ */
+ public String getExpiresString() {
+ return expiresString;
+ }
+
public String getLastModified() {
return lastModified;
}
@@ -128,6 +136,13 @@ public final class CacheManager {
return encoding;
}
+ /**
+ * @hide Pending API council approval
+ */
+ public String getContentDisposition() {
+ return contentdisposition;
+ }
+
// For out-of-package access to the underlying streams.
public InputStream getInputStream() {
return inStream;
@@ -321,7 +336,7 @@ public final class CacheManager {
}
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.CACHE_MANAGER) {
Log.v(LOGTAG, "getCacheFile for url " + url);
}
@@ -340,7 +355,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 +364,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);
@@ -403,19 +426,23 @@ public final class CacheManager {
}
cacheRet.contentLength = cacheRet.outFile.length();
- if (checkCacheRedirect(cacheRet.httpStatusCode)) {
+ boolean redirect = checkCacheRedirect(cacheRet.httpStatusCode);
+ if (redirect) {
// location is in database, no need to keep the file
cacheRet.contentLength = 0;
- cacheRet.localPath = new String();
- cacheRet.outFile.delete();
- } else if (cacheRet.contentLength == 0) {
- cacheRet.outFile.delete();
+ cacheRet.localPath = "";
+ }
+ if ((redirect || cacheRet.contentLength == 0)
+ && !cacheRet.outFile.delete()) {
+ Log.e(LOGTAG, cacheRet.outFile.getPath() + " delete failed.");
+ }
+ if (cacheRet.contentLength == 0) {
return;
}
mDataBase.addCache(url, cacheRet);
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.CACHE_MANAGER) {
Log.v(LOGTAG, "saveCacheFile for url " + url);
}
}
@@ -444,7 +471,10 @@ public final class CacheManager {
// if mBaseDir doesn't exist, files can be null.
if (files != null) {
for (int i = 0; i < files.length; i++) {
- new File(mBaseDir, files[i]).delete();
+ File f = new File(mBaseDir, files[i]);
+ if (!f.delete()) {
+ Log.e(LOGTAG, f.getPath() + " delete failed.");
+ }
}
}
} catch (SecurityException e) {
@@ -472,7 +502,10 @@ public final class CacheManager {
ArrayList<String> pathList = mDataBase.trimCache(CACHE_TRIM_AMOUNT);
int size = pathList.size();
for (int i = 0; i < size; i++) {
- new File(mBaseDir, pathList.get(i)).delete();
+ File f = new File(mBaseDir, pathList.get(i));
+ if (!f.delete()) {
+ Log.e(LOGTAG, f.getPath() + " delete failed.");
+ }
}
}
}
@@ -511,12 +544,7 @@ public final class CacheManager {
// cache file. If it is not, resolve the collision.
while (file.exists()) {
if (checkOldPath) {
- // as this is called from http thread through
- // createCacheFile, we need endCacheTransaction before
- // database access.
- WebViewCore.endCacheTransaction();
CacheResult oldResult = mDataBase.getCache(url);
- WebViewCore.startCacheTransaction();
if (oldResult != null && oldResult.contentLength > 0) {
if (path.equals(oldResult.localPath)) {
path = oldResult.localPath;
@@ -596,21 +624,27 @@ public final class CacheManager {
if (location != null) ret.location = location;
ret.expires = -1;
- String expires = headers.getExpires();
- if (expires != null) {
+ ret.expiresString = headers.getExpires();
+ if (ret.expiresString != null) {
try {
- ret.expires = HttpDateTime.parse(expires);
+ ret.expires = HttpDateTime.parse(ret.expiresString);
} catch (IllegalArgumentException ex) {
// Take care of the special "-1" and "0" cases
- if ("-1".equals(expires) || "0".equals(expires)) {
+ if ("-1".equals(ret.expiresString)
+ || "0".equals(ret.expiresString)) {
// make it expired, but can be used for history navigation
ret.expires = 0;
} else {
- Log.e(LOGTAG, "illegal expires: " + expires);
+ Log.e(LOGTAG, "illegal expires: " + ret.expiresString);
}
}
}
+ String contentDisposition = headers.getContentDisposition();
+ if (contentDisposition != null) {
+ ret.contentdisposition = contentDisposition;
+ }
+
String lastModified = headers.getLastModified();
if (lastModified != null) ret.lastModified = lastModified;
@@ -628,7 +662,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..41e604d 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -72,40 +72,46 @@ 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 REACHED_APPCACHE_MAXSIZE = 127;
+ private static final int JS_TIMEOUT = 128;
+ private static final int ADD_MESSAGE_TO_CONSOLE = 129;
+ private static final int GEOLOCATION_PERMISSIONS_SHOW_PROMPT = 130;
+ private static final int GEOLOCATION_PERMISSIONS_HIDE_PROMPT = 131;
+ private static final int RECEIVED_TOUCH_ICON_URL = 132;
// 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.
- private class ResultTransport<E> {
+ private static class ResultTransport<E> {
// Private result object
private E mResult;
@@ -145,6 +151,16 @@ class CallbackProxy extends Handler {
}
/**
+ * Get the WebChromeClient.
+ * @return the current WebChromeClient instance.
+ *
+ *@hide pending API council approval.
+ */
+ public WebChromeClient getWebChromeClient() {
+ return mWebChromeClient;
+ }
+
+ /**
* Set the client DownloadListener.
* @param client An implementation of DownloadListener.
*/
@@ -161,6 +177,17 @@ class CallbackProxy extends Handler {
}
/**
+ * Tell the host application that the WebView has changed viewing modes.
+ * @param newViewingMode One of the values described in WebView as possible
+ * values for the viewing mode
+ */
+ /* package */ void uiOnChangeViewingMode(int newViewingMode) {
+ if (mWebChromeClient != null) {
+ mWebChromeClient.onChangeViewingMode(mWebView, newViewingMode);
+ }
+ }
+
+ /**
* Called by the UI side. Calling overrideUrlLoading from the WebCore
* side will post a message to call this method.
*/
@@ -229,6 +256,13 @@ class CallbackProxy extends Handler {
}
break;
+ case RECEIVED_TOUCH_ICON_URL:
+ if (mWebChromeClient != null) {
+ mWebChromeClient.onReceivedTouchIconUrl(mWebView,
+ (String) msg.obj);
+ }
+ break;
+
case RECEIVED_TITLE:
if (mWebChromeClient != null) {
mWebChromeClient.onReceivedTitle(mWebView,
@@ -389,6 +423,63 @@ 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();
+ long totalUsedQuota =
+ ((Long) map.get("totalUsedQuota")).longValue();
+ long estimatedSize =
+ ((Long) map.get("estimatedSize")).longValue();
+ WebStorage.QuotaUpdater quotaUpdater =
+ (WebStorage.QuotaUpdater) map.get("quotaUpdater");
+
+ mWebChromeClient.onExceededDatabaseQuota(url,
+ databaseIdentifier, currentQuota, estimatedSize,
+ totalUsedQuota, quotaUpdater);
+ }
+ break;
+
+ case REACHED_APPCACHE_MAXSIZE:
+ if (mWebChromeClient != null) {
+ HashMap<String, Object> map =
+ (HashMap<String, Object>) msg.obj;
+ long spaceNeeded =
+ ((Long) map.get("spaceNeeded")).longValue();
+ long totalUsedQuota =
+ ((Long) map.get("totalUsedQuota")).longValue();
+ WebStorage.QuotaUpdater quotaUpdater =
+ (WebStorage.QuotaUpdater) map.get("quotaUpdater");
+
+ mWebChromeClient.onReachedMaxAppCacheSize(spaceNeeded,
+ totalUsedQuota, quotaUpdater);
+ }
+ break;
+
+ case GEOLOCATION_PERMISSIONS_SHOW_PROMPT:
+ if (mWebChromeClient != null) {
+ HashMap<String, Object> map =
+ (HashMap<String, Object>) msg.obj;
+ String origin = (String) map.get("origin");
+ GeolocationPermissions.Callback callback =
+ (GeolocationPermissions.Callback)
+ map.get("callback");
+ mWebChromeClient.onGeolocationPermissionsShowPrompt(origin,
+ callback);
+ }
+ break;
+
+ case GEOLOCATION_PERMISSIONS_HIDE_PROMPT:
+ if (mWebChromeClient != null) {
+ mWebChromeClient.onGeolocationPermissionsHidePrompt();
+ }
+ break;
+
case JS_ALERT:
if (mWebChromeClient != null) {
final JsResult res = (JsResult) msg.obj;
@@ -563,6 +654,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;
}
}
@@ -605,7 +703,40 @@ class CallbackProxy extends Handler {
//--------------------------------------------------------------------------
// Performance probe
+ private static final boolean PERF_PROBE = false;
private long mWebCoreThreadTime;
+ private long mWebCoreIdleTime;
+
+ /*
+ * If PERF_PROBE is true, this block needs to be added to MessageQueue.java.
+ * startWait() and finishWait() should be called before and after wait().
+
+ private WaitCallback mWaitCallback = null;
+ public static interface WaitCallback {
+ void startWait();
+ void finishWait();
+ }
+ public final void setWaitCallback(WaitCallback callback) {
+ mWaitCallback = callback;
+ }
+ */
+
+ // un-comment this block if PERF_PROBE is true
+ /*
+ private IdleCallback mIdleCallback = new IdleCallback();
+
+ private final class IdleCallback implements MessageQueue.WaitCallback {
+ private long mStartTime = 0;
+
+ public void finishWait() {
+ mWebCoreIdleTime += SystemClock.uptimeMillis() - mStartTime;
+ }
+
+ public void startWait() {
+ mStartTime = SystemClock.uptimeMillis();
+ }
+ }
+ */
public void onPageStarted(String url, Bitmap favicon) {
// Do an unsynchronized quick check to avoid posting if no callback has
@@ -614,9 +745,12 @@ class CallbackProxy extends Handler {
return;
}
// Performance probe
- if (false) {
+ if (PERF_PROBE) {
mWebCoreThreadTime = SystemClock.currentThreadTimeMillis();
+ mWebCoreIdleTime = 0;
Network.getInstance(mContext).startTiming();
+ // un-comment this if PERF_PROBE is true
+// Looper.myQueue().setWaitCallback(mIdleCallback);
}
Message msg = obtainMessage(PAGE_STARTED);
msg.obj = favicon;
@@ -631,10 +765,12 @@ class CallbackProxy extends Handler {
return;
}
// Performance probe
- if (false) {
+ if (PERF_PROBE) {
+ // un-comment this if PERF_PROBE is true
+// Looper.myQueue().setWaitCallback(null);
Log.d("WebCore", "WebCore thread used " +
(SystemClock.currentThreadTimeMillis() - mWebCoreThreadTime)
- + " ms");
+ + " ms and idled " + mWebCoreIdleTime + " ms");
Network.getInstance(mContext).stopTiming();
}
Message msg = obtainMessage(PAGE_FINISHED, url);
@@ -834,7 +970,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);
@@ -939,6 +1075,21 @@ class CallbackProxy extends Handler {
sendMessage(obtainMessage(RECEIVED_ICON, icon));
}
+ /* package */ void onReceivedTouchIconUrl(String url) {
+ // We should have a current item but we do not want to crash so check
+ // for null.
+ WebHistoryItem i = mBackForwardList.getCurrentItem();
+ if (i != null) {
+ i.setTouchIconUrl(url);
+ }
+ // Do an unsynchronized quick check to avoid posting if no callback has
+ // been set.
+ if (mWebChromeClient == null) {
+ return;
+ }
+ sendMessage(obtainMessage(RECEIVED_TOUCH_ICON_URL, url));
+ }
+
public void onReceivedTitle(String title) {
// Do an unsynchronized quick check to avoid posting if no callback has
// been set.
@@ -1037,6 +1188,130 @@ 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 estimatedSize The estimated size of the database.
+ * @param totalUsedQuota is the sum of all origins' quota.
+ * @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,
+ long estimatedSize, long totalUsedQuota,
+ 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("estimatedSize", estimatedSize);
+ map.put("totalUsedQuota", totalUsedQuota);
+ map.put("quotaUpdater", quotaUpdater);
+ exceededQuota.obj = map;
+ sendMessage(exceededQuota);
+ }
+
+ /**
+ * Called by WebViewCore to inform the Java side that the appcache has
+ * exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ * @param totalUsedQuota is the sum of all origins' quota.
+ * @param quotaUpdater An instance of a class encapsulating a callback
+ * to WebViewCore to run when the decision to allow or deny a bigger
+ * app cache size has been made.
+ * @hide pending API council approval.
+ */
+ public void onReachedMaxAppCacheSize(long spaceNeeded,
+ long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
+ if (mWebChromeClient == null) {
+ quotaUpdater.updateQuota(0);
+ return;
+ }
+
+ Message msg = obtainMessage(REACHED_APPCACHE_MAXSIZE);
+ HashMap<String, Object> map = new HashMap();
+ map.put("spaceNeeded", spaceNeeded);
+ map.put("totalUsedQuota", totalUsedQuota);
+ map.put("quotaUpdater", quotaUpdater);
+ msg.obj = map;
+ sendMessage(msg);
+ }
+
+ /**
+ * Called by WebViewCore to instruct the browser to display a prompt to ask
+ * the user to set the Geolocation permission state for the given origin.
+ * @param origin The origin requesting Geolocation permsissions.
+ * @param callback The callback to call once a permission state has been
+ * obtained.
+ * @hide pending API council review.
+ */
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {
+ if (mWebChromeClient == null) {
+ return;
+ }
+
+ Message showMessage =
+ obtainMessage(GEOLOCATION_PERMISSIONS_SHOW_PROMPT);
+ HashMap<String, Object> map = new HashMap();
+ map.put("origin", origin);
+ map.put("callback", callback);
+ showMessage.obj = map;
+ sendMessage(showMessage);
+ }
+
+ /**
+ * Called by WebViewCore to instruct the browser to hide the Geolocation
+ * permissions prompt.
+ * origin.
+ * @hide pending API council review.
+ */
+ public void onGeolocationPermissionsHidePrompt() {
+ if (mWebChromeClient == null) {
+ return;
+ }
+
+ Message hideMessage = obtainMessage(GEOLOCATION_PERMISSIONS_HIDE_PROMPT);
+ sendMessage(hideMessage);
+ }
+
+ /**
+ * 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/ContentLoader.java b/core/java/android/webkit/ContentLoader.java
index f6d7f69..27cd6b5 100644
--- a/core/java/android/webkit/ContentLoader.java
+++ b/core/java/android/webkit/ContentLoader.java
@@ -105,8 +105,7 @@ class ContentLoader extends StreamLoader {
if (mContentType != null) {
headers.setContentType("text/html");
}
- // override the cache-control header set by StreamLoader as content can
- // change, we don't want WebKit to cache it
+ // content can change, we don't want WebKit to cache it
headers.setCacheControl("no-store, no-cache");
}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index e8c2279..fca591f 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -23,9 +23,12 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
/**
* CookieManager manages cookies according to RFC2109 spec.
@@ -190,6 +193,31 @@ public final class CookieManager {
}
}
+ private static final CookieComparator COMPARATOR = new CookieComparator();
+
+ private static final class CookieComparator implements Comparator<Cookie> {
+ public int compare(Cookie cookie1, Cookie cookie2) {
+ // According to RFC 2109, multiple cookies are ordered in a way such
+ // that those with more specific Path attributes precede those with
+ // less specific. Ordering with respect to other attributes (e.g.,
+ // Domain) is unspecified.
+ // As Set is not modified if the two objects are same, we do want to
+ // assign different value for each cookie.
+ int diff = cookie2.path.length() - cookie1.path.length();
+ if (diff == 0) {
+ diff = cookie2.domain.length() - cookie1.domain.length();
+ if (diff == 0) {
+ diff = cookie2.name.hashCode() - cookie1.name.hashCode();
+ if (diff == 0) {
+ Log.w(LOGTAG, "Found two cookies with the same value." +
+ "cookie1=" + cookie1 + " , cookie2=" + cookie2);
+ }
+ }
+ }
+ return diff;
+ }
+ }
+
private CookieManager() {
}
@@ -262,7 +290,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);
}
@@ -401,8 +429,8 @@ public final class CookieManager {
long now = System.currentTimeMillis();
boolean secure = HTTPS.equals(uri.mScheme);
Iterator<Cookie> iter = cookieList.iterator();
- StringBuilder ret = new StringBuilder(256);
+ SortedSet<Cookie> cookieSet = new TreeSet<Cookie>(COMPARATOR);
while (iter.hasNext()) {
Cookie cookie = iter.next();
if (cookie.domainMatch(hostAndPath[0]) &&
@@ -413,26 +441,33 @@ public final class CookieManager {
&& (!cookie.secure || secure)
&& cookie.mode != Cookie.MODE_DELETED) {
cookie.lastAcessTime = now;
+ cookieSet.add(cookie);
+ }
+ }
- if (ret.length() > 0) {
- ret.append(SEMICOLON);
- // according to RC2109, SEMICOLON is office separator,
- // but when log in yahoo.com, it needs WHITE_SPACE too.
- ret.append(WHITE_SPACE);
- }
-
- ret.append(cookie.name);
- ret.append(EQUAL);
- ret.append(cookie.value);
+ StringBuilder ret = new StringBuilder(256);
+ Iterator<Cookie> setIter = cookieSet.iterator();
+ while (setIter.hasNext()) {
+ Cookie cookie = setIter.next();
+ if (ret.length() > 0) {
+ ret.append(SEMICOLON);
+ // according to RC2109, SEMICOLON is official separator,
+ // but when log in yahoo.com, it needs WHITE_SPACE too.
+ ret.append(WHITE_SPACE);
}
+
+ ret.append(cookie.name);
+ ret.append(EQUAL);
+ ret.append(cookie.value);
}
+
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 +623,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 +643,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 +651,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");
}
@@ -798,22 +833,24 @@ public final class CookieManager {
// "secure" is a known attribute doesn't use "=";
// while sites like live.com uses "secure="
- if (length - index > SECURE_LENGTH
+ if (length - index >= SECURE_LENGTH
&& cookieString.substring(index, index + SECURE_LENGTH).
equalsIgnoreCase(SECURE)) {
index += SECURE_LENGTH;
cookie.secure = true;
+ if (index == length) break;
if (cookieString.charAt(index) == EQUAL) index++;
continue;
}
// "httponly" is a known attribute doesn't use "=";
// while sites like live.com uses "httponly="
- if (length - index > HTTP_ONLY_LENGTH
+ if (length - index >= HTTP_ONLY_LENGTH
&& cookieString.substring(index,
index + HTTP_ONLY_LENGTH).
equalsIgnoreCase(HTTP_ONLY)) {
index += HTTP_ONLY_LENGTH;
+ if (index == length) break;
if (cookieString.charAt(index) == EQUAL) index++;
// FIXME: currently only parse the attribute
continue;
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/DateSorter.java b/core/java/android/webkit/DateSorter.java
index 750403b..c46702e 100644
--- a/core/java/android/webkit/DateSorter.java
+++ b/core/java/android/webkit/DateSorter.java
@@ -43,9 +43,6 @@ public class DateSorter {
private static final int NUM_DAYS_AGO = 5;
- Date mDate = new Date();
- Calendar mCal = Calendar.getInstance();
-
/**
* @param context Application context
*/
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
new file mode 100644
index 0000000..8e25395
--- /dev/null
+++ b/core/java/android/webkit/DebugFlags.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.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_TEXT_VIEW = 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 66ab021..c1eeb3b 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -28,7 +28,6 @@ class FrameLoader {
private final LoadListener mListener;
private final String mMethod;
- private final boolean mIsHighPriority;
private final WebSettings mSettings;
private Map<String, String> mHeaders;
private byte[] mPostData;
@@ -52,11 +51,10 @@ class FrameLoader {
private static final String LOGTAG = "webkit";
FrameLoader(LoadListener listener, WebSettings settings,
- String method, boolean highPriority) {
+ String method) {
mListener = listener;
mHeaders = null;
mMethod = method;
- mIsHighPriority = highPriority;
mCacheMode = WebSettings.LOAD_NORMAL;
mSettings = settings;
}
@@ -97,17 +95,6 @@ class FrameLoader {
public boolean executeLoad() {
String url = mListener.url();
- // Attempt to decode the percent-encoded url.
- try {
- url = new String(URLUtil.decode(url.getBytes()));
- } catch (IllegalArgumentException e) {
- // Fail with a bad url error if the decode fails.
- mListener.error(EventHandler.ERROR_BAD_URL,
- mListener.getContext().getString(
- com.android.internal.R.string.httpErrorBadUrl));
- return false;
- }
-
if (URLUtil.isNetworkUrl(url)){
if (mSettings.getBlockNetworkLoads()) {
mListener.error(EventHandler.ERROR_BAD_URL,
@@ -115,12 +102,19 @@ class FrameLoader {
com.android.internal.R.string.httpErrorBadUrl));
return false;
}
+ // Make sure it is correctly URL encoded before sending the request
+ if (!URLUtil.verifyURLEncoding(url)) {
+ mListener.error(EventHandler.ERROR_BAD_URL,
+ mListener.getContext().getString(
+ com.android.internal.R.string.httpErrorBadUrl));
+ return false;
+ }
mNetwork = Network.getInstance(mListener.getContext());
return handleHTTPLoad();
} 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());
}
@@ -134,6 +128,18 @@ class FrameLoader {
/* package */
static boolean handleLocalFile(String url, LoadListener loadListener,
WebSettings settings) {
+ // Attempt to decode the percent-encoded url before passing to the
+ // local loaders.
+ try {
+ url = new String(URLUtil.decode(url.getBytes()));
+ } catch (IllegalArgumentException e) {
+ loadListener.error(EventHandler.ERROR_BAD_URL,
+ loadListener.getContext().getString(
+ com.android.internal.R.string.httpErrorBadUrl));
+ // Return true here so we do not trigger an unsupported scheme
+ // error.
+ return true;
+ }
if (URLUtil.isAssetUrl(url)) {
FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
true, settings.getAllowFileAccess());
@@ -166,21 +172,17 @@ class FrameLoader {
populateStaticHeaders();
populateHeaders();
- // response was handled by UrlIntercept, don't issue HTTP request
- if (handleUrlIntercept()) return true;
-
// response was handled by Cache, don't issue HTTP request
if (handleCache()) {
// push the request data down to the LoadListener
// as response from the cache could be a redirect
// and we may need to initiate a network request if the cache
// can't satisfy redirect URL
- mListener.setRequestData(mMethod, mHeaders, mPostData,
- mIsHighPriority);
+ mListener.setRequestData(mMethod, mHeaders, mPostData);
return true;
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader: http " + mMethod + " load for: "
+ mListener.url());
}
@@ -190,7 +192,7 @@ class FrameLoader {
try {
ret = mNetwork.requestURL(mMethod, mHeaders,
- mPostData, mListener, mIsHighPriority);
+ mPostData, mListener);
} catch (android.net.ParseException ex) {
error = EventHandler.ERROR_BAD_URL;
} catch (java.lang.RuntimeException ex) {
@@ -207,11 +209,11 @@ class FrameLoader {
}
/*
- * This function is used by handleUrlInterecpt and handleCache to
+ * This function is used by handleCache to
* 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());
}
@@ -223,30 +225,6 @@ class FrameLoader {
}
/*
- * This function is used by handleHTTPLoad to allow URL
- * interception. This can be used to provide alternative load
- * methods such as locally stored versions or for debugging.
- *
- * Returns true if the response was handled by UrlIntercept.
- */
- private boolean handleUrlIntercept() {
- // Check if the URL can be served from UrlIntercept. If
- // successful, return the data just like a cache hit.
-
- PluginData data = UrlInterceptRegistry.getPluginData(
- mListener.url(), mHeaders);
-
- if(data != null) {
- PluginContentLoader loader =
- new PluginContentLoader(mListener, data);
- loader.load();
- return true;
- }
- // Not intercepted. Carry on as normal.
- return false;
- }
-
- /*
* This function is used by the handleHTTPLoad to setup the cache headers
* correctly.
* Returns true if the response was handled from the cache
@@ -285,7 +263,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/GearsPermissionsManager.java b/core/java/android/webkit/GearsPermissionsManager.java
deleted file mode 100644
index 6549cb8..0000000
--- a/core/java/android/webkit/GearsPermissionsManager.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.webkit;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.database.ContentObserver;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteStatement;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.provider.Settings;
-import android.util.Log;
-
-import java.io.File;
-import java.util.HashSet;
-
-/**
- * Donut-specific hack to keep Gears permissions in sync with the
- * system location setting.
- */
-class GearsPermissionsManager {
- // The application context.
- Context mContext;
- // The path to gears.so.
- private String mGearsPath;
-
- // The Gears permissions database directory.
- private final static String GEARS_DATABASE_DIR = "gears";
- // The Gears permissions database file name.
- private final static String GEARS_DATABASE_FILE = "permissions.db";
- // The Gears location permissions table.
- private final static String GEARS_LOCATION_ACCESS_TABLE_NAME =
- "LocationAccess";
- // The Gears storage access permissions table.
- private final static String GEARS_STORAGE_ACCESS_TABLE_NAME = "Access";
- // The Gears permissions db schema version table.
- private final static String GEARS_SCHEMA_VERSION_TABLE_NAME =
- "VersionInfo";
- // The Gears permission value that denotes "allow access to location".
- private static final int GEARS_ALLOW_LOCATION_ACCESS = 1;
- // The shared pref name.
- private static final String LAST_KNOWN_LOCATION_SETTING =
- "lastKnownLocationSystemSetting";
- // The Browser package name.
- private static final String BROWSER_PACKAGE_NAME = "com.android.browser";
- // The Secure Settings observer that will be notified when the system
- // location setting changes.
- private SecureSettingsObserver mSettingsObserver;
- // The Google URLs whitelisted for Gears location access.
- private static HashSet<String> sGearsWhiteList;
-
- static {
- sGearsWhiteList = new HashSet<String>();
- // NOTE: DO NOT ADD A "/" AT THE END!
- sGearsWhiteList.add("http://www.google.com");
- sGearsWhiteList.add("http://www.google.co.uk");
- }
-
- private static final String LOGTAG = "webcore";
- static final boolean DEBUG = false;
- static final boolean LOGV_ENABLED = DEBUG;
-
- GearsPermissionsManager(Context context, String gearsPath) {
- mContext = context;
- mGearsPath = gearsPath;
- }
-
- public void doCheckAndStartObserver() {
- // Are we running in the browser?
- if (!BROWSER_PACKAGE_NAME.equals(mContext.getPackageName())) {
- return;
- }
- // Do the check.
- checkGearsPermissions();
- // Install the observer.
- mSettingsObserver = new SecureSettingsObserver();
- mSettingsObserver.observe();
- }
-
- private void checkGearsPermissions() {
- // Get the current system settings.
- int setting = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.USE_LOCATION_FOR_SERVICES, -1);
- // Check if we need to set the Gears permissions.
- if (setting != -1 && locationSystemSettingChanged(setting)) {
- setGearsPermissionForGoogleDomains(setting);
- }
- }
-
- private boolean locationSystemSettingChanged(int newSetting) {
- SharedPreferences prefs =
- PreferenceManager.getDefaultSharedPreferences(mContext);
- int oldSetting = 0;
- oldSetting = prefs.getInt(LAST_KNOWN_LOCATION_SETTING, oldSetting);
- if (oldSetting == newSetting) {
- return false;
- }
- Editor ed = prefs.edit();
- ed.putInt(LAST_KNOWN_LOCATION_SETTING, newSetting);
- ed.commit();
- return true;
- }
-
- private void setGearsPermissionForGoogleDomains(int systemPermission) {
- // Transform the system permission into a boolean flag. When this
- // flag is true, it means the origins in gGearsWhiteList are added
- // to the Gears location permission table with permission 1 (allowed).
- // When the flag is false, the origins in gGearsWhiteList are removed
- // from the Gears location permission table. Next time the user
- // navigates to one of these origins, she will see the normal Gears
- // permission prompt.
- boolean addToGearsLocationTable = (systemPermission == 1 ? true : false);
- // Build the path to the Gears library.
-
- File file = new File(mGearsPath).getParentFile();
- if (file == null) {
- return;
- }
- // Build the Gears database file name.
- file = new File(file.getAbsolutePath() + File.separator
- + GEARS_DATABASE_DIR + File.separator + GEARS_DATABASE_FILE);
- // Remember whether or not we need to create the LocationAccess table.
- boolean needToCreateTables = false;
- if (!file.exists()) {
- needToCreateTables = true;
- // Create the path or else SQLiteDatabase.openOrCreateDatabase()
- // may throw on the device.
- file.getParentFile().mkdirs();
- }
- // If the database file does not yet exist and the system location
- // setting says that the Gears origins need to be removed from the
- // location permission table, it means that we don't actually need
- // to do anything at all.
- if (needToCreateTables && !addToGearsLocationTable) {
- return;
- }
- // Try opening the Gears database.
- SQLiteDatabase permissions;
- try {
- permissions = SQLiteDatabase.openOrCreateDatabase(file, null);
- } catch (SQLiteException e) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "Could not open Gears permission DB: "
- + e.getMessage());
- }
- // Just bail out.
- return;
- }
- // We now have a database open. Begin a transaction.
- permissions.beginTransaction();
- try {
- if (needToCreateTables) {
- // Create the tables. Note that this creates the
- // Gears tables for the permissions DB schema version 2.
- // The Gears schema upgrade process will take care of the rest.
- // First, the storage access table.
- SQLiteStatement statement = permissions.compileStatement(
- "CREATE TABLE IF NOT EXISTS "
- + GEARS_STORAGE_ACCESS_TABLE_NAME
- + " (Name TEXT UNIQUE, Value)");
- statement.execute();
- // Next the location access table.
- statement = permissions.compileStatement(
- "CREATE TABLE IF NOT EXISTS "
- + GEARS_LOCATION_ACCESS_TABLE_NAME
- + " (Name TEXT UNIQUE, Value)");
- statement.execute();
- // Finally, the schema version table.
- statement = permissions.compileStatement(
- "CREATE TABLE IF NOT EXISTS "
- + GEARS_SCHEMA_VERSION_TABLE_NAME
- + " (Name TEXT UNIQUE, Value)");
- statement.execute();
- // Set the schema version to 2.
- ContentValues schema = new ContentValues();
- schema.put("Name", "Version");
- schema.put("Value", 2);
- permissions.insert(GEARS_SCHEMA_VERSION_TABLE_NAME, null,
- schema);
- }
-
- if (addToGearsLocationTable) {
- ContentValues permissionValues = new ContentValues();
-
- for (String url : sGearsWhiteList) {
- permissionValues.put("Name", url);
- permissionValues.put("Value", GEARS_ALLOW_LOCATION_ACCESS);
- permissions.replace(GEARS_LOCATION_ACCESS_TABLE_NAME, null,
- permissionValues);
- permissionValues.clear();
- }
- } else {
- for (String url : sGearsWhiteList) {
- permissions.delete(GEARS_LOCATION_ACCESS_TABLE_NAME, "Name=?",
- new String[] { url });
- }
- }
- // Commit the transaction.
- permissions.setTransactionSuccessful();
- } catch (SQLiteException e) {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "Could not set the Gears permissions: "
- + e.getMessage());
- }
- } finally {
- permissions.endTransaction();
- permissions.close();
- }
- }
-
- class SecureSettingsObserver extends ContentObserver {
- SecureSettingsObserver() {
- super(new Handler());
- }
-
- void observe() {
- ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.USE_LOCATION_FOR_SERVICES), false, this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- checkGearsPermissions();
- }
- }
-}
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
new file mode 100755
index 0000000..e985ccc
--- /dev/null
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -0,0 +1,259 @@
+/*
+ * 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.HashSet;
+import java.util.Set;
+
+
+/**
+ * Implements the Java side of GeolocationPermissions. Simply marshalls calls
+ * from the UI thread to the WebKit thread.
+ * @hide
+ */
+public final class GeolocationPermissions {
+ /**
+ * Callback interface used by the browser to report a Geolocation permission
+ * state set by the user in response to a permissions prompt.
+ */
+ public interface Callback {
+ public void invoke(String origin, boolean allow, boolean remember);
+ };
+
+ // Log tag
+ private static final String TAG = "geolocationPermissions";
+
+ // Global instance
+ private static GeolocationPermissions sInstance;
+
+ private Handler mHandler;
+
+ // Members used to transfer the origins and permissions between threads.
+ private Set<String> mOrigins;
+ private boolean mAllowed;
+ private Set<String> mOriginsToClear;
+ private Set<String> mOriginsToAllow;
+ private static Lock mLock = new ReentrantLock();
+ private static boolean mUpdated;
+ private static Condition mUpdatedCondition = mLock.newCondition();
+
+ // Message ids
+ static final int GET_ORIGINS = 0;
+ static final int GET_ALLOWED = 1;
+ static final int CLEAR = 2;
+ static final int ALLOW = 3;
+ static final int CLEAR_ALL = 4;
+
+ /**
+ * Gets the singleton instance of the class.
+ */
+ public static GeolocationPermissions getInstance() {
+ if (sInstance == null) {
+ sInstance = new GeolocationPermissions();
+ }
+ return sInstance;
+ }
+
+ /**
+ * Creates the message handler. Must be called on the WebKit thread.
+ */
+ public void createHandler() {
+ mLock.lock();
+ if (mHandler == null) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ // Runs on the WebKit thread.
+ switch (msg.what) {
+ case GET_ORIGINS:
+ getOriginsImpl();
+ break;
+ case GET_ALLOWED:
+ getAllowedImpl((String) msg.obj);
+ break;
+ case CLEAR:
+ nativeClear((String) msg.obj);
+ break;
+ case ALLOW:
+ nativeAllow((String) msg.obj);
+ break;
+ case CLEAR_ALL:
+ nativeClearAll();
+ break;
+ }
+ }
+ };
+
+ if (mOriginsToClear != null) {
+ for (String origin : mOriginsToClear) {
+ nativeClear(origin);
+ }
+ }
+ if (mOriginsToAllow != null) {
+ for (String origin : mOriginsToAllow) {
+ nativeAllow(origin);
+ }
+ }
+ }
+ mLock.unlock();
+ }
+
+ /**
+ * Utility function to send a message to our handler.
+ */
+ private void postMessage(Message msg) {
+ assert(mHandler != null);
+ mHandler.sendMessage(msg);
+ }
+
+ /**
+ * Gets the set of origins for which Geolocation permissions are stored.
+ * Note that we represent the origins as strings. These are created using
+ * WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules'
+ * (Database, Geolocation etc) do so, it's safe to match up origins for the
+ * purposes of displaying UI.
+ */
+ public Set getOrigins() {
+ // Called on the UI thread.
+ Set origins = null;
+ mLock.lock();
+ try {
+ mUpdated = false;
+ postMessage(Message.obtain(null, GET_ORIGINS));
+ while (!mUpdated) {
+ mUpdatedCondition.await();
+ }
+ origins = mOrigins;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting for update", e);
+ } finally {
+ mLock.unlock();
+ }
+ return origins;
+ }
+
+ /**
+ * Helper method to get the set of origins.
+ */
+ private void getOriginsImpl() {
+ // Called on the WebKit thread.
+ mLock.lock();
+ mOrigins = nativeGetOrigins();
+ mUpdated = true;
+ mUpdatedCondition.signal();
+ mLock.unlock();
+ }
+
+ /**
+ * Gets the permission state for the specified origin.
+ */
+ public boolean getAllowed(String origin) {
+ // Called on the UI thread.
+ boolean allowed = false;
+ mLock.lock();
+ try {
+ mUpdated = false;
+ postMessage(Message.obtain(null, GET_ALLOWED, origin));
+ while (!mUpdated) {
+ mUpdatedCondition.await();
+ }
+ allowed = mAllowed;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Exception while waiting for update", e);
+ } finally {
+ mLock.unlock();
+ }
+ return allowed;
+ }
+
+ /**
+ * Helper method to get the permission state.
+ */
+ private void getAllowedImpl(String origin) {
+ // Called on the WebKit thread.
+ mLock.lock();
+ mAllowed = nativeGetAllowed(origin);
+ mUpdated = true;
+ mUpdatedCondition.signal();
+ mLock.unlock();
+ }
+
+ /**
+ * Clears the permission state for the specified origin. This method may be
+ * called before the WebKit thread has intialized the message handler.
+ * Messages will be queued until this time.
+ */
+ public void clear(String origin) {
+ // Called on the UI thread.
+ mLock.lock();
+ if (mHandler == null) {
+ if (mOriginsToClear == null) {
+ mOriginsToClear = new HashSet<String>();
+ }
+ mOriginsToClear.add(origin);
+ if (mOriginsToAllow != null) {
+ mOriginsToAllow.remove(origin);
+ }
+ } else {
+ postMessage(Message.obtain(null, CLEAR, origin));
+ }
+ mLock.unlock();
+ }
+
+ /**
+ * Allows the specified origin. This method may be called before the WebKit
+ * thread has intialized the message handler. Messages will be queued until
+ * this time.
+ */
+ public void allow(String origin) {
+ // Called on the UI thread.
+ mLock.lock();
+ if (mHandler == null) {
+ if (mOriginsToAllow == null) {
+ mOriginsToAllow = new HashSet<String>();
+ }
+ mOriginsToAllow.add(origin);
+ if (mOriginsToClear != null) {
+ mOriginsToClear.remove(origin);
+ }
+ } else {
+ postMessage(Message.obtain(null, ALLOW, origin));
+ }
+ mLock.unlock();
+ }
+
+ /**
+ * Clears the permission state for all origins.
+ */
+ public void clearAll() {
+ // Called on the UI thread.
+ postMessage(Message.obtain(null, CLEAR_ALL));
+ }
+
+ // Native functions, run on the WebKit thread.
+ private static native Set nativeGetOrigins();
+ private static native boolean nativeGetAllowed(String origin);
+ private static native void nativeClear(String origin);
+ private static native void nativeAllow(String origin);
+ private static native void nativeClearAll();
+}
diff --git a/core/java/android/webkit/GeolocationService.java b/core/java/android/webkit/GeolocationService.java
new file mode 100755
index 0000000..78b25ba
--- /dev/null
+++ b/core/java/android/webkit/GeolocationService.java
@@ -0,0 +1,189 @@
+/*
+ * 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.app.ActivityThread;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.os.Bundle;
+import android.util.Log;
+import android.webkit.WebView;
+import android.webkit.WebViewCore;
+
+
+/**
+ * Implements the Java side of GeolocationServiceAndroid.
+ * @hide Pending API council review.
+ */
+public final class GeolocationService implements LocationListener {
+
+ // Log tag
+ private static final String TAG = "geolocationService";
+
+ private long mNativeObject;
+ private LocationManager mLocationManager;
+ private boolean mIsGpsEnabled;
+ private boolean mIsRunning;
+ private boolean mIsNetworkProviderAvailable;
+ private boolean mIsGpsProviderAvailable;
+
+ /**
+ * Constructor
+ * @param nativeObject The native object to which this object will report position updates and
+ * errors.
+ */
+ public GeolocationService(long nativeObject) {
+ mNativeObject = nativeObject;
+ // Register newLocationAvailable with platform service.
+ ActivityThread thread = ActivityThread.systemMain();
+ Context context = thread.getApplication();
+ mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ if (mLocationManager == null) {
+ Log.e(TAG, "Could not get location manager.");
+ }
+ }
+
+ /**
+ * Start listening for location updates.
+ */
+ public void start() {
+ registerForLocationUpdates();
+ mIsRunning = true;
+ }
+
+ /**
+ * Stop listening for location updates.
+ */
+ public void stop() {
+ unregisterFromLocationUpdates();
+ mIsRunning = false;
+ }
+
+ /**
+ * Sets whether to use the GPS.
+ * @param enable Whether to use the GPS.
+ */
+ public void setEnableGps(boolean enable) {
+ if (mIsGpsEnabled != enable) {
+ mIsGpsEnabled = enable;
+ if (mIsRunning) {
+ // There's no way to unregister from a single provider, so we can
+ // only unregister from all, then reregister with all but the GPS.
+ unregisterFromLocationUpdates();
+ registerForLocationUpdates();
+ }
+ }
+ }
+
+ /**
+ * LocationListener implementation.
+ * Called when the location has changed.
+ * @param location The new location, as a Location object.
+ */
+ public void onLocationChanged(Location location) {
+ // Callbacks from the system location sevice are queued to this thread, so it's possible
+ // that we receive callbacks after unregistering. At this point, the native object will no
+ // longer exist.
+ if (mIsRunning) {
+ nativeNewLocationAvailable(mNativeObject, location);
+ }
+ }
+
+ /**
+ * LocationListener implementation.
+ * Called when the provider status changes.
+ * @param provider The name of the provider.
+ * @param status The new status of the provider.
+ * @param extras an optional Bundle with provider specific data.
+ */
+ public void onStatusChanged(String providerName, int status, Bundle extras) {
+ boolean isAvailable = (status == LocationProvider.AVAILABLE);
+ if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
+ mIsNetworkProviderAvailable = isAvailable;
+ } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
+ mIsGpsProviderAvailable = isAvailable;
+ }
+ maybeReportError("The last location provider is no longer available");
+ }
+
+ /**
+ * LocationListener implementation.
+ * Called when the provider is enabled.
+ * @param provider The name of the location provider that is now enabled.
+ */
+ public void onProviderEnabled(String providerName) {
+ // No need to notify the native side. It's enough to start sending
+ // valid position fixes again.
+ if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
+ mIsNetworkProviderAvailable = true;
+ } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
+ mIsGpsProviderAvailable = true;
+ }
+ }
+
+ /**
+ * LocationListener implementation.
+ * Called when the provider is disabled.
+ * @param provider The name of the location provider that is now disabled.
+ */
+ public void onProviderDisabled(String providerName) {
+ if (LocationManager.NETWORK_PROVIDER.equals(providerName)) {
+ mIsNetworkProviderAvailable = false;
+ } else if (LocationManager.GPS_PROVIDER.equals(providerName)) {
+ mIsGpsProviderAvailable = false;
+ }
+ maybeReportError("The last location provider was disabled");
+ }
+
+ /**
+ * Registers this object with the location service.
+ */
+ private void registerForLocationUpdates() {
+ mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
+ mIsNetworkProviderAvailable = true;
+ if (mIsGpsEnabled) {
+ mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
+ mIsGpsProviderAvailable = true;
+ }
+ }
+
+ /**
+ * Unregisters this object from the location service.
+ */
+ private void unregisterFromLocationUpdates() {
+ mLocationManager.removeUpdates(this);
+ }
+
+ /**
+ * Reports an error if neither the network nor the GPS provider is available.
+ */
+ private void maybeReportError(String message) {
+ // Callbacks from the system location sevice are queued to this thread, so it's possible
+ // that we receive callbacks after unregistering. At this point, the native object will no
+ // longer exist.
+ if (mIsRunning && !mIsNetworkProviderAvailable && !mIsGpsProviderAvailable) {
+ nativeNewErrorAvailable(mNativeObject, message);
+ }
+ }
+
+ // Native functions
+ private static native void nativeNewLocationAvailable(long nativeObject, Location location);
+ private static native void nativeNewErrorAvailable(long nativeObject, String message);
+}
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
new file mode 100644
index 0000000..5a164f8
--- /dev/null
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -0,0 +1,232 @@
+/*
+ * 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.content.Context;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.ViewManager.ChildView;
+import android.widget.AbsoluteLayout;
+import android.widget.MediaController;
+import android.widget.VideoView;
+
+import java.util.HashMap;
+
+/**
+ * <p>Proxy for HTML5 video views.
+ */
+class HTML5VideoViewProxy extends Handler {
+ // Logging tag.
+ private static final String LOGTAG = "HTML5VideoViewProxy";
+
+ // Message Ids for WebCore thread -> UI thread communication.
+ private static final int INIT = 100;
+ private static final int PLAY = 101;
+
+ // The WebView instance that created this view.
+ private WebView mWebView;
+ // The ChildView instance used by the ViewManager.
+ private ChildView mChildView;
+ // The VideoView instance. Note that we could
+ // also access this via mChildView.mView but it would
+ // always require cast, so it is more convenient to store
+ // it here as well.
+ private HTML5VideoView mVideoView;
+
+ // A VideoView subclass that responds to double-tap
+ // events by going fullscreen.
+ class HTML5VideoView extends VideoView {
+ // Used to save the layout parameters if the view
+ // is changed to fullscreen.
+ private AbsoluteLayout.LayoutParams mEmbeddedLayoutParams;
+ // Flag that denotes whether the view is fullscreen or not.
+ private boolean mIsFullscreen;
+ // Used to save the current playback position when
+ // transitioning to/from fullscreen.
+ private int mPlaybackPosition;
+ // The callback object passed to the host application. This callback
+ // is invoked when the host application dismisses our VideoView
+ // (e.g. the user presses the back key).
+ private WebChromeClient.CustomViewCallback mCallback =
+ new WebChromeClient.CustomViewCallback() {
+ public void onCustomViewHidden() {
+ playEmbedded();
+ }
+ };
+
+ // The OnPreparedListener, used to automatically resume
+ // playback when transitioning to/from fullscreen.
+ private MediaPlayer.OnPreparedListener mPreparedListener =
+ new MediaPlayer.OnPreparedListener() {
+ public void onPrepared(MediaPlayer mp) {
+ resumePlayback();
+ }
+ };
+
+ HTML5VideoView(Context context) {
+ super(context);
+ }
+
+ void savePlaybackPosition() {
+ if (isPlaying()) {
+ mPlaybackPosition = getCurrentPosition();
+ }
+ }
+
+ void resumePlayback() {
+ seekTo(mPlaybackPosition);
+ start();
+ setOnPreparedListener(null);
+ }
+
+ void playEmbedded() {
+ // Attach to the WebView.
+ mChildView.attachViewOnUIThread(mEmbeddedLayoutParams);
+ // Make sure we're visible
+ setVisibility(View.VISIBLE);
+ // Set the onPrepared listener so we start
+ // playing when the video view is reattached
+ // and its surface is recreated.
+ setOnPreparedListener(mPreparedListener);
+ mIsFullscreen = false;
+ }
+
+ void playFullScreen() {
+ WebChromeClient client = mWebView.getWebChromeClient();
+ if (client == null) {
+ return;
+ }
+ // Save the current layout params.
+ mEmbeddedLayoutParams =
+ (AbsoluteLayout.LayoutParams) getLayoutParams();
+ // Detach from the WebView.
+ mChildView.removeViewOnUIThread();
+ // Attach to the browser UI.
+ client.onShowCustomView(this, mCallback);
+ // Set the onPrepared listener so we start
+ // playing when after the video view is reattached
+ // and its surface is recreated.
+ setOnPreparedListener(mPreparedListener);
+ mIsFullscreen = true;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ // TODO: implement properly (i.e. detect double tap)
+ if (mIsFullscreen || !isPlaying()) {
+ return super.onTouchEvent(ev);
+ }
+ playFullScreen();
+ return true;
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ savePlaybackPosition();
+ }
+ }
+
+ /**
+ * Private constructor.
+ * @param context is the application context.
+ */
+ private HTML5VideoViewProxy(WebView webView) {
+ // This handler is for the main (UI) thread.
+ super(Looper.getMainLooper());
+ // Save the WebView object.
+ mWebView = webView;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ // This executes on the UI thread.
+ switch (msg.what) {
+ case INIT:
+ // Create the video view and set a default controller.
+ mVideoView = new HTML5VideoView(mWebView.getContext());
+ // This is needed because otherwise there will be a black square
+ // stuck on the screen.
+ mVideoView.setWillNotDraw(false);
+ mVideoView.setMediaController(new MediaController(mWebView.getContext()));
+ mChildView.mView = mVideoView;
+ break;
+ case PLAY:
+ if (mVideoView == null) {
+ return;
+ }
+ HashMap<String, Object> map =
+ (HashMap<String, Object>) msg.obj;
+ String url = (String) map.get("url");
+ mVideoView.setVideoURI(Uri.parse(url));
+ mVideoView.start();
+ break;
+ }
+ }
+
+ /**
+ * Play a video stream.
+ * @param url is the URL of the video stream.
+ * @param webview is the WebViewCore that is requesting the playback.
+ */
+ public void play(String url) {
+ // We need to know the webview that is requesting the playback.
+ Message message = obtainMessage(PLAY);
+ HashMap<String, Object> map = new HashMap();
+ map.put("url", url);
+ message.obj = map;
+ sendMessage(message);
+ }
+
+ public void createView() {
+ mChildView = mWebView.mViewManager.createView();
+ sendMessage(obtainMessage(INIT));
+ }
+
+ public void attachView(int x, int y, int width, int height) {
+ if (mChildView == null) {
+ return;
+ }
+ mChildView.attachView(x, y, width, height);
+ }
+
+ public void removeView() {
+ if (mChildView == null) {
+ return;
+ }
+ mChildView.removeView();
+ }
+
+ /**
+ * The factory for HTML5VideoViewProxy instances.
+ * @param webViewCore is the WebViewCore that is requesting the proxy.
+ *
+ * @return a new HTML5VideoViewProxy object.
+ */
+ public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore) {
+ return new HTML5VideoViewProxy(webViewCore.getWebView());
+ }
+}
diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java
index 84dc9f0..1c17575 100644
--- a/core/java/android/webkit/HttpAuthHandler.java
+++ b/core/java/android/webkit/HttpAuthHandler.java
@@ -49,8 +49,8 @@ public class HttpAuthHandler extends Handler {
// Message id for handling the user response
- private final int AUTH_PROCEED = 100;
- private final int AUTH_CANCEL = 200;
+ private static final int AUTH_PROCEED = 100;
+ private static final int AUTH_CANCEL = 200;
/**
* Creates a new HTTP authentication handler with an empty
diff --git a/core/java/android/webkit/HttpDateTime.java b/core/java/android/webkit/HttpDateTime.java
index c6ec2d2..00b2731 100644
--- a/core/java/android/webkit/HttpDateTime.java
+++ b/core/java/android/webkit/HttpDateTime.java
@@ -23,7 +23,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
-class HttpDateTime {
+/** {@hide} */
+public final class HttpDateTime {
/*
* Regular expression for parsing HTTP-date.
@@ -47,14 +48,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 +68,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 +85,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 +192,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 1dbd007..ddc2da1 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -34,9 +34,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.
@@ -51,6 +58,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.
*
@@ -60,16 +78,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)
+ .getPluginDirectories(), ((Boolean) msg.obj)
+ .booleanValue());
+ break;
}
}
@@ -86,7 +109,8 @@ final class JWebCoreJavaBridge extends Handler {
*/
public void pause() {
if (--mPauseTimerRefCount == 0) {
- setDeferringTimers(true);
+ mTimerPaused = true;
+ mHasDeferredTimers = false;
}
}
@@ -95,7 +119,11 @@ final class JWebCoreJavaBridge extends Handler {
*/
public void resume() {
if (++mPauseTimerRefCount == 1) {
- setDeferringTimers(false);
+ mTimerPaused = false;
+ if (mHasDeferredTimers) {
+ mHasDeferredTimers = false;
+ fireSharedTimer();
+ }
}
}
@@ -108,10 +136,9 @@ final class JWebCoreJavaBridge extends Handler {
/**
* Store a cookie string associated with a url.
* @param url The url to be used as a key for the cookie.
- * @param docUrl The policy base url used by WebCore.
* @param value The cookie string to be stored.
*/
- private void setCookies(String url, String docUrl, String value) {
+ private void setCookies(String url, String value) {
if (value.contains("\r") || value.contains("\n")) {
// for security reason, filter out '\r' and '\n' from the cookie
int size = value.length();
@@ -152,11 +179,25 @@ final class JWebCoreJavaBridge extends Handler {
}
/**
+ * Returns an array of plugin directoies
+ */
+ private String[] getPluginDirectories() {
+ return PluginManager.getInstance(null).getPluginDirectories();
+ }
+
+ /**
+ * Returns the path of the plugin data directory
+ */
+ private String getPluginSharedDataDirectory() {
+ return PluginManager.getInstance(null).getPluginSharedDataDirectory();
+ }
+
+ /**
* 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
@@ -180,11 +221,12 @@ 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 String[] getKeyStrengthList() {
@@ -199,6 +241,7 @@ final class JWebCoreJavaBridge extends Handler {
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 c3f3594..43c76a8 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";
@@ -101,6 +99,7 @@ class LoadListener extends Handler implements EventHandler {
private boolean mAuthFailed; // indicates that the prev. auth failed
private CacheLoader mCacheLoader;
private CacheManager.CacheResult mCacheResult;
+ private boolean mFromCache = false;
private HttpAuthHeader mAuthHeader;
private int mErrorID = OK;
private String mErrorDescription;
@@ -113,7 +112,6 @@ class LoadListener extends Handler implements EventHandler {
private String mMethod;
private Map<String, String> mRequestHeaders;
private byte[] mPostData;
- private boolean mIsHighPriority;
// Flag to indicate that this load is synchronous.
private boolean mSynchronous;
private Vector<Message> mMessageQueue;
@@ -142,15 +140,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>();
@@ -293,7 +289,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));
}
@@ -301,8 +297,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) {
@@ -322,8 +316,8 @@ 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")) {
// for attachment, use the filename in the Content-Disposition
// to guess the mimetype
@@ -339,17 +333,14 @@ class LoadListener extends Handler implements EventHandler {
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 {
@@ -419,11 +410,10 @@ class LoadListener extends Handler implements EventHandler {
mStatusCode == HTTP_MOVED_PERMANENTLY ||
mStatusCode == HTTP_TEMPORARY_REDIRECT) &&
mNativeLoader != 0) {
- // Content arriving from a StreamLoader (eg File, Cache or Data)
- // will not be cached as they have the header:
- // cache-control: no-store
- mCacheResult = CacheManager.createCacheFile(mUrl, mStatusCode,
- headers, mMimeType, false);
+ if (!mFromCache && URLUtil.isNetworkUrl(mUrl)) {
+ mCacheResult = CacheManager.createCacheFile(mUrl, mStatusCode,
+ headers, mMimeType, false);
+ }
if (mCacheResult != null) {
mCacheResult.encoding = mEncoding;
}
@@ -450,7 +440,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
@@ -464,6 +454,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));
}
@@ -507,7 +500,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);
}
@@ -535,23 +528,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.
@@ -573,7 +553,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));
@@ -626,7 +606,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;
@@ -646,6 +626,7 @@ class LoadListener extends Handler implements EventHandler {
* serviced by the Cache. */
/* package */ void setCacheLoader(CacheLoader c) {
mCacheLoader = c;
+ mFromCache = true;
}
/**
@@ -662,6 +643,8 @@ class LoadListener extends Handler implements EventHandler {
// Go ahead and set the cache loader to null in case the result is
// null.
mCacheLoader = null;
+ // reset the flag
+ mFromCache = false;
if (result != null) {
// The contents of the cache may need to be revalidated so just
@@ -676,12 +659,13 @@ 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());
}
// Load the cached file
mCacheLoader.load();
+ mFromCache = true;
return true;
}
}
@@ -695,12 +679,23 @@ class LoadListener extends Handler implements EventHandler {
* directly
*/
public boolean handleSslErrorRequest(SslError error) {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG,
"LoadListener.handleSslErrorRequest(): url:" + url() +
" primary error: " + error.getPrimaryError() +
" certificate: " + error.getCertificate());
}
+ // Check the cached preference table before sending a message. This
+ // will prevent waiting for an already available answer.
+ if (Network.getInstance(mContext).checkSslPrefTable(this, error)) {
+ return true;
+ }
+ // Do not post a message for a synchronous request. This will cause a
+ // deadlock. Just bail on the request.
+ if (isSynchronous()) {
+ mRequestHandle.handleSslErrorResponse(false);
+ return true;
+ }
sendMessageInternal(obtainMessage(MSG_SSL_ERROR, error));
// if it has been canceled, return false so that the network thread
// won't be blocked. If it is not canceled, save the mRequestHandle
@@ -773,7 +768,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);
@@ -823,14 +818,12 @@ class LoadListener extends Handler implements EventHandler {
* @param method
* @param headers
* @param postData
- * @param isHighPriority
*/
void setRequestData(String method, Map<String, String> headers,
- byte[] postData, boolean isHighPriority) {
+ byte[] postData) {
mMethod = method;
mRequestHeaders = headers;
mPostData = postData;
- mIsHighPriority = isHighPriority;
}
/**
@@ -870,7 +863,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);
}
@@ -878,7 +871,7 @@ class LoadListener extends Handler implements EventHandler {
}
void detachRequestHandle() {
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.detachRequestHandle(): " +
"requestHandle: " + mRequestHandle);
}
@@ -917,7 +910,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);
}
@@ -938,6 +931,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
@@ -992,8 +989,7 @@ class LoadListener extends Handler implements EventHandler {
// pass content-type content-length and content-encoding
final int nativeResponse = nativeCreateResponse(
mUrl, statusCode, mStatusText,
- mMimeType, mContentLength, mEncoding,
- mCacheResult == null ? 0 : mCacheResult.expires / 1000);
+ mMimeType, mContentLength, mEncoding);
if (mHeaders != null) {
mHeaders.getHeaders(new Headers.HeaderCallback() {
public void header(String name, String value) {
@@ -1115,7 +1111,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 {
@@ -1221,7 +1217,7 @@ class LoadListener extends Handler implements EventHandler {
// Network.requestURL.
Network network = Network.getInstance(getContext());
if (!network.requestURL(mMethod, mRequestHeaders,
- mPostData, this, mIsHighPriority)) {
+ mPostData, this)) {
// Signal a bad url error if we could not load the
// redirection.
handleError(EventHandler.ERROR_BAD_URL,
@@ -1247,7 +1243,7 @@ class LoadListener extends Handler implements EventHandler {
tearDown();
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener.onRedirect(): redirect to: " +
redirectTo);
}
@@ -1260,8 +1256,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);
}
@@ -1282,13 +1278,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;
@@ -1308,6 +1305,8 @@ class LoadListener extends Handler implements EventHandler {
guessMimeType();
}
}
+ // Ensure mMimeType is lower case.
+ mMimeType = mMimeType.toLowerCase();
}
/**
@@ -1397,7 +1396,8 @@ class LoadListener extends Handler implements EventHandler {
*/
private boolean ignoreCallbacks() {
return (mCancelled || mAuthHeader != null ||
- (mStatusCode > 300 && mStatusCode < 400));
+ // Allow 305 (Use Proxy) to call through.
+ (mStatusCode > 300 && mStatusCode < 400 && mStatusCode != 305));
}
/**
@@ -1438,7 +1438,7 @@ class LoadListener extends Handler implements EventHandler {
mMimeType = "text/html";
String newMimeType = guessMimeTypeFromExtension(mUrl);
if (newMimeType != null) {
- mMimeType = newMimeType;
+ mMimeType = newMimeType;
}
}
}
@@ -1448,23 +1448,12 @@ class LoadListener extends Handler implements EventHandler {
*/
private String guessMimeTypeFromExtension(String url) {
// PENDING: need to normalize url
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "guessMimeTypeFromExtension: url = " + url);
}
- String mimeType =
- MimeTypeMap.getSingleton().getMimeTypeFromExtension(
- MimeTypeMap.getFileExtensionFromUrl(url));
-
- 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(url));
}
/**
@@ -1483,7 +1472,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,
@@ -1510,12 +1499,11 @@ class LoadListener extends Handler implements EventHandler {
* @param expectedLength An estimate of the content length or the length
* given by the server.
* @param encoding HTTP encoding.
- * @param expireTime HTTP expires converted to seconds since the epoch.
* @return The native response pointer.
*/
private native int nativeCreateResponse(String url, int statusCode,
String statusText, String mimeType, long expectedLength,
- String encoding, long expireTime);
+ String encoding);
/**
* Add a response header to the native object.
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index 9fdde61..a55dbc8 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -22,7 +22,7 @@ import java.util.regex.Pattern;
/**
* Two-way map that maps MIME-types to file extensions and vice versa.
*/
-public /* package */ class MimeTypeMap {
+public class MimeTypeMap {
/**
* Singleton MIME-type map instance:
@@ -39,7 +39,6 @@ public /* package */ class MimeTypeMap {
*/
private HashMap<String, String> mExtensionToMimeTypeMap;
-
/**
* Creates a new MIME-type map.
*/
@@ -50,7 +49,10 @@ public /* package */ class MimeTypeMap {
/**
* Returns the file extension or an empty string iff there is no
- * extension.
+ * extension. This method is a convenience method for obtaining the
+ * extension of a url and has undefined results for other Strings.
+ * @param url
+ * @return The file extension of the given url.
*/
public static String getFileExtensionFromUrl(String url) {
if (url != null && url.length() > 0) {
@@ -80,8 +82,7 @@ public /* package */ class MimeTypeMap {
* Load an entry into the map. This does not check if the item already
* exists, it trusts the caller!
*/
- private void loadEntry(String mimeType, String extension,
- boolean textType) {
+ private void loadEntry(String mimeType, String extension) {
//
// if we have an existing x --> y mapping, we do not want to
// override it with another mapping x --> ?
@@ -94,18 +95,12 @@ public /* package */ class MimeTypeMap {
mMimeTypeToExtensionMap.put(mimeType, extension);
}
- //
- // here, we don't want to map extensions to text MIME types;
- // otherwise, we will start replacing generic text/plain and
- // text/html with text MIME types that our platform does not
- // understand.
- //
- if (!textType) {
- mExtensionToMimeTypeMap.put(extension, mimeType);
- }
+ mExtensionToMimeTypeMap.put(extension, mimeType);
}
/**
+ * Return true if the given MIME type has an entry in the map.
+ * @param mimeType A MIME type (i.e. text/plain)
* @return True iff there is a mimeType entry in the map.
*/
public boolean hasMimeType(String mimeType) {
@@ -117,7 +112,9 @@ public /* package */ class MimeTypeMap {
}
/**
- * @return The extension for the MIME type or null iff there is none.
+ * Return the MIME type for the given extension.
+ * @param extension A file extension without the leading '.'
+ * @return The MIME type for the given extension or null iff there is none.
*/
public String getMimeTypeFromExtension(String extension) {
if (extension != null && extension.length() > 0) {
@@ -128,18 +125,23 @@ public /* package */ class MimeTypeMap {
}
/**
+ * Return true if the given extension has a registered MIME type.
+ * @param extension A file extension without the leading '.'
* @return True iff there is an extension entry in the map.
*/
public boolean hasExtension(String extension) {
if (extension != null && extension.length() > 0) {
return mExtensionToMimeTypeMap.containsKey(extension);
}
-
return false;
}
/**
- * @return The MIME type for the extension or null iff there is none.
+ * Return the registered extension for the given MIME type. Note that some
+ * MIME types map to multiple extensions. This call will return the most
+ * common extension for the given MIME type.
+ * @param mimeType A MIME type (i.e. text/plain)
+ * @return The extension for the given MIME type or null iff there is none.
*/
public String getExtensionFromMimeType(String mimeType) {
if (mimeType != null && mimeType.length() > 0) {
@@ -150,6 +152,7 @@ public /* package */ class MimeTypeMap {
}
/**
+ * Get the singleton instance of MimeTypeMap.
* @return The singleton instance of the MIME-type map.
*/
public static MimeTypeMap getSingleton() {
@@ -164,341 +167,312 @@ public /* package */ class MimeTypeMap {
// mail.google.com/a/google.com
//
// and "active" MIME types (due to potential security issues).
- //
- // Also, notice that not all data from this table is actually
- // added (see loadEntry method for more details).
- sMimeTypeMap.loadEntry("application/andrew-inset", "ez", false);
- sMimeTypeMap.loadEntry("application/dsptype", "tsp", false);
- sMimeTypeMap.loadEntry("application/futuresplash", "spl", false);
- sMimeTypeMap.loadEntry("application/hta", "hta", false);
- sMimeTypeMap.loadEntry("application/mac-binhex40", "hqx", false);
- sMimeTypeMap.loadEntry("application/mac-compactpro", "cpt", false);
- sMimeTypeMap.loadEntry("application/mathematica", "nb", false);
- sMimeTypeMap.loadEntry("application/msaccess", "mdb", false);
- sMimeTypeMap.loadEntry("application/oda", "oda", false);
- sMimeTypeMap.loadEntry("application/ogg", "ogg", false);
- sMimeTypeMap.loadEntry("application/pdf", "pdf", false);
- sMimeTypeMap.loadEntry("application/pgp-keys", "key", false);
- sMimeTypeMap.loadEntry("application/pgp-signature", "pgp", false);
- sMimeTypeMap.loadEntry("application/pics-rules", "prf", false);
- sMimeTypeMap.loadEntry("application/rar", "rar", false);
- sMimeTypeMap.loadEntry("application/rdf+xml", "rdf", false);
- sMimeTypeMap.loadEntry("application/rss+xml", "rss", false);
- sMimeTypeMap.loadEntry("application/zip", "zip", false);
+ sMimeTypeMap.loadEntry("application/andrew-inset", "ez");
+ sMimeTypeMap.loadEntry("application/dsptype", "tsp");
+ sMimeTypeMap.loadEntry("application/futuresplash", "spl");
+ sMimeTypeMap.loadEntry("application/hta", "hta");
+ sMimeTypeMap.loadEntry("application/mac-binhex40", "hqx");
+ sMimeTypeMap.loadEntry("application/mac-compactpro", "cpt");
+ sMimeTypeMap.loadEntry("application/mathematica", "nb");
+ sMimeTypeMap.loadEntry("application/msaccess", "mdb");
+ sMimeTypeMap.loadEntry("application/oda", "oda");
+ sMimeTypeMap.loadEntry("application/ogg", "ogg");
+ sMimeTypeMap.loadEntry("application/pdf", "pdf");
+ sMimeTypeMap.loadEntry("application/pgp-keys", "key");
+ sMimeTypeMap.loadEntry("application/pgp-signature", "pgp");
+ sMimeTypeMap.loadEntry("application/pics-rules", "prf");
+ sMimeTypeMap.loadEntry("application/rar", "rar");
+ sMimeTypeMap.loadEntry("application/rdf+xml", "rdf");
+ sMimeTypeMap.loadEntry("application/rss+xml", "rss");
+ sMimeTypeMap.loadEntry("application/zip", "zip");
sMimeTypeMap.loadEntry("application/vnd.android.package-archive",
- "apk", false);
- sMimeTypeMap.loadEntry("application/vnd.cinderella", "cdy", false);
- sMimeTypeMap.loadEntry("application/vnd.ms-pki.stl", "stl", false);
+ "apk");
+ sMimeTypeMap.loadEntry("application/vnd.cinderella", "cdy");
+ sMimeTypeMap.loadEntry("application/vnd.ms-pki.stl", "stl");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.database", "odb",
- false);
+ "application/vnd.oasis.opendocument.database", "odb");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.formula", "odf",
- false);
+ "application/vnd.oasis.opendocument.formula", "odf");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.graphics", "odg",
- false);
+ "application/vnd.oasis.opendocument.graphics", "odg");
sMimeTypeMap.loadEntry(
"application/vnd.oasis.opendocument.graphics-template",
- "otg", false);
+ "otg");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.image", "odi", false);
+ "application/vnd.oasis.opendocument.image", "odi");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.spreadsheet", "ods",
- false);
+ "application/vnd.oasis.opendocument.spreadsheet", "ods");
sMimeTypeMap.loadEntry(
"application/vnd.oasis.opendocument.spreadsheet-template",
- "ots", false);
- sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text", "odt", false);
+ "ots");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text-master", "odm",
- false);
+ "application/vnd.oasis.opendocument.text", "odt");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text-template", "ott",
- false);
+ "application/vnd.oasis.opendocument.text-master", "odm");
sMimeTypeMap.loadEntry(
- "application/vnd.oasis.opendocument.text-web", "oth",
- false);
- sMimeTypeMap.loadEntry("application/vnd.rim.cod", "cod", false);
- sMimeTypeMap.loadEntry("application/vnd.smaf", "mmf", false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.calc", "sdc",
- false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.draw", "sda",
- false);
+ "application/vnd.oasis.opendocument.text-template", "ott");
sMimeTypeMap.loadEntry(
- "application/vnd.stardivision.impress", "sdd", false);
+ "application/vnd.oasis.opendocument.text-web", "oth");
+ sMimeTypeMap.loadEntry("application/vnd.rim.cod", "cod");
+ sMimeTypeMap.loadEntry("application/vnd.smaf", "mmf");
+ sMimeTypeMap.loadEntry("application/vnd.stardivision.calc", "sdc");
+ sMimeTypeMap.loadEntry("application/vnd.stardivision.draw", "sda");
sMimeTypeMap.loadEntry(
- "application/vnd.stardivision.impress", "sdp", false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.math", "smf",
- false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.writer", "sdw",
- false);
- sMimeTypeMap.loadEntry("application/vnd.stardivision.writer", "vor",
- false);
+ "application/vnd.stardivision.impress", "sdd");
sMimeTypeMap.loadEntry(
- "application/vnd.stardivision.writer-global", "sgl", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.calc", "sxc",
- false);
+ "application/vnd.stardivision.impress", "sdp");
+ sMimeTypeMap.loadEntry("application/vnd.stardivision.math", "smf");
+ sMimeTypeMap.loadEntry("application/vnd.stardivision.writer",
+ "sdw");
+ sMimeTypeMap.loadEntry("application/vnd.stardivision.writer",
+ "vor");
sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.calc.template", "stc", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.draw", "sxd",
- false);
+ "application/vnd.stardivision.writer-global", "sgl");
+ sMimeTypeMap.loadEntry("application/vnd.sun.xml.calc", "sxc");
sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.draw.template", "std", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.impress", "sxi",
- false);
+ "application/vnd.sun.xml.calc.template", "stc");
+ sMimeTypeMap.loadEntry("application/vnd.sun.xml.draw", "sxd");
sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.impress.template", "sti", false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.math", "sxm",
- false);
- sMimeTypeMap.loadEntry("application/vnd.sun.xml.writer", "sxw",
- false);
+ "application/vnd.sun.xml.draw.template", "std");
+ sMimeTypeMap.loadEntry("application/vnd.sun.xml.impress", "sxi");
sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.writer.global", "sxg", false);
+ "application/vnd.sun.xml.impress.template", "sti");
+ sMimeTypeMap.loadEntry("application/vnd.sun.xml.math", "sxm");
+ sMimeTypeMap.loadEntry("application/vnd.sun.xml.writer", "sxw");
sMimeTypeMap.loadEntry(
- "application/vnd.sun.xml.writer.template", "stw", false);
- sMimeTypeMap.loadEntry("application/vnd.visio", "vsd", false);
- sMimeTypeMap.loadEntry("application/x-abiword", "abw", false);
- sMimeTypeMap.loadEntry("application/x-apple-diskimage", "dmg",
- false);
- sMimeTypeMap.loadEntry("application/x-bcpio", "bcpio", false);
- sMimeTypeMap.loadEntry("application/x-bittorrent", "torrent",
- false);
- sMimeTypeMap.loadEntry("application/x-cdf", "cdf", false);
- sMimeTypeMap.loadEntry("application/x-cdlink", "vcd", false);
- sMimeTypeMap.loadEntry("application/x-chess-pgn", "pgn", false);
- sMimeTypeMap.loadEntry("application/x-cpio", "cpio", false);
- sMimeTypeMap.loadEntry("application/x-debian-package", "deb",
- false);
- sMimeTypeMap.loadEntry("application/x-debian-package", "udeb",
- false);
- sMimeTypeMap.loadEntry("application/x-director", "dcr", false);
- sMimeTypeMap.loadEntry("application/x-director", "dir", false);
- sMimeTypeMap.loadEntry("application/x-director", "dxr", false);
- sMimeTypeMap.loadEntry("application/x-dms", "dms", false);
- sMimeTypeMap.loadEntry("application/x-doom", "wad", false);
- sMimeTypeMap.loadEntry("application/x-dvi", "dvi", false);
- sMimeTypeMap.loadEntry("application/x-flac", "flac", false);
- sMimeTypeMap.loadEntry("application/x-font", "pfa", false);
- sMimeTypeMap.loadEntry("application/x-font", "pfb", false);
- sMimeTypeMap.loadEntry("application/x-font", "gsf", false);
- sMimeTypeMap.loadEntry("application/x-font", "pcf", false);
- sMimeTypeMap.loadEntry("application/x-font", "pcf.Z", false);
- sMimeTypeMap.loadEntry("application/x-freemind", "mm", false);
- sMimeTypeMap.loadEntry("application/x-futuresplash", "spl", false);
- sMimeTypeMap.loadEntry("application/x-gnumeric", "gnumeric", false);
- sMimeTypeMap.loadEntry("application/x-go-sgf", "sgf", false);
- sMimeTypeMap.loadEntry("application/x-graphing-calculator", "gcf",
- false);
- sMimeTypeMap.loadEntry("application/x-gtar", "gtar", false);
- sMimeTypeMap.loadEntry("application/x-gtar", "tgz", false);
- sMimeTypeMap.loadEntry("application/x-gtar", "taz", false);
- sMimeTypeMap.loadEntry("application/x-hdf", "hdf", false);
- sMimeTypeMap.loadEntry("application/x-ica", "ica", false);
- sMimeTypeMap.loadEntry("application/x-internet-signup", "ins",
- false);
- sMimeTypeMap.loadEntry("application/x-internet-signup", "isp",
- false);
- sMimeTypeMap.loadEntry("application/x-iphone", "iii", false);
- sMimeTypeMap.loadEntry("application/x-iso9660-image", "iso", false);
- sMimeTypeMap.loadEntry("application/x-jmol", "jmz", false);
- sMimeTypeMap.loadEntry("application/x-kchart", "chrt", false);
- sMimeTypeMap.loadEntry("application/x-killustrator", "kil", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skp", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skd", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skt", false);
- sMimeTypeMap.loadEntry("application/x-koan", "skm", false);
- sMimeTypeMap.loadEntry("application/x-kpresenter", "kpr", false);
- sMimeTypeMap.loadEntry("application/x-kpresenter", "kpt", false);
- sMimeTypeMap.loadEntry("application/x-kspread", "ksp", false);
- sMimeTypeMap.loadEntry("application/x-kword", "kwd", false);
- sMimeTypeMap.loadEntry("application/x-kword", "kwt", false);
- sMimeTypeMap.loadEntry("application/x-latex", "latex", false);
- sMimeTypeMap.loadEntry("application/x-lha", "lha", false);
- sMimeTypeMap.loadEntry("application/x-lzh", "lzh", false);
- sMimeTypeMap.loadEntry("application/x-lzx", "lzx", false);
- sMimeTypeMap.loadEntry("application/x-maker", "frm", false);
- sMimeTypeMap.loadEntry("application/x-maker", "maker", false);
- sMimeTypeMap.loadEntry("application/x-maker", "frame", false);
- sMimeTypeMap.loadEntry("application/x-maker", "fb", false);
- sMimeTypeMap.loadEntry("application/x-maker", "book", false);
- sMimeTypeMap.loadEntry("application/x-maker", "fbdoc", false);
- sMimeTypeMap.loadEntry("application/x-mif", "mif", false);
- sMimeTypeMap.loadEntry("application/x-ms-wmd", "wmd", false);
- sMimeTypeMap.loadEntry("application/x-ms-wmz", "wmz", false);
- sMimeTypeMap.loadEntry("application/x-msi", "msi", false);
- sMimeTypeMap.loadEntry("application/x-ns-proxy-autoconfig", "pac",
- false);
- sMimeTypeMap.loadEntry("application/x-nwc", "nwc", false);
- sMimeTypeMap.loadEntry("application/x-object", "o", false);
- sMimeTypeMap.loadEntry("application/x-oz-application", "oza",
- false);
- sMimeTypeMap.loadEntry("application/x-pkcs12", "p12", false);
- sMimeTypeMap.loadEntry("application/x-pkcs7-certreqresp", "p7r",
- false);
- sMimeTypeMap.loadEntry("application/x-pkcs7-crl", "crl", false);
- sMimeTypeMap.loadEntry("application/x-quicktimeplayer", "qtl",
- false);
- sMimeTypeMap.loadEntry("application/x-shar", "shar", false);
- sMimeTypeMap.loadEntry("application/x-stuffit", "sit", false);
- sMimeTypeMap.loadEntry("application/x-sv4cpio", "sv4cpio", false);
- sMimeTypeMap.loadEntry("application/x-sv4crc", "sv4crc", false);
- sMimeTypeMap.loadEntry("application/x-tar", "tar", false);
- sMimeTypeMap.loadEntry("application/x-texinfo", "texinfo", false);
- sMimeTypeMap.loadEntry("application/x-texinfo", "texi", false);
- sMimeTypeMap.loadEntry("application/x-troff", "t", false);
- sMimeTypeMap.loadEntry("application/x-troff", "roff", false);
- sMimeTypeMap.loadEntry("application/x-troff-man", "man", false);
- sMimeTypeMap.loadEntry("application/x-ustar", "ustar", false);
- sMimeTypeMap.loadEntry("application/x-wais-source", "src", false);
- sMimeTypeMap.loadEntry("application/x-wingz", "wz", false);
+ "application/vnd.sun.xml.writer.global", "sxg");
sMimeTypeMap.loadEntry(
- "application/x-webarchive", "webarchive", false); // added
- sMimeTypeMap.loadEntry("application/x-x509-ca-cert", "crt", false);
- sMimeTypeMap.loadEntry("application/x-x509-user-cert", "crt", false);
- sMimeTypeMap.loadEntry("application/x-xcf", "xcf", false);
- sMimeTypeMap.loadEntry("application/x-xfig", "fig", false);
- sMimeTypeMap.loadEntry("audio/basic", "snd", false);
- sMimeTypeMap.loadEntry("audio/midi", "mid", false);
- sMimeTypeMap.loadEntry("audio/midi", "midi", false);
- sMimeTypeMap.loadEntry("audio/midi", "kar", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mpga", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mpega", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mp2", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "mp3", false);
- sMimeTypeMap.loadEntry("audio/mpeg", "m4a", false);
- sMimeTypeMap.loadEntry("audio/mpegurl", "m3u", false);
- sMimeTypeMap.loadEntry("audio/prs.sid", "sid", false);
- sMimeTypeMap.loadEntry("audio/x-aiff", "aif", false);
- sMimeTypeMap.loadEntry("audio/x-aiff", "aiff", false);
- sMimeTypeMap.loadEntry("audio/x-aiff", "aifc", false);
- sMimeTypeMap.loadEntry("audio/x-gsm", "gsm", false);
- sMimeTypeMap.loadEntry("audio/x-mpegurl", "m3u", false);
- sMimeTypeMap.loadEntry("audio/x-ms-wma", "wma", false);
- sMimeTypeMap.loadEntry("audio/x-ms-wax", "wax", false);
- sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "ra", false);
- sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "rm", false);
- sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "ram", false);
- sMimeTypeMap.loadEntry("audio/x-realaudio", "ra", false);
- sMimeTypeMap.loadEntry("audio/x-scpls", "pls", false);
- sMimeTypeMap.loadEntry("audio/x-sd2", "sd2", false);
- sMimeTypeMap.loadEntry("audio/x-wav", "wav", false);
- sMimeTypeMap.loadEntry("image/bmp", "bmp", false); // added
- sMimeTypeMap.loadEntry("image/gif", "gif", false);
- sMimeTypeMap.loadEntry("image/ico", "cur", false); // added
- sMimeTypeMap.loadEntry("image/ico", "ico", false); // added
- sMimeTypeMap.loadEntry("image/ief", "ief", false);
- sMimeTypeMap.loadEntry("image/jpeg", "jpeg", false);
- sMimeTypeMap.loadEntry("image/jpeg", "jpg", false);
- sMimeTypeMap.loadEntry("image/jpeg", "jpe", false);
- sMimeTypeMap.loadEntry("image/pcx", "pcx", false);
- sMimeTypeMap.loadEntry("image/png", "png", false);
- sMimeTypeMap.loadEntry("image/svg+xml", "svg", false);
- sMimeTypeMap.loadEntry("image/svg+xml", "svgz", false);
- sMimeTypeMap.loadEntry("image/tiff", "tiff", false);
- sMimeTypeMap.loadEntry("image/tiff", "tif", false);
- sMimeTypeMap.loadEntry("image/vnd.djvu", "djvu", false);
- sMimeTypeMap.loadEntry("image/vnd.djvu", "djv", false);
- sMimeTypeMap.loadEntry("image/vnd.wap.wbmp", "wbmp", false);
- sMimeTypeMap.loadEntry("image/x-cmu-raster", "ras", false);
- sMimeTypeMap.loadEntry("image/x-coreldraw", "cdr", false);
- sMimeTypeMap.loadEntry("image/x-coreldrawpattern", "pat", false);
- sMimeTypeMap.loadEntry("image/x-coreldrawtemplate", "cdt", false);
- sMimeTypeMap.loadEntry("image/x-corelphotopaint", "cpt", false);
- sMimeTypeMap.loadEntry("image/x-icon", "ico", false);
- sMimeTypeMap.loadEntry("image/x-jg", "art", false);
- sMimeTypeMap.loadEntry("image/x-jng", "jng", false);
- sMimeTypeMap.loadEntry("image/x-ms-bmp", "bmp", false);
- sMimeTypeMap.loadEntry("image/x-photoshop", "psd", false);
- sMimeTypeMap.loadEntry("image/x-portable-anymap", "pnm", false);
- sMimeTypeMap.loadEntry("image/x-portable-bitmap", "pbm", false);
- sMimeTypeMap.loadEntry("image/x-portable-graymap", "pgm", false);
- sMimeTypeMap.loadEntry("image/x-portable-pixmap", "ppm", false);
- sMimeTypeMap.loadEntry("image/x-rgb", "rgb", false);
- sMimeTypeMap.loadEntry("image/x-xbitmap", "xbm", false);
- sMimeTypeMap.loadEntry("image/x-xpixmap", "xpm", false);
- sMimeTypeMap.loadEntry("image/x-xwindowdump", "xwd", false);
- sMimeTypeMap.loadEntry("model/iges", "igs", false);
- sMimeTypeMap.loadEntry("model/iges", "iges", false);
- sMimeTypeMap.loadEntry("model/mesh", "msh", false);
- sMimeTypeMap.loadEntry("model/mesh", "mesh", false);
- sMimeTypeMap.loadEntry("model/mesh", "silo", false);
- sMimeTypeMap.loadEntry("text/calendar", "ics", true);
- sMimeTypeMap.loadEntry("text/calendar", "icz", true);
- sMimeTypeMap.loadEntry("text/comma-separated-values", "csv", true);
- sMimeTypeMap.loadEntry("text/css", "css", true);
- sMimeTypeMap.loadEntry("text/h323", "323", true);
- sMimeTypeMap.loadEntry("text/iuls", "uls", true);
- sMimeTypeMap.loadEntry("text/mathml", "mml", true);
+ "application/vnd.sun.xml.writer.template", "stw");
+ sMimeTypeMap.loadEntry("application/vnd.visio", "vsd");
+ sMimeTypeMap.loadEntry("application/x-abiword", "abw");
+ sMimeTypeMap.loadEntry("application/x-apple-diskimage", "dmg");
+ sMimeTypeMap.loadEntry("application/x-bcpio", "bcpio");
+ sMimeTypeMap.loadEntry("application/x-bittorrent", "torrent");
+ sMimeTypeMap.loadEntry("application/x-cdf", "cdf");
+ sMimeTypeMap.loadEntry("application/x-cdlink", "vcd");
+ sMimeTypeMap.loadEntry("application/x-chess-pgn", "pgn");
+ sMimeTypeMap.loadEntry("application/x-cpio", "cpio");
+ sMimeTypeMap.loadEntry("application/x-debian-package", "deb");
+ sMimeTypeMap.loadEntry("application/x-debian-package", "udeb");
+ sMimeTypeMap.loadEntry("application/x-director", "dcr");
+ sMimeTypeMap.loadEntry("application/x-director", "dir");
+ sMimeTypeMap.loadEntry("application/x-director", "dxr");
+ sMimeTypeMap.loadEntry("application/x-dms", "dms");
+ sMimeTypeMap.loadEntry("application/x-doom", "wad");
+ sMimeTypeMap.loadEntry("application/x-dvi", "dvi");
+ sMimeTypeMap.loadEntry("application/x-flac", "flac");
+ sMimeTypeMap.loadEntry("application/x-font", "pfa");
+ sMimeTypeMap.loadEntry("application/x-font", "pfb");
+ sMimeTypeMap.loadEntry("application/x-font", "gsf");
+ sMimeTypeMap.loadEntry("application/x-font", "pcf");
+ sMimeTypeMap.loadEntry("application/x-font", "pcf.Z");
+ sMimeTypeMap.loadEntry("application/x-freemind", "mm");
+ sMimeTypeMap.loadEntry("application/x-futuresplash", "spl");
+ sMimeTypeMap.loadEntry("application/x-gnumeric", "gnumeric");
+ sMimeTypeMap.loadEntry("application/x-go-sgf", "sgf");
+ sMimeTypeMap.loadEntry("application/x-graphing-calculator", "gcf");
+ sMimeTypeMap.loadEntry("application/x-gtar", "gtar");
+ sMimeTypeMap.loadEntry("application/x-gtar", "tgz");
+ sMimeTypeMap.loadEntry("application/x-gtar", "taz");
+ sMimeTypeMap.loadEntry("application/x-hdf", "hdf");
+ sMimeTypeMap.loadEntry("application/x-ica", "ica");
+ sMimeTypeMap.loadEntry("application/x-internet-signup", "ins");
+ sMimeTypeMap.loadEntry("application/x-internet-signup", "isp");
+ sMimeTypeMap.loadEntry("application/x-iphone", "iii");
+ sMimeTypeMap.loadEntry("application/x-iso9660-image", "iso");
+ sMimeTypeMap.loadEntry("application/x-jmol", "jmz");
+ sMimeTypeMap.loadEntry("application/x-kchart", "chrt");
+ sMimeTypeMap.loadEntry("application/x-killustrator", "kil");
+ sMimeTypeMap.loadEntry("application/x-koan", "skp");
+ sMimeTypeMap.loadEntry("application/x-koan", "skd");
+ sMimeTypeMap.loadEntry("application/x-koan", "skt");
+ sMimeTypeMap.loadEntry("application/x-koan", "skm");
+ sMimeTypeMap.loadEntry("application/x-kpresenter", "kpr");
+ sMimeTypeMap.loadEntry("application/x-kpresenter", "kpt");
+ sMimeTypeMap.loadEntry("application/x-kspread", "ksp");
+ sMimeTypeMap.loadEntry("application/x-kword", "kwd");
+ sMimeTypeMap.loadEntry("application/x-kword", "kwt");
+ sMimeTypeMap.loadEntry("application/x-latex", "latex");
+ sMimeTypeMap.loadEntry("application/x-lha", "lha");
+ sMimeTypeMap.loadEntry("application/x-lzh", "lzh");
+ sMimeTypeMap.loadEntry("application/x-lzx", "lzx");
+ sMimeTypeMap.loadEntry("application/x-maker", "frm");
+ sMimeTypeMap.loadEntry("application/x-maker", "maker");
+ sMimeTypeMap.loadEntry("application/x-maker", "frame");
+ sMimeTypeMap.loadEntry("application/x-maker", "fb");
+ sMimeTypeMap.loadEntry("application/x-maker", "book");
+ sMimeTypeMap.loadEntry("application/x-maker", "fbdoc");
+ sMimeTypeMap.loadEntry("application/x-mif", "mif");
+ sMimeTypeMap.loadEntry("application/x-ms-wmd", "wmd");
+ sMimeTypeMap.loadEntry("application/x-ms-wmz", "wmz");
+ sMimeTypeMap.loadEntry("application/x-msi", "msi");
+ sMimeTypeMap.loadEntry("application/x-ns-proxy-autoconfig", "pac");
+ sMimeTypeMap.loadEntry("application/x-nwc", "nwc");
+ sMimeTypeMap.loadEntry("application/x-object", "o");
+ sMimeTypeMap.loadEntry("application/x-oz-application", "oza");
+ sMimeTypeMap.loadEntry("application/x-pkcs12", "p12");
+ sMimeTypeMap.loadEntry("application/x-pkcs7-certreqresp", "p7r");
+ sMimeTypeMap.loadEntry("application/x-pkcs7-crl", "crl");
+ sMimeTypeMap.loadEntry("application/x-quicktimeplayer", "qtl");
+ sMimeTypeMap.loadEntry("application/x-shar", "shar");
+ sMimeTypeMap.loadEntry("application/x-stuffit", "sit");
+ sMimeTypeMap.loadEntry("application/x-sv4cpio", "sv4cpio");
+ sMimeTypeMap.loadEntry("application/x-sv4crc", "sv4crc");
+ sMimeTypeMap.loadEntry("application/x-tar", "tar");
+ sMimeTypeMap.loadEntry("application/x-texinfo", "texinfo");
+ sMimeTypeMap.loadEntry("application/x-texinfo", "texi");
+ sMimeTypeMap.loadEntry("application/x-troff", "t");
+ sMimeTypeMap.loadEntry("application/x-troff", "roff");
+ sMimeTypeMap.loadEntry("application/x-troff-man", "man");
+ sMimeTypeMap.loadEntry("application/x-ustar", "ustar");
+ sMimeTypeMap.loadEntry("application/x-wais-source", "src");
+ sMimeTypeMap.loadEntry("application/x-wingz", "wz");
+ sMimeTypeMap.loadEntry("application/x-webarchive", "webarchive");
+ sMimeTypeMap.loadEntry("application/x-x509-ca-cert", "crt");
+ sMimeTypeMap.loadEntry("application/x-x509-user-cert", "crt");
+ sMimeTypeMap.loadEntry("application/x-xcf", "xcf");
+ sMimeTypeMap.loadEntry("application/x-xfig", "fig");
+ sMimeTypeMap.loadEntry("application/xhtml+xml", "xhtml");
+ sMimeTypeMap.loadEntry("audio/basic", "snd");
+ sMimeTypeMap.loadEntry("audio/midi", "mid");
+ sMimeTypeMap.loadEntry("audio/midi", "midi");
+ sMimeTypeMap.loadEntry("audio/midi", "kar");
+ sMimeTypeMap.loadEntry("audio/mpeg", "mpga");
+ sMimeTypeMap.loadEntry("audio/mpeg", "mpega");
+ sMimeTypeMap.loadEntry("audio/mpeg", "mp2");
+ sMimeTypeMap.loadEntry("audio/mpeg", "mp3");
+ sMimeTypeMap.loadEntry("audio/mpeg", "m4a");
+ sMimeTypeMap.loadEntry("audio/mpegurl", "m3u");
+ sMimeTypeMap.loadEntry("audio/prs.sid", "sid");
+ sMimeTypeMap.loadEntry("audio/x-aiff", "aif");
+ sMimeTypeMap.loadEntry("audio/x-aiff", "aiff");
+ sMimeTypeMap.loadEntry("audio/x-aiff", "aifc");
+ sMimeTypeMap.loadEntry("audio/x-gsm", "gsm");
+ sMimeTypeMap.loadEntry("audio/x-mpegurl", "m3u");
+ sMimeTypeMap.loadEntry("audio/x-ms-wma", "wma");
+ sMimeTypeMap.loadEntry("audio/x-ms-wax", "wax");
+ sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "ra");
+ sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "rm");
+ sMimeTypeMap.loadEntry("audio/x-pn-realaudio", "ram");
+ sMimeTypeMap.loadEntry("audio/x-realaudio", "ra");
+ sMimeTypeMap.loadEntry("audio/x-scpls", "pls");
+ sMimeTypeMap.loadEntry("audio/x-sd2", "sd2");
+ sMimeTypeMap.loadEntry("audio/x-wav", "wav");
+ sMimeTypeMap.loadEntry("image/bmp", "bmp");
+ sMimeTypeMap.loadEntry("image/gif", "gif");
+ sMimeTypeMap.loadEntry("image/ico", "cur");
+ sMimeTypeMap.loadEntry("image/ico", "ico");
+ sMimeTypeMap.loadEntry("image/ief", "ief");
+ sMimeTypeMap.loadEntry("image/jpeg", "jpeg");
+ sMimeTypeMap.loadEntry("image/jpeg", "jpg");
+ sMimeTypeMap.loadEntry("image/jpeg", "jpe");
+ sMimeTypeMap.loadEntry("image/pcx", "pcx");
+ sMimeTypeMap.loadEntry("image/png", "png");
+ sMimeTypeMap.loadEntry("image/svg+xml", "svg");
+ sMimeTypeMap.loadEntry("image/svg+xml", "svgz");
+ sMimeTypeMap.loadEntry("image/tiff", "tiff");
+ sMimeTypeMap.loadEntry("image/tiff", "tif");
+ sMimeTypeMap.loadEntry("image/vnd.djvu", "djvu");
+ sMimeTypeMap.loadEntry("image/vnd.djvu", "djv");
+ sMimeTypeMap.loadEntry("image/vnd.wap.wbmp", "wbmp");
+ sMimeTypeMap.loadEntry("image/x-cmu-raster", "ras");
+ sMimeTypeMap.loadEntry("image/x-coreldraw", "cdr");
+ sMimeTypeMap.loadEntry("image/x-coreldrawpattern", "pat");
+ sMimeTypeMap.loadEntry("image/x-coreldrawtemplate", "cdt");
+ sMimeTypeMap.loadEntry("image/x-corelphotopaint", "cpt");
+ sMimeTypeMap.loadEntry("image/x-icon", "ico");
+ sMimeTypeMap.loadEntry("image/x-jg", "art");
+ sMimeTypeMap.loadEntry("image/x-jng", "jng");
+ sMimeTypeMap.loadEntry("image/x-ms-bmp", "bmp");
+ sMimeTypeMap.loadEntry("image/x-photoshop", "psd");
+ sMimeTypeMap.loadEntry("image/x-portable-anymap", "pnm");
+ sMimeTypeMap.loadEntry("image/x-portable-bitmap", "pbm");
+ sMimeTypeMap.loadEntry("image/x-portable-graymap", "pgm");
+ sMimeTypeMap.loadEntry("image/x-portable-pixmap", "ppm");
+ sMimeTypeMap.loadEntry("image/x-rgb", "rgb");
+ sMimeTypeMap.loadEntry("image/x-xbitmap", "xbm");
+ sMimeTypeMap.loadEntry("image/x-xpixmap", "xpm");
+ sMimeTypeMap.loadEntry("image/x-xwindowdump", "xwd");
+ sMimeTypeMap.loadEntry("model/iges", "igs");
+ sMimeTypeMap.loadEntry("model/iges", "iges");
+ sMimeTypeMap.loadEntry("model/mesh", "msh");
+ sMimeTypeMap.loadEntry("model/mesh", "mesh");
+ sMimeTypeMap.loadEntry("model/mesh", "silo");
+ sMimeTypeMap.loadEntry("text/calendar", "ics");
+ sMimeTypeMap.loadEntry("text/calendar", "icz");
+ sMimeTypeMap.loadEntry("text/comma-separated-values", "csv");
+ sMimeTypeMap.loadEntry("text/css", "css");
+ sMimeTypeMap.loadEntry("text/h323", "323");
+ sMimeTypeMap.loadEntry("text/iuls", "uls");
+ sMimeTypeMap.loadEntry("text/mathml", "mml");
// add it first so it will be the default for ExtensionFromMimeType
- sMimeTypeMap.loadEntry("text/plain", "txt", true);
- sMimeTypeMap.loadEntry("text/plain", "asc", true);
- sMimeTypeMap.loadEntry("text/plain", "text", true);
- sMimeTypeMap.loadEntry("text/plain", "diff", true);
- sMimeTypeMap.loadEntry("text/plain", "pot", true);
- sMimeTypeMap.loadEntry("text/richtext", "rtx", true);
- sMimeTypeMap.loadEntry("text/rtf", "rtf", true);
- sMimeTypeMap.loadEntry("text/texmacs", "ts", true);
- sMimeTypeMap.loadEntry("text/text", "phps", true);
- sMimeTypeMap.loadEntry("text/tab-separated-values", "tsv", true);
- sMimeTypeMap.loadEntry("text/x-bibtex", "bib", true);
- sMimeTypeMap.loadEntry("text/x-boo", "boo", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "h++", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "hpp", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "hxx", true);
- sMimeTypeMap.loadEntry("text/x-c++hdr", "hh", true);
- sMimeTypeMap.loadEntry("text/x-c++src", "c++", true);
- sMimeTypeMap.loadEntry("text/x-c++src", "cpp", true);
- sMimeTypeMap.loadEntry("text/x-c++src", "cxx", true);
- sMimeTypeMap.loadEntry("text/x-chdr", "h", true);
- sMimeTypeMap.loadEntry("text/x-component", "htc", true);
- sMimeTypeMap.loadEntry("text/x-csh", "csh", true);
- sMimeTypeMap.loadEntry("text/x-csrc", "c", true);
- sMimeTypeMap.loadEntry("text/x-dsrc", "d", true);
- sMimeTypeMap.loadEntry("text/x-haskell", "hs", true);
- sMimeTypeMap.loadEntry("text/x-java", "java", true);
- sMimeTypeMap.loadEntry("text/x-literate-haskell", "lhs", true);
- sMimeTypeMap.loadEntry("text/x-moc", "moc", true);
- sMimeTypeMap.loadEntry("text/x-pascal", "p", true);
- sMimeTypeMap.loadEntry("text/x-pascal", "pas", true);
- sMimeTypeMap.loadEntry("text/x-pcs-gcd", "gcd", true);
- sMimeTypeMap.loadEntry("text/x-setext", "etx", true);
- sMimeTypeMap.loadEntry("text/x-tcl", "tcl", true);
- sMimeTypeMap.loadEntry("text/x-tex", "tex", true);
- sMimeTypeMap.loadEntry("text/x-tex", "ltx", true);
- sMimeTypeMap.loadEntry("text/x-tex", "sty", true);
- sMimeTypeMap.loadEntry("text/x-tex", "cls", true);
- sMimeTypeMap.loadEntry("text/x-vcalendar", "vcs", true);
- sMimeTypeMap.loadEntry("text/x-vcard", "vcf", true);
- sMimeTypeMap.loadEntry("video/3gpp", "3gp", false);
- sMimeTypeMap.loadEntry("video/3gpp", "3g2", false);
- sMimeTypeMap.loadEntry("video/dl", "dl", false);
- sMimeTypeMap.loadEntry("video/dv", "dif", false);
- sMimeTypeMap.loadEntry("video/dv", "dv", false);
- sMimeTypeMap.loadEntry("video/fli", "fli", false);
- sMimeTypeMap.loadEntry("video/mpeg", "mpeg", false);
- sMimeTypeMap.loadEntry("video/mpeg", "mpg", false);
- sMimeTypeMap.loadEntry("video/mpeg", "mpe", false);
- sMimeTypeMap.loadEntry("video/mp4", "mp4", false);
- sMimeTypeMap.loadEntry("video/mpeg", "VOB", false);
- sMimeTypeMap.loadEntry("video/quicktime", "qt", false);
- sMimeTypeMap.loadEntry("video/quicktime", "mov", false);
- sMimeTypeMap.loadEntry("video/vnd.mpegurl", "mxu", false);
- sMimeTypeMap.loadEntry("video/x-la-asf", "lsf", false);
- sMimeTypeMap.loadEntry("video/x-la-asf", "lsx", false);
- sMimeTypeMap.loadEntry("video/x-mng", "mng", false);
- sMimeTypeMap.loadEntry("video/x-ms-asf", "asf", false);
- sMimeTypeMap.loadEntry("video/x-ms-asf", "asx", false);
- sMimeTypeMap.loadEntry("video/x-ms-wm", "wm", false);
- sMimeTypeMap.loadEntry("video/x-ms-wmv", "wmv", false);
- sMimeTypeMap.loadEntry("video/x-ms-wmx", "wmx", false);
- sMimeTypeMap.loadEntry("video/x-ms-wvx", "wvx", false);
- sMimeTypeMap.loadEntry("video/x-msvideo", "avi", false);
- sMimeTypeMap.loadEntry("video/x-sgi-movie", "movie", false);
- sMimeTypeMap.loadEntry("x-conference/x-cooltalk", "ice", false);
- sMimeTypeMap.loadEntry("x-epoc/x-sisx-app", "sisx", false);
+ sMimeTypeMap.loadEntry("text/plain", "txt");
+ sMimeTypeMap.loadEntry("text/plain", "asc");
+ sMimeTypeMap.loadEntry("text/plain", "text");
+ sMimeTypeMap.loadEntry("text/plain", "diff");
+ sMimeTypeMap.loadEntry("text/plain", "pot");
+ sMimeTypeMap.loadEntry("text/richtext", "rtx");
+ sMimeTypeMap.loadEntry("text/rtf", "rtf");
+ sMimeTypeMap.loadEntry("text/texmacs", "ts");
+ sMimeTypeMap.loadEntry("text/text", "phps");
+ sMimeTypeMap.loadEntry("text/tab-separated-values", "tsv");
+ sMimeTypeMap.loadEntry("text/x-bibtex", "bib");
+ sMimeTypeMap.loadEntry("text/x-boo", "boo");
+ sMimeTypeMap.loadEntry("text/x-c++hdr", "h++");
+ sMimeTypeMap.loadEntry("text/x-c++hdr", "hpp");
+ sMimeTypeMap.loadEntry("text/x-c++hdr", "hxx");
+ sMimeTypeMap.loadEntry("text/x-c++hdr", "hh");
+ sMimeTypeMap.loadEntry("text/x-c++src", "c++");
+ sMimeTypeMap.loadEntry("text/x-c++src", "cpp");
+ sMimeTypeMap.loadEntry("text/x-c++src", "cxx");
+ sMimeTypeMap.loadEntry("text/x-chdr", "h");
+ sMimeTypeMap.loadEntry("text/x-component", "htc");
+ sMimeTypeMap.loadEntry("text/x-csh", "csh");
+ sMimeTypeMap.loadEntry("text/x-csrc", "c");
+ sMimeTypeMap.loadEntry("text/x-dsrc", "d");
+ sMimeTypeMap.loadEntry("text/x-haskell", "hs");
+ sMimeTypeMap.loadEntry("text/x-java", "java");
+ sMimeTypeMap.loadEntry("text/x-literate-haskell", "lhs");
+ sMimeTypeMap.loadEntry("text/x-moc", "moc");
+ sMimeTypeMap.loadEntry("text/x-pascal", "p");
+ sMimeTypeMap.loadEntry("text/x-pascal", "pas");
+ sMimeTypeMap.loadEntry("text/x-pcs-gcd", "gcd");
+ sMimeTypeMap.loadEntry("text/x-setext", "etx");
+ sMimeTypeMap.loadEntry("text/x-tcl", "tcl");
+ sMimeTypeMap.loadEntry("text/x-tex", "tex");
+ sMimeTypeMap.loadEntry("text/x-tex", "ltx");
+ sMimeTypeMap.loadEntry("text/x-tex", "sty");
+ sMimeTypeMap.loadEntry("text/x-tex", "cls");
+ sMimeTypeMap.loadEntry("text/x-vcalendar", "vcs");
+ sMimeTypeMap.loadEntry("text/x-vcard", "vcf");
+ sMimeTypeMap.loadEntry("video/3gpp", "3gp");
+ sMimeTypeMap.loadEntry("video/3gpp", "3g2");
+ sMimeTypeMap.loadEntry("video/dl", "dl");
+ sMimeTypeMap.loadEntry("video/dv", "dif");
+ sMimeTypeMap.loadEntry("video/dv", "dv");
+ sMimeTypeMap.loadEntry("video/fli", "fli");
+ sMimeTypeMap.loadEntry("video/mpeg", "mpeg");
+ sMimeTypeMap.loadEntry("video/mpeg", "mpg");
+ sMimeTypeMap.loadEntry("video/mpeg", "mpe");
+ sMimeTypeMap.loadEntry("video/mp4", "mp4");
+ sMimeTypeMap.loadEntry("video/mpeg", "VOB");
+ sMimeTypeMap.loadEntry("video/quicktime", "qt");
+ sMimeTypeMap.loadEntry("video/quicktime", "mov");
+ sMimeTypeMap.loadEntry("video/vnd.mpegurl", "mxu");
+ sMimeTypeMap.loadEntry("video/x-la-asf", "lsf");
+ sMimeTypeMap.loadEntry("video/x-la-asf", "lsx");
+ sMimeTypeMap.loadEntry("video/x-mng", "mng");
+ sMimeTypeMap.loadEntry("video/x-ms-asf", "asf");
+ sMimeTypeMap.loadEntry("video/x-ms-asf", "asx");
+ sMimeTypeMap.loadEntry("video/x-ms-wm", "wm");
+ sMimeTypeMap.loadEntry("video/x-ms-wmv", "wmv");
+ sMimeTypeMap.loadEntry("video/x-ms-wmx", "wmx");
+ sMimeTypeMap.loadEntry("video/x-ms-wvx", "wvx");
+ sMimeTypeMap.loadEntry("video/x-msvideo", "avi");
+ sMimeTypeMap.loadEntry("video/x-sgi-movie", "movie");
+ sMimeTypeMap.loadEntry("x-conference/x-cooltalk", "ice");
+ sMimeTypeMap.loadEntry("x-epoc/x-sisx-app", "sisx");
}
return sMimeTypeMap;
diff --git a/core/java/android/webkit/MockGeolocation.java b/core/java/android/webkit/MockGeolocation.java
new file mode 100644
index 0000000..028cb19
--- /dev/null
+++ b/core/java/android/webkit/MockGeolocation.java
@@ -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.
+ */
+
+package android.webkit;
+
+/**
+ * This class is simply a container for the methods used to configure WebKit's
+ * mock Geolocation service for use in LayoutTests.
+ * @hide Pending API council review.
+ */
+public final class MockGeolocation {
+
+ // Global instance of a MockGeolocation
+ private static MockGeolocation sMockGeolocation;
+
+ /**
+ * Set the position for the mock Geolocation service.
+ */
+ public void setPosition(double latitude, double longitude, double accuracy) {
+ // This should only ever be called on the WebKit thread.
+ nativeSetPosition(latitude, longitude, accuracy);
+ }
+
+ /**
+ * Set the error for the mock Geolocation service.
+ */
+ public void setError(int code, String message) {
+ // This should only ever be called on the WebKit thread.
+ nativeSetError(code, message);
+ }
+
+ /**
+ * Get the global instance of MockGeolocation.
+ * @return The global MockGeolocation instance.
+ */
+ public static MockGeolocation getInstance() {
+ if (sMockGeolocation == null) {
+ sMockGeolocation = new MockGeolocation();
+ }
+ return sMockGeolocation;
+ }
+
+ // Native functions
+ private static native void nativeSetPosition(double latitude, double longitude, double accuracy);
+ private static native void nativeSetError(int code, String message);
+}
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index c9b80ce..af0cb1e 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -132,11 +132,11 @@ 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));
}
- mSslErrorHandler = new SslErrorHandler(this);
+ mSslErrorHandler = new SslErrorHandler();
mHttpAuthHandler = new HttpAuthHandler(this);
mRequestQueue = new RequestQueue(context);
@@ -149,14 +149,12 @@ class Network {
* @param headers The http headers.
* @param postData The body of the request.
* @param loader A LoadListener for receiving the results of the request.
- * @param isHighPriority True if this is high priority request.
* @return True if the request was successfully queued.
*/
public boolean requestURL(String method,
Map<String, String> headers,
byte [] postData,
- LoadListener loader,
- boolean isHighPriority) {
+ LoadListener loader) {
String url = loader.url();
@@ -188,7 +186,7 @@ class Network {
RequestHandle handle = q.queueRequest(
url, loader.getWebAddress(), method, headers, loader,
- bodyProvider, bodyLength, isHighPriority);
+ bodyProvider, bodyLength);
loader.attachRequestHandle(handle);
if (loader.isSynchronous()) {
@@ -232,7 +230,7 @@ class Network {
* connecting through the proxy.
*/
public synchronized void setProxyUsername(String proxyUsername) {
- if (WebView.DEBUG) {
+ if (DebugFlags.NETWORK) {
Assert.assertTrue(isValidProxySet());
}
@@ -252,7 +250,7 @@ class Network {
* connecting through the proxy.
*/
public synchronized void setProxyPassword(String proxyPassword) {
- if (WebView.DEBUG) {
+ if (DebugFlags.NETWORK) {
Assert.assertTrue(isValidProxySet());
}
@@ -266,7 +264,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 +278,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,12 +298,20 @@ 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);
}
}
+ /* package */ boolean checkSslPrefTable(LoadListener loader,
+ SslError error) {
+ if (loader != null && error != null) {
+ return mSslErrorHandler.checkSslPrefTable(loader, error);
+ }
+ return false;
+ }
+
/**
* Handles authentication requests on their way up to the user (the user
* must provide credentials).
@@ -313,7 +319,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/Plugin.java b/core/java/android/webkit/Plugin.java
index f83da99..34a30a9 100644
--- a/core/java/android/webkit/Plugin.java
+++ b/core/java/android/webkit/Plugin.java
@@ -26,7 +26,11 @@ import android.webkit.WebView;
/**
* Represents a plugin (Java equivalent of the PluginPackageAndroid
* C++ class in libs/WebKitLib/WebKit/WebCore/plugins/android/)
+ *
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+@Deprecated
public class Plugin {
public interface PreferencesClickHandler {
public void handleClickEvent(Context context);
@@ -38,6 +42,11 @@ public class Plugin {
private String mDescription;
private PreferencesClickHandler mHandler;
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public Plugin(String name,
String path,
String fileName,
@@ -49,49 +58,103 @@ public class Plugin {
mHandler = new DefaultClickHandler();
}
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public String toString() {
return mName;
}
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public String getName() {
return mName;
}
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public String getPath() {
return mPath;
}
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public String getFileName() {
return mFileName;
}
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public String getDescription() {
return mDescription;
}
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public void setName(String name) {
mName = name;
}
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public void setPath(String path) {
mPath = path;
}
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public void setFileName(String fileName) {
mFileName = fileName;
}
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public void setDescription(String description) {
mDescription = description;
}
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public void setClickHandler(PreferencesClickHandler handler) {
mHandler = handler;
}
/**
* Invokes the click handler for this plugin.
+ *
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public void dispatchClickEvent(Context context) {
if (mHandler != null) {
mHandler.handleClickEvent(context);
@@ -100,11 +163,15 @@ public class Plugin {
/**
* Default click handler. The plugins should implement their own.
+ *
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
private class DefaultClickHandler implements PreferencesClickHandler,
DialogInterface.OnClickListener {
private AlertDialog mDialog;
-
+ @Deprecated
public void handleClickEvent(Context context) {
// Show a simple popup dialog containing the description
// string of the plugin.
@@ -117,7 +184,11 @@ public class Plugin {
.show();
}
}
-
+ /**
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+ @Deprecated
public void onClick(DialogInterface dialog, int which) {
mDialog.dismiss();
mDialog = null;
diff --git a/core/java/android/webkit/PluginContentLoader.java b/core/java/android/webkit/PluginContentLoader.java
deleted file mode 100644
index 2069599..0000000
--- a/core/java/android/webkit/PluginContentLoader.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.webkit;
-
-import android.net.http.Headers;
-
-import java.io.InputStream;
-import java.util.*;
-
-import org.apache.http.util.CharArrayBuffer;
-
-/**
- * This class is a concrete implementation of StreamLoader that uses a
- * PluginData object as the source for the stream.
- */
-class PluginContentLoader extends StreamLoader {
-
- private PluginData mData; // Content source
-
- /**
- * Constructs a PluginDataLoader for use when loading content from
- * a plugin.
- *
- * @param loadListener LoadListener to pass the content to
- * @param data PluginData used as the source for the content.
- */
- PluginContentLoader(LoadListener loadListener, PluginData data) {
- super(loadListener);
- mData = data;
- }
-
- @Override
- protected boolean setupStreamAndSendStatus() {
- mDataStream = mData.getInputStream();
- mContentLength = mData.getContentLength();
- mHandler.status(1, 1, mData.getStatusCode(), "OK");
- return true;
- }
-
- @Override
- protected void buildHeaders(Headers headers) {
- // Crate a CharArrayBuffer with an arbitrary initial capacity.
- CharArrayBuffer buffer = new CharArrayBuffer(100);
- Iterator<Map.Entry<String, String[]>> responseHeadersIt =
- mData.getHeaders().entrySet().iterator();
- while (responseHeadersIt.hasNext()) {
- Map.Entry<String, String[]> entry = responseHeadersIt.next();
- // Headers.parseHeader() expects lowercase keys, so keys
- // such as "Accept-Ranges" will fail to parse.
- //
- // UrlInterceptHandler instances supply a mapping of
- // lowercase key to [ unmodified key, value ], so for
- // Headers.parseHeader() to succeed, we need to construct
- // a string using the key (i.e. entry.getKey()) and the
- // element denoting the header value in the
- // [ unmodified key, value ] pair (i.e. entry.getValue()[1).
- //
- // The reason why UrlInterceptHandler instances supply such a
- // mapping in the first place is historical. Early versions of
- // the Gears plugin used java.net.HttpURLConnection, which always
- // returned headers names as capitalized strings. When these were
- // fed back into webkit, they failed to parse.
- //
- // Mewanwhile, Gears was modified to use Apache HTTP library
- // instead, so this design is now obsolete. Changing it however,
- // would require changes to the Gears C++ codebase and QA-ing and
- // submitting a new binary to the Android tree. Given the
- // timelines for the next Android release, we will not do this
- // for now.
- //
- // TODO: fix C++ Gears to remove the need for this
- // design.
- String keyValue = entry.getKey() + ": " + entry.getValue()[1];
- buffer.ensureCapacity(keyValue.length());
- buffer.append(keyValue);
- // Parse it into the header container.
- headers.parseHeader(buffer);
- // Clear the buffer
- buffer.clear();
- }
- }
-}
diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java
index 2b539fe..2dd445e 100644
--- a/core/java/android/webkit/PluginData.java
+++ b/core/java/android/webkit/PluginData.java
@@ -28,7 +28,10 @@ import java.util.Map;
* status code. The PluginData class is the container for all these
* parts.
*
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+@Deprecated
public final class PluginData {
/**
* The content stream.
@@ -47,10 +50,6 @@ public final class PluginData {
private Map<String, String[]> mHeaders;
/**
- * The index of the header value in the above mapping.
- */
- private int mHeaderValueIndex;
- /**
* The associated HTTP response code.
*/
private int mStatusCode;
@@ -63,7 +62,11 @@ public final class PluginData {
* @param headers The response headers. Map of
* lowercase header name to [ unmodified header name, header value]
* @param length The HTTP response status code.
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public PluginData(
InputStream stream,
long length,
@@ -79,7 +82,11 @@ public final class PluginData {
* Returns the input stream that contains the plugin content.
*
* @return An InputStream instance with the plugin content.
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public InputStream getInputStream() {
return mStream;
}
@@ -88,7 +95,11 @@ public final class PluginData {
* Returns the length of the plugin content.
*
* @return the length of the plugin content.
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public long getContentLength() {
return mContentLength;
}
@@ -100,7 +111,11 @@ public final class PluginData {
* @return A Map<String, String[]> containing all headers. The
* mapping is 'lowercase header name' to ['unmodified header
* name', header value].
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public Map<String, String[]> getHeaders() {
return mHeaders;
}
@@ -109,7 +124,11 @@ public final class PluginData {
* Returns the HTTP status code for the response.
*
* @return The HTTP statue code, e.g 200.
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public int getStatusCode() {
return mStatusCode;
}
diff --git a/core/java/android/webkit/PluginList.java b/core/java/android/webkit/PluginList.java
index a9d3d8c..a61b07b 100644
--- a/core/java/android/webkit/PluginList.java
+++ b/core/java/android/webkit/PluginList.java
@@ -24,27 +24,43 @@ import java.util.List;
* A simple list of initialized plugins. This list gets
* populated when the plugins are initialized (at
* browser startup, at the moment).
+ *
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+@Deprecated
public class PluginList {
private ArrayList<Plugin> mPlugins;
/**
* Public constructor. Initializes the list of plugins.
+ *
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public PluginList() {
mPlugins = new ArrayList<Plugin>();
}
/**
* Returns the list of plugins as a java.util.List.
+ *
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public synchronized List getList() {
return mPlugins;
}
/**
* Adds a plugin to the list.
+ *
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public synchronized void addPlugin(Plugin plugin) {
if (!mPlugins.contains(plugin)) {
mPlugins.add(plugin);
@@ -53,7 +69,11 @@ public class PluginList {
/**
* Removes a plugin from the list.
+ *
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public synchronized void removePlugin(Plugin plugin) {
int location = mPlugins.indexOf(plugin);
if (location != -1) {
@@ -63,14 +83,22 @@ public class PluginList {
/**
* Clears the plugin list.
+ *
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public synchronized void clear() {
mPlugins.clear();
}
/**
* Dispatches the click event to the appropriate plugin.
+ *
+ * @deprecated This interface was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public synchronized void pluginClicked(Context context, int position) {
try {
Plugin plugin = mPlugins.get(position);
diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java
new file mode 100644
index 0000000..32eea5f
--- /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[] getPluginDirectories() {
+ 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);
+ }
+
+ return directories.toArray(new String[directories.size()]);
+ }
+
+ String getPluginSharedDataDirectory() {
+ return mContext.getDir("plugins", 0).getPath();
+ }
+}
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index 5f84bbe..90ed65d 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -42,11 +42,6 @@ public class SslErrorHandler extends Handler {
private static final String LOGTAG = "network";
/**
- * Network.
- */
- private Network mNetwork;
-
- /**
* Queue of loaders that experience SSL-related problems.
*/
private LinkedList<LoadListener> mLoaderQueue;
@@ -57,13 +52,15 @@ public class SslErrorHandler extends Handler {
private Bundle mSslPrefTable;
// Message id for handling the response
- private final int HANDLE_RESPONSE = 100;
+ private static final int HANDLE_RESPONSE = 100;
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case HANDLE_RESPONSE:
- handleSslErrorResponse(msg.arg1 == 1);
+ LoadListener loader = (LoadListener) msg.obj;
+ handleSslErrorResponse(loader, loader.sslError(),
+ msg.arg1 == 1);
fastProcessQueuedSslErrors();
break;
}
@@ -72,9 +69,7 @@ public class SslErrorHandler extends Handler {
/**
* Creates a new error handler with an empty loader queue.
*/
- /* package */ SslErrorHandler(Network network) {
- mNetwork = network;
-
+ /* package */ SslErrorHandler() {
mLoaderQueue = new LinkedList<LoadListener>();
mSslPrefTable = new Bundle();
}
@@ -83,7 +78,7 @@ public class SslErrorHandler extends Handler {
* Saves this handler's state into a map.
* @return True iff succeeds.
*/
- /* package */ boolean saveState(Bundle outState) {
+ /* package */ synchronized boolean saveState(Bundle outState) {
boolean success = (outState != null);
if (success) {
// TODO?
@@ -97,7 +92,7 @@ public class SslErrorHandler extends Handler {
* Restores this handler's state from a map.
* @return True iff succeeds.
*/
- /* package */ boolean restoreState(Bundle inState) {
+ /* package */ synchronized boolean restoreState(Bundle inState) {
boolean success = (inState != null);
if (success) {
success = inState.containsKey("ssl-error-handler");
@@ -120,7 +115,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());
}
@@ -134,6 +129,28 @@ public class SslErrorHandler extends Handler {
}
/**
+ * Check the preference table for a ssl error that has already been shown
+ * to the user.
+ */
+ /* package */ synchronized boolean checkSslPrefTable(LoadListener loader,
+ SslError error) {
+ final String host = loader.host();
+ final int primary = error.getPrimaryError();
+
+ if (DebugFlags.SSL_ERROR_HANDLER) {
+ Assert.assertTrue(host != null && primary != 0);
+ }
+
+ if (mSslPrefTable.containsKey(host)) {
+ if (primary <= mSslPrefTable.getInt(host)) {
+ handleSslErrorResponse(loader, error, true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Processes queued SSL-error confirmation requests in
* a tight loop while there is no need to ask the user.
*/
@@ -151,28 +168,24 @@ public class SslErrorHandler extends Handler {
if (loader != null) {
// if this loader has been cancelled
if (loader.cancelled()) {
- // go to the following loader in the queue
+ // go to the following loader in the queue. Make sure this
+ // loader has been removed from the queue.
+ mLoaderQueue.remove(loader);
return true;
}
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) {
- Assert.assertTrue(host != null && primary != 0);
- }
-
- if (mSslPrefTable.containsKey(host)) {
- if (primary <= mSslPrefTable.getInt(host)) {
- handleSslErrorResponse(true);
- return true;
- }
+ // checkSslPrefTable will handle the ssl error response if the
+ // answer is available. It does not remove the loader from the
+ // queue.
+ if (checkSslPrefTable(loader, error)) {
+ mLoaderQueue.remove(loader);
+ return true;
}
// if we do not have information on record, ask
@@ -189,7 +202,7 @@ public class SslErrorHandler extends Handler {
* Proceed with the SSL certificate.
*/
public void proceed() {
- sendMessage(obtainMessage(HANDLE_RESPONSE, 1, 0));
+ sendMessage(obtainMessage(HANDLE_RESPONSE, 1, 0, mLoaderQueue.poll()));
}
/**
@@ -197,19 +210,20 @@ public class SslErrorHandler extends Handler {
* the error.
*/
public void cancel() {
- sendMessage(obtainMessage(HANDLE_RESPONSE, 0, 0));
+ sendMessage(obtainMessage(HANDLE_RESPONSE, 0, 0, mLoaderQueue.poll()));
}
/**
* Handles SSL error(s) on the way down from the user.
*/
- /* package */ synchronized void handleSslErrorResponse(boolean proceed) {
- LoadListener loader = mLoaderQueue.poll();
- if (WebView.DEBUG) {
+ /* package */ synchronized void handleSslErrorResponse(LoadListener loader,
+ SslError error, boolean proceed) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Assert.assertNotNull(loader);
+ Assert.assertNotNull(error);
}
- if (WebView.LOGV_ENABLED) {
+ if (DebugFlags.SSL_ERROR_HANDLER) {
Log.v(LOGTAG, "SslErrorHandler.handleSslErrorResponse():"
+ " proceed: " + proceed
+ " url:" + loader.url());
@@ -218,16 +232,16 @@ public class SslErrorHandler extends Handler {
if (!loader.cancelled()) {
if (proceed) {
// update the user's SSL error preference table
- int primary = loader.sslError().getPrimaryError();
+ int primary = error.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..623ff29 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()) {
@@ -153,7 +157,6 @@ abstract class StreamLoader extends Handler {
if (mContentLength > 0) {
headers.setContentLength(mContentLength);
}
- headers.setCacheControl(NO_STORE);
buildHeaders(headers);
mHandler.headers(headers);
}
diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java
deleted file mode 100644
index 99de56d..0000000
--- a/core/java/android/webkit/TextDialog.java
+++ /dev/null
@@ -1,593 +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.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;
-import android.view.inputmethod.InputMethodManager;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsoluteLayout.LayoutParams;
-import android.widget.ArrayAdapter;
-import android.widget.AutoCompleteTextView;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-/**
- * TextDialog 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 {
-
- private WebView mWebView;
- private boolean mSingle;
- private int mWidthSpec;
- private int mHeightSpec;
- private int mNodePointer;
- // FIXME: This is a hack for blocking unmatched key ups, in particular
- // on the enter key. The method for blocking unmatched key ups prevents
- // the shift key from working properly.
- private boolean mGotEnterDown;
- // mScrollToAccommodateCursor being set to false prevents us from scrolling
- // the cursor on screen when using the trackball to select a textfield.
- private boolean mScrollToAccommodateCursor;
- private int mMaxLength;
- // Keep track of the text before the change so we know whether we actually
- // need to send down the DOM events.
- private String mPreChange;
- // Array to store the final character added in onTextChanged, so that its
- // KeyEvents may be determined.
- private char[] mCharacter = new char[1];
- // This is used to reset the length filter when on a textfield
- // with no max length.
- // FIXME: This can be replaced with TextView.NO_FILTERS if that
- // is made public/protected.
- private static final InputFilter[] NO_FILTERS = new InputFilter[0];
-
- /**
- * Create a new TextDialog.
- * @param context The Context for this TextDialog.
- * @param webView The WebView that created this.
- */
- /* package */ TextDialog(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);
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.isSystem()) {
- return super.dispatchKeyEvent(event);
- }
- // Treat ACTION_DOWN and ACTION MULTIPLE the same
- boolean down = event.getAction() != KeyEvent.ACTION_UP;
- int keyCode = event.getKeyCode();
- 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
- // go ahead and pass the key down immediately.
- if (KeyEvent.KEYCODE_DEL == keyCode && 0 == oldLength) {
- sendDomEvent(event);
- return true;
- }
-
- if ((mSingle && KeyEvent.KEYCODE_ENTER == keyCode)) {
- if (isPopupShowing()) {
- return super.dispatchKeyEvent(event);
- }
- if (!down) {
- // Hide the keyboard, since the user has just submitted this
- // form. The submission happens thanks to the two calls
- // to sendDomEvent.
- InputMethodManager.getInstance(mContext)
- .hideSoftInputFromWindow(getWindowToken(), 0);
- sendDomEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
- sendDomEvent(event);
- }
- return super.dispatchKeyEvent(event);
- } else if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
- // Note that this handles center key and trackball.
- if (isPopupShowing()) {
- return super.dispatchKeyEvent(event);
- }
- // Center key should be passed to a potential onClick
- if (!down) {
- mWebView.shortPressOnTextField();
- }
- // Pass to super to handle longpress.
- return super.dispatchKeyEvent(event);
- }
-
- // Ensure there is a layout so arrow keys are handled properly.
- if (getLayout() == null) {
- measure(mWidthSpec, mHeightSpec);
- }
- int oldStart = Selection.getSelectionStart(text);
- int oldEnd = Selection.getSelectionEnd(text);
-
- boolean maxedOut = mMaxLength != -1 && oldLength == mMaxLength;
- // If we are at max length, and there is a selection rather than a
- // cursor, we need to store the text to compare later, since the key
- // may have changed the string.
- String oldText;
- if (maxedOut && oldEnd != oldStart) {
- oldText = text.toString();
- } else {
- oldText = "";
- }
- if (super.dispatchKeyEvent(event)) {
- // If the TextDialog 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.
-
- // UNLESS there is a max length determined by the html. In that
- // case, if the string was already at the max length, an
- // alphanumeric key will be erased by the LengthFilter,
- // 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 (maxedOut && !isArrowKey && keyCode != KeyEvent.KEYCODE_DEL) {
- if (oldEnd == oldStart) {
- // Return true so the key gets dropped.
- mScrollToAccommodateCursor = true;
- return true;
- } else if (!oldText.equals(getText().toString())) {
- // FIXME: This makes the text work properly, but it
- // does not pass down the key event, so it may not
- // work for a textfield that has the type of
- // behavior of GoogleSuggest. That said, it is
- // unlikely that a site would combine the two in
- // one textfield.
- Spannable span = (Spannable) getText();
- int newStart = Selection.getSelectionStart(span);
- int newEnd = Selection.getSelectionEnd(span);
- mWebView.replaceTextfieldText(0, oldLength, span.toString(),
- newStart, newEnd);
- mScrollToAccommodateCursor = true;
- return true;
- }
- }
- 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) {
- // 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.
- // Reset trackballtime to ensure it.
- mWebView.resetTrackballTime();
- return down ? mWebView.onKeyDown(keyCode, event) : mWebView
- .onKeyUp(keyCode, event);
- }
- return false;
- }
-
- /**
- * Create a fake touch up event at (x,y) with respect to this TextDialog.
- * 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
- * the cursor accordingly.
- */
- /* package */ void fakeTouchEvent(float x, float y) {
- // We need to ensure that there is a Layout, since the Layout is used
- // in determining where to place the cursor.
- if (getLayout() == null) {
- measure(mWidthSpec, mHeightSpec);
- }
- // Create a fake touch up, which is used to place the cursor.
- MotionEvent ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP,
- x, y, 0);
- onTouchEvent(ev);
- ev.recycle();
- }
-
- /**
- * Determine whether this TextDialog 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
- * pointed to by ptr.
- */
- /* package */ boolean isSameTextField(int ptr) {
- return ptr == mNodePointer;
- }
-
- @Override
- public boolean onPreDraw() {
- if (getLayout() == null) {
- measure(mWidthSpec, mHeightSpec);
- }
- 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
- // limit on text length from registering the onTextChanged event.
- if (mPreChange == null || mPreChange.equals(postChange) ||
- (mMaxLength > -1 && mPreChange.length() > mMaxLength &&
- mPreChange.substring(0, mMaxLength).equals(postChange))) {
- return;
- }
- mPreChange = postChange;
- // 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
- updateCachedTextfield();
- return;
- }
- // Find the last character being replaced. If it can be represented by
- // events, we will pass them to native (after replacing the beginning
- // of the changed text), so we can see javascript events.
- // Otherwise, replace the text being changed (including the last
- // character) in the textfield.
- TextUtils.getChars(s, start + count - 1, start + count, mCharacter, 0);
- KeyCharacterMap kmap =
- KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
- KeyEvent[] events = kmap.getEvents(mCharacter);
- boolean cannotUseKeyEvents = null == events;
- int charactersFromKeyEvents = cannotUseKeyEvents ? 0 : 1;
- if (count > 1 || cannotUseKeyEvents) {
- String replace = s.subSequence(start,
- start + count - charactersFromKeyEvents).toString();
- mWebView.replaceTextfieldText(start, start + before, replace,
- start + count - charactersFromKeyEvents,
- start + count - charactersFromKeyEvents);
- } else {
- // 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]);
- }
- }
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent event) {
- if (isPopupShowing()) {
- return super.onTrackballEvent(event);
- }
- if (event.getAction() != MotionEvent.ACTION_MOVE) {
- return false;
- }
- 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);
- return true;
- }
- // If the user is in a textfield, and the movement method is not
- // handling the trackball events, it means they are at the end of the
- // field and continuing to move the trackball. In this case, we should
- // not scroll the cursor on screen bc the user may be attempting to
- // scroll the page, possibly in the opposite direction of the cursor.
- mScrollToAccommodateCursor = false;
- return false;
- }
-
- /**
- * Remove this TextDialog from its host WebView, and return
- * focus to the host.
- */
- /* package */ void remove() {
- // hide the soft keyboard when the edit text is out of focus
- InputMethodManager.getInstance(mContext).hideSoftInputFromWindow(
- getWindowToken(), 0);
- mWebView.removeView(this);
- mWebView.requestFocus();
- mScrollToAccommodateCursor = false;
- }
-
- /* package */ void enableScrollOnScreen(boolean enable) {
- mScrollToAccommodateCursor = enable;
- }
-
- /* package */ void bringIntoView() {
- if (getLayout() != null) {
- bringPointIntoView(Selection.getSelectionEnd(getText()));
- }
- }
-
- @Override
- public boolean requestRectangleOnScreen(Rect rectangle) {
- if (mScrollToAccommodateCursor) {
- return super.requestRectangleOnScreen(rectangle);
- }
- return false;
- }
-
- /**
- * Send the DOM events for the specified event.
- * @param event KeyEvent to be translated into a DOM event.
- */
- private void sendDomEvent(KeyEvent event) {
- mWebView.passToJavaScript(getText().toString(), event);
- }
-
- /**
- * Always use this instead of setAdapter, as this has features specific to
- * the TextDialog.
- */
- public void setAdapterCustom(AutoCompleteAdapter adapter) {
- if (adapter != null) {
- setInputType(EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE);
- adapter.setTextView(this);
- }
- super.setAdapter(adapter);
- }
-
- /**
- * This is a special version of ArrayAdapter which changes its text size
- * to match the text size of its host TextView.
- */
- public static class AutoCompleteAdapter extends ArrayAdapter<String> {
- private TextView mTextView;
-
- public AutoCompleteAdapter(Context context, ArrayList<String> entries) {
- super(context, com.android.internal.R.layout
- .search_dropdown_item_1line, entries);
- }
-
- /**
- * {@inheritDoc}
- */
- public View getView(int position, View convertView, ViewGroup parent) {
- TextView tv =
- (TextView) super.getView(position, convertView, parent);
- if (tv != null && mTextView != null) {
- tv.setTextSize(mTextView.getTextSize());
- }
- return tv;
- }
-
- /**
- * Set the TextView so we can match its text size.
- */
- private void setTextView(TextView tv) {
- mTextView = tv;
- }
- }
-
- /**
- * Determine whether to use the system-wide password disguising method,
- * or to use none.
- * @param inPassword True if the textfield is a password field.
- */
- /* package */ void setInPassword(boolean inPassword) {
- if (inPassword) {
- setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.
- TYPE_TEXT_VARIATION_PASSWORD);
- }
- }
-
- /* package */ void setMaxLength(int maxLength) {
- mMaxLength = maxLength;
- if (-1 == maxLength) {
- setFilters(NO_FILTERS);
- } else {
- setFilters(new InputFilter[] {
- new InputFilter.LengthFilter(maxLength) });
- }
- }
-
- /**
- * Set the pointer for this node so it can be determined which node this
- * TextDialog represents.
- * @param ptr Integer representing the pointer to the node which this
- * TextDialog represents.
- */
- /* package */ void setNodePointer(int ptr) {
- mNodePointer = ptr;
- }
-
- /**
- * Determine the position and size of TextDialog, 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.
- * @param x x-position of the textfield.
- * @param y y-position of the textfield.
- * @param width width of the textfield.
- * @param height height of the textfield.
- */
- /* package */ void setRect(int x, int y, int width, int height) {
- LayoutParams lp = (LayoutParams) getLayoutParams();
- if (null == lp) {
- lp = new LayoutParams(width, height, x, y);
- } else {
- lp.x = x;
- lp.y = y;
- lp.width = width;
- lp.height = height;
- }
- if (getParent() == null) {
- mWebView.addView(this, lp);
- } else {
- setLayoutParams(lp);
- }
- // Set up a measure spec so a layout can always be recreated.
- mWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
- mHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
- requestFocus();
- }
-
- /**
- * Set whether this is a single-line textfield or a multi-line textarea.
- * Textfields scroll horizontally, and do not handle the enter key.
- * Textareas behave oppositely.
- * Do NOT call this after calling setInPassword(true). This will result in
- * removing the password input type.
- */
- public void setSingleLine(boolean single) {
- int inputType = EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
- if (!single) {
- inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
- | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
- | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
- }
- mSingle = single;
- setHorizontallyScrolling(single);
- setInputType(inputType);
- }
-
- /**
- * Set the text for this TextDialog, and set the selection to (start, end)
- * @param text Text to go into this TextDialog.
- * @param start Beginning of the selection.
- * @param end End of the selection.
- */
- /* package */ void setText(CharSequence text, int start, int end) {
- mPreChange = text.toString();
- setText(text);
- Spannable span = (Spannable) getText();
- int length = span.length();
- if (end > length) {
- end = length;
- }
- if (start < 0) {
- start = 0;
- } else if (start > length) {
- start = length;
- }
- Selection.setSelection(span, start, end);
- }
-
- /**
- * Set the text to the new string, but use the old selection, making sure
- * to keep it within the new string.
- * @param text The new text to place in the textfield.
- */
- /* package */ void setTextAndKeepSelection(String text) {
- mPreChange = text.toString();
- Editable edit = (Editable) getText();
- edit.replace(0, edit.length(), text);
- updateCachedTextfield();
- }
-
- /**
- * Update the cache to reflect the current text.
- */
- /* package */ void updateCachedTextfield() {
- mWebView.updateCachedTextfield(getText().toString());
- }
-}
diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index 9889fe9..232ed36 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;
@@ -126,6 +126,32 @@ public final class URLUtil {
return retData;
}
+ /**
+ * @return True iff the url is correctly URL encoded
+ */
+ static boolean verifyURLEncoding(String url) {
+ int count = url.length();
+ if (count == 0) {
+ return false;
+ }
+
+ int index = url.indexOf('%');
+ while (index >= 0 && index < count) {
+ if (index < count - 2) {
+ try {
+ parseHex((byte) url.charAt(++index));
+ parseHex((byte) url.charAt(++index));
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ index = url.indexOf('%', index + 1);
+ }
+ return true;
+ }
+
private static int parseHex(byte b) {
if (b >= '0' && b <= '9') return (b - '0');
if (b >= 'A' && b <= 'F') return (b - 'A' + 10);
@@ -146,6 +172,7 @@ public final class URLUtil {
* requests from a file url.
* @deprecated Cookieless proxy is no longer supported.
*/
+ @Deprecated
public static boolean isCookielessProxyUrl(String url) {
return (null != url) && url.startsWith(PROXY_BASE);
}
diff --git a/core/java/android/webkit/UrlInterceptHandler.java b/core/java/android/webkit/UrlInterceptHandler.java
index 9216413..78bab04 100644
--- a/core/java/android/webkit/UrlInterceptHandler.java
+++ b/core/java/android/webkit/UrlInterceptHandler.java
@@ -20,6 +20,11 @@ import android.webkit.CacheManager.CacheResult;
import android.webkit.PluginData;
import java.util.Map;
+/**
+ * @deprecated This interface was inteded to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+@Deprecated
public interface UrlInterceptHandler {
/**
@@ -30,8 +35,8 @@ public interface UrlInterceptHandler {
* @param url URL string.
* @param headers The headers associated with the request. May be null.
* @return The CacheResult containing the surrogate response.
- * @Deprecated Use PluginData getPluginData(String url,
- * Map<String, String> headers); instead
+ *
+ * @deprecated Do not use, this interface is deprecated.
*/
@Deprecated
public CacheResult service(String url, Map<String, String> headers);
@@ -44,6 +49,9 @@ public interface UrlInterceptHandler {
* @param url URL string.
* @param headers The headers associated with the request. May be null.
* @return The PluginData containing the surrogate response.
+ *
+ * @deprecated Do not use, this interface is deprecated.
*/
+ @Deprecated
public PluginData getPluginData(String url, Map<String, String> headers);
}
diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java
index 6051f29..eca5acd 100644
--- a/core/java/android/webkit/UrlInterceptRegistry.java
+++ b/core/java/android/webkit/UrlInterceptRegistry.java
@@ -24,6 +24,11 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
+/**
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
+ */
+@Deprecated
public final class UrlInterceptRegistry {
private final static String LOGTAG = "intercept";
@@ -42,7 +47,11 @@ public final class UrlInterceptRegistry {
* set the flag to control whether url intercept is enabled or disabled
*
* @param disabled true to disable the cache
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public static synchronized void setUrlInterceptDisabled(boolean disabled) {
mDisabled = disabled;
}
@@ -51,7 +60,11 @@ public final class UrlInterceptRegistry {
* get the state of the url intercept, enabled or disabled
*
* @return return if it is disabled
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public static synchronized boolean urlInterceptDisabled() {
return mDisabled;
}
@@ -62,7 +75,11 @@ public final class UrlInterceptRegistry {
*
* @param handler The new UrlInterceptHandler object
* @return true if the handler was not previously registered.
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public static synchronized boolean registerHandler(
UrlInterceptHandler handler) {
if (!getHandlers().contains(handler)) {
@@ -78,7 +95,11 @@ public final class UrlInterceptRegistry {
*
* @param handler A previously registered UrlInterceptHandler.
* @return true if the handler was found and removed from the list.
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public static synchronized boolean unregisterHandler(
UrlInterceptHandler handler) {
return getHandlers().remove(handler);
@@ -89,8 +110,9 @@ public final class UrlInterceptRegistry {
* UrlInterceptHandler interested, or null if none are.
*
* @return A CacheResult containing surrogate content.
- * @Deprecated Use PluginData getPluginData( String url,
- * Map<String, String> headers) instead.
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
@Deprecated
public static synchronized CacheResult getSurrogate(
@@ -115,7 +137,11 @@ public final class UrlInterceptRegistry {
* intercepts are disabled.
*
* @return A PluginData instance containing surrogate content.
+ *
+ * @deprecated This class was intended to be used by Gears. Since Gears was
+ * deprecated, so is this class.
*/
+ @Deprecated
public static synchronized PluginData getPluginData(
String url, Map<String, String> headers) {
if (urlInterceptDisabled()) {
diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java
new file mode 100644
index 0000000..af33b4f
--- /dev/null
+++ b/core/java/android/webkit/ViewManager.java
@@ -0,0 +1,137 @@
+/*
+ * 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.content.Context;
+import android.view.View;
+import android.widget.AbsoluteLayout;
+
+import java.util.ArrayList;
+
+class ViewManager {
+ private final WebView mWebView;
+ private final ArrayList<ChildView> mChildren = new ArrayList<ChildView>();
+ private boolean mHidden;
+
+ class ChildView {
+ int x;
+ int y;
+ int width;
+ int height;
+ View mView; // generic view to show
+
+ ChildView() {
+ }
+
+ void setBounds(int x, int y, int width, int height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ void attachView(int x, int y, int width, int height) {
+ if (mView == null) {
+ return;
+ }
+ setBounds(x, y, width, height);
+ final AbsoluteLayout.LayoutParams lp =
+ new AbsoluteLayout.LayoutParams(ctv(width), ctv(height),
+ ctv(x), ctv(y));
+ mWebView.mPrivateHandler.post(new Runnable() {
+ public void run() {
+ // This method may be called multiple times. If the view is
+ // already attached, just set the new LayoutParams,
+ // otherwise attach the view and add it to the list of
+ // children.
+ if (mView.getParent() != null) {
+ mView.setLayoutParams(lp);
+ } else {
+ attachViewOnUIThread(lp);
+ }
+ }
+ });
+ }
+
+ void attachViewOnUIThread(AbsoluteLayout.LayoutParams lp) {
+ mWebView.addView(mView, lp);
+ mChildren.add(this);
+ }
+
+ void removeView() {
+ if (mView == null) {
+ return;
+ }
+ mWebView.mPrivateHandler.post(new Runnable() {
+ public void run() {
+ removeViewOnUIThread();
+ }
+ });
+ }
+
+ void removeViewOnUIThread() {
+ mWebView.removeView(mView);
+ mChildren.remove(this);
+ }
+ }
+
+ ViewManager(WebView w) {
+ mWebView = w;
+ }
+
+ ChildView createView() {
+ return new ChildView();
+ }
+
+ // contentToView shorthand.
+ private int ctv(int val) {
+ return mWebView.contentToView(val);
+ }
+
+ void scaleAll() {
+ for (ChildView v : mChildren) {
+ View view = v.mView;
+ AbsoluteLayout.LayoutParams lp =
+ (AbsoluteLayout.LayoutParams) view.getLayoutParams();
+ lp.width = ctv(v.width);
+ lp.height = ctv(v.height);
+ lp.x = ctv(v.x);
+ lp.y = ctv(v.y);
+ view.setLayoutParams(lp);
+ }
+ }
+
+ void hideAll() {
+ if (mHidden) {
+ return;
+ }
+ for (ChildView v : mChildren) {
+ v.mView.setVisibility(View.GONE);
+ }
+ mHidden = true;
+ }
+
+ void showAll() {
+ if (!mHidden) {
+ return;
+ }
+ for (ChildView v : mChildren) {
+ v.mView.setVisibility(View.VISIBLE);
+ }
+ mHidden = false;
+ }
+}
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..ad4ba05 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -18,10 +18,20 @@ package android.webkit;
import android.graphics.Bitmap;
import android.os.Message;
+import android.view.View;
public class WebChromeClient {
/**
+ * Tell the host application that the WebView has changed viewing modes.
+ * @param view The WebView that initiated the callback.
+ * @param newViewingMode One of the values described in WebView as possible
+ * values for the viewing mode
+ * @hide
+ */
+ public void onChangeViewingMode(WebView view, int newViewingMode) {}
+
+ /**
* Tell the host application the current progress of loading a page.
* @param view The WebView that initiated the callback.
* @param newProgress Current page loading progress, represented by
@@ -44,6 +54,47 @@ public class WebChromeClient {
public void onReceivedIcon(WebView view, Bitmap icon) {}
/**
+ * Notify the host application of the url for an apple-touch-icon.
+ * @param view The WebView that initiated the callback.
+ * @param url The icon url.
+ * @hide pending council approval
+ */
+ public void onReceivedTouchIconUrl(WebView view, String url) {}
+
+ /**
+ * A callback interface used by the host application to notify
+ * the current page that its custom view has been dismissed.
+ *
+ * @hide pending council approval
+ */
+ public interface CustomViewCallback {
+ /**
+ * Invoked when the host application dismisses the
+ * custom view.
+ */
+ public void onCustomViewHidden();
+ }
+
+ /**
+ * Notify the host application that the current page would
+ * like to show a custom View.
+ * @param view is the View object to be shown.
+ * @param callback is the callback to be invoked if and when the view
+ * is dismissed.
+ *
+ * @hide pending council approval
+ */
+ public void onShowCustomView(View view, CustomViewCallback callback) {};
+
+ /**
+ * Notify the host application that the current page would
+ * like to hide its custom view.
+ *
+ * @hide pending council approval
+ */
+ public void onHideCustomView() {}
+
+ /**
* Request the host application to create a new Webview. The host
* application should handle placement of the new WebView in the view
* system. The default behavior returns null.
@@ -158,6 +209,55 @@ 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 estimatedSize The estimated size of the database.
+ * @param totalUsedQuota is the sum of all origins' quota.
+ * @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, long estimatedSize, long totalUsedQuota,
+ 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 the Application Cache has exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ * @param totalUsedQuota is the sum of all origins' quota.
+ * @param quotaUpdater A callback to inform the WebCore thread that a new
+ * app cache size is available. This callback must always be executed at
+ * some point to ensure that the sleeping WebCore thread is woken up.
+ * @hide pending API council approval.
+ */
+ public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ quotaUpdater.updateQuota(0);
+ }
+
+ /**
+ * Instructs the client to show a prompt to ask the user to set the
+ * Geolocation permission state for the specified origin.
+ * @hide pending API council approval.
+ */
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {}
+
+ /**
+ * Instructs the client to hide the Geolocation permissions prompt.
+ * @hide pending API council approval.
+ */
+ public void onGeolocationPermissionsHidePrompt() {}
+
/**
* 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 +272,14 @@ 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/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java
index fd26b98..abd8237 100644
--- a/core/java/android/webkit/WebHistoryItem.java
+++ b/core/java/android/webkit/WebHistoryItem.java
@@ -39,6 +39,8 @@ public class WebHistoryItem implements Cloneable {
private Bitmap mFavicon;
// The pre-flattened data used for saving the state.
private byte[] mFlattenedData;
+ // The apple-touch-icon url for use when adding the site to the home screen
+ private String mTouchIconUrl;
/**
* Basic constructor that assigns a unique id to the item. Called by JNI
@@ -127,6 +129,14 @@ public class WebHistoryItem implements Cloneable {
}
/**
+ * Return the touch icon url.
+ * @hide
+ */
+ public String getTouchIconUrl() {
+ return mTouchIconUrl;
+ }
+
+ /**
* Set the favicon.
* @param icon A Bitmap containing the favicon for this history item.
* Note: The VM ensures 32-bit atomic read/write operations so we don't have
@@ -137,6 +147,14 @@ public class WebHistoryItem implements Cloneable {
}
/**
+ * Set the touch icon url.
+ * @hide
+ */
+ /*package*/ void setTouchIconUrl(String url) {
+ mTouchIconUrl = url;
+ }
+
+ /**
* Get the pre-flattened data.
* Note: The VM ensures 32-bit atomic read/write operations so we don't have
* to synchronize this method.
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index d284f5e..6cc6bb4 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -37,7 +37,7 @@ public final class WebIconDatabase {
private final EventHandler mEventHandler = new EventHandler();
// Class to handle messages before WebCore is ready
- private class EventHandler extends Handler {
+ private static class EventHandler extends Handler {
// Message ids
static final int OPEN = 0;
static final int CLOSE = 1;
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index a038b55..3c306bb 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -22,9 +22,7 @@ import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.provider.Checkin;
-
import java.lang.SecurityException;
-
import java.util.Locale;
/**
@@ -130,9 +128,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;
@@ -146,7 +148,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;
@@ -161,6 +162,17 @@ public class WebSettings {
private boolean mUseWideViewport = false;
private boolean mSupportMultipleWindows = false;
private boolean mShrinksStandaloneImagesToFit = false;
+ // HTML5 API flags
+ private boolean mAppCacheEnabled = false;
+ private boolean mDatabaseEnabled = false;
+ private boolean mDomStorageEnabled = false;
+ private boolean mWorkersEnabled = false; // only affects V8.
+ private boolean mGeolocationEnabled = true;
+ // HTML5 configuration parameters
+ private long mAppCacheMaxSize = Long.MAX_VALUE;
+ private String mAppCachePath = "";
+ private String mDatabasePath = "";
+ private String mGeolocationDatabasePath = "";
// Don't need to synchronize the get/set methods as they
// are basic types, also none of these values are used in
// native WebCore code.
@@ -175,9 +187,11 @@ public class WebSettings {
private boolean mSupportZoom = true;
private boolean mBuiltInZoomControls = false;
private boolean mAllowFileAccess = true;
+ private boolean mLoadWithOverviewMode = true;
- // The Gears permissions manager. Only in Donut.
- static GearsPermissionsManager sGearsPermissionsManager;
+ // Manages interaction of the system setting 'Location & security - Share
+ // with Google' and the browser.
+ static GoogleLocationSettingManager sGoogleLocationSettingManager;
// Class to handle messages before WebCore is ready.
private class EventHandler {
@@ -199,7 +213,6 @@ public class WebSettings {
switch (msg.what) {
case SYNC:
synchronized (WebSettings.this) {
- checkGearsPermissions();
if (mBrowserFrame.mNativeFrame != 0) {
nativeSync(mBrowserFrame.mNativeFrame);
}
@@ -247,13 +260,13 @@ public class WebSettings {
// User agent strings.
private static final String DESKTOP_USERAGENT =
- "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en)"
- + " AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2"
- + " Safari/525.20.1";
+ "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us)"
+ + " AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0"
+ + " Safari/530.17";
private static final String IPHONE_USERAGENT =
- "Mozilla/5.0 (iPhone; U; CPU iPhone 2_1 like Mac OS X; en)"
- + " AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2"
- + " Mobile/5F136 Safari/525.20.1";
+ "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us)"
+ + " AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0"
+ + " Mobile/7A341 Safari/528.16";
private static Locale sLocale;
private static Object sLockForLocaleSettings;
@@ -347,11 +360,13 @@ public class WebSettings {
// default to "en"
buffer.append("en");
}
-
- final String model = Build.MODEL;
- if (model.length() > 0) {
- buffer.append("; ");
- buffer.append(model);
+ // add the model for the release build
+ if ("REL".equals(Build.VERSION.CODENAME)) {
+ final String model = Build.MODEL;
+ if (model.length() > 0) {
+ buffer.append("; ");
+ buffer.append(model);
+ }
}
final String id = Build.ID;
if (id.length() > 0) {
@@ -421,6 +436,22 @@ public class WebSettings {
}
/**
+ * Set whether the WebView loads a page with overview mode.
+ * @hide Pending API council approval
+ */
+ public void setLoadWithOverviewMode(boolean overview) {
+ mLoadWithOverviewMode = overview;
+ }
+
+ /**
+ * Returns true if this WebView loads page with overview mode
+ * @hide Pending API council approval
+ */
+ public boolean getLoadWithOverviewMode() {
+ return mLoadWithOverviewMode;
+ }
+
+ /**
* Store whether the WebView is saving form data.
*/
public void setSaveFormData(boolean save) {
@@ -511,24 +542,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;
}
/**
@@ -633,7 +661,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
@@ -654,7 +682,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() {
@@ -673,7 +701,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() {
@@ -700,7 +728,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) {
@@ -711,7 +739,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() {
@@ -730,7 +758,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() {
@@ -749,7 +777,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() {
@@ -770,7 +798,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() {
@@ -791,7 +819,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() {
@@ -812,7 +840,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() {
@@ -833,7 +861,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() {
@@ -853,6 +881,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() {
@@ -872,16 +901,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) {
@@ -894,13 +923,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",
@@ -936,19 +966,158 @@ 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;
+ }
+
+ /**
+ * 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();
+ }
+ }
+
+ /**
+ * Set the path where the Geolocation permissions database should be saved.
+ * This will update WebCore when the Sync runs in the C++ side.
+ * @param databasePath String path to the directory where the Geolocation
+ * permissions database should be saved. May be the empty string but
+ * should never be null.
+ * @hide pending api council approval
+ */
+ public synchronized void setGeolocationDatabasePath(String databasePath) {
+ if (databasePath != null && !databasePath.equals(mDatabasePath)) {
+ mGeolocationDatabasePath = 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();
+ }
+ }
+
+ /**
+ * Set the maximum size for the Application Caches content.
+ * @param appCacheMaxSize the maximum size in bytes.
+ *
+ * @hide pending api council approval
+ */
+ public synchronized void setAppCacheMaxSize(long appCacheMaxSize) {
+ if (appCacheMaxSize != mAppCacheMaxSize) {
+ mAppCacheMaxSize = appCacheMaxSize;
+ postSync();
+ }
+ }
+
+ /**
+ * 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();
+ }
+ }
+
+ /**
+ * Set whether the DOM storage API is enabled.
+ * @param flag boolean True if the WebView should use the DOM storage
+ * API.
+ * @hide pending API council.
+ */
+ public synchronized void setDomStorageEnabled(boolean flag) {
+ if (mDomStorageEnabled != flag) {
+ mDomStorageEnabled = flag;
+ postSync();
+ }
+ }
+
+ /**
+ * Returns true if the DOM Storage API's are enabled.
+ * @return True if the DOM Storage API's are enabled.
+ * @hide pending API council.
+ */
+ public synchronized boolean getDomStorageEnabled() {
+ return mDomStorageEnabled;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Tell the WebView to enable WebWorkers API.
+ * @param flag True if the WebView should enable WebWorkers.
+ * Note that this flag only affects V8. JSC does not have
+ * an equivalent setting.
+ * @hide pending api council approval
+ */
+ public synchronized void setWorkersEnabled(boolean flag) {
+ if (mWorkersEnabled != flag) {
+ mWorkersEnabled = flag;
postSync();
}
}
/**
- * Return true if javascript is enabled.
+ * Sets whether Geolocation is enabled.
+ * @param flag Whether Geolocation should be enabled.
+ * @hide pending api council approval
+ */
+ public synchronized void setGeolocationEnabled(boolean flag) {
+ if (mGeolocationEnabled != flag) {
+ mGeolocationEnabled = flag;
+ postSync();
+ }
+ }
+
+ /**
+ * Return true if javascript is enabled. <b>Note: The default is false.</b>
* @return True if javascript is enabled.
*/
public synchronized boolean getJavaScriptEnabled() {
@@ -964,11 +1133,10 @@ 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 "";
}
/**
@@ -985,7 +1153,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().
*/
@@ -1005,7 +1174,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() {
@@ -1094,8 +1263,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) {
@@ -1149,10 +1318,11 @@ 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);
}
- checkGearsPermissions();
+ sGoogleLocationSettingManager = new GoogleLocationSettingManager(mContext);
+ sGoogleLocationSettingManager.start();
nativeSync(frame.mNativeFrame);
mSyncPending = false;
mEventHandler.createHandler();
@@ -1168,23 +1338,6 @@ public class WebSettings {
return size;
}
- private void checkGearsPermissions() {
- // Did we already check the permissions at startup?
- if (sGearsPermissionsManager != null) {
- return;
- }
- // Is the pluginsPath sane?
- String pluginsPath = getPluginsPath();
- if (pluginsPath == null || pluginsPath.length() == 0) {
- // We don't yet have a meaningful plugin path, so
- // we can't do anything about the Gears permissions.
- return;
- }
- sGearsPermissionsManager =
- new GearsPermissionsManager(mContext, pluginsPath);
- sGearsPermissionsManager.doCheckAndStartObserver();
- }
-
/* Post a SYNC message to handle syncing the native settings. */
private synchronized void postSync() {
// Only post if a sync is not pending
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
new file mode 100644
index 0000000..ae560fb
--- /dev/null
+++ b/core/java/android/webkit/WebStorage.java
@@ -0,0 +1,311 @@
+/*
+ * 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.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * 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 the origins, quotas and usages as member values
+ // that we protect via a lock and update in syncValues().
+ // This is needed to transfer this data across threads.
+ private static Lock mLock = new ReentrantLock();
+ private static Condition mUpdateCondition = mLock.newCondition();
+ private static boolean mUpdateAvailable;
+
+ // 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 Set <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 static 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());
+ } break;
+
+ case DELETE_ORIGIN: {
+ Origin website = (Origin) msg.obj;
+ nativeDeleteOrigin(website.getOrigin());
+ } break;
+
+ case DELETE_ALL:
+ nativeDeleteAllData();
+ break;
+
+ case UPDATE:
+ syncValues();
+ break;
+ }
+ }
+ };
+ }
+ }
+
+ /**
+ * @hide
+ * Returns a list of origins having a database
+ */
+ public Set getOrigins() {
+ Set ret = null;
+ mLock.lock();
+ try {
+ mUpdateAvailable = false;
+ update();
+ while (!mUpdateAvailable) {
+ mUpdateCondition.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 {
+ mUpdateAvailable = false;
+ update();
+ while (!mUpdateAvailable) {
+ mUpdateCondition.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 {
+ mUpdateAvailable = false;
+ update();
+ while (!mUpdateAvailable) {
+ mUpdateCondition.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) {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ nativeSetQuotaForOrigin(origin, quota);
+ } else {
+ postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
+ new Origin(origin, quota)));
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Delete a given origin
+ */
+ public void deleteOrigin(String origin) {
+ if (origin != null) {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ nativeDeleteOrigin(origin);
+ } else {
+ postMessage(Message.obtain(null, DELETE_ORIGIN,
+ new Origin(origin)));
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Delete all databases
+ */
+ public void deleteAllData() {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ nativeDeleteAllData();
+ } else {
+ 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() {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ syncValues();
+ } else {
+ postMessage(Message.obtain(null, UPDATE));
+ }
+ }
+
+ /**
+ * Run on the webcore thread
+ * set the local values with the current ones
+ */
+ private void syncValues() {
+ mLock.lock();
+ Set tmp = nativeGetOrigins();
+ mOrigins = new HashSet<String>();
+ mQuotas.clear();
+ mUsages.clear();
+ Iterator<String> iter = tmp.iterator();
+ while (iter.hasNext()) {
+ String origin = iter.next();
+ mOrigins.add(origin);
+ mQuotas.put(origin, new Long(nativeGetQuotaForOrigin(origin)));
+ mUsages.put(origin, new Long(nativeGetUsageForOrigin(origin)));
+ }
+ mUpdateAvailable = true;
+ mUpdateCondition.signal();
+ mLock.unlock();
+ }
+
+ // Native functions
+ private static native Set 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 nativeDeleteAllData();
+}
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/WebTextView.java b/core/java/android/webkit/WebTextView.java
new file mode 100644
index 0000000..a1f2223
--- /dev/null
+++ b/core/java/android/webkit/WebTextView.java
@@ -0,0 +1,785 @@
+/*
+ * 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.webkit;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+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.text.method.Touch;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputConnection;
+import android.widget.AbsoluteLayout.LayoutParams;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * WebTextView is a specialized version of EditText used by WebView
+ * to overlay html textfields (and textareas) to use our standard
+ * text editing.
+ */
+/* package */ class WebTextView extends AutoCompleteTextView {
+
+ static final String LOGTAG = "webtextview";
+
+ private WebView mWebView;
+ private boolean mSingle;
+ private int mWidthSpec;
+ private int mHeightSpec;
+ private int mNodePointer;
+ // FIXME: This is a hack for blocking unmatched key ups, in particular
+ // on the enter key. The method for blocking unmatched key ups prevents
+ // the shift key from working properly.
+ private boolean mGotEnterDown;
+ private int mMaxLength;
+ // Keep track of the text before the change so we know whether we actually
+ // need to send down the DOM events.
+ private String mPreChange;
+ private Drawable mBackground;
+ // Variables for keeping track of the touch down, to send to the WebView
+ // when a drag starts
+ private float mDragStartX;
+ private float mDragStartY;
+ private long mDragStartTime;
+ private boolean mDragSent;
+ // True if the most recent drag event has caused either the TextView to
+ // scroll or the web page to scroll. Gets reset after a touch down.
+ private boolean mScrolled;
+ // Gets set to true when the the IME jumps to the next textfield. When this
+ // happens, the next time the user hits a key it is okay for the focus
+ // pointer to not match the WebTextView's node pointer
+ private boolean mOkayForFocusNotToMatch;
+ // Whether or not a selection change was generated from webkit. If it was,
+ // we do not need to pass the selection back to webkit.
+ private boolean mFromWebKit;
+ private boolean mGotTouchDown;
+ // Array to store the final character added in onTextChanged, so that its
+ // KeyEvents may be determined.
+ private char[] mCharacter = new char[1];
+ // This is used to reset the length filter when on a textfield
+ // with no max length.
+ // FIXME: This can be replaced with TextView.NO_FILTERS if that
+ // is made public/protected.
+ private static final InputFilter[] NO_FILTERS = new InputFilter[0];
+
+ /**
+ * Create a new WebTextView.
+ * @param context The Context for this WebTextView.
+ * @param webView The WebView that created this.
+ */
+ /* package */ WebTextView(Context context, WebView webView) {
+ super(context);
+ mWebView = webView;
+ mMaxLength = -1;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.isSystem()) {
+ return super.dispatchKeyEvent(event);
+ }
+ // Treat ACTION_DOWN and ACTION MULTIPLE the same
+ boolean down = event.getAction() != KeyEvent.ACTION_UP;
+ int keyCode = event.getKeyCode();
+
+ 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;
+ }
+ if (!isArrowKey && !mOkayForFocusNotToMatch
+ && mWebView.nativeFocusNodePointer() != mNodePointer) {
+ mWebView.nativeClearCursor();
+ // Do not call remove() here, which hides the soft keyboard. If
+ // the soft keyboard is being displayed, the user will still want
+ // it there.
+ mWebView.removeView(this);
+ mWebView.requestFocus();
+ return mWebView.dispatchKeyEvent(event);
+ }
+ // After a jump to next textfield and the first key press, the cursor
+ // and focus will once again match, so reset this value.
+ mOkayForFocusNotToMatch = false;
+
+ 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
+ // go ahead and pass the key down immediately.
+ if (KeyEvent.KEYCODE_DEL == keyCode && 0 == oldLength) {
+ sendDomEvent(event);
+ return true;
+ }
+
+ if ((mSingle && KeyEvent.KEYCODE_ENTER == keyCode)) {
+ if (isPopupShowing()) {
+ return super.dispatchKeyEvent(event);
+ }
+ if (!down) {
+ // Hide the keyboard, since the user has just submitted this
+ // form. The submission happens thanks to the two calls
+ // to sendDomEvent.
+ InputMethodManager.getInstance(mContext)
+ .hideSoftInputFromWindow(getWindowToken(), 0);
+ sendDomEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+ sendDomEvent(event);
+ }
+ return super.dispatchKeyEvent(event);
+ } else if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
+ // Note that this handles center key and trackball.
+ 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();
+ }
+ // Pass to super to handle longpress.
+ return super.dispatchKeyEvent(event);
+ }
+
+ // Ensure there is a layout so arrow keys are handled properly.
+ if (getLayout() == null) {
+ measure(mWidthSpec, mHeightSpec);
+ }
+ int oldStart = Selection.getSelectionStart(text);
+ int oldEnd = Selection.getSelectionEnd(text);
+
+ boolean maxedOut = mMaxLength != -1 && oldLength == mMaxLength;
+ // If we are at max length, and there is a selection rather than a
+ // cursor, we need to store the text to compare later, since the key
+ // may have changed the string.
+ String oldText;
+ if (maxedOut && oldEnd != oldStart) {
+ oldText = text.toString();
+ } else {
+ oldText = "";
+ }
+ if (super.dispatchKeyEvent(event)) {
+ // 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.
+
+ // UNLESS there is a max length determined by the html. In that
+ // case, if the string was already at the max length, an
+ // alphanumeric key will be erased by the LengthFilter,
+ // 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.
+ 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) {
+ // Return true so the key gets dropped.
+ return true;
+ } else if (!oldText.equals(getText().toString())) {
+ // FIXME: This makes the text work properly, but it
+ // does not pass down the key event, so it may not
+ // work for a textfield that has the type of
+ // behavior of GoogleSuggest. That said, it is
+ // unlikely that a site would combine the two in
+ // one textfield.
+ Spannable span = (Spannable) getText();
+ int newStart = Selection.getSelectionStart(span);
+ int newEnd = Selection.getSelectionEnd(span);
+ mWebView.replaceTextfieldText(0, oldLength, span.toString(),
+ newStart, newEnd);
+ 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);
+ }
+ */
+ return true;
+ }
+ // 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 (isArrowKey) {
+ // WebView check the trackballtime in onKeyDown to avoid calling
+ // 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
+ .onKeyUp(keyCode, event);
+ }
+ return false;
+ }
+
+ /**
+ * 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 WebTextView actually hit it, so that it can place
+ * the cursor accordingly.
+ */
+ /* package */ void fakeTouchEvent(float x, float y) {
+ // We need to ensure that there is a Layout, since the Layout is used
+ // in determining where to place the cursor.
+ if (getLayout() == null) {
+ measure(mWidthSpec, mHeightSpec);
+ }
+ // Create a fake touch up, which is used to place the cursor.
+ MotionEvent ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP,
+ x, y, 0);
+ onTouchEvent(ev);
+ ev.recycle();
+ }
+
+ /**
+ * Determine whether this WebTextView currently represents the node
+ * represented by ptr.
+ * @param ptr Pointer to a node to compare to.
+ * @return boolean Whether this WebTextView already represents the node
+ * pointed to by ptr.
+ */
+ /* package */ boolean isSameTextField(int ptr) {
+ return ptr == mNodePointer;
+ }
+
+ @Override public InputConnection onCreateInputConnection(
+ EditorInfo outAttrs) {
+ InputConnection connection = super.onCreateInputConnection(outAttrs);
+ if (mWebView != null) {
+ // Use the name of the textfield + the url. Use backslash as an
+ // arbitrary separator.
+ outAttrs.fieldName = mWebView.nativeFocusCandidateName() + "\\"
+ + mWebView.getUrl();
+ }
+ return connection;
+ }
+
+ @Override
+ public void onEditorAction(int actionCode) {
+ switch (actionCode) {
+ case EditorInfo.IME_ACTION_NEXT:
+ mWebView.nativeMoveCursorToNextTextInput();
+ // Preemptively rebuild the WebTextView, so that the action will
+ // be set properly.
+ mWebView.rebuildWebTextView();
+ // Since the cursor will no longer be in the same place as the
+ // focus, set the focus controller back to inactive
+ mWebView.setFocusControllerInactive();
+ mOkayForFocusNotToMatch = true;
+ break;
+ case EditorInfo.IME_ACTION_DONE:
+ super.onEditorAction(actionCode);
+ break;
+ case EditorInfo.IME_ACTION_GO:
+ // Send an enter and hide the soft keyboard
+ InputMethodManager.getInstance(mContext)
+ .hideSoftInputFromWindow(getWindowToken(), 0);
+ sendDomEvent(new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_ENTER));
+ sendDomEvent(new KeyEvent(KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_ENTER));
+
+ default:
+ break;
+ }
+ }
+
+ @Override
+ protected void onSelectionChanged(int selStart, int selEnd) {
+ if (!mFromWebKit && mWebView != null) {
+ if (DebugFlags.WEB_TEXT_VIEW) {
+ Log.v(LOGTAG, "onSelectionChanged selStart=" + selStart
+ + " selEnd=" + selEnd);
+ }
+ mWebView.setSelection(selStart, selEnd);
+ }
+ }
+
+ @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
+ // limit on text length from registering the onTextChanged event.
+ if (mPreChange == null || mPreChange.equals(postChange) ||
+ (mMaxLength > -1 && mPreChange.length() > mMaxLength &&
+ mPreChange.substring(0, mMaxLength).equals(postChange))) {
+ return;
+ }
+ mPreChange = postChange;
+ // 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
+ updateCachedTextfield();
+ return;
+ }
+ // Find the last character being replaced. If it can be represented by
+ // events, we will pass them to native (after replacing the beginning
+ // of the changed text), so we can see javascript events.
+ // Otherwise, replace the text being changed (including the last
+ // character) in the textfield.
+ TextUtils.getChars(s, start + count - 1, start + count, mCharacter, 0);
+ KeyCharacterMap kmap =
+ KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
+ KeyEvent[] events = kmap.getEvents(mCharacter);
+ boolean cannotUseKeyEvents = null == events;
+ int charactersFromKeyEvents = cannotUseKeyEvents ? 0 : 1;
+ if (count > 1 || cannotUseKeyEvents) {
+ String replace = s.subSequence(start,
+ start + count - charactersFromKeyEvents).toString();
+ mWebView.replaceTextfieldText(start, start + before, replace,
+ start + count - charactersFromKeyEvents,
+ start + count - charactersFromKeyEvents);
+ } else {
+ // This corrects the selection which may have been affected by the
+ // trackball or auto-correct.
+ if (DebugFlags.WEB_TEXT_VIEW) {
+ Log.v(LOGTAG, "onTextChanged start=" + start
+ + " start + before=" + (start + before));
+ }
+ mWebView.setSelection(start, start + before);
+ }
+ 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 onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ super.onTouchEvent(event);
+ // This event may be the start of a drag, so store it to pass to the
+ // WebView if it is.
+ mDragStartX = event.getX();
+ mDragStartY = event.getY();
+ mDragStartTime = event.getEventTime();
+ mDragSent = false;
+ mScrolled = false;
+ mGotTouchDown = true;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ Spannable buffer = getText();
+ int initialScrollX = Touch.getInitialScrollX(this, buffer);
+ int initialScrollY = Touch.getInitialScrollY(this, buffer);
+ super.onTouchEvent(event);
+ if (mScrollX != initialScrollX
+ || mScrollY != initialScrollY) {
+ if (mWebView != null) {
+ mWebView.scrollFocusedTextInput(mScrollX, mScrollY);
+ }
+ mScrolled = true;
+ return true;
+ }
+ if (mWebView != null) {
+ // Only want to set the initial state once.
+ if (!mDragSent) {
+ mWebView.initiateTextFieldDrag(mDragStartX, mDragStartY,
+ mDragStartTime);
+ mDragSent = true;
+ }
+ boolean scrolled = mWebView.textFieldDrag(event);
+ if (scrolled) {
+ mScrolled = true;
+ cancelLongPress();
+ return true;
+ }
+ }
+ return false;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ if (!mScrolled) {
+ // If the page scrolled, or the TextView scrolled, we do not
+ // want to change the selection
+ cancelLongPress();
+ if (mGotTouchDown && mWebView != null) {
+ mWebView.touchUpOnTextField(event);
+ }
+ }
+ // Necessary for the WebView to reset its state
+ if (mWebView != null && mDragSent) {
+ mWebView.onTouchEvent(event);
+ }
+ mGotTouchDown = false;
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event) {
+ if (isPopupShowing()) {
+ return super.onTrackballEvent(event);
+ }
+ 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)) {
+ // Selection is changed in onSelectionChanged
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Remove this WebTextView from its host WebView, and return
+ * focus to the host.
+ */
+ /* package */ void remove() {
+ // hide the soft keyboard when the edit text is out of focus
+ InputMethodManager.getInstance(mContext).hideSoftInputFromWindow(
+ getWindowToken(), 0);
+ mWebView.removeView(this);
+ mWebView.requestFocus();
+ }
+
+ /* package */ void bringIntoView() {
+ if (getLayout() != null) {
+ bringPointIntoView(Selection.getSelectionEnd(getText()));
+ }
+ }
+
+ /**
+ * Send the DOM events for the specified event.
+ * @param event KeyEvent to be translated into a DOM event.
+ */
+ private void sendDomEvent(KeyEvent event) {
+ mWebView.passToJavaScript(getText().toString(), event);
+ }
+
+ /**
+ * Always use this instead of setAdapter, as this has features specific to
+ * the WebTextView.
+ */
+ public void setAdapterCustom(AutoCompleteAdapter adapter) {
+ if (adapter != null) {
+ setInputType(EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE);
+ adapter.setTextView(this);
+ }
+ super.setAdapter(adapter);
+ }
+
+ /**
+ * This is a special version of ArrayAdapter which changes its text size
+ * to match the text size of its host TextView.
+ */
+ public static class AutoCompleteAdapter extends ArrayAdapter<String> {
+ private TextView mTextView;
+
+ public AutoCompleteAdapter(Context context, ArrayList<String> entries) {
+ super(context, com.android.internal.R.layout
+ .search_dropdown_item_1line, entries);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView tv =
+ (TextView) super.getView(position, convertView, parent);
+ if (tv != null && mTextView != null) {
+ tv.setTextSize(mTextView.getTextSize());
+ }
+ return tv;
+ }
+
+ /**
+ * Set the TextView so we can match its text size.
+ */
+ private void setTextView(TextView tv) {
+ mTextView = tv;
+ }
+ }
+
+ /**
+ * Determine whether to use the system-wide password disguising method,
+ * or to use none.
+ * @param inPassword True if the textfield is a password field.
+ */
+ /* package */ void setInPassword(boolean inPassword) {
+ if (inPassword) {
+ setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.
+ TYPE_TEXT_VARIATION_PASSWORD);
+ createBackground();
+ }
+ // For password fields, draw the WebTextView. For others, just show
+ // webkit's drawing.
+ setWillNotDraw(!inPassword);
+ setBackgroundDrawable(inPassword ? mBackground : null);
+ // For non-password fields, avoid the invals from TextView's blinking
+ // cursor
+ setCursorVisible(inPassword);
+ }
+
+ /**
+ * Private class used for the background of a password textfield.
+ */
+ private static class OutlineDrawable extends Drawable {
+ public void draw(Canvas canvas) {
+ Rect bounds = getBounds();
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ // Draw the background.
+ paint.setColor(Color.WHITE);
+ canvas.drawRect(bounds, paint);
+ // Draw the outline.
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(Color.BLACK);
+ canvas.drawRect(bounds, paint);
+ }
+ // Always want it to be opaque.
+ public int getOpacity() {
+ return PixelFormat.OPAQUE;
+ }
+ // These are needed because they are abstract in Drawable.
+ public void setAlpha(int alpha) { }
+ public void setColorFilter(ColorFilter cf) { }
+ }
+
+ /**
+ * Create a background for the WebTextView and set up the paint for drawing
+ * the text. This way, we can see the password transformation of the
+ * system, which (optionally) shows the actual text before changing to dots.
+ * The background is necessary to hide the webkit-drawn text beneath.
+ */
+ private void createBackground() {
+ if (mBackground != null) {
+ return;
+ }
+ mBackground = new OutlineDrawable();
+
+ setGravity(Gravity.CENTER_VERTICAL);
+ // 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 password textfields.
+ setTextColor(Color.BLACK);
+ }
+
+ /* package */ void setMaxLength(int maxLength) {
+ mMaxLength = maxLength;
+ if (-1 == maxLength) {
+ setFilters(NO_FILTERS);
+ } else {
+ setFilters(new InputFilter[] {
+ new InputFilter.LengthFilter(maxLength) });
+ }
+ }
+
+ /**
+ * Set the pointer for this node so it can be determined which node this
+ * WebTextView represents.
+ * @param ptr Integer representing the pointer to the node which this
+ * WebTextView represents.
+ */
+ /* package */ void setNodePointer(int ptr) {
+ mNodePointer = ptr;
+ }
+
+ /**
+ * 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.
+ * @param x x-position of the textfield.
+ * @param y y-position of the textfield.
+ * @param width width of the textfield.
+ * @param height height of the textfield.
+ */
+ /* package */ void setRect(int x, int y, int width, int height) {
+ LayoutParams lp = (LayoutParams) getLayoutParams();
+ if (null == lp) {
+ lp = new LayoutParams(width, height, x, y);
+ } else {
+ lp.x = x;
+ lp.y = y;
+ lp.width = width;
+ lp.height = height;
+ }
+ if (getParent() == null) {
+ mWebView.addView(this, lp);
+ } else {
+ setLayoutParams(lp);
+ }
+ // Set up a measure spec so a layout can always be recreated.
+ mWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ mHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ requestFocus();
+ }
+
+ /**
+ * Set the selection, and disable our onSelectionChanged action.
+ */
+ /* package */ void setSelectionFromWebKit(int start, int end) {
+ mFromWebKit = true;
+ Selection.setSelection((Spannable) getText(), start, end);
+ mFromWebKit = false;
+ }
+
+ /**
+ * Set whether this is a single-line textfield or a multi-line textarea.
+ * Textfields scroll horizontally, and do not handle the enter key.
+ * Textareas behave oppositely.
+ * Do NOT call this after calling setInPassword(true). This will result in
+ * removing the password input type.
+ */
+ public void setSingleLine(boolean single) {
+ int inputType = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
+ if (single) {
+ int action = mWebView.nativeTextFieldAction();
+ switch (action) {
+ // Keep in sync with CachedRoot::ImeAction
+ case 0: // NEXT
+ setImeOptions(EditorInfo.IME_ACTION_NEXT);
+ break;
+ case 1: // GO
+ setImeOptions(EditorInfo.IME_ACTION_GO);
+ break;
+ case -1: // FAILURE
+ case 2: // DONE
+ setImeOptions(EditorInfo.IME_ACTION_DONE);
+ break;
+ }
+ } else {
+ inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
+ | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
+ setImeOptions(EditorInfo.IME_ACTION_NONE);
+ }
+ mSingle = single;
+ setHorizontallyScrolling(single);
+ setInputType(inputType);
+ }
+
+ /**
+ * 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.
+ */
+ /* package */ void setText(CharSequence text, int start, int end) {
+ mPreChange = text.toString();
+ setText(text);
+ Spannable span = (Spannable) getText();
+ int length = span.length();
+ if (end > length) {
+ end = length;
+ }
+ if (start < 0) {
+ start = 0;
+ } else if (start > length) {
+ start = length;
+ }
+ if (DebugFlags.WEB_TEXT_VIEW) {
+ Log.v(LOGTAG, "setText start=" + start
+ + " end=" + end);
+ }
+ Selection.setSelection(span, start, end);
+ }
+
+ /**
+ * Set the text to the new string, but use the old selection, making sure
+ * to keep it within the new string.
+ * @param text The new text to place in the textfield.
+ */
+ /* package */ void setTextAndKeepSelection(String text) {
+ mPreChange = text.toString();
+ Editable edit = (Editable) getText();
+ edit.replace(0, edit.length(), text);
+ updateCachedTextfield();
+ }
+
+ /**
+ * Update the cache to reflect the current text.
+ */
+ /* package */ void updateCachedTextfield() {
+ mWebView.updateCachedTextfield(getText().toString());
+ }
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6936435..e39e3f1 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;
@@ -80,11 +80,10 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
-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 +92,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,62 +204,61 @@ 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)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(com.android.internal.R.layout.zoom_magnify, this, true);
- mZoomControls = (ZoomControls) findViewById(com.android.internal.R.id.zoomControls);
+ mPlusMinusZoomControls = (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);
+ mPlusMinusZoomControls.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();
+ return mPlusMinusZoomControls.hasFocus() || mZoomMagnify.hasFocus();
}
-
+
public void setOnZoomInClickListener(OnClickListener listener) {
- mZoomControls.setOnZoomInClickListener(listener);
+ mPlusMinusZoomControls.setOnZoomInClickListener(listener);
}
-
+
public void setOnZoomOutClickListener(OnClickListener listener) {
- mZoomControls.setOnZoomOutClickListener(listener);
+ mPlusMinusZoomControls.setOnZoomOutClickListener(listener);
}
-
+
public void setOnZoomMagnifyClickListener(OnClickListener listener) {
mZoomMagnify.setOnClickListener(listener);
}
- ZoomControls mZoomControls;
- ImageView mZoomMagnify;
+ ZoomControls mPlusMinusZoomControls;
+ ImageView mZoomMagnify;
}
-
+
/**
* Transportation object for returning WebView across thread boundaries.
*/
@@ -203,13 +298,13 @@ 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;
- // The list of loaded plugins.
- private static PluginList sPluginList;
+ // Used by WebViewCore to create child views.
+ /* package */ final ViewManager mViewManager;
/**
* Position of the last touch event.
@@ -229,9 +324,18 @@ public class WebView extends AbsoluteLayout
/**
* The minimum elapsed time before sending another ACTION_MOVE event to
- * WebViewCore
+ * WebViewCore. This really should be tuned for each type of the devices.
+ * For example in Google Map api test case, it takes Dream device at least
+ * 150ms to do a full cycle in the WebViewCore by processing a touch event,
+ * triggering the layout and drawing the picture. While the same process
+ * takes 60+ms on the current high speed device. If we make
+ * TOUCH_SENT_INTERVAL too small, there will be multiple touch events sent
+ * to WebViewCore queue and the real layout and draw events will be pushed
+ * to further, which slows down the refresh rate. Choose 50 to favor the
+ * current high speed devices. For Dream like devices, 100 is a better
+ * choice. Maybe make this in the buildspec later.
*/
- private static final int TOUCH_SENT_INTERVAL = 100;
+ private static final int TOUCH_SENT_INTERVAL = 50;
/**
* Helper class to get velocity for fling
@@ -239,6 +343,9 @@ public class WebView extends AbsoluteLayout
VelocityTracker mVelocityTracker;
private int mMaximumFling;
+ // use this flag to control whether enabling the new double tap zoom
+ static final boolean ENABLE_DOUBLETAP_ZOOM = true;
+
/**
* Touch mode
*/
@@ -258,6 +365,7 @@ public class WebView extends AbsoluteLayout
private static final int SCROLL_ZOOM_OUT = 11;
private static final int LAST_SCROLL_ZOOM = 11;
// end of touch mode values specific to scale+scroll
+ private static final int TOUCH_DOUBLE_TAP_MODE = 12;
// Whether to forward the touch events to WebCore
private boolean mForwardTouchEvents = false;
@@ -267,18 +375,23 @@ 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
- // 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;
+ // To keep track of whether the current drag was initiated by a WebTextView,
+ // so that we know not to hide the cursor
+ boolean mDragFromTextInput;
+
+ // 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
*/
// pre-computed square of ViewConfiguration.getScaledTouchSlop()
private int mTouchSlopSquare;
+ // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop()
+ private int mDoubleTapSlopSquare;
// pre-computed density adjusted navigation slop
private int mNavSlop;
// This should be ViewConfiguration.getTapTimeout()
@@ -292,7 +405,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.
@@ -313,7 +426,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;
@@ -328,51 +441,49 @@ 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 RELEASE_SINGLE_TAP = 5;
+ 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 MOVE_OUT_OF_PLUGIN = 19;
+ static final int CLEAR_TEXT_ENTRY = 20;
+ static final int UPDATE_TEXT_SELECTION_MSG_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 int REQUEST_KEYBOARD = 27;
+
static final String[] HandlerDebugString = {
- "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;
+ "REMEMBER_PASSWORD", // = 1;
+ "NEVER_REMEMBER_PASSWORD", // = 2;
+ "SWITCH_TO_SHORTPRESS", // = 3;
+ "SWITCH_TO_LONGPRESS", // = 4;
+ "RELEASE_SINGLE_TAP", // = 5;
+ "REQUEST_FORM_DATA", // = 6;
+ "SWITCH_TO_CLICK", // = 7;
+ "RESUME_WEBCORE_UPDATE", // = 8;
"9",
"SCROLL_TO_MSG_ID", // = 10;
"SCROLL_BY_MSG_ID", // = 11;
@@ -382,31 +493,82 @@ public class WebView extends AbsoluteLayout
"UPDATE_TEXT_ENTRY_MSG_ID", // = 15;
"WEBCORE_INITIALIZED_MSG_ID", // = 16;
"UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 17;
- "DID_FIRST_LAYOUT_MSG_ID", // = 18;
- "RECOMPUTE_FOCUS_MSG_ID", // = 19;
- "NOTIFY_FOCUS_SET_MSG_ID", // = 20;
- "MARK_NODE_INVALID_ID", // = 21;
+ "18", // = 18;
+ "MOVE_OUT_OF_PLUGIN", // = 19;
+ "CLEAR_TEXT_ENTRY", // = 20;
+ "UPDATE_TEXT_SELECTION_MSG_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;
+ "INVAL_RECT_MSG_ID", // = 26;
+ "REQUEST_KEYBOARD" // = 27;
};
- // width which view is considered to be fully zoomed out
- static final int ZOOM_OUT_WIDTH = 1008;
-
// default scale limit. Depending on the display density
private static float DEFAULT_MAX_ZOOM_SCALE;
private static float DEFAULT_MIN_ZOOM_SCALE;
// scale limit, which can be set through viewport meta tag in the web page
private float mMaxZoomScale;
private float mMinZoomScale;
- private boolean mMinZoomScaleFixed = false;
+ private boolean mMinZoomScaleFixed = true;
// initial scale in percent. 0 means using default.
private int mInitialScale = 0;
+ // while in the zoom overview mode, the page's width is fully fit to the
+ // current window. The page is alive, in another words, you can click to
+ // follow the links. Double tap will toggle between zoom overview mode and
+ // the last zoom scale.
+ boolean mInZoomOverview = false;
+
+ // The viewing mode of this webview. Reported back to the WebChromeClient
+ // so we can hide and display the title bar as appropriate.
+ private int mViewingMode;
+ /**
+ * Not supporting overview vs reading mode
+ * @hide
+ */
+ public final static int NO_VIEWING_MODE = 0;
+ /**
+ * Zoom overview mode. The page is zoomed all the way out, mInZoomOverview
+ * is true, and the title bar is showing. Double tapping will change to
+ * reading mode.
+ * @hide
+ */
+ public final static int OVERVIEW_MODE = 1;
+ /**
+ * Reading mode. The page is at the level specified by the user,
+ * mInZoomOverview is false, and the title bar is not showing. Double
+ * tapping will change to zoom overview mode.
+ * @hide
+ */
+ public final static int READING_MODE = 2;
+ /**
+ * Modified reading mode, which shows the title bar. mInZoomOverview is
+ * false, and double tapping will change to zoom overview mode. However,
+ * if the scrolling will change to reading mode. Used when swiping a
+ * tab into view which was in reading mode, unless it was a mobile site
+ * with zero scroll.
+ * @hide
+ */
+ public final static int READING_MODE_WITH_TITLE_BAR = 3;
+ /**
+ * Another modified reading mode. For loading a mobile site, or swiping a
+ * tab into view which was displaying a mobile site in reading mode
+ * with zero scroll
+ * @hide
+ */
+ public final static int TITLE_BAR_DISMISS_MODE = 4;
+ // Whether the current site is a mobile site. Determined when we receive
+ // NEW_PICTURE_MSG_ID to help determine how to handle double taps
+ private boolean mMobileSite;
+
+ // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
+ // engadget always have wider mContentWidth no matter what viewport size is.
+ int mZoomOverviewWidth = WebViewCore.DEFAULT_VIEWPORT_WIDTH;
+ float mLastScale;
+
// default scale. Depending on the display density.
static int DEFAULT_SCALE_PERCENT;
private float mDefaultScale;
@@ -421,6 +583,8 @@ public class WebView extends AbsoluteLayout
private float mZoomScale;
private float mInvInitialZoomScale;
private float mInvFinalZoomScale;
+ private int mInitialScrollX;
+ private int mInitialScrollY;
private long mZoomStart;
private static final int ZOOM_ANIMATION_LENGTH = 500;
@@ -433,7 +597,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;
@@ -456,7 +620,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.
@@ -473,7 +637,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
*/
@@ -543,8 +708,7 @@ public class WebView extends AbsoluteLayout
private ExtendedZoomControls mZoomControls;
private Runnable mZoomControlRunnable;
- private ZoomButtonsController mZoomButtonsController;
- private ImageView mZoomOverviewButton;
+ private ZoomButtonsController mZoomButtonsController;
// These keep track of the center point of the zoom. They are used to
// determine the point around which we should zoom.
@@ -567,11 +731,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.
@@ -602,18 +766,10 @@ 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);
- }
+ mViewManager = new ViewManager(this);
- private void initZoomController(Context context) {
- // Create the buttons controller
mZoomButtonsController = new ZoomButtonsController(this);
mZoomButtonsController.setOnZoomListener(mZoomListener);
// ZoomButtonsController positions the buttons at the bottom, but in
@@ -626,30 +782,11 @@ public class WebView extends AbsoluteLayout
params;
frameParams.gravity = Gravity.RIGHT;
}
-
- // Create the accessory buttons
- LayoutInflater inflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- ViewGroup container = mZoomButtonsController.getContainer();
- inflater.inflate(com.android.internal.R.layout.zoom_browser_accessory_buttons, container);
- mZoomOverviewButton =
- (ImageView) container.findViewById(com.android.internal.R.id.zoom_page_overview);
- mZoomOverviewButton.setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- mZoomButtonsController.setVisible(false);
- zoomScrollOut();
- if (mLogEvent) {
- Checkin.updateStats(mContext.getContentResolver(),
- Checkin.Stats.Tag.BROWSER_ZOOM_OVERVIEW, 1, 0.0);
- }
- }
- });
}
private void updateZoomButtonsEnabled() {
boolean canZoomIn = mActualScale < mMaxZoomScale;
- boolean canZoomOut = mActualScale > mMinZoomScale;
+ boolean canZoomOut = mActualScale > mMinZoomScale && !mInZoomOverview;
if (!canZoomIn && !canZoomOut) {
// Hide the zoom in and out buttons, as well as the fit to page
// button, if the page cannot zoom
@@ -663,8 +800,6 @@ public class WebView extends AbsoluteLayout
mZoomButtonsController.setZoomInEnabled(canZoomIn);
mZoomButtonsController.setZoomOutEnabled(canZoomOut);
}
- mZoomOverviewButton.setVisibility(canZoomScrollOut() ? View.VISIBLE:
- View.GONE);
}
private void init() {
@@ -675,9 +810,11 @@ public class WebView extends AbsoluteLayout
setLongClickable(true);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
- final int slop = configuration.getScaledTouchSlop();
+ int slop = configuration.getScaledTouchSlop();
mTouchSlopSquare = slop * slop;
mMinLockSnapReverseDistance = slop;
+ slop = configuration.getScaledDoubleTapSlop();
+ mDoubleTapSlopSquare = slop * slop;
final float density = getContext().getResources().getDisplayMetrics().density;
// use one line height, 16 based on our current default font, for how
// far we allow a touch be away from the edge of a link
@@ -899,7 +1036,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
@@ -930,12 +1067,23 @@ 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();
}
-
+
+ /**
+ * Sets JavaScript engine flags.
+ *
+ * @param flags JS engine flags in a String
+ *
+ * @hide pending API solidification
+ */
+ public void setJsFlags(String flags) {
+ mWebViewCore.sendMessage(EventHub.SET_JS_FLAGS, flags);
+ }
+
/**
* Inform WebView of the network state. This is used to set
* the javascript property window.navigator.isOnline and
@@ -948,7 +1096,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
@@ -1026,6 +1174,10 @@ public class WebView extends AbsoluteLayout
b.putInt("scrollX", mScrollX);
b.putInt("scrollY", mScrollY);
b.putFloat("scale", mActualScale);
+ if (mInZoomOverview) {
+ b.putFloat("lastScale", mLastScale);
+ }
+ b.putBoolean("mobile", mMobileSite);
return true;
}
return false;
@@ -1070,6 +1222,21 @@ public class WebView extends AbsoluteLayout
// onSizeChanged() is called, the rest will be set
// correctly
mActualScale = scale;
+ float lastScale = b.getFloat("lastScale", -1.0f);
+ mMobileSite = b.getBoolean("mobile", false);
+ if (lastScale > 0) {
+ mInZoomOverview = true;
+ mViewingMode = OVERVIEW_MODE;
+ mLastScale = lastScale;
+ } else {
+ mInZoomOverview = false;
+ if (mMobileSite && (mScrollX | mScrollY) == 0) {
+ mViewingMode = TITLE_BAR_DISMISS_MODE;
+ } else {
+ mViewingMode = READING_MODE_WITH_TITLE_BAR;
+ }
+ }
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
invalidate();
return true;
}
@@ -1079,10 +1246,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.
@@ -1143,6 +1310,9 @@ public class WebView extends AbsoluteLayout
* @param url The url of the resource to load.
*/
public void loadUrl(String url) {
+ if (url == null) {
+ return;
+ }
switchOutDrawHistory();
mWebViewCore.sendMessage(EventHub.LOAD_URL, url);
clearTextEntry();
@@ -1152,18 +1322,16 @@ 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);
+ WebViewCore.PostUrlData arg = new WebViewCore.PostUrlData();
+ arg.mUrl = url;
+ arg.mPostData = postData;
mWebViewCore.sendMessage(EventHub.POST_URL, arg);
clearTextEntry();
} else {
@@ -1197,7 +1365,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.
@@ -1208,18 +1376,18 @@ 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;
}
switchOutDrawHistory();
- HashMap arg = new HashMap();
- arg.put("baseUrl", baseUrl);
- arg.put("data", data);
- arg.put("mimeType", mimeType);
- arg.put("encoding", encoding);
- arg.put("failUrl", failUrl);
+ WebViewCore.BaseUrlData arg = new WebViewCore.BaseUrlData();
+ arg.mBaseUrl = baseUrl;
+ arg.mData = data;
+ arg.mMimeType = mimeType;
+ arg.mEncoding = encoding;
+ arg.mFailUrl = failUrl;
mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
clearTextEntry();
}
@@ -1329,7 +1497,7 @@ public class WebView extends AbsoluteLayout
ignoreSnapshot ? 1 : 0);
}
}
-
+
private boolean extendScroll(int y) {
int finalY = mScroller.getFinalY();
int newY = pinLocY(finalY + y);
@@ -1338,7 +1506,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
@@ -1348,7 +1516,7 @@ public class WebView extends AbsoluteLayout
if (mNativeClass == 0) {
return false;
}
- nativeClearFocus(-1, -1);
+ nativeClearCursor(); // start next trackball movement from page edge
if (top) {
// go to the top of the document
return pinScrollTo(mScrollX, 0, true, 0);
@@ -1362,10 +1530,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
@@ -1375,7 +1543,7 @@ public class WebView extends AbsoluteLayout
if (mNativeClass == 0) {
return false;
}
- nativeClearFocus(-1, -1);
+ nativeClearCursor(); // start next trackball movement from page edge
if (bottom) {
return pinScrollTo(mScrollX, mContentHeight, true, 0);
}
@@ -1388,7 +1556,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);
}
@@ -1401,7 +1569,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
@@ -1412,7 +1580,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();
}
@@ -1420,17 +1588,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.
*/
@@ -1471,7 +1639,7 @@ public class WebView extends AbsoluteLayout
}
/**
- * Return a HitTestResult based on the current focus node. If a HTML::a tag
+ * Return a HitTestResult based on the current cursor node. If a HTML::a tag
* is found and the anchor has a non-javascript url, the HitTestResult type
* is set to SRC_ANCHOR_TYPE and the url is set in the "extra" field. If the
* anchor does not have a url or if it is a javascript url, the type will
@@ -1494,26 +1662,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);
+ }
}
}
}
@@ -1525,8 +1693,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);
}
@@ -1538,31 +1706,29 @@ 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.
*/
+ // FIXME: API change required to change the name of this function. We now
+ // look at the cursor node, and not the focus node. Also, what is
+ // getFocusNodePath?
public void requestFocusNodeHref(Message hrefMsg) {
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()) {
+ mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_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.
*/
@@ -1606,7 +1772,7 @@ public class WebView extends AbsoluteLayout
return Math.round(x * mInvActualScale);
}
- private int contentToView(int x) {
+ /*package*/ int contentToView(int x) {
return Math.round(x * mActualScale);
}
@@ -1637,7 +1803,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
@@ -1697,7 +1863,10 @@ public class WebView extends AbsoluteLayout
mActualScale = scale;
mInvActualScale = 1 / scale;
- // as we don't have animation for scaling, don't do animation
+ // Scale all the child views
+ mViewManager.scaleAll();
+
+ // 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));
@@ -1718,18 +1887,21 @@ public class WebView extends AbsoluteLayout
private Rect sendOurVisibleRect() {
Rect rect = new Rect();
calcOurContentVisibleRect(rect);
- if (mFindIsUp) {
- rect.bottom -= viewToContent(FIND_HEIGHT);
- }
// Rect.equals() checks for null input.
if (!rect.equals(mLastVisibleRectSent)) {
+ Point pos = new Point(rect.left, rect.top);
mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
- rect.left, rect.top);
+ nativeMoveGeneration(), 0, pos);
mLastVisibleRectSent = rect;
}
Rect globalRect = new Rect();
if (getGlobalVisibleRect(globalRect)
&& !globalRect.equals(mLastGlobalRect)) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "sendOurVisibleRect=(" + globalRect.left + ","
+ + globalRect.top + ",r=" + globalRect.right + ",b="
+ + globalRect.bottom);
+ }
// TODO: the global offset is only used by windowRect()
// in ChromeClientAndroid ; other clients such as touch
// and mouse events could return view + screen relative points.
@@ -1744,6 +1916,9 @@ public class WebView extends AbsoluteLayout
Point p = new Point();
getGlobalVisibleRect(r, p);
r.offset(-p.x, -p.y);
+ if (mFindIsUp) {
+ r.bottom -= FIND_HEIGHT;
+ }
}
// Sets r to be our visible rectangle in content coordinates
@@ -1755,6 +1930,14 @@ public class WebView extends AbsoluteLayout
r.bottom = viewToContent(r.bottom);
}
+ static class ViewSizeData {
+ int mWidth;
+ int mHeight;
+ int mTextWrapWidth;
+ float mScale;
+ boolean mIgnoreHeight;
+ }
+
/**
* Compute unzoomed width and height, and if they differ from the last
* values we sent, send them to webkit (to be used has new viewport)
@@ -1762,7 +1945,8 @@ public class WebView extends AbsoluteLayout
* @return true if new values were sent
*/
private boolean sendViewSizeZoom() {
- int newWidth = Math.round(getViewWidth() * mInvActualScale);
+ int viewWidth = getViewWidth();
+ int newWidth = Math.round(viewWidth * mInvActualScale);
int newHeight = Math.round(getViewHeight() * mInvActualScale);
/*
* Because the native side may have already done a layout before the
@@ -1777,8 +1961,17 @@ public class WebView extends AbsoluteLayout
}
// Avoid sending another message if the dimensions have not changed.
if (newWidth != mLastWidthSent || newHeight != mLastHeightSent) {
- mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED,
- newWidth, newHeight, new Float(mActualScale));
+ ViewSizeData data = new ViewSizeData();
+ data.mWidth = newWidth;
+ data.mHeight = newHeight;
+ // while in zoom overview mode, the text are wrapped to the screen
+ // width matching mLastScale. So that we don't trigger re-flow while
+ // toggling between overview mode and normal mode.
+ data.mTextWrapWidth = mInZoomOverview ? Math.round(viewWidth
+ / mLastScale) : newWidth;
+ data.mScale = mActualScale;
+ data.mIgnoreHeight = mZoomScale != 0 && !mHeightCanMeasure;
+ mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED, data);
mLastWidthSent = newWidth;
mLastHeightSent = newHeight;
return true;
@@ -1821,10 +2014,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.
@@ -1856,13 +2049,22 @@ public class WebView extends AbsoluteLayout
}
/**
+ * Get the touch icon url for the apple-touch-icon <link> element.
+ * @hide
+ */
+ public String getTouchIconUrl() {
+ WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
+ return h != null ? h.getTouchIconUrl() : null;
+ }
+
+ /**
* Get the progress for the current page.
* @return The progress for the current page between 0 and 100.
*/
public int getProgress() {
return mCallbackProxy.getProgress();
}
-
+
/**
* @return the height of the HTML content.
*/
@@ -1871,30 +2073,77 @@ 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;
+ }
+
+ /**
+ * Call this to inform the view that memory is low so that it can
+ * free any available memory.
+ * @hide
+ */
+ public void freeMemory() {
+ mWebViewCore.sendMessage(EventHub.FREE_MEMORY);
+ }
+
+ /**
+ * 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);
}
@@ -1906,7 +2155,7 @@ public class WebView extends AbsoluteLayout
public void clearFormData() {
if (inEditingMode()) {
AutoCompleteAdapter adapter = null;
- mTextEntry.setAdapterCustom(adapter);
+ mWebTextView.setAdapterCustom(adapter);
}
}
@@ -1940,7 +2189,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.
@@ -1966,11 +2215,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
@@ -1983,14 +2229,40 @@ 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.
*
* @return the address, or if no address is found, return null.
*/
public static String findAddress(String addr) {
- return WebViewCore.nativeFindAddress(addr);
+ return findAddress(addr, false);
+ }
+
+ /**
+ * @hide
+ * 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
+ * - a street name
+ * - a street type (Road, Circle, etc), either spelled out or abbreviated
+ * - a city name
+ * - a state or territory, either spelled out or two-letter abbr.
+ * - an optional 5 digit or 9 digit zip code.
+ *
+ * Names are optionally 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
+ * five digits.
+ * @param addr The string to search for addresses.
+ * @param caseInsensitive addr Set to true to make search ignore case.
+ *
+ * @return the address, or if no address is found, return null.
+ */
+ public static String findAddress(String addr, boolean caseInsensitive) {
+ return WebViewCore.nativeFindAddress(addr, caseInsensitive);
}
/*
@@ -2075,13 +2347,13 @@ public class WebView extends AbsoluteLayout
// Scale from content to view coordinates, and pin.
// Also called by jni webview.cpp
- private void setContentScrollBy(int cx, int cy, boolean animate) {
+ private boolean setContentScrollBy(int cx, int cy, boolean animate) {
if (mDrawHistory) {
// disallow WebView to change the scroll position as History Picture
// is used in the view system.
// TODO: as we switchOutDrawHistory when trackball or navigation
// keys are hit, this should be safe. Right?
- return;
+ return false;
}
cx = contentToView(cx);
cy = contentToView(cy);
@@ -2098,11 +2370,9 @@ public class WebView extends AbsoluteLayout
// FIXME: Why do we only scroll horizontally if there is no
// vertical scroll?
// Log.d(LOGTAG, "setContentScrollBy cy=" + cy);
- if (cy == 0 && cx != 0) {
- pinScrollBy(cx, 0, animate, 0);
- }
+ return cy == 0 && cx != 0 && pinScrollBy(cx, 0, animate, 0);
} else {
- pinScrollBy(cx, cy, animate, 0);
+ return pinScrollBy(cx, cy, animate, 0);
}
}
@@ -2201,6 +2471,16 @@ public class WebView extends AbsoluteLayout
}
/**
+ * Gets the chrome handler.
+ * @return the current WebChromeClient instance.
+ *
+ * @hide API council approval.
+ */
+ public WebChromeClient getWebChromeClient() {
+ return mCallbackProxy.getWebChromeClient();
+ }
+
+ /**
* Set the Picture listener. This is an interface used to receive
* notifications of a new Picture.
* @param listener An implementation of WebView.PictureListener.
@@ -2245,10 +2525,9 @@ public class WebView extends AbsoluteLayout
* @param interfaceName The name to used to expose the class in Javascript
*/
public void addJavascriptInterface(Object obj, String interfaceName) {
- // Use Hashmap rather than Bundle as Bundles can't cope with Objects
- HashMap arg = new HashMap();
- arg.put("object", obj);
- arg.put("interfaceName", interfaceName);
+ WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
+ arg.mObject = obj;
+ arg.mInterfaceName = interfaceName;
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
}
@@ -2265,26 +2544,19 @@ public class WebView extends AbsoluteLayout
/**
* Return the list of currently loaded plugins.
* @return The list of currently loaded plugins.
+ *
+ * @deprecated This was used for Gears, which has been deprecated.
*/
+ @Deprecated
public static synchronized PluginList getPluginList() {
- if (sPluginList == null) {
- sPluginList = new PluginList();
- }
- return sPluginList;
+ return null;
}
/**
- * 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.
+ * @deprecated This was used for Gears, which has been deprecated.
*/
- public void refreshPlugins(boolean reloadOpenPages) {
- if (mWebViewCore != null) {
- mWebViewCore.sendMessage(EventHub.REFRESH_PLUGINS, reloadOpenPages);
- }
- }
+ @Deprecated
+ public void refreshPlugins(boolean reloadOpenPages) { }
//-------------------------------------------------------------------------
// Override View methods
@@ -2292,9 +2564,13 @@ public class WebView extends AbsoluteLayout
@Override
protected void finalize() throws Throwable {
- destroy();
+ try {
+ destroy();
+ } finally {
+ super.finalize();
+ }
}
-
+
@Override
protected void onDraw(Canvas canvas) {
// if mNativeClass is 0, the WebView has been destroyed. Do nothing.
@@ -2303,7 +2579,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);
@@ -2314,22 +2590,21 @@ public class WebView extends AbsoluteLayout
if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
scrollZoomDraw(canvas);
} else {
- nativeRecomputeFocus();
// Update the buttons in the picture, so when we draw the picture
// to the screen, they are in the correct state.
// Tell the native side if user is a) touching the screen,
// b) pressing the trackball down, or c) pressing the enter key
- // If the focus is a button, we need to draw it in the pressed
+ // If the cursor is on a button, we need to draw it in the pressed
// state.
// If mNativeClass is 0, we should not reach here, so we do not
// 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();
}
@@ -2345,15 +2620,23 @@ public class WebView extends AbsoluteLayout
@Override
public boolean performLongClick() {
+ if (mNativeClass != 0 && nativeCursorIsTextInput()) {
+ // Send the click so that the textfield is in focus
+ // FIXME: When we start respecting changes to the native textfield's
+ // selection, need to make sure that this does not change it.
+ mWebViewCore.sendMessage(EventHub.CLICK, nativeCursorFramePointer(),
+ nativeCursorNodePointer());
+ rebuildWebTextView();
+ }
if (inEditingMode()) {
- return mTextEntry.performLongClick();
+ return mWebTextView.performLongClick();
} else {
return super.performLongClick();
}
}
- private void drawCoreAndFocusRing(Canvas canvas, int color,
- boolean drawFocus) {
+ private void drawCoreAndCursorRing(Canvas canvas, int color,
+ boolean drawCursorRing) {
if (mDrawHistory) {
canvas.scale(mActualScale, mActualScale);
canvas.drawPicture(mHistoryPicture);
@@ -2361,14 +2644,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 {
@@ -2376,24 +2659,15 @@ public class WebView extends AbsoluteLayout
// set mZoomScale to be 0 as we have done animation
mZoomScale = 0;
}
- float scale = (mActualScale - zoomScale) * mInvActualScale;
- float tx = scale * (mZoomCenterX + mScrollX);
- float ty = scale * (mZoomCenterY + mScrollY);
-
- // this block pins the translate to "legal" bounds. This makes the
- // animation a bit non-obvious, but it means we won't pop when the
- // "real" zoom takes effect
- if (true) {
- // canvas.translate(mScrollX, mScrollY);
- tx -= mScrollX;
- ty -= mScrollY;
- tx = -pinLoc(-Math.round(tx), getViewWidth(), Math
- .round(mContentWidth * zoomScale));
- ty = -pinLoc(-Math.round(ty), getViewHeight(), Math
- .round(mContentHeight * zoomScale));
- tx += mScrollX;
- ty += mScrollY;
- }
+ float scale = zoomScale * mInvInitialZoomScale;
+ int tx = Math.round(scale * (mInitialScrollX + mZoomCenterX)
+ - mZoomCenterX);
+ tx = -pinLoc(tx, getViewWidth(), Math.round(mContentWidth
+ * zoomScale)) + mScrollX;
+ int ty = Math.round(scale * (mInitialScrollY + mZoomCenterY)
+ - mZoomCenterY);
+ ty = -pinLoc(ty, getViewHeight(), Math.round(mContentHeight
+ * zoomScale)) + mScrollY;
canvas.translate(tx, ty);
canvas.scale(zoomScale, zoomScale);
} else {
@@ -2408,10 +2682,10 @@ public class WebView extends AbsoluteLayout
if (mTouchSelection) {
nativeDrawSelectionRegion(canvas);
} else {
- nativeDrawSelection(canvas, mSelectX, mSelectY,
+ nativeDrawSelection(canvas, mSelectX, mSelectY,
mExtendSelection);
}
- } else if (drawFocus) {
+ } else if (drawCursorRing) {
if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
mTouchMode = TOUCH_SHORTPRESS_MODE;
HitTestResult hitTest = getHitTestResult();
@@ -2422,7 +2696,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.
@@ -2431,14 +2705,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;
@@ -2454,7 +2726,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();
@@ -2475,13 +2747,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);
@@ -2497,37 +2769,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;
@@ -2545,21 +2817,23 @@ 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;
+ // Show all the child views once we are done.
+ mViewManager.showAll();
} else {
mTouchMode = SCROLL_ZOOM_OUT;
}
}
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);
@@ -2603,8 +2877,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 + ")");
}
@@ -2632,14 +2906,17 @@ 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);
}
}
- private boolean canZoomScrollOut() {
+ /**
+ * @hide
+ */
+ public boolean canZoomScrollOut() {
if (mContentWidth == 0 || mContentHeight == 0) {
return false;
}
@@ -2649,7 +2926,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
@@ -2664,7 +2941,7 @@ public class WebView extends AbsoluteLayout
return mContentWidth >= width * limit
|| mContentHeight >= height * limit;
}
-
+
private void startZoomScrollOut() {
setHorizontalScrollBarEnabled(false);
setVerticalScrollBarEnabled(false);
@@ -2690,30 +2967,35 @@ 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() {
+
+ /**
+ * @hide
+ */
+ public void zoomScrollOut() {
if (canZoomScrollOut() == false) {
mTouchMode = TOUCH_DONE_MODE;
return;
}
+ // Hide the child views while in this mode.
+ mViewManager.hideAll();
startZoomScrollOut();
mTouchMode = SCROLL_ZOOM_ANIMATION_OUT;
invalidate();
}
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;
}
@@ -2725,12 +3007,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);
@@ -2738,12 +3020,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);
@@ -2752,12 +3034,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);
}
}
@@ -2802,7 +3084,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;
@@ -2818,72 +3100,29 @@ 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();
+ Point position = nativeCursorPosition();
+ result.mX = position.x;
+ result.mY = position.y;
+ 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));
+ WebViewCore.TextSelectionData data
+ = new WebViewCore.TextSelectionData(start, end);
+ mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, mTextGeneration, 0,
+ data);
}
/**
@@ -2893,119 +3132,138 @@ 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() {
+ private void displaySoftKeyboard(boolean isTextView) {
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(mTextEntry, 0);
- mTextEntry.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();
- if (lp != null) {
- // Take the last touch and adjust for the location of the
- // TextDialog.
- float x = mLastTouchX + (float) (mScrollX - lp.x);
- float y = mLastTouchY + (float) (mScrollY - lp.y);
- mTextEntry.fakeTouchEvent(x, y);
- }
- }
-
- private void updateTextEntry() {
- if (mTextEntry == null) {
- mTextEntry = new TextDialog(mContext, WebView.this);
- // Initialize our generation number.
- mTextGeneration = 0;
+
+ if (isTextView) {
+ imm.showSoftInput(mWebTextView, 0);
+ // Now we need to fake a touch event to place the cursor where the
+ // user touched.
+ AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams)
+ mWebTextView.getLayoutParams();
+ if (lp != null) {
+ // Take the last touch and adjust for the location of the
+ // WebTextView.
+ float x = mLastTouchX + (float) (mScrollX - lp.x);
+ float y = mLastTouchY + (float) (mScrollY - lp.y);
+ mWebTextView.fakeTouchEvent(x, y);
+ }
+ if (mInZoomOverview) {
+ // if in zoom overview mode, call doDoubleTap() to bring it back
+ // to normal mode so that user can enter text.
+ doDoubleTap();
+ }
+ }
+ else { // used by plugins
+ imm.showSoftInput(this, 0);
}
- // If we do not have focus, do nothing until we gain focus.
- if (!hasFocus() && !mTextEntry.hasFocus()
- || (mTouchMode >= FIRST_SCROLL_ZOOM
+ }
+
+ // Called by WebKit to instruct the UI to hide the keyboard
+ private void hideSoftKeyboard() {
+ InputMethodManager imm = (InputMethodManager)
+ getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+
+ imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
+ }
+
+ /*
+ * This method checks the current focus and cursor and potentially rebuilds
+ * mWebTextView to have the appropriate properties, such as password,
+ * multiline, and what text it contains. It also removes it if necessary.
+ */
+ /* package */ void rebuildWebTextView() {
+ // If the WebView does not have focus, do nothing until it gains focus.
+ if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())
+ || (mTouchMode >= FIRST_SCROLL_ZOOM
&& mTouchMode <= LAST_SCROLL_ZOOM)) {
- mNeedsUpdateTextEntry = 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 || !nativeFocusCandidateIsTextInput()) {
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));
- Rect visibleRect = sendOurVisibleRect();
+ mWebTextView.setTextSize(contentToView(nativeFocusCandidateTextSize()));
+ Rect visibleRect = new Rect();
+ calcOurContentVisibleRect(visibleRect);
// Note that sendOurVisibleRect calls viewToContent, so the coordinates
// should be in content coordinates.
- if (!Rect.intersects(node.mBounds, visibleRect)) {
- // Node is not on screen, so do not bother.
- return;
+ Rect bounds = nativeFocusCandidateNodeBounds();
+ if (!Rect.intersects(bounds, visibleRect)) {
+ mWebTextView.bringIntoView();
}
- 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 = nativeFocusCandidateText();
+ int nodePointer = nativeFocusCandidatePointer();
+ 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 :
- Gravity.NO_GRAVITY);
+ Rect vBox = contentToView(bounds);
+ mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
+ vBox.height());
+ mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ?
+ 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 = nativeFocusCandidateIsTextField();
+ if (isTextField) {
+ maxLength = nativeFocusCandidateMaxLength();
+ String name = nativeFocusCandidateName();
if (mWebViewCore.getSettings().getSaveFormData()
- && node.mName != null) {
- HashMap data = new HashMap();
- data.put("text", node.mText);
+ && name != null) {
Message update = mPrivateHandler.obtainMessage(
- UPDATE_TEXT_ENTRY_ADAPTER, node.mNodePointer, 0,
- data);
- UpdateTextEntryAdapter updater = new UpdateTextEntryAdapter(
- node.mName, getUrl(), update);
+ REQUEST_FORM_DATA, nodePointer);
+ 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(nativeFocusCandidateIsPassword());
if (null == text) {
- mTextEntry.setText("", 0, 0);
+ mWebTextView.setText("", 0, 0);
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "rebuildWebTextView null == text");
+ }
} else {
// Change to true to enable the old style behavior, where
// entering a textfield/textarea always set the selection to the
@@ -3016,24 +3274,35 @@ 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);
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "rebuildWebTextView length=" + length);
+ }
} else {
- mTextEntry.setText(text, 0, 0);
+ mWebTextView.setText(text, 0, 0);
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "rebuildWebTextView !isTextField");
+ }
}
}
- 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;
@@ -3044,29 +3313,21 @@ public class WebView extends AbsoluteLayout
if (pastEntries.size() > 0) {
AutoCompleteAdapter adapter = new
AutoCompleteAdapter(mContext, pastEntries);
- ((HashMap) mUpdateMessage.obj).put("adapter", adapter);
+ mUpdateMessage.obj = adapter;
mUpdateMessage.sendToTarget();
}
}
}
- 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);
+ + ", " + event + ", unicode=" + event.getUnicodeChar());
}
if (mNativeClass == 0) {
@@ -3092,29 +3353,27 @@ 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;
}
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- nativeClearFocus(contentX, contentY);
+ nativeHideCursor();
}
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
&& keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
// always handle the navigation keys in the UI thread
switchOutDrawHistory();
- if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
+ if (navHandledKey(keyCode, 1, false, event.getEventTime(), false)) {
playSoundEffect(keyCodeToSoundsEffect(keyCode));
return true;
}
@@ -3122,13 +3381,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);
@@ -3138,6 +3396,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:
@@ -3166,8 +3433,30 @@ public class WebView extends AbsoluteLayout
}
}
+ if (nativeCursorIsPlugin()) {
+ nativeUpdatePluginReceivesEvents();
+ invalidate();
+ } else if (nativeCursorIsTextInput()) {
+ // This message will put the node in focus, for the DOM's notion
+ // of focus, and make the focuscontroller active
+ mWebViewCore.sendMessage(EventHub.CLICK, nativeCursorFramePointer(),
+ nativeCursorNodePointer());
+ // This will bring up the WebTextView and put it in focus, for
+ // our view system's notion of focus
+ rebuildWebTextView();
+ // Now we need to pass the event to it
+ return mWebTextView.onKeyDown(keyCode, event);
+ } else if (nativeHasFocusNode()) {
+ // In this case, the cursor is not on a text input, but the focus
+ // might be. Check it, and if so, hand over to the WebTextView.
+ rebuildWebTextView();
+ if (inEditingMode()) {
+ return mWebTextView.onKeyDown(keyCode, event);
+ }
+ }
+
// 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
@@ -3180,20 +3469,19 @@ 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);
+ + ", " + event + ", unicode=" + event.getUnicodeChar());
}
if (mNativeClass == 0) {
return false;
}
- // 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
+ // special CALL handling when cursor node's href is "tel:XXX"
+ 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);
@@ -3220,7 +3508,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;
@@ -3234,55 +3522,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
@@ -3292,16 +3555,14 @@ public class WebView extends AbsoluteLayout
// Bubble up the key event as WebView doesn't handle it
return false;
}
-
+
/**
* @hide
*/
public void emulateShiftHeld() {
mExtendSelection = false;
mShiftIsPressed = true;
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- nativeClearFocus(contentX, contentY);
+ nativeHideCursor();
}
private boolean commitCopy() {
@@ -3349,16 +3610,13 @@ 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;
- }
+ clearTextEntry();
}
}
@@ -3371,26 +3629,25 @@ 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
- // necessary.
- mDrawFocusRing = true;
- if (mNeedsUpdateTextEntry) {
- updateTextEntry();
- }
+ // drawing the cursor ring
+ mDrawCursorRing = true;
if (mNativeClass != 0) {
nativeRecordButtons(true, false, true);
+ if (inEditingMode()) {
+ mWebViewCore.sendMessage(EventHub.SET_ACTIVE, 1, 0);
+ }
}
} 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
@@ -3399,39 +3656,49 @@ 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);
}
+ setFocusControllerInactive();
}
invalidate();
super.onWindowFocusChanged(hasWindowFocus);
}
+ /*
+ * Pass a message to WebCore Thread, telling the WebCore::Page's
+ * FocusController to be "inactive" so that it will
+ * not draw the blinking cursor. It gets set to "active" to draw the cursor
+ * in WebViewCore.cpp, when the WebCore thread receives key events/clicks.
+ */
+ /* package */ void setFocusControllerInactive() {
+ // Do not need to also check whether mWebViewCore is null, because
+ // mNativeClass is only set if mWebViewCore is non null
+ if (mNativeClass == 0) return;
+ mWebViewCore.sendMessage(EventHub.SET_ACTIVE, 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
if (hasWindowFocus()) {
- mDrawFocusRing = true;
- if (mNeedsUpdateTextEntry) {
- updateTextEntry();
- mNeedsUpdateTextEntry = false;
- }
+ mDrawCursorRing = true;
if (mNativeClass != 0) {
nativeRecordButtons(true, false, true);
}
@@ -3442,12 +3709,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);
}
+ setFocusControllerInactive();
}
mGotKeyDown = false;
}
@@ -3459,13 +3727,16 @@ public class WebView extends AbsoluteLayout
protected void onSizeChanged(int w, int h, int ow, int oh) {
super.onSizeChanged(w, h, ow, oh);
// Center zooming to the center of the screen.
- mZoomCenterX = getViewWidth() * .5f;
- mZoomCenterY = getViewHeight() * .5f;
+ if (mZoomScale == 0) { // unless we're already zooming
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
+ }
// update mMinZoomScale if the minimum zoom scale is not fixed
if (!mMinZoomScaleFixed) {
mMinZoomScale = (float) getViewWidth()
- / Math.max(ZOOM_OUT_WIDTH, mContentWidth);
+ / (mDrawHistory ? mHistoryPicture.getWidth()
+ : mZoomOverviewWidth);
}
// we always force, in case our height changed, in which case we still
@@ -3476,10 +3747,17 @@ public class WebView extends AbsoluteLayout
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
+
+ if (mViewingMode == READING_MODE_WITH_TITLE_BAR
+ || mViewingMode == TITLE_BAR_DISMISS_MODE) {
+ mViewingMode = READING_MODE;
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ }
+
sendOurVisibleRect();
}
-
-
+
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
boolean dispatch = true;
@@ -3523,7 +3801,7 @@ public class WebView extends AbsoluteLayout
return false;
}
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, ev + " at " + ev.getEventTime() + " mTouchMode="
+ mTouchMode);
}
@@ -3548,7 +3826,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;
@@ -3579,22 +3857,34 @@ 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)
, viewToContent(mSelectY), false);
mTouchSelection = mExtendSelection = true;
+ } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
+ mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
+ if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
+ mTouchMode = TOUCH_DOUBLE_TAP_MODE;
+ } else {
+ // commit the short press action for the previous tap
+ doShortPress();
+ // continue, mTouchMode should be still TOUCH_INIT_MODE
+ }
} else {
mTouchMode = TOUCH_INIT_MODE;
mPreventDrag = mForwardTouchEvents;
+ mWebViewCore.sendMessage(
+ EventHub.UPDATE_FRAME_CACHE_IF_LOADING);
if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
(eventTime - mLastTouchUpTime), eventTime);
}
}
// Trigger the link
- if (mTouchMode == TOUCH_INIT_MODE) {
+ if (mTouchMode == TOUCH_INIT_MODE
+ || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
}
@@ -3607,7 +3897,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
@@ -3624,7 +3914,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)
@@ -3640,7 +3930,8 @@ public class WebView extends AbsoluteLayout
if (mTouchMode == TOUCH_SHORTPRESS_MODE
|| mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- } else if (mTouchMode == TOUCH_INIT_MODE) {
+ } else if (mTouchMode == TOUCH_INIT_MODE
+ || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
}
@@ -3657,22 +3948,14 @@ public class WebView extends AbsoluteLayout
mTouchMode = TOUCH_DRAG_MODE;
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) {
- mWebViewCore
- .sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
+ if (!mDragFromTextInput) {
+ nativeHideCursor();
}
WebSettings settings = getSettings();
if (settings.supportZoom()
&& settings.getBuiltInZoomControls()
&& !mZoomButtonsController.isVisible()
- && (canZoomScrollOut() ||
+ && (canZoomScrollOut() ||
mMinZoomScale < mMaxZoomScale)) {
mZoomButtonsController.setVisible(true);
}
@@ -3685,6 +3968,13 @@ public class WebView extends AbsoluteLayout
deltaY = newScrollY - mScrollY;
boolean done = false;
if (deltaX == 0 && deltaY == 0) {
+ // The user attempted to pan the page, so dismiss the title
+ // bar
+ if (mViewingMode == READING_MODE_WITH_TITLE_BAR
+ || mViewingMode == TITLE_BAR_DISMISS_MODE) {
+ mViewingMode = READING_MODE;
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ }
done = true;
} else {
if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
@@ -3698,7 +3988,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))) {
@@ -3712,9 +4002,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;
}
@@ -3762,7 +4052,23 @@ public class WebView extends AbsoluteLayout
case MotionEvent.ACTION_UP: {
mLastTouchUpTime = eventTime;
switch (mTouchMode) {
+ case TOUCH_DOUBLE_TAP_MODE: // double tap
+ mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+ mTouchMode = TOUCH_DONE_MODE;
+ doDoubleTap();
+ break;
case TOUCH_INIT_MODE: // tap
+ if (ENABLE_DOUBLETAP_ZOOM) {
+ mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+ if (!mPreventDrag) {
+ mPrivateHandler.sendMessageDelayed(
+ mPrivateHandler.obtainMessage(
+ RELEASE_SINGLE_TAP),
+ ViewConfiguration.getDoubleTapTimeout());
+ }
+ break;
+ }
+ // fall through
case TOUCH_SHORTPRESS_START_MODE:
case TOUCH_SHORTPRESS_MODE:
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
@@ -3779,7 +4085,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));
@@ -3837,18 +4143,13 @@ public class WebView extends AbsoluteLayout
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
mTouchMode = TOUCH_DONE_MODE;
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
- nativeClearFocus(contentX, contentY);
+ nativeHideCursor();
break;
}
}
return true;
}
-
+
private long mTrackballFirstTime = 0;
private long mTrackballLastTime = 0;
private float mTrackballRemainsX = 0.0f;
@@ -3870,14 +4171,14 @@ public class WebView extends AbsoluteLayout
private boolean mShiftIsPressed = false;
private boolean mTrackballDown = false;
private long mTrackballUpTime = 0;
- private long mLastFocusTime = 0;
- private Rect mLastFocusBounds;
+ private long mLastCursorTime = 0;
+ private Rect mLastCursorBounds;
// 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;
}
@@ -3895,26 +4196,27 @@ 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 (mNativeClass == 0) {
+ return false;
}
- if (time - mLastFocusTime <= TRACKBALL_TIMEOUT
- && !mLastFocusBounds.equals(nativeGetFocusRingBounds())) {
- nativeSelectBestAt(mLastFocusBounds);
+ nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
+ if (time - mLastCursorTime <= TRACKBALL_TIMEOUT
+ && !mLastCursorBounds.equals(nativeGetCursorRingBounds())) {
+ nativeSelectBestAt(mLastCursorBounds);
}
- if (LOGV_ENABLED) {
+ if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "onTrackballEvent down ev=" + ev
- + " time=" + time
- + " mLastFocusTime=" + mLastFocusTime);
+ + " time=" + time
+ + " mLastCursorTime=" + mLastCursorTime);
}
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) {
@@ -3924,42 +4226,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();
@@ -3967,7 +4269,7 @@ public class WebView extends AbsoluteLayout
doTrackball(time);
return true;
}
-
+
void moveSelection(float xRate, float yRate) {
if (mNativeClass == 0)
return;
@@ -3981,8 +4283,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
@@ -3994,10 +4296,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);
@@ -4054,7 +4356,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);
@@ -4064,7 +4366,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
@@ -4081,9 +4383,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));
@@ -4101,18 +4403,18 @@ 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);
}
- if (navHandledKey(selectKeyCode, count, false, time)) {
+ if (navHandledKey(selectKeyCode, count, false, time, false)) {
playSoundEffect(keyCodeToSoundsEffect(selectKeyCode));
}
mTrackballRemainsX = mTrackballRemainsY = 0;
@@ -4120,12 +4422,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)) {
@@ -4138,18 +4440,17 @@ public class WebView extends AbsoluteLayout
pinScrollBy(xMove, yMove, true, 0);
}
mUserScroll = true;
- }
- 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;
@@ -4168,7 +4469,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;
@@ -4187,6 +4488,8 @@ public class WebView extends AbsoluteLayout
private boolean zoomWithPreview(float scale) {
float oldScale = mActualScale;
+ mInitialScrollX = mScrollX;
+ mInitialScrollY = mScrollY;
// snap to DEFAULT_SCALE if it is close
if (scale > (mDefaultScale - 0.05) && scale < (mDefaultScale + 0.05)) {
@@ -4201,6 +4504,9 @@ public class WebView extends AbsoluteLayout
mInvInitialZoomScale = 1.0f / oldScale;
mInvFinalZoomScale = 1.0f / mActualScale;
mZoomScale = mActualScale;
+ if (!mInZoomOverview) {
+ mLastScale = scale;
+ }
invalidate();
return true;
} else {
@@ -4229,7 +4535,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
@@ -4238,7 +4544,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.
*/
@@ -4290,7 +4596,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
@@ -4306,7 +4612,18 @@ public class WebView extends AbsoluteLayout
public boolean zoomIn() {
// TODO: alternatively we can disallow this during draw history mode
switchOutDrawHistory();
- return zoomWithPreview(mActualScale * 1.25f);
+ // Center zooming to the center of the screen.
+ if (mInZoomOverview) {
+ // if in overview mode, bring it back to normal mode
+ mLastTouchX = getViewWidth() * .5f;
+ mLastTouchY = getViewHeight() * .5f;
+ doDoubleTap();
+ return true;
+ } else {
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
+ return zoomWithPreview(mActualScale * 1.25f);
+ }
}
/**
@@ -4316,7 +4633,18 @@ public class WebView extends AbsoluteLayout
public boolean zoomOut() {
// TODO: alternatively we can disallow this during draw history mode
switchOutDrawHistory();
- return zoomWithPreview(mActualScale * 0.8f);
+ float scale = mActualScale * 0.8f;
+ if (scale < (mMinZoomScale + 0.1f) && WebView.ENABLE_DOUBLETAP_ZOOM
+ && mWebViewCore.getSettings().getUseWideViewPort()) {
+ // when zoom out to min scale, switch to overview mode
+ doDoubleTap();
+ return true;
+ } else {
+ // Center zooming to the center of the screen.
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
+ return zoomWithPreview(scale);
+ }
}
private void updateSelection() {
@@ -4328,19 +4656,77 @@ 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);
}
+ /**
+ * Scroll the focused text field/area to match the WebTextView
+ * @param x New x position of the WebTextView in view coordinates
+ * @param y New y position of the WebTextView in view coordinates
+ */
+ /*package*/ void scrollFocusedTextInput(int x, int y) {
+ if (!inEditingMode() || mWebViewCore == null) {
+ return;
+ }
+ mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, viewToContent(x),
+ viewToContent(y));
+ }
+
+ /**
+ * Set our starting point and time for a drag from the WebTextView.
+ */
+ /*package*/ void initiateTextFieldDrag(float x, float y, long eventTime) {
+ if (!inEditingMode()) {
+ return;
+ }
+ mLastTouchX = x + (float) (mWebTextView.getLeft() - mScrollX);
+ mLastTouchY = y + (float) (mWebTextView.getTop() - mScrollY);
+ mLastTouchTime = eventTime;
+ if (!mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ mPrivateHandler.removeMessages(RESUME_WEBCORE_UPDATE);
+ }
+ mSnapScrollMode = SNAP_NONE;
+ mVelocityTracker = VelocityTracker.obtain();
+ mTouchMode = TOUCH_DRAG_START_MODE;
+ }
+
+ /**
+ * Given a motion event from the WebTextView, set its location to our
+ * coordinates, and handle the event.
+ */
+ /*package*/ boolean textFieldDrag(MotionEvent event) {
+ if (!inEditingMode()) {
+ return false;
+ }
+ mDragFromTextInput = true;
+ event.offsetLocation((float) (mWebTextView.getLeft() - mScrollX),
+ (float) (mWebTextView.getTop() - mScrollY));
+ boolean result = onTouchEvent(event);
+ mDragFromTextInput = false;
+ return result;
+ }
+
+ /**
+ * Do a touch up from a WebTextView. This will be handled by webkit to
+ * change the selection.
+ * @param event MotionEvent in the WebTextView's coordinates.
+ */
+ /*package*/ void touchUpOnTextField(MotionEvent event) {
+ if (!inEditingMode()) {
+ return;
+ }
+ int x = viewToContent((int) event.getX() + mWebTextView.getLeft());
+ int y = viewToContent((int) event.getY() + mWebTextView.getTop());
+ nativeTextInputMotionUp(x, y);
+ }
+
/*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);
+ nativeTextInputMotionUp(x, y);
}
}
@@ -4352,29 +4738,104 @@ 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);
}
}
+ /**
+ * Called when the Tabs are used to slide this WebView's tab into view.
+ * @hide
+ */
+ public void slideIntoFocus() {
+ if (mViewingMode == READING_MODE) {
+ if (!mMobileSite || (mScrollX | mScrollY) != 0) {
+ mViewingMode = READING_MODE_WITH_TITLE_BAR;
+ } else {
+ mViewingMode = TITLE_BAR_DISMISS_MODE;
+ }
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ }
+ }
+
+ private void doDoubleTap() {
+ if (mWebViewCore.getSettings().getUseWideViewPort() == false ||
+ mViewingMode == NO_VIEWING_MODE) {
+ return;
+ }
+ if (mViewingMode == TITLE_BAR_DISMISS_MODE) {
+ mViewingMode = READING_MODE;
+ // mInZoomOverview will not change, so change the viewing mode
+ // and return
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ return;
+ }
+ if (mViewingMode == READING_MODE_WITH_TITLE_BAR && mMobileSite) {
+ scrollTo(0,0);
+ }
+ // READING_MODE_WITH_TITLE_BAR will go to OVERVIEW_MODE here.
+ mZoomCenterX = mLastTouchX;
+ mZoomCenterY = mLastTouchY;
+ mInZoomOverview = !mInZoomOverview;
+ mViewingMode = mInZoomOverview ? OVERVIEW_MODE : READING_MODE;
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ // remove the zoom control after double tap
+ if (getSettings().getBuiltInZoomControls()) {
+ if (mZoomButtonsController.isVisible()) {
+ mZoomButtonsController.setVisible(false);
+ }
+ } else {
+ if (mZoomControlRunnable != null) {
+ mPrivateHandler.removeCallbacks(mZoomControlRunnable);
+ }
+ if (mZoomControls != null) {
+ mZoomControls.hide();
+ }
+ }
+ if (mInZoomOverview) {
+ zoomWithPreview((float) getViewWidth() / mZoomOverviewWidth);
+ } else {
+ // mLastTouchX and mLastTouchY are the point in the current viewport
+ int contentX = viewToContent((int) mLastTouchX + mScrollX);
+ int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ int left = nativeGetBlockLeftEdge(contentX, contentY, mActualScale);
+ if (left != NO_LEFTEDGE) {
+ // add a 5pt padding to the left edge. Re-calculate the zoom
+ // center so that the new scroll x will be on the left edge.
+ mZoomCenterX = left < 5 ? 0 : (left - 5) * mLastScale
+ * mActualScale / (mLastScale - mActualScale);
+ }
+ zoomWithPreview(mLastScale);
+ }
+ }
+
// Called by JNI to handle a touch on a node representing an email address,
// address, or phone number
private void overrideLoading(String url) {
mCallbackProxy.uiOverrideUrlLoading(url);
}
+ // called by JNI
+ private void sendPluginState(int state) {
+ WebViewCore.PluginStateData psd = new WebViewCore.PluginStateData();
+ psd.mFrame = nativeCursorFramePointer();
+ psd.mNode = nativeCursorNodePointer();
+ psd.mState = state;
+ mWebViewCore.sendMessage(EventHub.PLUGIN_STATE, psd);
+ }
+
@Override
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()) {
@@ -4398,8 +4859,8 @@ public class WebView extends AbsoluteLayout
default:
return result;
}
- if (mNativeClass != 0 && !nativeUpdateFocusNode()) {
- navHandledKey(fakeKeyDirection, 1, true, 0);
+ if (mNativeClass != 0 && !nativeHasCursorNode()) {
+ navHandledKey(fakeKeyDirection, 1, true, 0, true);
}
}
}
@@ -4467,14 +4928,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();
@@ -4499,33 +4965,35 @@ 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));
+ WebViewCore.ReplaceTextData arg = new WebViewCore.ReplaceTextData();
+ arg.mReplace = replace;
+ arg.mNewStart = newStart;
+ arg.mNewEnd = newEnd;
mTextGeneration++;
+ arg.mTextGeneration = 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);
+ if (nativeCursorWantsKeyEvents() && !nativeCursorMatchesFocus()) {
+ mWebViewCore.sendMessage(EventHub.CLICK);
+ }
+ WebViewCore.JSKeyData arg = new WebViewCore.JSKeyData();
+ arg.mEvent = event;
+ arg.mCurrentText = 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() {
@@ -4543,9 +5011,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) {
@@ -4567,6 +5035,8 @@ public class WebView extends AbsoluteLayout
if (mTouchMode == TOUCH_INIT_MODE) {
mTouchMode = TOUCH_SHORTPRESS_START_MODE;
updateSelection();
+ } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
+ mTouchMode = TOUCH_DONE_MODE;
}
break;
}
@@ -4574,23 +5044,49 @@ public class WebView extends AbsoluteLayout
if (!mPreventDrag) {
mTouchMode = TOUCH_DONE_MODE;
performLongClick();
- updateTextEntry();
+ rebuildWebTextView();
+ }
+ break;
+ }
+ case RELEASE_SINGLE_TAP: {
+ if (!mPreventDrag) {
+ mTouchMode = TOUCH_DONE_MODE;
+ doShortPress();
}
break;
}
- case SWITCH_TO_ENTER:
- if (LOGV_ENABLED) Log.v(LOGTAG, "SWITCH_TO_ENTER");
+ case SWITCH_TO_CLICK:
+ // The user clicked with the trackball, and did not click a
+ // second time, so perform the action of a trackball single
+ // 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);
+ nativeUpdatePluginReceivesEvents();
+ WebViewCore.CursorData data = cursorData();
+ mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data);
+ playSoundEffect(SoundEffectConstants.CLICK);
+ boolean isTextInput = nativeCursorIsTextInput();
+ if (isTextInput || !mCallbackProxy.uiOverrideUrlLoading(
+ nativeCursorText())) {
+ mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame,
+ nativeCursorNodePointer());
+ }
+ if (isTextInput) {
+ rebuildWebTextView();
+ }
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;
@@ -4599,7 +5095,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,
@@ -4609,24 +5105,56 @@ public class WebView extends AbsoluteLayout
case SPAWN_SCROLL_TO_MSG_ID:
spawnContentScrollTo(msg.arg1, msg.arg2);
break;
- case NEW_PICTURE_MSG_ID:
+ case NEW_PICTURE_MSG_ID: {
+ WebSettings settings = mWebViewCore.getSettings();
// called for new content
- final WebViewCore.DrawData draw =
+ final int viewWidth = getViewWidth();
+ final WebViewCore.DrawData draw =
(WebViewCore.DrawData) msg.obj;
final Point viewSize = draw.mViewPoint;
- if (mZoomScale > 0) {
- // use the same logic in sendViewSizeZoom() to make sure
- // the mZoomScale has matched the viewSize so that we
- // can clear mZoomScale
- if (Math.round(getViewWidth() / mZoomScale) == viewSize.x) {
- mZoomScale = 0;
- mWebViewCore.sendMessage(EventHub.SET_SNAP_ANCHOR,
- 0, 0);
+ boolean useWideViewport = settings.getUseWideViewPort();
+ WebViewCore.RestoreState restoreState = draw.mRestoreState;
+ if (restoreState != null) {
+ mInZoomOverview = false;
+ mLastScale = restoreState.mTextWrapScale;
+ if (restoreState.mMinScale == 0) {
+ mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ mMinZoomScaleFixed = false;
+ } else {
+ mMinZoomScale = restoreState.mMinScale;
+ mMinZoomScaleFixed = true;
}
- }
- if (!mMinZoomScaleFixed) {
- mMinZoomScale = (float) getViewWidth()
- / Math.max(ZOOM_OUT_WIDTH, draw.mWidthHeight.x);
+ if (restoreState.mMaxScale == 0) {
+ mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
+ } else {
+ mMaxZoomScale = restoreState.mMaxScale;
+ }
+ setNewZoomScale(mLastScale, false);
+ setContentScrollTo(restoreState.mScrollX,
+ restoreState.mScrollY);
+ if (!ENABLE_DOUBLETAP_ZOOM
+ || !settings.getLoadWithOverviewMode()) {
+ mMobileSite = false;
+ mViewingMode = NO_VIEWING_MODE;
+ } else {
+ mMobileSite = restoreState.mMobileSite;
+ if (useWideViewport
+ && restoreState.mViewScale == 0) {
+ mViewingMode = OVERVIEW_MODE;
+ mInZoomOverview = true;
+ } else if (mMobileSite
+ && (mScrollX | mScrollY) == 0) {
+ mViewingMode = TITLE_BAR_DISMISS_MODE;
+ } else {
+ mViewingMode = READING_MODE_WITH_TITLE_BAR;
+ }
+ }
+ mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
+ // As we are on a new page, remove the WebTextView. This
+ // is necessary for page loads driven by webkit, and in
+ // particular when the user was on a password field, so
+ // the WebTextView was visible.
+ clearTextEntry();
}
// We update the layout (i.e. request a layout from the
// view system) if the last view size that we sent to
@@ -4634,9 +5162,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+"}");
@@ -4645,114 +5173,76 @@ public class WebView extends AbsoluteLayout
if (mPictureListener != null) {
mPictureListener.onNewPicture(WebView.this, capturePicture());
}
+ if (useWideViewport) {
+ mZoomOverviewWidth = Math.max(draw.mMinPrefWidth,
+ draw.mViewPoint.x);
+ }
+ if (!mMinZoomScaleFixed) {
+ mMinZoomScale = (float) viewWidth / mZoomOverviewWidth;
+ }
+ if (!mDrawHistory && mInZoomOverview) {
+ // fit the content width to the current view. Ignore
+ // the rounding error case.
+ if (Math.abs((viewWidth * mInvActualScale)
+ - mZoomOverviewWidth) > 1) {
+ setNewZoomScale((float) viewWidth
+ / mZoomOverviewWidth, false);
+ }
+ }
break;
+ }
case WEBCORE_INITIALIZED_MSG_ID:
// nativeCreate sets mNativeClass to a non-zero value
nativeCreate(msg.arg1);
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);
}
}
break;
- case DID_FIRST_LAYOUT_MSG_ID:
- if (mNativeClass == 0) {
- break;
+ case UPDATE_TEXT_SELECTION_MSG_ID:
+ if (inEditingMode()
+ && mWebTextView.isSameTextField(msg.arg1)
+ && msg.arg2 == mTextGeneration) {
+ WebViewCore.TextSelectionData tData
+ = (WebViewCore.TextSelectionData) msg.obj;
+ mWebTextView.setSelectionFromWebKit(tData.mStart,
+ tData.mEnd);
}
-// 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
-// reset, if need be, when the focus cache was built. Similarly, the text
-// view should already be torn down and rebuilt if needed.
-// nativeResetFocus();
-// clearTextEntry();
- HashMap scaleLimit = (HashMap) msg.obj;
- int minScale = (Integer) scaleLimit.get("minScale");
- if (minScale == 0) {
- mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
- mMinZoomScaleFixed = false;
- } else {
- mMinZoomScale = (float) (minScale / 100.0);
- mMinZoomScaleFixed = true;
- }
- int maxScale = (Integer) scaleLimit.get("maxScale");
- if (maxScale == 0) {
- mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
- } else {
- mMaxZoomScale = (float) (maxScale / 100.0);
- }
- // If history Picture is drawn, don't update zoomWidth
- if (mDrawHistory) {
- break;
- }
- int width = getViewWidth();
- if (width == 0) {
- break;
- }
- int initialScale = msg.arg1;
- int viewportWidth = msg.arg2;
- // start a new page with DEFAULT_SCALE zoom scale.
- float scale = mDefaultScale;
- if (mInitialScale > 0) {
- scale = mInitialScale / 100.0f;
- } else {
- if (mWebViewCore.getSettings().getUseWideViewPort()) {
- // force viewSizeChanged by setting mLastWidthSent
- // to 0
- mLastWidthSent = 0;
- }
- if (initialScale == 0) {
- // if viewportWidth is defined and it is smaller
- // than the view width, zoom in to fill the view
- if (viewportWidth > 0 && viewportWidth < width) {
- scale = (float) width / viewportWidth;
- }
- } else {
- scale = initialScale / 100.0f;
- }
- }
- setNewZoomScale(scale, false);
- break;
- case MARK_NODE_INVALID_ID:
- nativeMarkNodeInvalid(msg.arg1);
break;
- case NOTIFY_FOCUS_SET_MSG_ID:
- if (mNativeClass != 0) {
- nativeNotifyFocusSet(inEditingMode());
+ case MOVE_OUT_OF_PLUGIN:
+ if (nativePluginEatsNavKey()) {
+ navHandledKey(msg.arg1, 1, false, 0, true);
}
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();
+ rebuildWebTextView();
}
- updateTextEntry();
break;
- case RECOMPUTE_FOCUS_MSG_ID:
- if (mNativeClass != 0) {
- nativeRecomputeFocus();
- }
+ case CLEAR_TEXT_ENTRY:
+ clearTextEntry();
break;
case INVAL_RECT_MSG_ID: {
Rect r = (Rect)msg.obj;
@@ -4765,17 +5255,15 @@ public class WebView extends AbsoluteLayout
}
break;
}
- case UPDATE_TEXT_ENTRY_ADAPTER:
- HashMap data = (HashMap) msg.obj;
- if (mTextEntry.isSameTextField(msg.arg1)) {
- AutoCompleteAdapter adapter =
- (AutoCompleteAdapter) data.get("adapter");
- mTextEntry.setAdapterCustom(adapter);
+ case REQUEST_FORM_DATA:
+ AutoCompleteAdapter adapter = (AutoCompleteAdapter) msg.obj;
+ if (mWebTextView.isSameTextField(msg.arg1)) {
+ 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 {
@@ -4790,12 +5278,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.
@@ -4817,6 +5305,14 @@ public class WebView extends AbsoluteLayout
}
break;
+ case REQUEST_KEYBOARD:
+ if (msg.arg1 == 0) {
+ hideSoftKeyboard();
+ } else {
+ displaySoftKeyboard(false);
+ }
+ break;
+
default:
super.handleMessage(msg);
break;
@@ -4826,16 +5322,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;
@@ -4854,14 +5346,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);
}
@@ -4919,7 +5411,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;
@@ -4982,31 +5474,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);
@@ -5069,48 +5566,39 @@ 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);
+ /*
+ * Send a mouse move event to the webcore thread.
+ *
+ * @param removeFocus Pass true if the "mouse" cursor is now over a node
+ * which wants key events, but it is not the focus. This
+ * will make the visual appear as though nothing is in
+ * focus. Remove the WebTextView, if present, and stop
+ * drawing the blinking caret.
+ * called by JNI
+ */
+ private void sendMoveMouseIfLatest(boolean removeFocus) {
+ if (removeFocus) {
+ clearTextEntry();
+ setFocusControllerInactive();
+ }
+ 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) {
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);
}
@@ -5149,56 +5637,72 @@ 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) {
+ private boolean navHandledKey(int keyCode, int count, boolean noScroll,
+ long time, boolean ignorePlugin) {
if (mNativeClass == 0) {
return false;
}
- mLastFocusTime = time;
- mLastFocusBounds = nativeGetFocusRingBounds();
- boolean keyHandled = nativeMoveFocus(keyCode, count, noScroll) == false;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "navHandledKey mLastFocusBounds=" + mLastFocusBounds
- + " mLastFocusTime=" + mLastFocusTime
+ if (ignorePlugin == false && nativePluginEatsNavKey()) {
+ KeyEvent event = new KeyEvent(time, time, KeyEvent.ACTION_DOWN
+ , keyCode, count, (mShiftIsPressed ? KeyEvent.META_SHIFT_ON : 0)
+ | (false ? KeyEvent.META_ALT_ON : 0) // FIXME
+ | (false ? KeyEvent.META_SYM_ON : 0) // FIXME
+ , 0, 0, 0);
+ mWebViewCore.sendMessage(EventHub.KEY_DOWN, event);
+ mWebViewCore.sendMessage(EventHub.KEY_UP, event);
+ return true;
+ }
+ mLastCursorTime = time;
+ mLastCursorBounds = nativeGetCursorRingBounds();
+ boolean keyHandled
+ = nativeMoveCursor(keyCode, count, noScroll) == false;
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "navHandledKey mLastCursorBounds=" + mLastCursorBounds
+ + " mLastCursorTime=" + mLastCursorTime
+ " handled=" + keyHandled);
}
if (keyHandled == false || mHeightCanMeasure == false) {
return keyHandled;
}
- Rect contentFocus = nativeGetFocusRingBounds();
- if (contentFocus.isEmpty()) return keyHandled;
- Rect viewFocus = contentToView(contentFocus);
+ Rect contentCursorRingBounds = nativeGetCursorRingBounds();
+ if (contentCursorRingBounds.isEmpty()) return keyHandled;
+ Rect viewCursorRingBounds = contentToView(contentCursorRingBounds);
Rect visRect = new Rect();
calcOurVisibleRect(visRect);
Rect outset = new Rect(visRect);
int maxXScroll = visRect.width() / 2;
int maxYScroll = visRect.height() / 2;
outset.inset(-maxXScroll, -maxYScroll);
- if (Rect.intersects(outset, viewFocus) == false) {
+ if (Rect.intersects(outset, viewCursorRingBounds) == false) {
return keyHandled;
}
// FIXME: Necessary because ScrollView/ListView do not scroll left/right
- int maxH = Math.min(viewFocus.right - visRect.right, maxXScroll);
+ int maxH = Math.min(viewCursorRingBounds.right - visRect.right,
+ maxXScroll);
if (maxH > 0) {
pinScrollBy(maxH, 0, true, 0);
} else {
- maxH = Math.max(viewFocus.left - visRect.left, -maxXScroll);
+ maxH = Math.max(viewCursorRingBounds.left - visRect.left,
+ -maxXScroll);
if (maxH < 0) {
pinScrollBy(maxH, 0, true, 0);
}
}
- if (mLastFocusBounds.isEmpty()) return keyHandled;
- if (mLastFocusBounds.equals(contentFocus)) return keyHandled;
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "navHandledKey contentFocus=" + contentFocus);
+ if (mLastCursorBounds.isEmpty()) return keyHandled;
+ if (mLastCursorBounds.equals(contentCursorRingBounds)) {
+ return keyHandled;
+ }
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "navHandledKey contentCursorRingBounds="
+ + contentCursorRingBounds);
}
- requestRectangleOnScreen(viewFocus);
+ requestRectangleOnScreen(viewCursorRingBounds);
mUserScroll = true;
return keyHandled;
}
-
+
/**
* Set the background color. It's white by default. Pass
* zero to make the view transparent.
@@ -5213,7 +5717,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.
@@ -5223,52 +5727,85 @@ 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);
+
+ /* package */ native void nativeClearCursor();
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 nativeCursorIsPlugin();
+ private native boolean nativeCursorIsTextInput();
+ private native Point nativeCursorPosition();
+ private native String nativeCursorText();
+ /**
+ * Returns true if the native cursor node says it wants to handle key events
+ * (ala plugins). This can only be called if mNativeClass is non-zero!
+ */
+ 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 nativeFocusCandidateIsPassword();
+ private native boolean nativeFocusCandidateIsRtlText();
+ private native boolean nativeFocusCandidateIsTextField();
+ private native boolean nativeFocusCandidateIsTextInput();
+ private native int nativeFocusCandidateMaxLength();
+ /* package */ native String nativeFocusCandidateName();
+ private native Rect nativeFocusCandidateNodeBounds();
+ /* package */ native int nativeFocusCandidatePointer();
+ private native String nativeFocusCandidateText();
+ private native int nativeFocusCandidateTextSize();
+ /* package */ native int nativeFocusNodePointer();
+ private native Rect nativeGetCursorRingBounds();
+ private native Region nativeGetSelection();
+ private native boolean nativeHasCursorNode();
+ private native boolean nativeHasFocusNode();
+ private native void nativeHideCursor();
+ private native String nativeImageURI(int x, int y);
private native void nativeInstrumentReport();
- private native void nativeMarkNodeInvalid(int node);
+ /* package */ native void nativeMoveCursorToNextTextInput();
// 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 nativeMoveCursor(int keyCode, int count,
boolean noScroll);
- private native void nativeNotifyFocusSet(boolean inEditingMode);
- private native void nativeRecomputeFocus();
+ private native int nativeMoveGeneration();
+ private native void nativeMoveSelection(int x, int y,
+ boolean extendSelection);
+ private native boolean nativePluginEatsNavKey();
// 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 a value corresponding to CachedFrame::ImeAction
+ /* package */ native int nativeTextFieldAction();
/**
- * 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!
+ * Perform a click on a currently focused text input. Since it is already
+ * focused, there is no need to go through the nativeMotionUp code, which
+ * may change the Cursor.
*/
- private native boolean nativeFocusNodeWantsKeyEvents();
- private native void nativeMoveSelection(int x, int y
- , boolean extendSelection);
- private native Region nativeGetSelection();
-
- private native void nativeDumpDisplayTree(String urlOrNull);
+ private native void nativeTextInputMotionUp(int x, int y);
+ 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 nativeUpdatePluginReceivesEvents();
+ // return NO_LEFTEDGE means failure.
+ private static final int NO_LEFTEDGE = -1;
+ private native int nativeGetBlockLeftEdge(int x, int y, float scale);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index a5fa41e..f474f15 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -32,17 +32,17 @@ import android.os.Process;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.KeyEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Set;
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,14 +96,19 @@ final class WebViewCore {
private int mViewportMaximumScale = 0;
private boolean mViewportUserScalable = true;
-
- private int mRestoredScale = WebView.DEFAULT_SCALE_PERCENT;
+
+ private int mRestoredScale = 0;
+ private int mRestoredScreenWidthScale = 0;
private int mRestoredX = 0;
private int mRestoredY = 0;
private int mWebkitScrollX = 0;
private int mWebkitScrollY = 0;
+ // If the site doesn't use viewport meta tag to specify the viewport, use
+ // DEFAULT_VIEWPORT_WIDTH as default viewport width
+ static final int DEFAULT_VIEWPORT_WIDTH = 800;
+
// The thread name used to identify the WebCore thread and for use in
// debugging other classes that require operation within the WebCore thread.
/* package */ static final String THREAD_NAME = "WebViewCoreThread";
@@ -143,6 +148,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 +169,10 @@ 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();
+ // Create the handler for GeolocationPermissions.
+ GeolocationPermissions.getInstance().createHandler();
// The transferMessages call will transfer all pending messages to the
// WebCore thread handler.
mEventHub.transferMessages();
@@ -225,6 +236,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 +254,71 @@ final class WebViewCore {
}
/**
+ * Notify the browser 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.
+ * @param estimatedSize The estimated size of the database.
+ */
+ protected void exceededDatabaseQuota(String url,
+ String databaseIdentifier,
+ long currentQuota,
+ long estimatedSize) {
+ // 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, estimatedSize, getUsedQuota(),
+ new WebStorage.QuotaUpdater() {
+ public void updateQuota(long quota) {
+ nativeSetNewStorageLimit(quota);
+ }
+ });
+ }
+
+ /**
+ * Notify the browser that the appcache has exceeded its max size.
+ * @param spaceNeeded is the amount of disk space that would be needed
+ * in order for the last appcache operation to succeed.
+ */
+ protected void reachedMaxAppCacheSize(long spaceNeeded) {
+ mCallbackProxy.onReachedMaxAppCacheSize(spaceNeeded, getUsedQuota(),
+ new WebStorage.QuotaUpdater() {
+ public void updateQuota(long quota) {
+ nativeSetNewStorageLimit(quota);
+ }
+ });
+ }
+
+ /**
+ * Shows a prompt to ask the user to set the Geolocation permission state
+ * for the given origin.
+ * @param origin The origin for which Geolocation permissions are
+ * requested.
+ */
+ protected void geolocationPermissionsShowPrompt(String origin) {
+ mCallbackProxy.onGeolocationPermissionsShowPrompt(origin,
+ new GeolocationPermissions.Callback() {
+ public void invoke(String origin, boolean allow, boolean remember) {
+ GeolocationPermissionsData data = new GeolocationPermissionsData();
+ data.mOrigin = origin;
+ data.mAllow = allow;
+ data.mRemember = remember;
+ // Marshall to WebCore thread.
+ sendMessage(EventHub.GEOLOCATION_PERMISSIONS_PROVIDE, data);
+ }
+ });
+ }
+
+ /**
+ * Hides the Geolocation permissions prompt.
+ */
+ protected void geolocationPermissionsHidePrompt() {
+ mCallbackProxy.onGeolocationPermissionsHidePrompt();
+ }
+
+ /**
* 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.
@@ -277,31 +363,36 @@ final class WebViewCore {
// JNI methods
//-------------------------------------------------------------------------
- static native String nativeFindAddress(String addr);
+ static native String nativeFindAddress(String addr, boolean caseInsensitive);
/**
* 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.
@@ -309,9 +400,10 @@ final class WebViewCore {
private native void nativeSplitContent();
private native boolean nativeKey(int keyCode, int unichar,
- int repeatCount, boolean isShift, boolean isAlt, boolean isDown);
+ int repeatCount, boolean isShift, boolean isAlt, boolean isSym,
+ boolean isDown);
- private native boolean nativeClick();
+ private native void nativeClick(int framePtr, int nodePtr);
private native void nativeSendListBoxChoices(boolean[] choices, int size);
@@ -326,63 +418,58 @@ final class WebViewCore {
should this be called nativeSetViewPortSize?
*/
private native void nativeSetSize(int width, int height, int screenWidth,
- float scale, int realScreenWidth, int screenHeight);
+ float scale, int realScreenWidth, int screenHeight,
+ boolean ignoreHeight);
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,
+ int textGeneration);
- 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 x, int y);
- private native void nativeSetKitFocus(int moveGeneration,
- int buildGeneration, int framePtr, int nodePtr, int x, int y,
- boolean ignoreNullFocus);
+ private native void nativeMoveMouseIfLatest(int moveGeneration,
+ int framePtr, int x, int y);
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);
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);
-
+ private native void nativeSetJsFlags(String flags);
+
/**
* 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.
+ * @param textGeneration Text generation number when delete was pressed.
*/
- private native void nativeDeleteSelection(int frame, int node, int x, int y,
- int start, int end);
+ private native void nativeDeleteSelection(int start, int end,
+ int textGeneration);
/**
* Set the selection to (start, end) in the focused textfield. If start and
@@ -390,15 +477,34 @@ 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 or more space for the app cache, and that
+ * the main thread should wake up now.
+ * @param limit Is the new quota for an origin or new app cache max size.
+ */
+ private native void nativeSetNewStorageLimit(long limit);
+
+ private native void nativeUpdatePluginState(int framePtr, int nodePtr, int state);
+
+ /**
+ * Provide WebCore with a Geolocation permission state for the specified
+ * origin.
+ * @param origin The origin for which Geolocation permissions are provided.
+ * @param allow Whether Geolocation permissions are allowed.
+ * @param remember Whether this decision should be remembered beyond the
+ * life of the current page.
+ */
+ private native void nativeGeolocationPermissionsProvide(String origin, boolean allow, boolean remember);
+
// EventHub for processing messages
private final EventHub mEventHub;
// WebCore thread handler
@@ -447,7 +553,7 @@ final class WebViewCore {
CacheManager.endCacheTransaction();
CacheManager.startCacheTransaction();
sendMessageDelayed(
- obtainMessage(CACHE_TICKER),
+ obtainMessage(CACHE_TICKER),
CACHE_TICKER_INTERVAL);
}
break;
@@ -472,36 +578,64 @@ 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 BaseUrlData {
+ String mBaseUrl;
+ String mData;
+ String mMimeType;
+ String mEncoding;
+ String mFailUrl;
+ }
+
+ static class CursorData {
+ CursorData() {}
+ CursorData(int frame, int node, int x, int y) {
+ mFrame = frame;
+ mX = x;
+ mY = y;
}
int mMoveGeneration;
- int mBuildGeneration;
int mFrame;
- int mNode;
int mX;
int mY;
- boolean mIgnoreNullFocus;
+ }
+
+ static class JSInterfaceData {
+ Object mObject;
+ String mInterfaceName;
+ }
+
+ static class JSKeyData {
+ String mCurrentText;
+ KeyEvent mEvent;
+ }
+
+ static class PostUrlData {
+ String mUrl;
+ byte[] mPostData;
+ }
+
+ static class ReplaceTextData {
+ String mReplace;
+ int mNewStart;
+ int mNewEnd;
+ int mTextGeneration;
+ }
+
+ static class TextSelectionData {
+ public TextSelectionData(int start, int end) {
+ mStart = start;
+ mEnd = end;
+ }
+ int mStart;
+ int mEnd;
}
static class TouchUpData {
int mMoveGeneration;
- int mBuildGeneration;
int mFrame;
int mNode;
int mX;
int mY;
- int mSize;
- boolean mIsClick;
- boolean mRetry;
}
static class TouchEventData {
@@ -510,7 +644,21 @@ final class WebViewCore {
int mY;
}
+ static class PluginStateData {
+ int mFrame;
+ int mNode;
+ int mState;
+ }
+
+ static class GeolocationPermissionsData {
+ String mOrigin;
+ boolean mAllow;
+ boolean mRemember;
+ }
+
static final String[] HandlerDebugString = {
+ "UPDATE_FRAME_CACHE_IF_LOADING", // = 98
+ "SCROLL_TEXT_INPUT", // = 99
"LOAD_URL", // = 100;
"STOP_LOADING", // = 101;
"RELOAD", // = 102;
@@ -532,33 +680,37 @@ final class WebViewCore {
"CLICK", // = 118;
"SET_NETWORK_STATE", // = 119;
"DOC_HAS_IMAGES", // = 120;
- "SET_SNAP_ANCHOR", // = 121;
+ "121", // = 121;
"DELETE_SELECTION", // = 122;
"LISTBOX_CHOICES", // = 123;
"SINGLE_LISTBOX_CHOICE", // = 124;
- "125",
+ "MESSAGE_RELAY", // = 125;
"SET_BACKGROUND_COLOR", // = 126;
- "UNBLOCK_FOCUS", // = 127;
+ "PLUGIN_STATE", // = 127;
"SAVE_DOCUMENT_STATE", // = 128;
"GET_SELECTION", // = 129;
"WEBKIT_DRAW", // = 130;
"SYNC_SCROLL", // = 131;
- "REFRESH_PLUGINS", // = 132;
- // this will replace REFRESH_PLUGINS in the next release
- "POST_URL", // = 142;
+ "POST_URL", // = 132;
"SPLIT_PICTURE_SET", // = 133;
"CLEAR_CONTENT", // = 134;
- "SET_FINAL_FOCUS", // = 135;
- "SET_KIT_FOCUS", // = 136;
- "REQUEST_FOCUS_HREF", // = 137;
+ "SET_MOVE_MOUSE", // = 135;
+ "SET_MOVE_MOUSE_IF_LATEST", // = 136;
+ "REQUEST_CURSOR_HREF", // = 137;
"ADD_JS_INTERFACE", // = 138;
"LOAD_DATA", // = 139;
"TOUCH_UP", // = 140;
"TOUCH_EVENT", // = 141;
+ "SET_ACTIVE", // = 142;
+ "ON_PAUSE", // = 143
+ "ON_RESUME", // = 144
+ "FREE_MEMORY", // = 145
};
class EventHub {
// Message Ids
+ static final int UPDATE_FRAME_CACHE_IF_LOADING = 98;
+ static final int SCROLL_TEXT_INPUT = 99;
static final int LOAD_URL = 100;
static final int STOP_LOADING = 101;
static final int RELOAD = 102;
@@ -580,26 +732,24 @@ final class WebViewCore {
static final int CLICK = 118;
static final int SET_NETWORK_STATE = 119;
static final int DOC_HAS_IMAGES = 120;
- static final int SET_SNAP_ANCHOR = 121;
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 PLUGIN_STATE = 127; // plugin notifications
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;
- // this will replace REFRESH_PLUGINS in the next release
- static final int POST_URL = 142;
+ 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 REQUEST_FOCUS_HREF = 137;
+ static final int SET_MOVE_MOUSE = 135;
+ static final int SET_MOVE_MOUSE_IF_LATEST = 136;
+ static final int REQUEST_CURSOR_HREF = 137;
static final int ADD_JS_INTERFACE = 138;
static final int LOAD_DATA = 139;
@@ -608,6 +758,17 @@ final class WebViewCore {
// message used to pass UI touch events to WebCore
static final int TOUCH_EVENT = 141;
+ // Used to tell the focus controller not to draw the blinking cursor,
+ // based on whether the WebView has focus and whether the WebView's
+ // cursor matches the webpage's focus.
+ static final int SET_ACTIVE = 142;
+
+ // lifecycle activities for just this DOM (unlike pauseTimers, which
+ // is global)
+ static final int ON_PAUSE = 143;
+ static final int ON_RESUME = 144;
+ static final int FREE_MEMORY = 145;
+
// Network-based messaging
static final int CLEAR_SSL_PREF_TABLE = 150;
@@ -620,12 +781,12 @@ final class WebViewCore {
static final int DUMP_RENDERTREE = 171;
static final int DUMP_NAVTREE = 172;
+ static final int SET_JS_FLAGS = 173;
+ // Geolocation
+ static final int GEOLOCATION_PERMISSIONS_PROVIDE = 180;
+
// 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;
@@ -654,10 +815,14 @@ 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)
- : HandlerDebugString[msg.what - LOAD_URL]);
+ if (DebugFlags.WEB_VIEW_CORE) {
+ Log.v(LOGTAG, (msg.what < UPDATE_FRAME_CACHE_IF_LOADING
+ || msg.what
+ > FREE_MEMORY ? Integer.toString(msg.what)
+ : HandlerDebugString[msg.what
+ - UPDATE_FRAME_CACHE_IF_LOADING])
+ + " arg1=" + msg.arg1 + " arg2=" + msg.arg2
+ + " obj=" + msg.obj);
}
switch (msg.what) {
case WEBKIT_DRAW:
@@ -672,20 +837,26 @@ final class WebViewCore {
mNativeClass = 0;
break;
+ case UPDATE_FRAME_CACHE_IF_LOADING:
+ nativeUpdateFrameCacheIfLoading();
+ break;
+
+ case SCROLL_TEXT_INPUT:
+ nativeScrollFocusedTextInput(msg.arg1, msg.arg2);
+ break;
+
case LOAD_URL:
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);
+ PostUrlData param = (PostUrlData) msg.obj;
+ mBrowserFrame.postUrl(param.mUrl, param.mPostData);
break;
}
case LOAD_DATA:
- HashMap loadParams = (HashMap) msg.obj;
- String baseUrl = (String) loadParams.get("baseUrl");
+ BaseUrlData loadParams = (BaseUrlData) msg.obj;
+ String baseUrl = loadParams.mBaseUrl;
if (baseUrl != null) {
int i = baseUrl.indexOf(':');
if (i > 0) {
@@ -698,7 +869,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") &&
@@ -709,16 +880,16 @@ final class WebViewCore {
}
}
mBrowserFrame.loadData(baseUrl,
- (String) loadParams.get("data"),
- (String) loadParams.get("mimeType"),
- (String) loadParams.get("encoding"),
- (String) loadParams.get("failUrl"));
+ loadParams.mData,
+ loadParams.mMimeType,
+ loadParams.mEncoding,
+ loadParams.mFailUrl);
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()) {
@@ -741,20 +912,24 @@ final class WebViewCore {
break;
case CLICK:
- nativeClick();
+ nativeClick(msg.arg1, msg.arg2);
break;
- case VIEW_SIZE_CHANGED:
- viewSizeChanged(msg.arg1, msg.arg2,
- ((Float) msg.obj).floatValue());
+ case VIEW_SIZE_CHANGED: {
+ WebView.ViewSizeData data =
+ (WebView.ViewSizeData) msg.obj;
+ viewSizeChanged(data.mWidth, data.mHeight,
+ data.mTextWrapWidth, data.mScale,
+ data.mIgnoreHeight);
break;
-
+ }
case SET_SCROLL_OFFSET:
// note: these are in document coordinates
// (inv-zoom)
- nativeSetScrollOffset(msg.arg1, msg.arg2);
+ Point pt = (Point) msg.obj;
+ nativeSetScrollOffset(msg.arg1, pt.x, pt.y);
break;
-
+
case SET_GLOBAL_BOUNDS:
Rect r = (Rect) msg.obj;
nativeSetGlobalBounds(r.left, r.top, r.width(),
@@ -765,7 +940,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 {
@@ -802,6 +977,24 @@ final class WebViewCore {
}
break;
+ case ON_PAUSE:
+ nativePause();
+ break;
+
+ case ON_RESUME:
+ nativeResume();
+ break;
+
+ case FREE_MEMORY:
+ clearCache(false);
+ nativeFreeMemory();
+ break;
+
+ case PLUGIN_STATE:
+ PluginStateData psd = (PluginStateData) msg.obj;
+ nativeUpdatePluginState(psd.mFrame, psd.mNode, psd.mState);
+ break;
+
case SET_NETWORK_STATE:
if (BrowserFrame.sJavaBridge == null) {
throw new IllegalStateException("No WebView " +
@@ -812,10 +1005,7 @@ final class WebViewCore {
break;
case CLEAR_CACHE:
- mBrowserFrame.clearCache();
- if (msg.arg1 == 1) {
- CacheManager.removeAllCacheFiles();
- }
+ clearCache(msg.arg1 == 1);
break;
case CLEAR_HISTORY:
@@ -823,29 +1013,21 @@ final class WebViewCore {
close(mBrowserFrame.mNativeFrame);
break;
- case REPLACE_TEXT:
- HashMap jMap = (HashMap) msg.obj;
- FocusData fData = (FocusData) jMap.get("focusData");
- String replace = (String) jMap.get("replace");
- int newStart =
- ((Integer) jMap.get("start")).intValue();
- int newEnd =
- ((Integer) jMap.get("end")).intValue();
- nativeReplaceTextfieldText(fData.mFrame,
- fData.mNode, fData.mX, fData.mY, msg.arg1,
- msg.arg2, replace, newStart, newEnd);
+ case REPLACE_TEXT:
+ ReplaceTextData rep = (ReplaceTextData) msg.obj;
+ nativeReplaceTextfieldText(msg.arg1, msg.arg2,
+ rep.mReplace, rep.mNewStart, rep.mNewEnd,
+ rep.mTextGeneration);
break;
case PASS_TO_JS: {
- HashMap jsMap = (HashMap) msg.obj;
- FocusData fDat = (FocusData) jsMap.get("focusData");
- KeyEvent evt = (KeyEvent) jsMap.get("event");
+ JSKeyData jsData = (JSKeyData) msg.obj;
+ KeyEvent evt = jsData.mEvent;
int keyCode = evt.getKeyCode();
int keyValue = evt.getUnicodeChar();
int generation = msg.arg1;
- passToJs(fDat.mFrame, fDat.mNode, fDat.mX, fDat.mY,
- generation,
- (String) jsMap.get("currentText"),
+ passToJs(generation,
+ jsData.mCurrentText,
keyCode,
keyValue,
evt.isDown(),
@@ -855,8 +1037,8 @@ final class WebViewCore {
}
case SAVE_DOCUMENT_STATE: {
- FocusData fDat = (FocusData) msg.obj;
- nativeSaveDocumentState(fDat.mFrame);
+ CursorData cDat = (CursorData) msg.obj;
+ nativeSaveDocumentState(cDat.mFrame);
break;
}
@@ -868,11 +1050,8 @@ 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);
break;
case TOUCH_EVENT: {
@@ -885,13 +1064,14 @@ 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");
- String interfaceName = (String)
- map.get("interfaceName");
- mBrowserFrame.addJavascriptInterface(obj,
- interfaceName);
+ JSInterfaceData jsData = (JSInterfaceData) msg.obj;
+ mBrowserFrame.addJavascriptInterface(jsData.mObject,
+ jsData.mInterfaceName);
break;
case REQUEST_EXT_REPRESENTATION:
@@ -903,35 +1083,27 @@ 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);
- break;
-
- case UNBLOCK_FOCUS:
- nativeUnblockFocus();
+ case SET_MOVE_MOUSE:
+ CursorData cursorData = (CursorData) msg.obj;
+ nativeMoveMouse(cursorData.mFrame,
+ cursorData.mX, cursorData.mY);
break;
- case SET_KIT_FOCUS:
- FocusData focusData = (FocusData) msg.obj;
- nativeSetKitFocus(focusData.mMoveGeneration,
- focusData.mBuildGeneration,
- focusData.mFrame, focusData.mNode,
- focusData.mX, focusData.mY,
- focusData.mIgnoreNullFocus);
+ case SET_MOVE_MOUSE_IF_LATEST:
+ CursorData cData = (CursorData) msg.obj;
+ nativeMoveMouseIfLatest(cData.mMoveGeneration,
+ cData.mFrame,
+ cData.mX, cData.mY);
break;
- case REQUEST_FOCUS_HREF: {
+ case REQUEST_CURSOR_HREF: {
Message hrefMsg = (Message) msg.obj;
String res = nativeRetrieveHref(msg.arg1, msg.arg2);
hrefMsg.getData().putString("url", res);
hrefMsg.sendToTarget();
break;
}
-
+
case UPDATE_CACHE_AND_TEXT_ENTRY:
nativeUpdateFrameCache();
// FIXME: this should provide a minimal rectangle
@@ -948,24 +1120,17 @@ final class WebViewCore {
imageResult.sendToTarget();
break;
- 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);
+ TextSelectionData deleteSelectionData
+ = (TextSelectionData) msg.obj;
+ nativeDeleteSelection(deleteSelectionData.mStart,
+ deleteSelectionData.mEnd, msg.arg1);
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;
@@ -974,18 +1139,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
@@ -1005,26 +1170,39 @@ final class WebViewCore {
nativeDumpNavTree();
break;
+ case SET_JS_FLAGS:
+ nativeSetJsFlags((String)msg.obj);
+ break;
+
+ case GEOLOCATION_PERMISSIONS_PROVIDE:
+ GeolocationPermissionsData data =
+ (GeolocationPermissionsData) msg.obj;
+ nativeGeolocationPermissionsProvide(data.mOrigin,
+ data.mAllow, data.mRemember);
+ break;
+
case SYNC_SCROLL:
mWebkitScrollX = msg.arg1;
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;
}
}
};
@@ -1114,7 +1292,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();
}
@@ -1189,20 +1367,42 @@ final class WebViewCore {
// WebViewCore private methods
//-------------------------------------------------------------------------
+ private void clearCache(boolean includeDiskFiles) {
+ mBrowserFrame.clearCache();
+ if (includeDiskFiles) {
+ CacheManager.removeAllCacheFiles();
+ }
+ }
+
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)) {
+ evt.isSymPressed(),
+ isDown) && keyCode != KeyEvent.KEYCODE_ENTER) {
+ if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
+ && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
+ if (DebugFlags.WEB_VIEW_CORE) {
+ Log.v(LOGTAG, "key: arrow unused by plugin: " + keyCode);
+ }
+ if (mWebView != null && evt.isDown()) {
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.MOVE_OUT_OF_PLUGIN, keyCode).sendToTarget();
+ }
+ return;
+ }
// 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);
}
}
@@ -1210,21 +1410,25 @@ final class WebViewCore {
// These values are used to avoid requesting a layout based on old values
private int mCurrentViewWidth = 0;
private int mCurrentViewHeight = 0;
+ private float mCurrentViewScale = 1.0f;
// 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");
+ private void viewSizeChanged(int w, int h, int textwrapWidth, float scale,
+ boolean ignoreHeight) {
+ if (DebugFlags.WEB_VIEW_CORE) {
+ Log.v(LOGTAG, "viewSizeChanged w=" + w + "; h=" + h
+ + "; textwrapWidth=" + textwrapWidth + "; scale=" + scale);
+ }
if (w == 0) {
Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
return;
}
- if (mSettings.getUseWideViewPort()
- && (w < mViewportWidth || mViewportWidth == -1)) {
- int width = mViewportWidth;
+ int width = w;
+ if (mSettings.getUseWideViewPort()) {
if (mViewportWidth == -1) {
- if (mSettings.getLayoutAlgorithm() ==
+ if (mSettings.getLayoutAlgorithm() ==
WebSettings.LayoutAlgorithm.NORMAL) {
- width = WebView.ZOOM_OUT_WIDTH;
+ width = DEFAULT_VIEWPORT_WIDTH;
} else {
/*
* if a page's minimum preferred width is wider than the
@@ -1238,22 +1442,24 @@ final class WebViewCore {
* In the worse case, the native width will be adjusted when
* next zoom or screen orientation change happens.
*/
- width = Math.max(w, nativeGetContentMinPrefWidth());
+ width = Math.max(w, Math.max(DEFAULT_VIEWPORT_WIDTH,
+ nativeGetContentMinPrefWidth()));
}
+ } else {
+ width = Math.max(w, mViewportWidth);
}
- nativeSetSize(width, Math.round((float) width * h / w), w, scale,
- w, h);
- } else {
- nativeSetSize(w, h, w, scale, w, h);
}
+ nativeSetSize(width, width == w ? h : Math.round((float) width * h / w),
+ textwrapWidth, scale, w, h, ignoreHeight);
// Remember the current width and height
boolean needInvalidate = (mCurrentViewWidth == 0);
mCurrentViewWidth = w;
mCurrentViewHeight = h;
+ mCurrentViewScale = scale;
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,
@@ -1267,9 +1473,24 @@ final class WebViewCore {
}
}
+ // Utility method for exceededDatabaseQuota and reachedMaxAppCacheSize
+ // callbacks. Computes the sum of database quota for all origins.
+ private long getUsedQuota() {
+ WebStorage webStorage = WebStorage.getInstance();
+ Set<String> origins = webStorage.getOrigins();
+ if (origins == null) {
+ return 0;
+ }
+ long usedQuota = 0;
+ for (String origin : origins) {
+ usedQuota += webStorage.getQuotaForOrigin(origin);
+ }
+ return usedQuota;
+ }
+
// 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;
@@ -1278,31 +1499,56 @@ final class WebViewCore {
// Used to end scale+scroll mode, accessed by both threads
boolean mEndScaleZoom = false;
-
- public class DrawData {
- public DrawData() {
+
+ // mRestoreState is set in didFirstLayout(), and reset in the next
+ // webkitDraw after passing it to the UI thread.
+ private RestoreState mRestoreState = null;
+
+ static class RestoreState {
+ float mMinScale;
+ float mMaxScale;
+ float mViewScale;
+ float mTextWrapScale;
+ int mScrollX;
+ int mScrollY;
+ boolean mMobileSite;
+ }
+
+ static class DrawData {
+ DrawData() {
mInvalRegion = new Region();
mWidthHeight = new Point();
}
- public Region mInvalRegion;
- public Point mViewPoint;
- public Point mWidthHeight;
+ Region mInvalRegion;
+ Point mViewPoint;
+ Point mWidthHeight;
+ int mMinPrefWidth;
+ RestoreState mRestoreState; // only non-null if it is for the first
+ // picture set after the first layout
}
-
+
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 (WebView.ENABLE_DOUBLETAP_ZOOM && mSettings.getUseWideViewPort()) {
+ draw.mMinPrefWidth = Math.max(DEFAULT_VIEWPORT_WIDTH,
+ nativeGetContentMinPrefWidth());
+ }
+ if (mRestoreState != null) {
+ draw.mRestoreState = mRestoreState;
+ mRestoreState = null;
+ }
+ 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) {
@@ -1312,9 +1558,6 @@ final class WebViewCore {
mWebkitScrollY).sendToTarget();
mWebkitScrollX = mWebkitScrollY = 0;
}
- // nativeSnapToAnchor() needs to be called after NEW_PICTURE_MSG_ID
- // is sent, so that scroll will be based on the new content size.
- nativeSnapToAnchor();
}
}
@@ -1350,6 +1593,10 @@ final class WebViewCore {
}
}
+ /* package */ boolean pictureReady() {
+ return nativePictureReady();
+ }
+
/*package*/ Picture copyContentPicture() {
Picture result = new Picture();
nativeCopyContentToPicture(result);
@@ -1363,9 +1610,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) {
@@ -1385,7 +1632,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();
}
}
@@ -1434,7 +1681,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()) {
@@ -1442,9 +1689,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();
+ }
}
}
@@ -1461,8 +1713,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();
+ }
}
}
@@ -1479,24 +1737,14 @@ final class WebViewCore {
return;
}
if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.SPAWN_SCROLL_TO_MSG_ID, x, y).sendToTarget();
- }
- }
-
- // called by JNI
- private void sendMarkNodeInvalid(int node) {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.MARK_NODE_INVALID_ID, node, 0).sendToTarget();
- }
- }
-
- // called by JNI
- private void sendNotifyFocusSet() {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.NOTIFY_FOCUS_SET_MSG_ID).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();
+ }
}
}
@@ -1511,14 +1759,6 @@ final class WebViewCore {
contentDraw();
}
- // called by JNI
- private void sendRecomputeFocus() {
- if (mWebView != null) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.RECOMPUTE_FOCUS_MSG_ID).sendToTarget();
- }
- }
-
/* Called by JNI. The coordinates are in doc coordinates, so they need to
be scaled before they can be used by the view system, which happens
in WebView since it (and its thread) know the current scale factor.
@@ -1536,27 +1776,36 @@ final class WebViewCore {
}
private native void setViewportSettingsFromNative();
-
+
// called by JNI
- private void didFirstLayout() {
- // 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
- // white space in the GMail which uses WebView for message view.
- if (mWebView != null && mWebView.mHeightCanMeasure) {
- mWebView.mLastHeightSent = 0;
- // Send a negative scale to indicate that WebCore should reuse the
- // current scale
- mEventHub.sendMessage(Message.obtain(null,
- EventHub.VIEW_SIZE_CHANGED, mWebView.mLastWidthSent,
- mWebView.mLastHeightSent, -1.0f));
+ private void didFirstLayout(boolean standardLoad) {
+ if (DebugFlags.WEB_VIEW_CORE) {
+ Log.v(LOGTAG, "didFirstLayout standardLoad =" + standardLoad);
}
mBrowserFrame.didFirstLayout();
- // reset the scroll position as it is a new page now
- mWebkitScrollX = mWebkitScrollY = 0;
+ if (mWebView == null) return;
+
+ setupViewport(standardLoad || mRestoredScale > 0);
+ // reset the scroll position, the restored offset and scales
+ mWebkitScrollX = mWebkitScrollY = mRestoredX = mRestoredY
+ = mRestoredScale = mRestoredScreenWidthScale = 0;
+ }
+
+ // called by JNI
+ private void updateViewport() {
+ // if updateViewport is called before first layout, wait until first
+ // layout to update the viewport. In the rare case, this is called after
+ // first layout, force an update as we have just parsed the viewport
+ // meta tag.
+ if (mBrowserFrame.firstLayoutDone()) {
+ setupViewport(true);
+ }
+ }
+
+ private void setupViewport(boolean updateRestoreState) {
// set the viewport settings from WebKit
setViewportSettingsFromNative();
@@ -1607,38 +1856,83 @@ final class WebViewCore {
mViewportWidth = 0;
}
- // now notify webview
- if (mWebView != null) {
- HashMap scaleLimit = new HashMap();
- scaleLimit.put("minScale", mViewportMinimumScale);
- scaleLimit.put("maxScale", mViewportMaximumScale);
+ // if mViewportWidth is 0, it means device-width, always update.
+ if (mViewportWidth != 0 && !updateRestoreState) return;
- if (mRestoredScale > 0) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.DID_FIRST_LAYOUT_MSG_ID, mRestoredScale, 0,
- scaleLimit).sendToTarget();
- mRestoredScale = 0;
+ // now notify webview
+ int webViewWidth = Math.round(mCurrentViewWidth * mCurrentViewScale);
+ mRestoreState = new RestoreState();
+ mRestoreState.mMinScale = mViewportMinimumScale / 100.0f;
+ mRestoreState.mMaxScale = mViewportMaximumScale / 100.0f;
+ mRestoreState.mScrollX = mRestoredX;
+ mRestoreState.mScrollY = mRestoredY;
+ mRestoreState.mMobileSite = (0 == mViewportWidth);
+ if (mRestoredScale > 0) {
+ if (mRestoredScreenWidthScale > 0) {
+ mRestoreState.mTextWrapScale =
+ mRestoredScreenWidthScale / 100.0f;
+ // 0 will trigger WebView to turn on zoom overview mode
+ mRestoreState.mViewScale = 0;
} else {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.DID_FIRST_LAYOUT_MSG_ID, mViewportInitialScale,
- mViewportWidth, scaleLimit).sendToTarget();
+ mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
+ mRestoredScale / 100.0f;
}
+ } else {
+ if (mViewportInitialScale > 0) {
+ mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
+ mViewportInitialScale / 100.0f;
+ } else if (mViewportWidth > 0 && mViewportWidth < webViewWidth) {
+ mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
+ (float) webViewWidth / mViewportWidth;
+ } else {
+ mRestoreState.mTextWrapScale =
+ WebView.DEFAULT_SCALE_PERCENT / 100.0f;
+ // 0 will trigger WebView to turn on zoom overview mode
+ mRestoreState.mViewScale = 0;
+ }
+ }
- // 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) {
- if (mDrawIsScheduled) {
- mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
- }
- mDrawIsScheduled = true;
- mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
- EventHub.WEBKIT_DRAW));
- }
+ if (mWebView.mHeightCanMeasure) {
+ // 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 white space in the GMail which uses WebView for
+ // message view.
+ mWebView.mLastHeightSent = 0;
+ // Send a negative scale to indicate that WebCore should reuse
+ // the current scale
+ WebView.ViewSizeData data = new WebView.ViewSizeData();
+ data.mWidth = mWebView.mLastWidthSent;
+ data.mHeight = 0;
+ // if mHeightCanMeasure is true, getUseWideViewPort() can't be
+ // true. It is safe to use mWidth for mTextWrapWidth.
+ data.mTextWrapWidth = data.mWidth;
+ data.mScale = -1.0f;
+ data.mIgnoreHeight = false;
+ mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
+ EventHub.VIEW_SIZE_CHANGED, data));
+ } else if (mSettings.getUseWideViewPort()) {
+ if (mCurrentViewWidth == 0) {
+ // Trick to ensure VIEW_SIZE_CHANGED will be sent from WebView
+ // to WebViewCore
+ mWebView.mLastWidthSent = 0;
+ } else {
+ WebView.ViewSizeData data = new WebView.ViewSizeData();
+ // mViewScale as 0 means it is in zoom overview mode. So we don't
+ // know the exact scale. If mRestoredScale is non-zero, use it;
+ // otherwise just use mTextWrapScale as the initial scale.
+ data.mScale = mRestoreState.mViewScale == 0
+ ? (mRestoredScale > 0 ? mRestoredScale
+ : mRestoreState.mTextWrapScale)
+ : mRestoreState.mViewScale;
+ data.mWidth = Math.round(webViewWidth / data.mScale);
+ data.mHeight = mCurrentViewHeight * data.mWidth
+ / mCurrentViewWidth;
+ data.mTextWrapWidth = Math.round(webViewWidth
+ / mRestoreState.mTextWrapScale);
+ data.mIgnoreHeight = false;
+ mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
+ EventHub.VIEW_SIZE_CHANGED, data));
}
}
}
@@ -1651,6 +1945,17 @@ final class WebViewCore {
}
// called by JNI
+ private void restoreScreenWidthScale(int scale) {
+ if (!WebView.ENABLE_DOUBLETAP_ZOOM || !mSettings.getUseWideViewPort()) {
+ return;
+ }
+
+ if (mBrowserFrame.firstLayoutDone() == false) {
+ mRestoredScreenWidthScale = scale;
+ }
+ }
+
+ // called by JNI
private void needTouchEvents(boolean need) {
if (mWebView != null) {
Message.obtain(mWebView.mPrivateHandler,
@@ -1664,15 +1969,39 @@ 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();
}
}
+ // called by JNI
+ private void updateTextSelection(int pointer, int start, int end,
+ int textGeneration) {
+ if (mWebView != null) {
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration,
+ new TextSelectionData(start, end)).sendToTarget();
+ }
+ }
+
+ // called by JNI
+ private void clearTextEntry() {
+ if (mWebView == null) return;
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.CLEAR_TEXT_ENTRY).sendToTarget();
+ }
+
+ private native void nativeUpdateFrameCacheIfLoading();
+
+ /**
+ * Scroll the focused textfield to (x, y) in document space
+ */
+ private native void nativeScrollFocusedTextInput(int x, int y);
+
// these must be in document space (i.e. not scaled/zoomed).
- private native void nativeSetScrollOffset(int dx, int dy);
+ private native void nativeSetScrollOffset(int gen, int dx, int dy);
private native void nativeSetGlobalBounds(int x, int y, int w, int h);
@@ -1690,6 +2019,97 @@ final class WebViewCore {
if (mWebView != null) {
mWebView.requestListBox(array, enabledArray, selection);
}
-
+
+ }
+
+ // called by JNI
+ private void requestKeyboard(boolean showKeyboard) {
+ if (mWebView != null) {
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.REQUEST_KEYBOARD, showKeyboard ? 1 : 0, 0)
+ .sendToTarget();
+ }
}
+
+ // This class looks like a SurfaceView to native code. In java, we can
+ // assume the passed in SurfaceView is this class so we can talk to the
+ // ViewManager through the ChildView.
+ private class SurfaceViewProxy extends SurfaceView
+ implements SurfaceHolder.Callback {
+ private final ViewManager.ChildView mChildView;
+ private int mPointer;
+ private final boolean mIsFixedSize;
+ SurfaceViewProxy(Context context, ViewManager.ChildView childView,
+ int pointer, int pixelFormat, boolean isFixedSize) {
+ super(context);
+ setWillNotDraw(false); // this prevents the black box artifact
+ getHolder().addCallback(this);
+ getHolder().setFormat(pixelFormat);
+ mChildView = childView;
+ mChildView.mView = this;
+ mPointer = pointer;
+ mIsFixedSize = isFixedSize;
+ }
+ void destroy() {
+ mPointer = 0;
+ mChildView.removeView();
+ }
+ void attach(int x, int y, int width, int height) {
+ mChildView.attachView(x, y, width, height);
+
+ if (mIsFixedSize) {
+ getHolder().setFixedSize(width, height);
+ }
+ }
+
+ // SurfaceHolder.Callback methods
+ public void surfaceCreated(SurfaceHolder holder) {
+ if (mPointer != 0) {
+ nativeSurfaceChanged(mPointer, 0, 0, 0, 0);
+ }
+ }
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {
+ if (mPointer != 0) {
+ nativeSurfaceChanged(mPointer, 1, format, width, height);
+ }
+ }
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ if (mPointer != 0) {
+ nativeSurfaceChanged(mPointer, 2, 0, 0, 0);
+ }
+ }
+ }
+
+ // PluginWidget functions for mainting SurfaceViews for the Surface drawing
+ // model.
+ private SurfaceView createSurface(int nativePointer, int pixelFormat,
+ boolean isFixedSize) {
+ if (mWebView == null) {
+ return null;
+ }
+ return new SurfaceViewProxy(mContext, mWebView.mViewManager.createView(),
+ nativePointer, pixelFormat, isFixedSize);
+ }
+
+ private void destroySurface(SurfaceView surface) {
+ SurfaceViewProxy proxy = (SurfaceViewProxy) surface;
+ proxy.destroy();
+ }
+
+ private void attachSurface(SurfaceView surface, int x, int y,
+ int width, int height) {
+ SurfaceViewProxy proxy = (SurfaceViewProxy) surface;
+ proxy.attach(x, y, width, height);
+ }
+
+ // Callback for the SurfaceHolder.Callback. Called for all the surface
+ // callbacks. The state parameter is one of Created(0), Changed(1),
+ // Destroyed(2).
+ private native void nativeSurfaceChanged(int pointer, int state, int format,
+ int width, int height);
+
+ private native void nativePause();
+ private native void nativeResume();
+ private native void nativeFreeMemory();
}
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 1004e30..4e76254 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -48,7 +48,9 @@ public class WebViewDatabase {
// 6 -> 7 Change cache localPath from int to String
// 7 -> 8 Move cache to its own db
// 8 -> 9 Store both scheme and host when storing passwords
- private static final int CACHE_DATABASE_VERSION = 1;
+ private static final int CACHE_DATABASE_VERSION = 3;
+ // 1 -> 2 Add expires String
+ // 2 -> 3 Add content-disposition
private static WebViewDatabase mInstance = null;
@@ -107,6 +109,8 @@ public class WebViewDatabase {
private static final String CACHE_EXPIRES_COL = "expires";
+ private static final String CACHE_EXPIRES_STRING_COL = "expiresstring";
+
private static final String CACHE_MIMETYPE_COL = "mimetype";
private static final String CACHE_ENCODING_COL = "encoding";
@@ -117,6 +121,8 @@ public class WebViewDatabase {
private static final String CACHE_CONTENTLENGTH_COL = "contentlength";
+ private static final String CACHE_CONTENTDISPOSITION_COL = "contentdisposition";
+
// column id strings for "password" table
private static final String PASSWORD_HOST_COL = "host";
@@ -150,11 +156,13 @@ public class WebViewDatabase {
private static int mCacheLastModifyColIndex;
private static int mCacheETagColIndex;
private static int mCacheExpiresColIndex;
+ private static int mCacheExpiresStringColIndex;
private static int mCacheMimeTypeColIndex;
private static int mCacheEncodingColIndex;
private static int mCacheHttpStatusColIndex;
private static int mCacheLocationColIndex;
private static int mCacheContentLengthColIndex;
+ private static int mCacheContentDispositionColIndex;
private static int mCacheTransactionRefcount;
@@ -220,6 +228,8 @@ public class WebViewDatabase {
.getColumnIndex(CACHE_ETAG_COL);
mCacheExpiresColIndex = mCacheInserter
.getColumnIndex(CACHE_EXPIRES_COL);
+ mCacheExpiresStringColIndex = mCacheInserter
+ .getColumnIndex(CACHE_EXPIRES_STRING_COL);
mCacheMimeTypeColIndex = mCacheInserter
.getColumnIndex(CACHE_MIMETYPE_COL);
mCacheEncodingColIndex = mCacheInserter
@@ -230,6 +240,8 @@ public class WebViewDatabase {
.getColumnIndex(CACHE_LOCATION_COL);
mCacheContentLengthColIndex = mCacheInserter
.getColumnIndex(CACHE_CONTENTLENGTH_COL);
+ mCacheContentDispositionColIndex = mCacheInserter
+ .getColumnIndex(CACHE_CONTENTDISPOSITION_COL);
}
}
@@ -320,11 +332,12 @@ public class WebViewDatabase {
+ " TEXT, " + CACHE_FILE_PATH_COL + " TEXT, "
+ CACHE_LAST_MODIFY_COL + " TEXT, " + CACHE_ETAG_COL
+ " TEXT, " + CACHE_EXPIRES_COL + " INTEGER, "
+ + CACHE_EXPIRES_STRING_COL + " TEXT, "
+ CACHE_MIMETYPE_COL + " TEXT, " + CACHE_ENCODING_COL
+ " TEXT," + CACHE_HTTP_STATUS_COL + " INTEGER, "
+ CACHE_LOCATION_COL + " TEXT, " + CACHE_CONTENTLENGTH_COL
- + " INTEGER, " + " UNIQUE (" + CACHE_URL_COL
- + ") ON CONFLICT REPLACE);");
+ + " INTEGER, " + CACHE_CONTENTDISPOSITION_COL + " TEXT, "
+ + " UNIQUE (" + CACHE_URL_COL + ") ON CONFLICT REPLACE);");
mCacheDatabase.execSQL("CREATE INDEX cacheUrlIndex ON cache ("
+ CACHE_URL_COL + ")");
}
@@ -537,8 +550,8 @@ public class WebViewDatabase {
}
Cursor cursor = mCacheDatabase.rawQuery("SELECT filepath, lastmodify, etag, expires, "
- + "mimetype, encoding, httpstatus, location, contentlength "
- + "FROM cache WHERE url = ?",
+ + "expiresstring, mimetype, encoding, httpstatus, location, contentlength, "
+ + "contentdisposition FROM cache WHERE url = ?",
new String[] { url });
try {
@@ -548,11 +561,13 @@ public class WebViewDatabase {
ret.lastModified = cursor.getString(1);
ret.etag = cursor.getString(2);
ret.expires = cursor.getLong(3);
- ret.mimeType = cursor.getString(4);
- ret.encoding = cursor.getString(5);
- ret.httpStatusCode = cursor.getInt(6);
- ret.location = cursor.getString(7);
- ret.contentLength = cursor.getLong(8);
+ ret.expiresString = cursor.getString(4);
+ ret.mimeType = cursor.getString(5);
+ ret.encoding = cursor.getString(6);
+ ret.httpStatusCode = cursor.getInt(7);
+ ret.location = cursor.getString(8);
+ ret.contentLength = cursor.getLong(9);
+ ret.contentdisposition = cursor.getString(10);
return ret;
}
} finally {
@@ -591,11 +606,14 @@ public class WebViewDatabase {
mCacheInserter.bind(mCacheLastModifyColIndex, c.lastModified);
mCacheInserter.bind(mCacheETagColIndex, c.etag);
mCacheInserter.bind(mCacheExpiresColIndex, c.expires);
+ mCacheInserter.bind(mCacheExpiresStringColIndex, c.expiresString);
mCacheInserter.bind(mCacheMimeTypeColIndex, c.mimeType);
mCacheInserter.bind(mCacheEncodingColIndex, c.encoding);
mCacheInserter.bind(mCacheHttpStatusColIndex, c.httpStatusCode);
mCacheInserter.bind(mCacheLocationColIndex, c.location);
mCacheInserter.bind(mCacheContentLengthColIndex, c.contentLength);
+ mCacheInserter.bind(mCacheContentDispositionColIndex,
+ c.contentdisposition);
mCacheInserter.execute();
}
diff --git a/core/java/android/webkit/gears/AndroidGpsLocationProvider.java b/core/java/android/webkit/gears/AndroidGpsLocationProvider.java
deleted file mode 100644
index 3646042..0000000
--- a/core/java/android/webkit/gears/AndroidGpsLocationProvider.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
-import android.os.Bundle;
-import android.util.Log;
-import android.webkit.WebView;
-
-/**
- * GPS provider implementation for Android.
- */
-public final class AndroidGpsLocationProvider implements LocationListener {
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-GpsProvider";
- /**
- * Our location manager instance.
- */
- private LocationManager locationManager;
- /**
- * The native object ID.
- */
- private long nativeObject;
-
- public AndroidGpsLocationProvider(WebView webview, long object) {
- nativeObject = object;
- locationManager = (LocationManager) webview.getContext().getSystemService(
- Context.LOCATION_SERVICE);
- if (locationManager == null) {
- Log.e(TAG,
- "AndroidGpsLocationProvider: could not get location manager.");
- throw new NullPointerException(
- "AndroidGpsLocationProvider: locationManager is null.");
- }
- // Register for location updates.
- try {
- locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
- this);
- } catch (IllegalArgumentException ex) {
- Log.e(TAG,
- "AndroidLocationGpsProvider: could not register for updates: " + ex);
- throw ex;
- } catch (SecurityException ex) {
- Log.e(TAG,
- "AndroidGpsLocationProvider: not allowed to register for update: "
- + ex);
- throw ex;
- }
- }
-
- /**
- * Called when the provider is no longer needed.
- */
- public void shutdown() {
- locationManager.removeUpdates(this);
- Log.i(TAG, "GPS provider closed.");
- }
-
- /**
- * Called when the location has changed.
- * @param location The new location, as a Location object.
- */
- public void onLocationChanged(Location location) {
- Log.i(TAG, "Location changed: " + location);
- nativeLocationChanged(location, nativeObject);
- }
-
- /**
- * Called when the provider status changes.
- *
- * @param provider the name of the location provider associated with this
- * update.
- * @param status {@link LocationProvider#OUT_OF_SERVICE} if the
- * provider is out of service, and this is not expected to change in the
- * near future; {@link LocationProvider#TEMPORARILY_UNAVAILABLE} if
- * the provider is temporarily unavailable but is expected to be available
- * shortly; and {@link LocationProvider#AVAILABLE} if the
- * provider is currently available.
- * @param extras an optional Bundle which will contain provider specific
- * status variables (such as number of satellites).
- */
- public void onStatusChanged(String provider, int status, Bundle extras) {
- Log.i(TAG, "Provider " + provider + " status changed to " + status);
- if (status == LocationProvider.OUT_OF_SERVICE ||
- status == LocationProvider.TEMPORARILY_UNAVAILABLE) {
- nativeProviderError(false, nativeObject);
- }
- }
-
- /**
- * Called when the provider is enabled.
- *
- * @param provider the name of the location provider that is now enabled.
- */
- public void onProviderEnabled(String provider) {
- Log.i(TAG, "Provider " + provider + " enabled.");
- // No need to notify the native side. It's enough to start sending
- // valid position fixes again.
- }
-
- /**
- * Called when the provider is disabled.
- *
- * @param provider the name of the location provider that is now disabled.
- */
- public void onProviderDisabled(String provider) {
- Log.i(TAG, "Provider " + provider + " disabled.");
- nativeProviderError(true, nativeObject);
- }
-
- /**
- * The native method called when a new location is available.
- * @param location is the new Location instance to pass to the native side.
- * @param nativeObject is a pointer to the corresponding
- * AndroidGpsLocationProvider C++ instance.
- */
- private native void nativeLocationChanged(Location location, long object);
-
- /**
- * The native method called when there is a GPS provder error.
- * @param isDisabled is true when the error signifies the fact that the GPS
- * HW is disabled. For other errors, this param is always false.
- * @param nativeObject is a pointer to the corresponding
- * AndroidGpsLocationProvider C++ instance.
- */
- private native void nativeProviderError(boolean isDisabled, long object);
-}
diff --git a/core/java/android/webkit/gears/AndroidRadioDataProvider.java b/core/java/android/webkit/gears/AndroidRadioDataProvider.java
deleted file mode 100644
index 1384042..0000000
--- a/core/java/android/webkit/gears/AndroidRadioDataProvider.java
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.telephony.CellLocation;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.gsm.GsmCellLocation;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.webkit.WebView;
-
-/**
- * Radio data provider implementation for Android.
- */
-public final class AndroidRadioDataProvider extends PhoneStateListener {
-
- /** Logging tag */
- private static final String TAG = "Gears-J-RadioProvider";
-
- /** Network types */
- private static final int RADIO_TYPE_UNKNOWN = 0;
- private static final int RADIO_TYPE_GSM = 1;
- private static final int RADIO_TYPE_WCDMA = 2;
- private static final int RADIO_TYPE_CDMA = 3;
- private static final int RADIO_TYPE_EVDO = 4;
- private static final int RADIO_TYPE_1xRTT = 5;
-
- /** Simple container for radio data */
- public static final class RadioData {
- public int cellId = -1;
- public int locationAreaCode = -1;
- // TODO: use new SignalStrength instead of asu
- public int signalStrength = -1;
- public int mobileCountryCode = -1;
- public int mobileNetworkCode = -1;
- public int homeMobileCountryCode = -1;
- public int homeMobileNetworkCode = -1;
- public int radioType = RADIO_TYPE_UNKNOWN;
- public String carrierName;
-
- /**
- * Constructs radioData object from the given telephony data.
- * @param telephonyManager contains the TelephonyManager instance.
- * @param cellLocation contains information about the current GSM cell.
- * @param signalStrength is the strength of the network signal.
- * @param serviceState contains information about the network service.
- * @return a new RadioData object populated with the currently
- * available network information or null if there isn't
- * enough information.
- */
- public static RadioData getInstance(TelephonyManager telephonyManager,
- CellLocation cellLocation, int signalStrength,
- ServiceState serviceState) {
-
- if (!(cellLocation instanceof GsmCellLocation)) {
- // This also covers the case when cellLocation is null.
- // When that happens, we do not bother creating a
- // RadioData instance.
- return null;
- }
-
- RadioData radioData = new RadioData();
- GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation;
-
- // Extract the cell id, LAC, and signal strength.
- radioData.cellId = gsmCellLocation.getCid();
- radioData.locationAreaCode = gsmCellLocation.getLac();
- radioData.signalStrength = signalStrength;
-
- // Extract the home MCC and home MNC.
- String operator = telephonyManager.getSimOperator();
- radioData.setMobileCodes(operator, true);
-
- if (serviceState != null) {
- // Extract the carrier name.
- radioData.carrierName = serviceState.getOperatorAlphaLong();
-
- // Extract the MCC and MNC.
- operator = serviceState.getOperatorNumeric();
- radioData.setMobileCodes(operator, false);
- }
-
- // Finally get the radio type.
- //TODO We have to edit the parameter for getNetworkType regarding CDMA
- int type = telephonyManager.getNetworkType();
- if (type == TelephonyManager.NETWORK_TYPE_UMTS) {
- radioData.radioType = RADIO_TYPE_WCDMA;
- } else if (type == TelephonyManager.NETWORK_TYPE_GPRS
- || type == TelephonyManager.NETWORK_TYPE_EDGE) {
- radioData.radioType = RADIO_TYPE_GSM;
- } else if (type == TelephonyManager.NETWORK_TYPE_CDMA) {
- radioData.radioType = RADIO_TYPE_CDMA;
- } else if (type == TelephonyManager.NETWORK_TYPE_EVDO_0) {
- radioData.radioType = RADIO_TYPE_EVDO;
- } else if (type == TelephonyManager.NETWORK_TYPE_EVDO_A) {
- radioData.radioType = RADIO_TYPE_EVDO;
- } else if (type == TelephonyManager.NETWORK_TYPE_1xRTT) {
- radioData.radioType = RADIO_TYPE_1xRTT;
- }
-
- // Print out what we got.
- Log.i(TAG, "Got the following data:");
- Log.i(TAG, "CellId: " + radioData.cellId);
- Log.i(TAG, "LAC: " + radioData.locationAreaCode);
- Log.i(TAG, "MNC: " + radioData.mobileNetworkCode);
- Log.i(TAG, "MCC: " + radioData.mobileCountryCode);
- Log.i(TAG, "home MNC: " + radioData.homeMobileNetworkCode);
- Log.i(TAG, "home MCC: " + radioData.homeMobileCountryCode);
- Log.i(TAG, "Signal strength: " + radioData.signalStrength);
- Log.i(TAG, "Carrier: " + radioData.carrierName);
- Log.i(TAG, "Network type: " + radioData.radioType);
-
- return radioData;
- }
-
- private RadioData() {}
-
- /**
- * Parses a string containing a mobile country code and a mobile
- * network code and sets the corresponding member variables.
- * @param codes is the string to parse.
- * @param homeValues flags whether the codes are for the home operator.
- */
- private void setMobileCodes(String codes, boolean homeValues) {
- if (codes != null) {
- try {
- // The operator numeric format is 3 digit country code plus 2 or
- // 3 digit network code.
- int mcc = Integer.parseInt(codes.substring(0, 3));
- int mnc = Integer.parseInt(codes.substring(3));
- if (homeValues) {
- homeMobileCountryCode = mcc;
- homeMobileNetworkCode = mnc;
- } else {
- mobileCountryCode = mcc;
- mobileNetworkCode = mnc;
- }
- } catch (IndexOutOfBoundsException ex) {
- Log.e(
- TAG,
- "AndroidRadioDataProvider: Invalid operator numeric data: " + ex);
- } catch (NumberFormatException ex) {
- Log.e(
- TAG,
- "AndroidRadioDataProvider: Operator numeric format error: " + ex);
- }
- }
- }
- };
-
- /** The native object ID */
- private long nativeObject;
-
- /** The last known cellLocation */
- private CellLocation cellLocation = null;
-
- /** The last known signal strength */
- // TODO: use new SignalStrength instead of asu
- private int signalStrength = -1;
-
- /** The last known serviceState */
- private ServiceState serviceState = null;
-
- /**
- * Our TelephonyManager instance.
- */
- private TelephonyManager telephonyManager;
-
- /**
- * Public constructor. Uses the webview to get the Context object.
- */
- public AndroidRadioDataProvider(WebView webview, long object) {
- super();
- nativeObject = object;
- telephonyManager = (TelephonyManager) webview.getContext().getSystemService(
- Context.TELEPHONY_SERVICE);
- if (telephonyManager == null) {
- Log.e(TAG,
- "AndroidRadioDataProvider: could not get tepephony manager.");
- throw new NullPointerException(
- "AndroidRadioDataProvider: telephonyManager is null.");
- }
-
- // Register for cell id, signal strength and service state changed
- // notifications.
- telephonyManager.listen(this, PhoneStateListener.LISTEN_CELL_LOCATION
- | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
- | PhoneStateListener.LISTEN_SERVICE_STATE);
- }
-
- /**
- * Should be called when the provider is no longer needed.
- */
- public void shutdown() {
- telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
- Log.i(TAG, "AndroidRadioDataProvider shutdown.");
- }
-
- @Override
- public void onServiceStateChanged(ServiceState state) {
- serviceState = state;
- notifyListeners();
- }
-
- @Override
- public void onSignalStrengthsChanged(SignalStrength ss) {
- int gsmSignalStrength = ss.getGsmSignalStrength();
- signalStrength = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
- notifyListeners();
- }
-
- @Override
- public void onCellLocationChanged(CellLocation location) {
- cellLocation = location;
- notifyListeners();
- }
-
- private void notifyListeners() {
- RadioData radioData = RadioData.getInstance(telephonyManager, cellLocation,
- signalStrength, serviceState);
- if (radioData != null) {
- onUpdateAvailable(radioData, nativeObject);
- }
- }
-
- /**
- * The native method called when new radio data is available.
- * @param radioData is the RadioData instance to pass to the native side.
- * @param nativeObject is a pointer to the corresponding
- * AndroidRadioDataProvider C++ instance.
- */
- private static native void onUpdateAvailable(
- RadioData radioData, long nativeObject);
-}
diff --git a/core/java/android/webkit/gears/AndroidWifiDataProvider.java b/core/java/android/webkit/gears/AndroidWifiDataProvider.java
deleted file mode 100644
index d2850b0..0000000
--- a/core/java/android/webkit/gears/AndroidWifiDataProvider.java
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2008, Google Inc.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.webkit.WebView;
-import java.util.List;
-
-/**
- * WiFi data provider implementation for Android.
- * {@hide}
- */
-public final class AndroidWifiDataProvider extends BroadcastReceiver {
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-WifiProvider";
- /**
- * Flag for guarding Log.v() calls.
- * Set to true to enable extra debug logging.
- */
- private static final boolean LOGV_ENABLED = false;
- /**
- * Our Wifi manager instance.
- */
- private WifiManager mWifiManager;
- /**
- * The native object ID.
- */
- private long mNativeObject;
- /**
- * The Context instance.
- */
- private Context mContext;
-
- /**
- * Constructs a instance of this class and registers for wifi scan
- * updates. Note that this constructor must be called on a Looper
- * thread. Suitable threads can be created on the native side using
- * the AndroidLooperThread C++ class.
- */
- public AndroidWifiDataProvider(WebView webview, long object) {
- mNativeObject = object;
- mContext = webview.getContext();
- mWifiManager =
- (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- if (mWifiManager == null) {
- Log.e(TAG,
- "AndroidWifiDataProvider: could not get location manager.");
- throw new NullPointerException(
- "AndroidWifiDataProvider: locationManager is null.");
- }
-
- // Create a Handler that identifies the message loop associated
- // with the current thread. Note that it is not necessary to
- // override handleMessage() at all since the Intent
- // ReceiverDispatcher (see the ActivityThread class) only uses
- // this handler to post a Runnable to this thread's loop.
- Handler handler = new Handler(Looper.myLooper());
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
- mContext.registerReceiver(this, filter, null, handler);
-
- // Get the last scan results and pass them to the native side.
- // We can't just invoke the callback here, so we queue a message
- // to this thread's loop.
- handler.post(new Runnable() {
- public void run() {
- onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
- }
- });
- }
-
- /**
- * Called when the provider is no longer needed.
- */
- public void shutdown() {
- mContext.unregisterReceiver(this);
- if (LOGV_ENABLED) {
- Log.v(TAG, "Wifi provider closed.");
- }
- }
-
- /**
- * This method is called when the AndroidWifiDataProvider is receiving an
- * Intent broadcast.
- * @param context The Context in which the receiver is running.
- * @param intent The Intent being received.
- */
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(
- mWifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- if (LOGV_ENABLED) {
- Log.v(TAG, "Wifi scan resulst available");
- }
- onUpdateAvailable(mWifiManager.getScanResults(), mNativeObject);
- }
- }
-
- /**
- * The native method called when new wifi data is available.
- * @param scanResults is a list of ScanResults to pass to the native side.
- * @param nativeObject is a pointer to the corresponding
- * AndroidWifiDataProvider C++ instance.
- */
- private static native void onUpdateAvailable(
- List<ScanResult> scanResults, long nativeObject);
-}
diff --git a/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java b/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java
deleted file mode 100644
index 74d27ed..0000000
--- a/core/java/android/webkit/gears/ApacheHttpRequestAndroid.java
+++ /dev/null
@@ -1,1134 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.net.http.Headers;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-import android.webkit.CacheManager;
-import android.webkit.CacheManager.CacheResult;
-import android.webkit.CookieManager;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.IOException;
-import java.lang.StringBuilder;
-import java.util.Date;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Iterator;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.HttpResponse;
-import org.apache.http.entity.AbstractHttpEntity;
-import org.apache.http.client.*;
-import org.apache.http.client.methods.*;
-import org.apache.http.impl.client.AbstractHttpClient;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
-import org.apache.http.conn.ssl.StrictHostnameVerifier;
-import org.apache.http.impl.cookie.DateUtils;
-import org.apache.http.util.CharArrayBuffer;
-
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Performs the underlying HTTP/HTTPS GET, POST, HEAD, PUT, DELETE requests.
- * <p> These are performed synchronously (blocking). The caller should
- * ensure that it is in a background thread if asynchronous behavior
- * is required. All data is pushed, so there is no need for JNI native
- * callbacks.
- * <p> This uses Apache's HttpClient framework to perform most
- * of the underlying network activity. The Android brower's cache,
- * android.webkit.CacheManager, is also used when caching is enabled,
- * and updated with new data. The android.webkit.CookieManager is also
- * queried and updated as necessary.
- * <p> The public interface is designed to be called by native code
- * through JNI, and to simplify coding none of the public methods will
- * surface a checked exception. Unchecked exceptions may still be
- * raised but only if the system is in an ill state, such as out of
- * memory.
- * <p> TODO: This isn't plumbed into LocalServer yet. Mutually
- * dependent on LocalServer - will attach the two together once both
- * are submitted.
- */
-public final class ApacheHttpRequestAndroid {
- /** Debug logging tag. */
- private static final String LOG_TAG = "Gears-J";
- /** Flag for guarding Log.v() calls. */
- private static final boolean LOGV_ENABLED = false;
- /** HTTP response header line endings are CR-LF style. */
- private static final String HTTP_LINE_ENDING = "\r\n";
- /** Safe MIME type to use whenever it isn't specified. */
- private static final String DEFAULT_MIME_TYPE = "text/plain";
- /** Case-sensitive header keys */
- public static final String KEY_CONTENT_LENGTH = "Content-Length";
- public static final String KEY_EXPIRES = "Expires";
- public static final String KEY_LAST_MODIFIED = "Last-Modified";
- public static final String KEY_ETAG = "ETag";
- public static final String KEY_LOCATION = "Location";
- public static final String KEY_CONTENT_TYPE = "Content-Type";
- /** Number of bytes to send and receive on the HTTP connection in
- * one go. */
- private static final int BUFFER_SIZE = 4096;
-
- /** The first element of the String[] value in a headers map is the
- * unmodified (case-sensitive) key. */
- public static final int HEADERS_MAP_INDEX_KEY = 0;
- /** The second element of the String[] value in a headers map is the
- * associated value. */
- public static final int HEADERS_MAP_INDEX_VALUE = 1;
-
- /** Request headers, as key -> value map. */
- // TODO: replace this design by a simpler one (the C++ side has to
- // be modified too), where we do not store both the original header
- // and the lowercase one.
- private Map<String, String[]> mRequestHeaders =
- new HashMap<String, String[]>();
- /** Response headers, as a lowercase key -> value map. */
- private Map<String, String[]> mResponseHeaders =
- new HashMap<String, String[]>();
- /** The URL used for createCacheResult() */
- private String mCacheResultUrl;
- /** CacheResult being saved into, if inserting a new cache entry. */
- private CacheResult mCacheResult;
- /** Initialized by initChildThread(). Used to target abort(). */
- private Thread mBridgeThread;
-
- /** Our HttpClient */
- private AbstractHttpClient mClient;
- /** The HttpMethod associated with this request */
- private HttpRequestBase mMethod;
- /** The complete response line e.g "HTTP/1.0 200 OK" */
- private String mResponseLine;
- /** HTTP body stream, setup after connection. */
- private InputStream mBodyInputStream;
-
- /** HTTP Response Entity */
- private HttpResponse mResponse;
-
- /** Post Entity, used to stream the request to the server */
- private StreamEntity mPostEntity = null;
- /** Content lenght, mandatory when using POST */
- private long mContentLength;
-
- /** The request executes in a parallel thread */
- private Thread mHttpThread = null;
- /** protect mHttpThread, if interrupt() is called concurrently */
- private Lock mHttpThreadLock = new ReentrantLock();
- /** Flag set to true when the request thread is joined */
- private boolean mConnectionFinished = false;
- /** Flag set to true by interrupt() and/or connection errors */
- private boolean mConnectionFailed = false;
- /** Lock protecting the access to mConnectionFailed */
- private Lock mConnectionFailedLock = new ReentrantLock();
-
- /** Lock on the loop in StreamEntity */
- private Lock mStreamingReadyLock = new ReentrantLock();
- /** Condition variable used to signal the loop is ready... */
- private Condition mStreamingReady = mStreamingReadyLock.newCondition();
-
- /** Used to pass around the block of data POSTed */
- private Buffer mBuffer = new Buffer();
- /** Used to signal that the block of data has been written */
- private SignalConsumed mSignal = new SignalConsumed();
-
- // inner classes
-
- /**
- * Implements the http request
- */
- class Connection implements Runnable {
- public void run() {
- boolean problem = false;
- try {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "REQUEST : " + mMethod.getRequestLine());
- }
- mResponse = mClient.execute(mMethod);
- if (mResponse != null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "response (status line): "
- + mResponse.getStatusLine());
- }
- mResponseLine = "" + mResponse.getStatusLine();
- } else {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "problem, response == null");
- }
- problem = true;
- }
- } catch (IOException e) {
- Log.e(LOG_TAG, "Connection IO exception ", e);
- problem = true;
- } catch (RuntimeException e) {
- Log.e(LOG_TAG, "Connection runtime exception ", e);
- problem = true;
- }
-
- if (!problem) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Request complete ("
- + mMethod.getRequestLine() + ")");
- }
- } else {
- mConnectionFailedLock.lock();
- mConnectionFailed = true;
- mConnectionFailedLock.unlock();
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Request FAILED ("
- + mMethod.getRequestLine() + ")");
- }
- // We abort the execution in order to shutdown and release
- // the underlying connection
- mMethod.abort();
- if (mPostEntity != null) {
- // If there is a post entity, we need to wake it up from
- // a potential deadlock
- mPostEntity.signalOutputStream();
- }
- }
- }
- }
-
- /**
- * simple buffer class implementing a producer/consumer model
- */
- class Buffer {
- private DataPacket mPacket;
- private boolean mEmpty = true;
- public synchronized void put(DataPacket packet) {
- while (!mEmpty) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "InterruptedException while putting " +
- "a DataPacket in the Buffer: " + e);
- }
- }
- }
- mPacket = packet;
- mEmpty = false;
- notify();
- }
- public synchronized DataPacket get() {
- while (mEmpty) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "InterruptedException while getting " +
- "a DataPacket in the Buffer: " + e);
- }
- }
- }
- mEmpty = true;
- notify();
- return mPacket;
- }
- }
-
- /**
- * utility class used to block until the packet is signaled as being
- * consumed
- */
- class SignalConsumed {
- private boolean mConsumed = false;
- public synchronized void waitUntilPacketConsumed() {
- while (!mConsumed) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "InterruptedException while waiting " +
- "until a DataPacket is consumed: " + e);
- }
- }
- }
- mConsumed = false;
- notify();
- }
- public synchronized void packetConsumed() {
- while (mConsumed) {
- try {
- wait();
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "InterruptedException while indicating "
- + "that the DataPacket has been consumed: " + e);
- }
- }
- }
- mConsumed = true;
- notify();
- }
- }
-
- /**
- * Utility class encapsulating a packet of data
- */
- class DataPacket {
- private byte[] mContent;
- private int mLength;
- public DataPacket(byte[] content, int length) {
- mContent = content;
- mLength = length;
- }
- public byte[] getBytes() {
- return mContent;
- }
- public int getLength() {
- return mLength;
- }
- }
-
- /**
- * HttpEntity class to write the bytes received by the C++ thread
- * on the connection outputstream, in a streaming way.
- * This entity is executed in the request thread.
- * The writeTo() method is automatically called by the
- * HttpPost execution; upon reception, we loop while receiving
- * the data packets from the main thread, until completion
- * or error. When done, we flush the outputstream.
- * The main thread (sendPostData()) also blocks until the
- * outputstream is made available (or an error happens)
- */
- class StreamEntity implements HttpEntity {
- private OutputStream mOutputStream;
-
- // HttpEntity interface methods
-
- public boolean isRepeatable() {
- return false;
- }
-
- public boolean isChunked() {
- return false;
- }
-
- public long getContentLength() {
- return mContentLength;
- }
-
- public Header getContentType() {
- return null;
- }
-
- public Header getContentEncoding() {
- return null;
- }
-
- public InputStream getContent() throws IOException {
- return null;
- }
-
- public void writeTo(final OutputStream out) throws IOException {
- // We signal that the outputstream is available
- mStreamingReadyLock.lock();
- mOutputStream = out;
- mStreamingReady.signal();
- mStreamingReadyLock.unlock();
-
- // We then loop waiting on messages to process.
- boolean finished = false;
- while (!finished) {
- DataPacket packet = mBuffer.get();
- if (packet == null) {
- finished = true;
- } else {
- write(packet);
- }
- mSignal.packetConsumed();
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "stopping loop on error");
- }
- finished = true;
- }
- mConnectionFailedLock.unlock();
- }
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "flushing the outputstream...");
- }
- mOutputStream.flush();
- }
-
- public boolean isStreaming() {
- return true;
- }
-
- public void consumeContent() throws IOException {
- // Nothing to release
- }
-
- // local methods
-
- private void write(DataPacket packet) {
- try {
- if (mOutputStream == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "NO OUTPUT STREAM !!!");
- }
- return;
- }
- mOutputStream.write(packet.getBytes(), 0, packet.getLength());
- mOutputStream.flush();
- } catch (IOException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "exc: " + e);
- }
- mConnectionFailedLock.lock();
- mConnectionFailed = true;
- mConnectionFailedLock.unlock();
- }
- }
-
- public boolean isReady() {
- mStreamingReadyLock.lock();
- try {
- if (mOutputStream == null) {
- mStreamingReady.await();
- }
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "InterruptedException in "
- + "StreamEntity::isReady() : ", e);
- }
- } finally {
- mStreamingReadyLock.unlock();
- }
- if (mOutputStream == null) {
- return false;
- }
- return true;
- }
-
- public void signalOutputStream() {
- mStreamingReadyLock.lock();
- mStreamingReady.signal();
- mStreamingReadyLock.unlock();
- }
- }
-
- /**
- * Initialize mBridgeThread using the TLS value of
- * Thread.currentThread(). Called on start up of the native child
- * thread.
- */
- public synchronized void initChildThread() {
- mBridgeThread = Thread.currentThread();
- }
-
- public void setContentLength(long length) {
- mContentLength = length;
- }
-
- /**
- * Analagous to the native-side HttpRequest::open() function. This
- * initializes an underlying HttpClient method, but does
- * not go to the wire. On success, this enables a call to send() to
- * initiate the transaction.
- *
- * @param method The HTTP method, e.g GET or POST.
- * @param url The URL to open.
- * @return True on success with a complete HTTP response.
- * False on failure.
- */
- public synchronized boolean open(String method, String url) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "open " + method + " " + url);
- }
- // Create the client
- if (mConnectionFailed) {
- // interrupt() could have been called even before open()
- return false;
- }
- mClient = new DefaultHttpClient();
- mClient.setHttpRequestRetryHandler(
- new DefaultHttpRequestRetryHandler(0, false));
- mBodyInputStream = null;
- mResponseLine = null;
- mResponseHeaders = null;
- mPostEntity = null;
- mHttpThread = null;
- mConnectionFailed = false;
- mConnectionFinished = false;
-
- // Create the method. We support everything that
- // Apache HttpClient supports, apart from TRACE.
- if ("GET".equalsIgnoreCase(method)) {
- mMethod = new HttpGet(url);
- } else if ("POST".equalsIgnoreCase(method)) {
- mMethod = new HttpPost(url);
- mPostEntity = new StreamEntity();
- ((HttpPost)mMethod).setEntity(mPostEntity);
- } else if ("HEAD".equalsIgnoreCase(method)) {
- mMethod = new HttpHead(url);
- } else if ("PUT".equalsIgnoreCase(method)) {
- mMethod = new HttpPut(url);
- } else if ("DELETE".equalsIgnoreCase(method)) {
- mMethod = new HttpDelete(url);
- } else {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Method " + method + " not supported");
- }
- return false;
- }
- HttpParams params = mClient.getParams();
- // We handle the redirections C++-side
- HttpClientParams.setRedirecting(params, false);
- HttpProtocolParams.setUseExpectContinue(params, false);
- return true;
- }
-
- /**
- * We use this to start the connection thread (doing the method execute).
- * We usually always return true here, as the connection will run its
- * course in the thread.
- * We only return false if interrupted beforehand -- if a connection
- * problem happens, we will thus fail in either sendPostData() or
- * parseHeaders().
- */
- public synchronized boolean connectToRemote() {
- boolean ret = false;
- applyRequestHeaders();
- mConnectionFailedLock.lock();
- if (!mConnectionFailed) {
- mHttpThread = new Thread(new Connection());
- mHttpThread.start();
- }
- ret = mConnectionFailed;
- mConnectionFailedLock.unlock();
- return !ret;
- }
-
- /**
- * Get the complete response line of the HTTP request. Only valid on
- * completion of the transaction.
- * @return The complete HTTP response line, e.g "HTTP/1.0 200 OK".
- */
- public synchronized String getResponseLine() {
- return mResponseLine;
- }
-
- /**
- * Wait for the request thread completion
- * (unless already finished)
- */
- private void waitUntilConnectionFinished() {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "waitUntilConnectionFinished("
- + mConnectionFinished + ")");
- }
- if (!mConnectionFinished) {
- if (mHttpThread != null) {
- try {
- mHttpThread.join();
- mConnectionFinished = true;
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "http thread joined");
- }
- } catch (InterruptedException e) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "interrupted: " + e);
- }
- }
- } else {
- Log.e(LOG_TAG, ">>> Trying to join on mHttpThread " +
- "when it does not exist!");
- }
- }
- }
-
- // Headers handling
-
- /**
- * Receive all headers from the server and populate
- * mResponseHeaders.
- * @return True if headers are successfully received, False on
- * connection error.
- */
- public synchronized boolean parseHeaders() {
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- mConnectionFailedLock.unlock();
- return false;
- }
- mConnectionFailedLock.unlock();
- waitUntilConnectionFinished();
- mResponseHeaders = new HashMap<String, String[]>();
- if (mResponse == null)
- return false;
-
- Header[] headers = mResponse.getAllHeaders();
- for (int i = 0; i < headers.length; i++) {
- Header header = headers[i];
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "header " + header.getName()
- + " -> " + header.getValue());
- }
- setResponseHeader(header.getName(), header.getValue());
- }
-
- return true;
- }
-
- /**
- * Set a header to send with the HTTP request. Will not take effect
- * on a transaction already in progress. The key is associated
- * case-insensitive, but stored case-sensitive.
- * @param name The name of the header, e.g "Set-Cookie".
- * @param value The value for this header, e.g "text/html".
- */
- public synchronized void setRequestHeader(String name, String value) {
- String[] mapValue = { name, value };
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "setRequestHeader: " + name + " => " + value);
- }
- if (name.equalsIgnoreCase(KEY_CONTENT_LENGTH)) {
- setContentLength(Long.parseLong(value));
- } else {
- mRequestHeaders.put(name.toLowerCase(), mapValue);
- }
- }
-
- /**
- * Returns the value associated with the given request header.
- * @param name The name of the request header, non-null, case-insensitive.
- * @return The value associated with the request header, or null if
- * not set, or error.
- */
- public synchronized String getRequestHeader(String name) {
- String[] value = mRequestHeaders.get(name.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- }
-
- private void applyRequestHeaders() {
- if (mMethod == null)
- return;
- Iterator<String[]> it = mRequestHeaders.values().iterator();
- while (it.hasNext()) {
- // Set the key case-sensitive.
- String[] entry = it.next();
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "apply header " + entry[HEADERS_MAP_INDEX_KEY] +
- " => " + entry[HEADERS_MAP_INDEX_VALUE]);
- }
- mMethod.setHeader(entry[HEADERS_MAP_INDEX_KEY],
- entry[HEADERS_MAP_INDEX_VALUE]);
- }
- }
-
- /**
- * Returns the value associated with the given response header.
- * @param name The name of the response header, non-null, case-insensitive.
- * @return The value associated with the response header, or null if
- * not set or error.
- */
- public synchronized String getResponseHeader(String name) {
- if (mResponseHeaders != null) {
- String[] value = mResponseHeaders.get(name.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- } else {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "getResponseHeader() called but "
- + "response not received");
- }
- return null;
- }
- }
-
- /**
- * Return all response headers, separated by CR-LF line endings, and
- * ending with a trailing blank line. This mimics the format of the
- * raw response header up to but not including the body.
- * @return A string containing the entire response header.
- */
- public synchronized String getAllResponseHeaders() {
- if (mResponseHeaders == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "getAllResponseHeaders() called but "
- + "response not received");
- }
- return null;
- }
- StringBuilder result = new StringBuilder();
- Iterator<String[]> it = mResponseHeaders.values().iterator();
- while (it.hasNext()) {
- String[] entry = it.next();
- // Output the "key: value" lines.
- result.append(entry[HEADERS_MAP_INDEX_KEY]);
- result.append(": ");
- result.append(entry[HEADERS_MAP_INDEX_VALUE]);
- result.append(HTTP_LINE_ENDING);
- }
- result.append(HTTP_LINE_ENDING);
- return result.toString();
- }
-
-
- /**
- * Set a response header and associated value. The key is associated
- * case-insensitively, but stored case-sensitively.
- * @param name Case sensitive request header key.
- * @param value The associated value.
- */
- private void setResponseHeader(String name, String value) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Set response header " + name + ": " + value);
- }
- String mapValue[] = { name, value };
- mResponseHeaders.put(name.toLowerCase(), mapValue);
- }
-
- // Cookie handling
-
- /**
- * Get the cookie for the given URL.
- * @param url The fully qualified URL.
- * @return A string containing the cookie for the URL if it exists,
- * or null if not.
- */
- public static String getCookieForUrl(String url) {
- // Get the cookie for this URL, set as a header
- return CookieManager.getInstance().getCookie(url);
- }
-
- /**
- * Set the cookie for the given URL.
- * @param url The fully qualified URL.
- * @param cookie The new cookie value.
- * @return A string containing the cookie for the URL if it exists,
- * or null if not.
- */
- public static void setCookieForUrl(String url, String cookie) {
- // Get the cookie for this URL, set as a header
- CookieManager.getInstance().setCookie(url, cookie);
- }
-
- // Cache handling
-
- /**
- * Perform a request using LocalServer if possible. Initializes
- * class members so that receive() will obtain data from the stream
- * provided by the response.
- * @param url The fully qualified URL to try in LocalServer.
- * @return True if the url was found and is now setup to receive.
- * False if not found, with no side-effect.
- */
- public synchronized boolean useLocalServerResult(String url) {
- UrlInterceptHandlerGears handler =
- UrlInterceptHandlerGears.getInstance();
- if (handler == null) {
- return false;
- }
- UrlInterceptHandlerGears.ServiceResponse serviceResponse =
- handler.getServiceResponse(url, mRequestHeaders);
- if (serviceResponse == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "No response in LocalServer");
- }
- return false;
- }
- // LocalServer will handle this URL. Initialize stream and
- // response.
- mBodyInputStream = serviceResponse.getInputStream();
- mResponseLine = serviceResponse.getStatusLine();
- mResponseHeaders = serviceResponse.getResponseHeaders();
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Got response from LocalServer: " + mResponseLine);
- }
- return true;
- }
-
- /**
- * Perform a request using the cache result if present. Initializes
- * class members so that receive() will obtain data from the cache.
- * @param url The fully qualified URL to try in the cache.
- * @return True is the url was found and is now setup to receive
- * from cache. False if not found, with no side-effect.
- */
- public synchronized boolean useCacheResult(String url) {
- // Try the browser's cache. CacheManager wants a Map<String, String>.
- Map<String, String> cacheRequestHeaders = new HashMap<String, String>();
- Iterator<Map.Entry<String, String[]>> it =
- mRequestHeaders.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, String[]> entry = it.next();
- cacheRequestHeaders.put(
- entry.getKey(),
- entry.getValue()[HEADERS_MAP_INDEX_VALUE]);
- }
- CacheResult mCacheResult =
- CacheManager.getCacheFile(url, cacheRequestHeaders);
- if (mCacheResult == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "No CacheResult for " + url);
- }
- return false;
- }
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Got CacheResult from browser cache");
- }
- // Check for expiry. -1 is "never", otherwise milliseconds since 1970.
- // Can be compared to System.currentTimeMillis().
- long expires = mCacheResult.getExpires();
- if (expires >= 0 && System.currentTimeMillis() >= expires) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "CacheResult expired "
- + (System.currentTimeMillis() - expires)
- + " milliseconds ago");
- }
- // Cache hit has expired. Do not return it.
- return false;
- }
- // Setup the mBodyInputStream to come from the cache.
- mBodyInputStream = mCacheResult.getInputStream();
- if (mBodyInputStream == null) {
- // Cache result may have gone away.
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "No mBodyInputStream for CacheResult " + url);
- }
- return false;
- }
- // Cache hit. Parse headers.
- synthesizeHeadersFromCacheResult(mCacheResult);
- return true;
- }
-
- /**
- * Take the limited set of headers in a CacheResult and synthesize
- * response headers.
- * @param cacheResult A CacheResult to populate mResponseHeaders with.
- */
- private void synthesizeHeadersFromCacheResult(CacheResult cacheResult) {
- int statusCode = cacheResult.getHttpStatusCode();
- // The status message is informal, so we can greatly simplify it.
- String statusMessage;
- if (statusCode >= 200 && statusCode < 300) {
- statusMessage = "OK";
- } else if (statusCode >= 300 && statusCode < 400) {
- statusMessage = "MOVED";
- } else {
- statusMessage = "UNAVAILABLE";
- }
- // Synthesize the response line.
- mResponseLine = "HTTP/1.1 " + statusCode + " " + statusMessage;
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Synthesized " + mResponseLine);
- }
- // Synthesize the returned headers from cache.
- mResponseHeaders = new HashMap<String, String[]>();
- String contentLength = Long.toString(cacheResult.getContentLength());
- setResponseHeader(KEY_CONTENT_LENGTH, contentLength);
- long expires = cacheResult.getExpires();
- if (expires >= 0) {
- // "Expires" header is valid and finite. Milliseconds since 1970
- // epoch, formatted as RFC-1123.
- String expiresString = DateUtils.formatDate(new Date(expires));
- setResponseHeader(KEY_EXPIRES, expiresString);
- }
- String lastModified = cacheResult.getLastModified();
- if (lastModified != null) {
- // Last modification time of the page. Passed end-to-end, but
- // not used by us.
- setResponseHeader(KEY_LAST_MODIFIED, lastModified);
- }
- String eTag = cacheResult.getETag();
- if (eTag != null) {
- // Entity tag. A kind of GUID to identify identical resources.
- setResponseHeader(KEY_ETAG, eTag);
- }
- String location = cacheResult.getLocation();
- if (location != null) {
- // If valid, refers to the location of a redirect.
- setResponseHeader(KEY_LOCATION, location);
- }
- String mimeType = cacheResult.getMimeType();
- if (mimeType == null) {
- // Use a safe default MIME type when none is
- // specified. "text/plain" is safe to render in the browser
- // window (even if large) and won't be intepreted as anything
- // that would cause execution.
- mimeType = DEFAULT_MIME_TYPE;
- }
- String encoding = cacheResult.getEncoding();
- // Encoding may not be specified. No default.
- String contentType = mimeType;
- if (encoding != null) {
- if (encoding.length() > 0) {
- contentType += "; charset=" + encoding;
- }
- }
- setResponseHeader(KEY_CONTENT_TYPE, contentType);
- }
-
- /**
- * Create a CacheResult for this URL. This enables the repsonse body
- * to be sent in calls to appendCacheResult().
- * @param url The fully qualified URL to add to the cache.
- * @param responseCode The response code returned for the request, e.g 200.
- * @param mimeType The MIME type of the body, e.g "text/plain".
- * @param encoding The encoding, e.g "utf-8". Use "" for unknown.
- */
- public synchronized boolean createCacheResult(
- String url, int responseCode, String mimeType, String encoding) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Making cache entry for " + url);
- }
- // Take the headers and parse them into a format needed by
- // CacheManager.
- Headers cacheHeaders = new Headers();
- Iterator<Map.Entry<String, String[]>> it =
- mResponseHeaders.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, String[]> entry = it.next();
- // Headers.parseHeader() expects lowercase keys.
- String keyValue = entry.getKey() + ": "
- + entry.getValue()[HEADERS_MAP_INDEX_VALUE];
- CharArrayBuffer buffer = new CharArrayBuffer(keyValue.length());
- buffer.append(keyValue);
- // Parse it into the header container.
- cacheHeaders.parseHeader(buffer);
- }
- mCacheResult = CacheManager.createCacheFile(
- url, responseCode, cacheHeaders, mimeType, true);
- if (mCacheResult != null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Saving into cache");
- }
- mCacheResult.setEncoding(encoding);
- mCacheResultUrl = url;
- return true;
- } else {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Couldn't create mCacheResult");
- }
- return false;
- }
- }
-
- /**
- * Add data from the response body to the CacheResult created with
- * createCacheResult().
- * @param data A byte array of the next sequential bytes in the
- * response body.
- * @param bytes The number of bytes to write from the start of
- * the array.
- * @return True if all bytes successfully written, false on failure.
- */
- public synchronized boolean appendCacheResult(byte[] data, int bytes) {
- if (mCacheResult == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "appendCacheResult() called without a "
- + "CacheResult initialized");
- }
- return false;
- }
- try {
- mCacheResult.getOutputStream().write(data, 0, bytes);
- } catch (IOException ex) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Got IOException writing cache data: " + ex);
- }
- return false;
- }
- return true;
- }
-
- /**
- * Save the completed CacheResult into the CacheManager. This must
- * have been created first with createCacheResult().
- * @return Returns true if the entry has been successfully saved.
- */
- public synchronized boolean saveCacheResult() {
- if (mCacheResult == null || mCacheResultUrl == null) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Tried to save cache result but "
- + "createCacheResult not called");
- }
- return false;
- }
-
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Saving cache result");
- }
- CacheManager.saveCacheFile(mCacheResultUrl, mCacheResult);
- mCacheResult = null;
- mCacheResultUrl = null;
- return true;
- }
-
- /**
- * Called by the main thread to interrupt the child thread.
- * We do not set mConnectionFailed here as we still need the
- * ability to receive a null packet for sendPostData().
- */
- public synchronized void abort() {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "ABORT CALLED");
- }
- if (mMethod != null) {
- mMethod.abort();
- }
- }
-
- /**
- * Interrupt a blocking IO operation and wait for the
- * thread to complete.
- */
- public synchronized void interrupt() {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "INTERRUPT CALLED");
- }
- mConnectionFailedLock.lock();
- mConnectionFailed = true;
- mConnectionFailedLock.unlock();
- if (mMethod != null) {
- mMethod.abort();
- }
- if (mHttpThread != null) {
- waitUntilConnectionFinished();
- }
- }
-
- /**
- * Receive the next sequential bytes of the response body after
- * successful connection. This will receive up to the size of the
- * provided byte array. If there is no body, this will return 0
- * bytes on the first call after connection.
- * @param buf A pre-allocated byte array to receive data into.
- * @return The number of bytes from the start of the array which
- * have been filled, 0 on EOF, or negative on error.
- */
- public synchronized int receive(byte[] buf) {
- if (mBodyInputStream == null) {
- // If this is the first call, setup the InputStream. This may
- // fail if there were headers, but no body returned by the
- // server.
- try {
- if (mResponse != null) {
- HttpEntity entity = mResponse.getEntity();
- mBodyInputStream = entity.getContent();
- }
- } catch (IOException inputException) {
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Failed to connect InputStream: "
- + inputException);
- }
- // Not unexpected. For example, 404 response return headers,
- // and sometimes a body with a detailed error.
- }
- if (mBodyInputStream == null) {
- // No error stream either. Treat as a 0 byte response.
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "No InputStream");
- }
- return 0; // EOF.
- }
- }
- int ret;
- try {
- int got = mBodyInputStream.read(buf);
- if (got > 0) {
- // Got some bytes, not EOF.
- ret = got;
- } else {
- // EOF.
- mBodyInputStream.close();
- ret = 0;
- }
- } catch (IOException e) {
- // An abort() interrupts us by calling close() on our stream.
- if (LOGV_ENABLED) {
- Log.i(LOG_TAG, "Got IOException in mBodyInputStream.read(): ", e);
- }
- ret = -1;
- }
- return ret;
- }
-
- /**
- * For POST method requests, send a stream of data provided by the
- * native side in repeated callbacks.
- * We put the data in mBuffer, and wait until it is consumed
- * by the StreamEntity in the request thread.
- * @param data A byte array containing the data to sent, or null
- * if indicating EOF.
- * @param bytes The number of bytes from the start of the array to
- * send, or 0 if indicating EOF.
- * @return True if all bytes were successfully sent, false on error.
- */
- public boolean sendPostData(byte[] data, int bytes) {
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- mConnectionFailedLock.unlock();
- return false;
- }
- mConnectionFailedLock.unlock();
- if (mPostEntity == null) return false;
-
- // We block until the outputstream is available
- // (or in case of connection error)
- if (!mPostEntity.isReady()) return false;
-
- if (data == null && bytes == 0) {
- mBuffer.put(null);
- } else {
- mBuffer.put(new DataPacket(data, bytes));
- }
- mSignal.waitUntilPacketConsumed();
-
- mConnectionFailedLock.lock();
- if (mConnectionFailed) {
- Log.e(LOG_TAG, "failure");
- mConnectionFailedLock.unlock();
- return false;
- }
- mConnectionFailedLock.unlock();
- return true;
- }
-
-}
diff --git a/core/java/android/webkit/gears/DesktopAndroid.java b/core/java/android/webkit/gears/DesktopAndroid.java
deleted file mode 100644
index a7a144b..0000000
--- a/core/java/android/webkit/gears/DesktopAndroid.java
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.provider.Browser;
-import android.util.Log;
-import android.webkit.WebView;
-
-/**
- * Utility class to create a shortcut on Android
- */
-public class DesktopAndroid {
-
- private static final String TAG = "Gears-J-Desktop";
- private static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
- private static final String ACTION_INSTALL_SHORTCUT =
- "com.android.launcher.action.INSTALL_SHORTCUT";
-
- // Android now enforces a 64x64 limit for the icon
- private static int MAX_WIDTH = 64;
- private static int MAX_HEIGHT = 64;
-
- /**
- * Small utility function returning a Bitmap object.
- *
- * @param path the icon path
- */
- private static Bitmap getBitmap(String path) {
- return BitmapFactory.decodeFile(path);
- }
-
- /**
- * Create a shortcut for a webpage.
- *
- * <p>To set a shortcut on Android, we use the ACTION_INSTALL_SHORTCUT
- * from the default Home application. We only have to create an Intent
- * containing extra parameters specifying the shortcut.
- * <p>Note: the shortcut mechanism is not system wide and depends on the
- * Home application; if phone carriers decide to rewrite a Home application
- * that does not accept this Intent, no shortcut will be added.
- *
- * @param webview the webview we are called from
- * @param title the shortcut's title
- * @param url the shortcut's url
- * @param imagePath the local path of the shortcut's icon
- */
- public static void setShortcut(WebView webview, String title,
- String url, String imagePath) {
- Context context = webview.getContext();
-
- Intent viewWebPage = new Intent(Intent.ACTION_VIEW);
- viewWebPage.setData(Uri.parse(url));
- long urlHash = url.hashCode();
- long uniqueId = (urlHash << 32) | viewWebPage.hashCode();
- viewWebPage.putExtra(Browser.EXTRA_APPLICATION_ID,
- Long.toString(uniqueId));
-
- Intent intent = new Intent(ACTION_INSTALL_SHORTCUT);
- intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, viewWebPage);
- intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
-
- // We disallow the creation of duplicate shortcuts (i.e. same
- // url, same title, but different screen position).
- intent.putExtra(EXTRA_SHORTCUT_DUPLICATE, false);
-
- Bitmap bmp = getBitmap(imagePath);
- if (bmp != null) {
- if ((bmp.getWidth() > MAX_WIDTH) ||
- (bmp.getHeight() > MAX_HEIGHT)) {
- Bitmap scaledBitmap = Bitmap.createScaledBitmap(bmp,
- MAX_WIDTH, MAX_HEIGHT, true);
- intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, scaledBitmap);
- } else {
- intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bmp);
- }
- } else {
- // This should not happen as we just downloaded the icon
- Log.e(TAG, "icon file <" + imagePath + "> not found");
- }
-
- context.sendBroadcast(intent);
- }
-
-}
diff --git a/core/java/android/webkit/gears/NativeDialog.java b/core/java/android/webkit/gears/NativeDialog.java
deleted file mode 100644
index 9e2b375..0000000
--- a/core/java/android/webkit/gears/NativeDialog.java
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import java.io.File;
-import java.lang.InterruptedException;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Utility class to call a modal native dialog on Android
- * The dialog itself is an Activity defined in the Browser.
- * @hide
- */
-public class NativeDialog {
-
- private static final String TAG = "Gears-J-NativeDialog";
-
- private final String DIALOG_PACKAGE = "com.android.browser";
- private final String DIALOG_CLASS = DIALOG_PACKAGE + ".GearsNativeDialog";
-
- private static Lock mLock = new ReentrantLock();
- private static Condition mDialogFinished = mLock.newCondition();
- private static String mResults = null;
-
- private static boolean mAsynchronousDialog;
-
- /**
- * Utility function to build the intent calling the
- * dialog activity
- */
- private Intent createIntent(String type, String arguments) {
- Intent intent = new Intent();
- intent.setClassName(DIALOG_PACKAGE, DIALOG_CLASS);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra("dialogArguments", arguments);
- intent.putExtra("dialogType", type);
- return intent;
- }
-
- /**
- * Opens a native dialog synchronously and waits for its completion.
- *
- * The dialog is an activity (GearsNativeDialog) provided by the Browser
- * that we call via startActivity(). Contrary to a normal activity though,
- * we need to block until it returns. To do so, we define a static lock
- * object in this class, which GearsNativeDialog can unlock once done
- */
- public String showDialog(Context context, String file,
- String arguments) {
-
- try {
- mAsynchronousDialog = false;
- mLock.lock();
- File path = new File(file);
- String fileName = path.getName();
- String type = fileName.substring(0, fileName.indexOf(".html"));
- Intent intent = createIntent(type, arguments);
-
- mResults = null;
- context.startActivity(intent);
- mDialogFinished.await();
- } catch (InterruptedException e) {
- Log.e(TAG, "exception e: " + e);
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "exception e: " + e);
- } finally {
- mLock.unlock();
- }
-
- return mResults;
- }
-
- /**
- * Opens a native dialog asynchronously
- *
- * The dialog is an activity (GearsNativeDialog) provided by the
- * Browser.
- */
- public void showAsyncDialog(Context context, String type,
- String arguments) {
- mAsynchronousDialog = true;
- Intent intent = createIntent(type, arguments);
- context.startActivity(intent);
- }
-
- /**
- * Static method that GearsNativeDialog calls to unlock us
- */
- public static void signalFinishedDialog() {
- if (!mAsynchronousDialog) {
- mLock.lock();
- mDialogFinished.signal();
- mLock.unlock();
- } else {
- // we call the native callback
- closeAsynchronousDialog(mResults);
- }
- }
-
- /**
- * Static method that GearsNativeDialog calls to set the
- * dialog's result
- */
- public static void closeDialog(String res) {
- mResults = res;
- }
-
- /**
- * Native callback method
- */
- private native static void closeAsynchronousDialog(String res);
-}
diff --git a/core/java/android/webkit/gears/PluginSettings.java b/core/java/android/webkit/gears/PluginSettings.java
deleted file mode 100644
index 2d0cc13..0000000
--- a/core/java/android/webkit/gears/PluginSettings.java
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.Context;
-import android.util.Log;
-import android.webkit.Plugin;
-import android.webkit.Plugin.PreferencesClickHandler;
-
-/**
- * Simple bridge class intercepting the click in the
- * browser plugin list and calling the Gears settings
- * dialog.
- */
-public class PluginSettings {
-
- private static final String TAG = "Gears-J-PluginSettings";
- private Context mContext;
-
- public PluginSettings(Plugin plugin) {
- plugin.setClickHandler(new ClickHandler());
- }
-
- /**
- * We do not call the dialog synchronously here as the main
- * message loop would be blocked, so we call it via a secondary thread.
- */
- private class ClickHandler implements PreferencesClickHandler {
- public void handleClickEvent(Context context) {
- mContext = context.getApplicationContext();
- Thread startDialog = new Thread(new StartDialog(context));
- startDialog.start();
- }
- }
-
- /**
- * Simple wrapper class to call the gears native method in
- * a separate thread (the native code will then instanciate a NativeDialog
- * object which will start the GearsNativeDialog activity defined in
- * the Browser).
- */
- private class StartDialog implements Runnable {
- Context mContext;
-
- public StartDialog(Context context) {
- mContext = context;
- }
-
- public void run() {
- runSettingsDialog(mContext);
- }
- }
-
- private static native void runSettingsDialog(Context c);
-
-}
diff --git a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
deleted file mode 100644
index 43104bf..0000000
--- a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.util.Log;
-import android.webkit.CacheManager.CacheResult;
-import android.webkit.Plugin;
-import android.webkit.PluginData;
-import android.webkit.UrlInterceptRegistry;
-import android.webkit.UrlInterceptHandler;
-import android.webkit.WebView;
-
-import org.apache.http.util.CharArrayBuffer;
-
-import java.io.*;
-import java.util.*;
-
-/**
- * Services requests to handle URLs coming from the browser or
- * HttpRequestAndroid. This registers itself with the
- * UrlInterceptRegister in Android so we get a chance to service all
- * URLs passing through the browser before anything else.
- */
-public class UrlInterceptHandlerGears implements UrlInterceptHandler {
- /** Singleton instance. */
- private static UrlInterceptHandlerGears instance;
- /** Debug logging tag. */
- private static final String LOG_TAG = "Gears-J";
- /** Buffer size for reading/writing streams. */
- private static final int BUFFER_SIZE = 4096;
- /** Enable/disable all logging in this class. */
- private static boolean logEnabled = false;
- /** The unmodified (case-sensitive) key in the headers map is the
- * same index as used by HttpRequestAndroid. */
- public static final int HEADERS_MAP_INDEX_KEY =
- ApacheHttpRequestAndroid.HEADERS_MAP_INDEX_KEY;
- /** The associated value in the headers map is the same index as
- * used by HttpRequestAndroid. */
- public static final int HEADERS_MAP_INDEX_VALUE =
- ApacheHttpRequestAndroid.HEADERS_MAP_INDEX_VALUE;
-
- /**
- * Object passed to the native side, containing information about
- * the URL to service.
- */
- public static class ServiceRequest {
- // The URL being requested.
- private String url;
- // Request headers. Map of lowercase key to [ unmodified key, value ].
- private Map<String, String[]> requestHeaders;
-
- /**
- * Initialize members on construction.
- * @param url The URL being requested.
- * @param requestHeaders Headers associated with the request,
- * or null if none.
- * Map of lowercase key to [ unmodified key, value ].
- */
- public ServiceRequest(String url, Map<String, String[]> requestHeaders) {
- this.url = url;
- this.requestHeaders = requestHeaders;
- }
-
- /**
- * Returns the URL being requested.
- * @return The URL being requested.
- */
- public String getUrl() {
- return url;
- }
-
- /**
- * Get the value associated with a request header key, if any.
- * @param header The key to find, case insensitive.
- * @return The value associated with this header, or null if not found.
- */
- public String getRequestHeader(String header) {
- if (requestHeaders != null) {
- String[] value = requestHeaders.get(header.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- } else {
- return null;
- }
- }
- }
-
- /**
- * Object returned by the native side, containing information needed
- * to pass the entire response back to the browser or
- * HttpRequestAndroid. Works from either an in-memory array or a
- * file on disk.
- */
- public class ServiceResponse {
- // The response status code, e.g 200.
- private int statusCode;
- // The full status line, e.g "HTTP/1.1 200 OK".
- private String statusLine;
- // All headers associated with the response. Map of lowercase key
- // to [ unmodified key, value ].
- private Map<String, String[]> responseHeaders =
- new HashMap<String, String[]>();
- // The MIME type, e.g "text/html".
- private String mimeType;
- // The encoding, e.g "utf-8", or null if none.
- private String encoding;
- // The stream which contains the body when read().
- private InputStream inputStream;
- // The length of the content body.
- private long contentLength;
-
- /**
- * Initialize members using an in-memory array to return the body.
- * @param statusCode The response status code, e.g 200.
- * @param statusLine The full status line, e.g "HTTP/1.1 200 OK".
- * @param mimeType The MIME type, e.g "text/html".
- * @param encoding Encoding, e.g "utf-8" or null if none.
- * @param body The response body as a byte array, non-empty.
- */
- void setResultArray(
- int statusCode,
- String statusLine,
- String mimeType,
- String encoding,
- byte[] body) {
- this.statusCode = statusCode;
- this.statusLine = statusLine;
- this.mimeType = mimeType;
- this.encoding = encoding;
- // Setup a stream to read out of the byte array.
- this.contentLength = body.length;
- this.inputStream = new ByteArrayInputStream(body);
- }
-
- /**
- * Initialize members using a file on disk to return the body.
- * @param statusCode The response status code, e.g 200.
- * @param statusLine The full status line, e.g "HTTP/1.1 200 OK".
- * @param mimeType The MIME type, e.g "text/html".
- * @param encoding Encoding, e.g "utf-8" or null if none.
- * @param path Full path to the file containing the body.
- * @return True if the file is successfully setup to stream,
- * false on error such as file not found.
- */
- boolean setResultFile(
- int statusCode,
- String statusLine,
- String mimeType,
- String encoding,
- String path) {
- this.statusCode = statusCode;
- this.statusLine = statusLine;
- this.mimeType = mimeType;
- this.encoding = encoding;
- try {
- // Setup a stream to read out of a file on disk.
- File file = new File(path);
- this.contentLength = file.length();
- this.inputStream = new FileInputStream(file);
- return true;
- } catch (java.io.FileNotFoundException ex) {
- log("File not found: " + path);
- return false;
- }
- }
-
- /**
- * Set a response header, adding its settings to the header members.
- * @param key The case sensitive key for the response header,
- * e.g "Set-Cookie".
- * @param value The value associated with this key, e.g "cookie1234".
- */
- public void setResponseHeader(String key, String value) {
- // The map value contains the unmodified key (not lowercase).
- String[] mapValue = { key, value };
- responseHeaders.put(key.toLowerCase(), mapValue);
- }
-
- /**
- * Return the "Content-Type" header possibly supplied by a
- * previous setResponseHeader().
- * @return The "Content-Type" value, or null if not present.
- */
- public String getContentType() {
- // The map keys are lowercase.
- String[] value = responseHeaders.get("content-type");
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- }
-
- /**
- * Returns the HTTP status code for the response, supplied in
- * setResultArray() or setResultFile().
- * @return The HTTP statue code, e.g 200.
- */
- public int getStatusCode() {
- return statusCode;
- }
-
- /**
- * Returns the full HTTP status line for the response, supplied in
- * setResultArray() or setResultFile().
- * @return The HTTP statue line, e.g "HTTP/1.1 200 OK".
- */
- public String getStatusLine() {
- return statusLine;
- }
-
- /**
- * Get all response headers supplied in calls in
- * setResponseHeader().
- * @return A Map<String, String[]> containing all headers.
- */
- public Map<String, String[]> getResponseHeaders() {
- return responseHeaders;
- }
-
- /**
- * Returns the MIME type for the response, supplied in
- * setResultArray() or setResultFile().
- * @return The MIME type, e.g "text/html".
- */
- public String getMimeType() {
- return mimeType;
- }
-
- /**
- * Returns the encoding for the response, supplied in
- * setResultArray() or setResultFile(), or null if none.
- * @return The encoding, e.g "utf-8", or null if none.
- */
- public String getEncoding() {
- return encoding;
- }
-
- /**
- * Returns the InputStream setup by setResultArray() or
- * setResultFile() to allow reading data either from memory or
- * disk.
- * @return The InputStream containing the response body.
- */
- public InputStream getInputStream() {
- return inputStream;
- }
-
- /**
- * @return The length of the response body.
- */
- public long getContentLength() {
- return contentLength;
- }
- }
-
- /**
- * Construct and initialize the singleton instance.
- */
- public UrlInterceptHandlerGears() {
- if (instance != null) {
- Log.e(LOG_TAG, "UrlInterceptHandlerGears singleton already constructed");
- throw new RuntimeException();
- }
- instance = this;
- }
-
- /**
- * Turn on/off logging in this class.
- * @param on Logging enable state.
- */
- public static void enableLogging(boolean on) {
- logEnabled = on;
- }
-
- /**
- * Get the singleton instance.
- * @return The singleton instance.
- */
- public static UrlInterceptHandlerGears getInstance() {
- return instance;
- }
-
- /**
- * Register the singleton instance with the browser's interception
- * mechanism.
- */
- public synchronized void register() {
- UrlInterceptRegistry.registerHandler(this);
- }
-
- /**
- * Unregister the singleton instance from the browser's interception
- * mechanism.
- */
- public synchronized void unregister() {
- UrlInterceptRegistry.unregisterHandler(this);
- }
-
- /**
- * Given an URL, returns the CacheResult which contains the
- * surrogate response for the request, or null if the handler is
- * not interested.
- *
- * @param url URL string.
- * @param headers The headers associated with the request. May be null.
- * @return The CacheResult containing the surrogate response.
- * @Deprecated Use PluginData getPluginData(String url,
- * Map<String, String> headers); instead
- */
- @Deprecated
- public CacheResult service(String url, Map<String, String> headers) {
- throw new UnsupportedOperationException("unimplemented");
- }
-
- /**
- * Given an URL, returns a PluginData instance which contains the
- * response for the request. This implements the UrlInterceptHandler
- * interface.
- *
- * @param url The fully qualified URL being requested.
- * @param requestHeaders The request headers for this URL.
- * @return a PluginData object.
- */
- public PluginData getPluginData(String url, Map<String, String> requestHeaders) {
- // Thankfully the browser does call us with case-sensitive
- // headers. We just need to map it case-insensitive.
- Map<String, String[]> lowercaseRequestHeaders =
- new HashMap<String, String[]>();
- Iterator<Map.Entry<String, String>> requestHeadersIt =
- requestHeaders.entrySet().iterator();
- while (requestHeadersIt.hasNext()) {
- Map.Entry<String, String> entry = requestHeadersIt.next();
- String key = entry.getKey();
- String mapValue[] = { key, entry.getValue() };
- lowercaseRequestHeaders.put(key.toLowerCase(), mapValue);
- }
- ServiceResponse response = getServiceResponse(url, lowercaseRequestHeaders);
- if (response == null) {
- // No result for this URL.
- return null;
- }
- return new PluginData(response.getInputStream(),
- response.getContentLength(),
- response.getResponseHeaders(),
- response.getStatusCode());
- }
-
- /**
- * Given an URL, returns a CacheResult and headers which contain the
- * response for the request.
- *
- * @param url The fully qualified URL being requested.
- * @param requestHeaders The request headers for this URL.
- * @return If a response can be crafted, a ServiceResponse is
- * created which contains all response headers and an InputStream
- * attached to the body. If there is no response, null is returned.
- */
- public ServiceResponse getServiceResponse(String url,
- Map<String, String[]> requestHeaders) {
- if (!url.startsWith("http://") && !url.startsWith("https://")) {
- // Don't know how to service non-HTTP URLs
- return null;
- }
- // Call the native handler to craft a response for this URL.
- return nativeService(new ServiceRequest(url, requestHeaders));
- }
-
- /**
- * Convenience debug function. Calls the Android logging
- * mechanism. logEnabled is not a constant, so if the string
- * evaluation is potentially expensive, the caller also needs to
- * check it.
- * @param str String to log to the Android console.
- */
- private void log(String str) {
- if (logEnabled) {
- Log.i(LOG_TAG, str);
- }
- }
-
- /**
- * Native method which handles the bulk of the request in LocalServer.
- * @param request A ServiceRequest object containing information about
- * the request.
- * @return If serviced, a ServiceResponse object containing all the
- * information to provide a response for the URL, or null
- * if no response available for this URL.
- */
- private native static ServiceResponse nativeService(ServiceRequest request);
-}
diff --git a/core/java/android/webkit/gears/VersionExtractor.java b/core/java/android/webkit/gears/VersionExtractor.java
deleted file mode 100644
index 172dacb..0000000
--- a/core/java/android/webkit/gears/VersionExtractor.java
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.util.Log;
-import java.io.IOException;
-import java.io.StringReader;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.FactoryConfigurationError;
-import javax.xml.parsers.ParserConfigurationException;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.w3c.dom.Document;
-import org.w3c.dom.DOMException;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-/**
- * A class that can extract the Gears version and upgrade URL from an
- * xml document.
- */
-public final class VersionExtractor {
-
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-VersionExtractor";
- /**
- * XML element names.
- */
- private static final String VERSION = "em:version";
- private static final String URL = "em:updateLink";
-
- /**
- * Parses the input xml string and invokes the native
- * setVersionAndUrl method.
- * @param xml is the XML string to parse.
- * @return true if the extraction is successful and false otherwise.
- */
- public static boolean extract(String xml, long nativeObject) {
- try {
- // Build the builders.
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(false);
- DocumentBuilder builder = factory.newDocumentBuilder();
-
- // Create the document.
- Document doc = builder.parse(new InputSource(new StringReader(xml)));
-
- // Look for the version and url elements and get their text
- // contents.
- String version = extractText(doc, VERSION);
- String url = extractText(doc, URL);
-
- // If we have both, let the native side know.
- if (version != null && url != null) {
- setVersionAndUrl(version, url, nativeObject);
- return true;
- }
-
- return false;
-
- } catch (FactoryConfigurationError ex) {
- Log.e(TAG, "Could not create the DocumentBuilderFactory " + ex);
- } catch (ParserConfigurationException ex) {
- Log.e(TAG, "Could not create the DocumentBuilder " + ex);
- } catch (SAXException ex) {
- Log.e(TAG, "Could not parse the xml " + ex);
- } catch (IOException ex) {
- Log.e(TAG, "Could not read the xml " + ex);
- }
-
- return false;
- }
-
- /**
- * Extracts the text content of the first element with the given name.
- * @param doc is the Document where the element is searched for.
- * @param elementName is name of the element to searched for.
- * @return the text content of the element or null if no such
- * element is found.
- */
- private static String extractText(Document doc, String elementName) {
- String text = null;
- NodeList node_list = doc.getElementsByTagName(elementName);
-
- if (node_list.getLength() > 0) {
- // We are only interested in the first node. Normally there
- // should not be more than one anyway.
- Node node = node_list.item(0);
-
- // Iterate through the text children.
- NodeList child_list = node.getChildNodes();
-
- try {
- for (int i = 0; i < child_list.getLength(); ++i) {
- Node child = child_list.item(i);
- if (child.getNodeType() == Node.TEXT_NODE) {
- if (text == null) {
- text = new String();
- }
- text += child.getNodeValue();
- }
- }
- } catch (DOMException ex) {
- Log.e(TAG, "getNodeValue() failed " + ex);
- }
- }
-
- if (text != null) {
- text = text.trim();
- }
-
- return text;
- }
-
- /**
- * Native method used to send the version and url back to the C++
- * side.
- */
- private static native void setVersionAndUrl(
- String version, String url, long nativeObject);
-}
diff --git a/core/java/android/webkit/gears/ZipInflater.java b/core/java/android/webkit/gears/ZipInflater.java
deleted file mode 100644
index f6b6be5..0000000
--- a/core/java/android/webkit/gears/ZipInflater.java
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.os.StatFs;
-import android.util.Log;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Enumeration;
-import java.util.zip.CRC32;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
-
-
-/**
- * A class that can inflate a zip archive.
- */
-public final class ZipInflater {
- /**
- * Logging tag
- */
- private static final String TAG = "Gears-J-ZipInflater";
-
- /**
- * The size of the buffer used to read from the archive.
- */
- private static final int BUFFER_SIZE_BYTES = 32 * 1024; // 32 KB.
- /**
- * The path navigation component (i.e. "../").
- */
- private static final String PATH_NAVIGATION_COMPONENT = ".." + File.separator;
- /**
- * The root of the data partition.
- */
- private static final String DATA_PARTITION_ROOT = "/data";
-
- /**
- * We need two be able to store two versions of gears in parallel:
- * - the zipped version
- * - the unzipped version, which will be loaded next time the browser is started.
- * We are conservative and do not attempt to unpack unless there enough free
- * space on the device to store 4 times the new Gears size.
- */
- private static final long SIZE_MULTIPLIER = 4;
-
- /**
- * Unzips the archive with the given name.
- * @param filename is the name of the zip to inflate.
- * @param path is the path where the zip should be unpacked. It must contain
- * a trailing separator, or the extraction will fail.
- * @return true if the extraction is successful and false otherwise.
- */
- public static boolean inflate(String filename, String path) {
- Log.i(TAG, "Extracting " + filename + " to " + path);
-
- // Check that the path ends with a separator.
- if (!path.endsWith(File.separator)) {
- Log.e(TAG, "Path missing trailing separator: " + path);
- return false;
- }
-
- boolean result = false;
-
- // Use a ZipFile to get an enumeration of the entries and
- // calculate the overall uncompressed size of the archive. Also
- // check for existing files or directories that have the same
- // name as the entries in the archive. Also check for invalid
- // entry names (e.g names that attempt to navigate to the
- // parent directory).
- ZipInputStream zipStream = null;
- long uncompressedSize = 0;
- try {
- ZipFile zipFile = new ZipFile(filename);
- try {
- Enumeration entries = zipFile.entries();
- while (entries.hasMoreElements()) {
- ZipEntry entry = (ZipEntry) entries.nextElement();
- uncompressedSize += entry.getSize();
- // Check against entry names that may attempt to navigate
- // out of the destination directory.
- if (entry.getName().indexOf(PATH_NAVIGATION_COMPONENT) >= 0) {
- throw new IOException("Illegal entry name: " + entry.getName());
- }
-
- // Check against entries with the same name as pre-existing files or
- // directories.
- File file = new File(path + entry.getName());
- if (file.exists()) {
- // A file or directory with the same name already exist.
- // This must not happen, so we treat this as an error.
- throw new IOException(
- "A file or directory with the same name already exists.");
- }
- }
- } finally {
- zipFile.close();
- }
-
- Log.i(TAG, "Determined uncompressed size: " + uncompressedSize);
- // Check we have enough space to unpack this archive.
- if (freeSpace() <= uncompressedSize * SIZE_MULTIPLIER) {
- throw new IOException("Not enough space to unpack this archive.");
- }
-
- zipStream = new ZipInputStream(
- new BufferedInputStream(new FileInputStream(filename)));
- ZipEntry entry;
- int counter;
- byte buffer[] = new byte[BUFFER_SIZE_BYTES];
-
- // Iterate through the entries and write each of them to a file.
- while ((entry = zipStream.getNextEntry()) != null) {
- File file = new File(path + entry.getName());
- if (entry.isDirectory()) {
- // If the entry denotes a directory, we need to create a
- // directory with the same name.
- file.mkdirs();
- } else {
- CRC32 checksum = new CRC32();
- BufferedOutputStream output = new BufferedOutputStream(
- new FileOutputStream(file),
- BUFFER_SIZE_BYTES);
- try {
- // Read the entry and write it to the file.
- while ((counter = zipStream.read(buffer, 0, BUFFER_SIZE_BYTES)) !=
- -1) {
- output.write(buffer, 0, counter);
- checksum.update(buffer, 0, counter);
- }
- output.flush();
- } finally {
- output.close();
- }
-
- if (checksum.getValue() != entry.getCrc()) {
- throw new IOException(
- "Integrity check failed for: " + entry.getName());
- }
- }
- zipStream.closeEntry();
- }
-
- result = true;
-
- } catch (FileNotFoundException ex) {
- Log.e(TAG, "The zip file could not be found. " + ex);
- } catch (IOException ex) {
- Log.e(TAG, "Could not read or write an entry. " + ex);
- } catch(IllegalArgumentException ex) {
- Log.e(TAG, "Could not create the BufferedOutputStream. " + ex);
- } finally {
- if (zipStream != null) {
- try {
- zipStream.close();
- } catch (IOException ex) {
- // Ignored.
- }
- }
- // Discard any exceptions and return the result to the native side.
- return result;
- }
- }
-
- private static final long freeSpace() {
- StatFs data_partition = new StatFs(DATA_PARTITION_ROOT);
- long freeSpace = data_partition.getAvailableBlocks() *
- data_partition.getBlockSize();
- Log.i(TAG, "Free space on the data partition: " + freeSpace);
- return freeSpace;
- }
-}
diff --git a/core/java/android/webkit/gears/package.html b/core/java/android/webkit/gears/package.html
deleted file mode 100644
index db6f78b..0000000
--- a/core/java/android/webkit/gears/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<body>
-{@hide}
-</body> \ No newline at end of file
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index eea97dc..2f292d5 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -546,6 +546,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private void initAbsListView() {
// Setting focusable in touch mode will set the focusable property to true
+ setClickable(true);
setFocusableInTouchMode(true);
setWillNotDraw(false);
setAlwaysDrawnWithCacheEnabled(false);
@@ -1433,6 +1434,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* this is a long press.
*/
void keyPressed() {
+ if (!isEnabled() || !isClickable()) {
+ return;
+ }
+
Drawable selector = mSelector;
Rect selectorRect = mSelectorRect;
if (selector != null && (isFocused() || touchModeDrawsInPressedState())
@@ -1450,8 +1455,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
Drawable d = selector.getCurrent();
if (d != null && d instanceof TransitionDrawable) {
if (longClickable) {
- ((TransitionDrawable) d).startTransition(ViewConfiguration
- .getLongPressTimeout());
+ ((TransitionDrawable) d).startTransition(
+ ViewConfiguration.getLongPressTimeout());
} else {
((TransitionDrawable) d).resetTransition();
}
@@ -1732,18 +1737,29 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
@Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ @Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
- if (isPressed() && mSelectedPosition >= 0 && mAdapter != null &&
+ if (!isEnabled()) {
+ return true;
+ }
+ if (isClickable() && isPressed() &&
+ mSelectedPosition >= 0 && mAdapter != null &&
mSelectedPosition < mAdapter.getCount()) {
+
final View view = getChildAt(mSelectedPosition - mFirstPosition);
performItemClick(view, mSelectedPosition, mSelectedRowId);
setPressed(false);
if (view != null) view.setPressed(false);
return true;
}
+ break;
}
return super.onKeyUp(keyCode, event);
}
@@ -1892,6 +1908,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
@Override
public boolean onTouchEvent(MotionEvent ev) {
+ if (!isEnabled()) {
+ // A disabled view that is clickable still consumes the touch
+ // events, it just doesn't respond to them.
+ return isClickable() || isLongClickable();
+ }
+
if (mFastScroller != null) {
boolean intercepted = mFastScroller.onTouchEvent(ev);
if (intercepted) {
@@ -1974,7 +1996,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (y != mLastY) {
deltaY -= mMotionCorrection;
int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
- trackMotionScroll(deltaY, incrementalDeltaY);
+ // No need to do all this work if we're not going to move anyway
+ if (incrementalDeltaY != 0) {
+ trackMotionScroll(deltaY, incrementalDeltaY);
+ }
// Check to see if we have bumped into the scroll limit
View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
@@ -2041,7 +2066,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mSelector != null) {
Drawable d = mSelector.getCurrent();
if (d != null && d instanceof TransitionDrawable) {
- ((TransitionDrawable)d).resetTransition();
+ ((TransitionDrawable) d).resetTransition();
}
}
postDelayed(new Runnable() {
@@ -2065,15 +2090,27 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mTouchMode = TOUCH_MODE_REST;
break;
case TOUCH_MODE_SCROLL:
- final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- final int initialVelocity = (int) velocityTracker.getYVelocity();
- if (Math.abs(initialVelocity) > mMinimumVelocity && (getChildCount() > 0)) {
- if (mFlingRunnable == null) {
- mFlingRunnable = new FlingRunnable();
+ final int childCount = getChildCount();
+ if (childCount > 0) {
+ if (mFirstPosition == 0 && getChildAt(0).getTop() >= mListPadding.top &&
+ mFirstPosition + childCount < mItemCount &&
+ getChildAt(childCount - 1).getBottom() <=
+ getHeight() - mListPadding.bottom) {
+ mTouchMode = TOUCH_MODE_REST;
+ reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+ } else {
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+ final int initialVelocity = (int) velocityTracker.getYVelocity();
+
+ if (Math.abs(initialVelocity) > mMinimumVelocity) {
+ if (mFlingRunnable == null) {
+ mFlingRunnable = new FlingRunnable();
+ }
+ reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
+ mFlingRunnable.start(-initialVelocity);
+ }
}
- reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
- mFlingRunnable.start(-initialVelocity);
} else {
mTouchMode = TOUCH_MODE_REST;
reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 04cb8a0..2a0e5e5 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -64,10 +64,10 @@ public abstract class AbsSeekBar extends ProgressBar {
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.SeekBar, defStyle, 0);
Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
- setThumb(thumb);
+ setThumb(thumb); // will guess mThumbOffset if thumb != null...
+ // ...but allow layout to override this
int thumbOffset =
- a.getDimensionPixelOffset(com.android.internal.R.styleable.SeekBar_thumbOffset, 0);
- setThumbOffset(thumbOffset);
+ a.getDimensionPixelOffset(com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
a.recycle();
a = context.obtainStyledAttributes(attrs,
@@ -77,13 +77,21 @@ public abstract class AbsSeekBar extends ProgressBar {
}
/**
- * Sets the thumb that will be drawn at the end of the progress meter within the SeekBar
+ * Sets the thumb that will be drawn at the end of the progress meter within the SeekBar.
+ * <p>
+ * If the thumb is a valid drawable (i.e. not null), half its width will be
+ * used as the new thumb offset (@see #setThumbOffset(int)).
*
* @param thumb Drawable representing the thumb
*/
public void setThumb(Drawable thumb) {
if (thumb != null) {
thumb.setCallback(this);
+
+ // Assuming the thumb drawable is symmetric, set the thumb offset
+ // such that the thumb will hang halfway off either edge of the
+ // progress bar.
+ mThumbOffset = (int)thumb.getIntrinsicWidth() / 2;
}
mThumb = thumb;
invalidate();
@@ -320,11 +328,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/AlphabetIndexer.java b/core/java/android/widget/AlphabetIndexer.java
index f50676a..59b2c2a 100644
--- a/core/java/android/widget/AlphabetIndexer.java
+++ b/core/java/android/widget/AlphabetIndexer.java
@@ -28,7 +28,7 @@ import android.util.SparseIntArray;
* invalidates the cache if changes occur in the cursor.
* <p/>
* Your adapter is responsible for updating the cursor by calling {@link #setCursor} if the
- * cursor changes. {@link #getPositionForSection} method does the binary search for the starting
+ * cursor changes. {@link #getPositionForSection} method does the binary search for the starting
* index of a given section (alphabet).
*/
public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
@@ -37,33 +37,33 @@ public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
* Cursor that is used by the adapter of the list view.
*/
protected Cursor mDataCursor;
-
+
/**
* The index of the cursor column that this list is sorted on.
*/
protected int mColumnIndex;
-
+
/**
* The string of characters that make up the indexing sections.
*/
protected CharSequence mAlphabet;
-
+
/**
* Cached length of the alphabet array.
*/
private int mAlphabetLength;
-
+
/**
* This contains a cache of the computed indices so far. It will get reset whenever
* the dataset changes or the cursor changes.
*/
private SparseIntArray mAlphaMap;
-
+
/**
* Use a collator to compare strings in a localized manner.
*/
private java.text.Collator mCollator;
-
+
/**
* The section array converted from the alphabet string.
*/
@@ -72,9 +72,9 @@ public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
/**
* Constructs the indexer.
* @param cursor the cursor containing the data set
- * @param sortedColumnIndex the column number in the cursor that is sorted
+ * @param sortedColumnIndex the column number in the cursor that is sorted
* alphabetically
- * @param alphabet string containing the alphabet, with space as the first character.
+ * @param alphabet string containing the alphabet, with space as the first character.
* For example, use the string " ABCDEFGHIJKLMNOPQRSTUVWXYZ" for English indexing.
* The characters must be uppercase and be sorted in ascii/unicode order. Basically
* characters in the alphabet will show up as preview letters.
@@ -104,7 +104,7 @@ public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
public Object[] getSections() {
return mAlphabetArray;
}
-
+
/**
* Sets a new cursor as the data set and resets the cache of indices.
* @param cursor the new cursor to use as the data set
@@ -124,9 +124,16 @@ public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
* Default implementation compares the first character of word with letter.
*/
protected int compare(String word, String letter) {
- return mCollator.compare(word.substring(0, 1), letter);
+ final String firstLetter;
+ if (word.length() == 0) {
+ firstLetter = " ";
+ } else {
+ firstLetter = word.substring(0, 1);
+ }
+
+ return mCollator.compare(firstLetter, letter);
}
-
+
/**
* Performs a binary search or cache lookup to find the first row that
* matches a given section's starting letter.
@@ -143,7 +150,7 @@ public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
if (cursor == null || mAlphabet == null) {
return 0;
}
-
+
// Check bounds
if (sectionIndex <= 0) {
return 0;
@@ -164,7 +171,7 @@ public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
int key = letter;
// Check map
if (Integer.MIN_VALUE != (pos = alphaMap.get(key, Integer.MIN_VALUE))) {
- // Is it approximate? Using negative value to indicate that it's
+ // Is it approximate? Using negative value to indicate that it's
// an approximation and positive value when it is the accurate
// position.
if (pos < 0) {
@@ -204,7 +211,7 @@ public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
}
int diff = compare(curName, targetLetter);
if (diff != 0) {
- // Commenting out approximation code because it doesn't work for certain
+ // TODO: Commenting out approximation code because it doesn't work for certain
// lists with custom comparators
// Enter approximation in hash if a better solution doesn't exist
// String startingLetter = Character.toString(getFirstLetter(curName));
@@ -259,9 +266,9 @@ public class AlphabetIndexer extends DataSetObserver implements SectionIndexer {
return i;
}
}
- return 0; // Don't recognize the letter - falls under zero'th section
+ return 0; // Don't recognize the letter - falls under zero'th section
}
-
+
/*
* @hide
*/
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 02d77d1..d821a7d 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -194,7 +194,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
setFocusable(true);
addTextChangedListener(new MyWatcher());
-
+
mPassThroughClickListener = new PassThroughClickListener();
super.setOnClickListener(mPassThroughClickListener);
}
@@ -321,8 +321,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();
@@ -334,8 +332,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);
@@ -347,47 +343,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;
@@ -397,8 +361,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;
@@ -408,8 +370,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;
@@ -419,13 +379,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()}
*
@@ -1595,7 +1581,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.
@@ -1611,5 +1597,5 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
if (mWrapped != null) mWrapped.onClick(v);
}
}
-
+
}
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 5360621..6abb2ae 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -33,6 +33,7 @@ import android.view.ContextMenu;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ExpandableListConnector.PositionMetadata;
/**
@@ -916,7 +917,14 @@ public class ExpandableListView extends ListView {
@Override
ContextMenuInfo createContextMenuInfo(View view, int flatListPosition, long id) {
- PositionMetadata pm = mConnector.getUnflattenedPos(flatListPosition);
+ // Adjust for and handle for header views
+ final int adjustedPosition = flatListPosition - getHeaderViewsCount();
+ if (adjustedPosition < 0) {
+ // Return normal info for header view context menus
+ return new AdapterContextMenuInfo(view, flatListPosition, id);
+ }
+
+ PositionMetadata pm = mConnector.getUnflattenedPos(adjustedPosition);
ExpandableListPosition pos = pm.position;
pm.recycle();
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 2da777a..67c0def 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -55,7 +55,7 @@ class FastScroller {
private int mThumbY;
private RectF mOverlayPos;
- private int mOverlaySize = 104;
+ private int mOverlaySize;
private AbsListView mList;
private boolean mScrollCompleted;
@@ -119,10 +119,10 @@ class FastScroller {
private void useThumbDrawable(Context context, Drawable drawable) {
mThumbDrawable = drawable;
- mThumbW = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- 64, context.getResources().getDisplayMetrics());
- mThumbH = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- 52, context.getResources().getDisplayMetrics());
+ mThumbW = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.fastscroll_thumb_width);
+ mThumbH = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.fastscroll_thumb_height);
mChangedBounds = true;
}
@@ -138,7 +138,9 @@ class FastScroller {
mScrollCompleted = true;
getSectionsFromIndexer();
-
+
+ mOverlaySize = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.fastscroll_overlay_size);
mOverlayPos = new RectF();
mScrollFade = new ScrollFade();
mPaint = new Paint();
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index a9822f8..6cc794b 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -59,7 +59,7 @@ public class LinearLayout extends ViewGroup {
* Note: this is orthogonal to {@link #mBaselineAligned}, which is concerned
* with whether the children of this layout are baseline aligned.
*/
- private int mBaselineAlignedChildIndex = 0;
+ private int mBaselineAlignedChildIndex = -1;
/**
* The additional offset to the child's baseline.
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index f8a6f89..6316864 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1328,19 +1328,23 @@ public class ListView extends AbsListView {
// Make sure we are 1) Too low, and 2) Either there are more rows below the
// last row or the last row is scrolled off the bottom of the drawable area
- if (topOffset > 0 && (lastPosition < mItemCount - 1 || lastBottom > end)) {
- if (lastPosition == mItemCount - 1 ) {
- // Don't pull the bottom too far up
- topOffset = Math.min(topOffset, lastBottom - end);
- }
- // Move everything up
- offsetChildrenTopAndBottom(-topOffset);
- if (lastPosition < mItemCount - 1) {
- // Fill the gap that was opened below the last position with more rows, if
- // possible
- fillDown(lastPosition + 1, lastChild.getBottom() + mDividerHeight);
- // Close up the remaining gap
- adjustViewsUpOrDown();
+ if (topOffset > 0) {
+ if (lastPosition < mItemCount - 1 || lastBottom > end) {
+ if (lastPosition == mItemCount - 1) {
+ // Don't pull the bottom too far up
+ topOffset = Math.min(topOffset, lastBottom - end);
+ }
+ // Move everything up
+ offsetChildrenTopAndBottom(-topOffset);
+ if (lastPosition < mItemCount - 1) {
+ // Fill the gap that was opened below the last position with more rows, if
+ // possible
+ fillDown(lastPosition + 1, lastChild.getBottom() + mDividerHeight);
+ // Close up the remaining gap
+ adjustViewsUpOrDown();
+ }
+ } else if (lastPosition == mItemCount - 1) {
+ adjustViewsUpOrDown();
}
}
}
@@ -1428,7 +1432,8 @@ public class ListView extends AbsListView {
throw new IllegalStateException("The content of the adapter has changed but "
+ "ListView did not receive a notification. Make sure the content of "
+ "your adapter is not modified from a background thread, but only "
- + "from the UI thread.");
+ + "from the UI thread. [in ListView(" + getId() + ", " + getClass()
+ + ") with Adapter(" + mAdapter.getClass() + ")]");
}
setSelectedPositionInt(mNextSelectedPosition);
@@ -3264,12 +3269,13 @@ public class ListView extends AbsListView {
if (mChoiceMode == CHOICE_MODE_MULTIPLE) {
mCheckStates.put(position, value);
} else {
- // Clear the old value: if something was selected and value == false
- // then it is unselected
- mCheckStates.clear();
- // If value == true, select the appropriate position
+ // Clear all values if we're checking something, or unchecking the currently
+ // selected item
+ if (value || isItemChecked(position)) {
+ mCheckStates.clear();
+ }
// this may end up selecting the value we just cleared but this way
- // we don't have to first to a get(position)
+ // we ensure length of mCheckStates is 1, a fact getCheckedItemPosition relies on
if (value) {
mCheckStates.put(position, true);
}
@@ -3285,11 +3291,12 @@ public class ListView extends AbsListView {
/**
* Returns the checked state of the specified position. The result is only
- * valid if the choice mode has not been set to {@link #CHOICE_MODE_SINGLE}
+ * valid if the choice mode has been set to {@link #CHOICE_MODE_SINGLE}
* or {@link #CHOICE_MODE_MULTIPLE}.
*
* @param position The item whose checked state to return
- * @return The item's checked state
+ * @return The item's checked state or <code>false</code> if choice mode
+ * is invalid
*
* @see #setChoiceMode(int)
*/
@@ -3303,7 +3310,7 @@ public class ListView extends AbsListView {
/**
* Returns the currently checked item. The result is only valid if the choice
- * mode has not been set to {@link #CHOICE_MODE_SINGLE}.
+ * mode has been set to {@link #CHOICE_MODE_SINGLE}.
*
* @return The position of the currently checked item or
* {@link #INVALID_POSITION} if nothing is selected
@@ -3320,10 +3327,12 @@ public class ListView extends AbsListView {
/**
* Returns the set of checked items in the list. The result is only valid if
- * the choice mode has not been set to {@link #CHOICE_MODE_SINGLE}.
+ * the choice mode has not been set to {@link #CHOICE_MODE_NONE}.
*
* @return A SparseBooleanArray which will return true for each call to
- * get(int position) where position is a position in the list.
+ * get(int position) where position is a position in the list,
+ * or <code>null</code> if the choice mode is set to
+ * {@link #CHOICE_MODE_NONE}.
*/
public SparseBooleanArray getCheckedItemPositions() {
if (mChoiceMode != CHOICE_MODE_NONE) {
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 0c9d980..446a992 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -250,6 +250,29 @@ public class MediaController extends FrameLayout {
}
/**
+ * Disable pause or seek buttons if the stream cannot be paused or seeked.
+ * This requires the control interface to be a MediaPlayerControlExt
+ */
+ private void disableUnsupportedButtons() {
+ try {
+ if (mPauseButton != null && !mPlayer.canPause()) {
+ mPauseButton.setEnabled(false);
+ }
+ if (mRewButton != null && !mPlayer.canSeekBackward()) {
+ mRewButton.setEnabled(false);
+ }
+ if (mFfwdButton != null && !mPlayer.canSeekForward()) {
+ mFfwdButton.setEnabled(false);
+ }
+ } catch (IncompatibleClassChangeError ex) {
+ // We were given an old version of the interface, that doesn't have
+ // the canPause/canSeekXYZ methods. This is OK, it just means we
+ // assume the media can be paused and seeked, and so we don't disable
+ // the buttons.
+ }
+ }
+
+ /**
* Show the controller on screen. It will go away
* automatically after 'timeout' milliseconds of inactivity.
* @param timeout The timeout in milliseconds. Use 0 to show
@@ -259,6 +282,10 @@ public class MediaController extends FrameLayout {
if (!mShowing && mAnchor != null) {
setProgress();
+ if (mPauseButton != null) {
+ mPauseButton.requestFocus();
+ }
+ disableUnsupportedButtons();
int [] anchorpos = new int[2];
mAnchor.getLocationOnScreen(anchorpos);
@@ -392,6 +419,9 @@ public class MediaController extends FrameLayout {
keyCode == KeyEvent.KEYCODE_SPACE)) {
doPauseResume();
show(sDefaultTimeout);
+ if (mPauseButton != null) {
+ mPauseButton.requestFocus();
+ }
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
if (mPlayer.isPlaying()) {
@@ -421,17 +451,13 @@ public class MediaController extends FrameLayout {
};
private void updatePausePlay() {
- if (mRoot == null)
- return;
-
- ImageButton button = (ImageButton) mRoot.findViewById(com.android.internal.R.id.pause);
- if (button == null)
+ if (mRoot == null || mPauseButton == null)
return;
if (mPlayer.isPlaying()) {
- button.setImageResource(com.android.internal.R.drawable.ic_media_pause);
+ mPauseButton.setImageResource(com.android.internal.R.drawable.ic_media_pause);
} else {
- button.setImageResource(com.android.internal.R.drawable.ic_media_play);
+ mPauseButton.setImageResource(com.android.internal.R.drawable.ic_media_play);
}
}
@@ -516,7 +542,7 @@ public class MediaController extends FrameLayout {
if (mProgress != null) {
mProgress.setEnabled(enabled);
}
-
+ disableUnsupportedButtons();
super.setEnabled(enabled);
}
@@ -579,5 +605,8 @@ public class MediaController extends FrameLayout {
void seekTo(int pos);
boolean isPlaying();
int getBufferPercentage();
- };
+ boolean canPause();
+ boolean canSeekBackward();
+ boolean canSeekForward();
+ }
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 90fbb77..548dee9 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -817,6 +817,7 @@ public class PopupWindow {
* @param p the layout parameters of the popup's content view
*/
private void invokePopup(WindowManager.LayoutParams p) {
+ p.packageName = mContext.getPackageName();
mWindowManager.addView(mPopupView, p);
}
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index c9ace0a..381641f 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -17,6 +17,7 @@
package android.widget;
import android.content.Context;
+import android.hardware.SensorManager;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -79,9 +80,9 @@ public class Scroller {
mFinished = true;
mInterpolator = interpolator;
float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
- mDeceleration = 9.8f // g (m/s^2)
- * 39.37f // inch/meter
- * ppi // pixels per inch
+ mDeceleration = SensorManager.GRAVITY_EARTH // g (m/s^2)
+ * 39.37f // inch/meter
+ * ppi // pixels per inch
* ViewConfiguration.getScrollFriction();
}
@@ -347,7 +348,11 @@ public class Scroller {
}
/**
- *
+ * Stops the animation. Contrary to {@link #forceFinished(boolean)},
+ * aborting the animating cause the scroller to move to the final x and y
+ * position
+ *
+ * @see #forceFinished(boolean)
*/
public void abortAnimation() {
mCurrX = mFinalX;
@@ -356,10 +361,12 @@ public class Scroller {
}
/**
- * Extend the scroll animation. This allows a running animation to
- * scroll further and longer, when used with setFinalX() or setFinalY().
+ * Extend the scroll animation. This allows a running animation to scroll
+ * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
*
* @param extend Additional time to scroll in milliseconds.
+ * @see #setFinalX(int)
+ * @see #setFinalY(int)
*/
public void extendDuration(int extend) {
int passed = timePassed();
@@ -367,18 +374,37 @@ public class Scroller {
mDurationReciprocal = 1.0f / (float)mDuration;
mFinished = false;
}
-
+
+ /**
+ * Returns the time elapsed since the beginning of the scrolling.
+ *
+ * @return The elapsed time in milliseconds.
+ */
public int timePassed() {
return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
}
-
+
+ /**
+ * Sets the final position (X) for this scroller.
+ *
+ * @param newX The new X offset as an absolute distance from the origin.
+ * @see #extendDuration(int)
+ * @see #setFinalY(int)
+ */
public void setFinalX(int newX) {
mFinalX = newX;
mDeltaX = mFinalX - mStartX;
mFinished = false;
}
- public void setFinalY(int newY) {
+ /**
+ * Sets the final position (Y) for this scroller.
+ *
+ * @param newY The new Y offset as an absolute distance from the origin.
+ * @see #extendDuration(int)
+ * @see #setFinalX(int)
+ */
+ public void setFinalY(int newY) {
mFinalY = newY;
mDeltaY = mFinalY - mStartY;
mFinished = false;
diff --git a/core/java/android/widget/SimpleCursorTreeAdapter.java b/core/java/android/widget/SimpleCursorTreeAdapter.java
index c456f56..a1c65f0 100644
--- a/core/java/android/widget/SimpleCursorTreeAdapter.java
+++ b/core/java/android/widget/SimpleCursorTreeAdapter.java
@@ -26,9 +26,16 @@ import android.view.View;
* defined in an XML file. You can specify which columns you want, which views
* you want to display the columns, and the XML file that defines the appearance
* of these views. Separate XML files for child and groups are possible.
- * TextViews bind the values to their text property (see
- * {@link TextView#setText(CharSequence)}). ImageViews bind the values to their
- * image's Uri property (see {@link ImageView#setImageURI(android.net.Uri)}).
+ *
+ * Binding occurs in two phases. First, if a
+ * {@link android.widget.SimpleCursorTreeAdapter.ViewBinder} is available,
+ * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)}
+ * is invoked. If the returned value is true, binding has occurred. If the
+ * returned value is false and the view to bind is a TextView,
+ * {@link #setViewText(TextView, String)} is invoked. If the returned value
+ * is false and the view to bind is an ImageView,
+ * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate
+ * binding can be found, an {@link IllegalStateException} is thrown.
*/
public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter {
/** The indices of columns that contain data to display for a group. */
@@ -48,6 +55,11 @@ public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter
private int[] mChildTo;
/**
+ * View binder, if supplied
+ */
+ private ViewBinder mViewBinder;
+
+ /**
* Constructor.
*
* @param context The context where the {@link ExpandableListView}
@@ -193,21 +205,53 @@ public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter
initFromColumns(childCursor, childFromNames, mChildFrom);
}
+ /**
+ * Returns the {@link ViewBinder} used to bind data to views.
+ *
+ * @return a ViewBinder or null if the binder does not exist
+ *
+ * @see #setViewBinder(android.widget.SimpleCursorTreeAdapter.ViewBinder)
+ */
+ public ViewBinder getViewBinder() {
+ return mViewBinder;
+ }
+
+ /**
+ * Sets the binder used to bind data to views.
+ *
+ * @param viewBinder the binder used to bind data to views, can be null to
+ * remove the existing binder
+ *
+ * @see #getViewBinder()
+ */
+ public void setViewBinder(ViewBinder viewBinder) {
+ mViewBinder = viewBinder;
+ }
+
private void bindView(View view, Context context, Cursor cursor, int[] from, int[] to) {
+ final ViewBinder binder = mViewBinder;
+
for (int i = 0; i < to.length; i++) {
View v = view.findViewById(to[i]);
if (v != null) {
- String text = cursor.getString(from[i]);
- if (text == null) {
- text = "";
+ boolean bound = false;
+ if (binder != null) {
+ bound = binder.setViewValue(v, cursor, from[i]);
}
- if (v instanceof TextView) {
- ((TextView) v).setText(text);
- } else if (v instanceof ImageView) {
- setViewImage((ImageView) v, text);
- } else {
- throw new IllegalStateException("SimpleCursorAdapter can bind values only to" +
- " TextView and ImageView!");
+
+ if (!bound) {
+ String text = cursor.getString(from[i]);
+ if (text == null) {
+ text = "";
+ }
+ if (v instanceof TextView) {
+ setViewText((TextView) v, text);
+ } else if (v instanceof ImageView) {
+ setViewImage((ImageView) v, text);
+ } else {
+ throw new IllegalStateException("SimpleCursorTreeAdapter can bind values" +
+ " only to TextView and ImageView!");
+ }
}
}
}
@@ -238,4 +282,48 @@ public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter
v.setImageURI(Uri.parse(value));
}
}
+
+ /**
+ * Called by bindView() to set the text for a TextView but only if
+ * there is no existing ViewBinder or if the existing ViewBinder cannot
+ * handle binding to an TextView.
+ *
+ * Intended to be overridden by Adapters that need to filter strings
+ * retrieved from the database.
+ *
+ * @param v TextView to receive text
+ * @param text the text to be set for the TextView
+ */
+ public void setViewText(TextView v, String text) {
+ v.setText(text);
+ }
+
+ /**
+ * This class can be used by external clients of SimpleCursorTreeAdapter
+ * to bind values from the Cursor to views.
+ *
+ * You should use this class to bind values from the Cursor to views
+ * that are not directly supported by SimpleCursorTreeAdapter or to
+ * change the way binding occurs for views supported by
+ * SimpleCursorTreeAdapter.
+ *
+ * @see SimpleCursorTreeAdapter#setViewImage(ImageView, String)
+ * @see SimpleCursorTreeAdapter#setViewText(TextView, String)
+ */
+ public static interface ViewBinder {
+ /**
+ * Binds the Cursor column defined by the specified index to the specified view.
+ *
+ * When binding is handled by this ViewBinder, this method must return true.
+ * If this method returns false, SimpleCursorTreeAdapter will attempts to handle
+ * the binding on its own.
+ *
+ * @param view the view to bind the data to
+ * @param cursor the cursor to get the data from
+ * @param columnIndex the column at which the data can be found in the cursor
+ *
+ * @return true if the data was bound to the view, false otherwise
+ */
+ boolean setViewValue(View view, Cursor cursor, int columnIndex);
+ }
}
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 103d44d..ee3b91e 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -68,7 +68,7 @@ public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchMode
initTabHost();
}
- private final void initTabHost() {
+ private void initTabHost() {
setFocusableInTouchMode(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
@@ -101,8 +101,8 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
throw new RuntimeException(
"Your TabHost must have a TabWidget whose id attribute is 'android.R.id.tabs'");
}
-
- // KeyListener to attach to all tabs. Detects non-navigation keys
+
+ // KeyListener to attach to all tabs. Detects non-navigation keys
// and relays them to the tab content.
mTabKeyListener = new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
@@ -114,14 +114,14 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_ENTER:
return false;
-
+
}
mTabContent.requestFocus(View.FOCUS_FORWARD);
return mTabContent.dispatchKeyEvent(event);
}
-
+
};
-
+
mTabWidget.setTabSelectionListener(new TabWidget.OnTabSelectionChanged() {
public void onTabSelectionChanged(int tabIndex, boolean clicked) {
setCurrentTab(tabIndex);
@@ -134,7 +134,8 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
mTabContent = (FrameLayout) findViewById(com.android.internal.R.id.tabcontent);
if (mTabContent == null) {
throw new RuntimeException(
- "Your TabHost must have a FrameLayout whose id attribute is 'android.R.id.tabcontent'");
+ "Your TabHost must have a FrameLayout whose id attribute is "
+ + "'android.R.id.tabcontent'");
}
}
@@ -176,7 +177,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
if (!isInTouchMode) {
// leaving touch mode.. if nothing has focus, let's give it to
// the indicator of the current tab
- if (!mCurrentView.hasFocus() || mCurrentView.isFocused()) {
+ if (mCurrentView != null && (!mCurrentView.hasFocus() || mCurrentView.isFocused())) {
mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
}
}
@@ -283,7 +284,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
return true;
}
- return handled;
+ return handled;
}
@@ -312,7 +313,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
// Call the tab widget's focusCurrentTab(), instead of just
// selecting the tab.
mTabWidget.focusCurrentTab(mCurrentTab);
-
+
// tab content
mCurrentView = spec.mContentStrategy.getContentView();
@@ -367,7 +368,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
public interface TabContentFactory {
/**
* Callback to make the tab contents
- *
+ *
* @param tag
* Which tab was selected.
* @return The view to display the contents of the selected tab.
@@ -501,6 +502,8 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
View tabIndicator = inflater.inflate(R.layout.tab_indicator,
mTabWidget, // tab widget is the parent
false); // no inflate params
+ // TODO: Move this to xml when bug 2068024 is resolved.
+ tabIndicator.getBackground().setDither(true);
final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
tv.setText(mLabel);
@@ -528,6 +531,8 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
View tabIndicator = inflater.inflate(R.layout.tab_indicator,
mTabWidget, // tab widget is the parent
false); // no inflate params
+ // TODO: Move this to xml when bug 2068024 is resolved.
+ tabIndicator.getBackground().setDither(true);
final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
tv.setText(mLabel);
@@ -637,7 +642,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
}
}
mLaunchedView = wd;
-
+
// XXX Set FOCUS_AFTER_DESCENDANTS on embedded activities for now so they can get
// focus if none of their children have it. They need focus to be able to
// display menu items.
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 47f5c6c..889f37f 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -30,7 +30,7 @@ import android.view.View.OnFocusChangeListener;
/**
- *
+ *
* Displays a list of tab labels representing each page in the parent's tab
* collection. The container object for this widget is
* {@link android.widget.TabHost TabHost}. When the user selects a tab, this
@@ -64,21 +64,36 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
super(context, attrs);
initTabWidget();
- TypedArray a =
+ TypedArray a =
context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TabWidget,
defStyle, 0);
a.recycle();
}
-
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mStripMoved = true;
super.onSizeChanged(w, h, oldw, oldh);
}
+ @Override
+ protected int getChildDrawingOrder(int childCount, int i) {
+ // Always draw the selected tab last, so that drop shadows are drawn
+ // in the correct z-order.
+ if (i == childCount - 1) {
+ return mSelectedTab;
+ } else if (i >= mSelectedTab) {
+ return i + 1;
+ } else {
+ return i;
+ }
+ }
+
private void initTabWidget() {
setOrientation(LinearLayout.HORIZONTAL);
+ mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;
+
mBottomLeftStrip = mContext.getResources().getDrawable(
com.android.internal.R.drawable.tab_bottom_left);
mBottomRightStrip = mContext.getResources().getDrawable(
@@ -156,7 +171,7 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
}
super.childDrawableStateChanged(child);
}
-
+
@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
@@ -169,17 +184,17 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
}
View selectedChild = getChildTabViewAt(mSelectedTab);
-
+
mBottomLeftStrip.setState(selectedChild.getDrawableState());
mBottomRightStrip.setState(selectedChild.getDrawableState());
-
+
if (mStripMoved) {
Rect selBounds = new Rect(); // Bounds of the selected tab indicator
selBounds.left = selectedChild.getLeft();
selBounds.right = selectedChild.getRight();
final int myHeight = getHeight();
mBottomLeftStrip.setBounds(
- Math.min(0, selBounds.left
+ Math.min(0, selBounds.left
- mBottomLeftStrip.getIntrinsicWidth()),
myHeight - mBottomLeftStrip.getIntrinsicHeight(),
selBounds.left,
@@ -187,12 +202,12 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
mBottomRightStrip.setBounds(
selBounds.right,
myHeight - mBottomRightStrip.getIntrinsicHeight(),
- Math.max(getWidth(),
+ Math.max(getWidth(),
selBounds.right + mBottomRightStrip.getIntrinsicWidth()),
myHeight);
mStripMoved = false;
}
-
+
mBottomLeftStrip.draw(canvas);
mBottomRightStrip.draw(canvas);
}
@@ -202,26 +217,26 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
* This method is used to bring a tab to the front of the Widget,
* and is used to post to the rest of the UI that a different tab
* has been brought to the foreground.
- *
- * Note, this is separate from the traditional "focus" that is
- * employed from the view logic.
- *
- * For instance, if we have a list in a tabbed view, a user may be
- * navigating up and down the list, moving the UI focus (orange
- * highlighting) through the list items. The cursor movement does
- * not effect the "selected" tab though, because what is being
- * scrolled through is all on the same tab. The selected tab only
- * changes when we navigate between tabs (moving from the list view
+ *
+ * Note, this is separate from the traditional "focus" that is
+ * employed from the view logic.
+ *
+ * For instance, if we have a list in a tabbed view, a user may be
+ * navigating up and down the list, moving the UI focus (orange
+ * highlighting) through the list items. The cursor movement does
+ * not effect the "selected" tab though, because what is being
+ * scrolled through is all on the same tab. The selected tab only
+ * changes when we navigate between tabs (moving from the list view
* to the next tabbed view, in this example).
- *
+ *
* To move both the focus AND the selected tab at once, please use
- * {@link #setCurrentTab}. Normally, the view logic takes care of
- * adjusting the focus, so unless you're circumventing the UI,
+ * {@link #setCurrentTab}. Normally, the view logic takes care of
+ * adjusting the focus, so unless you're circumventing the UI,
* you'll probably just focus your interest here.
- *
+ *
* @param index The tab that you want to indicate as the selected
* tab (tab brought to the front of the widget)
- *
+ *
* @see #focusCurrentTab
*/
public void setCurrentTab(int index) {
@@ -234,19 +249,19 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
getChildTabViewAt(mSelectedTab).setSelected(true);
mStripMoved = true;
}
-
+
/**
* Sets the current tab and focuses the UI on it.
- * This method makes sure that the focused tab matches the selected
- * tab, normally at {@link #setCurrentTab}. Normally this would not
- * be an issue if we go through the UI, since the UI is responsible
- * for calling TabWidget.onFocusChanged(), but in the case where we
- * are selecting the tab programmatically, we'll need to make sure
+ * This method makes sure that the focused tab matches the selected
+ * tab, normally at {@link #setCurrentTab}. Normally this would not
+ * be an issue if we go through the UI, since the UI is responsible
+ * for calling TabWidget.onFocusChanged(), but in the case where we
+ * are selecting the tab programmatically, we'll need to make sure
* focus keeps up.
- *
- * @param index The tab that you want focused (highlighted in orange)
+ *
+ * @param index The tab that you want focused (highlighted in orange)
* and selected (tab brought to the front of the widget)
- *
+ *
* @see #setCurrentTab
*/
public void focusCurrentTab(int index) {
@@ -254,18 +269,18 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
// set the tab
setCurrentTab(index);
-
+
// change the focus if applicable.
if (oldTab != index) {
getChildTabViewAt(index).requestFocus();
}
}
-
+
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
int count = getTabCount();
-
+
for (int i = 0; i < count; i++) {
View child = getChildTabViewAt(i);
child.setEnabled(enabled);
@@ -318,7 +333,7 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
getChildTabViewAt(mSelectedTab).requestFocus();
return;
}
-
+
if (hasFocus) {
int i = 0;
int numTabs = getTabCount();
@@ -354,7 +369,7 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
/**
* Informs the TabHost which tab was selected. It also indicates
* if the tab was clicked/pressed or just focused into.
- *
+ *
* @param tabIndex index of the tab that was selected
* @param clicked whether the selection changed due to a touch/click
* or due to focus entering the tab through navigation. Pass true
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 260799e..a611d5a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -327,6 +327,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mText = "";
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
+ mTextPaint.density = getResources().getDisplayMetrics().density;
// If we get the paint from the skin, we should set it to left, since
// the layout always wants it to be left.
// mTextPaint.setTextAlign(Paint.Align.LEFT);
@@ -5769,7 +5770,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* Causes words in the text that are longer than the view is wide
* to be ellipsized instead of broken in the middle. You may also
* want to {@link #setSingleLine} or {@link #setHorizontallyScrolling}
- * to constrain the text toa single line. Use <code>null</code>
+ * to constrain the text to a single line. Use <code>null</code>
* to turn off ellipsizing.
*
* @attr ref android.R.styleable#TextView_ellipsize
@@ -6916,6 +6917,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ boolean hasLetter = false;
+ for (int i = start; i < end; i++) {
+ if (Character.isLetter(mTransformed.charAt(i))) {
+ hasLetter = true;
+ break;
+ }
+ }
+ if (!hasLetter) {
+ return null;
+ }
+
if (start == end) {
return null;
}
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 20dd8a6..549f984 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.res.Resources;
import android.media.AudioManager;
import android.media.MediaPlayer;
+import android.media.Metadata;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.net.Uri;
@@ -34,7 +35,7 @@ import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
-import android.widget.MediaController.MediaPlayerControl;
+import android.widget.MediaController.*;
import java.io.IOException;
@@ -51,11 +52,26 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
private Uri mUri;
private int mDuration;
+ // all possible internal states
+ private static final int STATE_ERROR = -1;
+ private static final int STATE_IDLE = 0;
+ private static final int STATE_PREPARING = 1;
+ private static final int STATE_PREPARED = 2;
+ private static final int STATE_PLAYING = 3;
+ private static final int STATE_PAUSED = 4;
+ private static final int STATE_PLAYBACK_COMPLETED = 5;
+
+ // mCurrentState is a VideoView object's current state.
+ // mTargetState is the state that a method caller intends to reach.
+ // For instance, regardless the VideoView object's current state,
+ // calling pause() intends to bring the object to a target state
+ // of STATE_PAUSED.
+ private int mCurrentState = STATE_IDLE;
+ private int mTargetState = STATE_IDLE;
+
// All the stuff we need for playing and showing a video
private SurfaceHolder mSurfaceHolder = null;
private MediaPlayer mMediaPlayer = null;
- private boolean mIsPrepared;
- private boolean mIsPlaybackCompleted;
private int mVideoWidth;
private int mVideoHeight;
private int mSurfaceWidth;
@@ -65,8 +81,10 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
private MediaPlayer.OnPreparedListener mOnPreparedListener;
private int mCurrentBufferPercentage;
private OnErrorListener mOnErrorListener;
- private boolean mStartWhenPrepared;
- private int mSeekWhenPrepared;
+ private int mSeekWhenPrepared; // recording the seek position while preparing
+ private boolean mCanPause;
+ private boolean mCanSeekBack;
+ private boolean mCanSeekForward;
public VideoView(Context context) {
super(context);
@@ -80,7 +98,6 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
public VideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
-
initVideoView();
}
@@ -143,6 +160,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
+ mCurrentState = STATE_IDLE;
+ mTargetState = STATE_IDLE;
}
public void setVideoPath(String path) {
@@ -151,7 +170,6 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
public void setVideoURI(Uri uri) {
mUri = uri;
- mStartWhenPrepared = false;
mSeekWhenPrepared = 0;
openVideo();
requestLayout();
@@ -163,6 +181,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
+ mCurrentState = STATE_IDLE;
+ mTargetState = STATE_IDLE;
}
}
@@ -176,18 +196,14 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "pause");
mContext.sendBroadcast(i);
-
- if (mMediaPlayer != null) {
- mMediaPlayer.reset();
- mMediaPlayer.release();
- mMediaPlayer = null;
- }
+
+ // we shouldn't clear the target state, because somebody might have
+ // called start() previously
+ release(false);
try {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
- mIsPrepared = false;
- Log.v(TAG, "reset duration to -1 in openVideo");
mDuration = -1;
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
@@ -198,12 +214,19 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.prepareAsync();
+ // we don't set the target state here either, but preserve the
+ // target state that was there before.
+ mCurrentState = STATE_PREPARING;
attachMediaController();
} catch (IOException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
+ mCurrentState = STATE_ERROR;
+ mTargetState = STATE_ERROR;
return;
} catch (IllegalArgumentException ex) {
Log.w(TAG, "Unable to open content: " + mUri, ex);
+ mCurrentState = STATE_ERROR;
+ mTargetState = STATE_ERROR;
return;
}
}
@@ -222,7 +245,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
View anchorView = this.getParent() instanceof View ?
(View)this.getParent() : this;
mMediaController.setAnchorView(anchorView);
- mMediaController.setEnabled(mIsPrepared);
+ mMediaController.setEnabled(isInPlaybackState());
}
}
@@ -239,8 +262,23 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
- // briefly show the mediacontroller
- mIsPrepared = true;
+ mCurrentState = STATE_PREPARED;
+
+ // Get the capabilities of the player for this stream
+ Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL,
+ MediaPlayer.BYPASS_METADATA_FILTER);
+
+ if (data != null) {
+ mCanPause = !data.has(Metadata.PAUSE_AVAILABLE)
+ || data.getBoolean(Metadata.PAUSE_AVAILABLE);
+ mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE)
+ || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE);
+ mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE)
+ || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE);
+ } else {
+ mCanPause = mCanSeekForward = mCanSeekForward = true;
+ }
+
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(mMediaPlayer);
}
@@ -249,6 +287,11 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
}
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
+
+ int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
+ if (seekToPosition != 0) {
+ seekTo(seekToPosition);
+ }
if (mVideoWidth != 0 && mVideoHeight != 0) {
//Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
getHolder().setFixedSize(mVideoWidth, mVideoHeight);
@@ -256,18 +299,13 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
// We didn't actually change the size (it was already at the size
// we need), so we won't get a "surface changed" callback, so
// start the video here instead of in the callback.
- if (mSeekWhenPrepared != 0) {
- mMediaPlayer.seekTo(mSeekWhenPrepared);
- mSeekWhenPrepared = 0;
- }
- if (mStartWhenPrepared) {
+ if (mTargetState == STATE_PLAYING) {
start();
- mStartWhenPrepared = false;
if (mMediaController != null) {
mMediaController.show();
}
} else if (!isPlaying() &&
- (mSeekWhenPrepared != 0 || getCurrentPosition() > 0)) {
+ (seekToPosition != 0 || getCurrentPosition() > 0)) {
if (mMediaController != null) {
// Show the media controls when we're paused into a video and make 'em stick.
mMediaController.show(0);
@@ -277,13 +315,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
} else {
// We don't know the video size yet, but should start anyway.
// The video size might be reported to us later.
- if (mSeekWhenPrepared != 0) {
- mMediaPlayer.seekTo(mSeekWhenPrepared);
- mSeekWhenPrepared = 0;
- }
- if (mStartWhenPrepared) {
+ if (mTargetState == STATE_PLAYING) {
start();
- mStartWhenPrepared = false;
}
}
}
@@ -292,7 +325,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
private MediaPlayer.OnCompletionListener mCompletionListener =
new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
- mIsPlaybackCompleted = true;
+ mCurrentState = STATE_PLAYBACK_COMPLETED;
+ mTargetState = STATE_PLAYBACK_COMPLETED;
if (mMediaController != null) {
mMediaController.hide();
}
@@ -306,6 +340,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
Log.d(TAG, "Error: " + framework_err + "," + impl_err);
+ mCurrentState = STATE_ERROR;
+ mTargetState = STATE_ERROR;
if (mMediaController != null) {
mMediaController.hide();
}
@@ -402,14 +438,13 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
{
mSurfaceWidth = w;
mSurfaceHeight = h;
- if (mMediaPlayer != null && mIsPrepared && mVideoWidth == w && mVideoHeight == h) {
+ boolean isValidState = (mTargetState == STATE_PLAYING);
+ boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h);
+ if (mMediaPlayer != null && isValidState && hasValidSize) {
if (mSeekWhenPrepared != 0) {
- mMediaPlayer.seekTo(mSeekWhenPrepared);
- mSeekWhenPrepared = 0;
+ seekTo(mSeekWhenPrepared);
}
- if (!mIsPlaybackCompleted) {
- start();
- }
+ start();
if (mMediaController != null) {
mMediaController.show();
}
@@ -427,17 +462,28 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
// after we return from this we can't use the surface any more
mSurfaceHolder = null;
if (mMediaController != null) mMediaController.hide();
- if (mMediaPlayer != null) {
- mMediaPlayer.reset();
- mMediaPlayer.release();
- mMediaPlayer = null;
- }
+ release(true);
}
};
+ /*
+ * release the media player in any state
+ */
+ private void release(boolean cleartargetstate) {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.reset();
+ mMediaPlayer.release();
+ mMediaPlayer = null;
+ mCurrentState = STATE_IDLE;
+ if (cleartargetstate) {
+ mTargetState = STATE_IDLE;
+ }
+ }
+ }
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
- if (mIsPrepared && mMediaPlayer != null && mMediaController != null) {
+ if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
}
return false;
@@ -445,7 +491,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
@Override
public boolean onTrackballEvent(MotionEvent ev) {
- if (mIsPrepared && mMediaPlayer != null && mMediaController != null) {
+ if (isInPlaybackState() && mMediaController != null) {
toggleMediaControlsVisiblity();
}
return false;
@@ -454,15 +500,13 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
- if (mIsPrepared &&
- keyCode != KeyEvent.KEYCODE_BACK &&
- keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
- keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
- keyCode != KeyEvent.KEYCODE_MENU &&
- keyCode != KeyEvent.KEYCODE_CALL &&
- keyCode != KeyEvent.KEYCODE_ENDCALL &&
- mMediaPlayer != null &&
- mMediaController != null) {
+ boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&
+ keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
+ keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
+ keyCode != KeyEvent.KEYCODE_MENU &&
+ keyCode != KeyEvent.KEYCODE_CALL &&
+ keyCode != KeyEvent.KEYCODE_ENDCALL;
+ if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
if (mMediaPlayer.isPlaying()) {
@@ -494,26 +538,26 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
}
public void start() {
- mIsPlaybackCompleted = false;
- if (mMediaPlayer != null && mIsPrepared) {
- mMediaPlayer.start();
- mStartWhenPrepared = false;
- } else {
- mStartWhenPrepared = true;
+ if (isInPlaybackState()) {
+ mMediaPlayer.start();
+ mCurrentState = STATE_PLAYING;
}
+ mTargetState = STATE_PLAYING;
}
public void pause() {
- if (mMediaPlayer != null && mIsPrepared) {
+ if (isInPlaybackState()) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
+ mCurrentState = STATE_PAUSED;
}
}
- mStartWhenPrepared = false;
+ mTargetState = STATE_PAUSED;
}
+ // cache duration as mDuration for faster access
public int getDuration() {
- if (mMediaPlayer != null && mIsPrepared) {
+ if (isInPlaybackState()) {
if (mDuration > 0) {
return mDuration;
}
@@ -525,25 +569,23 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
}
public int getCurrentPosition() {
- if (mMediaPlayer != null && mIsPrepared) {
+ if (isInPlaybackState()) {
return mMediaPlayer.getCurrentPosition();
}
return 0;
}
public void seekTo(int msec) {
- if (mMediaPlayer != null && mIsPrepared) {
+ if (isInPlaybackState()) {
mMediaPlayer.seekTo(msec);
+ mSeekWhenPrepared = 0;
} else {
mSeekWhenPrepared = msec;
}
}
public boolean isPlaying() {
- if (mMediaPlayer != null && mIsPrepared) {
- return mMediaPlayer.isPlaying();
- }
- return false;
+ return isInPlaybackState() && mMediaPlayer.isPlaying();
}
public int getBufferPercentage() {
@@ -552,4 +594,23 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
}
return 0;
}
+
+ private boolean isInPlaybackState() {
+ return (mMediaPlayer != null &&
+ mCurrentState != STATE_ERROR &&
+ mCurrentState != STATE_IDLE &&
+ mCurrentState != STATE_PREPARING);
+ }
+
+ public boolean canPause() {
+ return mCanPause;
+ }
+
+ public boolean canSeekBackward() {
+ return mCanSeekBack;
+ }
+
+ public boolean canSeekForward() {
+ return mCanSeekForward;
+ }
}
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
new file mode 100755
index 0000000..98fb236
--- /dev/null
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IMountService;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.widget.Toast;
+import android.util.Log;
+import android.location.LocationManager;
+import com.android.internal.location.GpsLocationProvider;
+import com.android.internal.location.GpsNetInitiatedHandler;
+
+/**
+ * This activity is shown to the user for him/her to accept or deny network-initiated
+ * requests. It uses the alert dialog style. It will be launched from a notification.
+ */
+public class NetInitiatedActivity extends AlertActivity implements DialogInterface.OnClickListener {
+
+ private static final String TAG = "NetInitiatedActivity";
+
+ private static final boolean DEBUG = true;
+ private static final boolean VERBOSE = false;
+
+ private static final int POSITIVE_BUTTON = AlertDialog.BUTTON1;
+ private static final int NEGATIVE_BUTTON = AlertDialog.BUTTON2;
+
+ // Dialog button text
+ public static final String BUTTON_TEXT_ACCEPT = "Accept";
+ public static final String BUTTON_TEXT_DENY = "Deny";
+
+ // Received ID from intent, -1 when no notification is in progress
+ private int notificationId = -1;
+
+ /** Used to detect when NI request is received */
+ private BroadcastReceiver mNetInitiatedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) Log.d(TAG, "NetInitiatedReceiver onReceive: " + intent.getAction());
+ if (intent.getAction() == GpsNetInitiatedHandler.ACTION_NI_VERIFY) {
+ handleNIVerify(intent);
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Set up the "dialog"
+ final Intent intent = getIntent();
+ final AlertController.AlertParams p = mAlertParams;
+ p.mIconId = com.android.internal.R.drawable.ic_dialog_usb;
+ p.mTitle = intent.getStringExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_TITLE);
+ p.mMessage = intent.getStringExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_MESSAGE);
+ p.mPositiveButtonText = BUTTON_TEXT_ACCEPT;
+ p.mPositiveButtonListener = this;
+ p.mNegativeButtonText = BUTTON_TEXT_DENY;
+ p.mNegativeButtonListener = this;
+
+ notificationId = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_NOTIF_ID, -1);
+ if (DEBUG) Log.d(TAG, "onCreate, notifId: " + notificationId);
+
+ setupAlert();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (DEBUG) Log.d(TAG, "onResume");
+ registerReceiver(mNetInitiatedReceiver, new IntentFilter(GpsNetInitiatedHandler.ACTION_NI_VERIFY));
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (DEBUG) Log.d(TAG, "onPause");
+ unregisterReceiver(mNetInitiatedReceiver);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == POSITIVE_BUTTON) {
+ sendUserResponse(GpsNetInitiatedHandler.GPS_NI_RESPONSE_ACCEPT);
+ }
+ if (which == NEGATIVE_BUTTON) {
+ sendUserResponse(GpsNetInitiatedHandler.GPS_NI_RESPONSE_DENY);
+ }
+
+ // No matter what, finish the activity
+ finish();
+ notificationId = -1;
+ }
+
+ // Respond to NI Handler under GpsLocationProvider, 1 = accept, 2 = deny
+ private void sendUserResponse(int response) {
+ if (DEBUG) Log.d(TAG, "sendUserResponse, response: " + response);
+ LocationManager locationManager = (LocationManager)
+ this.getSystemService(Context.LOCATION_SERVICE);
+ locationManager.sendNiResponse(notificationId, response);
+ }
+
+ private void handleNIVerify(Intent intent) {
+ int notifId = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_NOTIF_ID, -1);
+ notificationId = notifId;
+
+ if (DEBUG) Log.d(TAG, "handleNIVerify action: " + intent.getAction());
+ }
+
+ private void showNIError() {
+ Toast.makeText(this, "NI error" /* com.android.internal.R.string.usb_storage_error_message */,
+ Toast.LENGTH_LONG).show();
+ }
+}
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index 77d6e20..4c9451e 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -21,8 +21,8 @@ import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ProgressDialog;
import android.app.AlertDialog;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.IBluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.IBluetooth;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -179,13 +179,13 @@ public final class ShutdownThread extends Thread {
final ITelephony phone =
ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- final IBluetoothDevice bluetooth =
- IBluetoothDevice.Stub.asInterface(ServiceManager.checkService(
+ final IBluetooth bluetooth =
+ IBluetooth.Stub.asInterface(ServiceManager.checkService(
Context.BLUETOOTH_SERVICE));
try {
bluetoothOff = bluetooth == null ||
- bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF;
+ bluetooth.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_OFF;
if (!bluetoothOff) {
Log.w(TAG, "Disabling Bluetooth...");
bluetooth.disable(false); // disable but don't persist new state
@@ -213,7 +213,7 @@ public final class ShutdownThread extends Thread {
if (!bluetoothOff) {
try {
bluetoothOff =
- bluetooth.getBluetoothState() == BluetoothDevice.BLUETOOTH_STATE_OFF;
+ bluetooth.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_OFF;
} catch (RemoteException ex) {
Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
bluetoothOff = true;
diff --git a/core/java/com/android/internal/backup/SystemBackupAgent.java b/core/java/com/android/internal/backup/SystemBackupAgent.java
deleted file mode 100644
index 6b396d7..0000000
--- a/core/java/com/android/internal/backup/SystemBackupAgent.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.backup;
-
-import android.backup.AbsoluteFileBackupHelper;
-import android.backup.BackupHelperAgent;
-
-/**
- * Backup agent for various system-managed data
- */
-public class SystemBackupAgent extends BackupHelperAgent {
- // the set of files that we back up whole, as absolute paths
- String[] mFiles = {
- /* WallpaperService.WALLPAPER_FILE */
- "/data/data/com.android.settings/files/wallpaper",
- };
-
- public void onCreate() {
- addHelper("system_files", new AbsoluteFileBackupHelper(this, mFiles));
- }
-}
diff --git a/core/java/com/android/internal/content/SyncStateContentProviderHelper.java b/core/java/com/android/internal/content/SyncStateContentProviderHelper.java
new file mode 100644
index 0000000..d2931a4
--- /dev/null
+++ b/core/java/com/android/internal/content/SyncStateContentProviderHelper.java
@@ -0,0 +1,115 @@
+/*
+ * 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 com.android.internal.content;
+
+import com.android.internal.util.ArrayUtils;
+
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.accounts.Account;
+import android.content.ContentValues;
+import android.provider.SyncStateContract;
+
+/**
+ * Extends the schema of a ContentProvider to include the _sync_state table
+ * and implements query/insert/update/delete to access that table using the
+ * authority "syncstate". This can be used to store the sync state for a
+ * set of accounts.
+ *
+ * @hide
+ */
+public class SyncStateContentProviderHelper {
+ private static final String SELECT_BY_ACCOUNT =
+ SyncStateContract.Columns.ACCOUNT_NAME + "=? AND "
+ + SyncStateContract.Columns.ACCOUNT_TYPE + "=?";
+
+ private static final String SYNC_STATE_TABLE = "_sync_state";
+ private static final String SYNC_STATE_META_TABLE = "_sync_state_metadata";
+ private static final String SYNC_STATE_META_VERSION_COLUMN = "version";
+
+ private static long DB_VERSION = 1;
+
+ private static final String[] ACCOUNT_PROJECTION =
+ new String[]{SyncStateContract.Columns.ACCOUNT_NAME,
+ SyncStateContract.Columns.ACCOUNT_TYPE};
+
+ public static final String PATH = "syncstate";
+
+ public void createDatabase(SQLiteDatabase db) {
+ db.execSQL("DROP TABLE IF EXISTS " + SYNC_STATE_TABLE);
+ db.execSQL("CREATE TABLE " + SYNC_STATE_TABLE + " ("
+ + SyncStateContract.Columns._ID + " INTEGER PRIMARY KEY,"
+ + SyncStateContract.Columns.ACCOUNT_NAME + " TEXT NOT NULL,"
+ + SyncStateContract.Columns.ACCOUNT_TYPE + " TEXT NOT NULL,"
+ + SyncStateContract.Columns.DATA + " TEXT,"
+ + "UNIQUE(" + SyncStateContract.Columns.ACCOUNT_NAME + ", "
+ + SyncStateContract.Columns.ACCOUNT_TYPE + "));");
+
+ db.execSQL("DROP TABLE IF EXISTS " + SYNC_STATE_META_TABLE);
+ db.execSQL("CREATE TABLE " + SYNC_STATE_META_TABLE + " ("
+ + SYNC_STATE_META_VERSION_COLUMN + " INTEGER);");
+ ContentValues values = new ContentValues();
+ values.put(SYNC_STATE_META_VERSION_COLUMN, DB_VERSION);
+ db.insert(SYNC_STATE_META_TABLE, SYNC_STATE_META_VERSION_COLUMN, values);
+ }
+
+ public void onDatabaseOpened(SQLiteDatabase db) {
+ long version = DatabaseUtils.longForQuery(db,
+ "SELECT " + SYNC_STATE_META_VERSION_COLUMN + " FROM " + SYNC_STATE_META_TABLE,
+ null);
+ if (version != DB_VERSION) {
+ createDatabase(db);
+ }
+ }
+
+ public Cursor query(SQLiteDatabase db, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder) {
+ return db.query(SYNC_STATE_TABLE, projection, selection, selectionArgs,
+ null, null, sortOrder);
+ }
+
+ public long insert(SQLiteDatabase db, ContentValues values) {
+ return db.replace(SYNC_STATE_TABLE, SyncStateContract.Columns.ACCOUNT_NAME, values);
+ }
+
+ public int delete(SQLiteDatabase db, String userWhere, String[] whereArgs) {
+ return db.delete(SYNC_STATE_TABLE, userWhere, whereArgs);
+ }
+
+ public int update(SQLiteDatabase db, ContentValues values,
+ String selection, String[] selectionArgs) {
+ return db.update(SYNC_STATE_TABLE, values, selection, selectionArgs);
+ }
+
+ public void onAccountsChanged(SQLiteDatabase db, Account[] accounts) {
+ Cursor c = db.query(SYNC_STATE_TABLE, ACCOUNT_PROJECTION, null, null, null, null, null);
+ try {
+ while (c.moveToNext()) {
+ 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, SELECT_BY_ACCOUNT,
+ new String[]{accountName, accountType});
+ }
+ }
+ } finally {
+ c.close();
+ }
+ }
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a449e5f..2da72df 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -978,10 +978,13 @@ public final class BatteryStatsImpl extends BatteryStats {
} else if (mBtHeadset != null) {
return getCurrentBluetoothPingCount() - mBluetoothPingStart;
}
- return -1;
+ return 0;
}
public void setBtHeadset(BluetoothHeadset headset) {
+ if (headset != null && mBtHeadset == null && isOnBattery() && mBluetoothPingStart == -1) {
+ mBluetoothPingStart = getCurrentBluetoothPingCount();
+ }
mBtHeadset = headset;
}
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 932555d..5825024 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -93,6 +93,18 @@ public class HandlerCaller {
mH.sendMessage(msg);
}
+ public boolean hasMessages(int what) {
+ return mH.hasMessages(what);
+ }
+
+ public void removeMessages(int what) {
+ mH.removeMessages(what);
+ }
+
+ public void removeMessages(int what, Object obj) {
+ mH.removeMessages(what, obj);
+ }
+
public void sendMessage(Message msg) {
mH.sendMessage(msg);
}
@@ -132,6 +144,14 @@ public class HandlerCaller {
return mH.obtainMessage(what, arg1, arg2, arg3);
}
+ public Message obtainMessageIIOO(int what, int arg1, int arg2,
+ Object arg3, Object arg4) {
+ SomeArgs args = obtainArgs();
+ args.arg1 = arg3;
+ args.arg2 = arg4;
+ return mH.obtainMessage(what, arg1, arg2, args);
+ }
+
public Message obtainMessageIOO(int what, int arg1, Object arg2, Object arg3) {
SomeArgs args = obtainArgs();
args.arg1 = arg2;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 94149e1..a2d3cd8 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
@@ -328,6 +347,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.
*
@@ -519,6 +577,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/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
new file mode 100644
index 0000000..5357469
--- /dev/null
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.service.wallpaper;
+
+import android.app.WallpaperManager;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.service.wallpaper.WallpaperService;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+
+/**
+ * Default built-in wallpaper that simply shows a static image.
+ */
+public class ImageWallpaper extends WallpaperService {
+ WallpaperManager mWallpaperManager;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
+ }
+
+ public Engine onCreateEngine() {
+ return new DrawableEngine();
+ }
+
+ class DrawableEngine extends Engine {
+ private final Object mLock = new Object();
+ private final Rect mBounds = new Rect();
+ private WallpaperObserver mReceiver;
+ Drawable mBackground;
+ float mXOffset;
+ float mYOffset;
+
+ class WallpaperObserver extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ updateWallpaper();
+ drawFrame();
+ }
+ }
+
+ @Override
+ public void onCreate(SurfaceHolder surfaceHolder) {
+ super.onCreate(surfaceHolder);
+ IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
+ mReceiver = new WallpaperObserver();
+ registerReceiver(mReceiver, filter);
+ updateWallpaper();
+ surfaceHolder.setSizeFromLayout();
+ //setTouchEventsEnabled(true);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mReceiver);
+ }
+
+ @Override
+ public void onVisibilityChanged(boolean visible) {
+ drawFrame();
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent event) {
+ super.onTouchEvent(event);
+ }
+
+ @Override
+ public void onOffsetsChanged(float xOffset, float yOffset,
+ int xPixels, int yPixels) {
+ mXOffset = xOffset;
+ mYOffset = yOffset;
+ drawFrame();
+ }
+
+ @Override
+ public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ super.onSurfaceChanged(holder, format, width, height);
+ drawFrame();
+ }
+
+ @Override
+ public void onSurfaceCreated(SurfaceHolder holder) {
+ super.onSurfaceCreated(holder);
+ }
+
+ @Override
+ public void onSurfaceDestroyed(SurfaceHolder holder) {
+ super.onSurfaceDestroyed(holder);
+ }
+
+ void drawFrame() {
+ SurfaceHolder sh = getSurfaceHolder();
+ Canvas c = sh.lockCanvas();
+ if (c != null) {
+ final Rect frame = sh.getSurfaceFrame();
+ synchronized (mLock) {
+ final Drawable background = mBackground;
+ final int dw = frame.width();
+ final int dh = frame.height();
+ final int bw = mBackground.getIntrinsicWidth();
+ final int bh = mBackground.getIntrinsicHeight();
+ final int availw = bw-dw;
+ final int availh = bh-dh;
+ int xPixels = availw > 0
+ ? -(int)(availw*mXOffset+.5f) : -(availw/2);
+ int yPixels = availh > 0
+ ? -(int)(availh*mYOffset+.5f) : -(availh/2);
+ c.translate(xPixels, yPixels);
+ c.drawColor(0xff000000);
+ background.draw(c);
+ }
+ sh.unlockCanvasAndPost(c);
+ }
+ }
+
+ void updateWallpaper() {
+ synchronized (mLock) {
+ mBackground = mWallpaperManager.getDrawable();
+ mBounds.left = mBounds.top = 0;
+ mBounds.right = mBackground.getIntrinsicWidth();
+ mBounds.bottom = mBackground.getIntrinsicHeight();
+ mBackground.setBounds(mBounds);
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
new file mode 100644
index 0000000..f4f6297
--- /dev/null
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -0,0 +1,95 @@
+package com.android.internal.view;
+
+import android.graphics.Rect;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.view.IWindow;
+import android.view.IWindowSession;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+public class BaseIWindow extends IWindow.Stub {
+ private IWindowSession mSession;
+
+ public void setSession(IWindowSession session) {
+ mSession = session;
+ }
+
+ public void resized(int w, int h, Rect coveredInsets,
+ Rect visibleInsets, boolean reportDraw) {
+ if (reportDraw) {
+ try {
+ mSession.finishDrawing(this);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ public void dispatchKey(KeyEvent event) {
+ try {
+ mSession.finishKey(this);
+ } catch (RemoteException ex) {
+ }
+ }
+
+ public boolean onDispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
+ event.recycle();
+ return false;
+ }
+
+ public void dispatchPointer(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
+ try {
+ if (event == null) {
+ event = mSession.getPendingPointerMove(this);
+ onDispatchPointer(event, eventTime, false);
+ } else if (callWhenDone) {
+ if (!onDispatchPointer(event, eventTime, true)) {
+ mSession.finishKey(this);
+ }
+ } else {
+ onDispatchPointer(event, eventTime, false);
+ }
+ } catch (RemoteException ex) {
+ }
+ }
+
+ public boolean onDispatchTrackball(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
+ event.recycle();
+ return false;
+ }
+
+ public void dispatchTrackball(MotionEvent event, long eventTime,
+ boolean callWhenDone) {
+ try {
+ if (event == null) {
+ event = mSession.getPendingTrackballMove(this);
+ onDispatchTrackball(event, eventTime, false);
+ } else if (callWhenDone) {
+ if (!onDispatchTrackball(event, eventTime, true)) {
+ mSession.finishKey(this);
+ }
+ } else {
+ onDispatchTrackball(event, eventTime, false);
+ }
+ } catch (RemoteException ex) {
+ }
+ }
+
+ public void dispatchAppVisibility(boolean visible) {
+ }
+
+ public void dispatchGetNewSurface() {
+ }
+
+ public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
+ }
+
+ public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
+ }
+
+ public void dispatchWallpaperOffsets(float x, float y) {
+ }
+}
diff --git a/core/java/com/android/internal/view/BaseSurfaceHolder.java b/core/java/com/android/internal/view/BaseSurfaceHolder.java
new file mode 100644
index 0000000..2823689
--- /dev/null
+++ b/core/java/com/android/internal/view/BaseSurfaceHolder.java
@@ -0,0 +1,174 @@
+package com.android.internal.view;
+
+import android.graphics.Canvas;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+import java.util.ArrayList;
+import java.util.concurrent.locks.ReentrantLock;
+
+public abstract class BaseSurfaceHolder implements SurfaceHolder {
+ private static final String TAG = "BaseSurfaceHolder";
+ static final boolean DEBUG = false;
+
+ public final ArrayList<SurfaceHolder.Callback> mCallbacks
+ = new ArrayList<SurfaceHolder.Callback>();
+
+ public final ReentrantLock mSurfaceLock = new ReentrantLock();
+ public final Surface mSurface = new Surface();
+
+ int mRequestedWidth = -1;
+ int mRequestedHeight = -1;
+ int mRequestedFormat = PixelFormat.OPAQUE;
+ int mRequestedType = -1;
+
+ long mLastLockTime = 0;
+
+ int mType = -1;
+ final Rect mSurfaceFrame = new Rect();
+
+ public abstract void onUpdateSurface();
+ public abstract void onRelayoutContainer();
+ public abstract boolean onAllowLockCanvas();
+
+ public int getRequestedWidth() {
+ return mRequestedWidth;
+ }
+
+ public int getRequestedHeight() {
+ return mRequestedHeight;
+ }
+
+ public int getRequestedFormat() {
+ return mRequestedFormat;
+ }
+
+ public int getRequestedType() {
+ return mRequestedType;
+ }
+
+ public void addCallback(Callback callback) {
+ synchronized (mCallbacks) {
+ // This is a linear search, but in practice we'll
+ // have only a couple callbacks, so it doesn't matter.
+ if (mCallbacks.contains(callback) == false) {
+ mCallbacks.add(callback);
+ }
+ }
+ }
+
+ public void removeCallback(Callback callback) {
+ synchronized (mCallbacks) {
+ mCallbacks.remove(callback);
+ }
+ }
+
+ public void setFixedSize(int width, int height) {
+ if (mRequestedWidth != width || mRequestedHeight != height) {
+ mRequestedWidth = width;
+ mRequestedHeight = height;
+ onRelayoutContainer();
+ }
+ }
+
+ public void setSizeFromLayout() {
+ if (mRequestedWidth != -1 || mRequestedHeight != -1) {
+ mRequestedWidth = mRequestedHeight = -1;
+ onRelayoutContainer();
+ }
+ }
+
+ public void setFormat(int format) {
+ if (mRequestedFormat != format) {
+ mRequestedFormat = format;
+ onUpdateSurface();
+ }
+ }
+
+ public void setType(int type) {
+ switch (type) {
+ case SURFACE_TYPE_HARDWARE:
+ case SURFACE_TYPE_GPU:
+ // these are deprecated, treat as "NORMAL"
+ type = SURFACE_TYPE_NORMAL;
+ break;
+ }
+ switch (type) {
+ case SURFACE_TYPE_NORMAL:
+ case SURFACE_TYPE_PUSH_BUFFERS:
+ if (mRequestedType != type) {
+ mRequestedType = type;
+ onUpdateSurface();
+ }
+ break;
+ }
+ }
+
+ public Canvas lockCanvas() {
+ return internalLockCanvas(null);
+ }
+
+ public Canvas lockCanvas(Rect dirty) {
+ return internalLockCanvas(dirty);
+ }
+
+ private final Canvas internalLockCanvas(Rect dirty) {
+ if (mType == SURFACE_TYPE_PUSH_BUFFERS) {
+ throw new BadSurfaceTypeException(
+ "Surface type is SURFACE_TYPE_PUSH_BUFFERS");
+ }
+ mSurfaceLock.lock();
+
+ if (DEBUG) Log.i(TAG, "Locking canvas..,");
+
+ Canvas c = null;
+ if (onAllowLockCanvas()) {
+ Rect frame = dirty != null ? dirty : mSurfaceFrame;
+ try {
+ c = mSurface.lockCanvas(frame);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception locking surface", e);
+ }
+ }
+
+ if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
+ if (c != null) {
+ mLastLockTime = SystemClock.uptimeMillis();
+ return c;
+ }
+
+ // If the Surface is not ready to be drawn, then return null,
+ // but throttle calls to this function so it isn't called more
+ // than every 100ms.
+ long now = SystemClock.uptimeMillis();
+ long nextTime = mLastLockTime + 100;
+ if (nextTime > now) {
+ try {
+ Thread.sleep(nextTime-now);
+ } catch (InterruptedException e) {
+ }
+ now = SystemClock.uptimeMillis();
+ }
+ mLastLockTime = now;
+ mSurfaceLock.unlock();
+
+ return null;
+ }
+
+ public void unlockCanvasAndPost(Canvas canvas) {
+ mSurface.unlockCanvasAndPost(canvas);
+ mSurfaceLock.unlock();
+ }
+
+ public Surface getSurface() {
+ return mSurface;
+ }
+
+ public Rect getSurfaceFrame() {
+ return mSurfaceFrame;
+ }
+};
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
new file mode 100644
index 0000000..8bae3e4
--- /dev/null
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.Manifest;
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.provider.SocialContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.Presence;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.SocialContract.Activities;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+/**
+ * Header used across system for displaying a title bar with contact info. You
+ * can bind specific values on the header, or use helper methods like
+ * {@link #bindFromContactId(long)} to populate asynchronously.
+ * <p>
+ * The parent must request the {@link Manifest.permission#READ_CONTACTS}
+ * permission to access contact data.
+ */
+public class ContactHeaderWidget extends FrameLayout implements View.OnClickListener,
+ View.OnLongClickListener {
+
+ private static final String TAG = "ContactHeaderWidget";
+
+ private TextView mDisplayNameView;
+ private TextView mPhoneticNameView;
+ private CheckBox mStarredView;
+ private ImageView mPhotoView;
+ private ImageView mPresenceView;
+ private TextView mStatusView;
+ private int mNoPhotoResource;
+ private QueryHandler mQueryHandler;
+
+ protected long mContactId;
+ protected Uri mContactSummaryUri;
+ protected Uri mContactUri;
+ protected Uri mStatusUri;
+
+ protected String[] mExcludeMimes = null;
+
+ protected ContentResolver mContentResolver;
+
+ /**
+ * Interface for callbacks invoked when the user interacts with a header.
+ */
+ public interface ContactHeaderListener {
+ public void onPhotoLongClick(View view);
+ public void onDisplayNameLongClick(View view);
+ }
+
+ private ContactHeaderListener mListener;
+
+ //Projection used for the summary info in the header.
+ protected static final String[] HEADER_PROJECTION = new String[] {
+ Contacts.DISPLAY_NAME,
+ Contacts.STARRED,
+ Contacts.PHOTO_ID,
+ Contacts.PRESENCE_STATUS,
+ };
+ protected static final int HEADER_DISPLAY_NAME_COLUMN_INDEX = 0;
+ //TODO: We need to figure out how we're going to get the phonetic name.
+ //static final int HEADER_PHONETIC_NAME_COLUMN_INDEX
+ protected static final int HEADER_STARRED_COLUMN_INDEX = 1;
+ protected static final int HEADER_PHOTO_ID_COLUMN_INDEX = 2;
+ protected static final int HEADER_PRESENCE_STATUS_COLUMN_INDEX = 3;
+
+ //Projection used for finding the most recent social status.
+ protected static final String[] SOCIAL_PROJECTION = new String[] {
+ Activities.TITLE,
+ Activities.PUBLISHED,
+ };
+ protected static final int SOCIAL_TITLE_COLUMN_INDEX = 0;
+ protected static final int SOCIAL_PUBLISHED_COLUMN_INDEX = 1;
+
+ //Projection used for looking up contact id from phone number
+ protected static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
+ PhoneLookup._ID,
+ };
+ protected static final int PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
+
+ //Projection used for looking up contact id from email address
+ protected static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
+ RawContacts.CONTACT_ID,
+ };
+ protected static final int EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
+
+
+ private static final int TOKEN_CONTACT_INFO = 0;
+ private static final int TOKEN_SOCIAL = 1;
+
+ public ContactHeaderWidget(Context context) {
+ this(context, null);
+ }
+
+ public ContactHeaderWidget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ContactHeaderWidget(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ mContentResolver = mContext.getContentResolver();
+
+ LayoutInflater inflater =
+ (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.contact_header, this);
+
+ mDisplayNameView = (TextView) findViewById(R.id.name);
+ mDisplayNameView.setOnLongClickListener(this);
+
+ mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name);
+
+ mStarredView = (CheckBox)findViewById(R.id.star);
+ mStarredView.setOnClickListener(this);
+
+ mPhotoView = (ImageView)findViewById(R.id.photo);
+ mPhotoView.setOnClickListener(this);
+ mPhotoView.setOnLongClickListener(this);
+
+ mPresenceView = (ImageView) findViewById(R.id.presence);
+
+ mStatusView = (TextView)findViewById(R.id.status);
+
+ // Set the photo with a random "no contact" image
+ long now = SystemClock.elapsedRealtime();
+ int num = (int) now & 0xf;
+ if (num < 9) {
+ // Leaning in from right, common
+ mNoPhotoResource = R.drawable.ic_contact_picture;
+ } else if (num < 14) {
+ // Leaning in from left uncommon
+ mNoPhotoResource = R.drawable.ic_contact_picture_2;
+ } else {
+ // Coming in from the top, rare
+ mNoPhotoResource = R.drawable.ic_contact_picture_3;
+ }
+
+ mQueryHandler = new QueryHandler(mContentResolver);
+ }
+
+ /**
+ * Set the given {@link ContactHeaderListener} to handle header events.
+ */
+ public void setContactHeaderListener(ContactHeaderListener listener) {
+ mListener = listener;
+ }
+
+ /** {@inheritDoc} */
+ public boolean onLongClick(View v) {
+ switch (v.getId()) {
+ case R.id.photo:
+ performPhotoLongClick();
+ return true;
+ case R.id.name:
+ performDisplayNameLongClick();
+ return true;
+ }
+ return false;
+ }
+
+ private void performPhotoLongClick() {
+ if (mListener != null) {
+ mListener.onPhotoLongClick(mPhotoView);
+ }
+ }
+
+ private void performDisplayNameLongClick() {
+ if (mListener != null) {
+ mListener.onDisplayNameLongClick(mDisplayNameView);
+ }
+ }
+
+ private class QueryHandler extends AsyncQueryHandler {
+
+ public QueryHandler(ContentResolver cr) {
+ super(cr);
+ }
+
+ @Override
+ protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ try{
+ if (token == TOKEN_CONTACT_INFO) {
+ bindContactInfo(cursor);
+ invalidate();
+ } else if (token == TOKEN_SOCIAL) {
+ bindSocial(cursor);
+ invalidate();
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+ }
+
+ /**
+ * Turn on/off showing of the star element.
+ */
+ public void showStar(boolean showStar) {
+ mStarredView.setVisibility(showStar ? View.VISIBLE : View.GONE);
+ }
+
+ /**
+ * Manually set the starred state of this header widget. This doesn't change
+ * the underlying {@link Contacts} value, only the UI state.
+ */
+ public void setStared(boolean starred) {
+ mStarredView.setChecked(starred);
+ }
+
+ /**
+ * Manually set the presence.
+ */
+ public void setPresence(int presence) {
+ mPresenceView.setImageResource(Presence.getPresenceIconResourceId(presence));
+ }
+
+ /**
+ * Manually set the contact uri
+ */
+ public void setContactUri(Uri uri) {
+ mContactUri = uri;
+ }
+
+ /**
+ * Manually set the photo to display in the header. This doesn't change the
+ * underlying {@link Contacts}, only the UI state.
+ */
+ public void setPhoto(Bitmap bitmap) {
+ mPhotoView.setImageBitmap(bitmap);
+ }
+
+ /**
+ * Manually set the display name and phonetic name to show in the header.
+ * This doesn't change the underlying {@link Contacts}, only the UI state.
+ */
+ public void setDisplayName(CharSequence displayName, CharSequence phoneticName) {
+ mDisplayNameView.setText(displayName);
+ if (mPhoneticNameView != null) {
+ mPhoneticNameView.setText(phoneticName);
+ }
+ }
+
+ /**
+ * Manually set the social snippet text to display in the header.
+ */
+ public void setSocialSnippet(CharSequence snippet) {
+ mStatusView.setText(snippet);
+ }
+
+ /**
+ * Set a list of specific MIME-types to exclude and not display. For
+ * example, this can be used to hide the {@link Contacts#CONTENT_ITEM_TYPE}
+ * profile icon.
+ */
+ public void setExcludeMimes(String[] excludeMimes) {
+ mExcludeMimes = excludeMimes;
+ }
+
+ /**
+ * Convenience method for binding all available data from an existing
+ * contact.
+ *
+ * @param contactId the contact id of the contact whose info should be displayed.
+ */
+ public void bindFromContactId(long contactId) {
+ mContactId = contactId;
+ mContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, mContactId);
+
+ bindSummaryUri(ContentUris.withAppendedId(Contacts.CONTENT_SUMMARY_URI, mContactId));
+ bindSocialUri(ContentUris.withAppendedId(Activities.CONTENT_CONTACT_STATUS_URI, mContactId));
+ }
+
+ /**
+ * Convenience method for binding {@link Contacts} header details from a
+ * {@link Contacts#CONTENT_SUMMARY_URI} reference.
+ */
+ public void bindSummaryUri(Uri contactSummary) {
+ mContactSummaryUri = contactSummary;
+ mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, mContactSummaryUri, HEADER_PROJECTION,
+ null, null, null);
+ }
+
+ /**
+ * Convenience method for binding {@link Activities} header details from a
+ * {@link Activities#CONTENT_CONTACT_STATUS_URI}.
+ */
+ public void bindSocialUri(Uri contactSocial) {
+ mStatusUri = contactSocial;
+ mQueryHandler.startQuery(TOKEN_SOCIAL, null, mStatusUri, SOCIAL_PROJECTION, null, null,
+ null);
+ }
+
+ /**
+ * Convenience method for binding all available data from an existing
+ * contact.
+ *
+ * @param emailAddress The email address used to do a reverse lookup in
+ * the contacts database. If more than one contact contains this email
+ * address, one of them will be chosen to bind to.
+ */
+ public void bindFromEmail(String emailAddress) {
+ Cursor c = null;
+ try {
+ c = mContentResolver.query(Uri.withAppendedPath(Email.CONTENT_FILTER_EMAIL_URI, Uri
+ .encode(emailAddress)), EMAIL_LOOKUP_PROJECTION, null, null, null);
+ if (c != null && c.moveToFirst()) {
+ long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
+ bindFromContactId(contactId);
+ } else {
+ setDisplayName(emailAddress, null);
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ /**
+ * Convenience method for binding all available data from an existing
+ * contact.
+ *
+ * @param number The phone number used to do a reverse lookup in
+ * the contacts database. If more than one contact contains this phone
+ * number, one of them will be chosen to bind to.
+ */
+ public void bindFromPhoneNumber(String number) {
+ Cursor c = null;
+ try {
+ c = mContentResolver.query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
+ PHONE_LOOKUP_PROJECTION, null, null, null);
+ if (c != null && c.moveToFirst()) {
+ long contactId = c.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
+ bindFromContactId(contactId);
+ } else {
+ setDisplayName(number, null);
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ /**
+ * Bind the contact details provided by the given {@link Cursor}.
+ */
+ protected void bindContactInfo(Cursor c) {
+ if (c == null || !c.moveToFirst()) return;
+
+ // TODO: Bring back phonetic name
+ final String displayName = c.getString(HEADER_DISPLAY_NAME_COLUMN_INDEX);
+ final String phoneticName = null;
+ this.setDisplayName(displayName, null);
+
+ final boolean starred = c.getInt(HEADER_STARRED_COLUMN_INDEX) != 0;
+ mStarredView.setChecked(starred);
+
+ //Set the photo
+ Bitmap photoBitmap = loadContactPhoto(c.getLong(HEADER_PHOTO_ID_COLUMN_INDEX), null);
+ if (photoBitmap == null) {
+ photoBitmap = loadPlaceholderPhoto(null);
+ }
+ mPhotoView.setImageBitmap(photoBitmap);
+
+ //Set the presence status
+ int presence = c.getInt(HEADER_PRESENCE_STATUS_COLUMN_INDEX);
+ mPresenceView.setImageResource(Presence.getPresenceIconResourceId(presence));
+ }
+
+ /**
+ * Bind the social data provided by the given {@link Cursor}.
+ */
+ protected void bindSocial(Cursor c) {
+ if (c == null || !c.moveToFirst()) return;
+ final String status = c.getString(SOCIAL_TITLE_COLUMN_INDEX);
+ this.setSocialSnippet(status);
+ }
+
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.star: {
+ // Toggle "starred" state
+ final ContentValues values = new ContentValues(1);
+ values.put(Contacts.STARRED, mStarredView.isChecked());
+ mContentResolver.update(mContactUri, values, null, null);
+ break;
+ }
+ case R.id.photo: {
+ // Photo launches contact detail action
+ final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mContactUri);
+ final Rect target = getTargetRect(view);
+ intent.putExtra(Intents.EXTRA_TARGET_RECT, target);
+ intent.putExtra(Intents.EXTRA_MODE, Intents.MODE_SMALL);
+ if (mExcludeMimes != null) {
+ // Exclude specific MIME-types when requested
+ intent.putExtra(Intents.EXTRA_EXCLUDE_MIMES, mExcludeMimes);
+ }
+ mContext.startActivity(intent);
+ break;
+ }
+ }
+ }
+
+ private Rect getTargetRect(View anchor) {
+ final int[] location = new int[2];
+ anchor.getLocationOnScreen(location);
+
+ final Rect rect = new Rect();
+ rect.left = location[0];
+ rect.top = location[1];
+ rect.right = rect.left + anchor.getWidth();
+ rect.bottom = rect.top + anchor.getHeight();
+ return rect;
+ }
+
+ private Bitmap loadContactPhoto(long photoId, BitmapFactory.Options options) {
+ Cursor photoCursor = null;
+ Bitmap photoBm = null;
+
+ try {
+ photoCursor = mContentResolver.query(
+ ContentUris.withAppendedId(Data.CONTENT_URI, photoId),
+ new String[] { Photo.PHOTO },
+ null, null, null);
+
+ if (photoCursor != null && photoCursor.moveToFirst() && !photoCursor.isNull(0)) {
+ byte[] photoData = photoCursor.getBlob(0);
+ photoBm = BitmapFactory.decodeByteArray(photoData, 0,
+ photoData.length, options);
+ }
+ } finally {
+ if (photoCursor != null) {
+ photoCursor.close();
+ }
+ }
+
+ return photoBm;
+ }
+
+ private Bitmap loadPlaceholderPhoto(BitmapFactory.Options options) {
+ if (mNoPhotoResource == 0) {
+ return null;
+ }
+ return BitmapFactory.decodeResource(mContext.getResources(),
+ mNoPhotoResource, options);
+ }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f0b311c..58056bd 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -316,20 +316,14 @@ public class LockPatternUtils {
/**
* Set the state of whether the device is permanently locked, meaning the user
- * must authenticate via other means. If false, that means the user has gone
- * out of permanent lock, so the existing (forgotten) lock pattern needs to
- * be cleared.
+ * must authenticate via other means.
+ *
* @param locked Whether the user is permanently locked out until they verify their
* credentials. Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
* attempts.
*/
public void setPermanentlyLocked(boolean locked) {
setBoolean(LOCKOUT_PERMANENT_KEY, locked);
-
- if (!locked) {
- setLockPatternEnabled(false);
- saveLockPattern(null);
- }
}
/**
diff --git a/core/java/com/google/android/gdata/client/QueryParamsImpl.java b/core/java/com/google/android/gdata/client/QueryParamsImpl.java
index e27b36f..fbe0d22 100644
--- a/core/java/com/google/android/gdata/client/QueryParamsImpl.java
+++ b/core/java/com/google/android/gdata/client/QueryParamsImpl.java
@@ -60,6 +60,8 @@ public class QueryParamsImpl extends QueryParams {
sb.append('?');
}
for (String param : params) {
+ String value = mParams.get(param);
+ if (value == null) continue;
if (first) {
first = false;
} else {
@@ -67,7 +69,7 @@ public class QueryParamsImpl extends QueryParams {
}
sb.append(param);
sb.append('=');
- String value = mParams.get(param);
+
String encodedValue = null;
try {
diff --git a/core/java/com/google/android/gdata2/client/AndroidGDataClient.java b/core/java/com/google/android/gdata2/client/AndroidGDataClient.java
new file mode 100644
index 0000000..6ba791d
--- /dev/null
+++ b/core/java/com/google/android/gdata2/client/AndroidGDataClient.java
@@ -0,0 +1,590 @@
+// Copyright 2007 The Android Open Source Project
+
+package com.google.android.gdata2.client;
+
+import com.google.android.net.GoogleHttpClient;
+import com.google.wireless.gdata2.client.GDataClient;
+import com.google.wireless.gdata2.client.HttpException;
+import com.google.wireless.gdata2.client.QueryParams;
+import com.google.wireless.gdata2.data.StringUtils;
+import com.google.wireless.gdata2.parser.ParseException;
+import com.google.wireless.gdata2.serializer.GDataSerializer;
+import com.google.android.gdata2.client.QueryParamsImpl;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.entity.AbstractHttpEntity;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.http.AndroidHttpClient;
+import android.text.TextUtils;
+import android.util.Config;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.BufferedInputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+
+/**
+ * Implementation of a GDataClient using GoogleHttpClient to make HTTP
+ * requests. Always issues GETs and POSTs, using the X-HTTP-Method-Override
+ * header when a PUT or DELETE is desired, to avoid issues with firewalls, etc.,
+ * that do not allow methods other than GET or POST.
+ */
+public class AndroidGDataClient implements GDataClient {
+
+ private static final String TAG = "GDataClient";
+ private static final boolean DEBUG = false;
+ private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
+
+ private static final String X_HTTP_METHOD_OVERRIDE =
+ "X-HTTP-Method-Override";
+
+ private static final String DEFAULT_USER_AGENT_APP_VERSION = "Android-GData/1.2";
+
+ private static final int MAX_REDIRECTS = 10;
+ private static String DEFAULT_GDATA_VERSION = "2.0";
+
+
+ private String mGDataVersion;
+ private final GoogleHttpClient mHttpClient;
+ private ContentResolver mResolver;
+
+ /**
+ * Interface for creating HTTP requests. Used by
+ * {@link AndroidGDataClient#createAndExecuteMethod}, since HttpUriRequest does not allow for
+ * changing the URI after creation, e.g., when you want to follow a redirect.
+ */
+ private interface HttpRequestCreator {
+ HttpUriRequest createRequest(URI uri);
+ }
+
+ private static class GetRequestCreator implements HttpRequestCreator {
+ public GetRequestCreator() {
+ }
+
+ public HttpUriRequest createRequest(URI uri) {
+ HttpGet get = new HttpGet(uri);
+ return get;
+ }
+ }
+
+ private static class PostRequestCreator implements HttpRequestCreator {
+ private final String mMethodOverride;
+ private final HttpEntity mEntity;
+ public PostRequestCreator(String methodOverride, HttpEntity entity) {
+ mMethodOverride = methodOverride;
+ mEntity = entity;
+ }
+
+ public HttpUriRequest createRequest(URI uri) {
+ HttpPost post = new HttpPost(uri);
+ if (mMethodOverride != null) {
+ post.addHeader(X_HTTP_METHOD_OVERRIDE, mMethodOverride);
+ }
+ post.setEntity(mEntity);
+ return post;
+ }
+ }
+
+ // MAJOR TODO: make this work across redirects (if we can reset the InputStream).
+ // OR, read the bits into a local buffer (yuck, the media could be large).
+ private static class MediaPutRequestCreator implements HttpRequestCreator {
+ private final InputStream mMediaInputStream;
+ private final String mContentType;
+ public MediaPutRequestCreator(InputStream mediaInputStream, String contentType) {
+ mMediaInputStream = mediaInputStream;
+ mContentType = contentType;
+ }
+
+ public HttpUriRequest createRequest(URI uri) {
+ HttpPost post = new HttpPost(uri);
+ post.addHeader(X_HTTP_METHOD_OVERRIDE, "PUT");
+ // mMediaInputStream.reset();
+ InputStreamEntity entity = new InputStreamEntity(mMediaInputStream,
+ -1 /* read until EOF */);
+ entity.setContentType(mContentType);
+ post.setEntity(entity);
+ return post;
+ }
+ }
+
+
+ /**
+ * Creates a new AndroidGDataClient.
+ *
+ * @param context The ContentResolver to get URL rewriting rules from
+ * through the Android proxy server, using null to indicate not using proxy.
+ * The context will also be used by GoogleHttpClient for configuration of
+ * SSL session persistence.
+ */
+ public AndroidGDataClient(Context context) {
+ this(context, DEFAULT_USER_AGENT_APP_VERSION);
+ }
+
+ /**
+ * Creates a new AndroidGDataClient.
+ *
+ * @param context The ContentResolver to get URL rewriting rules from
+ * through the Android proxy server, using null to indicate not using proxy.
+ * The context will also be used by GoogleHttpClient for configuration of
+ * SSL session persistence.
+ * @param appAndVersion The application name and version to be used as the basis of the
+ * User-Agent. e.g., Android-GData/1.5.0.
+ */
+ public AndroidGDataClient(Context context, String appAndVersion) {
+ this(context, appAndVersion, DEFAULT_GDATA_VERSION);
+ }
+
+ /**
+ * Creates a new AndroidGDataClient.
+ *
+ * @param context The ContentResolver to get URL rewriting rules from
+ * through the Android proxy server, using null to indicate not using proxy.
+ * The context will also be used by GoogleHttpClient for configuration of
+ * SSL session persistence.
+ * @param appAndVersion The application name and version to be used as the basis of the
+ * User-Agent. e.g., Android-GData/1.5.0.
+ * @param gdataVersion The gdata service version that should be
+ * used, e.g. "2.0"
+ *
+ */
+ public AndroidGDataClient(Context context, String appAndVersion, String gdataVersion) {
+ mHttpClient = new GoogleHttpClient(context, appAndVersion,
+ true /* gzip capable */);
+ mHttpClient.enableCurlLogging(TAG, Log.VERBOSE);
+ mResolver = context.getContentResolver();
+ mGDataVersion = gdataVersion;
+ }
+
+
+ public void close() {
+ mHttpClient.close();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see GDataClient#encodeUri(java.lang.String)
+ */
+ public String encodeUri(String uri) {
+ String encodedUri;
+ try {
+ encodedUri = URLEncoder.encode(uri, "UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ // should not happen.
+ Log.e("JakartaGDataClient",
+ "UTF-8 not supported -- should not happen. "
+ + "Using default encoding.", uee);
+ encodedUri = URLEncoder.encode(uri);
+ }
+ return encodedUri;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.google.wireless.gdata.client.GDataClient#createQueryParams()
+ */
+ public QueryParams createQueryParams() {
+ return new QueryParamsImpl();
+ }
+
+ // follows redirects
+ private InputStream createAndExecuteMethod(HttpRequestCreator creator,
+ String uriString,
+ String authToken,
+ String eTag,
+ String protocolVersion)
+ throws HttpException, IOException {
+
+ HttpResponse response = null;
+ int status = 500;
+ int redirectsLeft = MAX_REDIRECTS;
+
+ URI uri;
+ try {
+ uri = new URI(uriString);
+ } catch (URISyntaxException use) {
+ Log.w(TAG, "Unable to parse " + uriString + " as URI.", use);
+ throw new IOException("Unable to parse " + uriString + " as URI: "
+ + use.getMessage());
+ }
+
+ // we follow redirects ourselves, since we want to follow redirects even on POSTs, which
+ // the HTTP library does not do. following redirects ourselves also allows us to log
+ // the redirects using our own logging.
+ while (redirectsLeft > 0) {
+
+ HttpUriRequest request = creator.createRequest(uri);
+
+ AndroidHttpClient.modifyRequestToAcceptGzipResponse(request);
+ // only add the auth token if not null (to allow for GData feeds that do not require
+ // authentication.)
+ if (!TextUtils.isEmpty(authToken)) {
+ request.addHeader("Authorization", "GoogleLogin auth=" + authToken);
+ }
+
+ // while by default we have a 2.0 in this variable, it is possible to construct
+ // a client that has an empty version field, to work with 1.0 services.
+ if (!TextUtils.isEmpty(mGDataVersion)) {
+ request.addHeader("GDataVersion", mGDataVersion);
+ }
+
+ // if we have a passed down eTag value, we need to add several headers
+ if (!TextUtils.isEmpty(eTag)) {
+ String method = request.getMethod();
+ Header overrideMethodHeader = request.getFirstHeader(X_HTTP_METHOD_OVERRIDE);
+ if (overrideMethodHeader != null) {
+ method = overrideMethodHeader.getValue();
+ }
+ if ("GET".equals(method)) {
+ // add the none match header, if the resource is not changed
+ // this request will result in a 304 now.
+ request.addHeader("If-None-Match", eTag);
+ } else if ("DELETE".equals(method)
+ || "PUT".equals(method)) {
+ // now we send an if-match, but only if the passed in eTag is a strong eTag
+ // as this only makes sense for a strong eTag
+ if (!eTag.startsWith("W/")) {
+ request.addHeader("If-Match", eTag);
+ }
+ }
+ }
+
+ if (LOCAL_LOGV) {
+ for (Header h : request.getAllHeaders()) {
+ Log.v(TAG, h.getName() + ": " + h.getValue());
+ }
+ }
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Executing " + request.getRequestLine().toString());
+ }
+
+ response = null;
+
+ try {
+ response = mHttpClient.execute(request);
+ } catch (IOException ioe) {
+ Log.w(TAG, "Unable to execute HTTP request." + ioe);
+ throw ioe;
+ }
+
+ StatusLine statusLine = response.getStatusLine();
+ if (statusLine == null) {
+ Log.w(TAG, "StatusLine is null.");
+ throw new NullPointerException("StatusLine is null -- should not happen.");
+ }
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, response.getStatusLine().toString());
+ for (Header h : response.getAllHeaders()) {
+ Log.d(TAG, h.getName() + ": " + h.getValue());
+ }
+ }
+ status = statusLine.getStatusCode();
+
+ HttpEntity entity = response.getEntity();
+
+ if ((status >= 200) && (status < 300) && entity != null) {
+ InputStream in = AndroidHttpClient.getUngzippedContent(entity);
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ in = logInputStreamContents(in);
+ }
+ return in;
+ }
+
+ // TODO: handle 301, 307?
+ // TODO: let the http client handle the redirects, if we can be sure we'll never get a
+ // redirect on POST.
+ if (status == 302) {
+ // consume the content, so the connection can be closed.
+ entity.consumeContent();
+ Header location = response.getFirstHeader("Location");
+ if (location == null) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Redirect requested but no Location "
+ + "specified.");
+ }
+ break;
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Following redirect to " + location.getValue());
+ }
+ try {
+ uri = new URI(location.getValue());
+ } catch (URISyntaxException use) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Unable to parse " + location.getValue() + " as URI.", use);
+ throw new IOException("Unable to parse " + location.getValue()
+ + " as URI.");
+ }
+ break;
+ }
+ --redirectsLeft;
+ } else {
+ break;
+ }
+ }
+
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Received " + status + " status code.");
+ }
+ String errorMessage = null;
+ HttpEntity entity = response.getEntity();
+ try {
+ if (response != null && entity != null) {
+ InputStream in = AndroidHttpClient.getUngzippedContent(entity);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buf = new byte[8192];
+ int bytesRead = -1;
+ while ((bytesRead = in.read(buf)) != -1) {
+ baos.write(buf, 0, bytesRead);
+ }
+ // TODO: use appropriate encoding, picked up from Content-Type.
+ errorMessage = new String(baos.toByteArray());
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, errorMessage);
+ }
+ }
+ } finally {
+ if (entity != null) {
+ entity.consumeContent();
+ }
+ }
+ String exceptionMessage = "Received " + status + " status code";
+ if (errorMessage != null) {
+ exceptionMessage += (": " + errorMessage);
+ }
+ throw new HttpException(exceptionMessage, status, null /* InputStream */);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see GDataClient#getFeedAsStream(java.lang.String, java.lang.String)
+ */
+ public InputStream getFeedAsStream(String feedUrl,
+ String authToken,
+ String eTag,
+ String protocolVersion)
+ throws HttpException, IOException {
+
+ InputStream in = createAndExecuteMethod(new GetRequestCreator(), feedUrl, authToken, eTag, protocolVersion);
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to access feed.");
+ }
+
+ /**
+ * Log the contents of the input stream.
+ * The original input stream is consumed, so the caller must use the
+ * BufferedInputStream that is returned.
+ * @param in InputStream
+ * @return replacement input stream for caller to use
+ * @throws IOException
+ */
+ private InputStream logInputStreamContents(InputStream in) throws IOException {
+ if (in == null) {
+ return in;
+ }
+ // bufferSize is the (arbitrary) maximum amount to log.
+ // The original InputStream is wrapped in a
+ // BufferedInputStream with a 16K buffer. This lets
+ // us read up to 16K, write it to the log, and then
+ // reset the stream so the the original client can
+ // then read the data. The BufferedInputStream
+ // provides the mark and reset support, even when
+ // the original InputStream does not.
+ final int bufferSize = 16384;
+ BufferedInputStream bin = new BufferedInputStream(in, bufferSize);
+ bin.mark(bufferSize);
+ int wanted = bufferSize;
+ int totalReceived = 0;
+ byte buf[] = new byte[wanted];
+ while (wanted > 0) {
+ int got = bin.read(buf, totalReceived, wanted);
+ if (got <= 0) break; // EOF
+ wanted -= got;
+ totalReceived += got;
+ }
+ Log.d(TAG, new String(buf, 0, totalReceived, "UTF-8"));
+ bin.reset();
+ return bin;
+ }
+
+ public InputStream getMediaEntryAsStream(String mediaEntryUrl, String authToken, String eTag, String protocolVersion)
+ throws HttpException, IOException {
+
+ InputStream in = createAndExecuteMethod(new GetRequestCreator(), mediaEntryUrl, authToken, eTag, protocolVersion);
+
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to access media entry.");
+ }
+
+ /* (non-Javadoc)
+ * @see GDataClient#createEntry
+ */
+ public InputStream createEntry(String feedUrl,
+ String authToken,
+ String protocolVersion,
+ GDataSerializer entry)
+ throws HttpException, IOException {
+
+ HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_CREATE);
+ InputStream in = createAndExecuteMethod(
+ new PostRequestCreator(null /* override */, entity),
+ feedUrl,
+ authToken,
+ null,
+ protocolVersion);
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to create entry.");
+ }
+
+ /* (non-Javadoc)
+ * @see GDataClient#updateEntry
+ */
+ public InputStream updateEntry(String editUri,
+ String authToken,
+ String eTag,
+ String protocolVersion,
+ GDataSerializer entry)
+ throws HttpException, IOException {
+ HttpEntity entity = createEntityForEntry(entry, GDataSerializer.FORMAT_UPDATE);
+ final String method = entry.getSupportsPartial() ? "PATCH" : "PUT";
+ InputStream in = createAndExecuteMethod(
+ new PostRequestCreator(method, entity),
+ editUri,
+ authToken,
+ eTag,
+ protocolVersion);
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to update entry.");
+ }
+
+ /* (non-Javadoc)
+ * @see GDataClient#deleteEntry
+ */
+ public void deleteEntry(String editUri, String authToken, String eTag)
+ throws HttpException, IOException {
+ if (StringUtils.isEmpty(editUri)) {
+ throw new IllegalArgumentException(
+ "you must specify an non-empty edit url");
+ }
+ InputStream in =
+ createAndExecuteMethod(
+ new PostRequestCreator("DELETE", null /* entity */),
+ editUri,
+ authToken,
+ eTag,
+ null /* protocolVersion, not required for a delete */);
+ if (in == null) {
+ throw new IOException("Unable to delete entry.");
+ }
+ try {
+ in.close();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ public InputStream updateMediaEntry(String editUri, String authToken, String eTag,
+ String protocolVersion, InputStream mediaEntryInputStream, String contentType)
+ throws HttpException, IOException {
+ InputStream in = createAndExecuteMethod(
+ new MediaPutRequestCreator(mediaEntryInputStream, contentType),
+ editUri,
+ authToken,
+ eTag,
+ protocolVersion);
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to write media entry.");
+ }
+
+ private HttpEntity createEntityForEntry(GDataSerializer entry, int format) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ entry.serialize(baos, format);
+ } catch (IOException ioe) {
+ Log.e(TAG, "Unable to serialize entry.", ioe);
+ throw ioe;
+ } catch (ParseException pe) {
+ Log.e(TAG, "Unable to serialize entry.", pe);
+ throw new IOException("Unable to serialize entry: " + pe.getMessage());
+ }
+
+ byte[] entryBytes = baos.toByteArray();
+
+ if (entryBytes != null && Log.isLoggable(TAG, Log.DEBUG)) {
+ try {
+ Log.d(TAG, "Serialized entry: " + new String(entryBytes, "UTF-8"));
+ } catch (UnsupportedEncodingException uee) {
+ // should not happen
+ throw new IllegalStateException("UTF-8 should be supported!",
+ uee);
+ }
+ }
+
+ AbstractHttpEntity entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver);
+ entity.setContentType(entry.getContentType());
+ return entity;
+ }
+
+ /**
+ * Connects to a GData server (specified by the batchUrl) and submits a
+ * batch for processing. The response from the server is returned as an
+ * {@link InputStream}. The caller is responsible for calling
+ * {@link InputStream#close()} on the returned {@link InputStream}.
+ *
+ * @param batchUrl The batch url to which the batch is submitted.
+ * @param authToken the authentication token that should be used when
+ * submitting the batch.
+ * @param protocolVersion The version of the protocol that
+ * should be used for this request.
+ * @param batch The batch of entries to submit.
+ * @throws IOException Thrown if an io error occurs while communicating with
+ * the service.
+ * @throws HttpException if the service returns an error response.
+ */
+ public InputStream submitBatch(String batchUrl,
+ String authToken,
+ String protocolVersion,
+ GDataSerializer batch)
+ throws HttpException, IOException
+ {
+ HttpEntity entity = createEntityForEntry(batch, GDataSerializer.FORMAT_BATCH);
+ InputStream in = createAndExecuteMethod(
+ new PostRequestCreator("POST", entity),
+ batchUrl,
+ authToken,
+ null,
+ protocolVersion);
+ if (in != null) {
+ return in;
+ }
+ throw new IOException("Unable to process batch request.");
+ }
+}
+
diff --git a/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java b/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java
new file mode 100644
index 0000000..f097706
--- /dev/null
+++ b/core/java/com/google/android/gdata2/client/AndroidXmlParserFactory.java
@@ -0,0 +1,31 @@
+package com.google.android.gdata2.client;
+
+import com.google.wireless.gdata2.parser.xml.XmlParserFactory;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.util.Xml;
+
+/**
+ * XmlParserFactory for the Android platform.
+ */
+public class AndroidXmlParserFactory implements XmlParserFactory {
+
+ /*
+ * (non-javadoc)
+ * @see XmlParserFactory#createParser
+ */
+ public XmlPullParser createParser() throws XmlPullParserException {
+ return Xml.newPullParser();
+ }
+
+ /*
+ * (non-javadoc)
+ * @see XmlParserFactory#createSerializer
+ */
+ public XmlSerializer createSerializer() throws XmlPullParserException {
+ return Xml.newSerializer();
+ }
+}
diff --git a/core/java/com/google/android/gdata2/client/QueryParamsImpl.java b/core/java/com/google/android/gdata2/client/QueryParamsImpl.java
new file mode 100644
index 0000000..a26f4ce
--- /dev/null
+++ b/core/java/com/google/android/gdata2/client/QueryParamsImpl.java
@@ -0,0 +1,99 @@
+package com.google.android.gdata2.client;
+import com.google.wireless.gdata2.client.QueryParams;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Simple implementation of the QueryParams interface.
+ */
+// TODO: deal with categories
+public class QueryParamsImpl extends QueryParams {
+
+ private final Map<String,String> mParams = new HashMap<String,String>();
+
+ /**
+ * Creates a new empty QueryParamsImpl.
+ */
+ public QueryParamsImpl() {
+ }
+
+ @Override
+ public void clear() {
+ setEntryId(null);
+ mParams.clear();
+ }
+
+ @Override
+ public String generateQueryUrl(String feedUrl) {
+
+ if (TextUtils.isEmpty(getEntryId()) &&
+ mParams.isEmpty()) {
+ // nothing to do
+ return feedUrl;
+ }
+
+ // handle entry IDs
+ if (!TextUtils.isEmpty(getEntryId())) {
+ if (!mParams.isEmpty()) {
+ throw new IllegalStateException("Cannot set both an entry ID "
+ + "and other query paramters.");
+ }
+ return feedUrl + '/' + getEntryId();
+ }
+
+ // otherwise, append the querystring params.
+ StringBuilder sb = new StringBuilder();
+ sb.append(feedUrl);
+ Set<String> params = mParams.keySet();
+ boolean first = true;
+ if (feedUrl.contains("?")) {
+ first = false;
+ } else {
+ sb.append('?');
+ }
+ for (String param : params) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append('&');
+ }
+ sb.append(param);
+ sb.append('=');
+ String value = mParams.get(param);
+ String encodedValue = null;
+
+ try {
+ encodedValue = URLEncoder.encode(value, "UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ // should not happen.
+ Log.w("QueryParamsImpl",
+ "UTF-8 not supported -- should not happen. "
+ + "Using default encoding.", uee);
+ encodedValue = URLEncoder.encode(value);
+ }
+ sb.append(encodedValue);
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String getParamValue(String param) {
+ if (!(mParams.containsKey(param))) {
+ return null;
+ }
+ return mParams.get(param);
+ }
+
+ @Override
+ public void setParamValue(String param, String value) {
+ mParams.put(param, value);
+ }
+
+}
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/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java
index d2a41f1..df91ea6 100644
--- a/core/java/com/google/android/mms/pdu/PduPersister.java
+++ b/core/java/com/google/android/mms/pdu/PduPersister.java
@@ -31,6 +31,7 @@ import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
+import android.provider.Telephony;
import android.provider.Telephony.Mms;
import android.provider.Telephony.MmsSms;
import android.provider.Telephony.Threads;
@@ -54,6 +55,8 @@ import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
+import com.google.android.mms.pdu.EncodedStringValue;
+
/**
* This class is the high-level manager of PDU storage.
*/
@@ -159,6 +162,7 @@ public class PduPersister {
Part.CONTENT_TYPE,
Part.FILENAME,
Part.NAME,
+ Part.TEXT
};
private static final int PART_COLUMN_ID = 0;
@@ -169,6 +173,7 @@ public class PduPersister {
private static final int PART_COLUMN_CONTENT_TYPE = 5;
private static final int PART_COLUMN_FILENAME = 6;
private static final int PART_COLUMN_NAME = 7;
+ private static final int PART_COLUMN_TEXT = 8;
private static final HashMap<Uri, Integer> MESSAGE_BOX_MAP;
// These map are used for convenience in persist() and load().
@@ -414,26 +419,36 @@ public class PduPersister {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = null;
- try {
- is = mContentResolver.openInputStream(partURI);
-
- byte[] buffer = new byte[256];
- int len = is.read(buffer);
- while (len >= 0) {
- baos.write(buffer, 0, len);
- len = is.read(buffer);
- }
- } catch (IOException e) {
- Log.e(TAG, "Failed to load part data", e);
- c.close();
- throw new MmsException(e);
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- Log.e(TAG, "Failed to close stream", e);
- } // Ignore
+ // Store simple string values directly in the database instead of an
+ // external file. This makes the text searchable and retrieval slightly
+ // faster.
+ if ("text/plain".equals(type) || "application/smil".equals(type)) {
+ String text = c.getString(PART_COLUMN_TEXT);
+ byte [] blob = new EncodedStringValue(text).getTextString();
+ baos.write(blob, 0, blob.length);
+ } else {
+
+ try {
+ is = mContentResolver.openInputStream(partURI);
+
+ byte[] buffer = new byte[256];
+ int len = is.read(buffer);
+ while (len >= 0) {
+ baos.write(buffer, 0, len);
+ len = is.read(buffer);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to load part data", e);
+ c.close();
+ throw new MmsException(e);
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close stream", e);
+ } // Ignore
+ }
}
}
part.setData(baos.toByteArray());
@@ -719,29 +734,37 @@ public class PduPersister {
InputStream is = null;
try {
- os = mContentResolver.openOutputStream(uri);
byte[] data = part.getData();
- if (data == null) {
- Uri dataUri = part.getDataUri();
- if ((dataUri == null) || (dataUri == uri)) {
- Log.w(TAG, "Can't find data for this part.");
- return;
- }
- is = mContentResolver.openInputStream(dataUri);
-
- if (LOCAL_LOGV) {
- Log.v(TAG, "Saving data to: " + uri);
- }
-
- byte[] buffer = new byte[256];
- for (int len = 0; (len = is.read(buffer)) != -1; ) {
- os.write(buffer, 0, len);
+ if ("text/plain".equals(contentType) || "application/smil".equals(contentType)) {
+ ContentValues cv = new ContentValues();
+ cv.put(Telephony.Mms.Part.TEXT, new EncodedStringValue(data).getString());
+ if (mContentResolver.update(uri, cv, null, null) != 1) {
+ throw new MmsException("unable to update " + uri.toString());
}
} else {
- if (LOCAL_LOGV) {
- Log.v(TAG, "Saving data to: " + uri);
+ os = mContentResolver.openOutputStream(uri);
+ if (data == null) {
+ Uri dataUri = part.getDataUri();
+ if ((dataUri == null) || (dataUri == uri)) {
+ Log.w(TAG, "Can't find data for this part.");
+ return;
+ }
+ is = mContentResolver.openInputStream(dataUri);
+
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "Saving data to: " + uri);
+ }
+
+ byte[] buffer = new byte[256];
+ for (int len = 0; (len = is.read(buffer)) != -1; ) {
+ os.write(buffer, 0, len);
+ }
+ } else {
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "Saving data to: " + uri);
+ }
+ os.write(data);
}
- os.write(data);
}
} catch (FileNotFoundException e) {
Log.e(TAG, "Failed to open Input/Output stream.", e);
@@ -998,6 +1021,7 @@ public class PduPersister {
+ "content://mms/drafts, content://mms/outbox, "
+ "content://mms/temp.");
}
+ PDU_CACHE_INSTANCE.purge(uri);
PduHeaders header = pdu.getPduHeaders();
PduBody body = null;
diff --git a/core/java/com/google/android/net/GoogleHttpClient.java b/core/java/com/google/android/net/GoogleHttpClient.java
index 922f5be..8a1298f 100644
--- a/core/java/com/google/android/net/GoogleHttpClient.java
+++ b/core/java/com/google/android/net/GoogleHttpClient.java
@@ -58,8 +58,8 @@ import java.net.URISyntaxException;
* and otherwise tweak HTTP requests.
*/
public class GoogleHttpClient implements HttpClient {
-
private static final String TAG = "GoogleHttpClient";
+ private static final boolean LOCAL_LOGV = Config.LOGV || false;
/** Exception thrown when a request is blocked by the URL rules. */
public static class BlockedRequestException extends IOException {
@@ -289,9 +289,7 @@ public class GoogleHttpClient implements HttpClient {
wrapper.setURI(uri);
request = wrapper;
- if (Config.LOGV) {
- Log.v(TAG, "Rule " + rule.mName + ": " + original + " -> " + rewritten);
- }
+ if (LOCAL_LOGV) Log.v(TAG, "Rule " + rule.mName + ": " + original + " -> " + rewritten);
return executeWithoutRewriting(request, context);
}
diff --git a/core/java/com/google/android/net/UrlRules.java b/core/java/com/google/android/net/UrlRules.java
index c269d1b..54d139d 100644
--- a/core/java/com/google/android/net/UrlRules.java
+++ b/core/java/com/google/android/net/UrlRules.java
@@ -20,6 +20,7 @@ import android.content.ContentResolver;
import android.database.Cursor;
import android.provider.Checkin;
import android.provider.Settings;
+import android.util.Config;
import android.util.Log;
import java.util.ArrayList;
@@ -53,6 +54,9 @@ import java.util.regex.Pattern;
* </pre>
*/
public class UrlRules {
+ public static final String TAG = "UrlRules";
+ public static final boolean LOCAL_LOGV = Config.LOGV || false;
+
/** Thrown when the rewrite rules can't be parsed. */
public static class RuleFormatException extends Exception {
public RuleFormatException(String msg) { super(msg); }
@@ -192,10 +196,11 @@ public class UrlRules {
Settings.Gservices.PROVISIONING_DIGEST);
if (sCachedDigest != null && sCachedDigest.equals(digest)) {
// The digest is the same, so the rules are the same.
+ if (LOCAL_LOGV) Log.v(TAG, "Using cached rules for digest: " + digest);
return sCachedRules;
}
- // Get all the Gservices settings with names starting with "url:".
+ if (LOCAL_LOGV) Log.v(TAG, "Scanning for Gservices \"url:*\" rules");
Cursor cursor = resolver.query(Settings.Gservices.CONTENT_URI,
new String[] {
Settings.Gservices.NAME,
@@ -210,16 +215,18 @@ public class UrlRules {
String name = cursor.getString(0).substring(4); // "url:X"
String value = cursor.getString(1);
if (value == null || value.length() == 0) continue;
+ if (LOCAL_LOGV) Log.v(TAG, " Rule " + name + ": " + value);
rules.add(new Rule(name, value));
} catch (RuleFormatException e) {
// Oops, Gservices has an invalid rule! Skip it.
- Log.e("UrlRules", "Invalid rule from Gservices", e);
+ Log.e(TAG, "Invalid rule from Gservices", e);
Checkin.logEvent(resolver,
Checkin.Events.Tag.GSERVICES_ERROR, e.toString());
}
}
sCachedRules = new UrlRules(rules.toArray(new Rule[rules.size()]));
sCachedDigest = digest;
+ if (LOCAL_LOGV) Log.v(TAG, "New rules stored for digest: " + digest);
} finally {
cursor.close();
}
diff --git a/core/jni/.android_server_BluetoothEventLoop.cpp.swp b/core/jni/.android_server_BluetoothEventLoop.cpp.swp
new file mode 100644
index 0000000..d36e403
--- /dev/null
+++ b/core/jni/.android_server_BluetoothEventLoop.cpp.swp
Binary files differ
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 888cb11..015268b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -11,10 +11,16 @@ else
LOCAL_CFLAGS += -DPACKED=""
endif
+ifeq ($(WITH_JIT),true)
+ LOCAL_CFLAGS += -DWITH_JIT
+endif
+
ifneq ($(USE_CUSTOM_RUNTIME_HEAP_MAX),)
LOCAL_CFLAGS += -DCUSTOM_RUNTIME_HEAP_MAX=$(USE_CUSTOM_RUNTIME_HEAP_MAX)
endif
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
LOCAL_SRC_FILES:= \
ActivityManager.cpp \
AndroidRuntime.cpp \
@@ -39,7 +45,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 \
@@ -104,13 +109,12 @@ 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_BluetoothService.cpp \
android_server_BluetoothEventLoop.cpp \
android_server_BluetoothA2dpService.cpp \
android_message_digest_sha1.cpp \
@@ -150,11 +154,11 @@ LOCAL_SHARED_LIBRARIES := \
libnativehelper \
libcutils \
libutils \
+ libbinder \
libnetutils \
libui \
libskiagl \
- libsgl \
- libcorecg \
+ libskia \
libsqlite \
libdvm \
libEGL \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c815301..f61e247 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,12 +142,11 @@ 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_BluetoothService(JNIEnv* env);
extern int register_android_server_BluetoothEventLoop(JNIEnv *env);
extern int register_android_server_BluetoothA2dpService(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -509,11 +507,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];
@@ -521,25 +525,20 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
+ char heapsizeOptsBuf[sizeof("-Xmx")-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;
+ enum {
+ kEMDefault,
+ kEMIntPortable,
+ kEMIntFast,
+#if defined(WITH_JIT)
+ kEMJitCompiler,
+#endif
+ } 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) {
@@ -557,10 +556,19 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
executionMode = kEMIntPortable;
} else if (strcmp(propBuf, "int:fast") == 0) {
executionMode = kEMIntFast;
+#if defined(WITH_JIT)
+ } else if (strcmp(propBuf, "int:jit") == 0) {
+ executionMode = kEMJitCompiler;
+#endif
}
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;
@@ -572,19 +580,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";
@@ -603,16 +598,10 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
mOptions.add(opt);
//options[curOpt++].optionString = "-verbose:class";
-#ifdef CUSTOM_RUNTIME_HEAP_MAX
-#define __make_max_heap_opt(val) #val
-#define _make_max_heap_opt(val) "-Xmx" __make_max_heap_opt(val)
- opt.optionString = _make_max_heap_opt(CUSTOM_RUNTIME_HEAP_MAX);
-#undef __make_max_heap_opt
-#undef _make_max_heap_opt
-#else
- /* limit memory use to 16MB */
- opt.optionString = "-Xmx16m";
-#endif
+ strcpy(heapsizeOptsBuf, "-Xmx");
+ property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
+ //LOGI("Heap size: %s", heapsizeOptsBuf);
+ opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
/*
@@ -658,6 +647,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);
}
}
@@ -697,13 +690,87 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
//opt.optionString = "-verbose:jni";
//mOptions.add(opt);
}
+
+#if defined(WITH_JIT)
+ /* Minimal profile threshold to trigger JIT compilation */
+ char jitThresholdBuf[sizeof("-Xthreshold:") + PROPERTY_VALUE_MAX];
+ property_get("dalvik.vm.jit.threshold", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ strcpy(jitThresholdBuf, "-Xthreshold:");
+ strcat(jitThresholdBuf, propBuf);
+ opt.optionString = jitThresholdBuf;
+ mOptions.add(opt);
+ }
+
+ /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */
+ char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX];
+ property_get("dalvik.vm.jit.op", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ strcpy(jitOpBuf, "-Xjitop:");
+ strcat(jitOpBuf, propBuf);
+ opt.optionString = jitOpBuf;
+ mOptions.add(opt);
+ }
+
+ /*
+ * Reverse the polarity of dalvik.vm.jit.op and force interpreter-only
+ * for non-selected opcodes.
+ */
+ property_get("dalvik.vm.jit.includeop", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ opt.optionString = "-Xincludeselectedop";
+ mOptions.add(opt);
+ }
+
+ /* Force interpreter-only mode for selected methods */
+ char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX];
+ property_get("dalvik.vm.jit.method", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ strcpy(jitMethodBuf, "-Xjitmethod:");
+ strcat(jitMethodBuf, propBuf);
+ opt.optionString = jitMethodBuf;
+ mOptions.add(opt);
+ }
+
+ /*
+ * Reverse the polarity of dalvik.vm.jit.method and force interpreter-only
+ * for non-selected methods.
+ */
+ property_get("dalvik.vm.jit.includemethod", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ opt.optionString = "-Xincludeselectedmethod";
+ mOptions.add(opt);
+ }
+
+ /*
+ * Enable profile collection on JIT'ed code.
+ */
+ property_get("dalvik.vm.jit.profile", propBuf, "");
+ if (strlen(propBuf) > 0) {
+ opt.optionString = "-Xjitprofile";
+ mOptions.add(opt);
+ }
+#endif
+
if (executionMode == kEMIntPortable) {
opt.optionString = "-Xint:portable";
mOptions.add(opt);
} else if (executionMode == kEMIntFast) {
opt.optionString = "-Xint:fast";
mOptions.add(opt);
+#if defined(WITH_JIT)
+ } else if (executionMode == kEMJitCompiler) {
+ opt.optionString = "-Xint:jit";
+ mOptions.add(opt);
+#endif
}
+
+ 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";
@@ -771,11 +838,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.
*/
@@ -845,7 +962,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
bail:
free(slashClassName);
- free(stackTraceFile);
}
void AndroidRuntime::start()
@@ -1095,7 +1211,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),
@@ -1117,12 +1232,11 @@ 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_BluetoothService),
REG_JNI(register_android_server_BluetoothEventLoop),
REG_JNI(register_android_server_BluetoothA2dpService),
REG_JNI(register_android_message_digest_sha1),
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 3fb07a7..002d3db 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/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 1c2e055..dc72008 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -23,6 +23,7 @@
#include "SkGLCanvas.h"
#include "SkGraphics.h"
#include "SkImageRef_GlobalPool.h"
+#include "SkPorterDuff.h"
#include "SkShader.h"
#include "SkTemplates.h"
@@ -324,7 +325,7 @@ public:
static void drawColor__II(JNIEnv* env, jobject, SkCanvas* canvas,
jint color, SkPorterDuff::Mode mode) {
- canvas->drawColor(color, mode);
+ canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
}
static void drawPaint(JNIEnv* env, jobject, SkCanvas* canvas,
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index b6ec4a2..ebfb209 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -21,6 +21,7 @@
#include "SkColorFilter.h"
#include "SkColorMatrixFilter.h"
+#include "SkPorterDuff.h"
namespace android {
@@ -32,8 +33,9 @@ public:
}
static SkColorFilter* CreatePorterDuffFilter(JNIEnv* env, jobject,
- jint srcColor, SkPorterDuff::Mode porterDuffMode) {
- return SkColorFilter::CreatePorterDuffFilter(srcColor, porterDuffMode);
+ jint srcColor, SkPorterDuff::Mode mode) {
+ return SkColorFilter::CreateModeFilter(srcColor,
+ SkPorterDuff::ToXfermodeMode(mode));
}
static SkColorFilter* CreateLightingFilter(JNIEnv* env, jobject,
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index d1fe83e..6b7f045 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -48,6 +48,13 @@ static JMetricsID gFontMetrics_fieldID;
static jclass gFontMetricsInt_class;
static JMetricsID gFontMetricsInt_fieldID;
+static void defaultSettingsForAndroid(SkPaint* paint) {
+ // looks best we decided
+ paint->setHinting(SkPaint::kSlight_Hinting);
+ // utf16 is required for java
+ paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+}
+
class SkPaintGlue {
public:
@@ -57,8 +64,7 @@ public:
static SkPaint* init(JNIEnv* env, jobject clazz) {
SkPaint* obj = new SkPaint();
- // utf16 is required for java
- obj->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ defaultSettingsForAndroid(obj);
return obj;
}
@@ -69,8 +75,7 @@ public:
static void reset(JNIEnv* env, jobject clazz, SkPaint* obj) {
obj->reset();
- // utf16 is required for java
- obj->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ defaultSettingsForAndroid(obj);
}
static void assign(JNIEnv* env, jobject clazz, SkPaint* dst, const SkPaint* src) {
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/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 21dde63..238ece1 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -141,6 +141,25 @@ static SkTypeface* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath)
return SkTypeface::CreateFromFile(str.c_str());
}
+#define MIN_GAMMA (0.1f)
+#define MAX_GAMMA (10.0f)
+static float pinGamma(float gamma) {
+ if (gamma < MIN_GAMMA) {
+ gamma = MIN_GAMMA;
+ } else if (gamma > MAX_GAMMA) {
+ gamma = MAX_GAMMA;
+ }
+ return gamma;
+}
+
+extern void skia_set_text_gamma(float, float);
+
+static void Typeface_setGammaForText(JNIEnv* env, jobject, jfloat blackGamma,
+ jfloat whiteGamma) {
+ // Comment this out for release builds. This is only used during development
+ skia_set_text_gamma(pinGamma(blackGamma), pinGamma(whiteGamma));
+}
+
///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gTypefaceMethods[] = {
@@ -151,7 +170,8 @@ static JNINativeMethod gTypefaceMethods[] = {
{ "nativeCreateFromAsset", "(Landroid/content/res/AssetManager;Ljava/lang/String;)I",
(void*)Typeface_createFromAsset },
{ "nativeCreateFromFile", "(Ljava/lang/String;)I",
- (void*)Typeface_createFromFile }
+ (void*)Typeface_createFromFile },
+ { "setGammaForText", "(FF)V", (void*)Typeface_setGammaForText },
};
int register_android_graphics_Typeface(JNIEnv* env);
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 41044db..4041346 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -1,16 +1,16 @@
/**
** 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
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
**
- ** http://www.apache.org/licenses/LICENSE-2.0
+ ** http://www.apache.org/licenses/LICENSE-2.0
**
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -53,18 +53,18 @@ public:
MallocHelper() {
mData = 0;
}
-
+
~MallocHelper() {
if (mData != 0) {
free(mData);
}
}
-
+
void* alloc(size_t size) {
mData = malloc(size);
return mData;
}
-
+
private:
void* mData;
};
@@ -88,17 +88,17 @@ int visibilityTest(float* pWS, float* pPositions, int positionsLength,
int result = POLY_CLIP_OUT;
float* pTransformed = 0;
int transformedIndexCount = 0;
-
+
if ( indexCount < 3 ) {
return POLY_CLIP_OUT;
}
-
+
// Find out how many vertices we need to transform
// We transform every vertex between the min and max indices, inclusive.
// This is OK for the data sets we expect to use with this function, but
// for other loads it might be better to use a more sophisticated vertex
// cache of some sort.
-
+
int minIndex = 65536;
int maxIndex = -1;
for(int i = 0; i < indexCount; i++) {
@@ -110,18 +110,18 @@ int visibilityTest(float* pWS, float* pPositions, int positionsLength,
maxIndex = index;
}
}
-
+
if ( maxIndex * 3 > positionsLength) {
return -1;
}
-
+
transformedIndexCount = maxIndex - minIndex + 1;
pTransformed = (float*) mallocHelper.alloc(transformedIndexCount * 4 * sizeof(float));
-
+
if (pTransformed == 0 ) {
return -2;
}
-
+
// Transform the vertices
{
const float* pSrc = pPositions + 3 * minIndex;
@@ -130,9 +130,9 @@ int visibilityTest(float* pWS, float* pPositions, int positionsLength,
mx4transform(pSrc[0], pSrc[1], pSrc[2], 1.0f, pWS, pDst);
}
}
-
+
// Clip the triangles
-
+
Poly poly;
float* pDest = & poly.vert[0].sx;
for (int i = 0; i < indexCount; i += 3) {
@@ -166,14 +166,14 @@ public:
mEnv->ReleasePrimitiveArrayCritical(mRef, mBase, mReleaseParam);
}
}
-
+
// We seperate the bounds check from the initialization because we want to
// be able to bounds-check multiple arrays, and we can't throw an exception
// after we've called GetPrimitiveArrayCritical.
-
+
// Return true if the bounds check succeeded
// Else instruct the runtime to throw an exception
-
+
bool check() {
if ( ! mRef) {
mEnv->ThrowNew(gIAEClass, "array == null");
@@ -190,9 +190,9 @@ public:
}
return true;
}
-
+
// Bind the array.
-
+
void bind() {
mBase = (T*) mEnv->GetPrimitiveArrayCritical(mRef, (jboolean *) 0);
mData = mBase + mOffset;
@@ -201,10 +201,10 @@ public:
void commitChanges() {
mReleaseParam = 0;
}
-
+
T* mData;
int mLength;
-
+
private:
T* mBase;
JNIEnv* mEnv;
@@ -226,29 +226,29 @@ inline float distance2(float x, float y, float z) {
inline float distance(float x, float y, float z) {
return sqrtf(distance2(x, y, z));
}
-
+
static
void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
jfloatArray positions_ref, jint positionsOffset, jint positionsCount,
jfloatArray sphere_ref, jint sphereOffset) {
FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
FloatArrayHelper sphere(env, sphere_ref, sphereOffset, 4);
-
+
bool checkOK = positions.check() && sphere.check();
if (! checkOK) {
return;
}
-
+
positions.bind();
sphere.bind();
-
+
if ( positionsCount < 1 ) {
env->ThrowNew(gIAEClass, "positionsCount < 1");
return;
}
-
+
const float* pSrc = positions.mData;
-
+
// find bounding box
float x0 = *pSrc++;
float x1 = x0;
@@ -256,7 +256,7 @@ void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
float y1 = y0;
float z0 = *pSrc++;
float z1 = z0;
-
+
for(int i = 1; i < positionsCount; i++) {
{
float x = *pSrc++;
@@ -286,7 +286,7 @@ void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
}
}
}
-
+
// Because we know our input meshes fit pretty well into bounding boxes,
// just take the diagonal of the box as defining our sphere.
float* pSphere = sphere.mData;
@@ -297,7 +297,7 @@ void util_computeBoundingSphere(JNIEnv *env, jclass clazz,
*pSphere++ = y0 + dy * 0.5f;
*pSphere++ = z0 + dz * 0.5f;
*pSphere++ = distance(dx, dy, dz) * 0.5f;
-
+
sphere.commitChanges();
}
@@ -344,7 +344,7 @@ static void computeFrustum(const float* m, float* f) {
normalizePlane(f);
f+= 4;
- // left
+ // left
f[0] = m3 + m[0];
f[1] = m7 + m[4];
f[2] = m11 + m[8];
@@ -396,20 +396,20 @@ int util_frustumCullSpheres(JNIEnv *env, jclass clazz,
FloatArrayHelper mvp(env, mvp_ref, mvpOffset, 16);
FloatArrayHelper spheres(env, spheres_ref, spheresOffset, spheresCount * 4);
IntArrayHelper results(env, results_ref, resultsOffset, resultsCapacity);
-
+
bool initializedOK = mvp.check() && spheres.check() && results.check();
if (! initializedOK) {
return -1;
}
-
+
mvp.bind();
spheres.bind();
results.bind();
-
+
computeFrustum(mvp.mData, frustum);
-
+
// Cull the spheres
-
+
pSphere = spheres.mData;
pResults = results.mData;
outputCount = 0;
@@ -436,27 +436,27 @@ int util_visibilityTest(JNIEnv *env, jclass clazz,
jfloatArray ws_ref, jint wsOffset,
jfloatArray positions_ref, jint positionsOffset,
jcharArray indices_ref, jint indicesOffset, jint indexCount) {
-
+
FloatArrayHelper ws(env, ws_ref, wsOffset, 16);
FloatArrayHelper positions(env, positions_ref, positionsOffset, 0);
UnsignedShortArrayHelper indices(env, indices_ref, indicesOffset, 0);
-
+
bool checkOK = ws.check() && positions.check() && indices.check();
if (! checkOK) {
// Return value will be ignored, because an exception has been thrown.
return -1;
}
-
+
if (indices.mLength < indexCount) {
env->ThrowNew(gIAEClass, "length < offset + indexCount");
// Return value will be ignored, because an exception has been thrown.
return -1;
}
-
+
ws.bind();
positions.bind();
indices.bind();
-
+
return visibilityTest(ws.mData,
positions.mData, positions.mLength,
indices.mData, indexCount);
@@ -496,19 +496,19 @@ void util_multiplyMM(JNIEnv *env, jclass clazz,
FloatArrayHelper resultMat(env, result_ref, resultOffset, 16);
FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 16);
-
+
bool checkOK = resultMat.check() && lhs.check() && rhs.check();
-
+
if ( !checkOK ) {
return;
}
-
+
resultMat.bind();
lhs.bind();
rhs.bind();
-
+
multiplyMM(resultMat.mData, lhs.mData, rhs.mData);
-
+
resultMat.commitChanges();
}
@@ -527,19 +527,19 @@ void util_multiplyMV(JNIEnv *env, jclass clazz,
FloatArrayHelper resultV(env, result_ref, resultOffset, 4);
FloatArrayHelper lhs(env, lhs_ref, lhsOffset, 16);
FloatArrayHelper rhs(env, rhs_ref, rhsOffset, 4);
-
+
bool checkOK = resultV.check() && lhs.check() && rhs.check();
-
+
if ( !checkOK ) {
return;
}
-
+
resultV.bind();
lhs.bind();
rhs.bind();
-
+
multiplyMV(resultV.mData, lhs.mData, rhs.mData);
-
+
resultV.commitChanges();
}
@@ -550,7 +550,7 @@ static jfieldID nativeBitmapID = 0;
void nativeUtilsClassInit(JNIEnv *env, jclass clazz)
{
jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
- nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
+ nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
}
static int checkFormat(SkBitmap::Config config, int format, int type)
@@ -653,7 +653,7 @@ static jint util_texImage2D(JNIEnv *env, jclass clazz,
}
int err = checkFormat(config, internalformat, type);
if (err)
- return err;
+ return err;
bitmap.lockPixels();
const int w = bitmap.width();
const int h = bitmap.height();
@@ -665,14 +665,15 @@ static jint util_texImage2D(JNIEnv *env, jclass clazz,
}
const size_t size = bitmap.getSize();
const size_t palette_size = 256*sizeof(SkPMColor);
- void* const data = malloc(size + palette_size);
+ const size_t imageSize = size + palette_size;
+ void* const data = malloc(imageSize);
if (data) {
void* const pixels = (char*)data + palette_size;
SkColorTable* ctable = bitmap.getColorTable();
memcpy(data, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
memcpy(pixels, p, size);
ctable->unlockColors(false);
- glCompressedTexImage2D(target, level, internalformat, w, h, border, 0, data);
+ glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data);
free(data);
} else {
err = -1;
@@ -700,7 +701,7 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
}
int err = checkFormat(config, format, type);
if (err)
- return err;
+ return err;
bitmap.lockPixels();
const int w = bitmap.width();
const int h = bitmap.height();
@@ -723,22 +724,22 @@ lookupClasses(JNIEnv* env) {
}
static JNINativeMethod gMatrixMethods[] = {
- { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
- { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
+ { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
+ { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
};
static JNINativeMethod gVisiblityMethods[] = {
- { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
+ { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
{ "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
- { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
+ { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
};
static JNINativeMethod gUtilsMethods[] = {
{"nativeClassInit", "()V", (void*)nativeUtilsClassInit },
- { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
- { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
- { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
- { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
+ { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
+ { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
+ { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
+ { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
};
typedef struct _ClassRegistrationInfo {
diff --git a/core/jni/android_bluetooth_BluetoothSocket.cpp b/core/jni/android_bluetooth_BluetoothSocket.cpp
new file mode 100644
index 0000000..0aeaadc
--- /dev/null
+++ b/core/jni/android_bluetooth_BluetoothSocket.cpp
@@ -0,0 +1,534 @@
+/*
+ * 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 const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
+
+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;
+ int sndbuf;
+ 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(RFCOMM_LM) failed, throwing");
+ jniThrowIOException(env, errno);
+ return;
+ }
+ }
+
+ if (type == TYPE_RFCOMM) {
+ sndbuf = RFCOMM_SO_SNDBUF;
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
+ LOGV("setsockopt(SO_SNDBUF) 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)) {
+ LOGV("...bind(%d) gave errno %d", s->fd, errno);
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ if (listen(s->fd, 1)) {
+ LOGV("...listen(%d) gave errno %d", s->fd, errno);
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ LOGV("...bindListenNative(%d) success", s->fd);
+
+ 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 73b8efd..0000000
--- a/core/jni/android_bluetooth_Database.cpp
+++ /dev/null
@@ -1,184 +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);
- }
- dbus_connection_set_exit_on_disconnect(conn, FALSE);
- }
-#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..343fa53 100644
--- a/core/jni/android_bluetooth_common.cpp
+++ b/core/jni/android_bluetooth_common.cpp
@@ -36,6 +36,43 @@
namespace android {
#ifdef HAVE_BLUETOOTH
+
+static Properties remote_device_properties[] = {
+ {"Address", DBUS_TYPE_STRING},
+ {"Name", DBUS_TYPE_STRING},
+ {"Icon", DBUS_TYPE_STRING},
+ {"Class", DBUS_TYPE_UINT32},
+ {"UUIDs", DBUS_TYPE_ARRAY},
+ {"Paired", DBUS_TYPE_BOOLEAN},
+ {"Connected", DBUS_TYPE_BOOLEAN},
+ {"Trusted", DBUS_TYPE_BOOLEAN},
+ {"Alias", DBUS_TYPE_STRING},
+ {"Nodes", DBUS_TYPE_ARRAY},
+ {"Adapter", DBUS_TYPE_OBJECT_PATH},
+ {"LegacyPairing", DBUS_TYPE_BOOLEAN},
+ {"RSSI", DBUS_TYPE_INT16},
+ {"TX", DBUS_TYPE_UINT32}
+};
+
+static Properties adapter_properties[] = {
+ {"Address", DBUS_TYPE_STRING},
+ {"Name", DBUS_TYPE_STRING},
+ {"Class", DBUS_TYPE_UINT32},
+ {"Powered", DBUS_TYPE_BOOLEAN},
+ {"Discoverable", DBUS_TYPE_BOOLEAN},
+ {"DiscoverableTimeout", DBUS_TYPE_UINT32},
+ {"Pairable", DBUS_TYPE_BOOLEAN},
+ {"PairableTimeout", DBUS_TYPE_UINT32},
+ {"Discovering", DBUS_TYPE_BOOLEAN},
+ {"Devices", DBUS_TYPE_ARRAY},
+};
+
+typedef union {
+ char *str_val;
+ int int_val;
+ char **array_val;
+} property_value;
+
jfieldID get_field(JNIEnv *env, jclass clazz, const char *member,
const char *mtype) {
jfieldID field = env->GetFieldID(clazz, member, mtype);
@@ -332,6 +369,44 @@ jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply) {
return ret;
}
+static void set_object_array_element(JNIEnv *env, jobjectArray strArray,
+ const char *value, int index) {
+ jstring obj;
+ obj = env->NewStringUTF(value);
+ env->SetObjectArrayElement(strArray, index, obj);
+ env->DeleteLocalRef(obj);
+}
+
+jobjectArray dbus_returns_array_of_object_path(JNIEnv *env,
+ DBusMessage *reply) {
+
+ DBusError err;
+ char **list;
+ int i, len;
+ jobjectArray strArray = NULL;
+
+ dbus_error_init(&err);
+ if (dbus_message_get_args (reply,
+ &err,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
+ &list, &len,
+ DBUS_TYPE_INVALID)) {
+ jclass stringClass;
+ jstring classNameStr;
+
+ stringClass = env->FindClass("java/lang/String");
+ strArray = env->NewObjectArray(len, stringClass, NULL);
+
+ for (i = 0; i < len; i++)
+ set_object_array_element(env, strArray, list[i], i);
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ }
+
+ dbus_message_unref(reply);
+ return strArray;
+}
+
jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply) {
DBusError err;
@@ -353,11 +428,8 @@ jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply) {
stringClass = env->FindClass("java/lang/String");
strArray = env->NewObjectArray(len, stringClass, NULL);
- for (i = 0; i < len; i++) {
- //LOGV("%s: array[%d] = [%s]", __FUNCTION__, i, list[i]);
- env->SetObjectArrayElement(strArray, i,
- env->NewStringUTF(list[i]));
- }
+ for (i = 0; i < len; i++)
+ set_object_array_element(env, strArray, list[i], i);
} else {
LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
}
@@ -390,17 +462,263 @@ jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply) {
return byteArray;
}
-void get_bdaddr(const char *str, bdaddr_t *ba) {
+void append_variant(DBusMessageIter *iter, int type, void *val)
+{
+ DBusMessageIter value_iter;
+ char var_type[2] = { type, '\0'};
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, var_type, &value_iter);
+ dbus_message_iter_append_basic(&value_iter, type, val);
+ dbus_message_iter_close_container(iter, &value_iter);
+}
+
+int get_property(DBusMessageIter iter, Properties *properties,
+ int max_num_properties, int *prop_index, property_value *value, int *len) {
+ DBusMessageIter prop_val, array_val_iter;
+ char *property = NULL;
+ uint32_t array_type;
+ char *str_val;
+ int i, j, type, int_val;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return -1;
+ dbus_message_iter_get_basic(&iter, &property);
+ if (!dbus_message_iter_next(&iter))
+ return -1;
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return -1;
+ for (i = 0; i < max_num_properties; i++) {
+ if (!strncmp(property, properties[i].name, strlen(property)))
+ break;
+ }
+ *prop_index = i;
+ if (i == max_num_properties)
+ return -1;
+
+ dbus_message_iter_recurse(&iter, &prop_val);
+ type = properties[*prop_index].type;
+ if (dbus_message_iter_get_arg_type(&prop_val) != type) {
+ LOGE("Property type mismatch in get_property: %d, expected:%d, index:%d",
+ dbus_message_iter_get_arg_type(&prop_val), type, *prop_index);
+ return -1;
+ }
+
+ switch(type) {
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ dbus_message_iter_get_basic(&prop_val, &value->str_val);
+ *len = 1;
+ break;
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_BOOLEAN:
+ dbus_message_iter_get_basic(&prop_val, &int_val);
+ value->int_val = int_val;
+ *len = 1;
+ break;
+ case DBUS_TYPE_ARRAY:
+ dbus_message_iter_recurse(&prop_val, &array_val_iter);
+ array_type = dbus_message_iter_get_arg_type(&array_val_iter);
+ *len = 0;
+ value->array_val = NULL;
+ if (array_type == DBUS_TYPE_OBJECT_PATH ||
+ array_type == DBUS_TYPE_STRING){
+ j = 0;
+ do {
+ j ++;
+ } while(dbus_message_iter_next(&array_val_iter));
+ dbus_message_iter_recurse(&prop_val, &array_val_iter);
+ // Allocate an array of char *
+ *len = j;
+ char **tmp = (char **)malloc(sizeof(char *) * *len);
+ if (!tmp)
+ return -1;
+ j = 0;
+ do {
+ dbus_message_iter_get_basic(&array_val_iter, &tmp[j]);
+ j ++;
+ } while(dbus_message_iter_next(&array_val_iter));
+ value->array_val = tmp;
+ }
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+void create_prop_array(JNIEnv *env, jobjectArray strArray, Properties *property,
+ property_value *value, int len, int *array_index ) {
+ char **prop_val = NULL;
+ char buf[32] = {'\0'}, buf1[32] = {'\0'};
+ int i;
+
+ char *name = property->name;
+ int prop_type = property->type;
+
+ set_object_array_element(env, strArray, name, *array_index);
+ *array_index += 1;
+
+ if (prop_type == DBUS_TYPE_UINT32 || prop_type == DBUS_TYPE_INT16) {
+ sprintf(buf, "%d", value->int_val);
+ set_object_array_element(env, strArray, buf, *array_index);
+ *array_index += 1;
+ } else if (prop_type == DBUS_TYPE_BOOLEAN) {
+ sprintf(buf, "%s", value->int_val ? "true" : "false");
+
+ set_object_array_element(env, strArray, buf, *array_index);
+ *array_index += 1;
+ } else if (prop_type == DBUS_TYPE_ARRAY) {
+ // Write the length first
+ sprintf(buf1, "%d", len);
+ set_object_array_element(env, strArray, buf1, *array_index);
+ *array_index += 1;
+
+ prop_val = value->array_val;
+ for (i = 0; i < len; i++) {
+ set_object_array_element(env, strArray, prop_val[i], *array_index);
+ *array_index += 1;
+ }
+ } else {
+ set_object_array_element(env, strArray, (const char *) value->str_val, *array_index);
+ *array_index += 1;
+ }
+}
+
+jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
+ const int max_num_properties) {
+ DBusMessageIter dict_entry, dict;
+ jobjectArray strArray = NULL;
+ property_value value;
+ int i, size = 0,array_index = 0;
+ int len = 0, prop_type = DBUS_TYPE_INVALID, prop_index = -1, type;
+ struct {
+ property_value value;
+ int len;
+ bool used;
+ } values[max_num_properties];
+ int t, j;
+
+ jclass stringClass = env->FindClass("java/lang/String");
+ DBusError err;
+ dbus_error_init(&err);
+
+ for (i = 0; i < max_num_properties; i++) {
+ values[i].used = false;
+ }
+
+ if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ goto failure;
+ dbus_message_iter_recurse(iter, &dict);
+ do {
+ len = 0;
+ if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
+ goto failure;
+ dbus_message_iter_recurse(&dict, &dict_entry);
+
+ if (!get_property(dict_entry, properties, max_num_properties, &prop_index,
+ &value, &len)) {
+ size += 2;
+ if (properties[prop_index].type == DBUS_TYPE_ARRAY)
+ size += len;
+ values[prop_index].value = value;
+ values[prop_index].len = len;
+ values[prop_index].used = true;
+ } else {
+ goto failure;
+ }
+ } while(dbus_message_iter_next(&dict));
+
+ strArray = env->NewObjectArray(size, stringClass, NULL);
+
+ for (i = 0; i < max_num_properties; i++) {
+ if (values[i].used) {
+ create_prop_array(env, strArray, &properties[i], &values[i].value, values[i].len,
+ &array_index);
+
+ if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used
+ && values[i].value.array_val != NULL)
+ free(values[i].value.array_val);
+ }
+
+ }
+ return strArray;
+
+failure:
+ if (dbus_error_is_set(&err))
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ for (i = 0; i < max_num_properties; i++)
+ if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used == true
+ && values[i].value.array_val != NULL)
+ free(values[i].value.array_val);
+ return NULL;
+}
+
+jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
+ Properties *properties, int max_num_properties) {
+ DBusMessageIter iter;
+ DBusError err;
+ jobjectArray strArray = NULL;
+ jclass stringClass= env->FindClass("java/lang/String");
+ int len = 0, prop_index = -1;
+ int array_index = 0, size = 0;
+ property_value value;
+
+ dbus_error_init(&err);
+ if (!dbus_message_iter_init(msg, &iter))
+ goto failure;
+
+ if (!get_property(iter, properties, max_num_properties,
+ &prop_index, &value, &len)) {
+ size += 2;
+ if (properties[prop_index].type == DBUS_TYPE_ARRAY)
+ size += len;
+ strArray = env->NewObjectArray(size, stringClass, NULL);
+
+ create_prop_array(env, strArray, &properties[prop_index],
+ &value, len, &array_index);
+
+ if (properties[prop_index].type == DBUS_TYPE_ARRAY && value.array_val != NULL)
+ free(value.array_val);
+
+ return strArray;
+ }
+failure:
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return NULL;
+}
+
+jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg) {
+ return parse_property_change(env, msg, (Properties *) &adapter_properties,
+ sizeof(adapter_properties) / sizeof(Properties));
+}
+
+jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg) {
+ return parse_property_change(env, msg, (Properties *) &remote_device_properties,
+ sizeof(remote_device_properties) / sizeof(Properties));
+}
+
+jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter) {
+ return parse_properties(env, iter, (Properties *) &adapter_properties,
+ sizeof(adapter_properties) / sizeof(Properties));
+}
+
+jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter) {
+ return parse_properties(env, iter, (Properties *) &remote_device_properties,
+ sizeof(remote_device_properties) / sizeof(Properties));
+}
+
+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..ef9b66b 100644
--- a/core/jni/android_bluetooth_common.h
+++ b/core/jni/android_bluetooth_common.h
@@ -68,6 +68,7 @@ jfieldID get_field(JNIEnv *env,
struct event_loop_native_data_t {
DBusConnection *conn;
+ const char *adapter;
/* protects the thread */
pthread_mutex_t thread_mutex;
@@ -89,6 +90,12 @@ struct event_loop_native_data_t {
jobject me;
};
+struct _Properties {
+ char name[32];
+ int type;
+};
+typedef struct _Properties Properties;
+
dbus_bool_t dbus_func_args_async(JNIEnv *env,
DBusConnection *conn,
int timeout_ms,
@@ -142,9 +149,19 @@ jint dbus_returns_uint32(JNIEnv *env, DBusMessage *reply);
jstring dbus_returns_string(JNIEnv *env, DBusMessage *reply);
jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply);
jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply);
+jobjectArray dbus_returns_array_of_object_path(JNIEnv *env, DBusMessage *reply);
jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply);
-void get_bdaddr(const char *str, bdaddr_t *ba);
+jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
+ const int max_num_properties);
+jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
+ Properties *properties, int max_num_properties);
+jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter);
+jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter);
+jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg);
+jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg);
+void append_variant(DBusMessageIter *iter, int type, void *val);
+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_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
index 7d6e24f..4c213a3 100644
--- a/core/jni/android_emoji_EmojiFactory.cpp
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -197,8 +197,11 @@ static jobject android_emoji_EmojiFactory_getBitmapFromAndroidPua(
static void android_emoji_EmojiFactory_destructor(
JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ /*
+ // Must not delete this object!!
EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
delete factory;
+ */
}
static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis(
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 9053468..8a312d9 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_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index bf0bd65..c329602 100755
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -16,33 +16,49 @@
#define LOG_TAG "GpsLocationProvider"
+//#define LOG_NDDEBUG 0
+
#include "JNIHelp.h"
#include "jni.h"
#include "hardware_legacy/gps.h"
+#include "hardware_legacy/gps_ni.h"
#include "utils/Log.h"
#include "utils/misc.h"
#include <string.h>
#include <pthread.h>
-
static pthread_mutex_t sEventMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER;
static jmethodID method_reportLocation;
static jmethodID method_reportStatus;
static jmethodID method_reportSvStatus;
static jmethodID method_reportAGpsStatus;
+static jmethodID method_reportNmea;
static jmethodID method_xtraDownloadRequest;
+static jmethodID method_reportNiNotification;
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
static const AGpsInterface* sAGpsInterface = NULL;
+static const GpsNiInterface* sGpsNiInterface = NULL;
// data written to by GPS callbacks
static GpsLocation sGpsLocation;
static GpsStatus sGpsStatus;
static GpsSvStatus sGpsSvStatus;
static AGpsStatus sAGpsStatus;
+static GpsNiNotification sGpsNiNotification;
+
+// buffer for NMEA data
+#define NMEA_SENTENCE_LENGTH 100
+#define NMEA_SENTENCE_COUNT 40
+struct NmeaSentence {
+ GpsUtcTime timestamp;
+ char nmea[NMEA_SENTENCE_LENGTH];
+};
+static NmeaSentence sNmeaBuffer[NMEA_SENTENCE_LENGTH];
+static int mNmeaSentenceCount = 0;
// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event
// and android_location_GpsLocationProvider_read_status
@@ -50,6 +66,8 @@ static GpsLocation sGpsLocationCopy;
static GpsStatus sGpsStatusCopy;
static GpsSvStatus sGpsSvStatusCopy;
static AGpsStatus sAGpsStatusCopy;
+static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_LENGTH];
+static GpsNiNotification sGpsNiNotificationCopy;
enum CallbackType {
kLocation = 1,
@@ -58,6 +76,8 @@ enum CallbackType {
kAGpsStatus = 8,
kXtraDownloadRequest = 16,
kDisableRequest = 32,
+ kNmeaAvailable = 64,
+ kNiNotification = 128,
};
static int sPendingCallbacks;
@@ -96,6 +116,30 @@ static void sv_status_callback(GpsSvStatus* sv_status)
pthread_mutex_unlock(&sEventMutex);
}
+static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
+{
+ pthread_mutex_lock(&sEventMutex);
+
+ if (length >= NMEA_SENTENCE_LENGTH) {
+ LOGE("NMEA data too long in nmea_callback (length = %d)\n", length);
+ length = NMEA_SENTENCE_LENGTH - 1;
+ }
+ if (mNmeaSentenceCount >= NMEA_SENTENCE_COUNT) {
+ LOGE("NMEA data overflowed buffer\n");
+ pthread_mutex_unlock(&sEventMutex);
+ return;
+ }
+
+ sPendingCallbacks |= kNmeaAvailable;
+ sNmeaBuffer[mNmeaSentenceCount].timestamp = timestamp;
+ memcpy(sNmeaBuffer[mNmeaSentenceCount].nmea, nmea, length);
+ sNmeaBuffer[mNmeaSentenceCount].nmea[length] = 0;
+ mNmeaSentenceCount++;
+
+ pthread_cond_signal(&sEventCond);
+ pthread_mutex_unlock(&sEventMutex);
+}
+
static void agps_status_callback(AGpsStatus* agps_status)
{
pthread_mutex_lock(&sEventMutex);
@@ -111,6 +155,7 @@ GpsCallbacks sGpsCallbacks = {
location_callback,
status_callback,
sv_status_callback,
+ nmea_callback
};
static void
@@ -122,6 +167,20 @@ download_request_callback()
pthread_mutex_unlock(&sEventMutex);
}
+static void
+gps_ni_notify_callback(GpsNiNotification *notification)
+{
+ LOGD("gps_ni_notify_callback: notif=%d", notification->notification_id);
+
+ pthread_mutex_lock(&sEventMutex);
+
+ sPendingCallbacks |= kNiNotification;
+ memcpy(&sGpsNiNotification, notification, sizeof(GpsNiNotification));
+
+ pthread_cond_signal(&sEventCond);
+ pthread_mutex_unlock(&sEventMutex);
+}
+
GpsXtraCallbacks sGpsXtraCallbacks = {
download_request_callback,
};
@@ -130,12 +189,18 @@ AGpsCallbacks sAGpsCallbacks = {
agps_status_callback,
};
+GpsNiCallbacks sGpsNiCallbacks = {
+ gps_ni_notify_callback,
+};
+
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
+ method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(IJ)V");
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
+ method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
}
static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
@@ -155,6 +220,12 @@ static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject o
sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
if (sAGpsInterface)
sAGpsInterface->init(&sAGpsCallbacks);
+
+ if (!sGpsNiInterface)
+ sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+ if (sGpsNiInterface)
+ sGpsNiInterface->init(&sGpsNiCallbacks);
+
return true;
}
@@ -171,7 +242,7 @@ static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject ob
sGpsInterface->cleanup();
}
-static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode,
+static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode,
jboolean singleFix, jint fixFrequency)
{
int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency));
@@ -196,45 +267,78 @@ static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, job
{
pthread_mutex_lock(&sEventMutex);
pthread_cond_wait(&sEventCond, &sEventMutex);
-
+
// copy and clear the callback flags
int pendingCallbacks = sPendingCallbacks;
sPendingCallbacks = 0;
+ int nmeaSentenceCount = mNmeaSentenceCount;
+ mNmeaSentenceCount = 0;
// copy everything and unlock the mutex before calling into Java code to avoid the possibility
// of timeouts in the GPS engine.
- memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
- memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
- memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
- memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
+ if (pendingCallbacks & kLocation)
+ memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
+ if (pendingCallbacks & kStatus)
+ memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
+ if (pendingCallbacks & kSvStatus)
+ memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
+ if (pendingCallbacks & kAGpsStatus)
+ memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
+ if (pendingCallbacks & kNmeaAvailable)
+ memcpy(&sNmeaBufferCopy, &sNmeaBuffer, nmeaSentenceCount * sizeof(sNmeaBuffer[0]));
+ if (pendingCallbacks & kNiNotification)
+ memcpy(&sGpsNiNotificationCopy, &sGpsNiNotification, sizeof(sGpsNiNotificationCopy));
pthread_mutex_unlock(&sEventMutex);
- if (pendingCallbacks & kLocation) {
+ if (pendingCallbacks & kLocation) {
env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags,
(jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude,
- (jdouble)sGpsLocationCopy.altitude,
- (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing,
+ (jdouble)sGpsLocationCopy.altitude,
+ (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing,
(jfloat)sGpsLocationCopy.accuracy, (jlong)sGpsLocationCopy.timestamp);
}
if (pendingCallbacks & kStatus) {
env->CallVoidMethod(obj, method_reportStatus, sGpsStatusCopy.status);
- }
+ }
if (pendingCallbacks & kSvStatus) {
env->CallVoidMethod(obj, method_reportSvStatus);
}
if (pendingCallbacks & kAGpsStatus) {
env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status);
}
- if (pendingCallbacks & kXtraDownloadRequest) {
+ if (pendingCallbacks & kNmeaAvailable) {
+ for (int i = 0; i < nmeaSentenceCount; i++) {
+ env->CallVoidMethod(obj, method_reportNmea, i, sNmeaBuffer[i].timestamp);
+ }
+ }
+ if (pendingCallbacks & kXtraDownloadRequest) {
env->CallVoidMethod(obj, method_xtraDownloadRequest);
}
if (pendingCallbacks & kDisableRequest) {
// don't need to do anything - we are just poking so wait_for_event will return.
}
+ if (pendingCallbacks & kNiNotification) {
+ LOGD("android_location_GpsLocationProvider_wait_for_event: sent notification callback.");
+ jstring reqId = env->NewStringUTF(sGpsNiNotificationCopy.requestor_id);
+ jstring text = env->NewStringUTF(sGpsNiNotificationCopy.text);
+ jstring extras = env->NewStringUTF(sGpsNiNotificationCopy.extras);
+ env->CallVoidMethod(obj, method_reportNiNotification,
+ sGpsNiNotificationCopy.notification_id,
+ sGpsNiNotificationCopy.ni_type,
+ sGpsNiNotificationCopy.notify_flags,
+ sGpsNiNotificationCopy.timeout,
+ sGpsNiNotificationCopy.default_response,
+ reqId,
+ text,
+ sGpsNiNotificationCopy.requestor_id_encoding,
+ sGpsNiNotificationCopy.text_encoding,
+ extras
+ );
+ }
}
-static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
- jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
+static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
+ jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
jintArray maskArray)
{
// this should only be called from within a call to reportStatus, so we don't need to lock here
@@ -264,6 +368,21 @@ static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, job
return num_svs;
}
+static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jint index, jbyteArray nmeaArray, jint buffer_size)
+{
+ // this should only be called from within a call to reportStatus, so we don't need to lock here
+
+ jbyte* nmea = env->GetByteArrayElements(nmeaArray, 0);
+
+ int length = strlen(sNmeaBuffer[index].nmea);
+ if (length > buffer_size)
+ length = buffer_size;
+ memcpy(nmea, sNmeaBuffer[index].nmea, length);
+
+ env->ReleaseByteArrayElements(nmeaArray, nmea, 0);
+ return length;
+}
+
static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time,
jlong timeReference, jint uncertainty)
{
@@ -291,7 +410,7 @@ static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env,
return (sGpsXtraInterface != NULL);
}
-static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
+static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
jbyteArray data, jint length)
{
jbyte* bytes = env->GetByteArrayElements(data, 0);
@@ -348,6 +467,16 @@ static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jo
}
}
+static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
+ jint notifId, jint response)
+{
+ if (!sGpsNiInterface)
+ sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+ if (sGpsNiInterface) {
+ sGpsNiInterface->respond(notifId, response);
+ }
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
@@ -360,6 +489,7 @@ static JNINativeMethod sMethods[] = {
{"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
{"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
{"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
+ {"native_read_nmea", "(I[BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
{"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
{"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
{"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
@@ -368,6 +498,7 @@ static JNINativeMethod sMethods[] = {
{"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
{"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
{"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
+ {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
};
int register_android_location_GpsLocationProvider(JNIEnv* env)
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 44a9e8c..0be996d 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -28,8 +28,8 @@
#include "android_runtime/AndroidRuntime.h"
#include "utils/Log.h"
-#include "media/AudioSystem.h"
#include "media/AudioRecord.h"
+#include "media/mediarecorder.h"
// ----------------------------------------------------------------------------
@@ -62,7 +62,7 @@ struct audiorecord_callback_cookie {
#define AUDIORECORD_ERROR_BAD_VALUE -2
#define AUDIORECORD_ERROR_INVALID_OPERATION -3
#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -16
-#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT -17
+#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18
#define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE -19
#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -20
@@ -122,17 +122,18 @@ static void recorderCallback(int event, void* user, void *info) {
// ----------------------------------------------------------------------------
static int
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
- jint source, jint sampleRateInHertz, jint nbChannels,
+ jint source, jint sampleRateInHertz, jint channels,
jint audioFormat, jint buffSizeInBytes)
{
//LOGV(">> Entering android_media_AudioRecord_setup");
- //LOGV("sampleRate=%d, audioFormat=%d, nbChannels=%d, buffSizeInBytes=%d",
- // sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+ //LOGV("sampleRate=%d, audioFormat=%d, channels=%x, buffSizeInBytes=%d",
+ // sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
- if ((nbChannels == 0) || (nbChannels > 2)) {
+ if (!AudioSystem::isInputChannel(channels)) {
LOGE("Error creating AudioRecord: channel count is not 1 or 2.");
- return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT;
+ return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
}
+ uint32_t nbChannels = AudioSystem::popCount(channels);
// compare the format against the Java constants
if ((audioFormat != javaAudioRecordFields.PCM16)
@@ -152,12 +153,7 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
int frameSize = nbChannels * bytesPerSample;
size_t frameCount = buffSizeInBytes / frameSize;
- // convert and check input source value
- // input_source values defined in AudioRecord.h are equal to
- // JAVA MediaRecord.AudioSource values minus 1.
- AudioRecord::input_source arSource = (AudioRecord::input_source)(source - 1);
- if (arSource < AudioRecord::DEFAULT_INPUT ||
- arSource >= AudioRecord::NUM_INPUT_SOURCES) {
+ if (source >= AUDIO_SOURCE_LIST_END) {
LOGE("Error creating AudioRecord: unknown source.");
return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
}
@@ -184,10 +180,10 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
// we use a weak reference so the AudioRecord object can be garbage collected.
lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
- lpRecorder->set(arSource,
+ lpRecorder->set(source,
sampleRateInHertz,
format, // word length, PCM
- nbChannels,
+ channels,
frameCount,
0, // flags
recorderCallback,// callback_t
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 692610e..3d8d296 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -50,25 +50,6 @@ static int check_AudioSystem_Command(status_t status)
}
static int
-android_media_AudioSystem_setVolume(JNIEnv *env, jobject clazz, jint type, jint volume)
-{
- LOGV("setVolume(%d)", int(volume));
-
- return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
-}
-
-static int
-android_media_AudioSystem_getVolume(JNIEnv *env, jobject clazz, jint type)
-{
- float v;
- int v_int = -1;
- if (AudioSystem::getStreamVolume(int(type), &v) == NO_ERROR) {
- v_int = AudioSystem::logToLinear(v);
- }
- return v_int;
-}
-
-static int
android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
{
return check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
@@ -82,34 +63,6 @@ android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
return state;
}
-static int
-android_media_AudioSystem_setRouting(JNIEnv *env, jobject clazz, jint mode, jint routes, jint mask)
-{
- return check_AudioSystem_Command(AudioSystem::setRouting(mode, uint32_t(routes), uint32_t(mask)));
-}
-
-static jint
-android_media_AudioSystem_getRouting(JNIEnv *env, jobject clazz, jint mode)
-{
- uint32_t routes = -1;
- AudioSystem::getRouting(mode, &routes);
- return jint(routes);
-}
-
-static int
-android_media_AudioSystem_setMode(JNIEnv *env, jobject clazz, jint mode)
-{
- return check_AudioSystem_Command(AudioSystem::setMode(mode));
-}
-
-static jint
-android_media_AudioSystem_getMode(JNIEnv *env, jobject clazz)
-{
- int mode = AudioSystem::MODE_INVALID;
- AudioSystem::getMode(&mode);
- return jint(mode);
-}
-
static jboolean
android_media_AudioSystem_isMusicActive(JNIEnv *env, jobject thiz)
{
@@ -118,16 +71,29 @@ android_media_AudioSystem_isMusicActive(JNIEnv *env, jobject thiz)
return state;
}
-// Temporary interface, do not use
-// TODO: Replace with a more generic key:value get/set mechanism
-static void
-android_media_AudioSystem_setParameter(JNIEnv *env, jobject thiz, jstring key, jstring value)
+static int
+android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
{
- const char *c_key = env->GetStringUTFChars(key, NULL);
- const char *c_value = env->GetStringUTFChars(value, NULL);
- AudioSystem::setParameter(c_key, c_value);
- env->ReleaseStringUTFChars(key, c_key);
- env->ReleaseStringUTFChars(value, c_value);
+ const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
+ String8 c_keyValuePairs8;
+ if (keyValuePairs) {
+ c_keyValuePairs8 = String8(c_keyValuePairs, env->GetStringLength(keyValuePairs));
+ env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
+ }
+ int status = check_AudioSystem_Command(AudioSystem::setParameters(0, c_keyValuePairs8));
+ return status;
+}
+
+static jstring
+android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
+{
+ const jchar* c_keys = env->GetStringCritical(keys, 0);
+ String8 c_keys8;
+ if (keys) {
+ c_keys8 = String8(c_keys, env->GetStringLength(keys));
+ env->ReleaseStringCritical(keys, c_keys);
+ }
+ return env->NewStringUTF(AudioSystem::getParameters(0, c_keys8).string());
}
void android_media_AudioSystem_error_callback(status_t err)
@@ -152,19 +118,93 @@ void android_media_AudioSystem_error_callback(status_t err)
env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), error);
}
+static int
+android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
+{
+ const char *c_address = env->GetStringUTFChars(device_address, NULL);
+ int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <AudioSystem::audio_devices>(device),
+ static_cast <AudioSystem::device_connection_state>(state),
+ c_address));
+ env->ReleaseStringUTFChars(device_address, c_address);
+ return status;
+}
+
+static int
+android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
+{
+ const char *c_address = env->GetStringUTFChars(device_address, NULL);
+ int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <AudioSystem::audio_devices>(device),
+ c_address));
+ env->ReleaseStringUTFChars(device_address, c_address);
+ return state;
+}
+
+static int
+android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
+{
+ return check_AudioSystem_Command(AudioSystem::setPhoneState(state));
+}
+
+static int
+android_media_AudioSystem_setRingerMode(JNIEnv *env, jobject thiz, jint mode, jint mask)
+{
+ return check_AudioSystem_Command(AudioSystem::setRingerMode(mode, mask));
+}
+
+static int
+android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
+{
+ return check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <AudioSystem::force_use>(usage),
+ static_cast <AudioSystem::forced_config>(config)));
+}
+
+static int
+android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
+{
+ return static_cast <int>(AudioSystem::getForceUse(static_cast <AudioSystem::force_use>(usage)));
+}
+
+static int
+android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
+{
+ return check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <AudioSystem::stream_type>(stream),
+ indexMin,
+ indexMax));
+}
+
+static int
+android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env, jobject thiz, jint stream, jint index)
+{
+ return check_AudioSystem_Command(AudioSystem::setStreamVolumeIndex(static_cast <AudioSystem::stream_type>(stream), index));
+}
+
+static int
+android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env, jobject thiz, jint stream)
+{
+ int index;
+ if (AudioSystem::getStreamVolumeIndex(static_cast <AudioSystem::stream_type>(stream), &index) != NO_ERROR) {
+ index = -1;
+ }
+ return index;
+}
+
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"setVolume", "(II)I", (void *)android_media_AudioSystem_setVolume},
- {"getVolume", "(I)I", (void *)android_media_AudioSystem_getVolume},
- {"setParameter", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)android_media_AudioSystem_setParameter},
+ {"setParameters", "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
+ {"getParameters", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
{"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
{"isMicrophoneMuted", "()Z", (void *)android_media_AudioSystem_isMicrophoneMuted},
- {"setRouting", "(III)I", (void *)android_media_AudioSystem_setRouting},
- {"getRouting", "(I)I", (void *)android_media_AudioSystem_getRouting},
- {"setMode", "(I)I", (void *)android_media_AudioSystem_setMode},
- {"getMode", "()I", (void *)android_media_AudioSystem_getMode},
{"isMusicActive", "()Z", (void *)android_media_AudioSystem_isMusicActive},
+ {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
+ {"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
+ {"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState},
+ {"setRingerMode", "(II)I", (void *)android_media_AudioSystem_setRingerMode},
+ {"setForceUse", "(II)I", (void *)android_media_AudioSystem_setForceUse},
+ {"getForceUse", "(I)I", (void *)android_media_AudioSystem_getForceUse},
+ {"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
+ {"setStreamVolumeIndex","(II)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
+ {"getStreamVolumeIndex","(I)I", (void *)android_media_AudioSystem_getStreamVolumeIndex}
};
const char* const kClassPathName = "android/media/AudioSystem";
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index fd92fbe..65c0435 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>
// ----------------------------------------------------------------------------
@@ -53,10 +53,11 @@ struct fields_t {
int STREAM_MUSIC; //... stream type constants
int STREAM_ALARM; //... stream type constants
int STREAM_NOTIFICATION; //... stream type constants
- int STREAM_BLUETOOTH_SCO; //... stream type constants
+ int STREAM_BLUETOOTH_SCO; //... stream type constants
+ int STREAM_DTMF; //... stream type constants
int MODE_STREAM; //... memory mode
int MODE_STATIC; //... memory mode
- jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
+ jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
};
static fields_t javaAudioTrackFields;
@@ -103,7 +104,7 @@ class AudioTrackJniStorage {
#define AUDIOTRACK_ERROR_BAD_VALUE -2
#define AUDIOTRACK_ERROR_INVALID_OPERATION -3
#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
-#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT -17
+#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
@@ -164,11 +165,11 @@ static void audioCallback(int event, void* user, void *info) {
// ----------------------------------------------------------------------------
static int
android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
- jint streamType, jint sampleRateInHertz, jint nbChannels,
+ jint streamType, jint sampleRateInHertz, jint channels,
jint audioFormat, jint buffSizeInBytes, jint memoryMode)
{
- LOGV("sampleRate=%d, audioFormat(from Java)=%d, nbChannels=%d, buffSize=%d",
- sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+ LOGV("sampleRate=%d, audioFormat(from Java)=%d, channels=%x, buffSize=%d",
+ sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
int afSampleRate;
int afFrameCount;
@@ -181,10 +182,11 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
}
- if ((nbChannels == 0) || (nbChannels > 2)) {
- LOGE("Error creating AudioTrack: channel count is not 1 or 2.");
- return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT;
+ if (!AudioSystem::isOutputChannel(channels)) {
+ LOGE("Error creating AudioTrack: invalid channel mask.");
+ return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
}
+ int nbChannels = AudioSystem::popCount(channels);
// check the stream type
AudioSystem::stream_type atStreamType;
@@ -202,6 +204,8 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
atStreamType = AudioSystem::NOTIFICATION;
} else if (streamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
atStreamType = AudioSystem::BLUETOOTH_SCO;
+ } else if (streamType == javaAudioTrackFields.STREAM_DTMF) {
+ atStreamType = AudioSystem::DTMF;
} else {
LOGE("Error creating AudioTrack: unknown stream type.");
return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
@@ -231,15 +235,7 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
int format = audioFormat == javaAudioTrackFields.PCM16 ?
AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
- int frameCount;
- if (buffSizeInBytes == -1) {
- // compute the frame count based on the system's output frame count
- // and the native sample rate
- frameCount = (sampleRateInHertz*afFrameCount)/afSampleRate;
- } else {
- // compute the frame count based on the specified buffer size
- frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
- }
+ int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
@@ -271,7 +267,7 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
- nbChannels,
+ channels,
frameCount,
0,// flags
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
@@ -291,7 +287,7 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
- nbChannels,
+ channels,
frameCount,
0,// flags
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
@@ -734,6 +730,8 @@ static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobjec
nativeStreamType = AudioSystem::NOTIFICATION;
} else if (javaStreamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
nativeStreamType = AudioSystem::BLUETOOTH_SCO;
+ } else if (javaStreamType == javaAudioTrackFields.STREAM_DTMF) {
+ nativeStreamType = AudioSystem::DTMF;
} else {
nativeStreamType = AudioSystem::DEFAULT;
}
@@ -829,6 +827,7 @@ static JNINativeMethod gMethods[] = {
#define JAVA_CONST_STREAM_ALARM_NAME "STREAM_ALARM"
#define JAVA_CONST_STREAM_NOTIFICATION_NAME "STREAM_NOTIFICATION"
#define JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME "STREAM_BLUETOOTH_SCO"
+#define JAVA_CONST_STREAM_DTMF_NAME "STREAM_DTMF"
#define JAVA_CONST_MODE_STREAM_NAME "MODE_STREAM"
#define JAVA_CONST_MODE_STATIC_NAME "MODE_STATIC"
#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
@@ -950,8 +949,10 @@ int register_android_media_AudioTrack(JNIEnv *env)
JAVA_CONST_STREAM_NOTIFICATION_NAME, &(javaAudioTrackFields.STREAM_NOTIFICATION))
|| !android_media_getIntConstantFromClass(env, audioManagerClass,
JAVA_AUDIOMANAGER_CLASS_NAME,
- JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME,
- &(javaAudioTrackFields.STREAM_BLUETOOTH_SCO))) {
+ JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME, &(javaAudioTrackFields.STREAM_BLUETOOTH_SCO))
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_DTMF_NAME, &(javaAudioTrackFields.STREAM_DTMF))) {
// error log performed in android_media_getIntConstantFromClass()
return -1;
}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 8383deb..feb0dad 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -23,6 +23,7 @@
#include <arpa/inet.h>
extern "C" {
+int ifc_enable(const char *ifname);
int ifc_disable(const char *ifname);
int ifc_add_host_route(const char *ifname, uint32_t addr);
int ifc_remove_host_routes(const char *ifname);
@@ -66,6 +67,16 @@ static struct fieldIds {
jfieldID leaseDuration;
} dhcpInfoFieldIds;
+static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
+{
+ int result;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::ifc_enable(nameStr);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ return (jint)result;
+}
+
static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
@@ -209,6 +220,7 @@ static jboolean android_net_utils_configureInterface(JNIEnv* env,
static JNINativeMethod gNetworkUtilMethods[] = {
/* name, signature, funcPtr */
+ { "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface },
{ "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface },
{ "addHostRoute", "(Ljava/lang/String;I)I", (void *)android_net_utils_addHostRoute },
{ "removeHostRoutes", "(Ljava/lang/String;)I", (void *)android_net_utils_removeHostRoutes },
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index ae744a8..38f3fda 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -311,18 +311,26 @@ static jboolean android_net_wifi_stopPacketFiltering(JNIEnv* env, jobject clazz)
return result;
}
-static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getRssiHelper(const char *cmd)
{
char reply[256];
int rssi = -200;
- if (doCommand("DRIVER RSSI", reply, sizeof(reply)) != 0) {
+ if (doCommand(cmd, reply, sizeof(reply)) != 0) {
return (jint)-1;
}
+
// reply comes back in the form "<SSID> rssi XX" where XX is the
// number we're interested in. if we're associating, it returns "OK".
// beware - <SSID> can contain spaces.
if (strcmp(reply, "OK") != 0) {
+ // beware of trailing spaces
+ char* end = reply + strlen(reply);
+ while (end > reply && end[-1] == ' ') {
+ end--;
+ }
+ *end = 0;
+
char* lastSpace = strrchr(reply, ' ');
// lastSpace should be preceded by "rssi" and followed by the value
if (lastSpace && !strncmp(lastSpace - 4, "rssi", 4)) {
@@ -332,6 +340,16 @@ static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz)
return (jint)rssi;
}
+static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz)
+{
+ return android_net_wifi_getRssiHelper("DRIVER RSSI");
+}
+
+static jint android_net_wifi_getRssiApproxCommand(JNIEnv* env, jobject clazz)
+{
+ return android_net_wifi_getRssiHelper("DRIVER RSSI-APPROX");
+}
+
static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject clazz)
{
char reply[256];
@@ -527,6 +545,8 @@ static JNINativeMethod gWifiMethods[] = {
{ "setBluetoothCoexistenceScanModeCommand", "(Z)Z",
(void*) android_net_wifi_setBluetoothCoexistenceScanModeCommand },
{ "getRssiCommand", "()I", (void*) android_net_wifi_getRssiCommand },
+ { "getRssiApproxCommand", "()I",
+ (void*) android_net_wifi_getRssiApproxCommand},
{ "getLinkSpeedCommand", "()I", (void*) android_net_wifi_getLinkSpeedCommand },
{ "getMacAddressCommand", "()Ljava/lang/String;", (void*) android_net_wifi_getMacAddressCommand },
{ "saveConfigCommand", "()Z", (void*) android_net_wifi_saveConfigCommand },
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_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp
index 8643393..1ae3ec7 100644
--- a/core/jni/android_os_MemoryFile.cpp
+++ b/core/jni/android_os_MemoryFile.cpp
@@ -118,7 +118,7 @@ static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDe
}
}
-static jboolean android_os_MemoryFile_is_ashmem_region(JNIEnv* env, jobject clazz,
+static jint android_os_MemoryFile_get_mapped_size(JNIEnv* env, jobject clazz,
jobject fileDescriptor) {
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
// Use ASHMEM_GET_SIZE to find out if the fd refers to an ashmem region.
@@ -129,13 +129,13 @@ static jboolean android_os_MemoryFile_is_ashmem_region(JNIEnv* env, jobject claz
if (errno == ENOTTY) {
// ENOTTY means that the ioctl does not apply to this object,
// i.e., it is not an ashmem region.
- return JNI_FALSE;
+ return (jint) -1;
}
// Some other error, throw exception
jniThrowIOException(env, errno);
- return JNI_FALSE;
+ return (jint) -1;
}
- return JNI_TRUE;
+ return (jint) result;
}
static const JNINativeMethod methods[] = {
@@ -146,8 +146,8 @@ static const JNINativeMethod methods[] = {
{"native_read", "(Ljava/io/FileDescriptor;I[BIIIZ)I", (void*)android_os_MemoryFile_read},
{"native_write", "(Ljava/io/FileDescriptor;I[BIIIZ)V", (void*)android_os_MemoryFile_write},
{"native_pin", "(Ljava/io/FileDescriptor;Z)V", (void*)android_os_MemoryFile_pin},
- {"native_is_ashmem_region", "(Ljava/io/FileDescriptor;)Z",
- (void*)android_os_MemoryFile_is_ashmem_region}
+ {"native_get_mapped_size", "(Ljava/io/FileDescriptor;)I",
+ (void*)android_os_MemoryFile_get_mapped_size}
};
static const char* const kClassPathName = "android/os/MemoryFile";
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index ca4fa11..406884b 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -36,9 +36,9 @@ static jstring SystemProperties_getSS(JNIEnv *env, jobject clazz,
"key must not be null.");
goto error;
}
-
+
key = env->GetStringUTFChars(keyJ, NULL);
-
+
len = property_get(key, buf, "");
if ((len <= 0) && (defJ != NULL)) {
rvJ = defJ;
@@ -47,9 +47,9 @@ static jstring SystemProperties_getSS(JNIEnv *env, jobject clazz,
} else {
rvJ = env->NewStringUTF("");
}
-
+
env->ReleaseStringUTFChars(keyJ, key);
-
+
error:
return rvJ;
}
@@ -60,6 +60,101 @@ static jstring SystemProperties_getS(JNIEnv *env, jobject clazz,
return SystemProperties_getSS(env, clazz, keyJ, NULL);
}
+static jint SystemProperties_get_int(JNIEnv *env, jobject clazz,
+ jstring keyJ, jint defJ)
+{
+ int len;
+ const char* key;
+ char buf[PROPERTY_VALUE_MAX];
+ jint result = defJ;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ goto error;
+ }
+
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ len = property_get(key, buf, "");
+ if (len > 0) {
+ jint temp;
+ if (sscanf(buf, "%d", &temp) == 1)
+ result = temp;
+ }
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+error:
+ return result;
+}
+
+static jlong SystemProperties_get_long(JNIEnv *env, jobject clazz,
+ jstring keyJ, jlong defJ)
+{
+ int len;
+ const char* key;
+ char buf[PROPERTY_VALUE_MAX];
+ jlong result = defJ;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ goto error;
+ }
+
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ len = property_get(key, buf, "");
+ if (len > 0) {
+ jlong temp;
+ if (sscanf(buf, "%lld", &temp) == 1)
+ result = temp;
+ }
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+error:
+ return result;
+}
+
+static jboolean SystemProperties_get_boolean(JNIEnv *env, jobject clazz,
+ jstring keyJ, jboolean defJ)
+{
+ int len;
+ const char* key;
+ char buf[PROPERTY_VALUE_MAX];
+ jboolean result = defJ;
+
+ if (keyJ == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "key must not be null.");
+ goto error;
+ }
+
+ key = env->GetStringUTFChars(keyJ, NULL);
+
+ len = property_get(key, buf, "");
+ if (len == 1) {
+ char ch = buf[0];
+ if (ch == '0' || ch == 'n')
+ result = false;
+ else if (ch == '1' || ch == 'y')
+ result = true;
+ } else if (len > 1) {
+ if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+ result = false;
+ } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+ result = true;
+ }
+ }
+
+ env->ReleaseStringUTFChars(keyJ, key);
+
+error:
+ return result;
+}
+
static void SystemProperties_set(JNIEnv *env, jobject clazz,
jstring keyJ, jstring valJ)
{
@@ -94,6 +189,12 @@ static JNINativeMethod method_table[] = {
(void*) SystemProperties_getS },
{ "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
(void*) SystemProperties_getSS },
+ { "native_get_int", "(Ljava/lang/String;I)I",
+ (void*) SystemProperties_get_int },
+ { "native_get_long", "(Ljava/lang/String;J)J",
+ (void*) SystemProperties_get_long },
+ { "native_get_boolean", "(Ljava/lang/String;Z)Z",
+ (void*) SystemProperties_get_boolean },
{ "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) SystemProperties_set },
};
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 91a8e8e..a185d8d 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -37,12 +37,7 @@
namespace android {
#ifdef HAVE_BLUETOOTH
-static jmethodID method_onHeadsetCreated;
-static jmethodID method_onHeadsetRemoved;
-static jmethodID method_onSinkConnected;
-static jmethodID method_onSinkDisconnected;
-static jmethodID method_onSinkPlaying;
-static jmethodID method_onSinkStopped;
+static jmethodID method_onSinkPropertyChanged;
typedef struct {
JavaVM *vm;
@@ -53,11 +48,11 @@ typedef struct {
static native_data_t *nat = NULL; // global native data
-#endif
-
-#ifdef HAVE_BLUETOOTH
-static void onConnectSinkResult(DBusMessage *msg, void *user, void *nat);
-static void onDisconnectSinkResult(DBusMessage *msg, void *user, void *nat);
+static Properties sink_properties[] = {
+ {"State", DBUS_TYPE_STRING},
+ {"Connected", DBUS_TYPE_BOOLEAN},
+ {"Playing", DBUS_TYPE_BOOLEAN},
+ };
#endif
/* Returns true on success (even if adapter is present but disabled).
@@ -100,91 +95,58 @@ static void cleanupNative(JNIEnv* env, jobject object) {
}
#endif
}
-static jobjectArray listHeadsetsNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, "/org/bluez/audio",
- "org.bluez.audio.Manager", "ListHeadsets",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-static jstring createHeadsetNative(JNIEnv *env, jobject object,
- jstring address) {
+static jobjectArray getSinkPropertiesNative(JNIEnv *env, jobject object,
+ jstring path) {
#ifdef HAVE_BLUETOOTH
LOGV(__FUNCTION__);
if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- LOGV("... address = %s\n", c_address);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, "/org/bluez/audio",
- "org.bluez.audio.Manager", "CreateHeadset",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return reply ? dbus_returns_string(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
+ DBusMessage *msg, *reply;
+ DBusError err;
+ dbus_error_init(&err);
-static jstring removeHeadsetNative(JNIEnv *env, jobject object, jstring path) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, "/org/bluez/audio",
- "org.bluez.audio.Manager", "RemoveHeadset",
- DBUS_TYPE_STRING, &c_path,
- DBUS_TYPE_INVALID);
+ reply = dbus_func_args_timeout(env,
+ nat->conn, -1, c_path,
+ "org.bluez.AudioSink", "GetProperties",
+ DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(path, c_path);
- return reply ? dbus_returns_string(env, reply) : NULL;
+ if (!reply && dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ return NULL;
+ } else if (!reply) {
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return NULL;
+ }
+ DBusMessageIter iter;
+ if (dbus_message_iter_init(reply, &iter))
+ return parse_properties(env, &iter, (Properties *)&sink_properties,
+ sizeof(sink_properties) / sizeof(Properties));
}
#endif
return NULL;
}
-static jstring getAddressNative(JNIEnv *env, jobject object, jstring path) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- if (nat) {
- const char *c_path = env->GetStringUTFChars(path, NULL);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, c_path,
- "org.bluez.audio.Device", "GetAddress",
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(path, c_path);
- return reply ? dbus_returns_string(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) {
#ifdef HAVE_BLUETOOTH
LOGV(__FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
- size_t path_sz = env->GetStringUTFLength(path) + 1;
- char *c_path_copy = (char *)malloc(path_sz); // callback data
- strncpy(c_path_copy, c_path, path_sz);
-
- bool ret =
- dbus_func_args_async(env, nat->conn, -1,
- onConnectSinkResult, (void *)c_path_copy, nat,
- c_path,
- "org.bluez.audio.Sink", "Connect",
- DBUS_TYPE_INVALID);
+ DBusError err;
+ dbus_error_init(&err);
+ DBusMessage *reply =
+ dbus_func_args_timeout(env, nat->conn, -1, c_path,
+ "org.bluez.AudioSink", "Connect",
+ DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(path, c_path);
- if (!ret) {
- free(c_path_copy);
+
+ if (!reply && dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ return JNI_FALSE;
+ } else if (!reply) {
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
return JNI_FALSE;
}
return JNI_TRUE;
@@ -199,19 +161,20 @@ static jboolean disconnectSinkNative(JNIEnv *env, jobject object,
LOGV(__FUNCTION__);
if (nat) {
const char *c_path = env->GetStringUTFChars(path, NULL);
- size_t path_sz = env->GetStringUTFLength(path) + 1;
- char *c_path_copy = (char *)malloc(path_sz); // callback data
- strncpy(c_path_copy, c_path, path_sz);
-
- bool ret =
- dbus_func_args_async(env, nat->conn, -1,
- onDisconnectSinkResult, (void *)c_path_copy, nat,
- c_path,
- "org.bluez.audio.Sink", "Disconnect",
- DBUS_TYPE_INVALID);
+ DBusError err;
+ dbus_error_init(&err);
+
+ DBusMessage *reply =
+ dbus_func_args_timeout(env, nat->conn, -1, c_path,
+ "org.bluez.AudioSink", "Disconnect",
+ DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(path, c_path);
- if (!ret) {
- free(c_path_copy);
+
+ if (!reply && dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
+ return JNI_FALSE;
+ } else if (!reply) {
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
return JNI_FALSE;
}
return JNI_TRUE;
@@ -220,93 +183,7 @@ static jboolean disconnectSinkNative(JNIEnv *env, jobject object,
return JNI_FALSE;
}
-static jboolean isSinkConnectedNative(JNIEnv *env, jobject object, jstring path) {
#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- if (nat) {
- const char *c_path = env->GetStringUTFChars(path, NULL);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, c_path,
- "org.bluez.audio.Sink", "IsConnected",
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(path, c_path);
- return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-#ifdef HAVE_BLUETOOTH
-static void onConnectSinkResult(DBusMessage *msg, void *user, void *natData) {
- LOGV(__FUNCTION__);
-
- char *c_path = (char *)user;
- DBusError err;
- JNIEnv *env;
-
- if (nat->vm->GetEnv((void**)&env, nat->envVer) < 0) {
- LOGE("%s: error finding Env for our VM\n", __FUNCTION__);
- return;
- }
-
- dbus_error_init(&err);
-
- LOGV("... path = %s", c_path);
- if (dbus_set_error_from_message(&err, msg)) {
- /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
- LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
- dbus_error_free(&err);
- env->CallVoidMethod(nat->me,
- method_onSinkDisconnected,
- env->NewStringUTF(c_path));
- if (env->ExceptionCheck()) {
- LOGE("VM Exception occurred in native function %s (%s:%d)",
- __FUNCTION__, __FILE__, __LINE__);
- }
- } // else Java callback is triggered by signal in a2dp_event_filter
-
- free(c_path);
-}
-
-static void onDisconnectSinkResult(DBusMessage *msg, void *user, void *natData) {
- LOGV(__FUNCTION__);
-
- char *c_path = (char *)user;
- DBusError err;
- JNIEnv *env;
-
- if (nat->vm->GetEnv((void**)&env, nat->envVer) < 0) {
- LOGE("%s: error finding Env for our VM\n", __FUNCTION__);
- return;
- }
-
- dbus_error_init(&err);
-
- LOGV("... path = %s", c_path);
- if (dbus_set_error_from_message(&err, msg)) {
- /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
- LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
- if (strcmp(err.name, "org.bluez.Error.NotConnected") == 0) {
- // we were already disconnected, so report disconnect
- env->CallVoidMethod(nat->me,
- method_onSinkDisconnected,
- env->NewStringUTF(c_path));
- } else {
- // Assume it is still connected
- env->CallVoidMethod(nat->me,
- method_onSinkConnected,
- env->NewStringUTF(c_path));
- }
- dbus_error_free(&err);
- if (env->ExceptionCheck()) {
- LOGE("VM Exception occurred in native function %s (%s:%d)",
- __FUNCTION__, __FILE__, __LINE__);
- }
- } // else Java callback is triggered by signal in a2dp_event_filter
-
- free(c_path);
-}
-
DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
DBusError err;
@@ -324,71 +201,19 @@ DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- if (dbus_message_is_signal(msg,
- "org.bluez.audio.Manager",
- "HeadsetCreated")) {
- char *c_path;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_path,
- DBUS_TYPE_INVALID)) {
- LOGV("... path = %s", c_path);
- env->CallVoidMethod(nat->me,
- method_onHeadsetCreated,
- env->NewStringUTF(c_path));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- result = DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.audio.Manager",
- "HeadsetRemoved")) {
- char *c_path;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_path,
- DBUS_TYPE_INVALID)) {
- LOGV("... path = %s", c_path);
- env->CallVoidMethod(nat->me,
- method_onHeadsetRemoved,
- env->NewStringUTF(c_path));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- result = DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.audio.Sink",
- "Connected")) {
+ if (dbus_message_is_signal(msg, "org.bluez.AudioSink",
+ "PropertyChanged")) {
+ jobjectArray str_array =
+ parse_property_change(env, msg, (Properties *)&sink_properties,
+ sizeof(sink_properties) / sizeof(Properties));
const char *c_path = dbus_message_get_path(msg);
- LOGV("... path = %s", c_path);
env->CallVoidMethod(nat->me,
- method_onSinkConnected,
- env->NewStringUTF(c_path));
+ method_onSinkPropertyChanged,
+ env->NewStringUTF(c_path),
+ str_array);
result = DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.audio.Sink",
- "Disconnected")) {
- const char *c_path = dbus_message_get_path(msg);
- LOGV("... path = %s", c_path);
- env->CallVoidMethod(nat->me,
- method_onSinkDisconnected,
- env->NewStringUTF(c_path));
- result = DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.audio.Sink",
- "Playing")) {
- const char *c_path = dbus_message_get_path(msg);
- LOGV("... path = %s", c_path);
- env->CallVoidMethod(nat->me,
- method_onSinkPlaying,
- env->NewStringUTF(c_path));
- result = DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.audio.Sink",
- "Stopped")) {
- const char *c_path = dbus_message_get_path(msg);
- LOGV("... path = %s", c_path);
- env->CallVoidMethod(nat->me,
- method_onSinkStopped,
- env->NewStringUTF(c_path));
- result = DBUS_HANDLER_RESULT_HANDLED;
- }
-
- if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) {
+ return result;
+ } else {
LOGV("... ignored");
}
if (env->ExceptionCheck()) {
@@ -407,14 +232,11 @@ static JNINativeMethod sMethods[] = {
{"initNative", "()Z", (void *)initNative},
{"cleanupNative", "()V", (void *)cleanupNative},
- /* Bluez audio 3.36 API */
- {"listHeadsetsNative", "()[Ljava/lang/String;", (void*)listHeadsetsNative},
- {"createHeadsetNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)createHeadsetNative},
- {"removeHeadsetNative", "(Ljava/lang/String;)Z", (void*)removeHeadsetNative},
- {"getAddressNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getAddressNative},
- {"connectSinkNative", "(Ljava/lang/String;)Z", (void*)connectSinkNative},
- {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void*)disconnectSinkNative},
- {"isSinkConnectedNative", "(Ljava/lang/String;)Z", (void*)isSinkConnectedNative},
+ /* Bluez audio 4.40 API */
+ {"connectSinkNative", "(Ljava/lang/String;)Z", (void *)connectSinkNative},
+ {"disconnectSinkNative", "(Ljava/lang/String;)Z", (void *)disconnectSinkNative},
+ {"getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
+ (void *)getSinkPropertiesNative},
};
int register_android_server_BluetoothA2dpService(JNIEnv *env) {
@@ -425,12 +247,8 @@ int register_android_server_BluetoothA2dpService(JNIEnv *env) {
}
#ifdef HAVE_BLUETOOTH
- method_onHeadsetCreated = env->GetMethodID(clazz, "onHeadsetCreated", "(Ljava/lang/String;)V");
- method_onHeadsetRemoved = env->GetMethodID(clazz, "onHeadsetRemoved", "(Ljava/lang/String;)V");
- method_onSinkConnected = env->GetMethodID(clazz, "onSinkConnected", "(Ljava/lang/String;)V");
- method_onSinkDisconnected = env->GetMethodID(clazz, "onSinkDisconnected", "(Ljava/lang/String;)V");
- method_onSinkPlaying = env->GetMethodID(clazz, "onSinkPlaying", "(Ljava/lang/String;)V");
- method_onSinkStopped = env->GetMethodID(clazz, "onSinkStopped", "(Ljava/lang/String;)V");
+ method_onSinkPropertyChanged = env->GetMethodID(clazz, "onSinkPropertyChanged",
+ "(Ljava/lang/String;[Ljava/lang/String;)V");
#endif
return AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothDeviceService.cpp
deleted file mode 100644
index 58ae4f6..0000000
--- a/core/jni/android_server_BluetoothDeviceService.cpp
+++ /dev/null
@@ -1,1035 +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 DBUS_CLASS_NAME BLUEZ_DBUS_BASE_IFC ".Adapter"
-#define LOG_TAG "BluetoothDeviceService.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 <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-
-#ifdef HAVE_BLUETOOTH
-#include <dbus/dbus.h>
-#include <bluedroid/bluetooth.h>
-#endif
-
-#include <cutils/properties.h>
-
-namespace android {
-
-#define BLUETOOTH_CLASS_ERROR 0xFF000000
-
-#ifdef HAVE_BLUETOOTH
-// We initialize these variables when we load class
-// android.server.BluetoothDeviceService
-static jfieldID field_mNativeData;
-static jfieldID field_mEventLoop;
-
-typedef struct {
- JNIEnv *env;
- DBusConnection *conn;
- const char *adapter; // dbus object name of the local adapter
-} native_data_t;
-
-extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *,
- jobject);
-void onCreateBondingResult(DBusMessage *msg, void *user, void *nat);
-void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *nat);
-
-/** Get native data stored in the opaque (Java code maintained) pointer mNativeData
- * Perform quick sanity check, if there are any problems return NULL
- */
-static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
- native_data_t *nat =
- (native_data_t *)(env->GetIntField(object, field_mNativeData));
- if (nat == NULL || nat->conn == NULL) {
- LOGE("Uninitialized native data\n");
- return NULL;
- }
- return nat;
-}
-#endif
-
-static void classInitNative(JNIEnv* env, jclass clazz) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- field_mNativeData = get_field(env, clazz, "mNativeData", "I");
- field_mEventLoop = get_field(env, clazz, "mEventLoop",
- "Landroid/server/BluetoothEventLoop;");
-#endif
-}
-
-/* Returns true on success (even if adapter is present but disabled).
- * Return false if dbus is down, or another serious error (out of memory)
-*/
-static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
- if (NULL == nat) {
- LOGE("%s: out of memory!", __FUNCTION__);
- return false;
- }
- nat->env = env;
-
- env->SetIntField(object, field_mNativeData, (jint)nat);
- DBusError err;
- dbus_error_init(&err);
- dbus_threads_init_default();
- nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
- if (dbus_error_is_set(&err)) {
- LOGE("Could not get onto the system bus: %s", err.message);
- dbus_error_free(&err);
- return false;
- }
- dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
-
- nat->adapter = BLUEZ_ADAPTER_OBJECT_NAME;
-#endif /*HAVE_BLUETOOTH*/
- return true;
-}
-
-static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat =
- (native_data_t *)env->GetIntField(object, field_mNativeData);
- if (nat) {
- free(nat);
- nat = NULL;
- }
-#endif
-}
-
-static jstring getNameNative(JNIEnv *env, jobject object){
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetName",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_string(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- return (env->NewStringUTF(nat->adapter));
- }
-#endif
- return NULL;
-}
-
-
-static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- DBusMessage *msg = NULL;
- DBusMessage *reply = NULL;
- DBusError err;
- const char *name;
- jboolean ret = JNI_FALSE;
-
- native_data_t *nat = get_native_data(env, object);
- if (nat == NULL) {
- goto done;
- }
-
- dbus_error_init(&err);
-
- /* Compose the command */
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
- DBUS_CLASS_NAME, "DiscoverDevices");
-
- if (msg == NULL) {
- LOGE("%s: Could not allocate D-Bus message object!", __FUNCTION__);
- goto done;
- }
-
- /* Send the command. */
- reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
- if (dbus_error_is_set(&err)) {
- /* We treat the in-progress error code as success. */
- if(strcmp(err.message, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) {
- LOGW("%s: D-Bus error: %s, treating as startDiscoveryNative success\n",
- __FUNCTION__, err.message);
- ret = JNI_TRUE;
- goto done;
- } else {
- LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
- ret = JNI_FALSE;
- goto done;
- }
- }
-
- ret = JNI_TRUE;
-done:
- if (reply) dbus_message_unref(reply);
- if (msg) dbus_message_unref(msg);
- return ret;
-#else
- return JNI_FALSE;
-#endif
-}
-
-static void cancelDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- DBusMessage *msg = NULL;
- DBusMessage *reply = NULL;
- DBusError err;
- const char *name;
- jstring ret;
- native_data_t *nat;
-
- dbus_error_init(&err);
-
- nat = get_native_data(env, object);
- if (nat == NULL) {
- goto done;
- }
-
- /* Compose the command */
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
- DBUS_CLASS_NAME, "CancelDiscovery");
-
- if (msg == NULL) {
- LOGE("%s: Could not allocate D-Bus message object!", __FUNCTION__);
- goto done;
- }
-
- /* Send the command. */
- reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
- if (dbus_error_is_set(&err)) {
- if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized") == 0) {
- // hcid sends this if there is no active discovery to cancel
- LOGV("%s: There was no active discovery to cancel", __FUNCTION__);
- dbus_error_free(&err);
- } else {
- LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- }
- }
-
-done:
- if (msg) dbus_message_unref(msg);
- if (reply) dbus_message_unref(reply);
-#endif
-}
-
-static jboolean startPeriodicDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- DBusMessage *msg = NULL;
- DBusMessage *reply = NULL;
- DBusError err;
- jboolean ret = JNI_FALSE;
-
- native_data_t *nat = get_native_data(env, object);
- if (nat == NULL) {
- goto done;
- }
-
- dbus_error_init(&err);
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
- DBUS_CLASS_NAME, "StartPeriodicDiscovery");
- if (msg == NULL) {
- LOGE("%s: Could not allocate DBUS message object\n", __FUNCTION__);
- goto done;
- }
-
- /* Send the command. */
- reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
- if (dbus_error_is_set(&err)) {
- /* We treat the in-progress error code as success. */
- if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) {
- LOGW("%s: D-Bus error: %s (%s), treating as "
- "startPeriodicDiscoveryNative success\n",
- __FUNCTION__, err.name, err.message);
- } else {
- LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
- ret = JNI_FALSE;
- goto done;
- }
- }
-
- ret = JNI_TRUE;
-done:
- if (reply) dbus_message_unref(reply);
- if (msg) dbus_message_unref(msg);
- return ret;
-#else
- return JNI_FALSE;
-#endif
-}
-
-static jboolean stopPeriodicDiscoveryNative(JNIEnv *env, jobject object) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- DBusMessage *msg = NULL;
- DBusMessage *reply = NULL;
- DBusError err;
- const char *name;
- jboolean ret = JNI_FALSE;
-
- native_data_t *nat = get_native_data(env, object);
- if (nat == NULL) {
- goto done;
- }
-
- dbus_error_init(&err);
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter,
- DBUS_CLASS_NAME, "StopPeriodicDiscovery");
- if (msg == NULL) {
- LOGE("%s: Could not allocate DBUS message object\n", __FUNCTION__);
- goto done;
- }
-
- /* Send the command. */
- reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
- if (dbus_error_is_set(&err)) {
- /* We treat the in-progress error code as success. */
- if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) {
- LOGW("%s: D-Bus error: %s (%s), treating as "
- "stopPeriodicDiscoveryNative success\n",
- __FUNCTION__, err.name, err.message);
- } else {
- LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
- ret = JNI_FALSE;
- goto done;
- }
- }
-
- ret = JNI_TRUE;
-done:
- if (reply) dbus_message_unref(reply);
- if (msg) dbus_message_unref(msg);
- return ret;
-#else
- return JNI_FALSE;
-#endif
-}
-
-static jboolean isPeriodicDiscoveryNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "IsPeriodicDiscovery",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean setDiscoverableTimeoutNative(JNIEnv *env, jobject object, jint timeout_s) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
-
- if (timeout_s < 0) {
- return JNI_FALSE;
- }
-
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "SetDiscoverableTimeout",
- DBUS_TYPE_UINT32, &timeout_s,
- DBUS_TYPE_INVALID);
- if (reply != NULL) {
- dbus_message_unref(reply);
- return JNI_TRUE;
- }
- }
-#endif
- return JNI_FALSE;
-}
-
-static jint getDiscoverableTimeoutNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetDiscoverableTimeout",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_uint32(env, reply) : -1;
- }
-#endif
- return -1;
-}
-
-static jboolean isConnectedNative(JNIEnv *env, jobject object, jstring address) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "IsConnected",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static void disconnectRemoteDeviceNative(JNIEnv *env, jobject object, jstring address) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- // Set a timeout of 5 seconds. Specifying the default timeout is
- // not long enough, as a remote-device disconnect results in
- // signal RemoteDisconnectRequested being sent, followed by a
- // delay of 2 seconds, after which the actual disconnect takes
- // place.
- DBusMessage *reply =
- dbus_func_args_timeout(env, nat->conn, 60000, nat->adapter,
- DBUS_CLASS_NAME, "DisconnectRemoteDevice",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- if (reply) dbus_message_unref(reply);
- }
-#endif
-}
-
-static jstring getModeNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetMode",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_string(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jboolean setModeNative(JNIEnv *env, jobject object, jstring mode) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_mode = env->GetStringUTFChars(mode, NULL);
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "SetMode",
- DBUS_TYPE_STRING, &c_mode,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(mode, c_mode);
- if (reply) {
- dbus_message_unref(reply);
- return JNI_TRUE;
- }
- return JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean createBondingNative(JNIEnv *env, jobject object,
- jstring address, jint timeout_ms) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
- struct event_loop_native_data_t *eventLoopNat =
- get_EventLoop_native_data(env, eventLoop);
-
- if (nat && eventLoopNat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- LOGV("... address = %s", c_address);
- char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
- strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
- bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
- onCreateBondingResult, // callback
- context_address,
- eventLoopNat,
- nat->adapter,
- DBUS_CLASS_NAME, "CreateBonding",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return ret ? JNI_TRUE : JNI_FALSE;
-
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean cancelBondingProcessNative(JNIEnv *env, jobject object,
- jstring address) {
- LOGV(__FUNCTION__);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- LOGV("... address = %s", c_address);
- DBusMessage *reply =
- dbus_func_args_timeout(env, nat->conn, -1, nat->adapter,
- DBUS_CLASS_NAME, "CancelBondingProcess",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- if (reply) {
- dbus_message_unref(reply);
- }
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean removeBondingNative(JNIEnv *env, jobject object, jstring address) {
- LOGV(__FUNCTION__);
- jboolean result = JNI_FALSE;
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- LOGV("... address = %s", c_address);
- DBusError err;
- dbus_error_init(&err);
- DBusMessage *reply =
- dbus_func_args_error(env, nat->conn, &err, nat->adapter,
- DBUS_CLASS_NAME, "RemoveBonding",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- if (dbus_error_is_set(&err)) {
- if (dbus_error_has_name(&err,
- BLUEZ_DBUS_BASE_IFC ".Error.DoesNotExist")) {
- LOGW("%s: Warning: %s (%s)", __FUNCTION__, err.message,
- c_address);
- result = JNI_TRUE;
- } else {
- LOGE("%s: D-Bus error %s (%s)", __FUNCTION__, err.name,
- err.message);
- }
- } else {
- result = JNI_TRUE;
- }
-
- env->ReleaseStringUTFChars(address, c_address);
- dbus_error_free(&err);
- if (reply) dbus_message_unref(reply);
- }
-#endif
- return result;
-}
-
-static jobjectArray listBondingsNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "ListBondings",
- DBUS_TYPE_INVALID);
- // return String[]
- return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jobjectArray listConnectionsNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "ListConnections",
- DBUS_TYPE_INVALID);
- // return String[]
- return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jobjectArray listRemoteDevicesNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "ListRemoteDevices",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jstring common_Get(JNIEnv *env, jobject object, const char *func) {
- LOGV("%s:%s", __FUNCTION__, func);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusError err;
- dbus_error_init(&err);
- DBusMessage *reply =
- dbus_func_args_error(env, nat->conn, &err, nat->adapter,
- DBUS_CLASS_NAME, func,
- DBUS_TYPE_INVALID);
- if (reply) {
- return dbus_returns_string(env, reply);
- } else {
- LOG_AND_FREE_DBUS_ERROR(&err);
- return NULL;
- }
- }
-#endif
- return NULL;
-}
-
-static jstring getAddressNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetAddress");
-}
-
-static jstring getVersionNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetVersion");
-}
-
-static jstring getRevisionNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetRevision");
-}
-
-static jstring getManufacturerNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetManufacturer");
-}
-
-static jstring getCompanyNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetCompany");
-}
-
-static jboolean setNameNative(JNIEnv *env, jobject obj, jstring name) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, obj);
- if (nat) {
- const char *c_name = env->GetStringUTFChars(name, NULL);
- DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "SetName",
- DBUS_TYPE_STRING, &c_name,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(name, c_name);
- if (reply) {
- dbus_message_unref(reply);
- return JNI_TRUE;
- }
- }
-#endif
- return JNI_FALSE;
-}
-
-static jstring common_getRemote(JNIEnv *env, jobject object, const char *func,
- jstring address) {
- LOGV("%s:%s", __FUNCTION__, func);
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- DBusError err;
- dbus_error_init(&err);
-
- LOGV("... address = %s", c_address);
-
- DBusMessage *reply =
- dbus_func_args_error(env, nat->conn, &err, nat->adapter,
- DBUS_CLASS_NAME, func,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- if (reply) {
- return dbus_returns_string(env, reply);
- } else if (!strcmp(func, "GetRemoteName") &&
- dbus_error_has_name(&err, "org.bluez.Error.RequestDeferred")) {
- // This error occurs if we request name during device discovery,
- // its fine
- LOGV("... %s: %s", func, err.message);
- dbus_error_free(&err);
- return NULL;
- } else {
- LOG_AND_FREE_DBUS_ERROR(&err);
- return NULL;
- }
- }
-#endif
- return NULL;
-}
-
-static jstring getRemoteVersionNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteVersion", address);
-}
-
-static jstring getRemoteRevisionNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteRevision", address);
-}
-
-static jstring getRemoteManufacturerNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteManufacturer", address);
-}
-
-static jstring getRemoteCompanyNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteCompany", address);
-}
-
-static jstring getRemoteNameNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteName", address);
-}
-
-static jstring lastSeenNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "LastSeen", address);
-}
-
-static jstring lastUsedNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "LastUsed", address);
-}
-
-static jint getRemoteClassNative(JNIEnv *env, jobject object, jstring address) {
- jint result = BLUETOOTH_CLASS_ERROR;
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
-
- LOGV("... address = %s", c_address);
-
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteClass",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- if (reply)
- {
- DBusError err;
- dbus_error_init(&err);
- if (!dbus_message_get_args(reply, &err,
- DBUS_TYPE_UINT32, &result,
- DBUS_TYPE_INVALID)) {
- LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
- }
- dbus_message_unref(reply);
- }
- }
-#endif
- return result;
-}
-
-static jbyteArray getRemoteFeaturesNative(JNIEnv *env, jobject object,
- jstring address) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
-
- LOGV("... address = %s", c_address);
-
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteFeatures",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- /* array of DBUS_TYPE_BYTE_AS_STRING */
- return reply ? dbus_returns_array_of_bytes(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jintArray getRemoteServiceHandlesNative(JNIEnv *env, jobject object,
- jstring address, jstring match) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- jintArray intArray = NULL;
- const char *c_address = env->GetStringUTFChars(address, NULL);
- const char *c_match = env->GetStringUTFChars(match, NULL);
-
- LOGV("... address = %s match = %s", c_address, c_match);
-
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteServiceHandles",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_STRING, &c_match,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- env->ReleaseStringUTFChars(match, c_match);
- if (reply)
- {
- DBusError err;
- jint *list;
- int i, len;
-
- dbus_error_init(&err);
- if (dbus_message_get_args (reply, &err,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
- &list, &len,
- DBUS_TYPE_INVALID)) {
- if (len) {
- intArray = env->NewIntArray(len);
- if (intArray)
- env->SetIntArrayRegion(intArray, 0, len, list);
- }
- } else {
- LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
- }
-
- dbus_message_unref(reply);
- }
- return intArray;
- }
-#endif
- return NULL;
-}
-
-static jbyteArray getRemoteServiceRecordNative(JNIEnv *env, jobject object,
- jstring address, jint handle) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
-
- LOGV("... address = %s", c_address);
-
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteServiceRecord",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_UINT32, &handle,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return reply ? dbus_returns_array_of_bytes(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
-static jboolean getRemoteServiceChannelNative(JNIEnv *env, jobject object,
- jstring address, jshort uuid16) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
- struct event_loop_native_data_t *eventLoopNat =
- get_EventLoop_native_data(env, eventLoop);
- if (nat && eventLoopNat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
- strlcpy(context_address, c_address, BTADDR_SIZE);
-
- LOGV("... address = %s", c_address);
- LOGV("... uuid16 = %#X", uuid16);
-
- bool ret = dbus_func_args_async(env, nat->conn, 20000, // ms
- onGetRemoteServiceChannelResult, context_address,
- eventLoopNat,
- nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteServiceChannel",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_UINT16, &uuid16,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return ret ? JNI_TRUE : JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jint enableNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- return bt_enable();
-#endif
- return -1;
-}
-
-static jint disableNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- return bt_disable();
-#endif
- return -1;
-}
-
-static jint isEnabledNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- return bt_is_enabled();
-#endif
- return -1;
-}
-
-static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
- jstring pin, int nativeData) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *msg = (DBusMessage *)nativeData;
- DBusMessage *reply = dbus_message_new_method_return(msg);
- if (!reply) {
- LOGE("%s: Cannot create message reply to return PIN code to "
- "D-Bus\n", __FUNCTION__);
- dbus_message_unref(msg);
- return JNI_FALSE;
- }
-
- const char *c_pin = env->GetStringUTFChars(pin, NULL);
-
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin,
- DBUS_TYPE_INVALID);
-
- dbus_connection_send(nat->conn, reply, NULL);
- dbus_message_unref(msg);
- dbus_message_unref(reply);
- env->ReleaseStringUTFChars(pin, c_pin);
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean cancelPinNative(JNIEnv *env, jobject object, jstring address,
- int nativeData) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *msg = (DBusMessage *)nativeData;
- DBusMessage *reply = dbus_message_new_error(msg,
- "org.bluez.Error.Canceled", "PIN Entry was canceled");
- if (!reply) {
- LOGE("%s: Cannot create message reply to return PIN cancel to "
- "D-BUS\n", __FUNCTION__);
- dbus_message_unref(msg);
- return JNI_FALSE;
- }
-
- dbus_connection_send(nat->conn, reply, NULL);
- dbus_message_unref(msg);
- dbus_message_unref(reply);
- return JNI_TRUE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- {"classInitNative", "()V", (void*)classInitNative},
- {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
- {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
- {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative},
-
- {"isEnabledNative", "()I", (void *)isEnabledNative},
- {"enableNative", "()I", (void *)enableNative},
- {"disableNative", "()I", (void *)disableNative},
-
- {"getAddressNative", "()Ljava/lang/String;", (void *)getAddressNative},
- {"getNameNative", "()Ljava/lang/String;", (void*)getNameNative},
- {"setNameNative", "(Ljava/lang/String;)Z", (void *)setNameNative},
- {"getVersionNative", "()Ljava/lang/String;", (void *)getVersionNative},
- {"getRevisionNative", "()Ljava/lang/String;", (void *)getRevisionNative},
- {"getManufacturerNative", "()Ljava/lang/String;", (void *)getManufacturerNative},
- {"getCompanyNative", "()Ljava/lang/String;", (void *)getCompanyNative},
-
- {"getModeNative", "()Ljava/lang/String;", (void *)getModeNative},
- {"setModeNative", "(Ljava/lang/String;)Z", (void *)setModeNative},
-
- {"getDiscoverableTimeoutNative", "()I", (void *)getDiscoverableTimeoutNative},
- {"setDiscoverableTimeoutNative", "(I)Z", (void *)setDiscoverableTimeoutNative},
-
- {"startDiscoveryNative", "(Z)Z", (void*)startDiscoveryNative},
- {"cancelDiscoveryNative", "()Z", (void *)cancelDiscoveryNative},
- {"startPeriodicDiscoveryNative", "()Z", (void *)startPeriodicDiscoveryNative},
- {"stopPeriodicDiscoveryNative", "()Z", (void *)stopPeriodicDiscoveryNative},
- {"isPeriodicDiscoveryNative", "()Z", (void *)isPeriodicDiscoveryNative},
- {"listRemoteDevicesNative", "()[Ljava/lang/String;", (void *)listRemoteDevicesNative},
-
- {"listConnectionsNative", "()[Ljava/lang/String;", (void *)listConnectionsNative},
- {"isConnectedNative", "(Ljava/lang/String;)Z", (void *)isConnectedNative},
- {"disconnectRemoteDeviceNative", "(Ljava/lang/String;)Z", (void *)disconnectRemoteDeviceNative},
-
- {"createBondingNative", "(Ljava/lang/String;I)Z", (void *)createBondingNative},
- {"cancelBondingProcessNative", "(Ljava/lang/String;)Z", (void *)cancelBondingProcessNative},
- {"listBondingsNative", "()[Ljava/lang/String;", (void *)listBondingsNative},
- {"removeBondingNative", "(Ljava/lang/String;)Z", (void *)removeBondingNative},
-
- {"getRemoteNameNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteNameNative},
- {"getRemoteVersionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteVersionNative},
- {"getRemoteRevisionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteRevisionNative},
- {"getRemoteClassNative", "(Ljava/lang/String;)I", (void *)getRemoteClassNative},
- {"getRemoteManufacturerNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteManufacturerNative},
- {"getRemoteCompanyNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteCompanyNative},
- {"getRemoteServiceChannelNative", "(Ljava/lang/String;S)Z", (void *)getRemoteServiceChannelNative},
- {"getRemoteFeaturesNative", "(Ljava/lang/String;)[B", (void *)getRemoteFeaturesNative},
- {"lastSeenNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastSeenNative},
- {"lastUsedNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastUsedNative},
- {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
- {"cancelPinNative", "(Ljava/lang/String;I)Z", (void *)cancelPinNative},
-};
-
-int register_android_server_BluetoothDeviceService(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/server/BluetoothDeviceService", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index ad24136..1bfabd7 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -39,33 +39,26 @@ namespace android {
#ifdef HAVE_BLUETOOTH
static jfieldID field_mNativeData;
-static jmethodID method_onModeChanged;
-static jmethodID method_onNameChanged;
-static jmethodID method_onDiscoveryStarted;
-static jmethodID method_onDiscoveryCompleted;
-static jmethodID method_onRemoteDeviceFound;
-static jmethodID method_onRemoteDeviceDisappeared;
-static jmethodID method_onRemoteClassUpdated;
-static jmethodID method_onRemoteNameUpdated;
-static jmethodID method_onRemoteNameFailed;
-static jmethodID method_onRemoteDeviceConnected;
-static jmethodID method_onRemoteDeviceDisconnectRequested;
-static jmethodID method_onRemoteDeviceDisconnected;
-static jmethodID method_onBondingCreated;
-static jmethodID method_onBondingRemoved;
-
-static jmethodID method_onCreateBondingResult;
-static jmethodID method_onGetRemoteServiceChannelResult;
-
-static jmethodID method_onPasskeyAgentRequest;
-static jmethodID method_onPasskeyAgentCancel;
-static jmethodID method_onAuthAgentAuthorize;
-static jmethodID method_onAuthAgentCancel;
-
-static jmethodID method_onRestartRequired;
+static jmethodID method_onPropertyChanged;
+static jmethodID method_onDevicePropertyChanged;
+static jmethodID method_onDeviceFound;
+static jmethodID method_onDeviceDisappeared;
+static jmethodID method_onDeviceCreated;
+static jmethodID method_onDeviceRemoved;
+
+static jmethodID method_onCreatePairedDeviceResult;
+static jmethodID method_onGetDeviceServiceChannelResult;
+
+static jmethodID method_onRequestPinCode;
+static jmethodID method_onRequestPasskey;
+static jmethodID method_onRequestConfirmation;
+static jmethodID method_onAgentAuthorize;
+static jmethodID method_onAgentCancel;
typedef event_loop_native_data_t native_data_t;
+#define EVENT_LOOP_REFS 10
+
static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
return (native_data_t *)(env->GetIntField(object,
field_mNativeData));
@@ -80,30 +73,30 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
LOGV(__FUNCTION__);
#ifdef HAVE_BLUETOOTH
- method_onModeChanged = env->GetMethodID(clazz, "onModeChanged", "(Ljava/lang/String;)V");
- method_onNameChanged = env->GetMethodID(clazz, "onNameChanged", "(Ljava/lang/String;)V");
- method_onDiscoveryStarted = env->GetMethodID(clazz, "onDiscoveryStarted", "()V");
- method_onDiscoveryCompleted = env->GetMethodID(clazz, "onDiscoveryCompleted", "()V");
- method_onRemoteDeviceFound = env->GetMethodID(clazz, "onRemoteDeviceFound", "(Ljava/lang/String;IS)V");
- method_onRemoteDeviceDisappeared = env->GetMethodID(clazz, "onRemoteDeviceDisappeared", "(Ljava/lang/String;)V");
- method_onRemoteClassUpdated = env->GetMethodID(clazz, "onRemoteClassUpdated", "(Ljava/lang/String;I)V");
- method_onRemoteNameUpdated = env->GetMethodID(clazz, "onRemoteNameUpdated", "(Ljava/lang/String;Ljava/lang/String;)V");
- method_onRemoteNameFailed = env->GetMethodID(clazz, "onRemoteNameFailed", "(Ljava/lang/String;)V");
- method_onRemoteDeviceConnected = env->GetMethodID(clazz, "onRemoteDeviceConnected", "(Ljava/lang/String;)V");
- method_onRemoteDeviceDisconnectRequested = env->GetMethodID(clazz, "onRemoteDeviceDisconnectRequested", "(Ljava/lang/String;)V");
- method_onRemoteDeviceDisconnected = env->GetMethodID(clazz, "onRemoteDeviceDisconnected", "(Ljava/lang/String;)V");
- method_onBondingCreated = env->GetMethodID(clazz, "onBondingCreated", "(Ljava/lang/String;)V");
- method_onBondingRemoved = env->GetMethodID(clazz, "onBondingRemoved", "(Ljava/lang/String;)V");
-
- method_onCreateBondingResult = env->GetMethodID(clazz, "onCreateBondingResult", "(Ljava/lang/String;I)V");
-
- method_onPasskeyAgentRequest = env->GetMethodID(clazz, "onPasskeyAgentRequest", "(Ljava/lang/String;I)V");
- method_onPasskeyAgentCancel = env->GetMethodID(clazz, "onPasskeyAgentCancel", "(Ljava/lang/String;)V");
- method_onAuthAgentAuthorize = env->GetMethodID(clazz, "onAuthAgentAuthorize", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
- method_onAuthAgentCancel = env->GetMethodID(clazz, "onAuthAgentCancel", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
- method_onGetRemoteServiceChannelResult = env->GetMethodID(clazz, "onGetRemoteServiceChannelResult", "(Ljava/lang/String;I)V");
-
- method_onRestartRequired = env->GetMethodID(clazz, "onRestartRequired", "()V");
+ method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
+ "([Ljava/lang/String;)V");
+ method_onDevicePropertyChanged = env->GetMethodID(clazz,
+ "onDevicePropertyChanged",
+ "(Ljava/lang/String;[Ljava/lang/String;)V");
+ method_onDeviceFound = env->GetMethodID(clazz, "onDeviceFound",
+ "(Ljava/lang/String;[Ljava/lang/String;)V");
+ method_onDeviceDisappeared = env->GetMethodID(clazz, "onDeviceDisappeared",
+ "(Ljava/lang/String;)V");
+ method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V");
+ method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V");
+
+ method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
+ "(Ljava/lang/String;I)V");
+
+ method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
+ "(Ljava/lang/String;Ljava/lang/String;)Z");
+ method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V");
+ method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode",
+ "(Ljava/lang/String;I)V");
+ method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey",
+ "(Ljava/lang/String;I)V");
+ method_onRequestConfirmation = env->GetMethodID(clazz, "onRequestConfirmation",
+ "(Ljava/lang/String;II)V");
field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
#endif
@@ -154,9 +147,11 @@ static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
#ifdef HAVE_BLUETOOTH
static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
void *data);
-static DBusHandlerResult agent_event_filter(DBusConnection *conn,
- DBusMessage *msg,
- void *data);
+DBusHandlerResult agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data);
+static int register_agent(native_data_t *nat,
+ const char *agent_path, const char *capabilities);
static const DBusObjectPathVTable agent_vtable = {
NULL, agent_event_filter, NULL, NULL, NULL, NULL
@@ -178,11 +173,12 @@ static short dbus_flags_to_unix_events(unsigned int flags) {
static jboolean setUpEventLoop(native_data_t *nat) {
LOGV(__FUNCTION__);
- dbus_threads_init_default();
- DBusError err;
- dbus_error_init(&err);
if (nat != NULL && nat->conn != NULL) {
+ dbus_threads_init_default();
+ DBusError err;
+ dbus_error_init(&err);
+
// Add a filter for all incoming messages
if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
return JNI_FALSE;
@@ -204,108 +200,143 @@ static jboolean setUpEventLoop(native_data_t *nat) {
return JNI_FALSE;
}
dbus_bus_add_match(nat->conn,
- "type='signal',interface='org.bluez.audio.Manager'",
- &err);
- if (dbus_error_is_set(&err)) {
- LOG_AND_FREE_DBUS_ERROR(&err);
- return JNI_FALSE;
- }
- dbus_bus_add_match(nat->conn,
- "type='signal',interface='org.bluez.audio.Device'",
+ "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'",
&err);
if (dbus_error_is_set(&err)) {
LOG_AND_FREE_DBUS_ERROR(&err);
return JNI_FALSE;
}
dbus_bus_add_match(nat->conn,
- "type='signal',interface='org.bluez.audio.Sink'",
+ "type='signal',interface='org.bluez.AudioSink'",
&err);
if (dbus_error_is_set(&err)) {
LOG_AND_FREE_DBUS_ERROR(&err);
return JNI_FALSE;
}
- // Add an object handler for passkey agent method calls
- const char *path = "/android/bluetooth/Agent";
- if (!dbus_connection_register_object_path(nat->conn, path,
- &agent_vtable, nat)) {
- LOGE("%s: Can't register object path %s for agent!",
- __FUNCTION__, path);
+ const char *agent_path = "/android/bluetooth/agent";
+ const char *capabilities = "DisplayYesNo";
+ if (register_agent(nat, agent_path, capabilities) < 0) {
+ dbus_connection_unregister_object_path (nat->conn, agent_path);
return JNI_FALSE;
}
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+}
- // RegisterDefaultPasskeyAgent() will fail until hcid is up, so keep
- // trying for 10 seconds.
- int attempt;
- for (attempt = 0; attempt < 1000; attempt++) {
- DBusMessage *reply = dbus_func_args_error(NULL, nat->conn, &err,
- BLUEZ_DBUS_BASE_PATH,
- "org.bluez.Security", "RegisterDefaultPasskeyAgent",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
- if (reply) {
- // Success
- dbus_message_unref(reply);
- LOGV("Registered agent on attempt %d of 1000\n", attempt);
- break;
- } else if (dbus_error_has_name(&err,
- "org.freedesktop.DBus.Error.ServiceUnknown")) {
- // hcid is still down, retry
- dbus_error_free(&err);
- usleep(10000); // 10 ms
- } else {
- // Some other error we weren't expecting
- LOG_AND_FREE_DBUS_ERROR(&err);
- return JNI_FALSE;
- }
+
+const char * get_adapter_path(DBusConnection *conn) {
+ DBusMessage *msg, *reply;
+ DBusError err;
+ const char *device_path = NULL;
+ msg = dbus_message_new_method_call("org.bluez", "/",
+ "org.bluez.Manager", "DefaultAdapter");
+ if (!msg) {
+ LOGE("%s: Can't allocate new method call for GetProperties!",
+ __FUNCTION__);
+ return NULL;
+ }
+ dbus_message_append_args(msg, DBUS_TYPE_INVALID);
+
+ dbus_error_init(&err);
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+ dbus_message_unref(msg);
+
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
}
- if (attempt == 1000) {
- LOGE("Time-out trying to call RegisterDefaultPasskeyAgent(), "
- "is hcid running?");
- return JNI_FALSE;
+ return NULL;
+ }
+ if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH,
+ &device_path, DBUS_TYPE_INVALID)
+ || !device_path){
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
}
+ return NULL;
+ }
+ return device_path;
+}
- // Now register the Auth agent
- DBusMessage *reply = dbus_func_args_error(NULL, nat->conn, &err,
- BLUEZ_DBUS_BASE_PATH,
- "org.bluez.Security", "RegisterDefaultAuthorizationAgent",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
- if (!reply) {
+static int register_agent(native_data_t *nat,
+ const char * agent_path, const char * capabilities)
+{
+ DBusMessage *msg, *reply;
+ DBusError err;
+
+ if (!dbus_connection_register_object_path(nat->conn, agent_path,
+ &agent_vtable, nat)) {
+ LOGE("%s: Can't register object path %s for agent!",
+ __FUNCTION__, agent_path);
+ return -1;
+ }
+
+ nat->adapter = get_adapter_path(nat->conn);
+ msg = dbus_message_new_method_call("org.bluez", nat->adapter,
+ "org.bluez.Adapter", "RegisterAgent");
+ if (!msg) {
+ LOGE("%s: Can't allocate new method call for agent!",
+ __FUNCTION__);
+ return -1;
+ }
+ dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
+ DBUS_TYPE_STRING, &capabilities,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&err);
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ dbus_message_unref(msg);
+
+ if (!reply) {
+ LOGE("%s: Can't register agent!", __FUNCTION__);
+ if (dbus_error_is_set(&err)) {
LOG_AND_FREE_DBUS_ERROR(&err);
- return JNI_FALSE;
}
-
- dbus_message_unref(reply);
- return JNI_TRUE;
+ return -1;
}
- return JNI_FALSE;
+ dbus_message_unref(reply);
+ dbus_connection_flush(nat->conn);
+
+ return 0;
}
static void tearDownEventLoop(native_data_t *nat) {
LOGV(__FUNCTION__);
if (nat != NULL && nat->conn != NULL) {
+ DBusMessage *msg, *reply;
DBusError err;
dbus_error_init(&err);
+ const char * agent_path = "/android/bluetooth/agent";
+
+ msg = dbus_message_new_method_call("org.bluez",
+ nat->adapter,
+ "org.bluez.Adapter",
+ "UnregisterAgent");
+ if (msg != NULL) {
+ dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
+ DBUS_TYPE_INVALID);
+ reply = dbus_connection_send_with_reply_and_block(nat->conn,
+ msg, -1, &err);
- const char *path = "/android/bluetooth/Agent";
- DBusMessage *reply =
- dbus_func_args(NULL, nat->conn, BLUEZ_DBUS_BASE_PATH,
- "org.bluez.Security", "UnregisterDefaultPasskeyAgent",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
- if (reply) dbus_message_unref(reply);
-
- reply =
- dbus_func_args(NULL, nat->conn, BLUEZ_DBUS_BASE_PATH,
- "org.bluez.Security", "UnregisterDefaultAuthorizationAgent",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
- if (reply) dbus_message_unref(reply);
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ dbus_error_free(&err);
+ }
+ } else {
+ dbus_message_unref(reply);
+ }
+ dbus_message_unref(msg);
+ } else {
+ LOGE("%s: Can't create new method call!", __FUNCTION__);
+ }
- dbus_connection_unregister_object_path(nat->conn, path);
+ dbus_connection_flush(nat->conn);
+ dbus_connection_unregister_object_path(nat->conn, agent_path);
dbus_bus_remove_match(nat->conn,
"type='signal',interface='org.bluez.audio.Sink'",
@@ -650,6 +681,7 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
native_data_t *nat;
JNIEnv *env;
DBusError err;
+ DBusHandlerResult ret;
dbus_error_init(&err);
@@ -660,321 +692,173 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- LOGV("%s: Received signal %s:%s from %s", __FUNCTION__,
- dbus_message_get_interface(msg), dbus_message_get_member(msg),
- dbus_message_get_path(msg));
+ // STOPSHIP: Change to LOGV
+ LOGE("%s: Received signal %s:%s from %s", __FUNCTION__,
+ dbus_message_get_interface(msg), dbus_message_get_member(msg),
+ dbus_message_get_path(msg));
+ env->PushLocalFrame(EVENT_LOOP_REFS);
if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
- "RemoteDeviceFound")) {
+ "DeviceFound")) {
char *c_address;
- int n_class;
- short n_rssi;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_UINT32, &n_class,
- DBUS_TYPE_INT16, &n_rssi,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s class = %#X rssi = %hd", c_address, n_class,
- n_rssi);
+ DBusMessageIter iter;
+ jobjectArray str_array = NULL;
+ if (dbus_message_iter_init(msg, &iter)) {
+ dbus_message_iter_get_basic(&iter, &c_address);
+ if (dbus_message_iter_next(&iter))
+ str_array =
+ parse_remote_device_properties(env, &iter);
+ }
+ if (str_array != NULL) {
env->CallVoidMethod(nat->me,
- method_onRemoteDeviceFound,
+ method_onDeviceFound,
env->NewStringUTF(c_address),
- (jint)n_class,
- (jshort)n_rssi);
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ str_array);
+ } else
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ goto success;
} else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "DiscoveryStarted")) {
- LOGI("DiscoveryStarted signal received");
- env->CallVoidMethod(nat->me, method_onDiscoveryStarted);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "DiscoveryCompleted")) {
- LOGI("DiscoveryCompleted signal received");
- env->CallVoidMethod(nat->me, method_onDiscoveryCompleted);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteDeviceDisappeared")) {
+ "org.bluez.Adapter",
+ "DeviceDisappeared")) {
char *c_address;
if (dbus_message_get_args(msg, &err,
DBUS_TYPE_STRING, &c_address,
DBUS_TYPE_INVALID)) {
LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me, method_onRemoteDeviceDisappeared,
+ env->CallVoidMethod(nat->me, method_onDeviceDisappeared,
env->NewStringUTF(c_address));
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteClassUpdated")) {
- char *c_address;
- int n_class;
+ "org.bluez.Adapter",
+ "DeviceCreated")) {
+ char *c_object_path;
if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_UINT32, &n_class,
+ DBUS_TYPE_OBJECT_PATH, &c_object_path,
DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me, method_onRemoteClassUpdated,
- env->NewStringUTF(c_address), (jint)n_class);
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteNameUpdated")) {
- char *c_address;
- char *c_name;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_STRING, &c_name,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s, name = %s", c_address, c_name);
+ LOGV("... address = %s", c_object_path);
env->CallVoidMethod(nat->me,
- method_onRemoteNameUpdated,
- env->NewStringUTF(c_address),
- env->NewStringUTF(c_name));
+ method_onDeviceCreated,
+ env->NewStringUTF(c_object_path));
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteNameFailed")) {
- char *c_address;
+ "org.bluez.Adapter",
+ "DeviceRemoved")) {
+ char *c_object_path;
if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onRemoteNameFailed,
- env->NewStringUTF(c_address));
+ DBUS_TYPE_OBJECT_PATH, &c_object_path,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... Object Path = %s", c_object_path);
+ env->CallVoidMethod(nat->me,
+ method_onDeviceRemoved,
+ env->NewStringUTF(c_object_path));
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
- "RemoteDeviceConnected")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onRemoteDeviceConnected,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteDeviceDisconnectRequested")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onRemoteDeviceDisconnectRequested,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteDeviceDisconnected")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onRemoteDeviceDisconnected,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "BondingCreated")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onBondingCreated,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "BondingRemoved")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onBondingRemoved,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "ModeChanged")) {
- char *c_mode;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_mode,
- DBUS_TYPE_INVALID)) {
- LOGV("... mode = %s", c_mode);
+ "PropertyChanged")) {
+ jobjectArray str_array = parse_adapter_property_change(env, msg);
+ if (str_array != NULL) {
+ /* Check if bluetoothd has (re)started, if so update the path. */
+ jstring property =(jstring) env->GetObjectArrayElement(str_array, 0);
+ const char *c_property = env->GetStringUTFChars(property, NULL);
+ if (!strncmp(c_property, "Powered", strlen("Powered"))) {
+ jstring value =
+ (jstring) env->GetObjectArrayElement(str_array, 1);
+ const char *c_value = env->GetStringUTFChars(value, NULL);
+ if (!strncmp(c_value, "true", strlen("true")))
+ nat->adapter = get_adapter_path(nat->conn);
+ env->ReleaseStringUTFChars(value, c_value);
+ }
+ env->ReleaseStringUTFChars(property, c_property);
+
env->CallVoidMethod(nat->me,
- method_onModeChanged,
- env->NewStringUTF(c_mode));
+ method_onPropertyChanged,
+ str_array);
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "NameChanged")) {
- char *c_name;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_name,
- DBUS_TYPE_INVALID)) {
- LOGV("... name = %s", c_name);
+ "org.bluez.Device",
+ "PropertyChanged")) {
+ jobjectArray str_array = parse_remote_device_property_change(env, msg);
+ if (str_array != NULL) {
+ const char *remote_device_path = dbus_message_get_path(msg);
env->CallVoidMethod(nat->me,
- method_onNameChanged,
- env->NewStringUTF(c_name));
+ method_onDevicePropertyChanged,
+ env->NewStringUTF(remote_device_path),
+ str_array);
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.freedesktop.DBus",
- "NameOwnerChanged")) {
- char *c_name;
- char *c_old_owner;
- char *c_new_owner;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_name,
- DBUS_TYPE_STRING, &c_old_owner,
- DBUS_TYPE_STRING, &c_new_owner,
- DBUS_TYPE_INVALID)) {
- LOGV("... name = %s", c_name);
- LOGV("... old_owner = %s", c_old_owner);
- LOGV("... new_owner = %s", c_new_owner);
- if (!strcmp(c_name, "org.bluez") && c_new_owner[0] != '\0') {
- // New owner of org.bluez. This can only happen when hcid
- // restarts. Need to restart framework BT services to recover.
- LOGE("Looks like hcid restarted");
- env->CallVoidMethod(nat->me, method_onRestartRequired);
- }
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
}
- return a2dp_event_filter(msg, env);
+ ret = a2dp_event_filter(msg, env);
+ env->PopLocalFrame(NULL);
+ return ret;
+
+success:
+ env->PopLocalFrame(NULL);
+ return DBUS_HANDLER_RESULT_HANDLED;
}
// Called by dbus during WaitForAndDispatchEventNative()
-static DBusHandlerResult agent_event_filter(DBusConnection *conn,
- DBusMessage *msg, void *data) {
+DBusHandlerResult agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data) {
native_data_t *nat = (native_data_t *)data;
JNIEnv *env;
- nat->vm->GetEnv((void**)&env, nat->envVer);
if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
LOGV("%s: not interested (not a method call).", __FUNCTION__);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- LOGV("%s: Received method %s:%s", __FUNCTION__,
+ LOGI("%s: Received method %s:%s", __FUNCTION__,
dbus_message_get_interface(msg), dbus_message_get_member(msg));
- if (dbus_message_is_method_call(msg,
- "org.bluez.PasskeyAgent", "Request")) {
-
- const char *adapter;
- const char *address;
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &adapter,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_INVALID)) {
- LOGE("%s: Invalid arguments for Request() method", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- LOGV("... address = %s", address);
-
- dbus_message_ref(msg); // increment refcount because we pass to java
-
- env->CallVoidMethod(nat->me, method_onPasskeyAgentRequest,
- env->NewStringUTF(address), (int)msg);
-
- return DBUS_HANDLER_RESULT_HANDLED;
-
- } else if (dbus_message_is_method_call(msg,
- "org.bluez.PasskeyAgent", "Cancel")) {
+ if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED;
- const char *adapter;
- const char *address;
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &adapter,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_INVALID)) {
- LOGE("%s: Invalid arguments for Cancel() method", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
+ nat->vm->GetEnv((void**)&env, nat->envVer);
+ env->PushLocalFrame(EVENT_LOOP_REFS);
- LOGV("... address = %s", address);
+ if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "Cancel")) {
- env->CallVoidMethod(nat->me, method_onPasskeyAgentCancel,
- env->NewStringUTF(address));
+ env->CallVoidMethod(nat->me, method_onAgentCancel);
// reply
DBusMessage *reply = dbus_message_new_method_return(msg);
if (!reply) {
LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
-
- } else if (dbus_message_is_method_call(msg,
- "org.bluez.PasskeyAgent", "Release")) {
- LOGW("We are no longer the passkey agent!");
+ goto success;
- // reply
- DBusMessage *reply = dbus_message_new_method_return(msg);
- if (!reply) {
- LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
- dbus_connection_send(nat->conn, reply, NULL);
- dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
} else if (dbus_message_is_method_call(msg,
- "org.bluez.AuthorizationAgent", "Authorize")) {
- const char *adapter;
- const char *address;
- const char *service;
+ "org.bluez.Agent", "Authorize")) {
+ char *object_path;
const char *uuid;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &adapter,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_STRING, &service,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
DBUS_TYPE_STRING, &uuid,
DBUS_TYPE_INVALID)) {
LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
- LOGV("... address = %s", address);
- LOGV("... service = %s", service);
+ LOGV("... object_path = %s", object_path);
LOGV("... uuid = %s", uuid);
- bool auth_granted = env->CallBooleanMethod(nat->me,
- method_onAuthAgentAuthorize, env->NewStringUTF(address),
- env->NewStringUTF(service), env->NewStringUTF(uuid));
+ bool auth_granted =
+ env->CallBooleanMethod(nat->me, method_onAgentAuthorize,
+ env->NewStringUTF(object_path), env->NewStringUTF(uuid));
// reply
if (auth_granted) {
DBusMessage *reply = dbus_message_new_method_return(msg);
if (!reply) {
LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
@@ -983,64 +867,83 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn,
"org.bluez.Error.Rejected", "Authorization rejected");
if (!reply) {
LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
}
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else if (dbus_message_is_method_call(msg,
- "org.bluez.AuthorizationAgent", "Cancel")) {
- const char *adapter;
- const char *address;
- const char *service;
- const char *uuid;
+ "org.bluez.Agent", "RequestPinCode")) {
+ char *object_path;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &adapter,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_STRING, &service,
- DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
DBUS_TYPE_INVALID)) {
- LOGE("%s: Invalid arguments for Cancel() method", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
+ goto failure;
}
- LOGV("... address = %s", address);
- LOGV("... service = %s", service);
- LOGV("... uuid = %s", uuid);
-
- env->CallVoidMethod(nat->me,
- method_onAuthAgentCancel, env->NewStringUTF(address),
- env->NewStringUTF(service), env->NewStringUTF(uuid));
-
- // reply
- DBusMessage *reply = dbus_message_new_method_return(msg);
- if (!reply) {
- LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestPinCode,
+ env->NewStringUTF(object_path),
+ int(msg));
+ goto success;
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "RequestPasskey")) {
+ char *object_path;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
+ goto failure;
}
- dbus_connection_send(nat->conn, reply, NULL);
- dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestPasskey,
+ env->NewStringUTF(object_path),
+ int(msg));
+ goto success;
} else if (dbus_message_is_method_call(msg,
- "org.bluez.AuthorizationAgent", "Release")) {
- LOGW("We are no longer the auth agent!");
+ "org.bluez.Agent", "RequestConfirmation")) {
+ char *object_path;
+ uint32_t passkey;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_UINT32, &passkey,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
+ goto failure;
+ }
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestConfirmation,
+ env->NewStringUTF(object_path),
+ passkey,
+ int(msg));
+ goto success;
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "Release")) {
// reply
DBusMessage *reply = dbus_message_new_method_return(msg);
if (!reply) {
LOGE("%s: Cannot create message reply\n", __FUNCTION__);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto failure;
}
dbus_connection_send(nat->conn, reply, NULL);
dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
+ goto success;
} else {
- LOGV("... ignored");
+ LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg));
}
+failure:
+ env->PopLocalFrame(NULL);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+success:
+ env->PopLocalFrame(NULL);
+ return DBUS_HANDLER_RESULT_HANDLED;
+
}
#endif
@@ -1055,7 +958,7 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn,
#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
-void onCreateBondingResult(DBusMessage *msg, void *user, void *n) {
+void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
LOGV(__FUNCTION__);
native_data_t *nat = (native_data_t *)n;
@@ -1106,7 +1009,7 @@ void onCreateBondingResult(DBusMessage *msg, void *user, void *n) {
}
env->CallVoidMethod(nat->me,
- method_onCreateBondingResult,
+ method_onCreatePairedDeviceResult,
env->NewStringUTF(address),
result);
done:
@@ -1114,7 +1017,7 @@ done:
free(user);
}
-void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *n) {
+void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
LOGV(__FUNCTION__);
const char *address = (const char *) user;
@@ -1133,14 +1036,13 @@ void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *n) {
!dbus_message_get_args(msg, &err,
DBUS_TYPE_INT32, &channel,
DBUS_TYPE_INVALID)) {
- /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
dbus_error_free(&err);
}
done:
env->CallVoidMethod(nat->me,
- method_onGetRemoteServiceChannelResult,
+ method_onGetDeviceServiceChannelResult,
env->NewStringUTF(address),
channel);
free(user);
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
new file mode 100644
index 0000000..d1901b4
--- /dev/null
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -0,0 +1,750 @@
+/*
+** 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 DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
+#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
+#define LOG_TAG "BluetoothService.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 <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#include <bluedroid/bluetooth.h>
+#endif
+
+#include <cutils/properties.h>
+
+namespace android {
+
+#define BLUETOOTH_CLASS_ERROR 0xFF000000
+#define PROPERTIES_NREFS 10
+
+#ifdef HAVE_BLUETOOTH
+// We initialize these variables when we load class
+// android.server.BluetoothService
+static jfieldID field_mNativeData;
+static jfieldID field_mEventLoop;
+
+typedef struct {
+ JNIEnv *env;
+ DBusConnection *conn;
+ const char *adapter; // dbus object name of the local adapter
+} native_data_t;
+
+extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *,
+ jobject);
+extern DBusHandlerResult agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data);
+void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
+
+
+/** Get native data stored in the opaque (Java code maintained) pointer mNativeData
+ * Perform quick sanity check, if there are any problems return NULL
+ */
+static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
+ native_data_t *nat =
+ (native_data_t *)(env->GetIntField(object, field_mNativeData));
+ if (nat == NULL || nat->conn == NULL) {
+ LOGE("Uninitialized native data\n");
+ return NULL;
+ }
+ return nat;
+}
+#endif
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ field_mNativeData = get_field(env, clazz, "mNativeData", "I");
+ field_mEventLoop = get_field(env, clazz, "mEventLoop",
+ "Landroid/server/BluetoothEventLoop;");
+#endif
+}
+
+/* Returns true on success (even if adapter is present but disabled).
+ * Return false if dbus is down, or another serious error (out of memory)
+*/
+static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (NULL == nat) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return false;
+ }
+ nat->env = env;
+
+ env->SetIntField(object, field_mNativeData, (jint)nat);
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_threads_init_default();
+ nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set(&err)) {
+ LOGE("Could not get onto the system bus: %s", err.message);
+ dbus_error_free(&err);
+ return false;
+ }
+ dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
+#endif /*HAVE_BLUETOOTH*/
+ return true;
+}
+
+static const char *get_adapter_path(JNIEnv* env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ event_loop_native_data_t *event_nat =
+ get_EventLoop_native_data(env, env->GetObjectField(object,
+ field_mEventLoop));
+ if (event_nat == NULL)
+ return NULL;
+ return event_nat->adapter;
+#else
+ return NULL;
+#endif
+}
+
+// This function is called when the adapter is enabled.
+static jboolean setupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat =
+ (native_data_t *)env->GetIntField(object, field_mNativeData);
+ event_loop_native_data_t *event_nat =
+ get_EventLoop_native_data(env, env->GetObjectField(object,
+ field_mEventLoop));
+ // Register agent for remote devices.
+ const char *device_agent_path = "/android/bluetooth/remote_device_agent";
+ static const DBusObjectPathVTable agent_vtable = {
+ NULL, agent_event_filter, NULL, NULL, NULL, NULL };
+
+ if (!dbus_connection_register_object_path(nat->conn, device_agent_path,
+ &agent_vtable, event_nat)) {
+ LOGE("%s: Can't register object path %s for remote device agent!",
+ __FUNCTION__, device_agent_path);
+ return JNI_FALSE;
+ }
+#endif /*HAVE_BLUETOOTH*/
+ return JNI_TRUE;
+}
+
+static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat =
+ (native_data_t *)env->GetIntField(object, field_mNativeData);
+ if (nat != NULL) {
+ const char *device_agent_path =
+ "/android/bluetooth/remote_device_agent";
+ dbus_connection_unregister_object_path (nat->conn, device_agent_path);
+ }
+#endif /*HAVE_BLUETOOTH*/
+ return JNI_TRUE;
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat =
+ (native_data_t *)env->GetIntField(object, field_mNativeData);
+ if (nat) {
+ free(nat);
+ nat = NULL;
+ }
+#endif
+}
+
+static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ return (env->NewStringUTF(get_adapter_path(env, object)));
+ }
+#endif
+ return NULL;
+}
+
+
+static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError err;
+ const char *name;
+ jboolean ret = JNI_FALSE;
+
+ native_data_t *nat = get_native_data(env, object);
+ if (nat == NULL) {
+ goto done;
+ }
+
+ dbus_error_init(&err);
+
+ /* Compose the command */
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "StartDiscovery");
+
+ if (msg == NULL) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ }
+ goto done;
+ }
+
+ /* Send the command. */
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ ret = JNI_FALSE;
+ goto done;
+ }
+
+ ret = JNI_TRUE;
+done:
+ if (reply) dbus_message_unref(reply);
+ if (msg) dbus_message_unref(msg);
+ return ret;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static void stopDiscoveryNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ DBusError err;
+ const char *name;
+ jstring ret;
+ native_data_t *nat;
+
+ dbus_error_init(&err);
+
+ nat = get_native_data(env, object);
+ if (nat == NULL) {
+ goto done;
+ }
+
+ /* Compose the command */
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "StopDiscovery");
+ if (msg == NULL) {
+ if (dbus_error_is_set(&err))
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ goto done;
+ }
+
+ /* Send the command. */
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ if (dbus_error_is_set(&err)) {
+ if(strncmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized",
+ strlen(BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized")) == 0) {
+ // hcid sends this if there is no active discovery to cancel
+ LOGV("%s: There was no active discovery to cancel", __FUNCTION__);
+ dbus_error_free(&err);
+ } else {
+ LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ }
+ }
+
+done:
+ if (msg) dbus_message_unref(msg);
+ if (reply) dbus_message_unref(reply);
+#endif
+}
+
+static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
+ jstring address, jint timeout_ms) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+ struct event_loop_native_data_t *eventLoopNat =
+ get_EventLoop_native_data(env, eventLoop);
+
+ if (nat && eventLoopNat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ LOGV("... address = %s", c_address);
+ char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
+ const char *capabilities = "DisplayYesNo";
+ const char *agent_path = "/android/bluetooth/remote_device_agent";
+
+ strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
+ bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
+ onCreatePairedDeviceResult, // callback
+ context_address,
+ eventLoopNat,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE,
+ "CreatePairedDevice",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_OBJECT_PATH, &agent_path,
+ DBUS_TYPE_STRING, &capabilities,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return ret ? JNI_TRUE : JNI_FALSE;
+
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object,
+ jstring path,
+ jstring pattern, jint attr_id) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+ struct event_loop_native_data_t *eventLoopNat =
+ get_EventLoop_native_data(env, eventLoop);
+ if (nat && eventLoopNat) {
+ const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ LOGV("... pattern = %s", c_pattern);
+ LOGV("... attr_id = %#X", attr_id);
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, c_path,
+ DBUS_DEVICE_IFACE, "GetServiceAttributeValue",
+ DBUS_TYPE_STRING, &c_pattern,
+ DBUS_TYPE_UINT16, &attr_id,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(pattern, c_pattern);
+ env->ReleaseStringUTFChars(path, c_path);
+ return reply ? dbus_returns_int32(env, reply) : -1;
+ }
+#endif
+ return -1;
+}
+
+static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object,
+ jstring address) {
+ LOGV(__FUNCTION__);
+ jboolean result = JNI_FALSE;
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ DBusError err;
+ dbus_error_init(&err);
+ LOGV("... address = %s", c_address);
+ DBusMessage *reply =
+ dbus_func_args_timeout(env, nat->conn, -1,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "CancelDeviceCreation",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ } else
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return JNI_FALSE;
+ } else {
+ result = JNI_TRUE;
+ }
+ dbus_message_unref(reply);
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
+ LOGV(__FUNCTION__);
+ jboolean result = JNI_FALSE;
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
+ DBusError err;
+ dbus_error_init(&err);
+ DBusMessage *reply =
+ dbus_func_args_error(env, nat->conn, &err,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "RemoveDevice",
+ DBUS_TYPE_OBJECT_PATH, &c_object_path,
+ DBUS_TYPE_INVALID);
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ } else
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ result = JNI_FALSE;
+ } else {
+ result = JNI_TRUE;
+ }
+ env->ReleaseStringUTFChars(object_path, c_object_path);
+ if (reply) dbus_message_unref(reply);
+ }
+#endif
+ return result;
+}
+
+static jint enableNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ return bt_enable();
+#endif
+ return -1;
+}
+
+static jint disableNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ return bt_disable();
+#endif
+ return -1;
+}
+
+static jint isEnabledNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ return bt_is_enabled();
+#endif
+ return -1;
+}
+
+static jboolean setPairingConfirmationNative(JNIEnv *env, jobject object,
+ jstring address, bool confirm,
+ int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply;
+ if (confirm) {
+ reply = dbus_message_new_method_return(msg);
+ } else {
+ reply = dbus_message_new_error(msg,
+ "org.bluez.Error.Rejected", "User rejected confirmation");
+ }
+
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to RequestConfirmation to "
+ "D-Bus\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address,
+ int passkey, int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return Passkey code to "
+ "D-Bus\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32, (uint32_t *)&passkey,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
+ jstring pin, int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return PIN code to "
+ "D-Bus\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ const char *c_pin = env->GetStringUTFChars(pin, NULL);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ env->ReleaseStringUTFChars(pin, c_pin);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean cancelPairingUserInputNative(JNIEnv *env, jobject object,
+ jstring address, int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply = dbus_message_new_error(msg,
+ "org.bluez.Error.Canceled", "Pairing User Input was canceled");
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return cancelUserInput to"
+ "D-BUS\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object,
+ jstring path)
+{
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg, *reply;
+ DBusError err;
+ dbus_error_init(&err);
+
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ reply = dbus_func_args_timeout(env,
+ nat->conn, -1, c_path,
+ DBUS_DEVICE_IFACE, "GetProperties",
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(path, c_path);
+
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ } else
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return NULL;
+ }
+ env->PushLocalFrame(PROPERTIES_NREFS);
+
+ DBusMessageIter iter;
+ jobjectArray str_array = NULL;
+ if (dbus_message_iter_init(reply, &iter))
+ str_array = parse_remote_device_properties(env, &iter);
+ dbus_message_unref(reply);
+
+ env->PopLocalFrame(NULL);
+
+ return str_array;
+ }
+#endif
+ return NULL;
+}
+
+static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg, *reply;
+ DBusError err;
+ dbus_error_init(&err);
+
+ reply = dbus_func_args_timeout(env,
+ nat->conn, -1, get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "GetProperties",
+ DBUS_TYPE_INVALID);
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ } else
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return NULL;
+ }
+ env->PushLocalFrame(PROPERTIES_NREFS);
+
+ DBusMessageIter iter;
+ jobjectArray str_array = NULL;
+ if (dbus_message_iter_init(reply, &iter))
+ str_array = parse_adapter_properties(env, &iter);
+ dbus_message_unref(reply);
+
+ env->PopLocalFrame(NULL);
+ return str_array;
+ }
+#endif
+ return NULL;
+}
+
+static jboolean setAdapterPropertyNative(JNIEnv *env, jobject object, jstring key,
+ void *value, jint type) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *reply, *msg;
+ DBusMessageIter iter;
+ DBusError err;
+ const char *c_key = env->GetStringUTFChars(key, NULL);
+ dbus_error_init(&err);
+
+ msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "SetProperty");
+ if (!msg) {
+ LOGE("%s: Can't allocate new method call for GetProperties!",
+ __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID);
+ dbus_message_iter_init_append(msg, &iter);
+ append_variant(&iter, type, value);
+
+ reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
+ dbus_message_unref(msg);
+
+ env->ReleaseStringUTFChars(key, c_key);
+
+ if (!reply) {
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ } else
+ LOGE("DBus reply is NULL in function %s", __FUNCTION__);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean setAdapterPropertyStringNative(JNIEnv *env, jobject object, jstring key,
+ jstring value) {
+#ifdef HAVE_BLUETOOTH
+ const char *c_value = env->GetStringUTFChars(value, NULL);
+ jboolean ret = setAdapterPropertyNative(env, object, key, (void *)&c_value, DBUS_TYPE_STRING);
+ env->ReleaseStringUTFChars(value, (char *)c_value);
+ return ret;
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static jboolean setAdapterPropertyIntegerNative(JNIEnv *env, jobject object, jstring key,
+ jint value) {
+#ifdef HAVE_BLUETOOTH
+ return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_UINT32);
+#else
+ return JNI_FALSE;
+#endif
+}
+
+static jboolean setAdapterPropertyBooleanNative(JNIEnv *env, jobject object, jstring key,
+ jint value) {
+#ifdef HAVE_BLUETOOTH
+ return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_BOOLEAN);
+#else
+ return JNI_FALSE;
+#endif
+}
+
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"classInitNative", "()V", (void*)classInitNative},
+ {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
+ {"setupNativeDataNative", "()Z", (void *)setupNativeDataNative},
+ {"tearDownNativeDataNative", "()Z", (void *)tearDownNativeDataNative},
+ {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+ {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative},
+
+ {"isEnabledNative", "()I", (void *)isEnabledNative},
+ {"enableNative", "()I", (void *)enableNative},
+ {"disableNative", "()I", (void *)disableNative},
+
+ {"getAdapterPropertiesNative", "()[Ljava/lang/Object;", (void *)getAdapterPropertiesNative},
+ {"getDevicePropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
+ (void *)getDevicePropertiesNative},
+ {"setAdapterPropertyStringNative", "(Ljava/lang/String;Ljava/lang/String;)Z",
+ (void *)setAdapterPropertyStringNative},
+ {"setAdapterPropertyBooleanNative", "(Ljava/lang/String;I)Z",
+ (void *)setAdapterPropertyBooleanNative},
+ {"setAdapterPropertyIntegerNative", "(Ljava/lang/String;I)Z",
+ (void *)setAdapterPropertyIntegerNative},
+
+ {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative},
+ {"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative},
+
+ {"createPairedDeviceNative", "(Ljava/lang/String;I)Z", (void *)createPairedDeviceNative},
+ {"cancelDeviceCreationNative", "(Ljava/lang/String;)Z", (void *)cancelDeviceCreationNative},
+ {"removeDeviceNative", "(Ljava/lang/String;)Z", (void *)removeDeviceNative},
+ {"getDeviceServiceChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)I",
+ (void *)getDeviceServiceChannelNative},
+
+ {"setPairingConfirmationNative", "(Ljava/lang/String;ZI)Z",
+ (void *)setPairingConfirmationNative},
+ {"setPasskeyNative", "(Ljava/lang/String;II)Z", (void *)setPasskeyNative},
+ {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
+ {"cancelPairingUserInputNative", "(Ljava/lang/String;I)Z",
+ (void *)cancelPairingUserInputNative},
+};
+
+int register_android_server_BluetoothService(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/server/BluetoothService", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
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_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 5e5103a..34b7c89 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -51,17 +51,17 @@ struct ByteBuf {
size_t len;
size_t capacity;
uint8_t* buf;
-
+
ByteBuf(size_t initSize) {
buf = (uint8_t*)malloc(initSize);
len = 0;
- capacity = initSize;
+ capacity = initSize;
}
-
+
~ByteBuf() {
free(buf);
}
-
+
bool ensureExtraCapacity(size_t extra) {
size_t spaceNeeded = len + extra;
if (spaceNeeded > capacity) {
@@ -77,7 +77,7 @@ struct ByteBuf {
return true;
}
}
-
+
void putIntEvent(jint value) {
bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE);
buf[len++] = EVENT_TYPE_INT;
@@ -162,7 +162,7 @@ static jint android_util_EventLog_writeEvent_Integer(JNIEnv* env, jobject clazz,
* In class android.util.EventLog:
* static native int writeEvent(long tag, long value)
*/
-static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
+static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz,
jint tag, jlong value)
{
return android_btWriteLog(tag, EVENT_TYPE_LONG, &value, sizeof(value));
@@ -210,6 +210,8 @@ static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz,
/*
* In class android.util.EventLog:
* static native void readEvents(int[] tags, Collection<Event> output)
+ *
+ * Reads events from the event log, typically /dev/log/events
*/
static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
jintArray tags,
@@ -273,6 +275,80 @@ static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
env->ReleaseIntArrayElements(tags, tagValues, 0);
}
+/*
+ * In class android.util.EventLog:
+ * static native void readEvents(String path, Collection<Event> output)
+ *
+ * Reads events from a file (See Checkin.Aggregation). Events are stored in
+ * native raw format (logger_entry + payload).
+ */
+static void android_util_EventLog_readEventsFile(JNIEnv* env, jobject clazz, jstring path,
+ jobject out) {
+ if (path == NULL || out == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
+
+ const char *pathString = env->GetStringUTFChars(path, 0);
+ int fd = open(pathString, O_RDONLY | O_NONBLOCK);
+ env->ReleaseStringUTFChars(path, pathString);
+
+ if (fd < 0) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ uint8_t buf[LOGGER_ENTRY_MAX_LEN];
+ for (;;) {
+ // read log entry structure from file
+ int len = read(fd, buf, sizeof(logger_entry));
+ if (len == 0) {
+ break; // end of file
+ } else if (len < 0) {
+ jniThrowIOException(env, errno);
+ } else if ((size_t) len < sizeof(logger_entry)) {
+ jniThrowException(env, "java/io/IOException", "Event header too short");
+ break;
+ }
+
+ // read event payload
+ logger_entry* entry = (logger_entry*) buf;
+ if (entry->len > LOGGER_ENTRY_MAX_PAYLOAD) {
+ jniThrowException(env,
+ "java/lang/IllegalArgumentException",
+ "Too much data for event payload. Corrupt file?");
+ break;
+ }
+
+ len = read(fd, buf + sizeof(logger_entry), entry->len);
+ if (len == 0) {
+ break; // end of file
+ } else if (len < 0) {
+ jniThrowIOException(env, errno);
+ } else if ((size_t) len < entry->len) {
+ jniThrowException(env, "java/io/IOException", "Event payload too short");
+ break;
+ }
+
+ // create EventLog$Event and add it to the collection
+ int buffer_size = sizeof(logger_entry) + entry->len;
+ jbyteArray array = env->NewByteArray(buffer_size);
+ if (array == NULL) break;
+
+ jbyte *bytes = env->GetByteArrayElements(array, NULL);
+ memcpy(bytes, buf, buffer_size);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+
+ jobject event = env->NewObject(gEventClass, gEventInitID, array);
+ if (event == NULL) break;
+
+ env->CallBooleanMethod(out, gCollectionAddID, event);
+ env->DeleteLocalRef(event);
+ env->DeleteLocalRef(array);
+ }
+
+ close(fd);
+}
/*
* JNI registration.
@@ -292,6 +368,10 @@ static JNINativeMethod gRegisterMethods[] = {
{ "readEvents",
"([ILjava/util/Collection;)V",
(void*) android_util_EventLog_readEvents
+ },
+ { "readEvents",
+ "(Ljava/lang/String;Ljava/util/Collection;)V",
+ (void*) android_util_EventLog_readEventsFile
}
};
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 98fe0e65..723fd4b 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>
@@ -385,7 +385,7 @@ static int pid_compare(const void* v1, const void* v2)
return *((const jint*)v1) - *((const jint*)v2);
}
-jint android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
+static jlong android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
{
int fd = open("/proc/meminfo", O_RDONLY);
@@ -405,7 +405,7 @@ jint android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
buffer[len] = 0;
int numFound = 0;
- int mem = 0;
+ jlong mem = 0;
static const char* const sums[] = { "MemFree:", "Cached:", NULL };
static const int sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), NULL };
@@ -424,7 +424,7 @@ jint android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
p++;
if (*p == 0) p--;
}
- mem += atoi(num) * 1024;
+ mem += atoll(num) * 1024;
numFound++;
break;
}
@@ -874,7 +874,7 @@ static const JNINativeMethod methods[] = {
{"setGid", "(I)I", (void*)android_os_Process_setGid},
{"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
{"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
- {"getFreeMemory", "()I", (void*)android_os_Process_getFreeMemory},
+ {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
{"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
{"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
{"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 076775f..02677f4 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -24,6 +24,7 @@
#include <SkCanvas.h>
#include <SkBitmap.h>
+#include <SkRegion.h>
#include "jni.h"
#include <android_runtime/AndroidRuntime.h>
@@ -45,6 +46,7 @@ struct sso_t {
static sso_t sso;
struct so_t {
+ jfieldID surfaceControl;
jfieldID surface;
jfieldID saveCount;
jfieldID canvas;
@@ -121,10 +123,50 @@ static void SurfaceSession_kill(JNIEnv* env, jobject clazz)
// ----------------------------------------------------------------------------
+static sp<SurfaceControl> getSurfaceControl(JNIEnv* env, jobject clazz)
+{
+ SurfaceControl* const p =
+ (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+ return sp<SurfaceControl>(p);
+}
+
+static void setSurfaceControl(JNIEnv* env, jobject clazz,
+ const sp<SurfaceControl>& surface)
+{
+ SurfaceControl* const p =
+ (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+ if (surface.get()) {
+ surface->incStrong(clazz);
+ }
+ if (p) {
+ p->decStrong(clazz);
+ }
+ env->SetIntField(clazz, so.surfaceControl, (int)surface.get());
+}
+
static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
{
- Surface* const p = (Surface*)env->GetIntField(clazz, so.surface);
- return sp<Surface>(p);
+ sp<Surface> result((Surface*)env->GetIntField(clazz, so.surface));
+ if (result == 0) {
+ /*
+ * if this method is called from the WindowManager's process, it means
+ * the client is is not remote, and therefore is allowed to have
+ * a Surface (data), so we create it here.
+ * If we don't have a SurfaceControl, it means we're in a different
+ * process.
+ */
+
+ SurfaceControl* const control =
+ (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
+ if (control) {
+ result = control->getSurface();
+ if (result != 0) {
+ result->incStrong(clazz);
+ env->SetIntField(clazz, so.surface, (int)result.get());
+ }
+ }
+ }
+ return result;
}
static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
@@ -153,12 +195,12 @@ static void Surface_init(
SurfaceComposerClient* client =
(SurfaceComposerClient*)env->GetIntField(session, sso.client);
- sp<Surface> surface(client->createSurface(pid, dpy, w, h, format, flags));
+ sp<SurfaceControl> surface(client->createSurface(pid, dpy, w, h, format, flags));
if (surface == 0) {
doThrow(env, OutOfResourcesException);
return;
}
- setSurface(env, clazz, surface);
+ setSurfaceControl(env, clazz, surface);
}
static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
@@ -168,28 +210,44 @@ static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
doThrow(env, "java/lang/NullPointerException", NULL);
return;
}
- const sp<Surface>& rhs = Surface::readFromParcel(parcel);
+ sp<Surface> rhs = new Surface(*parcel);
setSurface(env, clazz, rhs);
}
static void Surface_clear(JNIEnv* env, jobject clazz, uintptr_t *ostack)
{
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (SurfaceControl::isValid(surface)) {
+ surface->clear();
+ }
+ setSurfaceControl(env, clazz, 0);
+ setSurface(env, clazz, 0);
+}
+
+static void Surface_release(JNIEnv* env, jobject clazz, uintptr_t *ostack)
+{
+ setSurfaceControl(env, clazz, 0);
setSurface(env, clazz, 0);
}
static jboolean Surface_isValid(JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- return surface->isValid() ? JNI_TRUE : JNI_FALSE;
+ const sp<SurfaceControl>& surfaceControl(getSurfaceControl(env, clazz));
+ if (surfaceControl != 0) {
+ return SurfaceControl::isValid(surfaceControl) ? JNI_TRUE : JNI_FALSE;
+ }
+ const sp<Surface>& surface(getSurface(env, clazz));
+ return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE;
}
static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
{
- /* note: if PIXEL_FORMAT_XRGB_8888 means that all alpha bytes are 0xFF, then
+ /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
we can map to SkBitmap::kARGB_8888_Config, and optionally call
bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
*/
switch (format) {
+ case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config;
case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config;
case PIXEL_FORMAT_RGBA_4444: return SkBitmap::kARGB_4444_Config;
case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config;
@@ -200,8 +258,8 @@ static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (!surface->isValid())
+ const sp<Surface>& surface(getSurface(env, clazz));
+ if (!Surface::isValid(surface))
return 0;
// get dirty region
@@ -212,7 +270,7 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
dirty.top = env->GetIntField(dirtyRect, ro.t);
dirty.right = env->GetIntField(dirtyRect, ro.r);
dirty.bottom= env->GetIntField(dirtyRect, ro.b);
- if (dirty.left < dirty.right && dirty.top < dirty.bottom) {
+ if (!dirty.isEmpty()) {
dirtyRegion.set(dirty);
}
} else {
@@ -235,7 +293,11 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
SkBitmap bitmap;
- bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, info.bpr);
+ ssize_t bpr = info.s * bytesPerPixel(info.format);
+ bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
+ if (info.format == PIXEL_FORMAT_RGBX_8888) {
+ bitmap.setIsOpaque(true);
+ }
if (info.w > 0 && info.h > 0) {
bitmap.setPixels(info.bits);
} else {
@@ -243,13 +305,27 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
bitmap.setPixels(NULL);
}
nativeCanvas->setBitmapDevice(bitmap);
- nativeCanvas->clipRegion(dirtyRegion.toSkRegion());
+
+ SkRegion clipReg;
+ if (dirtyRegion.isRect()) { // very common case
+ const Rect& b(dirtyRegion.getBounds());
+ clipReg.setRect(b.left, b.top, b.right, b.bottom);
+ } else {
+ size_t count;
+ Rect const* r = dirtyRegion.getArray(&count);
+ while (count) {
+ clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);
+ r++, count--;
+ }
+ }
+
+ nativeCanvas->clipRegion(clipReg);
int saveCount = nativeCanvas->save();
env->SetIntField(clazz, so.saveCount, saveCount);
if (dirtyRect) {
- Rect bounds(dirtyRegion.bounds());
+ const Rect& bounds(dirtyRegion.getBounds());
env->SetIntField(dirtyRect, ro.l, bounds.left);
env->SetIntField(dirtyRect, ro.t, bounds.top);
env->SetIntField(dirtyRect, ro.r, bounds.right);
@@ -268,8 +344,8 @@ static void Surface_unlockCanvasAndPost(
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- if (!surface->isValid())
+ const sp<Surface>& surface(getSurface(env, clazz));
+ if (!Surface::isValid(surface))
return;
// detach the canvas from the surface
@@ -289,26 +365,8 @@ static void Surface_unlockCanvasAndPost(
static void Surface_unlockCanvas(
JNIEnv* env, jobject clazz, jobject argCanvas)
{
- jobject canvas = env->GetObjectField(clazz, so.canvas);
- if (canvas != argCanvas) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
-
- const sp<Surface>& surface = getSurface(env, clazz);
- if (!surface->isValid())
- return;
-
- status_t err = surface->unlock();
- if (err < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
- SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
- int saveCount = env->GetIntField(clazz, so.saveCount);
- nativeCanvas->restoreToCount(saveCount);
- nativeCanvas->setBitmapDevice(SkBitmap());
- env->SetIntField(clazz, so.saveCount, 0);
+ // XXX: this API has been removed
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_openTransaction(
@@ -353,138 +411,140 @@ static void Surface_unfreezeDisplay(
static void Surface_setLayer(
JNIEnv* env, jobject clazz, jint zorder)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setLayer(zorder) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setLayer(zorder);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setPosition(
JNIEnv* env, jobject clazz, jint x, jint y)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setPosition(x, y) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setPosition(x, y);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setSize(
JNIEnv* env, jobject clazz, jint w, jint h)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setSize(w, h) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setSize(w, h);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_hide(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->hide() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->hide();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_show(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->show() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->show();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_freeze(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->freeze() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->freeze();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_unfreeze(
JNIEnv* env, jobject clazz)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->unfreeze() < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->unfreeze();
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setFlags(
JNIEnv* env, jobject clazz, jint flags, jint mask)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setFlags(flags, mask) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setFlags(flags, mask);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setTransparentRegion(
JNIEnv* env, jobject clazz, jobject argRegion)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region);
- if (surface->setTransparentRegionHint(Region(*nativeRegion)) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region);
+
+ const SkIRect& b(nativeRegion->getBounds());
+ Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
+ if (nativeRegion->isComplex()) {
+ SkRegion::Iterator it(*nativeRegion);
+ while (!it.done()) {
+ const SkIRect& r(it.rect());
+ reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
+ it.next();
}
}
+
+ status_t err = surface->setTransparentRegionHint(reg);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setAlpha(
JNIEnv* env, jobject clazz, jfloat alpha)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setAlpha(alpha) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setAlpha(alpha);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setMatrix(
JNIEnv* env, jobject clazz,
jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setMatrix(dsdx, dtdx, dsdy, dtdy) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setMatrix(dsdx, dtdx, dsdy, dtdy);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
static void Surface_setFreezeTint(
JNIEnv* env, jobject clazz,
jint tint)
{
- const sp<Surface>& surface = getSurface(env, clazz);
- if (surface->isValid()) {
- if (surface->setFreezeTint(tint) < 0) {
- doThrow(env, "java/lang/IllegalArgumentException", NULL);
- }
- }
+ const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
+ if (surface == 0) return;
+ status_t err = surface->setFreezeTint(tint);
+ if (err<0 && err!=NO_INIT)
+ doThrow(env, "java/lang/IllegalArgumentException", NULL);
}
+// ----------------------------------------------------------------------------
+
static void Surface_copyFrom(
JNIEnv* env, jobject clazz, jobject other)
{
@@ -496,16 +556,21 @@ static void Surface_copyFrom(
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- const sp<Surface>& rhs = getSurface(env, other);
- if (!Surface::isSameSurface(surface, rhs)) {
+ /*
+ * This is used by the WindowManagerService just after constructing
+ * a Surface and is necessary for returning the Surface reference to
+ * the caller. At this point, we should only have a SurfaceControl.
+ */
+
+ const sp<SurfaceControl>& surface = getSurfaceControl(env, clazz);
+ const sp<SurfaceControl>& rhs = getSurfaceControl(env, other);
+ if (!SurfaceControl::isSameSurface(surface, rhs)) {
// we reassign the surface only if it's a different one
// otherwise we would loose our client-side state.
- setSurface(env, clazz, rhs->dup());
+ setSurfaceControl(env, clazz, rhs);
}
}
-
static void Surface_readFromParcel(
JNIEnv* env, jobject clazz, jobject argParcel)
{
@@ -515,9 +580,9 @@ static void Surface_readFromParcel(
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- const sp<Surface>& rhs = Surface::readFromParcel(parcel);
- if (!Surface::isSameSurface(surface, rhs)) {
+ const sp<Surface>& control(getSurface(env, clazz));
+ sp<Surface> rhs = new Surface(*parcel);
+ if (!Surface::isSameSurface(control, rhs)) {
// we reassign the surface only if it's a different one
// otherwise we would loose our client-side state.
setSurface(env, clazz, rhs);
@@ -535,8 +600,8 @@ static void Surface_writeToParcel(
return;
}
- const sp<Surface>& surface = getSurface(env, clazz);
- Surface::writeToParcel(surface, parcel);
+ const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
+ SurfaceControl::writeSurfaceToParcel(control, parcel);
}
// ----------------------------------------------------------------------------
@@ -557,7 +622,8 @@ static JNINativeMethod gSurfaceMethods[] = {
{"nativeClassInit", "()V", (void*)nativeClassInit },
{"init", "(Landroid/view/SurfaceSession;IIIIII)V", (void*)Surface_init },
{"init", "(Landroid/os/Parcel;)V", (void*)Surface_initParcel },
- {"clear", "()V", (void*)Surface_clear },
+ {"clear", "()V", (void*)Surface_clear },
+ {"release", "()V", (void*)Surface_release },
{"copyFrom", "(Landroid/view/Surface;)V", (void*)Surface_copyFrom },
{"isValid", "()Z", (void*)Surface_isValid },
{"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas },
@@ -586,7 +652,8 @@ static JNINativeMethod gSurfaceMethods[] = {
void nativeClassInit(JNIEnv* env, jclass clazz)
{
- so.surface = env->GetFieldID(clazz, "mSurface", "I");
+ so.surface = env->GetFieldID(clazz, "mSurface", "I");
+ so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I");
so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I");
so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;");
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 4452065..974fc0b 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -21,7 +21,6 @@
#include <EGL/egl.h>
#include <GLES/gl.h>
-#include <ui/EGLNativeWindowSurface.h>
#include <ui/Surface.h>
#include <SkBitmap.h>
#include <SkPixelRef.h>
@@ -338,7 +337,7 @@ not_valid_surface:
goto not_valid_surface;
jint* base = beginNativeAttribList(_env, attrib_list);
- EGLSurface sur = eglCreateWindowSurface(dpy, cnf, new EGLNativeWindowSurface(window), base);
+ EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window, base);
endNativeAttributeList(_env, attrib_list, base);
return (jint)sur;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cf2184c..1ea5fa3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -25,7 +25,7 @@
<!-- Special broadcasts that only the system can send -->
<!-- ================================================ -->
<eat-comment />
-
+
<protected-broadcast android:name="android.intent.action.SCREEN_OFF" />
<protected-broadcast android:name="android.intent.action.SCREEN_ON" />
<protected-broadcast android:name="android.intent.action.USER_PRESENT" />
@@ -51,12 +51,12 @@
<protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_OK" />
<protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" />
<protected-broadcast android:name="android.intent.action.REBOOT" />
-
+
<!-- ====================================== -->
<!-- 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,
@@ -85,7 +85,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
@@ -135,7 +135,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
@@ -189,8 +189,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"
@@ -226,7 +226,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"
@@ -271,7 +271,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
@@ -308,11 +308,19 @@
android:description="@string/permdesc_bluetooth"
android:label="@string/permlab_bluetooth" />
+ <!-- Allows applications to call into AccountAuthenticators. Only
+ the system can get this permission. -->
+ <permission android:name="android.permission.ACCOUNT_MANAGER_SERVICE"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="signature"
+ android:description="@string/permdesc_accountManagerService"
+ android:label="@string/permlab_accountManagerService" />
+
<!-- ================================== -->
<!-- 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
@@ -329,11 +337,33 @@
android:description="@string/permdesc_getAccounts"
android:label="@string/permlab_getAccounts" />
+ <!-- Allows an application to act as an AccountAuthenticator for
+ the AccountManager -->
+ <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_authenticateAccounts"
+ android:description="@string/permdesc_authenticateAccounts" />
+
+ <!-- Allows an application to request authtokens from the AccountManager -->
+ <permission android:name="android.permission.USE_CREDENTIALS"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_useCredentials"
+ android:description="@string/permdesc_useCredentials" />
+
+ <!-- Allows an application to manage the list of accounts in the AccountManager -->
+ <permission android:name="android.permission.MANAGE_ACCOUNTS"
+ android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_manageAccounts"
+ android:description="@string/permdesc_manageAccounts" />
+
<!-- ================================== -->
<!-- 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"
@@ -386,7 +416,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
@@ -440,7 +470,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
@@ -664,7 +694,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"
@@ -676,7 +706,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"
@@ -727,7 +757,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
@@ -863,6 +893,13 @@
android:description="@string/permdesc_bindInputMethod"
android:protectionLevel="signature" />
+ <!-- Must be required by wallpaper services, to ensure that only the
+ system can bind to them. -->
+ <permission android:name="android.permission.BIND_WALLPAPER"
+ android:label="@string/permlab_bindWallpaper"
+ android:description="@string/permdesc_bindWallpaper"
+ android:protectionLevel="signatureOrSystem" />
+
<!-- Allows low-level access to setting the orientation (actually
rotation) of the screen. Not for use by normal applications. -->
<permission android:name="android.permission.SET_ORIENTATION"
@@ -974,6 +1011,12 @@
android:description="@string/permdesc_callPrivileged"
android:protectionLevel="signatureOrSystem" />
+ <!-- Allows an application to perform CDMA OTA provisioning @hide -->
+ <permission android:name="android.permission.PERFORM_CDMA_PROVISIONING"
+ android:label="@string/permlab_performCdmaProvisioning"
+ android:description="@string/permdesc_performCdmaProvisioning"
+ android:protectionLevel="signatureOrSystem" />
+
<!-- Allows enabling/disabling location update notifications from
the radio. Not for use by normal applications. -->
<permission android:name="android.permission.CONTROL_LOCATION_UPDATES"
@@ -1008,6 +1051,13 @@
android:description="@string/permdesc_backup"
android:protectionLevel="signatureOrSystem" />
+ <!-- Allows an application to participate in the backup and restore process
+ @hide -->
+ <permission android:name="android.permission.BACKUP_DATA"
+ android:label="@string/permlab_backup_data"
+ android:description="@string/permdesc_backup_data"
+ android:protectionLevel="signatureOrSystem" />
+
<!-- Allows an application to tell the AppWidget service which application
can access AppWidget's data. The normal user flow is that a user
picks an AppWidget to go into a particular host, thereby giving that
@@ -1051,12 +1101,18 @@
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature" />
+ <!-- Allows applications to set a live wallpaper.
+ @hide -->
+ <permission android:name="android.permission.SET_WALLPAPER_COMPONENT"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
android:label="@string/android_system_label"
android:allowClearUserData="false"
- android:backupAgent="com.android.internal.backup.SystemBackupAgent"
+ android:backupAgent="com.android.server.SystemBackupAgent"
android:icon="@drawable/ic_launcher_android">
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.Dialog.Alert"
@@ -1089,8 +1145,35 @@
android:excludeFromRecents="true">
</activity>
+ <activity android:name="android.accounts.ChooseAccountActivity"
+ android:excludeFromRecents="true"
+ android:exported="true">
+ </activity>
+
+ <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
+ android:excludeFromRecents="true"
+ android:exported="true">
+ </activity>
+
+ <activity android:name="com.android.server.ShutdownActivity"
+ android:permission="android.permission.SHUTDOWN"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.ACTION_REQUEST_SHUTDOWN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ <activity android:name="com.android.internal.app.NetInitiatedActivity"
+ android:theme="@style/Theme.Dialog.Alert"
+ android:excludeFromRecents="true">
+ </activity>
+
<service android:name="com.android.server.LoadAverageService"
- android:exported="true" />
+ android:exported="true" />
+
+ <service android:name="com.android.internal.service.wallpaper.ImageWallpaper"
+ android:permission="android.permission.BIND_WALLPAPER">
+ </service>
<receiver android:name="com.android.server.BootReceiver" >
<intent-filter>
@@ -1101,7 +1184,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/anim/wallpaper_activity_close_enter.xml b/core/res/res/anim/wallpaper_activity_close_enter.xml
new file mode 100644
index 0000000..9e9bd80
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_close_enter.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator"
+ android:zAdjustment="top">
+ <scale android:fromXScale="2.0" android:toXScale="1.0"
+ android:fromYScale="2.0" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <translate android:fromXDelta="-150%" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/anim/wallpaper_activity_close_exit.xml b/core/res/res/anim/wallpaper_activity_close_exit.xml
new file mode 100644
index 0000000..badbbf0
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_close_exit.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator">
+ <scale android:fromXScale="1.0" android:toXScale=".5"
+ android:fromYScale="1.0" android:toYScale=".5"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <translate android:fromXDelta="0%" android:toXDelta="100%"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/wallpaper_activity_open_enter.xml b/core/res/res/anim/wallpaper_activity_open_enter.xml
new file mode 100644
index 0000000..e60bac2
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_open_enter.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator">
+ <scale android:fromXScale=".5" android:toXScale="1.0"
+ android:fromYScale=".5" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <translate android:fromXDelta="100%" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/anim/wallpaper_activity_open_exit.xml b/core/res/res/anim/wallpaper_activity_open_exit.xml
new file mode 100644
index 0000000..01abbb7
--- /dev/null
+++ b/core/res/res/anim/wallpaper_activity_open_exit.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator"
+ android:zAdjustment="top">
+ <scale android:fromXScale="1.0" android:toXScale="2.0"
+ android:fromYScale="1.0" android:toYScale="2.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <translate android:fromXDelta="0" android:toXDelta="-150%"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/wallpaper_enter.xml b/core/res/res/anim/wallpaper_enter.xml
new file mode 100644
index 0000000..981f5f6
--- /dev/null
+++ b/core/res/res/anim/wallpaper_enter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator">
+ <scale android:fromXScale="3.0" android:toXScale="1.0"
+ android:fromYScale="3.0" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_longAnimTime" />
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime" />
+</set>
diff --git a/core/res/res/anim/wallpaper_exit.xml b/core/res/res/anim/wallpaper_exit.xml
new file mode 100644
index 0000000..2306071
--- /dev/null
+++ b/core/res/res/anim/wallpaper_exit.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/options_panel_exit.xml
+**
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator">
+ <scale android:fromXScale="1.0" android:toXScale="3.0"
+ android:fromYScale="1.0" android:toYScale="3.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_longAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_longAnimTime"/>
+</set>
diff --git a/core/res/res/color/tab_indicator_text.xml b/core/res/res/color/tab_indicator_text.xml
index ce321db..5f5c2a4 100644
--- a/core/res/res/color/tab_indicator_text.xml
+++ b/core/res/res/color/tab_indicator_text.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_selected="true" android:color="#323232"/>
- <item android:color="#FFF"/> <!-- not selected -->
+ <item android:state_selected="true" android:color="#ffffff"/>
+ <item android:color="#808080"/> <!-- not selected -->
</selector>
diff --git a/core/res/res/drawable-hdpi/activity_title_bar.9.png b/core/res/res/drawable-hdpi/activity_title_bar.9.png
new file mode 100644
index 0000000..48d60c4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/activity_title_bar.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/arrow_down_float.png b/core/res/res/drawable-hdpi/arrow_down_float.png
new file mode 100644
index 0000000..2466c8f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/arrow_down_float.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/arrow_up_float.png b/core/res/res/drawable-hdpi/arrow_up_float.png
new file mode 100644
index 0000000..d1301c3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/arrow_up_float.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/battery_charge_background.png b/core/res/res/drawable-hdpi/battery_charge_background.png
new file mode 100644
index 0000000..19023a9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/battery_charge_background.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/battery_charge_fill_empty.9.png b/core/res/res/drawable-hdpi/battery_charge_fill_empty.9.png
new file mode 100644
index 0000000..c4e70a8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/battery_charge_fill_empty.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/battery_charge_fill_full.9.png b/core/res/res/drawable-hdpi/battery_charge_fill_full.9.png
new file mode 100644
index 0000000..ac66f5a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/battery_charge_fill_full.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/battery_charge_fill_warning.9.png b/core/res/res/drawable-hdpi/battery_charge_fill_warning.9.png
new file mode 100644
index 0000000..32d99c6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/battery_charge_fill_warning.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/battery_low_battery.png b/core/res/res/drawable-hdpi/battery_low_battery.png
new file mode 100644
index 0000000..d894f7b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/battery_low_battery.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/blank_tile.png b/core/res/res/drawable-hdpi/blank_tile.png
new file mode 100644
index 0000000..e2a386c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/blank_tile.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/bottom_bar.png b/core/res/res/drawable-hdpi/bottom_bar.png
new file mode 100644
index 0000000..1f38f3c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/bottom_bar.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_buttonless_off.png b/core/res/res/drawable-hdpi/btn_check_buttonless_off.png
new file mode 100644
index 0000000..baf9010
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_buttonless_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_buttonless_on.png b/core/res/res/drawable-hdpi/btn_check_buttonless_on.png
new file mode 100644
index 0000000..2a77e4c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_buttonless_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_label_background.9.png b/core/res/res/drawable-hdpi/btn_check_label_background.9.png
new file mode 100644
index 0000000..97e6806
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_label_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off.png b/core/res/res/drawable-hdpi/btn_check_off.png
new file mode 100644
index 0000000..aad9ef7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable.png b/core/res/res/drawable-hdpi/btn_check_off_disable.png
new file mode 100644
index 0000000..eaee9e0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png b/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
new file mode 100644
index 0000000..6d2c293
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed.png b/core/res/res/drawable-hdpi/btn_check_off_pressed.png
new file mode 100644
index 0000000..1c442e9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_selected.png b/core/res/res/drawable-hdpi/btn_check_off_selected.png
new file mode 100644
index 0000000..b852b2c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on.png b/core/res/res/drawable-hdpi/btn_check_on.png
new file mode 100644
index 0000000..cd5c181
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable.png b/core/res/res/drawable-hdpi/btn_check_on_disable.png
new file mode 100644
index 0000000..b4fc51a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png b/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
new file mode 100644
index 0000000..bf34647
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed.png b/core/res/res/drawable-hdpi/btn_check_on_pressed.png
new file mode 100644
index 0000000..fa5c7a2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_selected.png b/core/res/res/drawable-hdpi/btn_check_on_selected.png
new file mode 100644
index 0000000..a6a21ad
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_circle_disable.png b/core/res/res/drawable-hdpi/btn_circle_disable.png
new file mode 100644
index 0000000..d829716
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_circle_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_circle_disable_focused.png b/core/res/res/drawable-hdpi/btn_circle_disable_focused.png
new file mode 100644
index 0000000..c1b5b6e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_circle_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_circle_normal.png b/core/res/res/drawable-hdpi/btn_circle_normal.png
new file mode 100644
index 0000000..bf3fb5a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_circle_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_circle_pressed.png b/core/res/res/drawable-hdpi/btn_circle_pressed.png
new file mode 100644
index 0000000..50e22e6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_circle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_circle_selected.png b/core/res/res/drawable-hdpi/btn_circle_selected.png
new file mode 100644
index 0000000..cfc68fb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_circle_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_close_normal.png b/core/res/res/drawable-hdpi/btn_close_normal.png
new file mode 100644
index 0000000..df3d56c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_close_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_close_pressed.png b/core/res/res/drawable-hdpi/btn_close_pressed.png
new file mode 100644
index 0000000..ef88fe0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_close_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_default.png b/core/res/res/drawable-hdpi/btn_code_lock_default.png
new file mode 100644
index 0000000..df3137f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_touched.png b/core/res/res/drawable-hdpi/btn_code_lock_touched.png
new file mode 100644
index 0000000..bf9e46a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_normal.9.png b/core/res/res/drawable-hdpi/btn_default_normal.9.png
new file mode 100644
index 0000000..329ce6e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_normal_disable.9.png b/core/res/res/drawable-hdpi/btn_default_normal_disable.9.png
new file mode 100644
index 0000000..a518c6b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_normal_disable_focused.9.png b/core/res/res/drawable-hdpi/btn_default_normal_disable_focused.9.png
new file mode 100644
index 0000000..71a05b7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed.9.png b/core/res/res/drawable-hdpi/btn_default_pressed.9.png
new file mode 100644
index 0000000..d9d02bf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_selected.9.png b/core/res/res/drawable-hdpi/btn_default_selected.9.png
new file mode 100644
index 0000000..ab7c612
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_normal.9.png b/core/res/res/drawable-hdpi/btn_default_small_normal.9.png
new file mode 100644
index 0000000..baafed6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_small_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png b/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png
new file mode 100644
index 0000000..175197b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png b/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
new file mode 100644
index 0000000..ec1feff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png b/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png
new file mode 100644
index 0000000..c1f9a0f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_small_selected.9.png b/core/res/res/drawable-hdpi/btn_default_small_selected.9.png
new file mode 100644
index 0000000..0ea3f40
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_default_small_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dialog_disable.png b/core/res/res/drawable-hdpi/btn_dialog_disable.png
new file mode 100644
index 0000000..2fc5d1a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dialog_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dialog_normal.png b/core/res/res/drawable-hdpi/btn_dialog_normal.png
new file mode 100644
index 0000000..c4a1026
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dialog_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dialog_pressed.png b/core/res/res/drawable-hdpi/btn_dialog_pressed.png
new file mode 100644
index 0000000..846f8bf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dialog_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dialog_selected.png b/core/res/res/drawable-hdpi/btn_dialog_selected.png
new file mode 100644
index 0000000..659c289
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dialog_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png b/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png
new file mode 100644
index 0000000..9392495
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dropdown_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png b/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png
new file mode 100644
index 0000000..beaba45
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dropdown_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png b/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png
new file mode 100644
index 0000000..ec51fc9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dropdown_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_erase_default.9.png b/core/res/res/drawable-hdpi/btn_erase_default.9.png
new file mode 100644
index 0000000..30984f4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_erase_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_erase_pressed.9.png b/core/res/res/drawable-hdpi/btn_erase_pressed.9.png
new file mode 100644
index 0000000..a8225e8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_erase_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_erase_selected.9.png b/core/res/res/drawable-hdpi/btn_erase_selected.9.png
new file mode 100644
index 0000000..f020f77
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_erase_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_global_search_normal.9.png b/core/res/res/drawable-hdpi/btn_global_search_normal.9.png
new file mode 100644
index 0000000..5bec4f8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_global_search_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_normal.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_normal.9.png
new file mode 100644
index 0000000..5697369
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png
new file mode 100644
index 0000000..9940245
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_normal_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png
new file mode 100644
index 0000000..5a26d83
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_normal_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_pressed.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_pressed.9.png
new file mode 100644
index 0000000..089dbf3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png
new file mode 100644
index 0000000..c10a3db
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_pressed_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png b/core/res/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png
new file mode 100644
index 0000000..9e83ace
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_keyboard_key_pressed_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_media_player.9.png b/core/res/res/drawable-hdpi/btn_media_player.9.png
new file mode 100644
index 0000000..bf16315
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_media_player.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_media_player_disabled.9.png b/core/res/res/drawable-hdpi/btn_media_player_disabled.9.png
new file mode 100644
index 0000000..d7b8ed5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_media_player_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_media_player_disabled_selected.9.png b/core/res/res/drawable-hdpi/btn_media_player_disabled_selected.9.png
new file mode 100644
index 0000000..1a35c31
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_media_player_disabled_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_media_player_pressed.9.png b/core/res/res/drawable-hdpi/btn_media_player_pressed.9.png
new file mode 100644
index 0000000..17dd3fc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_media_player_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_media_player_selected.9.png b/core/res/res/drawable-hdpi/btn_media_player_selected.9.png
new file mode 100644
index 0000000..a146d8f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_media_player_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_minus_default.png b/core/res/res/drawable-hdpi/btn_minus_default.png
new file mode 100644
index 0000000..f2831af
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_minus_default.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_minus_disable.png b/core/res/res/drawable-hdpi/btn_minus_disable.png
new file mode 100644
index 0000000..24ce695
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_minus_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_minus_disable_focused.png b/core/res/res/drawable-hdpi/btn_minus_disable_focused.png
new file mode 100644
index 0000000..e92c2b1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_minus_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_minus_pressed.png b/core/res/res/drawable-hdpi/btn_minus_pressed.png
new file mode 100644
index 0000000..ba2ed26
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_minus_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_minus_selected.png b/core/res/res/drawable-hdpi/btn_minus_selected.png
new file mode 100644
index 0000000..6b938b3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_minus_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_plus_default.png b/core/res/res/drawable-hdpi/btn_plus_default.png
new file mode 100644
index 0000000..441d1fb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_plus_default.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_plus_disable.png b/core/res/res/drawable-hdpi/btn_plus_disable.png
new file mode 100644
index 0000000..4e965c1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_plus_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_plus_disable_focused.png b/core/res/res/drawable-hdpi/btn_plus_disable_focused.png
new file mode 100644
index 0000000..0c938eb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_plus_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_plus_pressed.png b/core/res/res/drawable-hdpi/btn_plus_pressed.png
new file mode 100644
index 0000000..8dd5a68
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_plus_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_plus_selected.png b/core/res/res/drawable-hdpi/btn_plus_selected.png
new file mode 100644
index 0000000..8fe30ed
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_plus_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_label_background.9.png b/core/res/res/drawable-hdpi/btn_radio_label_background.9.png
new file mode 100644
index 0000000..45c5c6a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_label_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off.png b/core/res/res/drawable-hdpi/btn_radio_off.png
new file mode 100644
index 0000000..c0b14aa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
new file mode 100644
index 0000000..3189581
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_selected.png b/core/res/res/drawable-hdpi/btn_radio_off_selected.png
new file mode 100644
index 0000000..f337703
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on.png b/core/res/res/drawable-hdpi/btn_radio_on.png
new file mode 100644
index 0000000..c90d2eb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
new file mode 100644
index 0000000..d79450b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_selected.png b/core/res/res/drawable-hdpi/btn_radio_on_selected.png
new file mode 100644
index 0000000..db50c43
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_normal.png b/core/res/res/drawable-hdpi/btn_rating_star_off_normal.png
new file mode 100644
index 0000000..d119807
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed.png b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed.png
new file mode 100644
index 0000000..6f76da3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_selected.png b/core/res/res/drawable-hdpi/btn_rating_star_off_selected.png
new file mode 100644
index 0000000..566090d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_normal.png b/core/res/res/drawable-hdpi/btn_rating_star_on_normal.png
new file mode 100644
index 0000000..c55c1f6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed.png b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed.png
new file mode 100644
index 0000000..89b8161
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_selected.png b/core/res/res/drawable-hdpi/btn_rating_star_on_selected.png
new file mode 100644
index 0000000..1a76a26
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_search_dialog_default.9.png b/core/res/res/drawable-hdpi/btn_search_dialog_default.9.png
new file mode 100644
index 0000000..fe38843
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_search_dialog_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_search_dialog_pressed.9.png b/core/res/res/drawable-hdpi/btn_search_dialog_pressed.9.png
new file mode 100644
index 0000000..e673b27
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_search_dialog_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_search_dialog_selected.9.png b/core/res/res/drawable-hdpi/btn_search_dialog_selected.9.png
new file mode 100644
index 0000000..64b689d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_search_dialog_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_search_dialog_voice_default.9.png b/core/res/res/drawable-hdpi/btn_search_dialog_voice_default.9.png
new file mode 100644
index 0000000..f65fa14
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_search_dialog_voice_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_search_dialog_voice_pressed.9.png b/core/res/res/drawable-hdpi/btn_search_dialog_voice_pressed.9.png
new file mode 100644
index 0000000..17cc0dd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_search_dialog_voice_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_search_dialog_voice_selected.9.png b/core/res/res/drawable-hdpi/btn_search_dialog_voice_selected.9.png
new file mode 100644
index 0000000..0509e14
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_search_dialog_voice_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_square_overlay_disabled.png b/core/res/res/drawable-hdpi/btn_square_overlay_disabled.png
new file mode 100644
index 0000000..71a037e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_square_overlay_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_square_overlay_disabled_focused.png b/core/res/res/drawable-hdpi/btn_square_overlay_disabled_focused.png
new file mode 100644
index 0000000..a474605
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_square_overlay_disabled_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_square_overlay_normal.png b/core/res/res/drawable-hdpi/btn_square_overlay_normal.png
new file mode 100644
index 0000000..bf5da22
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_square_overlay_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_square_overlay_pressed.png b/core/res/res/drawable-hdpi/btn_square_overlay_pressed.png
new file mode 100644
index 0000000..52a302d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_square_overlay_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_square_overlay_selected.png b/core/res/res/drawable-hdpi/btn_square_overlay_selected.png
new file mode 100644
index 0000000..e065682
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_square_overlay_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_big_off.png b/core/res/res/drawable-hdpi/btn_star_big_off.png
new file mode 100644
index 0000000..4be0f5d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_big_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_big_off_disable.png b/core/res/res/drawable-hdpi/btn_star_big_off_disable.png
new file mode 100644
index 0000000..faba665
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_big_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_big_off_disable_focused.png b/core/res/res/drawable-hdpi/btn_star_big_off_disable_focused.png
new file mode 100644
index 0000000..fc8aca4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_big_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_big_off_pressed.png b/core/res/res/drawable-hdpi/btn_star_big_off_pressed.png
new file mode 100644
index 0000000..b8c8e70
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_big_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_big_off_selected.png b/core/res/res/drawable-hdpi/btn_star_big_off_selected.png
new file mode 100644
index 0000000..86250bb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_big_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_big_on.png b/core/res/res/drawable-hdpi/btn_star_big_on.png
new file mode 100644
index 0000000..4213050
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_big_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_big_on_disable.png b/core/res/res/drawable-hdpi/btn_star_big_on_disable.png
new file mode 100644
index 0000000..5629849
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_big_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_big_on_disable_focused.png b/core/res/res/drawable-hdpi/btn_star_big_on_disable_focused.png
new file mode 100644
index 0000000..cb9f79c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_big_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_big_on_pressed.png b/core/res/res/drawable-hdpi/btn_star_big_on_pressed.png
new file mode 100644
index 0000000..648cd1b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_big_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_big_on_selected.png b/core/res/res/drawable-hdpi/btn_star_big_on_selected.png
new file mode 100644
index 0000000..cb15673
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_big_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_label_background.9.png b/core/res/res/drawable-hdpi/btn_star_label_background.9.png
new file mode 100644
index 0000000..6008067
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_star_label_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off.9.png b/core/res/res/drawable-hdpi/btn_toggle_off.9.png
new file mode 100644
index 0000000..9e141d8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_toggle_off.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on.9.png b/core/res/res/drawable-hdpi/btn_toggle_on.9.png
new file mode 100644
index 0000000..dba2fa5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_toggle_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_down_disabled.9.png b/core/res/res/drawable-hdpi/btn_zoom_down_disabled.9.png
new file mode 100644
index 0000000..6441f4d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_down_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_down_disabled_focused.9.png b/core/res/res/drawable-hdpi/btn_zoom_down_disabled_focused.9.png
new file mode 100644
index 0000000..cfb0613
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_down_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_down_normal.9.png b/core/res/res/drawable-hdpi/btn_zoom_down_normal.9.png
new file mode 100644
index 0000000..b30f834
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_down_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_down_pressed.9.png b/core/res/res/drawable-hdpi/btn_zoom_down_pressed.9.png
new file mode 100644
index 0000000..4ff9910
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_down_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_down_selected.9.png b/core/res/res/drawable-hdpi/btn_zoom_down_selected.9.png
new file mode 100644
index 0000000..5542695
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_down_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_page_normal.png b/core/res/res/drawable-hdpi/btn_zoom_page_normal.png
new file mode 100644
index 0000000..15d60a0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_page_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_page_press.png b/core/res/res/drawable-hdpi/btn_zoom_page_press.png
new file mode 100644
index 0000000..28f437e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_page_press.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_up_disabled.9.png b/core/res/res/drawable-hdpi/btn_zoom_up_disabled.9.png
new file mode 100644
index 0000000..9813201
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_up_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_up_disabled_focused.9.png b/core/res/res/drawable-hdpi/btn_zoom_up_disabled_focused.9.png
new file mode 100644
index 0000000..8710c72
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_up_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_up_normal.9.png b/core/res/res/drawable-hdpi/btn_zoom_up_normal.9.png
new file mode 100644
index 0000000..763d271
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_up_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_up_pressed.9.png b/core/res/res/drawable-hdpi/btn_zoom_up_pressed.9.png
new file mode 100644
index 0000000..b77936a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_up_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_zoom_up_selected.9.png b/core/res/res/drawable-hdpi/btn_zoom_up_selected.9.png
new file mode 100644
index 0000000..a8e4af1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_zoom_up_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/button_onoff_indicator_off.png b/core/res/res/drawable-hdpi/button_onoff_indicator_off.png
new file mode 100644
index 0000000..9af36e9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/button_onoff_indicator_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/button_onoff_indicator_on.png b/core/res/res/drawable-hdpi/button_onoff_indicator_on.png
new file mode 100644
index 0000000..bde297e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/button_onoff_indicator_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/call_contact.png b/core/res/res/drawable-hdpi/call_contact.png
new file mode 100644
index 0000000..57fea24
--- /dev/null
+++ b/core/res/res/drawable-hdpi/call_contact.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/checkbox_off_background.png b/core/res/res/drawable-hdpi/checkbox_off_background.png
new file mode 100644
index 0000000..a8e4785
--- /dev/null
+++ b/core/res/res/drawable-hdpi/checkbox_off_background.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/checkbox_on_background.png b/core/res/res/drawable-hdpi/checkbox_on_background.png
new file mode 100644
index 0000000..800d3d5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/checkbox_on_background.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/clock_dial.png b/core/res/res/drawable-hdpi/clock_dial.png
new file mode 100644
index 0000000..9de29bc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/clock_dial.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/clock_hand_hour.png b/core/res/res/drawable-hdpi/clock_hand_hour.png
new file mode 100644
index 0000000..9f7e5c0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/clock_hand_hour.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/clock_hand_minute.png b/core/res/res/drawable-hdpi/clock_hand_minute.png
new file mode 100644
index 0000000..2eec380
--- /dev/null
+++ b/core/res/res/drawable-hdpi/clock_hand_minute.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/code_lock_bottom.9.png b/core/res/res/drawable-hdpi/code_lock_bottom.9.png
new file mode 100644
index 0000000..e72d0f7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/code_lock_bottom.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/code_lock_left.9.png b/core/res/res/drawable-hdpi/code_lock_left.9.png
new file mode 100644
index 0000000..76ff1f5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/code_lock_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/code_lock_top.9.png b/core/res/res/drawable-hdpi/code_lock_top.9.png
new file mode 100644
index 0000000..20af255
--- /dev/null
+++ b/core/res/res/drawable-hdpi/code_lock_top.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/compass_arrow.png b/core/res/res/drawable-hdpi/compass_arrow.png
new file mode 100644
index 0000000..6dbd900
--- /dev/null
+++ b/core/res/res/drawable-hdpi/compass_arrow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/compass_base.png b/core/res/res/drawable-hdpi/compass_base.png
new file mode 100644
index 0000000..298fc09
--- /dev/null
+++ b/core/res/res/drawable-hdpi/compass_base.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/create_contact.png b/core/res/res/drawable-hdpi/create_contact.png
new file mode 100644
index 0000000..19d59b4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/create_contact.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dark_header.9.png b/core/res/res/drawable-hdpi/dark_header.9.png
new file mode 100644
index 0000000..a2fa569
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dark_header.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_divider_horizontal_light.9.png b/core/res/res/drawable-hdpi/dialog_divider_horizontal_light.9.png
new file mode 100644
index 0000000..441ef32
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_divider_horizontal_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png b/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
new file mode 100644
index 0000000..c7803a2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png b/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
new file mode 100644
index 0000000..d8d8aa9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png b/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
new file mode 100644
index 0000000..63859f7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png b/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
new file mode 100644
index 0000000..ced2832
--- /dev/null
+++ b/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_dim_dark.9.png b/core/res/res/drawable-hdpi/divider_horizontal_dim_dark.9.png
new file mode 100644
index 0000000..63859f7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/divider_horizontal_dim_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_textfield.9.png b/core/res/res/drawable-hdpi/divider_horizontal_textfield.9.png
new file mode 100644
index 0000000..23b0b51
--- /dev/null
+++ b/core/res/res/drawable-hdpi/divider_horizontal_textfield.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_vertical_bright.9.png b/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
new file mode 100644
index 0000000..128a4de
--- /dev/null
+++ b/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/editbox_background_focus_yellow.9.png b/core/res/res/drawable-hdpi/editbox_background_focus_yellow.9.png
new file mode 100644
index 0000000..70cd52b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/editbox_background_focus_yellow.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/editbox_background_normal.9.png b/core/res/res/drawable-hdpi/editbox_background_normal.9.png
new file mode 100644
index 0000000..ce12b3b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/editbox_background_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/editbox_dropdown_background.9.png b/core/res/res/drawable-hdpi/editbox_dropdown_background.9.png
new file mode 100644
index 0000000..e7967d5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/editbox_dropdown_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/editbox_dropdown_background_dark.9.png b/core/res/res/drawable-hdpi/editbox_dropdown_background_dark.9.png
new file mode 100644
index 0000000..4cce373
--- /dev/null
+++ b/core/res/res/drawable-hdpi/editbox_dropdown_background_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_angel.png b/core/res/res/drawable-hdpi/emo_im_angel.png
new file mode 100644
index 0000000..10742a6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_angel.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_cool.png b/core/res/res/drawable-hdpi/emo_im_cool.png
new file mode 100644
index 0000000..e3c8654
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_cool.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_crying.png b/core/res/res/drawable-hdpi/emo_im_crying.png
new file mode 100644
index 0000000..b23791c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_crying.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_foot_in_mouth.png b/core/res/res/drawable-hdpi/emo_im_foot_in_mouth.png
new file mode 100644
index 0000000..050b7be
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_foot_in_mouth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_happy.png b/core/res/res/drawable-hdpi/emo_im_happy.png
new file mode 100644
index 0000000..69e3bed
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_happy.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_kissing.png b/core/res/res/drawable-hdpi/emo_im_kissing.png
new file mode 100644
index 0000000..0cca68e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_kissing.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_laughing.png b/core/res/res/drawable-hdpi/emo_im_laughing.png
new file mode 100644
index 0000000..8406ad0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_laughing.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_lips_are_sealed.png b/core/res/res/drawable-hdpi/emo_im_lips_are_sealed.png
new file mode 100644
index 0000000..222f175
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_lips_are_sealed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_money_mouth.png b/core/res/res/drawable-hdpi/emo_im_money_mouth.png
new file mode 100644
index 0000000..d711bfb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_money_mouth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_sad.png b/core/res/res/drawable-hdpi/emo_im_sad.png
new file mode 100644
index 0000000..40017f1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_sad.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_surprised.png b/core/res/res/drawable-hdpi/emo_im_surprised.png
new file mode 100644
index 0000000..4b2af7a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_surprised.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_tongue_sticking_out.png b/core/res/res/drawable-hdpi/emo_im_tongue_sticking_out.png
new file mode 100644
index 0000000..42ac80d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_tongue_sticking_out.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_undecided.png b/core/res/res/drawable-hdpi/emo_im_undecided.png
new file mode 100644
index 0000000..2cf5bd2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_undecided.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_winking.png b/core/res/res/drawable-hdpi/emo_im_winking.png
new file mode 100644
index 0000000..a3a0876
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_winking.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_wtf.png b/core/res/res/drawable-hdpi/emo_im_wtf.png
new file mode 100644
index 0000000..86c4bda
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_wtf.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/emo_im_yelling.png b/core/res/res/drawable-hdpi/emo_im_yelling.png
new file mode 100644
index 0000000..cfd991a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/emo_im_yelling.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/expander_ic_maximized.9.png b/core/res/res/drawable-hdpi/expander_ic_maximized.9.png
new file mode 100644
index 0000000..4dcb984
--- /dev/null
+++ b/core/res/res/drawable-hdpi/expander_ic_maximized.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/expander_ic_minimized.9.png b/core/res/res/drawable-hdpi/expander_ic_minimized.9.png
new file mode 100644
index 0000000..45b7322
--- /dev/null
+++ b/core/res/res/drawable-hdpi/expander_ic_minimized.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/focused_application_background_static.png b/core/res/res/drawable-hdpi/focused_application_background_static.png
new file mode 100644
index 0000000..6872f26
--- /dev/null
+++ b/core/res/res/drawable-hdpi/focused_application_background_static.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/frame_gallery_thumb.9.png b/core/res/res/drawable-hdpi/frame_gallery_thumb.9.png
new file mode 100644
index 0000000..8edbd3f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/frame_gallery_thumb.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/frame_gallery_thumb_pressed.9.png b/core/res/res/drawable-hdpi/frame_gallery_thumb_pressed.9.png
new file mode 100644
index 0000000..986e6d5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/frame_gallery_thumb_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/frame_gallery_thumb_selected.9.png b/core/res/res/drawable-hdpi/frame_gallery_thumb_selected.9.png
new file mode 100644
index 0000000..95f3ab5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/frame_gallery_thumb_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/gallery_selected_default.9.png b/core/res/res/drawable-hdpi/gallery_selected_default.9.png
new file mode 100644
index 0000000..99403aa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/gallery_selected_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/gallery_selected_focused.9.png b/core/res/res/drawable-hdpi/gallery_selected_focused.9.png
new file mode 100644
index 0000000..3aa2e17
--- /dev/null
+++ b/core/res/res/drawable-hdpi/gallery_selected_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/gallery_selected_pressed.9.png b/core/res/res/drawable-hdpi/gallery_selected_pressed.9.png
new file mode 100644
index 0000000..8f1e752
--- /dev/null
+++ b/core/res/res/drawable-hdpi/gallery_selected_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/gallery_unselected_default.9.png b/core/res/res/drawable-hdpi/gallery_unselected_default.9.png
new file mode 100644
index 0000000..855dca1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/gallery_unselected_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/gallery_unselected_pressed.9.png b/core/res/res/drawable-hdpi/gallery_unselected_pressed.9.png
new file mode 100644
index 0000000..5ec400c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/gallery_unselected_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/grid_selector_background_focus.9.png b/core/res/res/drawable-hdpi/grid_selector_background_focus.9.png
new file mode 100644
index 0000000..be2aeed
--- /dev/null
+++ b/core/res/res/drawable-hdpi/grid_selector_background_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/grid_selector_background_pressed.9.png b/core/res/res/drawable-hdpi/grid_selector_background_pressed.9.png
new file mode 100644
index 0000000..27e455a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/grid_selector_background_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/highlight_disabled.9.png b/core/res/res/drawable-hdpi/highlight_disabled.9.png
new file mode 100644
index 0000000..46f755d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/highlight_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/highlight_pressed.9.png b/core/res/res/drawable-hdpi/highlight_pressed.9.png
new file mode 100644
index 0000000..91d7db1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/highlight_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/highlight_selected.9.png b/core/res/res/drawable-hdpi/highlight_selected.9.png
new file mode 100644
index 0000000..6e92dd5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/highlight_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_round_more_disabled.png b/core/res/res/drawable-hdpi/ic_btn_round_more_disabled.png
new file mode 100644
index 0000000..0125944
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_btn_round_more_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_round_more_normal.png b/core/res/res/drawable-hdpi/ic_btn_round_more_normal.png
new file mode 100644
index 0000000..33d7f89
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_btn_round_more_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_search.png b/core/res/res/drawable-hdpi/ic_btn_search.png
new file mode 100644
index 0000000..23eebf5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_btn_search.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_speak_now.png b/core/res/res/drawable-hdpi/ic_btn_speak_now.png
new file mode 100644
index 0000000..6dc01fb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_btn_speak_now.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_fit_page_disabled.png b/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_fit_page_disabled.png
new file mode 100644
index 0000000..19fe4d4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_fit_page_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_fit_page_normal.png b/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_fit_page_normal.png
new file mode 100644
index 0000000..c5a0594
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_fit_page_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_page_overview_disabled.png b/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_page_overview_disabled.png
new file mode 100644
index 0000000..e5b22e8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_page_overview_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_page_overview_normal.png b/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_page_overview_normal.png
new file mode 100644
index 0000000..0612d01
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_btn_square_browser_zoom_page_overview_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_bullet_key_permission.png b/core/res/res/drawable-hdpi/ic_bullet_key_permission.png
new file mode 100644
index 0000000..98d95dc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_bullet_key_permission.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_contact_picture.png b/core/res/res/drawable-hdpi/ic_contact_picture.png
new file mode 100644
index 0000000..a60565a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_contact_picture.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_delete.png b/core/res/res/drawable-hdpi/ic_delete.png
new file mode 100644
index 0000000..f3e53d7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_delete.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_dialog_alert.png b/core/res/res/drawable-hdpi/ic_dialog_alert.png
new file mode 100644
index 0000000..7f905ba
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_dialog_alert.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_dialog_dialer.png b/core/res/res/drawable-hdpi/ic_dialog_dialer.png
new file mode 100644
index 0000000..2ded243
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_dialog_dialer.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_dialog_email.png b/core/res/res/drawable-hdpi/ic_dialog_email.png
new file mode 100644
index 0000000..faea271
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_dialog_email.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_dialog_info.png b/core/res/res/drawable-hdpi/ic_dialog_info.png
new file mode 100644
index 0000000..efee1ef
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_dialog_info.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_dialog_map.png b/core/res/res/drawable-hdpi/ic_dialog_map.png
new file mode 100644
index 0000000..f102b08
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_dialog_map.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_dialog_menu_generic.png b/core/res/res/drawable-hdpi/ic_dialog_menu_generic.png
new file mode 100644
index 0000000..ef8a877
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_dialog_menu_generic.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_dialog_time.png b/core/res/res/drawable-hdpi/ic_dialog_time.png
new file mode 100644
index 0000000..337a43a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_dialog_time.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_dialog_usb.png b/core/res/res/drawable-hdpi/ic_dialog_usb.png
new file mode 100644
index 0000000..e69e14a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_dialog_usb.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_emergency.png b/core/res/res/drawable-hdpi/ic_emergency.png
new file mode 100644
index 0000000..a2dd372
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_emergency.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_input_add.png b/core/res/res/drawable-hdpi/ic_input_add.png
new file mode 100644
index 0000000..d26ebac
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_input_add.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_input_delete.png b/core/res/res/drawable-hdpi/ic_input_delete.png
new file mode 100644
index 0000000..f35f89f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_input_delete.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_input_get.png b/core/res/res/drawable-hdpi/ic_input_get.png
new file mode 100644
index 0000000..e2b665a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_input_get.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_launcher_android.png b/core/res/res/drawable-hdpi/ic_launcher_android.png
new file mode 100644
index 0000000..d70b8ca
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_airplane_mode.png b/core/res/res/drawable-hdpi/ic_lock_airplane_mode.png
new file mode 100644
index 0000000..610f9d0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_airplane_mode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-hdpi/ic_lock_airplane_mode_off.png
new file mode 100644
index 0000000..cd50647
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_airplane_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png
new file mode 100644
index 0000000..3f3af06
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_idle_charging.png b/core/res/res/drawable-hdpi/ic_lock_idle_charging.png
new file mode 100644
index 0000000..42572ee
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_idle_charging.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_idle_lock.png b/core/res/res/drawable-hdpi/ic_lock_idle_lock.png
new file mode 100644
index 0000000..11163d8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_idle_lock.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_idle_low_battery.png b/core/res/res/drawable-hdpi/ic_lock_idle_low_battery.png
new file mode 100644
index 0000000..30ff905
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_idle_low_battery.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_lock.png b/core/res/res/drawable-hdpi/ic_lock_lock.png
new file mode 100644
index 0000000..0fc79e1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_lock.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_power_off.png b/core/res/res/drawable-hdpi/ic_lock_power_off.png
new file mode 100644
index 0000000..2f120c6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_power_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_silent_mode.png b/core/res/res/drawable-hdpi/ic_lock_silent_mode.png
new file mode 100644
index 0000000..00e1960
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_silent_mode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_silent_mode_off.png b/core/res/res/drawable-hdpi/ic_lock_silent_mode_off.png
new file mode 100644
index 0000000..6b4ce89
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_silent_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_maps_indicator_current_position.png b/core/res/res/drawable-hdpi/ic_maps_indicator_current_position.png
new file mode 100644
index 0000000..bc9160d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_maps_indicator_current_position.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim1.png b/core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim1.png
new file mode 100644
index 0000000..d3d9339
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim2.png b/core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim2.png
new file mode 100644
index 0000000..e32c223
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim3.png b/core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim3.png
new file mode 100644
index 0000000..cf2db7c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_maps_indicator_current_position_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_ff.png b/core/res/res/drawable-hdpi/ic_media_ff.png
new file mode 100644
index 0000000..b0dc05b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_ff.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_next.png b/core/res/res/drawable-hdpi/ic_media_next.png
new file mode 100644
index 0000000..2552f4e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_next.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_pause.png b/core/res/res/drawable-hdpi/ic_media_pause.png
new file mode 100644
index 0000000..d4670c2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_pause.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_play.png b/core/res/res/drawable-hdpi/ic_media_play.png
new file mode 100644
index 0000000..e67ec80
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_play.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_previous.png b/core/res/res/drawable-hdpi/ic_media_previous.png
new file mode 100644
index 0000000..05eba71
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_previous.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_rew.png b/core/res/res/drawable-hdpi/ic_media_rew.png
new file mode 100644
index 0000000..88eed2e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_rew.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_account_list.png b/core/res/res/drawable-hdpi/ic_menu_account_list.png
new file mode 100644
index 0000000..f858d2c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_account_list.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_add.png b/core/res/res/drawable-hdpi/ic_menu_add.png
new file mode 100644
index 0000000..65cc01e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_add.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_agenda.png b/core/res/res/drawable-hdpi/ic_menu_agenda.png
new file mode 100644
index 0000000..6bb5cc8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_agenda.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_allfriends.png b/core/res/res/drawable-hdpi/ic_menu_allfriends.png
new file mode 100644
index 0000000..8d11ca1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_allfriends.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_always_landscape_portrait.png b/core/res/res/drawable-hdpi/ic_menu_always_landscape_portrait.png
new file mode 100644
index 0000000..7ae1760
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_always_landscape_portrait.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_archive.png b/core/res/res/drawable-hdpi/ic_menu_archive.png
new file mode 100644
index 0000000..9ca5c62
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_archive.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_attachment.png b/core/res/res/drawable-hdpi/ic_menu_attachment.png
new file mode 100644
index 0000000..8f11153
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_attachment.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_back.png b/core/res/res/drawable-hdpi/ic_menu_back.png
new file mode 100644
index 0000000..a6cd712
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_back.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_block.png b/core/res/res/drawable-hdpi/ic_menu_block.png
new file mode 100644
index 0000000..e1f9c2c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_block.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_blocked_user.png b/core/res/res/drawable-hdpi/ic_menu_blocked_user.png
new file mode 100644
index 0000000..3dd9a4a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_blocked_user.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_call.png b/core/res/res/drawable-hdpi/ic_menu_call.png
new file mode 100644
index 0000000..2ccc087
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_camera.png b/core/res/res/drawable-hdpi/ic_menu_camera.png
new file mode 100644
index 0000000..5a3850f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_camera.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_cc.png b/core/res/res/drawable-hdpi/ic_menu_cc.png
new file mode 100644
index 0000000..47905a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_cc.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_chat_dashboard.png b/core/res/res/drawable-hdpi/ic_menu_chat_dashboard.png
new file mode 100644
index 0000000..dde6741
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_chat_dashboard.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_clear_playlist.png b/core/res/res/drawable-hdpi/ic_menu_clear_playlist.png
new file mode 100644
index 0000000..e6be48b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_clear_playlist.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_close_clear_cancel.png b/core/res/res/drawable-hdpi/ic_menu_close_clear_cancel.png
new file mode 100644
index 0000000..a54ea9d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_close_clear_cancel.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_compass.png b/core/res/res/drawable-hdpi/ic_menu_compass.png
new file mode 100644
index 0000000..104270f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_compass.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_compose.png b/core/res/res/drawable-hdpi/ic_menu_compose.png
new file mode 100644
index 0000000..6ad379e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_compose.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_crop.png b/core/res/res/drawable-hdpi/ic_menu_crop.png
new file mode 100644
index 0000000..0d4c9fe
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_crop.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_day.png b/core/res/res/drawable-hdpi/ic_menu_day.png
new file mode 100644
index 0000000..84429aa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_day.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_delete.png b/core/res/res/drawable-hdpi/ic_menu_delete.png
new file mode 100644
index 0000000..2aed26a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_delete.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_directions.png b/core/res/res/drawable-hdpi/ic_menu_directions.png
new file mode 100644
index 0000000..23f6eb3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_directions.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_edit.png b/core/res/res/drawable-hdpi/ic_menu_edit.png
new file mode 100644
index 0000000..602dd10
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_edit.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_emoticons.png b/core/res/res/drawable-hdpi/ic_menu_emoticons.png
new file mode 100644
index 0000000..2fab515
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_emoticons.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_end_conversation.png b/core/res/res/drawable-hdpi/ic_menu_end_conversation.png
new file mode 100644
index 0000000..c05a207
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_end_conversation.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_forward.png b/core/res/res/drawable-hdpi/ic_menu_forward.png
new file mode 100644
index 0000000..606e6aa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_forward.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_friendslist.png b/core/res/res/drawable-hdpi/ic_menu_friendslist.png
new file mode 100644
index 0000000..a90e573
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_friendslist.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_gallery.png b/core/res/res/drawable-hdpi/ic_menu_gallery.png
new file mode 100644
index 0000000..76dfbc3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_gallery.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_goto.png b/core/res/res/drawable-hdpi/ic_menu_goto.png
new file mode 100644
index 0000000..a1acecb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_goto.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_help.png b/core/res/res/drawable-hdpi/ic_menu_help.png
new file mode 100644
index 0000000..4300e86
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_help.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_home.png b/core/res/res/drawable-hdpi/ic_menu_home.png
new file mode 100644
index 0000000..35cb52a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_home.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_info_details.png b/core/res/res/drawable-hdpi/ic_menu_info_details.png
new file mode 100644
index 0000000..7696ceb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_info_details.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_invite.png b/core/res/res/drawable-hdpi/ic_menu_invite.png
new file mode 100644
index 0000000..3cb129f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_invite.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_login.png b/core/res/res/drawable-hdpi/ic_menu_login.png
new file mode 100644
index 0000000..d23ebf0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_login.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_manage.png b/core/res/res/drawable-hdpi/ic_menu_manage.png
new file mode 100644
index 0000000..c7c4cbc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_manage.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_mapmode.png b/core/res/res/drawable-hdpi/ic_menu_mapmode.png
new file mode 100644
index 0000000..c895ccb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_mapmode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_mark.png b/core/res/res/drawable-hdpi/ic_menu_mark.png
new file mode 100644
index 0000000..724d787
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_mark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_month.png b/core/res/res/drawable-hdpi/ic_menu_month.png
new file mode 100644
index 0000000..3e55ae6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_month.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_more.png b/core/res/res/drawable-hdpi/ic_menu_more.png
new file mode 100644
index 0000000..ed4376f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_more.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_my_calendar.png b/core/res/res/drawable-hdpi/ic_menu_my_calendar.png
new file mode 100644
index 0000000..3d6ea1f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_my_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_mylocation.png b/core/res/res/drawable-hdpi/ic_menu_mylocation.png
new file mode 100644
index 0000000..1bcb0cd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_mylocation.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_myplaces.png b/core/res/res/drawable-hdpi/ic_menu_myplaces.png
new file mode 100644
index 0000000..5f726d8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_myplaces.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_notifications.png b/core/res/res/drawable-hdpi/ic_menu_notifications.png
new file mode 100644
index 0000000..fb63937
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_notifications.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_play_clip.png b/core/res/res/drawable-hdpi/ic_menu_play_clip.png
new file mode 100644
index 0000000..ddde03a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_play_clip.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_preferences.png b/core/res/res/drawable-hdpi/ic_menu_preferences.png
new file mode 100644
index 0000000..64c42d2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_preferences.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_recent_history.png b/core/res/res/drawable-hdpi/ic_menu_recent_history.png
new file mode 100644
index 0000000..0dd1627
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_recent_history.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_refresh.png b/core/res/res/drawable-hdpi/ic_menu_refresh.png
new file mode 100644
index 0000000..53cacca
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_refresh.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_report_image.png b/core/res/res/drawable-hdpi/ic_menu_report_image.png
new file mode 100644
index 0000000..b6aa5d6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_report_image.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_revert.png b/core/res/res/drawable-hdpi/ic_menu_revert.png
new file mode 100644
index 0000000..11860a4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_revert.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_rotate.png b/core/res/res/drawable-hdpi/ic_menu_rotate.png
new file mode 100644
index 0000000..85115af
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_rotate.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_save.png b/core/res/res/drawable-hdpi/ic_menu_save.png
new file mode 100644
index 0000000..fc26c5d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_save.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_search.png b/core/res/res/drawable-hdpi/ic_menu_search.png
new file mode 100644
index 0000000..f78234e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_search.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_send.png b/core/res/res/drawable-hdpi/ic_menu_send.png
new file mode 100644
index 0000000..2567b58
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_send.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_set_as.png b/core/res/res/drawable-hdpi/ic_menu_set_as.png
new file mode 100644
index 0000000..7e79c15
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_set_as.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_share.png b/core/res/res/drawable-hdpi/ic_menu_share.png
new file mode 100644
index 0000000..b41b348
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_share.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_slideshow.png b/core/res/res/drawable-hdpi/ic_menu_slideshow.png
new file mode 100644
index 0000000..53b1a6f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_slideshow.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_sort_alphabetically.png b/core/res/res/drawable-hdpi/ic_menu_sort_alphabetically.png
new file mode 100644
index 0000000..5d68998
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_sort_alphabetically.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_sort_by_size.png b/core/res/res/drawable-hdpi/ic_menu_sort_by_size.png
new file mode 100644
index 0000000..c9388fd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_sort_by_size.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_star.png b/core/res/res/drawable-hdpi/ic_menu_star.png
new file mode 100644
index 0000000..21a2c4b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_star.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_start_conversation.png b/core/res/res/drawable-hdpi/ic_menu_start_conversation.png
new file mode 100644
index 0000000..d63d3a7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_start_conversation.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_stop.png b/core/res/res/drawable-hdpi/ic_menu_stop.png
new file mode 100644
index 0000000..7c99ed4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_stop.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_today.png b/core/res/res/drawable-hdpi/ic_menu_today.png
new file mode 100644
index 0000000..4a9352d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_today.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_upload.png b/core/res/res/drawable-hdpi/ic_menu_upload.png
new file mode 100644
index 0000000..d845112
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_upload.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_upload_you_tube.png b/core/res/res/drawable-hdpi/ic_menu_upload_you_tube.png
new file mode 100644
index 0000000..df5fa7f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_upload_you_tube.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_view.png b/core/res/res/drawable-hdpi/ic_menu_view.png
new file mode 100644
index 0000000..75155d4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_view.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_week.png b/core/res/res/drawable-hdpi/ic_menu_week.png
new file mode 100644
index 0000000..c216eca
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_week.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_zoom.png b/core/res/res/drawable-hdpi/ic_menu_zoom.png
new file mode 100644
index 0000000..9fa4d7e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_menu_zoom.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notification_clear_all.png b/core/res/res/drawable-hdpi/ic_notification_clear_all.png
new file mode 100644
index 0000000..6bff858
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notification_clear_all.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notification_overlay.9.png b/core/res/res/drawable-hdpi/ic_notification_overlay.9.png
new file mode 100644
index 0000000..744178f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_partial_secure.png b/core/res/res/drawable-hdpi/ic_partial_secure.png
new file mode 100644
index 0000000..70bd08d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_partial_secure.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_popup_disk_full.png b/core/res/res/drawable-hdpi/ic_popup_disk_full.png
new file mode 100644
index 0000000..b3c00a7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_popup_disk_full.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_popup_reminder.png b/core/res/res/drawable-hdpi/ic_popup_reminder.png
new file mode 100644
index 0000000..9652dde
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_popup_reminder.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_popup_sync_1.png b/core/res/res/drawable-hdpi/ic_popup_sync_1.png
new file mode 100644
index 0000000..a248f59
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_popup_sync_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_popup_sync_2.png b/core/res/res/drawable-hdpi/ic_popup_sync_2.png
new file mode 100644
index 0000000..756bfc6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_popup_sync_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_popup_sync_3.png b/core/res/res/drawable-hdpi/ic_popup_sync_3.png
new file mode 100644
index 0000000..e06825b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_popup_sync_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_popup_sync_4.png b/core/res/res/drawable-hdpi/ic_popup_sync_4.png
new file mode 100644
index 0000000..87ce8f6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_popup_sync_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_popup_sync_5.png b/core/res/res/drawable-hdpi/ic_popup_sync_5.png
new file mode 100644
index 0000000..635480c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_popup_sync_5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_popup_sync_6.png b/core/res/res/drawable-hdpi/ic_popup_sync_6.png
new file mode 100644
index 0000000..b339eb2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_popup_sync_6.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_search_category_default.png b/core/res/res/drawable-hdpi/ic_search_category_default.png
new file mode 100644
index 0000000..4038129
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_search_category_default.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_secure.png b/core/res/res/drawable-hdpi/ic_secure.png
new file mode 100644
index 0000000..5fb62c2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_secure.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_text_dot.png b/core/res/res/drawable-hdpi/ic_text_dot.png
new file mode 100644
index 0000000..a7eaec5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_text_dot.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_vibrate.png b/core/res/res/drawable-hdpi/ic_vibrate.png
new file mode 100644
index 0000000..3d1e9a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_volume.png b/core/res/res/drawable-hdpi/ic_volume.png
new file mode 100644
index 0000000..ec555f1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_volume.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_volume_bluetooth_ad2p.png b/core/res/res/drawable-hdpi/ic_volume_bluetooth_ad2p.png
new file mode 100644
index 0000000..31851e1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_volume_bluetooth_ad2p.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_volume_bluetooth_in_call.png b/core/res/res/drawable-hdpi/ic_volume_bluetooth_in_call.png
new file mode 100644
index 0000000..108a9e1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_volume_bluetooth_in_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_volume_off.png b/core/res/res/drawable-hdpi/ic_volume_off.png
new file mode 100644
index 0000000..3ace6bf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_volume_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_volume_off_small.png b/core/res/res/drawable-hdpi/ic_volume_off_small.png
new file mode 100644
index 0000000..4b36677
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_volume_off_small.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_volume_small.png b/core/res/res/drawable-hdpi/ic_volume_small.png
new file mode 100644
index 0000000..538e304
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_volume_small.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/icon_highlight_rectangle.9.png b/core/res/res/drawable-hdpi/icon_highlight_rectangle.9.png
new file mode 100644
index 0000000..a4da974
--- /dev/null
+++ b/core/res/res/drawable-hdpi/icon_highlight_rectangle.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/icon_highlight_square.9.png b/core/res/res/drawable-hdpi/icon_highlight_square.9.png
new file mode 100644
index 0000000..6f9a442
--- /dev/null
+++ b/core/res/res/drawable-hdpi/icon_highlight_square.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ime_qwerty.png b/core/res/res/drawable-hdpi/ime_qwerty.png
new file mode 100644
index 0000000..f9967cc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ime_qwerty.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up.png b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up.png
new file mode 100644
index 0000000..6560696
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up.png
new file mode 100644
index 0000000..698c3ec
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default.png
new file mode 100644
index 0000000..0102a61
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png
new file mode 100644
index 0000000..82ad8f7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png
new file mode 100644
index 0000000..f9d0d33
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_input_error.png b/core/res/res/drawable-hdpi/indicator_input_error.png
new file mode 100644
index 0000000..213976c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_input_error.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/keyboard_accessory_bg_landscape.9.png b/core/res/res/drawable-hdpi/keyboard_accessory_bg_landscape.9.png
new file mode 100644
index 0000000..5b0f6c5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/keyboard_accessory_bg_landscape.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/keyboard_background.9.png b/core/res/res/drawable-hdpi/keyboard_background.9.png
new file mode 100644
index 0000000..7a03b8e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/keyboard_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/keyboard_key_feedback_background.9.png b/core/res/res/drawable-hdpi/keyboard_key_feedback_background.9.png
new file mode 100644
index 0000000..dc3e1f9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/keyboard_key_feedback_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png b/core/res/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png
new file mode 100644
index 0000000..c67ed53
--- /dev/null
+++ b/core/res/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/keyboard_popup_panel_background.9.png b/core/res/res/drawable-hdpi/keyboard_popup_panel_background.9.png
new file mode 100644
index 0000000..8e2461b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/keyboard_popup_panel_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/keyboard_textfield_selected.9.png b/core/res/res/drawable-hdpi/keyboard_textfield_selected.9.png
new file mode 100644
index 0000000..61db22c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/keyboard_textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/light_header.9.png b/core/res/res/drawable-hdpi/light_header.9.png
new file mode 100644
index 0000000..27db59d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/light_header.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_background_disabled.9.png b/core/res/res/drawable-hdpi/list_selector_background_disabled.9.png
new file mode 100644
index 0000000..c40233e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_background_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_background_focus.9.png b/core/res/res/drawable-hdpi/list_selector_background_focus.9.png
new file mode 100644
index 0000000..d8e16b9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_background_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_background_longpress.9.png b/core/res/res/drawable-hdpi/list_selector_background_longpress.9.png
new file mode 100644
index 0000000..1676ca7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_background_longpress.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selector_background_pressed.9.png b/core/res/res/drawable-hdpi/list_selector_background_pressed.9.png
new file mode 100644
index 0000000..ba79cf7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_selector_background_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/loading_tile.png b/core/res/res/drawable-hdpi/loading_tile.png
new file mode 100644
index 0000000..691ca45
--- /dev/null
+++ b/core/res/res/drawable-hdpi/loading_tile.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/maps_google_logo.png b/core/res/res/drawable-hdpi/maps_google_logo.png
new file mode 100644
index 0000000..5956ee2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/maps_google_logo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_background.9.png b/core/res/res/drawable-hdpi/menu_background.9.png
new file mode 100644
index 0000000..cbe62af
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menu_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_background_fill_parent_width.9.png b/core/res/res/drawable-hdpi/menu_background_fill_parent_width.9.png
new file mode 100644
index 0000000..0812487
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menu_background_fill_parent_width.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_separator.9.png b/core/res/res/drawable-hdpi/menu_separator.9.png
new file mode 100644
index 0000000..3685b4e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menu_separator.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_submenu_background.9.png b/core/res/res/drawable-hdpi/menu_submenu_background.9.png
new file mode 100644
index 0000000..cbd4400
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menu_submenu_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menuitem_background_focus.9.png b/core/res/res/drawable-hdpi/menuitem_background_focus.9.png
new file mode 100644
index 0000000..d8e16b9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menuitem_background_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menuitem_background_pressed.9.png b/core/res/res/drawable-hdpi/menuitem_background_pressed.9.png
new file mode 100644
index 0000000..ba79cf7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menuitem_background_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/menuitem_background_solid_focused.9.png b/core/res/res/drawable-hdpi/menuitem_background_solid_focused.9.png
index 99dd9b1..99dd9b1 100644
--- a/core/res/res/drawable/menuitem_background_solid_focused.9.png
+++ b/core/res/res/drawable-hdpi/menuitem_background_solid_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/menuitem_background_solid_pressed.9.png b/core/res/res/drawable-hdpi/menuitem_background_solid_pressed.9.png
index 389063a..389063a 100644
--- a/core/res/res/drawable/menuitem_background_solid_pressed.9.png
+++ b/core/res/res/drawable-hdpi/menuitem_background_solid_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menuitem_checkbox_on.png b/core/res/res/drawable-hdpi/menuitem_checkbox_on.png
new file mode 100644
index 0000000..e90f631
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menuitem_checkbox_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/no_tile_128.png b/core/res/res/drawable-hdpi/no_tile_128.png
new file mode 100644
index 0000000..86b998d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/no_tile_128.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/panel_background.9.png b/core/res/res/drawable-hdpi/panel_background.9.png
new file mode 100644
index 0000000..bfe5713
--- /dev/null
+++ b/core/res/res/drawable-hdpi/panel_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/panel_picture_frame_bg_focus_blue.9.png b/core/res/res/drawable-hdpi/panel_picture_frame_bg_focus_blue.9.png
new file mode 100644
index 0000000..fdafdf5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/panel_picture_frame_bg_focus_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/panel_picture_frame_bg_normal.9.png b/core/res/res/drawable-hdpi/panel_picture_frame_bg_normal.9.png
new file mode 100644
index 0000000..a654277
--- /dev/null
+++ b/core/res/res/drawable-hdpi/panel_picture_frame_bg_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/panel_picture_frame_bg_pressed_blue.9.png b/core/res/res/drawable-hdpi/panel_picture_frame_bg_pressed_blue.9.png
new file mode 100644
index 0000000..73162a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/panel_picture_frame_bg_pressed_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pickerbox_background.png b/core/res/res/drawable-hdpi/pickerbox_background.png
new file mode 100644
index 0000000..9315a31
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pickerbox_background.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pickerbox_selected.9.png b/core/res/res/drawable-hdpi/pickerbox_selected.9.png
new file mode 100644
index 0000000..a88ec63
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pickerbox_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pickerbox_unselected.9.png b/core/res/res/drawable-hdpi/pickerbox_unselected.9.png
new file mode 100644
index 0000000..9f6b7cb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pickerbox_unselected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/picture_emergency.png b/core/res/res/drawable-hdpi/picture_emergency.png
new file mode 100644
index 0000000..b0f10f9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/picture_emergency.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/picture_frame.9.png b/core/res/res/drawable-hdpi/picture_frame.9.png
new file mode 100644
index 0000000..c038b2a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/picture_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_bottom_bright.9.png b/core/res/res/drawable-hdpi/popup_bottom_bright.9.png
new file mode 100644
index 0000000..cca47d3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_bottom_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_bottom_dark.9.png b/core/res/res/drawable-hdpi/popup_bottom_dark.9.png
new file mode 100644
index 0000000..62a0bd0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_bottom_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_bottom_medium.9.png b/core/res/res/drawable-hdpi/popup_bottom_medium.9.png
new file mode 100644
index 0000000..6ebb4f7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_bottom_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_center_bright.9.png b/core/res/res/drawable-hdpi/popup_center_bright.9.png
new file mode 100644
index 0000000..756e9ed
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_center_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_center_dark.9.png b/core/res/res/drawable-hdpi/popup_center_dark.9.png
new file mode 100644
index 0000000..77b4524
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_center_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_center_medium.9.png b/core/res/res/drawable-hdpi/popup_center_medium.9.png
new file mode 100644
index 0000000..de4be2a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_center_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_full_bright.9.png b/core/res/res/drawable-hdpi/popup_full_bright.9.png
new file mode 100644
index 0000000..6c30bec
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_full_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_full_dark.9.png b/core/res/res/drawable-hdpi/popup_full_dark.9.png
new file mode 100644
index 0000000..fc8c00e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_full_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_inline_error.9.png b/core/res/res/drawable-hdpi/popup_inline_error.9.png
new file mode 100644
index 0000000..b188d81
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_inline_error.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_inline_error_above.9.png b/core/res/res/drawable-hdpi/popup_inline_error_above.9.png
new file mode 100644
index 0000000..3d4e8ba
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_inline_error_above.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_top_bright.9.png b/core/res/res/drawable-hdpi/popup_top_bright.9.png
new file mode 100644
index 0000000..ddd30ab
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_top_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_top_dark.9.png b/core/res/res/drawable-hdpi/popup_top_dark.9.png
new file mode 100644
index 0000000..144d0fc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/popup_top_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/presence_away.png b/core/res/res/drawable-hdpi/presence_away.png
new file mode 100644
index 0000000..d4aa66b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/presence_away.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/presence_busy.png b/core/res/res/drawable-hdpi/presence_busy.png
new file mode 100644
index 0000000..4b27853
--- /dev/null
+++ b/core/res/res/drawable-hdpi/presence_busy.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/presence_invisible.png b/core/res/res/drawable-hdpi/presence_invisible.png
new file mode 100644
index 0000000..0e27fba
--- /dev/null
+++ b/core/res/res/drawable-hdpi/presence_invisible.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/presence_offline.png b/core/res/res/drawable-hdpi/presence_offline.png
new file mode 100644
index 0000000..e511aa4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/presence_offline.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/presence_online.png b/core/res/res/drawable-hdpi/presence_online.png
new file mode 100644
index 0000000..d787d2f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/presence_online.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pressed_application_background_static.png b/core/res/res/drawable-hdpi/pressed_application_background_static.png
new file mode 100644
index 0000000..dae96e6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/pressed_application_background_static.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate1.png b/core/res/res/drawable-hdpi/progressbar_indeterminate1.png
new file mode 100644
index 0000000..ea88e32
--- /dev/null
+++ b/core/res/res/drawable-hdpi/progressbar_indeterminate1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate2.png b/core/res/res/drawable-hdpi/progressbar_indeterminate2.png
new file mode 100644
index 0000000..436c48c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/progressbar_indeterminate2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progressbar_indeterminate3.png b/core/res/res/drawable-hdpi/progressbar_indeterminate3.png
new file mode 100644
index 0000000..ea88e32
--- /dev/null
+++ b/core/res/res/drawable-hdpi/progressbar_indeterminate3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/radiobutton_off_background.png b/core/res/res/drawable-hdpi/radiobutton_off_background.png
new file mode 100644
index 0000000..5ce33cd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/radiobutton_off_background.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/radiobutton_on_background.png b/core/res/res/drawable-hdpi/radiobutton_on_background.png
new file mode 100644
index 0000000..0f46071
--- /dev/null
+++ b/core/res/res/drawable-hdpi/radiobutton_on_background.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/rate_star_big_half.png b/core/res/res/drawable-hdpi/rate_star_big_half.png
new file mode 100644
index 0000000..61906a5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/rate_star_big_half.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/rate_star_big_off.png b/core/res/res/drawable-hdpi/rate_star_big_off.png
new file mode 100644
index 0000000..a688a45
--- /dev/null
+++ b/core/res/res/drawable-hdpi/rate_star_big_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/rate_star_big_on.png b/core/res/res/drawable-hdpi/rate_star_big_on.png
new file mode 100644
index 0000000..77cb067
--- /dev/null
+++ b/core/res/res/drawable-hdpi/rate_star_big_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/rate_star_small_half.png b/core/res/res/drawable-hdpi/rate_star_small_half.png
new file mode 100644
index 0000000..6b2efd9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/rate_star_small_half.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/rate_star_small_off.png b/core/res/res/drawable-hdpi/rate_star_small_off.png
new file mode 100644
index 0000000..8422919
--- /dev/null
+++ b/core/res/res/drawable-hdpi/rate_star_small_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/rate_star_small_on.png b/core/res/res/drawable-hdpi/rate_star_small_on.png
new file mode 100644
index 0000000..45e2324
--- /dev/null
+++ b/core/res/res/drawable-hdpi/rate_star_small_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/reticle.png b/core/res/res/drawable-hdpi/reticle.png
new file mode 100644
index 0000000..a3e8c1b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/reticle.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/screen_progress_frame.9.png b/core/res/res/drawable-hdpi/screen_progress_frame.9.png
new file mode 100644
index 0000000..3f9d738
--- /dev/null
+++ b/core/res/res/drawable-hdpi/screen_progress_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/screen_progress_inner.9.png b/core/res/res/drawable-hdpi/screen_progress_inner.9.png
new file mode 100644
index 0000000..10c7da5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/screen_progress_inner.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png b/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png
new file mode 100644
index 0000000..b540cd3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrollbar_handle_horizontal.9.png b/core/res/res/drawable-hdpi/scrollbar_handle_horizontal.9.png
new file mode 100644
index 0000000..cd206e2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrollbar_handle_horizontal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrollbar_handle_vertical.9.png b/core/res/res/drawable-hdpi/scrollbar_handle_vertical.9.png
new file mode 100644
index 0000000..3ec0791
--- /dev/null
+++ b/core/res/res/drawable-hdpi/scrollbar_handle_vertical.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/search_dropdown_background.9.png b/core/res/res/drawable-hdpi/search_dropdown_background.9.png
new file mode 100644
index 0000000..e6945db
--- /dev/null
+++ b/core/res/res/drawable-hdpi/search_dropdown_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/search_plate.9.png b/core/res/res/drawable-hdpi/search_plate.9.png
new file mode 100644
index 0000000..561c9fa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/search_plate.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/search_plate_global.9.png b/core/res/res/drawable-hdpi/search_plate_global.9.png
new file mode 100644
index 0000000..32c6dc3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/search_plate_global.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/seek_thumb_normal.png b/core/res/res/drawable-hdpi/seek_thumb_normal.png
new file mode 100644
index 0000000..cc83a7d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/seek_thumb_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/seek_thumb_pressed.png b/core/res/res/drawable-hdpi/seek_thumb_pressed.png
new file mode 100644
index 0000000..15f79ea
--- /dev/null
+++ b/core/res/res/drawable-hdpi/seek_thumb_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/seek_thumb_selected.png b/core/res/res/drawable-hdpi/seek_thumb_selected.png
new file mode 100644
index 0000000..8a7cf68
--- /dev/null
+++ b/core/res/res/drawable-hdpi/seek_thumb_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/settings_header_raw.9.png b/core/res/res/drawable-hdpi/settings_header_raw.9.png
new file mode 100644
index 0000000..6857c0f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/settings_header_raw.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_16.png b/core/res/res/drawable-hdpi/spinner_black_16.png
new file mode 100644
index 0000000..eb34867
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_black_16.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_20.png b/core/res/res/drawable-hdpi/spinner_black_20.png
new file mode 100644
index 0000000..dac06d7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_black_20.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_48.png b/core/res/res/drawable-hdpi/spinner_black_48.png
new file mode 100644
index 0000000..337f72a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_black_48.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_76.png b/core/res/res/drawable-hdpi/spinner_black_76.png
new file mode 100644
index 0000000..2edc3e7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_black_76.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_dropdown_background_down.9.png b/core/res/res/drawable-hdpi/spinner_dropdown_background_down.9.png
new file mode 100644
index 0000000..566543d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_dropdown_background_down.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_dropdown_background_up.9.png b/core/res/res/drawable-hdpi/spinner_dropdown_background_up.9.png
new file mode 100644
index 0000000..7b883cc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_dropdown_background_up.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_normal.9.png b/core/res/res/drawable-hdpi/spinner_normal.9.png
new file mode 100644
index 0000000..b1f25f0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_press.9.png b/core/res/res/drawable-hdpi/spinner_press.9.png
new file mode 100644
index 0000000..6aab271
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_press.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_select.9.png b/core/res/res/drawable-hdpi/spinner_select.9.png
new file mode 100644
index 0000000..9024d07
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_select.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_16.png b/core/res/res/drawable-hdpi/spinner_white_16.png
new file mode 100644
index 0000000..7914a68
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_white_16.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_48.png b/core/res/res/drawable-hdpi/spinner_white_48.png
new file mode 100644
index 0000000..faee8ca
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_white_48.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_76.png b/core/res/res/drawable-hdpi/spinner_white_76.png
new file mode 100644
index 0000000..cd26379
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinner_white_76.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinnerbox_arrow_first.9.png b/core/res/res/drawable-hdpi/spinnerbox_arrow_first.9.png
new file mode 100644
index 0000000..af80855
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinnerbox_arrow_first.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinnerbox_arrow_last.9.png b/core/res/res/drawable-hdpi/spinnerbox_arrow_last.9.png
new file mode 100644
index 0000000..dc47275
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinnerbox_arrow_last.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinnerbox_arrow_middle.9.png b/core/res/res/drawable-hdpi/spinnerbox_arrow_middle.9.png
new file mode 100644
index 0000000..007f279
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinnerbox_arrow_middle.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinnerbox_arrow_single.9.png b/core/res/res/drawable-hdpi/spinnerbox_arrow_single.9.png
new file mode 100644
index 0000000..24592a3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/spinnerbox_arrow_single.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/star_big_off.png b/core/res/res/drawable-hdpi/star_big_off.png
new file mode 100644
index 0000000..ee6c942
--- /dev/null
+++ b/core/res/res/drawable-hdpi/star_big_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/star_big_on.png b/core/res/res/drawable-hdpi/star_big_on.png
new file mode 100644
index 0000000..17b4d73
--- /dev/null
+++ b/core/res/res/drawable-hdpi/star_big_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/star_off.png b/core/res/res/drawable-hdpi/star_off.png
new file mode 100644
index 0000000..e1897c7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/star_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/star_on.png b/core/res/res/drawable-hdpi/star_on.png
new file mode 100644
index 0000000..b7440ea
--- /dev/null
+++ b/core/res/res/drawable-hdpi/star_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_ecb_mode.png b/core/res/res/drawable-hdpi/stat_ecb_mode.png
new file mode 100644
index 0000000..91e6c1e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_ecb_mode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_alarm.png b/core/res/res/drawable-hdpi/stat_notify_alarm.png
new file mode 100644
index 0000000..adac8a9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_call_mute.png b/core/res/res/drawable-hdpi/stat_notify_call_mute.png
new file mode 100644
index 0000000..a43139b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_chat.png b/core/res/res/drawable-hdpi/stat_notify_chat.png
new file mode 100644
index 0000000..7b837b3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_chat.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_disk_full.png b/core/res/res/drawable-hdpi/stat_notify_disk_full.png
new file mode 100644
index 0000000..2163fa7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_disk_full.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_error.png b/core/res/res/drawable-hdpi/stat_notify_error.png
new file mode 100644
index 0000000..9853cda
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_error.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_missed_call.png b/core/res/res/drawable-hdpi/stat_notify_missed_call.png
new file mode 100644
index 0000000..a313360
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_missed_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_more.png b/core/res/res/drawable-hdpi/stat_notify_more.png
new file mode 100644
index 0000000..bbbd59b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_more.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sdcard.png b/core/res/res/drawable-hdpi/stat_notify_sdcard.png
new file mode 100644
index 0000000..0161419
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sdcard.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png b/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png
new file mode 100644
index 0000000..23b2f0a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sdcard_usb.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sim_toolkit.png b/core/res/res/drawable-hdpi/stat_notify_sim_toolkit.png
new file mode 100644
index 0000000..401fbb0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sim_toolkit.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync.png b/core/res/res/drawable-hdpi/stat_notify_sync.png
new file mode 100644
index 0000000..dacfc3a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sync.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync_anim0.png b/core/res/res/drawable-hdpi/stat_notify_sync_anim0.png
new file mode 100644
index 0000000..00e2ebb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_sync_error.png b/core/res/res/drawable-hdpi/stat_notify_sync_error.png
new file mode 100644
index 0000000..3083b44
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_sync_error.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_voicemail.png b/core/res/res/drawable-hdpi/stat_notify_voicemail.png
new file mode 100644
index 0000000..7f62e94
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png b/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png
new file mode 100644
index 0000000..712e071
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_0.png b/core/res/res/drawable-hdpi/stat_sys_battery_0.png
new file mode 100644
index 0000000..171b8b5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_10.png b/core/res/res/drawable-hdpi/stat_sys_battery_10.png
new file mode 100644
index 0000000..77e8793
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_10.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_100.png b/core/res/res/drawable-hdpi/stat_sys_battery_100.png
new file mode 100644
index 0000000..d13d083
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_20.png b/core/res/res/drawable-hdpi/stat_sys_battery_20.png
new file mode 100644
index 0000000..c14dc07
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_20.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_40.png b/core/res/res/drawable-hdpi/stat_sys_battery_40.png
new file mode 100644
index 0000000..a3077b0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_40.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_60.png b/core/res/res/drawable-hdpi/stat_sys_battery_60.png
new file mode 100644
index 0000000..621e905
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_60.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_80.png b/core/res/res/drawable-hdpi/stat_sys_battery_80.png
new file mode 100644
index 0000000..29830e9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_80.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
new file mode 100644
index 0000000..61556c6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
new file mode 100644
index 0000000..985dc0f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
new file mode 100644
index 0000000..b319d07
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
new file mode 100644
index 0000000..cbf21c6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
new file mode 100644
index 0000000..51565c3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
new file mode 100644
index 0000000..bf41a89
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_charge_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png b/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
new file mode 100644
index 0000000..8c5daba
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_battery_unknown.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
new file mode 100644
index 0000000..7cf5962
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png b/core/res/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
new file mode 100644
index 0000000..3e3f4f0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_bluetooth_connected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_3g.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_3g.png
new file mode 100644
index 0000000..42af121
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_e.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_e.png
new file mode 100644
index 0000000..6106dd4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_connected_g.png b/core/res/res/drawable-hdpi/stat_sys_data_connected_g.png
new file mode 100644
index 0000000..cc6e284
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_3g.png b/core/res/res/drawable-hdpi/stat_sys_data_in_3g.png
new file mode 100644
index 0000000..5848981
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_e.png b/core/res/res/drawable-hdpi/stat_sys_data_in_e.png
new file mode 100644
index 0000000..e4c6c2b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_in_g.png b/core/res/res/drawable-hdpi/stat_sys_data_in_g.png
new file mode 100644
index 0000000..05a910b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.png
new file mode 100644
index 0000000..b4383e2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_e.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_e.png
new file mode 100644
index 0000000..78b04db
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_g.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_g.png
new file mode 100644
index 0000000..9475159
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_3g.png b/core/res/res/drawable-hdpi/stat_sys_data_out_3g.png
new file mode 100644
index 0000000..2f49d60
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_e.png b/core/res/res/drawable-hdpi/stat_sys_data_out_e.png
new file mode 100644
index 0000000..433fa8d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_out_g.png b/core/res/res/drawable-hdpi/stat_sys_data_out_g.png
new file mode 100644
index 0000000..eb43a91
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_usb.png b/core/res/res/drawable-hdpi/stat_sys_data_usb.png
new file mode 100644
index 0000000..7a83544
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_usb.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim0.png b/core/res/res/drawable-hdpi/stat_sys_download_anim0.png
new file mode 100644
index 0000000..a907d79
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim1.png b/core/res/res/drawable-hdpi/stat_sys_download_anim1.png
new file mode 100644
index 0000000..e9f42ad
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim2.png b/core/res/res/drawable-hdpi/stat_sys_download_anim2.png
new file mode 100644
index 0000000..d1682e0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim3.png b/core/res/res/drawable-hdpi/stat_sys_download_anim3.png
new file mode 100644
index 0000000..70e757b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim4.png b/core/res/res/drawable-hdpi/stat_sys_download_anim4.png
new file mode 100644
index 0000000..3b2d7d1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_download_anim5.png b/core/res/res/drawable-hdpi/stat_sys_download_anim5.png
new file mode 100644
index 0000000..ced2bb2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_download_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_gps_acquiring.png b/core/res/res/drawable-hdpi/stat_sys_gps_acquiring.png
new file mode 100644
index 0000000..fe7b2cc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_gps_acquiring.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_gps_on.png b/core/res/res/drawable-hdpi/stat_sys_gps_on.png
new file mode 100644
index 0000000..6ab4720
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_headset.png b/core/res/res/drawable-hdpi/stat_sys_headset.png
new file mode 100644
index 0000000..7a70aea
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_headset.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_no_sim.png b/core/res/res/drawable-hdpi/stat_sys_no_sim.png
new file mode 100644
index 0000000..48d1ca3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call.png b/core/res/res/drawable-hdpi/stat_sys_phone_call.png
new file mode 100644
index 0000000..0aa15d6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_phone_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
new file mode 100644
index 0000000..a143f87
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_phone_call_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_forward.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_forward.png
new file mode 100644
index 0000000..b1ab8ac
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_phone_call_on_hold.png b/core/res/res/drawable-hdpi/stat_sys_phone_call_on_hold.png
new file mode 100644
index 0000000..b881a67
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_phone_call_on_hold.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_0.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_0.png
new file mode 100644
index 0000000..938cca7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_0_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_0_cdma.png
new file mode 100644
index 0000000..5ddd177
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_0_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_1.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_1.png
new file mode 100644
index 0000000..6f82aa9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_1_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_1_cdma.png
new file mode 100644
index 0000000..fa4265c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_1_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_2.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_2.png
new file mode 100644
index 0000000..db9752a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_2_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_2_cdma.png
new file mode 100644
index 0000000..c99af17
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_2_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_3.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_3.png
new file mode 100644
index 0000000..70594e5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png
new file mode 100644
index 0000000..5e0235f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_3_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_4.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_4.png
new file mode 100644
index 0000000..d361263
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma.png b/core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma.png
new file mode 100644
index 0000000..8b110a3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_r_signal_4_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png
new file mode 100644
index 0000000..84b9f94
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_0_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png
new file mode 100644
index 0000000..657b572
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_1_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png
new file mode 100644
index 0000000..236d44e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_2_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma.png
new file mode 100644
index 0000000..e140735
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_3_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png b/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png
new file mode 100644
index 0000000..0e4f854
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ra_signal_4_cdma.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ringer_silent.png b/core/res/res/drawable-hdpi/stat_sys_ringer_silent.png
new file mode 100644
index 0000000..d5c301c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.png b/core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.png
new file mode 100644
index 0000000..21c1c08
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_0.png b/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
new file mode 100644
index 0000000..f7f5757
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png b/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png
new file mode 100644
index 0000000..5f01083
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png b/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
new file mode 100644
index 0000000..f7f5757
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_0.png b/core/res/res/drawable-hdpi/stat_sys_signal_0.png
new file mode 100644
index 0000000..83ef6a3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_1.png b/core/res/res/drawable-hdpi/stat_sys_signal_1.png
new file mode 100644
index 0000000..a1ca717
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_2.png b/core/res/res/drawable-hdpi/stat_sys_signal_2.png
new file mode 100644
index 0000000..a478bd0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_3.png b/core/res/res/drawable-hdpi/stat_sys_signal_3.png
new file mode 100644
index 0000000..a3978de
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_4.png b/core/res/res/drawable-hdpi/stat_sys_signal_4.png
new file mode 100644
index 0000000..1b553e8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_flightmode.png b/core/res/res/drawable-hdpi/stat_sys_signal_flightmode.png
new file mode 100644
index 0000000..6ee35fb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_signal_null.png b/core/res/res/drawable-hdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..6b103f5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_speakerphone.png b/core/res/res/drawable-hdpi/stat_sys_speakerphone.png
new file mode 100644
index 0000000..62eadb3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tty_mode.png b/core/res/res/drawable-hdpi/stat_sys_tty_mode.png
new file mode 100644
index 0000000..4e161c6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_tty_mode.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png
new file mode 100644
index 0000000..4b7e942
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
new file mode 100644
index 0000000..a416350
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
new file mode 100644
index 0000000..8d199dd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png
new file mode 100644
index 0000000..dfef071
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png
new file mode 100644
index 0000000..abe56f1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png b/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png
new file mode 100644
index 0000000..1e917c1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_upload_anim5.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call.png b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call.png
new file mode 100644
index 0000000..d6b25d2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png
new file mode 100644
index 0000000..a143f87
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.png b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.png
new file mode 100644
index 0000000..53608cf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_vp_phone_call_on_hold.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_warning.png b/core/res/res/drawable-hdpi/stat_sys_warning.png
new file mode 100644
index 0000000..8f7bd5d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_warning.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_0.png b/core/res/res/drawable-hdpi/stat_sys_wifi_signal_0.png
new file mode 100644
index 0000000..9a0aa21
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_1.png b/core/res/res/drawable-hdpi/stat_sys_wifi_signal_1.png
new file mode 100644
index 0000000..39db490
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_2.png b/core/res/res/drawable-hdpi/stat_sys_wifi_signal_2.png
new file mode 100644
index 0000000..5c0ae76
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_3.png b/core/res/res/drawable-hdpi/stat_sys_wifi_signal_3.png
new file mode 100644
index 0000000..f7e0b38
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_wifi_signal_4.png b/core/res/res/drawable-hdpi/stat_sys_wifi_signal_4.png
new file mode 100644
index 0000000..5ad5d12
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/status_bar_background.png b/core/res/res/drawable-hdpi/status_bar_background.png
new file mode 100644
index 0000000..e6a865a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/status_bar_background.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/status_bar_close_on.9.png b/core/res/res/drawable-hdpi/status_bar_close_on.9.png
new file mode 100644
index 0000000..5acf638
--- /dev/null
+++ b/core/res/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/status_bar_header_background.9.png b/core/res/res/drawable-hdpi/status_bar_header_background.9.png
new file mode 100644
index 0000000..be36ff2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/status_bar_header_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/status_bar_item_app_background_normal.9.png b/core/res/res/drawable-hdpi/status_bar_item_app_background_normal.9.png
new file mode 100644
index 0000000..4fbfa4f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/status_bar_item_app_background_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/status_bar_item_background_focus.9.png b/core/res/res/drawable-hdpi/status_bar_item_background_focus.9.png
new file mode 100644
index 0000000..0876bc6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/status_bar_item_background_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/status_bar_item_background_normal.9.png b/core/res/res/drawable-hdpi/status_bar_item_background_normal.9.png
new file mode 100644
index 0000000..c01c018
--- /dev/null
+++ b/core/res/res/drawable-hdpi/status_bar_item_background_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/status_bar_item_background_pressed.9.png b/core/res/res/drawable-hdpi/status_bar_item_background_pressed.9.png
new file mode 100644
index 0000000..343e4ca
--- /dev/null
+++ b/core/res/res/drawable-hdpi/status_bar_item_background_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/statusbar_background.png b/core/res/res/drawable-hdpi/statusbar_background.png
new file mode 100644
index 0000000..c2b3a5e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/statusbar_background.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/submenu_arrow_nofocus.png b/core/res/res/drawable-hdpi/submenu_arrow_nofocus.png
new file mode 100644
index 0000000..afc0891
--- /dev/null
+++ b/core/res/res/drawable-hdpi/submenu_arrow_nofocus.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_action_add.png b/core/res/res/drawable-hdpi/sym_action_add.png
new file mode 100644
index 0000000..6e028b2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_action_add.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_action_call.png b/core/res/res/drawable-hdpi/sym_action_call.png
new file mode 100644
index 0000000..105f7d0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_action_call.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_action_chat.png b/core/res/res/drawable-hdpi/sym_action_chat.png
new file mode 100644
index 0000000..7fd34f0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_action_chat.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_action_email.png b/core/res/res/drawable-hdpi/sym_action_email.png
new file mode 100644
index 0000000..1d933e4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_action_email.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_call_incoming.png b/core/res/res/drawable-hdpi/sym_call_incoming.png
new file mode 100644
index 0000000..83c75dc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_call_incoming.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_call_missed.png b/core/res/res/drawable-hdpi/sym_call_missed.png
new file mode 100644
index 0000000..abcbbbf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_call_missed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_call_outgoing.png b/core/res/res/drawable-hdpi/sym_call_outgoing.png
new file mode 100644
index 0000000..6cb8653
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_call_outgoing.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_contact_card.png b/core/res/res/drawable-hdpi/sym_contact_card.png
new file mode 100644
index 0000000..fe9c751
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_contact_card.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sym_def_app_icon.png b/core/res/res/drawable-hdpi/sym_def_app_icon.png
new file mode 100644
index 0000000..4b5384f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus.9.png b/core/res/res/drawable-hdpi/tab_focus.9.png
new file mode 100644
index 0000000..0c3a9ee
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png b/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
new file mode 100644
index 0000000..54e3022
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png b/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
new file mode 100644
index 0000000..34a85f0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press.9.png b/core/res/res/drawable-hdpi/tab_press.9.png
new file mode 100644
index 0000000..6b3c1c7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_press.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press_bar_left.9.png b/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
new file mode 100644
index 0000000..f998532
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press_bar_right.9.png b/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
new file mode 100644
index 0000000..43515bd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected.9.png b/core/res/res/drawable-hdpi/tab_selected.9.png
new file mode 100644
index 0000000..b128b48
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png b/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
new file mode 100644
index 0000000..a49ef68
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png b/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
new file mode 100644
index 0000000..472f839
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected.9.png b/core/res/res/drawable-hdpi/tab_unselected.9.png
new file mode 100644
index 0000000..ed9e311
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_unselected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_default.9.png b/core/res/res/drawable-hdpi/textfield_default.9.png
new file mode 100644
index 0000000..a2f022a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled.9.png b/core/res/res/drawable-hdpi/textfield_disabled.9.png
new file mode 100644
index 0000000..6a28cb4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png b/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
new file mode 100644
index 0000000..0de9cda
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_pressed.9.png b/core/res/res/drawable-hdpi/textfield_pressed.9.png
new file mode 100644
index 0000000..d5892c8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default.9.png b/core/res/res/drawable-hdpi/textfield_search_default.9.png
new file mode 100644
index 0000000..db64da1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_search_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_pressed.9.png b/core/res/res/drawable-hdpi/textfield_search_pressed.9.png
new file mode 100644
index 0000000..cde51e4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_search_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_selected.9.png b/core/res/res/drawable-hdpi/textfield_search_selected.9.png
new file mode 100644
index 0000000..f4bf352
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_search_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_selected.9.png b/core/res/res/drawable-hdpi/textfield_selected.9.png
new file mode 100644
index 0000000..7a072dd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_down_disabled.9.png b/core/res/res/drawable-hdpi/timepicker_down_disabled.9.png
new file mode 100644
index 0000000..73b6915
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_down_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_down_disabled_focused.9.png b/core/res/res/drawable-hdpi/timepicker_down_disabled_focused.9.png
new file mode 100644
index 0000000..046e60f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_down_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_down_normal.9.png b/core/res/res/drawable-hdpi/timepicker_down_normal.9.png
new file mode 100644
index 0000000..9baf7cc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_down_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_down_pressed.9.png b/core/res/res/drawable-hdpi/timepicker_down_pressed.9.png
new file mode 100644
index 0000000..d95fdd3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_down_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_down_selected.9.png b/core/res/res/drawable-hdpi/timepicker_down_selected.9.png
new file mode 100644
index 0000000..a84448f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_down_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_input_disabled.9.png b/core/res/res/drawable-hdpi/timepicker_input_disabled.9.png
new file mode 100644
index 0000000..aa17a98
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_input_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_input_normal.9.png b/core/res/res/drawable-hdpi/timepicker_input_normal.9.png
new file mode 100644
index 0000000..be78a58
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_input_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_input_pressed.9.png b/core/res/res/drawable-hdpi/timepicker_input_pressed.9.png
new file mode 100644
index 0000000..b28f66c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_input_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_input_selected.9.png b/core/res/res/drawable-hdpi/timepicker_input_selected.9.png
new file mode 100644
index 0000000..2e175e8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_input_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_up_disabled.9.png b/core/res/res/drawable-hdpi/timepicker_up_disabled.9.png
new file mode 100644
index 0000000..348e48c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_up_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_up_disabled_focused.9.png b/core/res/res/drawable-hdpi/timepicker_up_disabled_focused.9.png
new file mode 100644
index 0000000..93cf3a0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_up_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_up_normal.9.png b/core/res/res/drawable-hdpi/timepicker_up_normal.9.png
new file mode 100644
index 0000000..b4acced
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_up_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_up_pressed.9.png b/core/res/res/drawable-hdpi/timepicker_up_pressed.9.png
new file mode 100644
index 0000000..bd29510
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_up_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/timepicker_up_selected.9.png b/core/res/res/drawable-hdpi/timepicker_up_selected.9.png
new file mode 100644
index 0000000..a666998
--- /dev/null
+++ b/core/res/res/drawable-hdpi/timepicker_up_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_portrait.9.png b/core/res/res/drawable-hdpi/title_bar_portrait.9.png
new file mode 100644
index 0000000..161432f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/title_bar_portrait.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_shadow.9.png b/core/res/res/drawable-hdpi/title_bar_shadow.9.png
new file mode 100644
index 0000000..e67f457
--- /dev/null
+++ b/core/res/res/drawable-hdpi/title_bar_shadow.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_tall.png b/core/res/res/drawable-hdpi/title_bar_tall.png
new file mode 100644
index 0000000..f177440
--- /dev/null
+++ b/core/res/res/drawable-hdpi/title_bar_tall.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png
new file mode 100644
index 0000000..8f5d811
--- /dev/null
+++ b/core/res/res/drawable-hdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/unknown_image.png b/core/res/res/drawable-hdpi/unknown_image.png
new file mode 100644
index 0000000..76341db
--- /dev/null
+++ b/core/res/res/drawable-hdpi/unknown_image.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/zoom_plate.9.png b/core/res/res/drawable-hdpi/zoom_plate.9.png
new file mode 100644
index 0000000..e97dac1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/zoom_plate.9.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/statusbar_background.png b/core/res/res/drawable-land-hdpi/statusbar_background.png
new file mode 100644
index 0000000..4a955c5
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/statusbar_background.png
Binary files differ
diff --git a/core/res/res/drawable-land-hdpi/title_bar_tall.png b/core/res/res/drawable-land-hdpi/title_bar_tall.png
new file mode 100644
index 0000000..96b5ffe
--- /dev/null
+++ b/core/res/res/drawable-land-hdpi/title_bar_tall.png
Binary files differ
diff --git a/core/res/res/drawable-land/statusbar_background.png b/core/res/res/drawable-land-mdpi/statusbar_background.png
index ef61e52..ef61e52 100644
--- a/core/res/res/drawable-land/statusbar_background.png
+++ b/core/res/res/drawable-land-mdpi/statusbar_background.png
Binary files differ
diff --git a/core/res/res/drawable-land/title_bar_tall.png b/core/res/res/drawable-land-mdpi/title_bar_tall.png
index 16290fb..16290fb 100644
--- a/core/res/res/drawable-land/title_bar_tall.png
+++ b/core/res/res/drawable-land-mdpi/title_bar_tall.png
Binary files differ
diff --git a/core/res/res/drawable/activity_title_bar.9.png b/core/res/res/drawable-mdpi/activity_title_bar.9.png
index bd0680d..bd0680d 100644
--- a/core/res/res/drawable/activity_title_bar.9.png
+++ b/core/res/res/drawable-mdpi/activity_title_bar.9.png
Binary files differ
diff --git a/core/res/res/drawable/arrow_down_float.png b/core/res/res/drawable-mdpi/arrow_down_float.png
index dd82523..dd82523 100644
--- a/core/res/res/drawable/arrow_down_float.png
+++ b/core/res/res/drawable-mdpi/arrow_down_float.png
Binary files differ
diff --git a/core/res/res/drawable/arrow_up_float.png b/core/res/res/drawable-mdpi/arrow_up_float.png
index 9bc3d1c..9bc3d1c 100644
--- a/core/res/res/drawable/arrow_up_float.png
+++ b/core/res/res/drawable-mdpi/arrow_up_float.png
Binary files differ
diff --git a/core/res/res/drawable/battery_charge_background.png b/core/res/res/drawable-mdpi/battery_charge_background.png
index 9219745..9219745 100644
--- a/core/res/res/drawable/battery_charge_background.png
+++ b/core/res/res/drawable-mdpi/battery_charge_background.png
Binary files differ
diff --git a/core/res/res/drawable/battery_charge_fill_empty.9.png b/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png
index 9ed20ba..9ed20ba 100644
--- a/core/res/res/drawable/battery_charge_fill_empty.9.png
+++ b/core/res/res/drawable-mdpi/battery_charge_fill_empty.9.png
Binary files differ
diff --git a/core/res/res/drawable/battery_charge_fill_full.9.png b/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png
index 8e6aaca..8e6aaca 100644
--- a/core/res/res/drawable/battery_charge_fill_full.9.png
+++ b/core/res/res/drawable-mdpi/battery_charge_fill_full.9.png
Binary files differ
diff --git a/core/res/res/drawable/battery_charge_fill_warning.9.png b/core/res/res/drawable-mdpi/battery_charge_fill_warning.9.png
index d3287db..d3287db 100644
--- a/core/res/res/drawable/battery_charge_fill_warning.9.png
+++ b/core/res/res/drawable-mdpi/battery_charge_fill_warning.9.png
Binary files differ
diff --git a/core/res/res/drawable/battery_low_battery.png b/core/res/res/drawable-mdpi/battery_low_battery.png
index 60bbe6c..60bbe6c 100644
--- a/core/res/res/drawable/battery_low_battery.png
+++ b/core/res/res/drawable-mdpi/battery_low_battery.png
Binary files differ
diff --git a/core/res/res/drawable/blank_tile.png b/core/res/res/drawable-mdpi/blank_tile.png
index 63b9296..63b9296 100644
--- a/core/res/res/drawable/blank_tile.png
+++ b/core/res/res/drawable-mdpi/blank_tile.png
Binary files differ
diff --git a/core/res/res/drawable/bottom_bar.png b/core/res/res/drawable-mdpi/bottom_bar.png
index 1fdb078..1fdb078 100644
--- a/core/res/res/drawable/bottom_bar.png
+++ b/core/res/res/drawable-mdpi/bottom_bar.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_buttonless_off.png b/core/res/res/drawable-mdpi/btn_check_buttonless_off.png
index f8972fc..f8972fc 100755
--- a/core/res/res/drawable/btn_check_buttonless_off.png
+++ b/core/res/res/drawable-mdpi/btn_check_buttonless_off.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_buttonless_on.png b/core/res/res/drawable-mdpi/btn_check_buttonless_on.png
index a10a37a..a10a37a 100755
--- a/core/res/res/drawable/btn_check_buttonless_on.png
+++ b/core/res/res/drawable-mdpi/btn_check_buttonless_on.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_label_background.9.png b/core/res/res/drawable-mdpi/btn_check_label_background.9.png
index 79367b8..79367b8 100644
--- a/core/res/res/drawable/btn_check_label_background.9.png
+++ b/core/res/res/drawable-mdpi/btn_check_label_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off.png b/core/res/res/drawable-mdpi/btn_check_off.png
index 56d3861..56d3861 100644
--- a/core/res/res/drawable/btn_check_off.png
+++ b/core/res/res/drawable-mdpi/btn_check_off.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_disable.png b/core/res/res/drawable-mdpi/btn_check_off_disable.png
index e012afd..e012afd 100644
--- a/core/res/res/drawable/btn_check_off_disable.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_disable_focused.png b/core/res/res/drawable-mdpi/btn_check_off_disable_focused.png
index 0837bbd..0837bbd 100644
--- a/core/res/res/drawable/btn_check_off_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_pressed.png b/core/res/res/drawable-mdpi/btn_check_off_pressed.png
index 984dfd7..984dfd7 100644
--- a/core/res/res/drawable/btn_check_off_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_selected.png b/core/res/res/drawable-mdpi/btn_check_off_selected.png
index 20842d4..20842d4 100644
--- a/core/res/res/drawable/btn_check_off_selected.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on.png b/core/res/res/drawable-mdpi/btn_check_on.png
index 791ac1d..791ac1d 100644
--- a/core/res/res/drawable/btn_check_on.png
+++ b/core/res/res/drawable-mdpi/btn_check_on.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_disable.png b/core/res/res/drawable-mdpi/btn_check_on_disable.png
index 6cb02f3..6cb02f3 100644
--- a/core/res/res/drawable/btn_check_on_disable.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_disable_focused.png b/core/res/res/drawable-mdpi/btn_check_on_disable_focused.png
index 8a73b33..8a73b33 100644
--- a/core/res/res/drawable/btn_check_on_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_pressed.png b/core/res/res/drawable-mdpi/btn_check_on_pressed.png
index 300d64a..300d64a 100644
--- a/core/res/res/drawable/btn_check_on_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_selected.png b/core/res/res/drawable-mdpi/btn_check_on_selected.png
index 0b36adb..0b36adb 100644
--- a/core/res/res/drawable/btn_check_on_selected.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_disable.png b/core/res/res/drawable-mdpi/btn_circle_disable.png
index 33b74a6..33b74a6 100644
--- a/core/res/res/drawable/btn_circle_disable.png
+++ b/core/res/res/drawable-mdpi/btn_circle_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_disable_focused.png b/core/res/res/drawable-mdpi/btn_circle_disable_focused.png
index 005ad8d..005ad8d 100644
--- a/core/res/res/drawable/btn_circle_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_circle_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_normal.png b/core/res/res/drawable-mdpi/btn_circle_normal.png
index fc5af1c..fc5af1c 100644
--- a/core/res/res/drawable/btn_circle_normal.png
+++ b/core/res/res/drawable-mdpi/btn_circle_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_pressed.png b/core/res/res/drawable-mdpi/btn_circle_pressed.png
index 8f40afd..8f40afd 100644
--- a/core/res/res/drawable/btn_circle_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_circle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_selected.png b/core/res/res/drawable-mdpi/btn_circle_selected.png
index c74fac2..c74fac2 100644
--- a/core/res/res/drawable/btn_circle_selected.png
+++ b/core/res/res/drawable-mdpi/btn_circle_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_close_normal.png b/core/res/res/drawable-mdpi/btn_close_normal.png
index ecc4dde..ecc4dde 100644
--- a/core/res/res/drawable/btn_close_normal.png
+++ b/core/res/res/drawable-mdpi/btn_close_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_close_pressed.png b/core/res/res/drawable-mdpi/btn_close_pressed.png
index 49223c5..49223c5 100644
--- a/core/res/res/drawable/btn_close_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_close_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_code_lock_default.png b/core/res/res/drawable-mdpi/btn_code_lock_default.png
index c2e0b05..c2e0b05 100755
--- a/core/res/res/drawable/btn_code_lock_default.png
+++ b/core/res/res/drawable-mdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable/btn_code_lock_touched.png b/core/res/res/drawable-mdpi/btn_code_lock_touched.png
index 70e95a2..70e95a2 100755
--- a/core/res/res/drawable/btn_code_lock_touched.png
+++ b/core/res/res/drawable-mdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_normal.9.png b/core/res/res/drawable-mdpi/btn_default_normal.9.png
index a2d5ccd..a2d5ccd 100644
--- a/core/res/res/drawable/btn_default_normal.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_normal_disable.9.png b/core/res/res/drawable-mdpi/btn_default_normal_disable.9.png
index edd3a3e..edd3a3e 100644
--- a/core/res/res/drawable/btn_default_normal_disable.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_normal_disable_focused.9.png b/core/res/res/drawable-mdpi/btn_default_normal_disable_focused.9.png
index f506179..f506179 100644
--- a/core/res/res/drawable/btn_default_normal_disable_focused.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_pressed.9.png b/core/res/res/drawable-mdpi/btn_default_pressed.9.png
index 033bf89..033bf89 100644
--- a/core/res/res/drawable/btn_default_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_selected.9.png b/core/res/res/drawable-mdpi/btn_default_selected.9.png
index 1e900bf..1e900bf 100644
--- a/core/res/res/drawable/btn_default_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_normal.9.png b/core/res/res/drawable-mdpi/btn_default_small_normal.9.png
index bcedd5f..bcedd5f 100644
--- a/core/res/res/drawable/btn_default_small_normal.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_small_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_normal_disable.9.png b/core/res/res/drawable-mdpi/btn_default_small_normal_disable.9.png
index ac6260f..ac6260f 100644
--- a/core/res/res/drawable/btn_default_small_normal_disable.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png b/core/res/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
index 4ee1b3f..4ee1b3f 100644
--- a/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_pressed.9.png b/core/res/res/drawable-mdpi/btn_default_small_pressed.9.png
index 25e38f4..25e38f4 100644
--- a/core/res/res/drawable/btn_default_small_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_selected.9.png b/core/res/res/drawable-mdpi/btn_default_small_selected.9.png
index cc209c6..cc209c6 100644
--- a/core/res/res/drawable/btn_default_small_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_small_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dialog_disable.png b/core/res/res/drawable-mdpi/btn_dialog_disable.png
index f041cab..f041cab 100755
--- a/core/res/res/drawable/btn_dialog_disable.png
+++ b/core/res/res/drawable-mdpi/btn_dialog_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dialog_normal.png b/core/res/res/drawable-mdpi/btn_dialog_normal.png
index a2d27fa..a2d27fa 100755
--- a/core/res/res/drawable/btn_dialog_normal.png
+++ b/core/res/res/drawable-mdpi/btn_dialog_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dialog_pressed.png b/core/res/res/drawable-mdpi/btn_dialog_pressed.png
index 9c9922a..9c9922a 100755
--- a/core/res/res/drawable/btn_dialog_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_dialog_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dialog_selected.png b/core/res/res/drawable-mdpi/btn_dialog_selected.png
index 7656de5..7656de5 100755
--- a/core/res/res/drawable/btn_dialog_selected.png
+++ b/core/res/res/drawable-mdpi/btn_dialog_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dropdown_normal.9.png b/core/res/res/drawable-mdpi/btn_dropdown_normal.9.png
index f6e9a19..f6e9a19 100644
--- a/core/res/res/drawable/btn_dropdown_normal.9.png
+++ b/core/res/res/drawable-mdpi/btn_dropdown_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dropdown_pressed.9.png b/core/res/res/drawable-mdpi/btn_dropdown_pressed.9.png
index 3bdf52d..3bdf52d 100644
--- a/core/res/res/drawable/btn_dropdown_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_dropdown_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_dropdown_selected.9.png b/core/res/res/drawable-mdpi/btn_dropdown_selected.9.png
index 087956e..087956e 100644
--- a/core/res/res/drawable/btn_dropdown_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_dropdown_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_erase_default.9.png b/core/res/res/drawable-mdpi/btn_erase_default.9.png
index c3bf60c..c3bf60c 100755
--- a/core/res/res/drawable/btn_erase_default.9.png
+++ b/core/res/res/drawable-mdpi/btn_erase_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_erase_pressed.9.png b/core/res/res/drawable-mdpi/btn_erase_pressed.9.png
index 727aafe..727aafe 100755
--- a/core/res/res/drawable/btn_erase_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_erase_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_erase_selected.9.png b/core/res/res/drawable-mdpi/btn_erase_selected.9.png
index c6bd020..c6bd020 100755
--- a/core/res/res/drawable/btn_erase_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_erase_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_global_search_normal.9.png b/core/res/res/drawable-mdpi/btn_global_search_normal.9.png
index 9b7d3e5..9b7d3e5 100644
--- a/core/res/res/drawable/btn_global_search_normal.9.png
+++ b/core/res/res/drawable-mdpi/btn_global_search_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_normal.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_normal.9.png
index 7ba18dd..7ba18dd 100644
--- a/core/res/res/drawable/btn_keyboard_key_normal.9.png
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_normal_off.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_normal_off.9.png
index bda9b83..bda9b83 100644
--- a/core/res/res/drawable/btn_keyboard_key_normal_off.9.png
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_normal_off.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_normal_on.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_normal_on.9.png
index 0c16ed5..0c16ed5 100644
--- a/core/res/res/drawable/btn_keyboard_key_normal_on.9.png
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_normal_on.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_pressed.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_pressed.9.png
index 39b9314..39b9314 100755
--- a/core/res/res/drawable/btn_keyboard_key_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.png
index bdcf06e..bdcf06e 100644
--- a/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_pressed_off.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png b/core/res/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.png
index 79621a9..79621a9 100644
--- a/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png
+++ b/core/res/res/drawable-mdpi/btn_keyboard_key_pressed_on.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_media_player.9.png b/core/res/res/drawable-mdpi/btn_media_player.9.png
index 3ec3f68..3ec3f68 100755
--- a/core/res/res/drawable/btn_media_player.9.png
+++ b/core/res/res/drawable-mdpi/btn_media_player.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_media_player_disabled.9.png b/core/res/res/drawable-mdpi/btn_media_player_disabled.9.png
index e74335b..e74335b 100755
--- a/core/res/res/drawable/btn_media_player_disabled.9.png
+++ b/core/res/res/drawable-mdpi/btn_media_player_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_media_player_disabled_selected.9.png b/core/res/res/drawable-mdpi/btn_media_player_disabled_selected.9.png
index 2c6517f..2c6517f 100755
--- a/core/res/res/drawable/btn_media_player_disabled_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_media_player_disabled_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_media_player_pressed.9.png b/core/res/res/drawable-mdpi/btn_media_player_pressed.9.png
index 40bee47..40bee47 100755
--- a/core/res/res/drawable/btn_media_player_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_media_player_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_media_player_selected.9.png b/core/res/res/drawable-mdpi/btn_media_player_selected.9.png
index 28d809f..28d809f 100755
--- a/core/res/res/drawable/btn_media_player_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_media_player_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_minus_default.png b/core/res/res/drawable-mdpi/btn_minus_default.png
index ee95879..ee95879 100644
--- a/core/res/res/drawable/btn_minus_default.png
+++ b/core/res/res/drawable-mdpi/btn_minus_default.png
Binary files differ
diff --git a/core/res/res/drawable/btn_minus_disable.png b/core/res/res/drawable-mdpi/btn_minus_disable.png
index dff7bf7..dff7bf7 100644
--- a/core/res/res/drawable/btn_minus_disable.png
+++ b/core/res/res/drawable-mdpi/btn_minus_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_minus_disable_focused.png b/core/res/res/drawable-mdpi/btn_minus_disable_focused.png
index 3f04557..3f04557 100644
--- a/core/res/res/drawable/btn_minus_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_minus_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_minus_pressed.png b/core/res/res/drawable-mdpi/btn_minus_pressed.png
index 758d958..758d958 100644
--- a/core/res/res/drawable/btn_minus_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_minus_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_minus_selected.png b/core/res/res/drawable-mdpi/btn_minus_selected.png
index 752a249..752a249 100644
--- a/core/res/res/drawable/btn_minus_selected.png
+++ b/core/res/res/drawable-mdpi/btn_minus_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_plus_default.png b/core/res/res/drawable-mdpi/btn_plus_default.png
index aa31e37..aa31e37 100644
--- a/core/res/res/drawable/btn_plus_default.png
+++ b/core/res/res/drawable-mdpi/btn_plus_default.png
Binary files differ
diff --git a/core/res/res/drawable/btn_plus_disable.png b/core/res/res/drawable-mdpi/btn_plus_disable.png
index c373cd3..c373cd3 100644
--- a/core/res/res/drawable/btn_plus_disable.png
+++ b/core/res/res/drawable-mdpi/btn_plus_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_plus_disable_focused.png b/core/res/res/drawable-mdpi/btn_plus_disable_focused.png
index 8f72a5f..8f72a5f 100644
--- a/core/res/res/drawable/btn_plus_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_plus_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_plus_pressed.png b/core/res/res/drawable-mdpi/btn_plus_pressed.png
index 1fb8413..1fb8413 100644
--- a/core/res/res/drawable/btn_plus_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_plus_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_plus_selected.png b/core/res/res/drawable-mdpi/btn_plus_selected.png
index 47fe9bf..47fe9bf 100644
--- a/core/res/res/drawable/btn_plus_selected.png
+++ b/core/res/res/drawable-mdpi/btn_plus_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_label_background.9.png b/core/res/res/drawable-mdpi/btn_radio_label_background.9.png
index 16e8939..16e8939 100644
--- a/core/res/res/drawable/btn_radio_label_background.9.png
+++ b/core/res/res/drawable-mdpi/btn_radio_label_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off.png b/core/res/res/drawable-mdpi/btn_radio_off.png
index 407632b..407632b 100644
--- a/core/res/res/drawable/btn_radio_off.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off_pressed.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed.png
index d6d8a9d..d6d8a9d 100644
--- a/core/res/res/drawable/btn_radio_off_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off_selected.png b/core/res/res/drawable-mdpi/btn_radio_off_selected.png
index 53f3e87..53f3e87 100644
--- a/core/res/res/drawable/btn_radio_off_selected.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on.png b/core/res/res/drawable-mdpi/btn_radio_on.png
index 25a3ccc..25a3ccc 100644
--- a/core/res/res/drawable/btn_radio_on.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on_pressed.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed.png
index c904a35..c904a35 100644
--- a/core/res/res/drawable/btn_radio_on_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on_selected.png b/core/res/res/drawable-mdpi/btn_radio_on_selected.png
index 78e1fc0..78e1fc0 100644
--- a/core/res/res/drawable/btn_radio_on_selected.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_off_normal.png b/core/res/res/drawable-mdpi/btn_rating_star_off_normal.png
index a99441d..a99441d 100644
--- a/core/res/res/drawable/btn_rating_star_off_normal.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_off_pressed.png b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed.png
index f47a454..f47a454 100644
--- a/core/res/res/drawable/btn_rating_star_off_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_off_selected.png b/core/res/res/drawable-mdpi/btn_rating_star_off_selected.png
index 5f71e08..5f71e08 100644
--- a/core/res/res/drawable/btn_rating_star_off_selected.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_on_normal.png b/core/res/res/drawable-mdpi/btn_rating_star_on_normal.png
index b7825d3..b7825d3 100644
--- a/core/res/res/drawable/btn_rating_star_on_normal.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_on_pressed.png b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed.png
index 4052445..4052445 100644
--- a/core/res/res/drawable/btn_rating_star_on_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_on_selected.png b/core/res/res/drawable-mdpi/btn_rating_star_on_selected.png
index 5d139b6..5d139b6 100644
--- a/core/res/res/drawable/btn_rating_star_on_selected.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_default.9.png b/core/res/res/drawable-mdpi/btn_search_dialog_default.9.png
index 7275231..7275231 100644
--- a/core/res/res/drawable/btn_search_dialog_default.9.png
+++ b/core/res/res/drawable-mdpi/btn_search_dialog_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_pressed.9.png b/core/res/res/drawable-mdpi/btn_search_dialog_pressed.9.png
index 50a9209..50a9209 100644
--- a/core/res/res/drawable/btn_search_dialog_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_search_dialog_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_selected.9.png b/core/res/res/drawable-mdpi/btn_search_dialog_selected.9.png
index 14b774a..14b774a 100644
--- a/core/res/res/drawable/btn_search_dialog_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_search_dialog_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_voice_default.9.png b/core/res/res/drawable-mdpi/btn_search_dialog_voice_default.9.png
index febf222..febf222 100644
--- a/core/res/res/drawable/btn_search_dialog_voice_default.9.png
+++ b/core/res/res/drawable-mdpi/btn_search_dialog_voice_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png b/core/res/res/drawable-mdpi/btn_search_dialog_voice_pressed.9.png
index 70a200b..70a200b 100644
--- a/core/res/res/drawable/btn_search_dialog_voice_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_search_dialog_voice_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_search_dialog_voice_selected.9.png b/core/res/res/drawable-mdpi/btn_search_dialog_voice_selected.9.png
index 6f2989f..6f2989f 100644
--- a/core/res/res/drawable/btn_search_dialog_voice_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_search_dialog_voice_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_square_overlay_disabled.png b/core/res/res/drawable-mdpi/btn_square_overlay_disabled.png
index cf7e4ea..cf7e4ea 100644
--- a/core/res/res/drawable/btn_square_overlay_disabled.png
+++ b/core/res/res/drawable-mdpi/btn_square_overlay_disabled.png
Binary files differ
diff --git a/core/res/res/drawable/btn_square_overlay_disabled_focused.png b/core/res/res/drawable-mdpi/btn_square_overlay_disabled_focused.png
index 5aa1143..5aa1143 100644
--- a/core/res/res/drawable/btn_square_overlay_disabled_focused.png
+++ b/core/res/res/drawable-mdpi/btn_square_overlay_disabled_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_square_overlay_normal.png b/core/res/res/drawable-mdpi/btn_square_overlay_normal.png
index 45fa4fe..45fa4fe 100644
--- a/core/res/res/drawable/btn_square_overlay_normal.png
+++ b/core/res/res/drawable-mdpi/btn_square_overlay_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_square_overlay_pressed.png b/core/res/res/drawable-mdpi/btn_square_overlay_pressed.png
index 952571b..952571b 100644
--- a/core/res/res/drawable/btn_square_overlay_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_square_overlay_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_square_overlay_selected.png b/core/res/res/drawable-mdpi/btn_square_overlay_selected.png
index ce4515e..ce4515e 100644
--- a/core/res/res/drawable/btn_square_overlay_selected.png
+++ b/core/res/res/drawable-mdpi/btn_square_overlay_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_off.png b/core/res/res/drawable-mdpi/btn_star_big_off.png
index 7e9342b..7e9342b 100755
--- a/core/res/res/drawable/btn_star_big_off.png
+++ b/core/res/res/drawable-mdpi/btn_star_big_off.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_off_disable.png b/core/res/res/drawable-mdpi/btn_star_big_off_disable.png
index 066d920..066d920 100755
--- a/core/res/res/drawable/btn_star_big_off_disable.png
+++ b/core/res/res/drawable-mdpi/btn_star_big_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_off_disable_focused.png b/core/res/res/drawable-mdpi/btn_star_big_off_disable_focused.png
index 1855d2c..1855d2c 100755
--- a/core/res/res/drawable/btn_star_big_off_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_star_big_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_off_pressed.png b/core/res/res/drawable-mdpi/btn_star_big_off_pressed.png
index f1b8912..f1b8912 100755
--- a/core/res/res/drawable/btn_star_big_off_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_star_big_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_off_selected.png b/core/res/res/drawable-mdpi/btn_star_big_off_selected.png
index 0be64c4..0be64c4 100755
--- a/core/res/res/drawable/btn_star_big_off_selected.png
+++ b/core/res/res/drawable-mdpi/btn_star_big_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_on.png b/core/res/res/drawable-mdpi/btn_star_big_on.png
index a9bdb05..a9bdb05 100755
--- a/core/res/res/drawable/btn_star_big_on.png
+++ b/core/res/res/drawable-mdpi/btn_star_big_on.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_on_disable.png b/core/res/res/drawable-mdpi/btn_star_big_on_disable.png
index 5e65a2f..5e65a2f 100755
--- a/core/res/res/drawable/btn_star_big_on_disable.png
+++ b/core/res/res/drawable-mdpi/btn_star_big_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_on_disable_focused.png b/core/res/res/drawable-mdpi/btn_star_big_on_disable_focused.png
index de57571..de57571 100755
--- a/core/res/res/drawable/btn_star_big_on_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_star_big_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_on_pressed.png b/core/res/res/drawable-mdpi/btn_star_big_on_pressed.png
index 159a84b..159a84b 100755
--- a/core/res/res/drawable/btn_star_big_on_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_star_big_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_on_selected.png b/core/res/res/drawable-mdpi/btn_star_big_on_selected.png
index 0592d51..0592d51 100755
--- a/core/res/res/drawable/btn_star_big_on_selected.png
+++ b/core/res/res/drawable-mdpi/btn_star_big_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_label_background.9.png b/core/res/res/drawable-mdpi/btn_star_label_background.9.png
index e493171..e493171 100644
--- a/core/res/res/drawable/btn_star_label_background.9.png
+++ b/core/res/res/drawable-mdpi/btn_star_label_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_toggle_off.9.png b/core/res/res/drawable-mdpi/btn_toggle_off.9.png
index 26ee1c2..26ee1c2 100644
--- a/core/res/res/drawable/btn_toggle_off.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_toggle_on.9.png b/core/res/res/drawable-mdpi/btn_toggle_on.9.png
index 53e95af..53e95af 100644
--- a/core/res/res/drawable/btn_toggle_on.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down_disabled.9.png b/core/res/res/drawable-mdpi/btn_zoom_down_disabled.9.png
index 7780bd7..7780bd7 100644
--- a/core/res/res/drawable/btn_zoom_down_disabled.9.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_down_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down_disabled_focused.9.png b/core/res/res/drawable-mdpi/btn_zoom_down_disabled_focused.9.png
index 39131c5..39131c5 100644
--- a/core/res/res/drawable/btn_zoom_down_disabled_focused.9.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_down_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down_normal.9.png b/core/res/res/drawable-mdpi/btn_zoom_down_normal.9.png
index b589a84..b589a84 100644
--- a/core/res/res/drawable/btn_zoom_down_normal.9.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_down_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down_pressed.9.png b/core/res/res/drawable-mdpi/btn_zoom_down_pressed.9.png
index a8ca467..a8ca467 100644
--- a/core/res/res/drawable/btn_zoom_down_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_down_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down_selected.9.png b/core/res/res/drawable-mdpi/btn_zoom_down_selected.9.png
index af551e7..af551e7 100644
--- a/core/res/res/drawable/btn_zoom_down_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_down_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_page_normal.png b/core/res/res/drawable-mdpi/btn_zoom_page_normal.png
index 839915b..839915b 100644
--- a/core/res/res/drawable/btn_zoom_page_normal.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_page_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_page_press.png b/core/res/res/drawable-mdpi/btn_zoom_page_press.png
index e8af276..e8af276 100644
--- a/core/res/res/drawable/btn_zoom_page_press.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_page_press.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up_disabled.9.png b/core/res/res/drawable-mdpi/btn_zoom_up_disabled.9.png
index 5203630..5203630 100644
--- a/core/res/res/drawable/btn_zoom_up_disabled.9.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_up_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up_disabled_focused.9.png b/core/res/res/drawable-mdpi/btn_zoom_up_disabled_focused.9.png
index c72c9cd..c72c9cd 100644
--- a/core/res/res/drawable/btn_zoom_up_disabled_focused.9.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_up_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up_normal.9.png b/core/res/res/drawable-mdpi/btn_zoom_up_normal.9.png
index 5027348..5027348 100644
--- a/core/res/res/drawable/btn_zoom_up_normal.9.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_up_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up_pressed.9.png b/core/res/res/drawable-mdpi/btn_zoom_up_pressed.9.png
index 1a93e3a..1a93e3a 100644
--- a/core/res/res/drawable/btn_zoom_up_pressed.9.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_up_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up_selected.9.png b/core/res/res/drawable-mdpi/btn_zoom_up_selected.9.png
index 26aafee..26aafee 100644
--- a/core/res/res/drawable/btn_zoom_up_selected.9.png
+++ b/core/res/res/drawable-mdpi/btn_zoom_up_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/button_onoff_indicator_off.png b/core/res/res/drawable-mdpi/button_onoff_indicator_off.png
index 91e7244..91e7244 100644
--- a/core/res/res/drawable/button_onoff_indicator_off.png
+++ b/core/res/res/drawable-mdpi/button_onoff_indicator_off.png
Binary files differ
diff --git a/core/res/res/drawable/button_onoff_indicator_on.png b/core/res/res/drawable-mdpi/button_onoff_indicator_on.png
index 361364b..361364b 100644
--- a/core/res/res/drawable/button_onoff_indicator_on.png
+++ b/core/res/res/drawable-mdpi/button_onoff_indicator_on.png
Binary files differ
diff --git a/core/res/res/drawable/call_contact.png b/core/res/res/drawable-mdpi/call_contact.png
index 1abeb5d..1abeb5d 100644
--- a/core/res/res/drawable/call_contact.png
+++ b/core/res/res/drawable-mdpi/call_contact.png
Binary files differ
diff --git a/core/res/res/drawable/checkbox_off_background.png b/core/res/res/drawable-mdpi/checkbox_off_background.png
index 6b2124f..6b2124f 100644
--- a/core/res/res/drawable/checkbox_off_background.png
+++ b/core/res/res/drawable-mdpi/checkbox_off_background.png
Binary files differ
diff --git a/core/res/res/drawable/checkbox_on_background.png b/core/res/res/drawable-mdpi/checkbox_on_background.png
index 56495fc..56495fc 100644
--- a/core/res/res/drawable/checkbox_on_background.png
+++ b/core/res/res/drawable-mdpi/checkbox_on_background.png
Binary files differ
diff --git a/core/res/res/drawable/clock_dial.png b/core/res/res/drawable-mdpi/clock_dial.png
index 82f73fe..82f73fe 100644
--- a/core/res/res/drawable/clock_dial.png
+++ b/core/res/res/drawable-mdpi/clock_dial.png
Binary files differ
diff --git a/core/res/res/drawable/clock_hand_hour.png b/core/res/res/drawable-mdpi/clock_hand_hour.png
index 1f0aec8..1f0aec8 100644
--- a/core/res/res/drawable/clock_hand_hour.png
+++ b/core/res/res/drawable-mdpi/clock_hand_hour.png
Binary files differ
diff --git a/core/res/res/drawable/clock_hand_minute.png b/core/res/res/drawable-mdpi/clock_hand_minute.png
index 6cd8a4b..6cd8a4b 100644
--- a/core/res/res/drawable/clock_hand_minute.png
+++ b/core/res/res/drawable-mdpi/clock_hand_minute.png
Binary files differ
diff --git a/core/res/res/drawable/code_lock_bottom.9.png b/core/res/res/drawable-mdpi/code_lock_bottom.9.png
index 812cf00..812cf00 100644
--- a/core/res/res/drawable/code_lock_bottom.9.png
+++ b/core/res/res/drawable-mdpi/code_lock_bottom.9.png
Binary files differ
diff --git a/core/res/res/drawable/code_lock_left.9.png b/core/res/res/drawable-mdpi/code_lock_left.9.png
index 215dcc8..215dcc8 100644
--- a/core/res/res/drawable/code_lock_left.9.png
+++ b/core/res/res/drawable-mdpi/code_lock_left.9.png
Binary files differ
diff --git a/core/res/res/drawable/code_lock_top.9.png b/core/res/res/drawable-mdpi/code_lock_top.9.png
index 2b75a7c..2b75a7c 100644
--- a/core/res/res/drawable/code_lock_top.9.png
+++ b/core/res/res/drawable-mdpi/code_lock_top.9.png
Binary files differ
diff --git a/core/res/res/drawable/compass_arrow.png b/core/res/res/drawable-mdpi/compass_arrow.png
index 5a4d8c1..5a4d8c1 100644
--- a/core/res/res/drawable/compass_arrow.png
+++ b/core/res/res/drawable-mdpi/compass_arrow.png
Binary files differ
diff --git a/core/res/res/drawable/compass_base.png b/core/res/res/drawable-mdpi/compass_base.png
index 3d694f0..3d694f0 100644
--- a/core/res/res/drawable/compass_base.png
+++ b/core/res/res/drawable-mdpi/compass_base.png
Binary files differ
diff --git a/core/res/res/drawable/create_contact.png b/core/res/res/drawable-mdpi/create_contact.png
index 5c5718b..5c5718b 100644
--- a/core/res/res/drawable/create_contact.png
+++ b/core/res/res/drawable-mdpi/create_contact.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dark_header.9.png b/core/res/res/drawable-mdpi/dark_header.9.png
new file mode 100644
index 0000000..7242b61
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dark_header.9.png
Binary files differ
diff --git a/core/res/res/drawable/dialog_divider_horizontal_light.9.png b/core/res/res/drawable-mdpi/dialog_divider_horizontal_light.9.png
index b69619b..b69619b 100755
--- a/core/res/res/drawable/dialog_divider_horizontal_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_divider_horizontal_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/divider_horizontal_bright.9.png b/core/res/res/drawable-mdpi/divider_horizontal_bright.9.png
new file mode 100644
index 0000000..395227a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/divider_horizontal_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/divider_horizontal_bright_opaque.9.png b/core/res/res/drawable-mdpi/divider_horizontal_bright_opaque.9.png
new file mode 100644
index 0000000..5c537ee
--- /dev/null
+++ b/core/res/res/drawable-mdpi/divider_horizontal_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/divider_horizontal_dark.9.png b/core/res/res/drawable-mdpi/divider_horizontal_dark.9.png
new file mode 100644
index 0000000..548d0bd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/divider_horizontal_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/divider_horizontal_dark_opaque.9.png b/core/res/res/drawable-mdpi/divider_horizontal_dark_opaque.9.png
new file mode 100644
index 0000000..8f35315
--- /dev/null
+++ b/core/res/res/drawable-mdpi/divider_horizontal_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_dim_dark.9.png b/core/res/res/drawable-mdpi/divider_horizontal_dim_dark.9.png
index 08838ca..08838ca 100644
--- a/core/res/res/drawable/divider_horizontal_dim_dark.9.png
+++ b/core/res/res/drawable-mdpi/divider_horizontal_dim_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_textfield.9.png b/core/res/res/drawable-mdpi/divider_horizontal_textfield.9.png
index 43eb51d..43eb51d 100644
--- a/core/res/res/drawable/divider_horizontal_textfield.9.png
+++ b/core/res/res/drawable-mdpi/divider_horizontal_textfield.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/divider_vertical_bright.9.png b/core/res/res/drawable-mdpi/divider_vertical_bright.9.png
new file mode 100644
index 0000000..395227a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/divider_vertical_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable/editbox_background_focus_yellow.9.png b/core/res/res/drawable-mdpi/editbox_background_focus_yellow.9.png
index faf52ed..faf52ed 100644
--- a/core/res/res/drawable/editbox_background_focus_yellow.9.png
+++ b/core/res/res/drawable-mdpi/editbox_background_focus_yellow.9.png
Binary files differ
diff --git a/core/res/res/drawable/editbox_background_normal.9.png b/core/res/res/drawable-mdpi/editbox_background_normal.9.png
index 9b8be77..9b8be77 100644
--- a/core/res/res/drawable/editbox_background_normal.9.png
+++ b/core/res/res/drawable-mdpi/editbox_background_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/editbox_dropdown_background.9.png b/core/res/res/drawable-mdpi/editbox_dropdown_background.9.png
index ed1bc29..ed1bc29 100644
--- a/core/res/res/drawable/editbox_dropdown_background.9.png
+++ b/core/res/res/drawable-mdpi/editbox_dropdown_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/editbox_dropdown_background_dark.9.png b/core/res/res/drawable-mdpi/editbox_dropdown_background_dark.9.png
index 88c1d9d..88c1d9d 100644
--- a/core/res/res/drawable/editbox_dropdown_background_dark.9.png
+++ b/core/res/res/drawable-mdpi/editbox_dropdown_background_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_angel.png b/core/res/res/drawable-mdpi/emo_im_angel.png
index c34dfa6..c34dfa6 100644
--- a/core/res/res/drawable/emo_im_angel.png
+++ b/core/res/res/drawable-mdpi/emo_im_angel.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_cool.png b/core/res/res/drawable-mdpi/emo_im_cool.png
index d8eeb34..d8eeb34 100644
--- a/core/res/res/drawable/emo_im_cool.png
+++ b/core/res/res/drawable-mdpi/emo_im_cool.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_crying.png b/core/res/res/drawable-mdpi/emo_im_crying.png
index 1cafdb3..1cafdb3 100644
--- a/core/res/res/drawable/emo_im_crying.png
+++ b/core/res/res/drawable-mdpi/emo_im_crying.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_foot_in_mouth.png b/core/res/res/drawable-mdpi/emo_im_foot_in_mouth.png
index 09d1fba..09d1fba 100644
--- a/core/res/res/drawable/emo_im_foot_in_mouth.png
+++ b/core/res/res/drawable-mdpi/emo_im_foot_in_mouth.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_happy.png b/core/res/res/drawable-mdpi/emo_im_happy.png
index b86602a..b86602a 100644
--- a/core/res/res/drawable/emo_im_happy.png
+++ b/core/res/res/drawable-mdpi/emo_im_happy.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_kissing.png b/core/res/res/drawable-mdpi/emo_im_kissing.png
index 56378f6..56378f6 100644
--- a/core/res/res/drawable/emo_im_kissing.png
+++ b/core/res/res/drawable-mdpi/emo_im_kissing.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_laughing.png b/core/res/res/drawable-mdpi/emo_im_laughing.png
index 980bf28..980bf28 100644
--- a/core/res/res/drawable/emo_im_laughing.png
+++ b/core/res/res/drawable-mdpi/emo_im_laughing.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_lips_are_sealed.png b/core/res/res/drawable-mdpi/emo_im_lips_are_sealed.png
index f2de993..f2de993 100644
--- a/core/res/res/drawable/emo_im_lips_are_sealed.png
+++ b/core/res/res/drawable-mdpi/emo_im_lips_are_sealed.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_money_mouth.png b/core/res/res/drawable-mdpi/emo_im_money_mouth.png
index 08c53fd..08c53fd 100644
--- a/core/res/res/drawable/emo_im_money_mouth.png
+++ b/core/res/res/drawable-mdpi/emo_im_money_mouth.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_sad.png b/core/res/res/drawable-mdpi/emo_im_sad.png
index 31c08d0..31c08d0 100644
--- a/core/res/res/drawable/emo_im_sad.png
+++ b/core/res/res/drawable-mdpi/emo_im_sad.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_surprised.png b/core/res/res/drawable-mdpi/emo_im_surprised.png
index abe8c7a..abe8c7a 100644
--- a/core/res/res/drawable/emo_im_surprised.png
+++ b/core/res/res/drawable-mdpi/emo_im_surprised.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_tongue_sticking_out.png b/core/res/res/drawable-mdpi/emo_im_tongue_sticking_out.png
index 6f0f47b..6f0f47b 100644
--- a/core/res/res/drawable/emo_im_tongue_sticking_out.png
+++ b/core/res/res/drawable-mdpi/emo_im_tongue_sticking_out.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_undecided.png b/core/res/res/drawable-mdpi/emo_im_undecided.png
index eb4f8c5..eb4f8c5 100644
--- a/core/res/res/drawable/emo_im_undecided.png
+++ b/core/res/res/drawable-mdpi/emo_im_undecided.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_winking.png b/core/res/res/drawable-mdpi/emo_im_winking.png
index 568562a..568562a 100644
--- a/core/res/res/drawable/emo_im_winking.png
+++ b/core/res/res/drawable-mdpi/emo_im_winking.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_wtf.png b/core/res/res/drawable-mdpi/emo_im_wtf.png
index 41dd47f..41dd47f 100644
--- a/core/res/res/drawable/emo_im_wtf.png
+++ b/core/res/res/drawable-mdpi/emo_im_wtf.png
Binary files differ
diff --git a/core/res/res/drawable/emo_im_yelling.png b/core/res/res/drawable-mdpi/emo_im_yelling.png
index c3c8612..c3c8612 100644
--- a/core/res/res/drawable/emo_im_yelling.png
+++ b/core/res/res/drawable-mdpi/emo_im_yelling.png
Binary files differ
diff --git a/core/res/res/drawable/expander_ic_maximized.9.png b/core/res/res/drawable-mdpi/expander_ic_maximized.9.png
index 465cabd..465cabd 100644
--- a/core/res/res/drawable/expander_ic_maximized.9.png
+++ b/core/res/res/drawable-mdpi/expander_ic_maximized.9.png
Binary files differ
diff --git a/core/res/res/drawable/expander_ic_minimized.9.png b/core/res/res/drawable-mdpi/expander_ic_minimized.9.png
index 9967ecb..9967ecb 100644
--- a/core/res/res/drawable/expander_ic_minimized.9.png
+++ b/core/res/res/drawable-mdpi/expander_ic_minimized.9.png
Binary files differ
diff --git a/core/res/res/drawable/focused_application_background_static.png b/core/res/res/drawable-mdpi/focused_application_background_static.png
index fd18d30..fd18d30 100644
--- a/core/res/res/drawable/focused_application_background_static.png
+++ b/core/res/res/drawable-mdpi/focused_application_background_static.png
Binary files differ
diff --git a/core/res/res/drawable/frame_gallery_thumb.9.png b/core/res/res/drawable-mdpi/frame_gallery_thumb.9.png
index 804f6f3..804f6f3 100755
--- a/core/res/res/drawable/frame_gallery_thumb.9.png
+++ b/core/res/res/drawable-mdpi/frame_gallery_thumb.9.png
Binary files differ
diff --git a/core/res/res/drawable/frame_gallery_thumb_pressed.9.png b/core/res/res/drawable-mdpi/frame_gallery_thumb_pressed.9.png
index e1ffa06..e1ffa06 100755
--- a/core/res/res/drawable/frame_gallery_thumb_pressed.9.png
+++ b/core/res/res/drawable-mdpi/frame_gallery_thumb_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/frame_gallery_thumb_selected.9.png b/core/res/res/drawable-mdpi/frame_gallery_thumb_selected.9.png
index 8bae932..8bae932 100755
--- a/core/res/res/drawable/frame_gallery_thumb_selected.9.png
+++ b/core/res/res/drawable-mdpi/frame_gallery_thumb_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/gallery_selected_default.9.png b/core/res/res/drawable-mdpi/gallery_selected_default.9.png
index 22122b2..22122b2 100755
--- a/core/res/res/drawable/gallery_selected_default.9.png
+++ b/core/res/res/drawable-mdpi/gallery_selected_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/gallery_selected_focused.9.png b/core/res/res/drawable-mdpi/gallery_selected_focused.9.png
index 1332745..1332745 100755
--- a/core/res/res/drawable/gallery_selected_focused.9.png
+++ b/core/res/res/drawable-mdpi/gallery_selected_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/gallery_selected_pressed.9.png b/core/res/res/drawable-mdpi/gallery_selected_pressed.9.png
index 306e543..306e543 100755
--- a/core/res/res/drawable/gallery_selected_pressed.9.png
+++ b/core/res/res/drawable-mdpi/gallery_selected_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/gallery_unselected_default.9.png b/core/res/res/drawable-mdpi/gallery_unselected_default.9.png
index 0df06fa..0df06fa 100755
--- a/core/res/res/drawable/gallery_unselected_default.9.png
+++ b/core/res/res/drawable-mdpi/gallery_unselected_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/gallery_unselected_pressed.9.png b/core/res/res/drawable-mdpi/gallery_unselected_pressed.9.png
index 4b25c3f..4b25c3f 100644
--- a/core/res/res/drawable/gallery_unselected_pressed.9.png
+++ b/core/res/res/drawable-mdpi/gallery_unselected_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/grid_selector_background_focus.9.png b/core/res/res/drawable-mdpi/grid_selector_background_focus.9.png
index 2e28232..2e28232 100644
--- a/core/res/res/drawable/grid_selector_background_focus.9.png
+++ b/core/res/res/drawable-mdpi/grid_selector_background_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable/grid_selector_background_pressed.9.png b/core/res/res/drawable-mdpi/grid_selector_background_pressed.9.png
index e20f091..e20f091 100644
--- a/core/res/res/drawable/grid_selector_background_pressed.9.png
+++ b/core/res/res/drawable-mdpi/grid_selector_background_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/highlight_disabled.9.png b/core/res/res/drawable-mdpi/highlight_disabled.9.png
index 1393262..1393262 100644
--- a/core/res/res/drawable/highlight_disabled.9.png
+++ b/core/res/res/drawable-mdpi/highlight_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/highlight_pressed.9.png b/core/res/res/drawable-mdpi/highlight_pressed.9.png
index 9bd2b50..9bd2b50 100644
--- a/core/res/res/drawable/highlight_pressed.9.png
+++ b/core/res/res/drawable-mdpi/highlight_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/highlight_selected.9.png b/core/res/res/drawable-mdpi/highlight_selected.9.png
index ecf0cad..ecf0cad 100644
--- a/core/res/res/drawable/highlight_selected.9.png
+++ b/core/res/res/drawable-mdpi/highlight_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_round_more_disabled.png b/core/res/res/drawable-mdpi/ic_btn_round_more_disabled.png
index 1ab98c9..1ab98c9 100644
--- a/core/res/res/drawable/ic_btn_round_more_disabled.png
+++ b/core/res/res/drawable-mdpi/ic_btn_round_more_disabled.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_round_more_normal.png b/core/res/res/drawable-mdpi/ic_btn_round_more_normal.png
index ebdc55c..ebdc55c 100644
--- a/core/res/res/drawable/ic_btn_round_more_normal.png
+++ b/core/res/res/drawable-mdpi/ic_btn_round_more_normal.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_search.png b/core/res/res/drawable-mdpi/ic_btn_search.png
index 3f8913e..3f8913e 100644
--- a/core/res/res/drawable/ic_btn_search.png
+++ b/core/res/res/drawable-mdpi/ic_btn_search.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_speak_now.png b/core/res/res/drawable-mdpi/ic_btn_speak_now.png
index 83ee68b..83ee68b 100644
--- a/core/res/res/drawable/ic_btn_speak_now.png
+++ b/core/res/res/drawable-mdpi/ic_btn_speak_now.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_disabled.png b/core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_fit_page_disabled.png
index 914662d..914662d 100644
--- a/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_disabled.png
+++ b/core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_fit_page_disabled.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_normal.png b/core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_fit_page_normal.png
index 3b67c6d..3b67c6d 100644
--- a/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_normal.png
+++ b/core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_fit_page_normal.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_disabled.png b/core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_page_overview_disabled.png
index 859900a..859900a 100644
--- a/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_disabled.png
+++ b/core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_page_overview_disabled.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_normal.png b/core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_page_overview_normal.png
index 4e8ff35..4e8ff35 100644
--- a/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview_normal.png
+++ b/core/res/res/drawable-mdpi/ic_btn_square_browser_zoom_page_overview_normal.png
Binary files differ
diff --git a/core/res/res/drawable/ic_bullet_key_permission.png b/core/res/res/drawable-mdpi/ic_bullet_key_permission.png
index ccb010f..ccb010f 100644
--- a/core/res/res/drawable/ic_bullet_key_permission.png
+++ b/core/res/res/drawable-mdpi/ic_bullet_key_permission.png
Binary files differ
diff --git a/core/res/res/drawable/ic_contact_picture.png b/core/res/res/drawable-mdpi/ic_contact_picture.png
index 3a338e8..3a338e8 100644
--- a/core/res/res/drawable/ic_contact_picture.png
+++ b/core/res/res/drawable-mdpi/ic_contact_picture.png
Binary files differ
diff --git a/core/res/res/drawable/ic_delete.png b/core/res/res/drawable-mdpi/ic_delete.png
index f074db3..f074db3 100644
--- a/core/res/res/drawable/ic_delete.png
+++ b/core/res/res/drawable-mdpi/ic_delete.png
Binary files differ
diff --git a/core/res/res/drawable/ic_dialog_alert.png b/core/res/res/drawable-mdpi/ic_dialog_alert.png
index 0a7de04..0a7de04 100644
--- a/core/res/res/drawable/ic_dialog_alert.png
+++ b/core/res/res/drawable-mdpi/ic_dialog_alert.png
Binary files differ
diff --git a/core/res/res/drawable/ic_dialog_dialer.png b/core/res/res/drawable-mdpi/ic_dialog_dialer.png
index f0c1838..f0c1838 100644
--- a/core/res/res/drawable/ic_dialog_dialer.png
+++ b/core/res/res/drawable-mdpi/ic_dialog_dialer.png
Binary files differ
diff --git a/core/res/res/drawable/ic_dialog_email.png b/core/res/res/drawable-mdpi/ic_dialog_email.png
index 20ebb13..20ebb13 100644
--- a/core/res/res/drawable/ic_dialog_email.png
+++ b/core/res/res/drawable-mdpi/ic_dialog_email.png
Binary files differ
diff --git a/core/res/res/drawable/ic_dialog_info.png b/core/res/res/drawable-mdpi/ic_dialog_info.png
index e8b0229..e8b0229 100755
--- a/core/res/res/drawable/ic_dialog_info.png
+++ b/core/res/res/drawable-mdpi/ic_dialog_info.png
Binary files differ
diff --git a/core/res/res/drawable/ic_dialog_map.png b/core/res/res/drawable-mdpi/ic_dialog_map.png
index b126354..b126354 100644
--- a/core/res/res/drawable/ic_dialog_map.png
+++ b/core/res/res/drawable-mdpi/ic_dialog_map.png
Binary files differ
diff --git a/core/res/res/drawable/ic_dialog_menu_generic.png b/core/res/res/drawable-mdpi/ic_dialog_menu_generic.png
index de07bda..de07bda 100755
--- a/core/res/res/drawable/ic_dialog_menu_generic.png
+++ b/core/res/res/drawable-mdpi/ic_dialog_menu_generic.png
Binary files differ
diff --git a/core/res/res/drawable/ic_dialog_time.png b/core/res/res/drawable-mdpi/ic_dialog_time.png
index dffec29..dffec29 100755
--- a/core/res/res/drawable/ic_dialog_time.png
+++ b/core/res/res/drawable-mdpi/ic_dialog_time.png
Binary files differ
diff --git a/core/res/res/drawable/ic_dialog_usb.png b/core/res/res/drawable-mdpi/ic_dialog_usb.png
index fbc8a9d..fbc8a9d 100644
--- a/core/res/res/drawable/ic_dialog_usb.png
+++ b/core/res/res/drawable-mdpi/ic_dialog_usb.png
Binary files differ
diff --git a/core/res/res/drawable/ic_emergency.png b/core/res/res/drawable-mdpi/ic_emergency.png
index 45d0f21..45d0f21 100755
--- a/core/res/res/drawable/ic_emergency.png
+++ b/core/res/res/drawable-mdpi/ic_emergency.png
Binary files differ
diff --git a/core/res/res/drawable/ic_input_add.png b/core/res/res/drawable-mdpi/ic_input_add.png
index 00770f8..00770f8 100644
--- a/core/res/res/drawable/ic_input_add.png
+++ b/core/res/res/drawable-mdpi/ic_input_add.png
Binary files differ
diff --git a/core/res/res/drawable/ic_input_delete.png b/core/res/res/drawable-mdpi/ic_input_delete.png
index ee4c911..ee4c911 100644
--- a/core/res/res/drawable/ic_input_delete.png
+++ b/core/res/res/drawable-mdpi/ic_input_delete.png
Binary files differ
diff --git a/core/res/res/drawable/ic_input_get.png b/core/res/res/drawable-mdpi/ic_input_get.png
index 2f2cfcf..2f2cfcf 100644
--- a/core/res/res/drawable/ic_input_get.png
+++ b/core/res/res/drawable-mdpi/ic_input_get.png
Binary files differ
diff --git a/core/res/res/drawable/ic_launcher_android.png b/core/res/res/drawable-mdpi/ic_launcher_android.png
index 855484a..855484a 100644
--- a/core/res/res/drawable/ic_launcher_android.png
+++ b/core/res/res/drawable-mdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_airplane_mode.png b/core/res/res/drawable-mdpi/ic_lock_airplane_mode.png
index caafcb2..caafcb2 100755
--- a/core/res/res/drawable/ic_lock_airplane_mode.png
+++ b/core/res/res/drawable-mdpi/ic_lock_airplane_mode.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_airplane_mode_off.png b/core/res/res/drawable-mdpi/ic_lock_airplane_mode_off.png
index cb2cbdf..cb2cbdf 100755
--- a/core/res/res/drawable/ic_lock_airplane_mode_off.png
+++ b/core/res/res/drawable-mdpi/ic_lock_airplane_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_idle_alarm.png b/core/res/res/drawable-mdpi/ic_lock_idle_alarm.png
index 8c8899f..8c8899f 100644
--- a/core/res/res/drawable/ic_lock_idle_alarm.png
+++ b/core/res/res/drawable-mdpi/ic_lock_idle_alarm.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_idle_charging.png b/core/res/res/drawable-mdpi/ic_lock_idle_charging.png
index 20d6320..20d6320 100755
--- a/core/res/res/drawable/ic_lock_idle_charging.png
+++ b/core/res/res/drawable-mdpi/ic_lock_idle_charging.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_idle_lock.png b/core/res/res/drawable-mdpi/ic_lock_idle_lock.png
index 0206aee..0206aee 100755
--- a/core/res/res/drawable/ic_lock_idle_lock.png
+++ b/core/res/res/drawable-mdpi/ic_lock_idle_lock.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_idle_low_battery.png b/core/res/res/drawable-mdpi/ic_lock_idle_low_battery.png
index bb96782..bb96782 100755
--- a/core/res/res/drawable/ic_lock_idle_low_battery.png
+++ b/core/res/res/drawable-mdpi/ic_lock_idle_low_battery.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_lock.png b/core/res/res/drawable-mdpi/ic_lock_lock.png
index b662b03..b662b03 100644
--- a/core/res/res/drawable/ic_lock_lock.png
+++ b/core/res/res/drawable-mdpi/ic_lock_lock.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_power_off.png b/core/res/res/drawable-mdpi/ic_lock_power_off.png
index 4405b43..4405b43 100644
--- a/core/res/res/drawable/ic_lock_power_off.png
+++ b/core/res/res/drawable-mdpi/ic_lock_power_off.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_silent_mode.png b/core/res/res/drawable-mdpi/ic_lock_silent_mode.png
index 439a6f5..439a6f5 100644
--- a/core/res/res/drawable/ic_lock_silent_mode.png
+++ b/core/res/res/drawable-mdpi/ic_lock_silent_mode.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_silent_mode_off.png b/core/res/res/drawable-mdpi/ic_lock_silent_mode_off.png
index fc7e960..fc7e960 100644
--- a/core/res/res/drawable/ic_lock_silent_mode_off.png
+++ b/core/res/res/drawable-mdpi/ic_lock_silent_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable/ic_maps_indicator_current_position.png b/core/res/res/drawable-mdpi/ic_maps_indicator_current_position.png
index 4e427d8..4e427d8 100644
--- a/core/res/res/drawable/ic_maps_indicator_current_position.png
+++ b/core/res/res/drawable-mdpi/ic_maps_indicator_current_position.png
Binary files differ
diff --git a/core/res/res/drawable/ic_maps_indicator_current_position_anim1.png b/core/res/res/drawable-mdpi/ic_maps_indicator_current_position_anim1.png
index 47bb9fa..47bb9fa 100644
--- a/core/res/res/drawable/ic_maps_indicator_current_position_anim1.png
+++ b/core/res/res/drawable-mdpi/ic_maps_indicator_current_position_anim1.png
Binary files differ
diff --git a/core/res/res/drawable/ic_maps_indicator_current_position_anim2.png b/core/res/res/drawable-mdpi/ic_maps_indicator_current_position_anim2.png
index b1167bc..b1167bc 100644
--- a/core/res/res/drawable/ic_maps_indicator_current_position_anim2.png
+++ b/core/res/res/drawable-mdpi/ic_maps_indicator_current_position_anim2.png
Binary files differ
diff --git a/core/res/res/drawable/ic_maps_indicator_current_position_anim3.png b/core/res/res/drawable-mdpi/ic_maps_indicator_current_position_anim3.png
index f681a4c..f681a4c 100644
--- a/core/res/res/drawable/ic_maps_indicator_current_position_anim3.png
+++ b/core/res/res/drawable-mdpi/ic_maps_indicator_current_position_anim3.png
Binary files differ
diff --git a/core/res/res/drawable/ic_media_ff.png b/core/res/res/drawable-mdpi/ic_media_ff.png
index ce7e195..ce7e195 100755
--- a/core/res/res/drawable/ic_media_ff.png
+++ b/core/res/res/drawable-mdpi/ic_media_ff.png
Binary files differ
diff --git a/core/res/res/drawable/ic_media_next.png b/core/res/res/drawable-mdpi/ic_media_next.png
index 84f38e8..84f38e8 100755
--- a/core/res/res/drawable/ic_media_next.png
+++ b/core/res/res/drawable-mdpi/ic_media_next.png
Binary files differ
diff --git a/core/res/res/drawable/ic_media_pause.png b/core/res/res/drawable-mdpi/ic_media_pause.png
index 688118e..688118e 100755
--- a/core/res/res/drawable/ic_media_pause.png
+++ b/core/res/res/drawable-mdpi/ic_media_pause.png
Binary files differ
diff --git a/core/res/res/drawable/ic_media_play.png b/core/res/res/drawable-mdpi/ic_media_play.png
index 7aa7af8..7aa7af8 100755
--- a/core/res/res/drawable/ic_media_play.png
+++ b/core/res/res/drawable-mdpi/ic_media_play.png
Binary files differ
diff --git a/core/res/res/drawable/ic_media_previous.png b/core/res/res/drawable-mdpi/ic_media_previous.png
index 1bba544..1bba544 100755
--- a/core/res/res/drawable/ic_media_previous.png
+++ b/core/res/res/drawable-mdpi/ic_media_previous.png
Binary files differ
diff --git a/core/res/res/drawable/ic_media_rew.png b/core/res/res/drawable-mdpi/ic_media_rew.png
index 132df7f..132df7f 100755
--- a/core/res/res/drawable/ic_media_rew.png
+++ b/core/res/res/drawable-mdpi/ic_media_rew.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_account_list.png b/core/res/res/drawable-mdpi/ic_menu_account_list.png
index f0945b2..f0945b2 100644
--- a/core/res/res/drawable/ic_menu_account_list.png
+++ b/core/res/res/drawable-mdpi/ic_menu_account_list.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_add.png b/core/res/res/drawable-mdpi/ic_menu_add.png
index 6752bfd..6752bfd 100755
--- a/core/res/res/drawable/ic_menu_add.png
+++ b/core/res/res/drawable-mdpi/ic_menu_add.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_agenda.png b/core/res/res/drawable-mdpi/ic_menu_agenda.png
index 9f2c1dc..9f2c1dc 100755
--- a/core/res/res/drawable/ic_menu_agenda.png
+++ b/core/res/res/drawable-mdpi/ic_menu_agenda.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_allfriends.png b/core/res/res/drawable-mdpi/ic_menu_allfriends.png
index a5bd331..a5bd331 100755
--- a/core/res/res/drawable/ic_menu_allfriends.png
+++ b/core/res/res/drawable-mdpi/ic_menu_allfriends.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_always_landscape_portrait.png b/core/res/res/drawable-mdpi/ic_menu_always_landscape_portrait.png
index 68911c4..68911c4 100644
--- a/core/res/res/drawable/ic_menu_always_landscape_portrait.png
+++ b/core/res/res/drawable-mdpi/ic_menu_always_landscape_portrait.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_archive.png b/core/res/res/drawable-mdpi/ic_menu_archive.png
index a4599e3..a4599e3 100644
--- a/core/res/res/drawable/ic_menu_archive.png
+++ b/core/res/res/drawable-mdpi/ic_menu_archive.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_attachment.png b/core/res/res/drawable-mdpi/ic_menu_attachment.png
index 89d626f..89d626f 100644
--- a/core/res/res/drawable/ic_menu_attachment.png
+++ b/core/res/res/drawable-mdpi/ic_menu_attachment.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_back.png b/core/res/res/drawable-mdpi/ic_menu_back.png
index 5ce50eb..5ce50eb 100644
--- a/core/res/res/drawable/ic_menu_back.png
+++ b/core/res/res/drawable-mdpi/ic_menu_back.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_block.png b/core/res/res/drawable-mdpi/ic_menu_block.png
index 422eeb1..422eeb1 100644
--- a/core/res/res/drawable/ic_menu_block.png
+++ b/core/res/res/drawable-mdpi/ic_menu_block.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_blocked_user.png b/core/res/res/drawable-mdpi/ic_menu_blocked_user.png
index 5a5619b..5a5619b 100644
--- a/core/res/res/drawable/ic_menu_blocked_user.png
+++ b/core/res/res/drawable-mdpi/ic_menu_blocked_user.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_call.png b/core/res/res/drawable-mdpi/ic_menu_call.png
index a63f86b..a63f86b 100644
--- a/core/res/res/drawable/ic_menu_call.png
+++ b/core/res/res/drawable-mdpi/ic_menu_call.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_camera.png b/core/res/res/drawable-mdpi/ic_menu_camera.png
index cdf7ca3..cdf7ca3 100755
--- a/core/res/res/drawable/ic_menu_camera.png
+++ b/core/res/res/drawable-mdpi/ic_menu_camera.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_cc.png b/core/res/res/drawable-mdpi/ic_menu_cc.png
index 4876021..4876021 100644
--- a/core/res/res/drawable/ic_menu_cc.png
+++ b/core/res/res/drawable-mdpi/ic_menu_cc.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_chat_dashboard.png b/core/res/res/drawable-mdpi/ic_menu_chat_dashboard.png
index 37fd3cb..37fd3cb 100644
--- a/core/res/res/drawable/ic_menu_chat_dashboard.png
+++ b/core/res/res/drawable-mdpi/ic_menu_chat_dashboard.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_clear_playlist.png b/core/res/res/drawable-mdpi/ic_menu_clear_playlist.png
index 750db62..750db62 100644
--- a/core/res/res/drawable/ic_menu_clear_playlist.png
+++ b/core/res/res/drawable-mdpi/ic_menu_clear_playlist.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_close_clear_cancel.png b/core/res/res/drawable-mdpi/ic_menu_close_clear_cancel.png
index 78222ea..78222ea 100644
--- a/core/res/res/drawable/ic_menu_close_clear_cancel.png
+++ b/core/res/res/drawable-mdpi/ic_menu_close_clear_cancel.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_compass.png b/core/res/res/drawable-mdpi/ic_menu_compass.png
index 7717dde..7717dde 100644
--- a/core/res/res/drawable/ic_menu_compass.png
+++ b/core/res/res/drawable-mdpi/ic_menu_compass.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_compose.png b/core/res/res/drawable-mdpi/ic_menu_compose.png
index 1b4733e..1b4733e 100644
--- a/core/res/res/drawable/ic_menu_compose.png
+++ b/core/res/res/drawable-mdpi/ic_menu_compose.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_crop.png b/core/res/res/drawable-mdpi/ic_menu_crop.png
index c0df996..c0df996 100755
--- a/core/res/res/drawable/ic_menu_crop.png
+++ b/core/res/res/drawable-mdpi/ic_menu_crop.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_day.png b/core/res/res/drawable-mdpi/ic_menu_day.png
index db5d3a4..db5d3a4 100755
--- a/core/res/res/drawable/ic_menu_day.png
+++ b/core/res/res/drawable-mdpi/ic_menu_day.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_delete.png b/core/res/res/drawable-mdpi/ic_menu_delete.png
index 7d95494..7d95494 100755
--- a/core/res/res/drawable/ic_menu_delete.png
+++ b/core/res/res/drawable-mdpi/ic_menu_delete.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_directions.png b/core/res/res/drawable-mdpi/ic_menu_directions.png
index 00a288f..00a288f 100755
--- a/core/res/res/drawable/ic_menu_directions.png
+++ b/core/res/res/drawable-mdpi/ic_menu_directions.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_edit.png b/core/res/res/drawable-mdpi/ic_menu_edit.png
index 41a9c2e..41a9c2e 100755
--- a/core/res/res/drawable/ic_menu_edit.png
+++ b/core/res/res/drawable-mdpi/ic_menu_edit.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_emoticons.png b/core/res/res/drawable-mdpi/ic_menu_emoticons.png
index e8c4e47..e8c4e47 100644
--- a/core/res/res/drawable/ic_menu_emoticons.png
+++ b/core/res/res/drawable-mdpi/ic_menu_emoticons.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_end_conversation.png b/core/res/res/drawable-mdpi/ic_menu_end_conversation.png
index 0ea0fcb..0ea0fcb 100644
--- a/core/res/res/drawable/ic_menu_end_conversation.png
+++ b/core/res/res/drawable-mdpi/ic_menu_end_conversation.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_forward.png b/core/res/res/drawable-mdpi/ic_menu_forward.png
index 0936fac..0936fac 100644
--- a/core/res/res/drawable/ic_menu_forward.png
+++ b/core/res/res/drawable-mdpi/ic_menu_forward.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_friendslist.png b/core/res/res/drawable-mdpi/ic_menu_friendslist.png
index 8ec6b1a..8ec6b1a 100644
--- a/core/res/res/drawable/ic_menu_friendslist.png
+++ b/core/res/res/drawable-mdpi/ic_menu_friendslist.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_gallery.png b/core/res/res/drawable-mdpi/ic_menu_gallery.png
index f61bbd8..f61bbd8 100755
--- a/core/res/res/drawable/ic_menu_gallery.png
+++ b/core/res/res/drawable-mdpi/ic_menu_gallery.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_goto.png b/core/res/res/drawable-mdpi/ic_menu_goto.png
index 40183eb..40183eb 100644
--- a/core/res/res/drawable/ic_menu_goto.png
+++ b/core/res/res/drawable-mdpi/ic_menu_goto.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_help.png b/core/res/res/drawable-mdpi/ic_menu_help.png
index 7c55dfd..7c55dfd 100644
--- a/core/res/res/drawable/ic_menu_help.png
+++ b/core/res/res/drawable-mdpi/ic_menu_help.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_home.png b/core/res/res/drawable-mdpi/ic_menu_home.png
index 34943f6..34943f6 100644
--- a/core/res/res/drawable/ic_menu_home.png
+++ b/core/res/res/drawable-mdpi/ic_menu_home.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_info_details.png b/core/res/res/drawable-mdpi/ic_menu_info_details.png
index 1786d1e..1786d1e 100755
--- a/core/res/res/drawable/ic_menu_info_details.png
+++ b/core/res/res/drawable-mdpi/ic_menu_info_details.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_invite.png b/core/res/res/drawable-mdpi/ic_menu_invite.png
index 7577e6d..7577e6d 100644
--- a/core/res/res/drawable/ic_menu_invite.png
+++ b/core/res/res/drawable-mdpi/ic_menu_invite.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_login.png b/core/res/res/drawable-mdpi/ic_menu_login.png
index 2b856bc..2b856bc 100644
--- a/core/res/res/drawable/ic_menu_login.png
+++ b/core/res/res/drawable-mdpi/ic_menu_login.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_manage.png b/core/res/res/drawable-mdpi/ic_menu_manage.png
index f155bbc..f155bbc 100755
--- a/core/res/res/drawable/ic_menu_manage.png
+++ b/core/res/res/drawable-mdpi/ic_menu_manage.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_mapmode.png b/core/res/res/drawable-mdpi/ic_menu_mapmode.png
index d85cab5..d85cab5 100644
--- a/core/res/res/drawable/ic_menu_mapmode.png
+++ b/core/res/res/drawable-mdpi/ic_menu_mapmode.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_mark.png b/core/res/res/drawable-mdpi/ic_menu_mark.png
index 5e95da7..5e95da7 100644
--- a/core/res/res/drawable/ic_menu_mark.png
+++ b/core/res/res/drawable-mdpi/ic_menu_mark.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_month.png b/core/res/res/drawable-mdpi/ic_menu_month.png
index bf6cb89..bf6cb89 100755
--- a/core/res/res/drawable/ic_menu_month.png
+++ b/core/res/res/drawable-mdpi/ic_menu_month.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_more.png b/core/res/res/drawable-mdpi/ic_menu_more.png
index b9fc5fa..b9fc5fa 100644
--- a/core/res/res/drawable/ic_menu_more.png
+++ b/core/res/res/drawable-mdpi/ic_menu_more.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_my_calendar.png b/core/res/res/drawable-mdpi/ic_menu_my_calendar.png
index 0c88fd3..0c88fd3 100755
--- a/core/res/res/drawable/ic_menu_my_calendar.png
+++ b/core/res/res/drawable-mdpi/ic_menu_my_calendar.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_mylocation.png b/core/res/res/drawable-mdpi/ic_menu_mylocation.png
index fdbd5ca..fdbd5ca 100755
--- a/core/res/res/drawable/ic_menu_mylocation.png
+++ b/core/res/res/drawable-mdpi/ic_menu_mylocation.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_myplaces.png b/core/res/res/drawable-mdpi/ic_menu_myplaces.png
index 06f11ba..06f11ba 100644
--- a/core/res/res/drawable/ic_menu_myplaces.png
+++ b/core/res/res/drawable-mdpi/ic_menu_myplaces.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_notifications.png b/core/res/res/drawable-mdpi/ic_menu_notifications.png
index 866d4e0..866d4e0 100644
--- a/core/res/res/drawable/ic_menu_notifications.png
+++ b/core/res/res/drawable-mdpi/ic_menu_notifications.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_play_clip.png b/core/res/res/drawable-mdpi/ic_menu_play_clip.png
index 4669947..4669947 100644
--- a/core/res/res/drawable/ic_menu_play_clip.png
+++ b/core/res/res/drawable-mdpi/ic_menu_play_clip.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_preferences.png b/core/res/res/drawable-mdpi/ic_menu_preferences.png
index b8e7141..b8e7141 100644
--- a/core/res/res/drawable/ic_menu_preferences.png
+++ b/core/res/res/drawable-mdpi/ic_menu_preferences.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_recent_history.png b/core/res/res/drawable-mdpi/ic_menu_recent_history.png
index 4ccae5d..4ccae5d 100644
--- a/core/res/res/drawable/ic_menu_recent_history.png
+++ b/core/res/res/drawable-mdpi/ic_menu_recent_history.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_refresh.png b/core/res/res/drawable-mdpi/ic_menu_refresh.png
index 77d70dd..77d70dd 100644
--- a/core/res/res/drawable/ic_menu_refresh.png
+++ b/core/res/res/drawable-mdpi/ic_menu_refresh.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_report_image.png b/core/res/res/drawable-mdpi/ic_menu_report_image.png
index 393d727..393d727 100644
--- a/core/res/res/drawable/ic_menu_report_image.png
+++ b/core/res/res/drawable-mdpi/ic_menu_report_image.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_revert.png b/core/res/res/drawable-mdpi/ic_menu_revert.png
index e7e04f5..e7e04f5 100644
--- a/core/res/res/drawable/ic_menu_revert.png
+++ b/core/res/res/drawable-mdpi/ic_menu_revert.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_rotate.png b/core/res/res/drawable-mdpi/ic_menu_rotate.png
index 27368b2..27368b2 100755
--- a/core/res/res/drawable/ic_menu_rotate.png
+++ b/core/res/res/drawable-mdpi/ic_menu_rotate.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_save.png b/core/res/res/drawable-mdpi/ic_menu_save.png
index 36d50b3..36d50b3 100644
--- a/core/res/res/drawable/ic_menu_save.png
+++ b/core/res/res/drawable-mdpi/ic_menu_save.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_search.png b/core/res/res/drawable-mdpi/ic_menu_search.png
index 94446db..94446db 100755
--- a/core/res/res/drawable/ic_menu_search.png
+++ b/core/res/res/drawable-mdpi/ic_menu_search.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_send.png b/core/res/res/drawable-mdpi/ic_menu_send.png
index 74c096d..74c096d 100755
--- a/core/res/res/drawable/ic_menu_send.png
+++ b/core/res/res/drawable-mdpi/ic_menu_send.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_set_as.png b/core/res/res/drawable-mdpi/ic_menu_set_as.png
index cb9dc49..cb9dc49 100755
--- a/core/res/res/drawable/ic_menu_set_as.png
+++ b/core/res/res/drawable-mdpi/ic_menu_set_as.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_share.png b/core/res/res/drawable-mdpi/ic_menu_share.png
index 44db9b1..44db9b1 100755
--- a/core/res/res/drawable/ic_menu_share.png
+++ b/core/res/res/drawable-mdpi/ic_menu_share.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_slideshow.png b/core/res/res/drawable-mdpi/ic_menu_slideshow.png
index 38dd8f0..38dd8f0 100644
--- a/core/res/res/drawable/ic_menu_slideshow.png
+++ b/core/res/res/drawable-mdpi/ic_menu_slideshow.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_sort_alphabetically.png b/core/res/res/drawable-mdpi/ic_menu_sort_alphabetically.png
index 2583eb8..2583eb8 100755
--- a/core/res/res/drawable/ic_menu_sort_alphabetically.png
+++ b/core/res/res/drawable-mdpi/ic_menu_sort_alphabetically.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_sort_by_size.png b/core/res/res/drawable-mdpi/ic_menu_sort_by_size.png
index 65e2786..65e2786 100755
--- a/core/res/res/drawable/ic_menu_sort_by_size.png
+++ b/core/res/res/drawable-mdpi/ic_menu_sort_by_size.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_star.png b/core/res/res/drawable-mdpi/ic_menu_star.png
index 527d74a..527d74a 100755
--- a/core/res/res/drawable/ic_menu_star.png
+++ b/core/res/res/drawable-mdpi/ic_menu_star.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_start_conversation.png b/core/res/res/drawable-mdpi/ic_menu_start_conversation.png
index aadcc2f..aadcc2f 100644
--- a/core/res/res/drawable/ic_menu_start_conversation.png
+++ b/core/res/res/drawable-mdpi/ic_menu_start_conversation.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_stop.png b/core/res/res/drawable-mdpi/ic_menu_stop.png
index 4fc825c..4fc825c 100644
--- a/core/res/res/drawable/ic_menu_stop.png
+++ b/core/res/res/drawable-mdpi/ic_menu_stop.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_today.png b/core/res/res/drawable-mdpi/ic_menu_today.png
index c63b6af..c63b6af 100755
--- a/core/res/res/drawable/ic_menu_today.png
+++ b/core/res/res/drawable-mdpi/ic_menu_today.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_upload.png b/core/res/res/drawable-mdpi/ic_menu_upload.png
index 1c0dd3f..1c0dd3f 100755
--- a/core/res/res/drawable/ic_menu_upload.png
+++ b/core/res/res/drawable-mdpi/ic_menu_upload.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_upload_you_tube.png b/core/res/res/drawable-mdpi/ic_menu_upload_you_tube.png
index 0095564..0095564 100755
--- a/core/res/res/drawable/ic_menu_upload_you_tube.png
+++ b/core/res/res/drawable-mdpi/ic_menu_upload_you_tube.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_view.png b/core/res/res/drawable-mdpi/ic_menu_view.png
index 69828a9..69828a9 100755
--- a/core/res/res/drawable/ic_menu_view.png
+++ b/core/res/res/drawable-mdpi/ic_menu_view.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_week.png b/core/res/res/drawable-mdpi/ic_menu_week.png
index 62cd65e..62cd65e 100755
--- a/core/res/res/drawable/ic_menu_week.png
+++ b/core/res/res/drawable-mdpi/ic_menu_week.png
Binary files differ
diff --git a/core/res/res/drawable/ic_menu_zoom.png b/core/res/res/drawable-mdpi/ic_menu_zoom.png
index 0b8c4e8..0b8c4e8 100644
--- a/core/res/res/drawable/ic_menu_zoom.png
+++ b/core/res/res/drawable-mdpi/ic_menu_zoom.png
Binary files differ
diff --git a/core/res/res/drawable/ic_notification_clear_all.png b/core/res/res/drawable-mdpi/ic_notification_clear_all.png
index f2114d7..f2114d7 100644
--- a/core/res/res/drawable/ic_notification_clear_all.png
+++ b/core/res/res/drawable-mdpi/ic_notification_clear_all.png
Binary files differ
diff --git a/core/res/res/drawable/ic_notification_overlay.9.png b/core/res/res/drawable-mdpi/ic_notification_overlay.9.png
index 1a3063c..1a3063c 100644
--- a/core/res/res/drawable/ic_notification_overlay.9.png
+++ b/core/res/res/drawable-mdpi/ic_notification_overlay.9.png
Binary files differ
diff --git a/core/res/res/drawable/ic_partial_secure.png b/core/res/res/drawable-mdpi/ic_partial_secure.png
index 76ba96a..76ba96a 100644
--- a/core/res/res/drawable/ic_partial_secure.png
+++ b/core/res/res/drawable-mdpi/ic_partial_secure.png
Binary files differ
diff --git a/core/res/res/drawable/ic_popup_disk_full.png b/core/res/res/drawable-mdpi/ic_popup_disk_full.png
index e6da5d0..e6da5d0 100644
--- a/core/res/res/drawable/ic_popup_disk_full.png
+++ b/core/res/res/drawable-mdpi/ic_popup_disk_full.png
Binary files differ
diff --git a/core/res/res/drawable/ic_popup_reminder.png b/core/res/res/drawable-mdpi/ic_popup_reminder.png
index af15279..af15279 100755
--- a/core/res/res/drawable/ic_popup_reminder.png
+++ b/core/res/res/drawable-mdpi/ic_popup_reminder.png
Binary files differ
diff --git a/core/res/res/drawable/ic_popup_sync_1.png b/core/res/res/drawable-mdpi/ic_popup_sync_1.png
index 13d8cdd..13d8cdd 100644
--- a/core/res/res/drawable/ic_popup_sync_1.png
+++ b/core/res/res/drawable-mdpi/ic_popup_sync_1.png
Binary files differ
diff --git a/core/res/res/drawable/ic_popup_sync_2.png b/core/res/res/drawable-mdpi/ic_popup_sync_2.png
index 6ca162a..6ca162a 100644
--- a/core/res/res/drawable/ic_popup_sync_2.png
+++ b/core/res/res/drawable-mdpi/ic_popup_sync_2.png
Binary files differ
diff --git a/core/res/res/drawable/ic_popup_sync_3.png b/core/res/res/drawable-mdpi/ic_popup_sync_3.png
index a7c21dd..a7c21dd 100644
--- a/core/res/res/drawable/ic_popup_sync_3.png
+++ b/core/res/res/drawable-mdpi/ic_popup_sync_3.png
Binary files differ
diff --git a/core/res/res/drawable/ic_popup_sync_4.png b/core/res/res/drawable-mdpi/ic_popup_sync_4.png
index e9be04e..e9be04e 100644
--- a/core/res/res/drawable/ic_popup_sync_4.png
+++ b/core/res/res/drawable-mdpi/ic_popup_sync_4.png
Binary files differ
diff --git a/core/res/res/drawable/ic_popup_sync_5.png b/core/res/res/drawable-mdpi/ic_popup_sync_5.png
index 65d87c4..65d87c4 100644
--- a/core/res/res/drawable/ic_popup_sync_5.png
+++ b/core/res/res/drawable-mdpi/ic_popup_sync_5.png
Binary files differ
diff --git a/core/res/res/drawable/ic_popup_sync_6.png b/core/res/res/drawable-mdpi/ic_popup_sync_6.png
index 2015c88..2015c88 100644
--- a/core/res/res/drawable/ic_popup_sync_6.png
+++ b/core/res/res/drawable-mdpi/ic_popup_sync_6.png
Binary files differ
diff --git a/core/res/res/drawable/ic_search_category_default.png b/core/res/res/drawable-mdpi/ic_search_category_default.png
index 7eea584..7eea584 100755
--- a/core/res/res/drawable/ic_search_category_default.png
+++ b/core/res/res/drawable-mdpi/ic_search_category_default.png
Binary files differ
diff --git a/core/res/res/drawable/ic_secure.png b/core/res/res/drawable-mdpi/ic_secure.png
index 4f15fc4..4f15fc4 100644
--- a/core/res/res/drawable/ic_secure.png
+++ b/core/res/res/drawable-mdpi/ic_secure.png
Binary files differ
diff --git a/core/res/res/drawable/ic_text_dot.png b/core/res/res/drawable-mdpi/ic_text_dot.png
index 47913f6..47913f6 100644
--- a/core/res/res/drawable/ic_text_dot.png
+++ b/core/res/res/drawable-mdpi/ic_text_dot.png
Binary files differ
diff --git a/core/res/res/drawable/ic_vibrate.png b/core/res/res/drawable-mdpi/ic_vibrate.png
index eb24e50..eb24e50 100755
--- a/core/res/res/drawable/ic_vibrate.png
+++ b/core/res/res/drawable-mdpi/ic_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable/ic_volume.png b/core/res/res/drawable-mdpi/ic_volume.png
index cee70f0..cee70f0 100755
--- a/core/res/res/drawable/ic_volume.png
+++ b/core/res/res/drawable-mdpi/ic_volume.png
Binary files differ
diff --git a/core/res/res/drawable/ic_volume_bluetooth_ad2p.png b/core/res/res/drawable-mdpi/ic_volume_bluetooth_ad2p.png
index cf86ab3..cf86ab3 100644
--- a/core/res/res/drawable/ic_volume_bluetooth_ad2p.png
+++ b/core/res/res/drawable-mdpi/ic_volume_bluetooth_ad2p.png
Binary files differ
diff --git a/core/res/res/drawable/ic_volume_bluetooth_in_call.png b/core/res/res/drawable-mdpi/ic_volume_bluetooth_in_call.png
index 94801fc..94801fc 100644
--- a/core/res/res/drawable/ic_volume_bluetooth_in_call.png
+++ b/core/res/res/drawable-mdpi/ic_volume_bluetooth_in_call.png
Binary files differ
diff --git a/core/res/res/drawable/ic_volume_off.png b/core/res/res/drawable-mdpi/ic_volume_off.png
index f3850fc..f3850fc 100644
--- a/core/res/res/drawable/ic_volume_off.png
+++ b/core/res/res/drawable-mdpi/ic_volume_off.png
Binary files differ
diff --git a/core/res/res/drawable/ic_volume_off_small.png b/core/res/res/drawable-mdpi/ic_volume_off_small.png
index ae55bd6..ae55bd6 100755
--- a/core/res/res/drawable/ic_volume_off_small.png
+++ b/core/res/res/drawable-mdpi/ic_volume_off_small.png
Binary files differ
diff --git a/core/res/res/drawable/ic_volume_small.png b/core/res/res/drawable-mdpi/ic_volume_small.png
index 00a4f89..00a4f89 100755
--- a/core/res/res/drawable/ic_volume_small.png
+++ b/core/res/res/drawable-mdpi/ic_volume_small.png
Binary files differ
diff --git a/core/res/res/drawable/icon_highlight_rectangle.9.png b/core/res/res/drawable-mdpi/icon_highlight_rectangle.9.png
index 3dafde3..3dafde3 100644
--- a/core/res/res/drawable/icon_highlight_rectangle.9.png
+++ b/core/res/res/drawable-mdpi/icon_highlight_rectangle.9.png
Binary files differ
diff --git a/core/res/res/drawable/icon_highlight_square.9.png b/core/res/res/drawable-mdpi/icon_highlight_square.9.png
index a93a3f8..a93a3f8 100644
--- a/core/res/res/drawable/icon_highlight_square.9.png
+++ b/core/res/res/drawable-mdpi/icon_highlight_square.9.png
Binary files differ
diff --git a/core/res/res/drawable/ime_qwerty.png b/core/res/res/drawable-mdpi/ime_qwerty.png
index e6e5cda..e6e5cda 100644
--- a/core/res/res/drawable/ime_qwerty.png
+++ b/core/res/res/drawable-mdpi/ime_qwerty.png
Binary files differ
diff --git a/core/res/res/drawable/indicator_code_lock_drag_direction_green_up.png b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up.png
index ef91dc4..ef91dc4 100644
--- a/core/res/res/drawable/indicator_code_lock_drag_direction_green_up.png
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up.png
Binary files differ
diff --git a/core/res/res/drawable/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up.png
index f3d4204..f3d4204 100644
--- a/core/res/res/drawable/indicator_code_lock_drag_direction_red_up.png
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up.png
Binary files differ
diff --git a/core/res/res/drawable/indicator_code_lock_point_area_default.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default.png
index 4e88b37..4e88b37 100755
--- a/core/res/res/drawable/indicator_code_lock_point_area_default.png
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default.png
Binary files differ
diff --git a/core/res/res/drawable/indicator_code_lock_point_area_green.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_green.png
index 8020846..8020846 100755
--- a/core/res/res/drawable/indicator_code_lock_point_area_green.png
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_green.png
Binary files differ
diff --git a/core/res/res/drawable/indicator_code_lock_point_area_red.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red.png
index b7aee1ba..b7aee1ba 100755
--- a/core/res/res/drawable/indicator_code_lock_point_area_red.png
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red.png
Binary files differ
diff --git a/core/res/res/drawable/indicator_input_error.png b/core/res/res/drawable-mdpi/indicator_input_error.png
index ee60165..ee60165 100755
--- a/core/res/res/drawable/indicator_input_error.png
+++ b/core/res/res/drawable-mdpi/indicator_input_error.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_accessory_bg_landscape.9.png b/core/res/res/drawable-mdpi/keyboard_accessory_bg_landscape.9.png
index 8f828f6..8f828f6 100644
--- a/core/res/res/drawable/keyboard_accessory_bg_landscape.9.png
+++ b/core/res/res/drawable-mdpi/keyboard_accessory_bg_landscape.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_background.9.png b/core/res/res/drawable-mdpi/keyboard_background.9.png
index 1d3ce05..1d3ce05 100644
--- a/core/res/res/drawable/keyboard_background.9.png
+++ b/core/res/res/drawable-mdpi/keyboard_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_key_feedback_background.9.png b/core/res/res/drawable-mdpi/keyboard_key_feedback_background.9.png
index 2a80f09..2a80f09 100644
--- a/core/res/res/drawable/keyboard_key_feedback_background.9.png
+++ b/core/res/res/drawable-mdpi/keyboard_key_feedback_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_key_feedback_more_background.9.png b/core/res/res/drawable-mdpi/keyboard_key_feedback_more_background.9.png
index 29aa285..29aa285 100755
--- a/core/res/res/drawable/keyboard_key_feedback_more_background.9.png
+++ b/core/res/res/drawable-mdpi/keyboard_key_feedback_more_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_popup_panel_background.9.png b/core/res/res/drawable-mdpi/keyboard_popup_panel_background.9.png
index 36d75df..36d75df 100644
--- a/core/res/res/drawable/keyboard_popup_panel_background.9.png
+++ b/core/res/res/drawable-mdpi/keyboard_popup_panel_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_textfield_selected.9.png b/core/res/res/drawable-mdpi/keyboard_textfield_selected.9.png
index 6e703af..6e703af 100644
--- a/core/res/res/drawable/keyboard_textfield_selected.9.png
+++ b/core/res/res/drawable-mdpi/keyboard_textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/light_header.9.png b/core/res/res/drawable-mdpi/light_header.9.png
new file mode 100644
index 0000000..fcd9e2d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/light_header.9.png
Binary files differ
diff --git a/core/res/res/drawable/list_selector_background_disabled.9.png b/core/res/res/drawable-mdpi/list_selector_background_disabled.9.png
index bf970b0..bf970b0 100644
--- a/core/res/res/drawable/list_selector_background_disabled.9.png
+++ b/core/res/res/drawable-mdpi/list_selector_background_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/list_selector_background_focus.9.png b/core/res/res/drawable-mdpi/list_selector_background_focus.9.png
index c3e2415..c3e2415 100644
--- a/core/res/res/drawable/list_selector_background_focus.9.png
+++ b/core/res/res/drawable-mdpi/list_selector_background_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable/list_selector_background_longpress.9.png b/core/res/res/drawable-mdpi/list_selector_background_longpress.9.png
index 5cbb251..5cbb251 100644
--- a/core/res/res/drawable/list_selector_background_longpress.9.png
+++ b/core/res/res/drawable-mdpi/list_selector_background_longpress.9.png
Binary files differ
diff --git a/core/res/res/drawable/list_selector_background_pressed.9.png b/core/res/res/drawable-mdpi/list_selector_background_pressed.9.png
index 02b4e9a..02b4e9a 100644
--- a/core/res/res/drawable/list_selector_background_pressed.9.png
+++ b/core/res/res/drawable-mdpi/list_selector_background_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/loading_tile.png b/core/res/res/drawable-mdpi/loading_tile.png
index f5a80c9..f5a80c9 100644
--- a/core/res/res/drawable/loading_tile.png
+++ b/core/res/res/drawable-mdpi/loading_tile.png
Binary files differ
diff --git a/core/res/res/drawable/maps_google_logo.png b/core/res/res/drawable-mdpi/maps_google_logo.png
index 1374aaa..1374aaa 100644
--- a/core/res/res/drawable/maps_google_logo.png
+++ b/core/res/res/drawable-mdpi/maps_google_logo.png
Binary files differ
diff --git a/core/res/res/drawable/menu_background.9.png b/core/res/res/drawable-mdpi/menu_background.9.png
index ee99583..ee99583 100644
--- a/core/res/res/drawable/menu_background.9.png
+++ b/core/res/res/drawable-mdpi/menu_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/menu_background_fill_parent_width.9.png b/core/res/res/drawable-mdpi/menu_background_fill_parent_width.9.png
index d368983..d368983 100644
--- a/core/res/res/drawable/menu_background_fill_parent_width.9.png
+++ b/core/res/res/drawable-mdpi/menu_background_fill_parent_width.9.png
Binary files differ
diff --git a/core/res/res/drawable/menu_separator.9.png b/core/res/res/drawable-mdpi/menu_separator.9.png
index 8a1a336..8a1a336 100644
--- a/core/res/res/drawable/menu_separator.9.png
+++ b/core/res/res/drawable-mdpi/menu_separator.9.png
Binary files differ
diff --git a/core/res/res/drawable/menu_submenu_background.9.png b/core/res/res/drawable-mdpi/menu_submenu_background.9.png
index a153532..a153532 100644
--- a/core/res/res/drawable/menu_submenu_background.9.png
+++ b/core/res/res/drawable-mdpi/menu_submenu_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/menuitem_background_focus.9.png b/core/res/res/drawable-mdpi/menuitem_background_focus.9.png
index c3e2415..c3e2415 100644
--- a/core/res/res/drawable/menuitem_background_focus.9.png
+++ b/core/res/res/drawable-mdpi/menuitem_background_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable/menuitem_background_pressed.9.png b/core/res/res/drawable-mdpi/menuitem_background_pressed.9.png
index 02b4e9a..02b4e9a 100644
--- a/core/res/res/drawable/menuitem_background_pressed.9.png
+++ b/core/res/res/drawable-mdpi/menuitem_background_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menuitem_background_solid_focused.9.png b/core/res/res/drawable-mdpi/menuitem_background_solid_focused.9.png
new file mode 100644
index 0000000..99dd9b1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/menuitem_background_solid_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menuitem_background_solid_pressed.9.png b/core/res/res/drawable-mdpi/menuitem_background_solid_pressed.9.png
new file mode 100644
index 0000000..389063a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/menuitem_background_solid_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/menuitem_checkbox_on.png b/core/res/res/drawable-mdpi/menuitem_checkbox_on.png
index bd8ff93..bd8ff93 100644
--- a/core/res/res/drawable/menuitem_checkbox_on.png
+++ b/core/res/res/drawable-mdpi/menuitem_checkbox_on.png
Binary files differ
diff --git a/core/res/res/drawable/no_tile_128.png b/core/res/res/drawable-mdpi/no_tile_128.png
index a9b007d..a9b007d 100644
--- a/core/res/res/drawable/no_tile_128.png
+++ b/core/res/res/drawable-mdpi/no_tile_128.png
Binary files differ
diff --git a/core/res/res/drawable/panel_background.9.png b/core/res/res/drawable-mdpi/panel_background.9.png
index 2305be4..2305be4 100644
--- a/core/res/res/drawable/panel_background.9.png
+++ b/core/res/res/drawable-mdpi/panel_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/panel_picture_frame_bg_focus_blue.9.png b/core/res/res/drawable-mdpi/panel_picture_frame_bg_focus_blue.9.png
index 7ebdbe5..7ebdbe5 100644
--- a/core/res/res/drawable/panel_picture_frame_bg_focus_blue.9.png
+++ b/core/res/res/drawable-mdpi/panel_picture_frame_bg_focus_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable/panel_picture_frame_bg_normal.9.png b/core/res/res/drawable-mdpi/panel_picture_frame_bg_normal.9.png
index fd17d09..fd17d09 100644
--- a/core/res/res/drawable/panel_picture_frame_bg_normal.9.png
+++ b/core/res/res/drawable-mdpi/panel_picture_frame_bg_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/panel_picture_frame_bg_pressed_blue.9.png b/core/res/res/drawable-mdpi/panel_picture_frame_bg_pressed_blue.9.png
index 7bb0216..7bb0216 100644
--- a/core/res/res/drawable/panel_picture_frame_bg_pressed_blue.9.png
+++ b/core/res/res/drawable-mdpi/panel_picture_frame_bg_pressed_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable/pickerbox_background.png b/core/res/res/drawable-mdpi/pickerbox_background.png
index 6494cd8..6494cd8 100644
--- a/core/res/res/drawable/pickerbox_background.png
+++ b/core/res/res/drawable-mdpi/pickerbox_background.png
Binary files differ
diff --git a/core/res/res/drawable/pickerbox_selected.9.png b/core/res/res/drawable-mdpi/pickerbox_selected.9.png
index d986a31..d986a31 100644
--- a/core/res/res/drawable/pickerbox_selected.9.png
+++ b/core/res/res/drawable-mdpi/pickerbox_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/pickerbox_unselected.9.png b/core/res/res/drawable-mdpi/pickerbox_unselected.9.png
index 27ec6b9..27ec6b9 100644
--- a/core/res/res/drawable/pickerbox_unselected.9.png
+++ b/core/res/res/drawable-mdpi/pickerbox_unselected.9.png
Binary files differ
diff --git a/core/res/res/drawable/picture_emergency.png b/core/res/res/drawable-mdpi/picture_emergency.png
index 3690b07..3690b07 100644
--- a/core/res/res/drawable/picture_emergency.png
+++ b/core/res/res/drawable-mdpi/picture_emergency.png
Binary files differ
diff --git a/core/res/res/drawable/picture_frame.9.png b/core/res/res/drawable-mdpi/picture_frame.9.png
index ba71570..ba71570 100644
--- a/core/res/res/drawable/picture_frame.9.png
+++ b/core/res/res/drawable-mdpi/picture_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_bottom_bright.9.png b/core/res/res/drawable-mdpi/popup_bottom_bright.9.png
index e8e203b..e8e203b 100644
--- a/core/res/res/drawable/popup_bottom_bright.9.png
+++ b/core/res/res/drawable-mdpi/popup_bottom_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_bottom_dark.9.png b/core/res/res/drawable-mdpi/popup_bottom_dark.9.png
index 76a2a7f..76a2a7f 100644
--- a/core/res/res/drawable/popup_bottom_dark.9.png
+++ b/core/res/res/drawable-mdpi/popup_bottom_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_bottom_medium.9.png b/core/res/res/drawable-mdpi/popup_bottom_medium.9.png
index dee6d6b..dee6d6b 100755
--- a/core/res/res/drawable/popup_bottom_medium.9.png
+++ b/core/res/res/drawable-mdpi/popup_bottom_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_center_bright.9.png b/core/res/res/drawable-mdpi/popup_center_bright.9.png
index c817338..c817338 100644
--- a/core/res/res/drawable/popup_center_bright.9.png
+++ b/core/res/res/drawable-mdpi/popup_center_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_center_dark.9.png b/core/res/res/drawable-mdpi/popup_center_dark.9.png
index 79ffdaa..79ffdaa 100644
--- a/core/res/res/drawable/popup_center_dark.9.png
+++ b/core/res/res/drawable-mdpi/popup_center_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_center_medium.9.png b/core/res/res/drawable-mdpi/popup_center_medium.9.png
index ba2e9bf..ba2e9bf 100755
--- a/core/res/res/drawable/popup_center_medium.9.png
+++ b/core/res/res/drawable-mdpi/popup_center_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_full_bright.9.png b/core/res/res/drawable-mdpi/popup_full_bright.9.png
index d33ff2b..d33ff2b 100644
--- a/core/res/res/drawable/popup_full_bright.9.png
+++ b/core/res/res/drawable-mdpi/popup_full_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_full_dark.9.png b/core/res/res/drawable-mdpi/popup_full_dark.9.png
index 2305be4..2305be4 100644
--- a/core/res/res/drawable/popup_full_dark.9.png
+++ b/core/res/res/drawable-mdpi/popup_full_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_inline_error.9.png b/core/res/res/drawable-mdpi/popup_inline_error.9.png
index 6a8297a..6a8297a 100755
--- a/core/res/res/drawable/popup_inline_error.9.png
+++ b/core/res/res/drawable-mdpi/popup_inline_error.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_inline_error_above.9.png b/core/res/res/drawable-mdpi/popup_inline_error_above.9.png
index 2e601d0..2e601d0 100644
--- a/core/res/res/drawable/popup_inline_error_above.9.png
+++ b/core/res/res/drawable-mdpi/popup_inline_error_above.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_top_bright.9.png b/core/res/res/drawable-mdpi/popup_top_bright.9.png
index 727a948..727a948 100644
--- a/core/res/res/drawable/popup_top_bright.9.png
+++ b/core/res/res/drawable-mdpi/popup_top_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_top_dark.9.png b/core/res/res/drawable-mdpi/popup_top_dark.9.png
index af511f2..af511f2 100644
--- a/core/res/res/drawable/popup_top_dark.9.png
+++ b/core/res/res/drawable-mdpi/popup_top_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/presence_away.png b/core/res/res/drawable-mdpi/presence_away.png
index f8120df..f8120df 100644
--- a/core/res/res/drawable/presence_away.png
+++ b/core/res/res/drawable-mdpi/presence_away.png
Binary files differ
diff --git a/core/res/res/drawable/presence_busy.png b/core/res/res/drawable-mdpi/presence_busy.png
index 9d7620b..9d7620b 100644
--- a/core/res/res/drawable/presence_busy.png
+++ b/core/res/res/drawable-mdpi/presence_busy.png
Binary files differ
diff --git a/core/res/res/drawable/presence_invisible.png b/core/res/res/drawable-mdpi/presence_invisible.png
index 21399a4..21399a4 100644
--- a/core/res/res/drawable/presence_invisible.png
+++ b/core/res/res/drawable-mdpi/presence_invisible.png
Binary files differ
diff --git a/core/res/res/drawable/presence_offline.png b/core/res/res/drawable-mdpi/presence_offline.png
index 3941b82..3941b82 100644
--- a/core/res/res/drawable/presence_offline.png
+++ b/core/res/res/drawable-mdpi/presence_offline.png
Binary files differ
diff --git a/core/res/res/drawable/presence_online.png b/core/res/res/drawable-mdpi/presence_online.png
index 22d5683..22d5683 100644
--- a/core/res/res/drawable/presence_online.png
+++ b/core/res/res/drawable-mdpi/presence_online.png
Binary files differ
diff --git a/core/res/res/drawable/pressed_application_background_static.png b/core/res/res/drawable-mdpi/pressed_application_background_static.png
index 070f6fd..070f6fd 100644
--- a/core/res/res/drawable/pressed_application_background_static.png
+++ b/core/res/res/drawable-mdpi/pressed_application_background_static.png
Binary files differ
diff --git a/core/res/res/drawable/progressbar_indeterminate1.png b/core/res/res/drawable-mdpi/progressbar_indeterminate1.png
index 5eddb30..5eddb30 100644
--- a/core/res/res/drawable/progressbar_indeterminate1.png
+++ b/core/res/res/drawable-mdpi/progressbar_indeterminate1.png
Binary files differ
diff --git a/core/res/res/drawable/progressbar_indeterminate2.png b/core/res/res/drawable-mdpi/progressbar_indeterminate2.png
index 4ca3a63..4ca3a63 100644
--- a/core/res/res/drawable/progressbar_indeterminate2.png
+++ b/core/res/res/drawable-mdpi/progressbar_indeterminate2.png
Binary files differ
diff --git a/core/res/res/drawable/progressbar_indeterminate3.png b/core/res/res/drawable-mdpi/progressbar_indeterminate3.png
index da8e601..da8e601 100644
--- a/core/res/res/drawable/progressbar_indeterminate3.png
+++ b/core/res/res/drawable-mdpi/progressbar_indeterminate3.png
Binary files differ
diff --git a/core/res/res/drawable/radiobutton_off_background.png b/core/res/res/drawable-mdpi/radiobutton_off_background.png
index 1b94e21..1b94e21 100644
--- a/core/res/res/drawable/radiobutton_off_background.png
+++ b/core/res/res/drawable-mdpi/radiobutton_off_background.png
Binary files differ
diff --git a/core/res/res/drawable/radiobutton_on_background.png b/core/res/res/drawable-mdpi/radiobutton_on_background.png
index 636a803..636a803 100644
--- a/core/res/res/drawable/radiobutton_on_background.png
+++ b/core/res/res/drawable-mdpi/radiobutton_on_background.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_big_half.png b/core/res/res/drawable-mdpi/rate_star_big_half.png
index 9762292..9762292 100644
--- a/core/res/res/drawable/rate_star_big_half.png
+++ b/core/res/res/drawable-mdpi/rate_star_big_half.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_big_off.png b/core/res/res/drawable-mdpi/rate_star_big_off.png
index 6b5039f..6b5039f 100644
--- a/core/res/res/drawable/rate_star_big_off.png
+++ b/core/res/res/drawable-mdpi/rate_star_big_off.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_big_on.png b/core/res/res/drawable-mdpi/rate_star_big_on.png
index a972db2..a972db2 100644
--- a/core/res/res/drawable/rate_star_big_on.png
+++ b/core/res/res/drawable-mdpi/rate_star_big_on.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_small_half.png b/core/res/res/drawable-mdpi/rate_star_small_half.png
index 437a11c..437a11c 100644
--- a/core/res/res/drawable/rate_star_small_half.png
+++ b/core/res/res/drawable-mdpi/rate_star_small_half.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_small_off.png b/core/res/res/drawable-mdpi/rate_star_small_off.png
index 6fb0a36..6fb0a36 100644
--- a/core/res/res/drawable/rate_star_small_off.png
+++ b/core/res/res/drawable-mdpi/rate_star_small_off.png
Binary files differ
diff --git a/core/res/res/drawable/rate_star_small_on.png b/core/res/res/drawable-mdpi/rate_star_small_on.png
index 5392361..5392361 100644
--- a/core/res/res/drawable/rate_star_small_on.png
+++ b/core/res/res/drawable-mdpi/rate_star_small_on.png
Binary files differ
diff --git a/core/res/res/drawable/reticle.png b/core/res/res/drawable-mdpi/reticle.png
index c6ccf8e..c6ccf8e 100644
--- a/core/res/res/drawable/reticle.png
+++ b/core/res/res/drawable-mdpi/reticle.png
Binary files differ
diff --git a/core/res/res/drawable/screen_progress_frame.9.png b/core/res/res/drawable-mdpi/screen_progress_frame.9.png
index 0e92429..0e92429 100644
--- a/core/res/res/drawable/screen_progress_frame.9.png
+++ b/core/res/res/drawable-mdpi/screen_progress_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable/screen_progress_inner.9.png b/core/res/res/drawable-mdpi/screen_progress_inner.9.png
index 1799a53..1799a53 100644
--- a/core/res/res/drawable/screen_progress_inner.9.png
+++ b/core/res/res/drawable-mdpi/screen_progress_inner.9.png
Binary files differ
diff --git a/core/res/res/drawable/scrollbar_handle_accelerated_anim2.9.png b/core/res/res/drawable-mdpi/scrollbar_handle_accelerated_anim2.9.png
index 85caddd..85caddd 100755
--- a/core/res/res/drawable/scrollbar_handle_accelerated_anim2.9.png
+++ b/core/res/res/drawable-mdpi/scrollbar_handle_accelerated_anim2.9.png
Binary files differ
diff --git a/core/res/res/drawable/scrollbar_handle_horizontal.9.png b/core/res/res/drawable-mdpi/scrollbar_handle_horizontal.9.png
index 8584d1f..8584d1f 100755
--- a/core/res/res/drawable/scrollbar_handle_horizontal.9.png
+++ b/core/res/res/drawable-mdpi/scrollbar_handle_horizontal.9.png
Binary files differ
diff --git a/core/res/res/drawable/scrollbar_handle_vertical.9.png b/core/res/res/drawable-mdpi/scrollbar_handle_vertical.9.png
index 331a05d..331a05d 100755
--- a/core/res/res/drawable/scrollbar_handle_vertical.9.png
+++ b/core/res/res/drawable-mdpi/scrollbar_handle_vertical.9.png
Binary files differ
diff --git a/core/res/res/drawable/search_dropdown_background.9.png b/core/res/res/drawable-mdpi/search_dropdown_background.9.png
index 804260a..804260a 100644
--- a/core/res/res/drawable/search_dropdown_background.9.png
+++ b/core/res/res/drawable-mdpi/search_dropdown_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/search_plate.9.png b/core/res/res/drawable-mdpi/search_plate.9.png
index 8c42f10..8c42f10 100755
--- a/core/res/res/drawable/search_plate.9.png
+++ b/core/res/res/drawable-mdpi/search_plate.9.png
Binary files differ
diff --git a/core/res/res/drawable/search_plate_global.9.png b/core/res/res/drawable-mdpi/search_plate_global.9.png
index 1cad902..1cad902 100644
--- a/core/res/res/drawable/search_plate_global.9.png
+++ b/core/res/res/drawable-mdpi/search_plate_global.9.png
Binary files differ
diff --git a/core/res/res/drawable/seek_thumb_normal.png b/core/res/res/drawable-mdpi/seek_thumb_normal.png
index e9f2e23..e9f2e23 100644
--- a/core/res/res/drawable/seek_thumb_normal.png
+++ b/core/res/res/drawable-mdpi/seek_thumb_normal.png
Binary files differ
diff --git a/core/res/res/drawable/seek_thumb_pressed.png b/core/res/res/drawable-mdpi/seek_thumb_pressed.png
index 3ea5051..3ea5051 100644
--- a/core/res/res/drawable/seek_thumb_pressed.png
+++ b/core/res/res/drawable-mdpi/seek_thumb_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/seek_thumb_selected.png b/core/res/res/drawable-mdpi/seek_thumb_selected.png
index 98b7ba0..98b7ba0 100644
--- a/core/res/res/drawable/seek_thumb_selected.png
+++ b/core/res/res/drawable-mdpi/seek_thumb_selected.png
Binary files differ
diff --git a/core/res/res/drawable/settings_header_raw.9.png b/core/res/res/drawable-mdpi/settings_header_raw.9.png
index 6b8134d..6b8134d 100644
--- a/core/res/res/drawable/settings_header_raw.9.png
+++ b/core/res/res/drawable-mdpi/settings_header_raw.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_black_16.png b/core/res/res/drawable-mdpi/spinner_black_16.png
index 5ee33ce..5ee33ce 100644
--- a/core/res/res/drawable/spinner_black_16.png
+++ b/core/res/res/drawable-mdpi/spinner_black_16.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_black_20.png b/core/res/res/drawable-mdpi/spinner_black_20.png
index e55b60d..e55b60d 100755
--- a/core/res/res/drawable/spinner_black_20.png
+++ b/core/res/res/drawable-mdpi/spinner_black_20.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_black_48.png b/core/res/res/drawable-mdpi/spinner_black_48.png
index 3a68192..3a68192 100644
--- a/core/res/res/drawable/spinner_black_48.png
+++ b/core/res/res/drawable-mdpi/spinner_black_48.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_black_76.png b/core/res/res/drawable-mdpi/spinner_black_76.png
index ec57460..ec57460 100644
--- a/core/res/res/drawable/spinner_black_76.png
+++ b/core/res/res/drawable-mdpi/spinner_black_76.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_dropdown_background_down.9.png b/core/res/res/drawable-mdpi/spinner_dropdown_background_down.9.png
index 8fd22f4..8fd22f4 100644
--- a/core/res/res/drawable/spinner_dropdown_background_down.9.png
+++ b/core/res/res/drawable-mdpi/spinner_dropdown_background_down.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_dropdown_background_up.9.png b/core/res/res/drawable-mdpi/spinner_dropdown_background_up.9.png
index 1354feb..1354feb 100644
--- a/core/res/res/drawable/spinner_dropdown_background_up.9.png
+++ b/core/res/res/drawable-mdpi/spinner_dropdown_background_up.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_normal.9.png b/core/res/res/drawable-mdpi/spinner_normal.9.png
index e0bab34..e0bab34 100644
--- a/core/res/res/drawable/spinner_normal.9.png
+++ b/core/res/res/drawable-mdpi/spinner_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_press.9.png b/core/res/res/drawable-mdpi/spinner_press.9.png
index a51c7ad..a51c7ad 100644
--- a/core/res/res/drawable/spinner_press.9.png
+++ b/core/res/res/drawable-mdpi/spinner_press.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_select.9.png b/core/res/res/drawable-mdpi/spinner_select.9.png
index 1bb19be..1bb19be 100644
--- a/core/res/res/drawable/spinner_select.9.png
+++ b/core/res/res/drawable-mdpi/spinner_select.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_white_16.png b/core/res/res/drawable-mdpi/spinner_white_16.png
index dd2e1fd..dd2e1fd 100644
--- a/core/res/res/drawable/spinner_white_16.png
+++ b/core/res/res/drawable-mdpi/spinner_white_16.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_white_48.png b/core/res/res/drawable-mdpi/spinner_white_48.png
index d25a33e..d25a33e 100644
--- a/core/res/res/drawable/spinner_white_48.png
+++ b/core/res/res/drawable-mdpi/spinner_white_48.png
Binary files differ
diff --git a/core/res/res/drawable/spinner_white_76.png b/core/res/res/drawable-mdpi/spinner_white_76.png
index f53e8ff..f53e8ff 100644
--- a/core/res/res/drawable/spinner_white_76.png
+++ b/core/res/res/drawable-mdpi/spinner_white_76.png
Binary files differ
diff --git a/core/res/res/drawable/spinnerbox_arrow_first.9.png b/core/res/res/drawable-mdpi/spinnerbox_arrow_first.9.png
index d8e268d..d8e268d 100644
--- a/core/res/res/drawable/spinnerbox_arrow_first.9.png
+++ b/core/res/res/drawable-mdpi/spinnerbox_arrow_first.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinnerbox_arrow_last.9.png b/core/res/res/drawable-mdpi/spinnerbox_arrow_last.9.png
index 087e650..087e650 100644
--- a/core/res/res/drawable/spinnerbox_arrow_last.9.png
+++ b/core/res/res/drawable-mdpi/spinnerbox_arrow_last.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinnerbox_arrow_middle.9.png b/core/res/res/drawable-mdpi/spinnerbox_arrow_middle.9.png
index f1f2ff5..f1f2ff5 100644
--- a/core/res/res/drawable/spinnerbox_arrow_middle.9.png
+++ b/core/res/res/drawable-mdpi/spinnerbox_arrow_middle.9.png
Binary files differ
diff --git a/core/res/res/drawable/spinnerbox_arrow_single.9.png b/core/res/res/drawable-mdpi/spinnerbox_arrow_single.9.png
index f537b3b..f537b3b 100644
--- a/core/res/res/drawable/spinnerbox_arrow_single.9.png
+++ b/core/res/res/drawable-mdpi/spinnerbox_arrow_single.9.png
Binary files differ
diff --git a/core/res/res/drawable/star_big_off.png b/core/res/res/drawable-mdpi/star_big_off.png
index 34ab4ab..34ab4ab 100644
--- a/core/res/res/drawable/star_big_off.png
+++ b/core/res/res/drawable-mdpi/star_big_off.png
Binary files differ
diff --git a/core/res/res/drawable/star_big_on.png b/core/res/res/drawable-mdpi/star_big_on.png
index 7aaf2bc..7aaf2bc 100644
--- a/core/res/res/drawable/star_big_on.png
+++ b/core/res/res/drawable-mdpi/star_big_on.png
Binary files differ
diff --git a/core/res/res/drawable/star_off.png b/core/res/res/drawable-mdpi/star_off.png
index ada53fc..ada53fc 100644
--- a/core/res/res/drawable/star_off.png
+++ b/core/res/res/drawable-mdpi/star_off.png
Binary files differ
diff --git a/core/res/res/drawable/star_on.png b/core/res/res/drawable-mdpi/star_on.png
index 49a57b6..49a57b6 100644
--- a/core/res/res/drawable/star_on.png
+++ b/core/res/res/drawable-mdpi/star_on.png
Binary files differ
diff --git a/core/res/res/drawable/stat_ecb_mode.png b/core/res/res/drawable-mdpi/stat_ecb_mode.png
index a948770..a948770 100644
--- a/core/res/res/drawable/stat_ecb_mode.png
+++ b/core/res/res/drawable-mdpi/stat_ecb_mode.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_alarm.png b/core/res/res/drawable-mdpi/stat_notify_alarm.png
index 1b01b85..1b01b85 100644
--- a/core/res/res/drawable/stat_notify_alarm.png
+++ b/core/res/res/drawable-mdpi/stat_notify_alarm.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_call_mute.png b/core/res/res/drawable-mdpi/stat_notify_call_mute.png
index 6da8313..6da8313 100644
--- a/core/res/res/drawable/stat_notify_call_mute.png
+++ b/core/res/res/drawable-mdpi/stat_notify_call_mute.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_chat.png b/core/res/res/drawable-mdpi/stat_notify_chat.png
index 238f043..238f043 100644
--- a/core/res/res/drawable/stat_notify_chat.png
+++ b/core/res/res/drawable-mdpi/stat_notify_chat.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_disk_full.png b/core/res/res/drawable-mdpi/stat_notify_disk_full.png
index 9120f00..9120f00 100755
--- a/core/res/res/drawable/stat_notify_disk_full.png
+++ b/core/res/res/drawable-mdpi/stat_notify_disk_full.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_error.png b/core/res/res/drawable-mdpi/stat_notify_error.png
index 6ced2b7..6ced2b7 100644
--- a/core/res/res/drawable/stat_notify_error.png
+++ b/core/res/res/drawable-mdpi/stat_notify_error.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_missed_call.png b/core/res/res/drawable-mdpi/stat_notify_missed_call.png
index fe746b3..fe746b3 100644
--- a/core/res/res/drawable/stat_notify_missed_call.png
+++ b/core/res/res/drawable-mdpi/stat_notify_missed_call.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_more.png b/core/res/res/drawable-mdpi/stat_notify_more.png
index e129ba9..e129ba9 100644
--- a/core/res/res/drawable/stat_notify_more.png
+++ b/core/res/res/drawable-mdpi/stat_notify_more.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_sdcard.png b/core/res/res/drawable-mdpi/stat_notify_sdcard.png
index aaf1f74..aaf1f74 100644
--- a/core/res/res/drawable/stat_notify_sdcard.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sdcard.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_sdcard_usb.png b/core/res/res/drawable-mdpi/stat_notify_sdcard_usb.png
index 8bc6661..8bc6661 100644
--- a/core/res/res/drawable/stat_notify_sdcard_usb.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sdcard_usb.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_sim_toolkit.png b/core/res/res/drawable-mdpi/stat_notify_sim_toolkit.png
index c1ce8f2..c1ce8f2 100755
--- a/core/res/res/drawable/stat_notify_sim_toolkit.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sim_toolkit.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_sync.png b/core/res/res/drawable-mdpi/stat_notify_sync.png
index 0edf692..0edf692 100644
--- a/core/res/res/drawable/stat_notify_sync.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sync.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_sync_anim0.png b/core/res/res/drawable-mdpi/stat_notify_sync_anim0.png
index 0edf692..0edf692 100644
--- a/core/res/res/drawable/stat_notify_sync_anim0.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sync_anim0.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_sync_error.png b/core/res/res/drawable-mdpi/stat_notify_sync_error.png
index 3078b8c..3078b8c 100644
--- a/core/res/res/drawable/stat_notify_sync_error.png
+++ b/core/res/res/drawable-mdpi/stat_notify_sync_error.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_voicemail.png b/core/res/res/drawable-mdpi/stat_notify_voicemail.png
index 658fa05..658fa05 100644
--- a/core/res/res/drawable/stat_notify_voicemail.png
+++ b/core/res/res/drawable-mdpi/stat_notify_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_wifi_in_range.png b/core/res/res/drawable-mdpi/stat_notify_wifi_in_range.png
index e9c74b4..e9c74b4 100644
--- a/core/res/res/drawable/stat_notify_wifi_in_range.png
+++ b/core/res/res/drawable-mdpi/stat_notify_wifi_in_range.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_0.png b/core/res/res/drawable-mdpi/stat_sys_battery_0.png
index 4a5e99e..4a5e99e 100644
--- a/core/res/res/drawable/stat_sys_battery_0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_0.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_10.png b/core/res/res/drawable-mdpi/stat_sys_battery_10.png
index b789f23..b789f23 100755
--- a/core/res/res/drawable/stat_sys_battery_10.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_10.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_100.png b/core/res/res/drawable-mdpi/stat_sys_battery_100.png
index d280aeb..d280aeb 100644
--- a/core/res/res/drawable/stat_sys_battery_100.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_100.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_20.png b/core/res/res/drawable-mdpi/stat_sys_battery_20.png
index 009a9fd..009a9fd 100644
--- a/core/res/res/drawable/stat_sys_battery_20.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_20.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_40.png b/core/res/res/drawable-mdpi/stat_sys_battery_40.png
index 15b57f4..15b57f4 100644
--- a/core/res/res/drawable/stat_sys_battery_40.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_40.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_60.png b/core/res/res/drawable-mdpi/stat_sys_battery_60.png
index 21078fd..21078fd 100644
--- a/core/res/res/drawable/stat_sys_battery_60.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_60.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_80.png b/core/res/res/drawable-mdpi/stat_sys_battery_80.png
index 9268f7b..9268f7b 100644
--- a/core/res/res/drawable/stat_sys_battery_80.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_80.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_charge_anim0.png b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim0.png
index ff3cabd..ff3cabd 100644
--- a/core/res/res/drawable/stat_sys_battery_charge_anim0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim0.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_charge_anim1.png b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim1.png
index b563701..b563701 100644
--- a/core/res/res/drawable/stat_sys_battery_charge_anim1.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim1.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_charge_anim2.png b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim2.png
index 904989e..904989e 100644
--- a/core/res/res/drawable/stat_sys_battery_charge_anim2.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim2.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_charge_anim3.png b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim3.png
index ba011c9..ba011c9 100644
--- a/core/res/res/drawable/stat_sys_battery_charge_anim3.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim3.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_charge_anim4.png b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim4.png
index 4f1c485..4f1c485 100644
--- a/core/res/res/drawable/stat_sys_battery_charge_anim4.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim4.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_charge_anim5.png b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim5.png
index 4d3396d..4d3396d 100644
--- a/core/res/res/drawable/stat_sys_battery_charge_anim5.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_charge_anim5.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_battery_unknown.png b/core/res/res/drawable-mdpi/stat_sys_battery_unknown.png
index ed72ebf..ed72ebf 100644
--- a/core/res/res/drawable/stat_sys_battery_unknown.png
+++ b/core/res/res/drawable-mdpi/stat_sys_battery_unknown.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_bluetooth.png b/core/res/res/drawable-mdpi/stat_sys_data_bluetooth.png
index 7a8b78f..7a8b78f 100644
--- a/core/res/res/drawable/stat_sys_data_bluetooth.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_bluetooth_connected.png b/core/res/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
index f09b83b..f09b83b 100755
--- a/core/res/res/drawable/stat_sys_data_bluetooth_connected.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_bluetooth_connected.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_connected_3g.png b/core/res/res/drawable-mdpi/stat_sys_data_connected_3g.png
index a109280..a109280 100644
--- a/core/res/res/drawable/stat_sys_data_connected_3g.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_connected_e.png b/core/res/res/drawable-mdpi/stat_sys_data_connected_e.png
index c552644..c552644 100644
--- a/core/res/res/drawable/stat_sys_data_connected_e.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_connected_g.png b/core/res/res/drawable-mdpi/stat_sys_data_connected_g.png
index f7edb49..f7edb49 100644
--- a/core/res/res/drawable/stat_sys_data_connected_g.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_3g.png b/core/res/res/drawable-mdpi/stat_sys_data_in_3g.png
index 01b003c..01b003c 100644
--- a/core/res/res/drawable/stat_sys_data_in_3g.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_e.png b/core/res/res/drawable-mdpi/stat_sys_data_in_e.png
index bffa0eb..bffa0eb 100644
--- a/core/res/res/drawable/stat_sys_data_in_e.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_g.png b/core/res/res/drawable-mdpi/stat_sys_data_in_g.png
index 8884b48..8884b48 100644
--- a/core/res/res/drawable/stat_sys_data_in_g.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_3g.png b/core/res/res/drawable-mdpi/stat_sys_data_inandout_3g.png
index 3651300..3651300 100644
--- a/core/res/res/drawable/stat_sys_data_inandout_3g.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_e.png b/core/res/res/drawable-mdpi/stat_sys_data_inandout_e.png
index 99533e0..99533e0 100644
--- a/core/res/res/drawable/stat_sys_data_inandout_e.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_inandout_e.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_g.png b/core/res/res/drawable-mdpi/stat_sys_data_inandout_g.png
index f4e5a12..f4e5a12 100644
--- a/core/res/res/drawable/stat_sys_data_inandout_g.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_3g.png b/core/res/res/drawable-mdpi/stat_sys_data_out_3g.png
index f7f0f89..f7f0f89 100644
--- a/core/res/res/drawable/stat_sys_data_out_3g.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_e.png b/core/res/res/drawable-mdpi/stat_sys_data_out_e.png
index c915426..c915426 100644
--- a/core/res/res/drawable/stat_sys_data_out_e.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_g.png b/core/res/res/drawable-mdpi/stat_sys_data_out_g.png
index 5d36035..5d36035 100644
--- a/core/res/res/drawable/stat_sys_data_out_g.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_usb.png b/core/res/res/drawable-mdpi/stat_sys_data_usb.png
index 2d0da4c..2d0da4c 100644
--- a/core/res/res/drawable/stat_sys_data_usb.png
+++ b/core/res/res/drawable-mdpi/stat_sys_data_usb.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_download_anim0.png b/core/res/res/drawable-mdpi/stat_sys_download_anim0.png
index 69b95cd..69b95cd 100755
--- a/core/res/res/drawable/stat_sys_download_anim0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim0.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_download_anim1.png b/core/res/res/drawable-mdpi/stat_sys_download_anim1.png
index 1e18eb5..1e18eb5 100755
--- a/core/res/res/drawable/stat_sys_download_anim1.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim1.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_download_anim2.png b/core/res/res/drawable-mdpi/stat_sys_download_anim2.png
index d7f2312..d7f2312 100755
--- a/core/res/res/drawable/stat_sys_download_anim2.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim2.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_download_anim3.png b/core/res/res/drawable-mdpi/stat_sys_download_anim3.png
index 83f8d0f..83f8d0f 100755
--- a/core/res/res/drawable/stat_sys_download_anim3.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim3.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_download_anim4.png b/core/res/res/drawable-mdpi/stat_sys_download_anim4.png
index 9c1bd47..9c1bd47 100755
--- a/core/res/res/drawable/stat_sys_download_anim4.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim4.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_download_anim5.png b/core/res/res/drawable-mdpi/stat_sys_download_anim5.png
index 3a81164..3a81164 100755
--- a/core/res/res/drawable/stat_sys_download_anim5.png
+++ b/core/res/res/drawable-mdpi/stat_sys_download_anim5.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_gps_acquiring.png b/core/res/res/drawable-mdpi/stat_sys_gps_acquiring.png
index 31bc94e..31bc94e 100644
--- a/core/res/res/drawable/stat_sys_gps_acquiring.png
+++ b/core/res/res/drawable-mdpi/stat_sys_gps_acquiring.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_gps_on.png b/core/res/res/drawable-mdpi/stat_sys_gps_on.png
index a2c677d..a2c677d 100755
--- a/core/res/res/drawable/stat_sys_gps_on.png
+++ b/core/res/res/drawable-mdpi/stat_sys_gps_on.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_headset.png b/core/res/res/drawable-mdpi/stat_sys_headset.png
index 45fbea2..45fbea2 100644
--- a/core/res/res/drawable/stat_sys_headset.png
+++ b/core/res/res/drawable-mdpi/stat_sys_headset.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_no_sim.png b/core/res/res/drawable-mdpi/stat_sys_no_sim.png
index 2134d49..2134d49 100644
--- a/core/res/res/drawable/stat_sys_no_sim.png
+++ b/core/res/res/drawable-mdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_phone_call.png b/core/res/res/drawable-mdpi/stat_sys_phone_call.png
index c44d062..c44d062 100644
--- a/core/res/res/drawable/stat_sys_phone_call.png
+++ b/core/res/res/drawable-mdpi/stat_sys_phone_call.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png
index 7abfd19..7abfd19 100644
--- a/core/res/res/drawable/stat_sys_phone_call_bluetooth.png
+++ b/core/res/res/drawable-mdpi/stat_sys_phone_call_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_phone_call_forward.png b/core/res/res/drawable-mdpi/stat_sys_phone_call_forward.png
index ed4b6ec..ed4b6ec 100755
--- a/core/res/res/drawable/stat_sys_phone_call_forward.png
+++ b/core/res/res/drawable-mdpi/stat_sys_phone_call_forward.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_phone_call_on_hold.png b/core/res/res/drawable-mdpi/stat_sys_phone_call_on_hold.png
index 9216447..9216447 100644
--- a/core/res/res/drawable/stat_sys_phone_call_on_hold.png
+++ b/core/res/res/drawable-mdpi/stat_sys_phone_call_on_hold.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_r_signal_0.png b/core/res/res/drawable-mdpi/stat_sys_r_signal_0.png
index bfbf18e..bfbf18e 100644
--- a/core/res/res/drawable/stat_sys_r_signal_0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_r_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_r_signal_0_cdma.png b/core/res/res/drawable-mdpi/stat_sys_r_signal_0_cdma.png
index f615681..f615681 100644
--- a/core/res/res/drawable/stat_sys_r_signal_0_cdma.png
+++ b/core/res/res/drawable-mdpi/stat_sys_r_signal_0_cdma.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_r_signal_1.png b/core/res/res/drawable-mdpi/stat_sys_r_signal_1.png
index 896ba4d..896ba4d 100644
--- a/core/res/res/drawable/stat_sys_r_signal_1.png
+++ b/core/res/res/drawable-mdpi/stat_sys_r_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_r_signal_1_cdma.png b/core/res/res/drawable-mdpi/stat_sys_r_signal_1_cdma.png
index c3962a2..c3962a2 100644
--- a/core/res/res/drawable/stat_sys_r_signal_1_cdma.png
+++ b/core/res/res/drawable-mdpi/stat_sys_r_signal_1_cdma.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_r_signal_2.png b/core/res/res/drawable-mdpi/stat_sys_r_signal_2.png
index af79eff..af79eff 100644
--- a/core/res/res/drawable/stat_sys_r_signal_2.png
+++ b/core/res/res/drawable-mdpi/stat_sys_r_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_r_signal_2_cdma.png b/core/res/res/drawable-mdpi/stat_sys_r_signal_2_cdma.png
index 68bfe94..68bfe94 100644
--- a/core/res/res/drawable/stat_sys_r_signal_2_cdma.png
+++ b/core/res/res/drawable-mdpi/stat_sys_r_signal_2_cdma.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_r_signal_3.png b/core/res/res/drawable-mdpi/stat_sys_r_signal_3.png
index 92c09c8..92c09c8 100644
--- a/core/res/res/drawable/stat_sys_r_signal_3.png
+++ b/core/res/res/drawable-mdpi/stat_sys_r_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_r_signal_3_cdma.png b/core/res/res/drawable-mdpi/stat_sys_r_signal_3_cdma.png
index 4ccd416..4ccd416 100644
--- a/core/res/res/drawable/stat_sys_r_signal_3_cdma.png
+++ b/core/res/res/drawable-mdpi/stat_sys_r_signal_3_cdma.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_r_signal_4.png b/core/res/res/drawable-mdpi/stat_sys_r_signal_4.png
index f04fb11..f04fb11 100644
--- a/core/res/res/drawable/stat_sys_r_signal_4.png
+++ b/core/res/res/drawable-mdpi/stat_sys_r_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_r_signal_4_cdma.png b/core/res/res/drawable-mdpi/stat_sys_r_signal_4_cdma.png
index 0b25570..0b25570 100644
--- a/core/res/res/drawable/stat_sys_r_signal_4_cdma.png
+++ b/core/res/res/drawable-mdpi/stat_sys_r_signal_4_cdma.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_ra_signal_0_cdma.png b/core/res/res/drawable-mdpi/stat_sys_ra_signal_0_cdma.png
index 9a38733..9a38733 100644
--- a/core/res/res/drawable/stat_sys_ra_signal_0_cdma.png
+++ b/core/res/res/drawable-mdpi/stat_sys_ra_signal_0_cdma.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_ra_signal_1_cdma.png b/core/res/res/drawable-mdpi/stat_sys_ra_signal_1_cdma.png
index c70e283..c70e283 100644
--- a/core/res/res/drawable/stat_sys_ra_signal_1_cdma.png
+++ b/core/res/res/drawable-mdpi/stat_sys_ra_signal_1_cdma.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_ra_signal_2_cdma.png b/core/res/res/drawable-mdpi/stat_sys_ra_signal_2_cdma.png
index a09564c..a09564c 100644
--- a/core/res/res/drawable/stat_sys_ra_signal_2_cdma.png
+++ b/core/res/res/drawable-mdpi/stat_sys_ra_signal_2_cdma.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_ra_signal_3_cdma.png b/core/res/res/drawable-mdpi/stat_sys_ra_signal_3_cdma.png
index 2637dec..2637dec 100644
--- a/core/res/res/drawable/stat_sys_ra_signal_3_cdma.png
+++ b/core/res/res/drawable-mdpi/stat_sys_ra_signal_3_cdma.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_ra_signal_4_cdma.png b/core/res/res/drawable-mdpi/stat_sys_ra_signal_4_cdma.png
index aba13e7..aba13e7 100644
--- a/core/res/res/drawable/stat_sys_ra_signal_4_cdma.png
+++ b/core/res/res/drawable-mdpi/stat_sys_ra_signal_4_cdma.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_ringer_silent.png b/core/res/res/drawable-mdpi/stat_sys_ringer_silent.png
index d62f32d..d62f32d 100644
--- a/core/res/res/drawable/stat_sys_ringer_silent.png
+++ b/core/res/res/drawable-mdpi/stat_sys_ringer_silent.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_ringer_vibrate.png b/core/res/res/drawable-mdpi/stat_sys_ringer_vibrate.png
index 665ca38..665ca38 100644
--- a/core/res/res/drawable/stat_sys_ringer_vibrate.png
+++ b/core/res/res/drawable-mdpi/stat_sys_ringer_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_roaming_cdma_0.png b/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
index c61cce7..c61cce7 100755
--- a/core/res/res/drawable/stat_sys_roaming_cdma_0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_roaming_cdma_flash_anim0.png b/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png
index d62502d..d62502d 100755
--- a/core/res/res/drawable/stat_sys_roaming_cdma_flash_anim0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim0.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_roaming_cdma_flash_anim1.png b/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
index c61cce7..c61cce7 100755
--- a/core/res/res/drawable/stat_sys_roaming_cdma_flash_anim1.png
+++ b/core/res/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_0.png b/core/res/res/drawable-mdpi/stat_sys_signal_0.png
index cb7b7b3..cb7b7b3 100644
--- a/core/res/res/drawable/stat_sys_signal_0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_1.png b/core/res/res/drawable-mdpi/stat_sys_signal_1.png
index 5376e92..5376e92 100644
--- a/core/res/res/drawable/stat_sys_signal_1.png
+++ b/core/res/res/drawable-mdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_2.png b/core/res/res/drawable-mdpi/stat_sys_signal_2.png
index fd54363..fd54363 100644
--- a/core/res/res/drawable/stat_sys_signal_2.png
+++ b/core/res/res/drawable-mdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_3.png b/core/res/res/drawable-mdpi/stat_sys_signal_3.png
index 6c4873a..6c4873a 100644
--- a/core/res/res/drawable/stat_sys_signal_3.png
+++ b/core/res/res/drawable-mdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_4.png b/core/res/res/drawable-mdpi/stat_sys_signal_4.png
index a3320cb..a3320cb 100644
--- a/core/res/res/drawable/stat_sys_signal_4.png
+++ b/core/res/res/drawable-mdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_flightmode.png b/core/res/res/drawable-mdpi/stat_sys_signal_flightmode.png
index 2f4fd4f..2f4fd4f 100644..100755
--- a/core/res/res/drawable/stat_sys_signal_flightmode.png
+++ b/core/res/res/drawable-mdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_null.png b/core/res/res/drawable-mdpi/stat_sys_signal_null.png
index 5aa23f6..5aa23f6 100644
--- a/core/res/res/drawable/stat_sys_signal_null.png
+++ b/core/res/res/drawable-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_speakerphone.png b/core/res/res/drawable-mdpi/stat_sys_speakerphone.png
index 642dfd4..642dfd4 100644
--- a/core/res/res/drawable/stat_sys_speakerphone.png
+++ b/core/res/res/drawable-mdpi/stat_sys_speakerphone.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_tty_mode.png b/core/res/res/drawable-mdpi/stat_sys_tty_mode.png
index ed157a8..ed157a8 100644
--- a/core/res/res/drawable/stat_sys_tty_mode.png
+++ b/core/res/res/drawable-mdpi/stat_sys_tty_mode.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_upload_anim0.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim0.png
index b7a5978..b7a5978 100755
--- a/core/res/res/drawable/stat_sys_upload_anim0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim0.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_upload_anim1.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim1.png
index a203e15..a203e15 100755
--- a/core/res/res/drawable/stat_sys_upload_anim1.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim1.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_upload_anim2.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim2.png
index 4af7630..4af7630 100755
--- a/core/res/res/drawable/stat_sys_upload_anim2.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim2.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_upload_anim3.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim3.png
index 1dd76b1..1dd76b1 100755
--- a/core/res/res/drawable/stat_sys_upload_anim3.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim3.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_upload_anim4.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim4.png
index 36c18bf..36c18bf 100755
--- a/core/res/res/drawable/stat_sys_upload_anim4.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim4.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_upload_anim5.png b/core/res/res/drawable-mdpi/stat_sys_upload_anim5.png
index 748331f..748331f 100755
--- a/core/res/res/drawable/stat_sys_upload_anim5.png
+++ b/core/res/res/drawable-mdpi/stat_sys_upload_anim5.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_vp_phone_call.png b/core/res/res/drawable-mdpi/stat_sys_vp_phone_call.png
index aa03b4f..aa03b4f 100644
--- a/core/res/res/drawable/stat_sys_vp_phone_call.png
+++ b/core/res/res/drawable-mdpi/stat_sys_vp_phone_call.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_vp_phone_call_bluetooth.png b/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png
index 7abfd19..7abfd19 100644
--- a/core/res/res/drawable/stat_sys_vp_phone_call_bluetooth.png
+++ b/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_vp_phone_call_on_hold.png b/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_on_hold.png
index 5f45440..5f45440 100644
--- a/core/res/res/drawable/stat_sys_vp_phone_call_on_hold.png
+++ b/core/res/res/drawable-mdpi/stat_sys_vp_phone_call_on_hold.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_warning.png b/core/res/res/drawable-mdpi/stat_sys_warning.png
index be00f47..be00f47 100644
--- a/core/res/res/drawable/stat_sys_warning.png
+++ b/core/res/res/drawable-mdpi/stat_sys_warning.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_wifi_signal_0.png b/core/res/res/drawable-mdpi/stat_sys_wifi_signal_0.png
index 8ee3421..8ee3421 100644
--- a/core/res/res/drawable/stat_sys_wifi_signal_0.png
+++ b/core/res/res/drawable-mdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_wifi_signal_1.png b/core/res/res/drawable-mdpi/stat_sys_wifi_signal_1.png
index 184fa36..184fa36 100644
--- a/core/res/res/drawable/stat_sys_wifi_signal_1.png
+++ b/core/res/res/drawable-mdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_wifi_signal_2.png b/core/res/res/drawable-mdpi/stat_sys_wifi_signal_2.png
index 79935bb..79935bb 100644
--- a/core/res/res/drawable/stat_sys_wifi_signal_2.png
+++ b/core/res/res/drawable-mdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_wifi_signal_3.png b/core/res/res/drawable-mdpi/stat_sys_wifi_signal_3.png
index d2099e6..d2099e6 100644
--- a/core/res/res/drawable/stat_sys_wifi_signal_3.png
+++ b/core/res/res/drawable-mdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_wifi_signal_4.png b/core/res/res/drawable-mdpi/stat_sys_wifi_signal_4.png
index 2062aad..2062aad 100644
--- a/core/res/res/drawable/stat_sys_wifi_signal_4.png
+++ b/core/res/res/drawable-mdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/core/res/res/drawable/status_bar_background.png b/core/res/res/drawable-mdpi/status_bar_background.png
index cd11166..cd11166 100644
--- a/core/res/res/drawable/status_bar_background.png
+++ b/core/res/res/drawable-mdpi/status_bar_background.png
Binary files differ
diff --git a/core/res/res/drawable/status_bar_close_on.9.png b/core/res/res/drawable-mdpi/status_bar_close_on.9.png
index 9cbd9fe..9cbd9fe 100644
--- a/core/res/res/drawable/status_bar_close_on.9.png
+++ b/core/res/res/drawable-mdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/core/res/res/drawable/status_bar_header_background.9.png b/core/res/res/drawable-mdpi/status_bar_header_background.9.png
index fa9a90c..fa9a90c 100644
--- a/core/res/res/drawable/status_bar_header_background.9.png
+++ b/core/res/res/drawable-mdpi/status_bar_header_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/status_bar_item_app_background_normal.9.png b/core/res/res/drawable-mdpi/status_bar_item_app_background_normal.9.png
index c079615..c079615 100644
--- a/core/res/res/drawable/status_bar_item_app_background_normal.9.png
+++ b/core/res/res/drawable-mdpi/status_bar_item_app_background_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/status_bar_item_background_focus.9.png b/core/res/res/drawable-mdpi/status_bar_item_background_focus.9.png
index c3e2415..c3e2415 100644
--- a/core/res/res/drawable/status_bar_item_background_focus.9.png
+++ b/core/res/res/drawable-mdpi/status_bar_item_background_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable/status_bar_item_background_normal.9.png b/core/res/res/drawable-mdpi/status_bar_item_background_normal.9.png
index b8e399d..b8e399d 100644
--- a/core/res/res/drawable/status_bar_item_background_normal.9.png
+++ b/core/res/res/drawable-mdpi/status_bar_item_background_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/status_bar_item_background_pressed.9.png b/core/res/res/drawable-mdpi/status_bar_item_background_pressed.9.png
index 02b4e9a..02b4e9a 100644
--- a/core/res/res/drawable/status_bar_item_background_pressed.9.png
+++ b/core/res/res/drawable-mdpi/status_bar_item_background_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/statusbar_background.png b/core/res/res/drawable-mdpi/statusbar_background.png
index 204d76a..204d76a 100644
--- a/core/res/res/drawable/statusbar_background.png
+++ b/core/res/res/drawable-mdpi/statusbar_background.png
Binary files differ
diff --git a/core/res/res/drawable/submenu_arrow_nofocus.png b/core/res/res/drawable-mdpi/submenu_arrow_nofocus.png
index cead09e..cead09e 100644
--- a/core/res/res/drawable/submenu_arrow_nofocus.png
+++ b/core/res/res/drawable-mdpi/submenu_arrow_nofocus.png
Binary files differ
diff --git a/core/res/res/drawable/sym_action_add.png b/core/res/res/drawable-mdpi/sym_action_add.png
index af637b3..af637b3 100644
--- a/core/res/res/drawable/sym_action_add.png
+++ b/core/res/res/drawable-mdpi/sym_action_add.png
Binary files differ
diff --git a/core/res/res/drawable/sym_action_call.png b/core/res/res/drawable-mdpi/sym_action_call.png
index a442758..a442758 100644
--- a/core/res/res/drawable/sym_action_call.png
+++ b/core/res/res/drawable-mdpi/sym_action_call.png
Binary files differ
diff --git a/core/res/res/drawable/sym_action_chat.png b/core/res/res/drawable-mdpi/sym_action_chat.png
index 9f6419e..9f6419e 100644
--- a/core/res/res/drawable/sym_action_chat.png
+++ b/core/res/res/drawable-mdpi/sym_action_chat.png
Binary files differ
diff --git a/core/res/res/drawable/sym_action_email.png b/core/res/res/drawable-mdpi/sym_action_email.png
index 5fea417..5fea417 100644
--- a/core/res/res/drawable/sym_action_email.png
+++ b/core/res/res/drawable-mdpi/sym_action_email.png
Binary files differ
diff --git a/core/res/res/drawable/sym_call_incoming.png b/core/res/res/drawable-mdpi/sym_call_incoming.png
index 652b882..652b882 100644
--- a/core/res/res/drawable/sym_call_incoming.png
+++ b/core/res/res/drawable-mdpi/sym_call_incoming.png
Binary files differ
diff --git a/core/res/res/drawable/sym_call_missed.png b/core/res/res/drawable-mdpi/sym_call_missed.png
index ed859d0..ed859d0 100644
--- a/core/res/res/drawable/sym_call_missed.png
+++ b/core/res/res/drawable-mdpi/sym_call_missed.png
Binary files differ
diff --git a/core/res/res/drawable/sym_call_outgoing.png b/core/res/res/drawable-mdpi/sym_call_outgoing.png
index bdf675d..bdf675d 100644
--- a/core/res/res/drawable/sym_call_outgoing.png
+++ b/core/res/res/drawable-mdpi/sym_call_outgoing.png
Binary files differ
diff --git a/core/res/res/drawable/sym_contact_card.png b/core/res/res/drawable-mdpi/sym_contact_card.png
index 023ea6f..023ea6f 100644
--- a/core/res/res/drawable/sym_contact_card.png
+++ b/core/res/res/drawable-mdpi/sym_contact_card.png
Binary files differ
diff --git a/core/res/res/drawable/sym_def_app_icon.png b/core/res/res/drawable-mdpi/sym_def_app_icon.png
index 8be3b54..8be3b54 100644
--- a/core/res/res/drawable/sym_def_app_icon.png
+++ b/core/res/res/drawable-mdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_focus.9.png b/core/res/res/drawable-mdpi/tab_focus.9.png
new file mode 100755
index 0000000..d9bcc57
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_focus_bar_left.9.png b/core/res/res/drawable-mdpi/tab_focus_bar_left.9.png
new file mode 100755
index 0000000..2536d94
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_focus_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_focus_bar_right.9.png b/core/res/res/drawable-mdpi/tab_focus_bar_right.9.png
new file mode 100755
index 0000000..2536d94
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_focus_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_press.9.png b/core/res/res/drawable-mdpi/tab_press.9.png
new file mode 100755
index 0000000..3332660
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_press.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_press_bar_left.9.png b/core/res/res/drawable-mdpi/tab_press_bar_left.9.png
new file mode 100755
index 0000000..d2c75e3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_press_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_press_bar_right.9.png b/core/res/res/drawable-mdpi/tab_press_bar_right.9.png
new file mode 100755
index 0000000..d2c75e3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_press_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected.9.png b/core/res/res/drawable-mdpi/tab_selected.9.png
new file mode 100644
index 0000000..54190ea
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected_bar_left.9.png b/core/res/res/drawable-mdpi/tab_selected_bar_left.9.png
new file mode 100755
index 0000000..d20f3a2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_selected_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected_bar_right.9.png b/core/res/res/drawable-mdpi/tab_selected_bar_right.9.png
new file mode 100755
index 0000000..d20f3a2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_selected_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_unselected.9.png b/core/res/res/drawable-mdpi/tab_unselected.9.png
new file mode 100644
index 0000000..1b8a69c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_unselected.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_default.9.png b/core/res/res/drawable-mdpi/textfield_default.9.png
index cc78e6c..cc78e6c 100644
--- a/core/res/res/drawable/textfield_default.9.png
+++ b/core/res/res/drawable-mdpi/textfield_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_disabled.9.png b/core/res/res/drawable-mdpi/textfield_disabled.9.png
index 9c77149..9c77149 100644
--- a/core/res/res/drawable/textfield_disabled.9.png
+++ b/core/res/res/drawable-mdpi/textfield_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_disabled_selected.9.png b/core/res/res/drawable-mdpi/textfield_disabled_selected.9.png
index 6d47708..6d47708 100644
--- a/core/res/res/drawable/textfield_disabled_selected.9.png
+++ b/core/res/res/drawable-mdpi/textfield_disabled_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_pressed.9.png b/core/res/res/drawable-mdpi/textfield_pressed.9.png
index c909ad2..c909ad2 100644
--- a/core/res/res/drawable/textfield_pressed.9.png
+++ b/core/res/res/drawable-mdpi/textfield_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_search_default.9.png b/core/res/res/drawable-mdpi/textfield_search_default.9.png
index 7dc5b27..7dc5b27 100755
--- a/core/res/res/drawable/textfield_search_default.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_search_pressed.9.png b/core/res/res/drawable-mdpi/textfield_search_pressed.9.png
index da00c25..da00c25 100644
--- a/core/res/res/drawable/textfield_search_pressed.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_search_selected.9.png b/core/res/res/drawable-mdpi/textfield_search_selected.9.png
index a9fd3b2..a9fd3b2 100755
--- a/core/res/res/drawable/textfield_search_selected.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_selected.9.png b/core/res/res/drawable-mdpi/textfield_selected.9.png
index 0c1b446..0c1b446 100644
--- a/core/res/res/drawable/textfield_selected.9.png
+++ b/core/res/res/drawable-mdpi/textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_down_disabled.9.png b/core/res/res/drawable-mdpi/timepicker_down_disabled.9.png
index 596294b..596294b 100755
--- a/core/res/res/drawable/timepicker_down_disabled.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_down_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_down_disabled_focused.9.png b/core/res/res/drawable-mdpi/timepicker_down_disabled_focused.9.png
index 662cffd..662cffd 100755
--- a/core/res/res/drawable/timepicker_down_disabled_focused.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_down_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_down_normal.9.png b/core/res/res/drawable-mdpi/timepicker_down_normal.9.png
index f17e8f9..f17e8f9 100755
--- a/core/res/res/drawable/timepicker_down_normal.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_down_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_down_pressed.9.png b/core/res/res/drawable-mdpi/timepicker_down_pressed.9.png
index 777bcf5..777bcf5 100755
--- a/core/res/res/drawable/timepicker_down_pressed.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_down_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_down_selected.9.png b/core/res/res/drawable-mdpi/timepicker_down_selected.9.png
index b45db62..b45db62 100755
--- a/core/res/res/drawable/timepicker_down_selected.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_down_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_input_disabled.9.png b/core/res/res/drawable-mdpi/timepicker_input_disabled.9.png
index f73658e..f73658e 100755
--- a/core/res/res/drawable/timepicker_input_disabled.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_input_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_input_normal.9.png b/core/res/res/drawable-mdpi/timepicker_input_normal.9.png
index 8032ada..8032ada 100755
--- a/core/res/res/drawable/timepicker_input_normal.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_input_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_input_pressed.9.png b/core/res/res/drawable-mdpi/timepicker_input_pressed.9.png
index 30d8d5f..30d8d5f 100755
--- a/core/res/res/drawable/timepicker_input_pressed.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_input_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_input_selected.9.png b/core/res/res/drawable-mdpi/timepicker_input_selected.9.png
index 874f18f..874f18f 100755
--- a/core/res/res/drawable/timepicker_input_selected.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_input_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_up_disabled.9.png b/core/res/res/drawable-mdpi/timepicker_up_disabled.9.png
index 327b0b5..327b0b5 100755
--- a/core/res/res/drawable/timepicker_up_disabled.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_up_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_up_disabled_focused.9.png b/core/res/res/drawable-mdpi/timepicker_up_disabled_focused.9.png
index 4c96680..4c96680 100755
--- a/core/res/res/drawable/timepicker_up_disabled_focused.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_up_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_up_normal.9.png b/core/res/res/drawable-mdpi/timepicker_up_normal.9.png
index dcd26e0..dcd26e0 100755
--- a/core/res/res/drawable/timepicker_up_normal.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_up_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_up_pressed.9.png b/core/res/res/drawable-mdpi/timepicker_up_pressed.9.png
index 7dac778..7dac778 100755
--- a/core/res/res/drawable/timepicker_up_pressed.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_up_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_up_selected.9.png b/core/res/res/drawable-mdpi/timepicker_up_selected.9.png
index 35dae8e..35dae8e 100755
--- a/core/res/res/drawable/timepicker_up_selected.9.png
+++ b/core/res/res/drawable-mdpi/timepicker_up_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/title_bar_portrait.9.png b/core/res/res/drawable-mdpi/title_bar_portrait.9.png
index 482d82e..482d82e 100644
--- a/core/res/res/drawable/title_bar_portrait.9.png
+++ b/core/res/res/drawable-mdpi/title_bar_portrait.9.png
Binary files differ
diff --git a/core/res/res/drawable/title_bar_shadow.9.png b/core/res/res/drawable-mdpi/title_bar_shadow.9.png
index 0872366..0872366 100644
--- a/core/res/res/drawable/title_bar_shadow.9.png
+++ b/core/res/res/drawable-mdpi/title_bar_shadow.9.png
Binary files differ
diff --git a/core/res/res/drawable/title_bar_tall.png b/core/res/res/drawable-mdpi/title_bar_tall.png
index cd565dc..cd565dc 100644
--- a/core/res/res/drawable/title_bar_tall.png
+++ b/core/res/res/drawable-mdpi/title_bar_tall.png
Binary files differ
diff --git a/core/res/res/drawable/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png
index 08c4f86..08c4f86 100755
--- a/core/res/res/drawable/toast_frame.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable/unknown_image.png b/core/res/res/drawable-mdpi/unknown_image.png
index b1c3e92..b1c3e92 100644
--- a/core/res/res/drawable/unknown_image.png
+++ b/core/res/res/drawable-mdpi/unknown_image.png
Binary files differ
diff --git a/core/res/res/drawable/zoom_plate.9.png b/core/res/res/drawable-mdpi/zoom_plate.9.png
index c8c1a08..c8c1a08 100644
--- a/core/res/res/drawable/zoom_plate.9.png
+++ b/core/res/res/drawable-mdpi/zoom_plate.9.png
Binary files differ
diff --git a/core/res/res/drawable/contact_header_bg.9.png b/core/res/res/drawable/contact_header_bg.9.png
new file mode 100644
index 0000000..7f9a5a3
--- /dev/null
+++ b/core/res/res/drawable/contact_header_bg.9.png
Binary files differ
diff --git a/core/res/res/drawable/dark_header.9.png b/core/res/res/drawable/dark_header.9.png
deleted file mode 100644
index 8fa5f09..0000000
--- a/core/res/res/drawable/dark_header.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/dark_header_dither.xml b/core/res/res/drawable/dark_header_dither.xml
new file mode 100644
index 0000000..0741fa4
--- /dev/null
+++ b/core/res/res/drawable/dark_header_dither.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/dark_header"
+ android:dither="true"
+/>
diff --git a/core/res/res/drawable/divider_horizontal_bright.9.png b/core/res/res/drawable/divider_horizontal_bright.9.png
deleted file mode 100644
index 144fc22..0000000
--- a/core/res/res/drawable/divider_horizontal_bright.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_bright_opaque.9.png b/core/res/res/drawable/divider_horizontal_bright_opaque.9.png
deleted file mode 100644
index 30c9b2b..0000000
--- a/core/res/res/drawable/divider_horizontal_bright_opaque.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_dark.9.png b/core/res/res/drawable/divider_horizontal_dark.9.png
deleted file mode 100644
index 08838ca..0000000
--- a/core/res/res/drawable/divider_horizontal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_dark_opaque.9.png b/core/res/res/drawable/divider_horizontal_dark_opaque.9.png
deleted file mode 100644
index ce21acd..0000000
--- a/core/res/res/drawable/divider_horizontal_dark_opaque.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_bright.9.png b/core/res/res/drawable/divider_vertical_bright.9.png
deleted file mode 100644
index da6e4ec..0000000
--- a/core/res/res/drawable/divider_vertical_bright.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_bright_opaque.9.png b/core/res/res/drawable/divider_vertical_bright_opaque.9.png
new file mode 100644
index 0000000..5c537ee
--- /dev/null
+++ b/core/res/res/drawable/divider_vertical_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_dark.9.png b/core/res/res/drawable/divider_vertical_dark.9.png
new file mode 100644
index 0000000..548d0bd
--- /dev/null
+++ b/core/res/res/drawable/divider_vertical_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_dark_opaque.9.png b/core/res/res/drawable/divider_vertical_dark_opaque.9.png
new file mode 100644
index 0000000..8f35315
--- /dev/null
+++ b/core/res/res/drawable/divider_vertical_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_dark.xml b/core/res/res/drawable/fasttrack_badge_dark.xml
new file mode 100644
index 0000000..c60d403
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_dark.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="false"
+ android:state_selected="false"
+ android:state_pressed="false"
+ android:drawable="@drawable/fasttrack_badge_dark_normal" />
+
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/fasttrack_badge_dark_pressed" />
+
+</selector>
diff --git a/core/res/res/drawable/fasttrack_badge_dark_normal.9.png b/core/res/res/drawable/fasttrack_badge_dark_normal.9.png
new file mode 100644
index 0000000..52bb08c
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_dark_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png b/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png
new file mode 100644
index 0000000..84a6783
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_light.xml b/core/res/res/drawable/fasttrack_badge_light.xml
new file mode 100644
index 0000000..fd81258
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_light.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="false"
+ android:state_selected="false"
+ android:state_pressed="false"
+ android:drawable="@drawable/fasttrack_badge_light_normal" />
+
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/fasttrack_badge_light_pressed" />
+
+</selector>
diff --git a/core/res/res/drawable/fasttrack_badge_light_normal.9.png b/core/res/res/drawable/fasttrack_badge_light_normal.9.png
new file mode 100644
index 0000000..595b179
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_light_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_light_pressed.9.png b/core/res/res/drawable/fasttrack_badge_light_pressed.9.png
new file mode 100644
index 0000000..8e3f557
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_light_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_middle.xml b/core/res/res/drawable/fasttrack_badge_middle.xml
new file mode 100644
index 0000000..6df230a
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_middle.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_focused="false"
+ android:state_selected="false"
+ android:state_pressed="false"
+ android:drawable="@drawable/fasttrack_badge_middle_normal" />
+
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/fasttrack_badge_middle_pressed" />
+
+</selector> \ No newline at end of file
diff --git a/core/res/res/drawable/fasttrack_badge_middle_normal.9.png b/core/res/res/drawable/fasttrack_badge_middle_normal.9.png
new file mode 100644
index 0000000..07df063
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_middle_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_middle_pressed.9.png b/core/res/res/drawable/fasttrack_badge_middle_pressed.9.png
new file mode 100644
index 0000000..ded95f6
--- /dev/null
+++ b/core/res/res/drawable/fasttrack_badge_middle_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/ic_contact_picture_2.png b/core/res/res/drawable/ic_contact_picture_2.png
new file mode 100644
index 0000000..8b184af
--- /dev/null
+++ b/core/res/res/drawable/ic_contact_picture_2.png
Binary files differ
diff --git a/core/res/res/drawable/ic_contact_picture_3.png b/core/res/res/drawable/ic_contact_picture_3.png
new file mode 100644
index 0000000..a2d08b5
--- /dev/null
+++ b/core/res/res/drawable/ic_contact_picture_3.png
Binary files differ
diff --git a/core/res/res/drawable/light_header.9.png b/core/res/res/drawable/light_header.9.png
deleted file mode 100644
index ad5dce1..0000000
--- a/core/res/res/drawable/light_header.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/light_header_dither.xml b/core/res/res/drawable/light_header_dither.xml
new file mode 100644
index 0000000..c54b6c2
--- /dev/null
+++ b/core/res/res/drawable/light_header_dither.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/light_header"
+ android:dither="true"
+/>
diff --git a/core/res/res/drawable/stat_sys_data_connected_1x.png b/core/res/res/drawable/stat_sys_data_connected_1x.png
new file mode 100644
index 0000000..130724f
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_connected_1xrtt.png b/core/res/res/drawable/stat_sys_data_connected_1xrtt.png
deleted file mode 100644
index c2fbbdf..0000000
--- a/core/res/res/drawable/stat_sys_data_connected_1xrtt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_connected_evdo.png b/core/res/res/drawable/stat_sys_data_connected_evdo.png
deleted file mode 100644
index db9f282..0000000
--- a/core/res/res/drawable/stat_sys_data_connected_evdo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_connected_h.png b/core/res/res/drawable/stat_sys_data_connected_h.png
new file mode 100644
index 0000000..7d5413a
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_connected_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_dormant_1xrtt.png b/core/res/res/drawable/stat_sys_data_dormant_1xrtt.png
deleted file mode 100755
index 11c2eae..0000000
--- a/core/res/res/drawable/stat_sys_data_dormant_1xrtt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_dormant_evdo.png b/core/res/res/drawable/stat_sys_data_dormant_evdo.png
deleted file mode 100755
index 811fcb5..0000000
--- a/core/res/res/drawable/stat_sys_data_dormant_evdo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_1x.png b/core/res/res/drawable/stat_sys_data_in_1x.png
new file mode 100644
index 0000000..3155e632
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_in_1x.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_1xrtt.png b/core/res/res/drawable/stat_sys_data_in_1xrtt.png
deleted file mode 100644
index a421a8a..0000000
--- a/core/res/res/drawable/stat_sys_data_in_1xrtt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_evdo.png b/core/res/res/drawable/stat_sys_data_in_evdo.png
deleted file mode 100644
index 54f55ba..0000000
--- a/core/res/res/drawable/stat_sys_data_in_evdo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_in_h.png b/core/res/res/drawable/stat_sys_data_in_h.png
new file mode 100644
index 0000000..695b80c
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_in_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_1x.png b/core/res/res/drawable/stat_sys_data_inandout_1x.png
new file mode 100644
index 0000000..1017e3b
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png b/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png
deleted file mode 100644
index 1a94cdf..0000000
--- a/core/res/res/drawable/stat_sys_data_inandout_1xrtt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_evdo.png b/core/res/res/drawable/stat_sys_data_inandout_evdo.png
deleted file mode 100644
index 7aa6f00..0000000
--- a/core/res/res/drawable/stat_sys_data_inandout_evdo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_inandout_h.png b/core/res/res/drawable/stat_sys_data_inandout_h.png
new file mode 100644
index 0000000..467acd1
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_1x.png b/core/res/res/drawable/stat_sys_data_out_1x.png
new file mode 100644
index 0000000..5418791
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_out_1x.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_1xrtt.png b/core/res/res/drawable/stat_sys_data_out_1xrtt.png
deleted file mode 100644
index 74fd351..0000000
--- a/core/res/res/drawable/stat_sys_data_out_1xrtt.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_evdo.png b/core/res/res/drawable/stat_sys_data_out_evdo.png
deleted file mode 100644
index 21e19a7..0000000
--- a/core/res/res/drawable/stat_sys_data_out_evdo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_data_out_h.png b/core/res/res/drawable/stat_sys_data_out_h.png
new file mode 100644
index 0000000..da50305
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_data_out_h.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_0_cdma.png b/core/res/res/drawable/stat_sys_signal_0_cdma.png
deleted file mode 100644
index 0ef7d53..0000000
--- a/core/res/res/drawable/stat_sys_signal_0_cdma.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_1_cdma.png b/core/res/res/drawable/stat_sys_signal_1_cdma.png
deleted file mode 100644
index f4839d4..0000000
--- a/core/res/res/drawable/stat_sys_signal_1_cdma.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_2_cdma.png b/core/res/res/drawable/stat_sys_signal_2_cdma.png
deleted file mode 100644
index e25a99c..0000000
--- a/core/res/res/drawable/stat_sys_signal_2_cdma.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_3_cdma.png b/core/res/res/drawable/stat_sys_signal_3_cdma.png
deleted file mode 100644
index d828d99..0000000
--- a/core/res/res/drawable/stat_sys_signal_3_cdma.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_4_cdma.png b/core/res/res/drawable/stat_sys_signal_4_cdma.png
deleted file mode 100644
index 53a31ea..0000000
--- a/core/res/res/drawable/stat_sys_signal_4_cdma.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_cdma_0.png b/core/res/res/drawable/stat_sys_signal_cdma_0.png
deleted file mode 100755
index 0ef7d53..0000000
--- a/core/res/res/drawable/stat_sys_signal_cdma_0.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_cdma_1.png b/core/res/res/drawable/stat_sys_signal_cdma_1.png
deleted file mode 100755
index f4839d4..0000000
--- a/core/res/res/drawable/stat_sys_signal_cdma_1.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_cdma_2.png b/core/res/res/drawable/stat_sys_signal_cdma_2.png
deleted file mode 100755
index e25a99c..0000000
--- a/core/res/res/drawable/stat_sys_signal_cdma_2.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_cdma_3.png b/core/res/res/drawable/stat_sys_signal_cdma_3.png
deleted file mode 100755
index d828d99..0000000
--- a/core/res/res/drawable/stat_sys_signal_cdma_3.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_cdma_4.png b/core/res/res/drawable/stat_sys_signal_cdma_4.png
deleted file mode 100755
index 53a31ea..0000000
--- a/core/res/res/drawable/stat_sys_signal_cdma_4.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_evdo_0.png b/core/res/res/drawable/stat_sys_signal_evdo_0.png
deleted file mode 100755
index 1b8aec7..0000000
--- a/core/res/res/drawable/stat_sys_signal_evdo_0.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_evdo_1.png b/core/res/res/drawable/stat_sys_signal_evdo_1.png
deleted file mode 100755
index 7ce01fd..0000000
--- a/core/res/res/drawable/stat_sys_signal_evdo_1.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_evdo_2.png b/core/res/res/drawable/stat_sys_signal_evdo_2.png
deleted file mode 100755
index 890cd59..0000000
--- a/core/res/res/drawable/stat_sys_signal_evdo_2.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_evdo_3.png b/core/res/res/drawable/stat_sys_signal_evdo_3.png
deleted file mode 100755
index 712c640..0000000
--- a/core/res/res/drawable/stat_sys_signal_evdo_3.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_evdo_4.png b/core/res/res/drawable/stat_sys_signal_evdo_4.png
deleted file mode 100755
index f0537dd..0000000
--- a/core/res/res/drawable/stat_sys_signal_evdo_4.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_focus.9.png b/core/res/res/drawable/tab_focus.9.png
deleted file mode 100755
index 2806da9..0000000
--- a/core/res/res/drawable/tab_focus.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_focus_bar_left.9.png b/core/res/res/drawable/tab_focus_bar_left.9.png
deleted file mode 100755
index 21421cb..0000000
--- a/core/res/res/drawable/tab_focus_bar_left.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_focus_bar_right.9.png b/core/res/res/drawable/tab_focus_bar_right.9.png
deleted file mode 100755
index b6304d9..0000000
--- a/core/res/res/drawable/tab_focus_bar_right.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_press.9.png b/core/res/res/drawable/tab_press.9.png
deleted file mode 100755
index 3fb717c..0000000
--- a/core/res/res/drawable/tab_press.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_press_bar_left.9.png b/core/res/res/drawable/tab_press_bar_left.9.png
deleted file mode 100755
index 95ef2d3..0000000
--- a/core/res/res/drawable/tab_press_bar_left.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_press_bar_right.9.png b/core/res/res/drawable/tab_press_bar_right.9.png
deleted file mode 100755
index 7ae938b5..0000000
--- a/core/res/res/drawable/tab_press_bar_right.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_selected.9.png b/core/res/res/drawable/tab_selected.9.png
deleted file mode 100644
index f929d99..0000000
--- a/core/res/res/drawable/tab_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_selected_bar_left.9.png b/core/res/res/drawable/tab_selected_bar_left.9.png
deleted file mode 100755
index 58e2d35..0000000
--- a/core/res/res/drawable/tab_selected_bar_left.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_selected_bar_right.9.png b/core/res/res/drawable/tab_selected_bar_right.9.png
deleted file mode 100755
index 0c9c8dd..0000000
--- a/core/res/res/drawable/tab_selected_bar_right.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/tab_unselected.9.png b/core/res/res/drawable/tab_unselected.9.png
deleted file mode 100644
index 9036c1d..0000000
--- a/core/res/res/drawable/tab_unselected.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/layout-ja/contact_header_name.xml b/core/res/res/layout-ja/contact_header_name.xml
new file mode 100644
index 0000000..9dceeb6
--- /dev/null
+++ b/core/res/res/layout-ja/contact_header_name.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- In Japanese-language locales, the "Name" field contains two separate
+ TextViews: the name itself, and also the phonetic ("furigana") field. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content">
+
+ <TextView android:id="@+id/name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ />
+
+ <TextView android:id="@+id/phonetic_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+
+</LinearLayout>
diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml
new file mode 100644
index 0000000..ba91e00
--- /dev/null
+++ b/core/res/res/layout/contact_header.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/banner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:background="@drawable/title_bar_tall"
+ android:paddingRight="5dip"
+ android:gravity="center_vertical">
+
+ <ImageView android:id="@+id/photo"
+ android:layout_width="48dip"
+ android:layout_height="52dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginLeft="10dip"
+ android:scaleType="fitCenter"
+ android:background="@drawable/fasttrack_badge_middle"/>
+
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginTop="5dip"
+ android:orientation="vertical">
+
+ <!-- "Name" field is locale-specific. -->
+ <include layout="@layout/contact_header_name"/>
+
+ <TextView android:id="@+id/status"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:maxLines="2"
+ android:ellipsize="end"/>
+
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/presence"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="3dip"
+ android:paddingRight="6dip"/>
+
+ <CheckBox
+ android:id="@+id/star"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ style="?android:attr/starStyle" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/contact_header_name.xml b/core/res/res/layout/contact_header_name.xml
new file mode 100644
index 0000000..9a56fb4
--- /dev/null
+++ b/core/res/res/layout/contact_header_name.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- In the default locale, the "Name" field is a single TextView -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/name"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ android:singleLine="true"
+ android:ellipsize="end"
+ />
diff --git a/core/res/res/layout/grant_credentials_permission.xml b/core/res/res/layout/grant_credentials_permission.xml
new file mode 100644
index 0000000..fe1c22e
--- /dev/null
+++ b/core/res/res/layout/grant_credentials_permission.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/message" />
+ <Button android:id="@+id/allow"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/allow" />
+
+ <Button android:id="@+id/deny"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/deny" />
+
+ <ListView android:id="@+id/packages_list"
+ android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+
+</LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_glogin_unlock.xml b/core/res/res/layout/keyguard_screen_glogin_unlock.xml
index 74ff3b0..6e00d11 100644
--- a/core/res/res/layout/keyguard_screen_glogin_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_glogin_unlock.xml
@@ -42,7 +42,6 @@
android:gravity="center_vertical"
android:drawableLeft="@drawable/ic_lock_idle_lock"
android:drawablePadding="5dip"
- android:text="@android:string/lockscreen_glogin_too_many_attempts"
/>
<!-- spacer below header -->
diff --git a/core/res/res/layout/preference_dialog.xml b/core/res/res/layout/preference_dialog.xml
new file mode 100644
index 0000000..5cf0f6e
--- /dev/null
+++ b/core/res/res/layout/preference_dialog.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Layout used by DialogPreference widgets. This is inflated inside
+ android.R.layout.preference. -->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="4dip"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/btn_circle"
+ android:src="@drawable/ic_btn_round_more" />
+
diff --git a/core/res/res/layout/tab_indicator.xml b/core/res/res/layout/tab_indicator.xml
index fcf0b5e..e3ea555 100644
--- a/core/res/res/layout/tab_indicator.xml
+++ b/core/res/res/layout/tab_indicator.xml
@@ -18,6 +18,8 @@
android:layout_width="0dip"
android:layout_height="64dip"
android:layout_weight="1"
+ android:layout_marginLeft="-4px"
+ android:layout_marginRight="-4px"
android:orientation="vertical"
android:background="@android:drawable/tab_indicator">
diff --git a/core/res/res/layout/zoom_browser_accessory_buttons.xml b/core/res/res/layout/zoom_browser_accessory_buttons.xml
index 69afca9..4bf2bdf 100644
--- a/core/res/res/layout/zoom_browser_accessory_buttons.xml
+++ b/core/res/res/layout/zoom_browser_accessory_buttons.xml
@@ -18,11 +18,18 @@
*/
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <ImageView android:id="@+id/zoom_page_overview"
- android:background="@android:drawable/btn_browser_zoom_page_overview"
+ <ImageView android:id="@+id/zoom_fit_page"
+ android:background="@android:drawable/btn_browser_zoom_fit_page"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left"
android:layout_marginLeft="7dip"
/>
+ <ImageView android:id="@+id/zoom_page_overview"
+ android:background="@android:drawable/btn_browser_zoom_page_overview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|right"
+ android:layout_marginRight="7dip"
+ />
</merge>
diff --git a/core/res/res/raw/loaderror.html b/core/res/res/raw/loaderror.html
index 359a1e7..fd3d766 100644
--- a/core/res/res/raw/loaderror.html
+++ b/core/res/res/raw/loaderror.html
@@ -1,5 +1,6 @@
<html>
<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<title>Web page not available</title>
<style type="text/css">
body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw/nodomain.html b/core/res/res/raw/nodomain.html
index 7a107fb..a71dbcd 100644
--- a/core/res/res/raw/nodomain.html
+++ b/core/res/res/raw/nodomain.html
@@ -1,5 +1,6 @@
<html>
<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<title>Web page not available</title>
<style type="text/css">
body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8c6704e..0d6137b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -15,695 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"kB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"&lt;bez názvu&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(žádné telefonní Äíslo)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Neznámé)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Hlasová schránka"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problém s připojením nebo neplatný kód MMI."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Služba byla zapnuta."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Služba byla zapnuta pro:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Služba byla vypnuta."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registrace byla úspěšná."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Smazaní proběhlo úspěšně."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Nesprávné heslo."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"Funkce MMI byla dokonÄena."</string>
- <string name="badPin" msgid="5085454289896032547">"Původní kód PIN byl zadán nesprávně."</string>
- <string name="badPuk" msgid="5702522162746042460">"Kód PUK byl zadán nesprávně."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Zadané kódy PIN se neshodují."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Zadejte kód PIN o délce 4-8 Äíslic."</string>
- <string name="needPuk" msgid="919668385956251611">"Karta SIM je blokována pomocí kódu PUK. Odblokujete ji zadáním kódu PUK."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Chcete-li odblokovat kartu SIM, zadejte kód PUK2."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Příchozí identifikace volajícího"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Odchozí identifikace volajícího"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Přesměrování hovorů"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Další hovor na lince"</string>
- <string name="BaMmi" msgid="455193067926770581">"Blokování hovorů"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Změna hesla"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Změna kódu PIN"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Volané Äíslo uvedeno"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Volání Äísla omezeno"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Konference tří úÄastníků"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Odmítnutí nevyžádaných obtěžujících hovorů"</string>
- <string name="CndMmi" msgid="3116446237081575808">"DoruÄení volaného Äísla"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Nerušit"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Ve výchozím nastavení je identifikace volajícího omezena. Příští hovor: Omezeno"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Ve výchozím nastavení je identifikace volajícího omezena. Příští hovor: Neomezeno"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Omezeno"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Neomezeno"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Služba není zřízena."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Nelze změnit nastavení identifikace volajícího."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Omezený přístup byl změněn."</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Datová služba je zablokována."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Tísňová linka je zablokována."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Hlasová služba a služba SMS jsou zablokovány."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Veškeré hlasové služby a služby SMS jsou zablokovány."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Hlas"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Data"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Async"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synchronizace"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pakety"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Indikátor roamingu svítí"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Indikátor roamingu nesvítí"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Indikátor roamingu bliká"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Není v blízkosti"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Mimo budovu"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming – preferovaný systém"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming – dostupný systém"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming – alianÄní partner"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming – prémiový partner"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming – úplná funkÄnost služby"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming – ÄásteÄná funkÄnost služby"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Banner roamingu je zapnutý"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Banner roamingu je vypnutý"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Vyhledávání služby"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sek."</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Požadavek zadaný pomocí kódu funkce byl úspěšnÄ› dokonÄen."</string>
- <string name="fcError" msgid="3327560126588500777">"Problém s připojením nebo neplatný kód funkce."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Webová stránka obsahuje chybu."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Adresu URL nelze najít."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Schéma ověření webu není podporováno."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Ověření nebylo úspěšné."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Ověření pomocí serveru proxy bylo neúspěšné."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Připojení k serveru bylo neúspěšné."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Komunikace se serverem se nezdařila. Opakujte akci později."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Spojení se serverem vypršelo."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Stránka obsahuje příliš mnoho přesměrování serveru."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokol není podporován."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Nelze navázat zabezpeÄené spojení."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Stránku nelze otevřít, protože adresa URL je neplatná."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"K souboru nelze získat přístup."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Požadovaný soubor nebyl nalezen."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Je zpracováváno příliš mnoho požadavků. Opakujte akci později."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synchronizace"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizace"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Příliš mnoho smazaných položek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Paměť telefonu je plná. Smažte některé soubory a uvolněte místo."</string>
- <string name="me" msgid="6545696007631404292">"Já"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Možnosti telefonu"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Tichý režim"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Zapnout bezdrátové připojení"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Vypnout bezdrátové připojení"</string>
- <string name="screen_lock" msgid="799094655496098153">"Zámek obrazovky"</string>
- <string name="power_off" msgid="4266614107412865048">"Vypnout"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Vypínání..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Váš telefon bude vypnut."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Žádné nedávno použité aplikace."</string>
- <string name="global_actions" msgid="2406416831541615258">"Možnosti telefonu"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Zámek obrazovky"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Vypnout"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tichý režim"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je VYPNUTÃ."</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvuk je zapnutý"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V letadle"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V letadle je ZAPNUTÃ"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V letadle je VYPNUTÃ"</string>
- <string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Zpoplatněné služby"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Umožňuje aplikacím provádÄ›t Äinnosti, které vás mohou stát peníze."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše zprávy"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Čtení a zápis zpráv SMS, e-mailů a dalších zpráv."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Vaše osobní informace"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Přímý přístup k vašim kontaktům a kalendáři v telefonu."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Vaše poloha"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Sleduje vaši fyzickou polohu"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Síťová komunikace"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Umožňuje aplikacím získat přístup k různým funkcím sítě."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"VaÅ¡e úÄty Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Přístup k dostupným úÄtům Google."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Řízení hardwaru"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Přímý přístup k hardwaru telefonu."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefonní hovory"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Sledování, záznam a zpracování telefonních hovorů."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Systémové nástroje"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Nízkoúrovňový přístup a kontrola nad systémem."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Nástroje pro vývojáře"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funkce pouze pro vývojáře aplikací"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Úložiště"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Přístup ke kartě SD."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"zakázání Äi zmÄ›ny stavového řádku"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Umožňuje aplikaci zakázat stavový řádek nebo pÅ™idat Äi odebrat systémové ikony."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"rozbalení a sbalení stavového řádku"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Umožňuje aplikaci rozbalit Äi sbalit stavový řádek."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"zachycení odchozích hovorů"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Umožňuje aplikaci zpracovat odchozí hovory a zmÄ›nit Äíslo, které má být vytoÄeno. Å kodlivé aplikace mohou sledovat Äi pÅ™esmÄ›rovat odchozí hovory nebo jim zabránit."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"příjem zpráv SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Umožňuje aplikaci přijímat a zpracovávat zprávy SMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"příjem zpráv MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Umožňuje aplikaci přijímat a zpracovávat zprávy MMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"odesílaní zpráv SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Umožňuje aplikaci odesílat zprávy SMS. Škodlivé aplikace mohou bez vašeho potvrzení odesílat zpoplatněné zprávy."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"Ätení zpráv SMS a MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Umožňuje aplikaci Äíst zprávy SMS uložené ve vaÅ¡em telefonu nebo na kartÄ› SIM. Å kodlivé aplikace mohou naÄíst vaÅ¡e soukromé zprávy."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"úprava zpráv SMS a MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Umožňuje aplikaci zapisovat do zpráv SMS uložených ve vašem telefonu nebo na kartě SIM. Škodlivé aplikace mohou smazat vaše zprávy."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"příjem WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Umožňuje aplikaci přijímat a zpracovávat zprávy WAP. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"naÄtení spuÅ¡tÄ›ných aplikací"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Umožňuje aplikaci naÄíst informace o aktuálnÄ› a nedávno spuÅ¡tÄ›ných úlohách. Toto nastavení může Å¡kodlivým aplikacím umožnit odhalení soukromých informací o jiných aplikacích."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"změna uspořádání spuštěných aplikací"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Umožňuje aplikaci pÅ™esouvat úlohy do popÅ™edí Äi pozadí. Å kodlivé aplikace mohou vynutit své pÅ™esunutí do popÅ™edí bez vaÅ¡eho pÅ™iÄinÄ›ní."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"povolit ladění aplikací"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Umožňuje aplikaci povolit ladÄ›ní jiné aplikace. Å kodlivé aplikace mohou pomocí tohoto nastavení ukonÄit jiné aplikace."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"změna vašeho nastavení uživatelského rozhraní"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Umožňuje aplikaci zmÄ›nit aktuální konfiguraci, napÅ™. národní prostÅ™edí Äi obecnou velikost písma."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"restartování ostatních aplikací"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Umožňuje aplikaci vynutit restartování jiných aplikací."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"vynucení zavření aplikace"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Umožňuje aplikaci vynutit zavÅ™ení a pÅ™esunutí libovolné Äinnosti v popÅ™edí na pozadí. Běžné aplikace by toto nastavení nemÄ›ly nikdy využívat."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"naÄtení interního stavu systému"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Umožňuje aplikaci naÄíst interní stav systému. Å kodlivé aplikace mohou naÄíst řádu soukromých a zabezpeÄených informací, které by nikdy nemÄ›ly potÅ™ebovat."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"ÄásteÄné vypnutí"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Uvede správce Äinností do vypnutého stavu. Nedojde vÅ¡ak k úplnému vypnutí."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zabránění přepínání aplikací"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Zabrání uživateli přepnout na jinou aplikaci."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"sledování a řízení spouštění všech aplikací"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Umožňuje aplikaci sledovat a řídit spouÅ¡tÄ›ní Äinností systémem. Å kodlivé aplikace mohou zcela ovládnout systém. Toto oprávnÄ›ní je zapotÅ™ebí pouze pro úÄely vývoje, nikdy pro běžné použití telefonu."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"odeslání vysílání o odstranÄ›ní balíÄku"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Umožňuje aplikaci vysílat oznámení o odstranÄ›ní balíÄku aplikace. Å kodlivé aplikace mohou pomocí tohoto nastavení ukonÄit libovolnou další spuÅ¡tÄ›nou aplikaci."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"odeslání vysílání o přijaté zprávě SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy SMS. Škodlivé aplikace mohou pomocí tohoto nastavení falšovat příchozí zprávy SMS."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"odeslání vysílání typu WAP-PUSH-received"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Umožňuje aplikaci vysílat oznámení o pÅ™ijetí zprávy WAP PUSH. Å kodlivé aplikace mohou pomocí tohoto nastavení zfalÅ¡ovat výpis o doruÄení zprávy MMS nebo nepozorovanÄ› nahradit obsah jakékoli webové stránky Å¡kodlivým obsahem."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"omezení poÄtu spuÅ¡tÄ›ných procesů"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Umožňuje aplikaci řídit maximální poÄet spuÅ¡tÄ›ných procesů. Běžné aplikace toto nastavení nikdy nevyužívají."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"zavření všech aplikací na pozadí"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Umožňuje aplikaci ovládat, zda jsou Äinnosti vždy dokonÄeny po pÅ™esunutí do pozadí. Běžné aplikace toto nastavení nikdy nevyužívají."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"změna statistických údajů o baterii"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Umožňuje zmÄ›nu shromáždÄ›ných statistických údajů o baterii. Není urÄeno pro běžné aplikace."</string>
- <string name="permlab_backup" msgid="470013022865453920">"ovládání zálohování a obnovy systému"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Umožňuje aplikaci ovládat mechanizmus zálohování a obnovy systému. Není urÄeno k použití v běžných aplikacích."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobrazení nepovolených oken"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Umožňuje vytvoření oken, která mají být použita interním systémem uživatelského rozhraní. Běžné aplikace toto nastavení nepoužívají."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"zobrazení upozornění systémové úrovně"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Umožňuje aplikaci zobrazit okna s výstrahami systému. Škodlivé aplikace mohou převzít kontrolu nad celou obrazovkou telefonu."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"změna globální rychlosti animace"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Umožňuje aplikaci kdykoli globálnÄ› zmÄ›nit rychlost animace (rychlejší Äi pomalejší animace)."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"správa tokenů aplikací"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Umožňuje aplikaci vytvořit a spravovat své vlastní tokeny a obejít jejich obvyklé řazení typu Z. Toto nastavení by nikdy nemělo být potřeba pro běžné aplikace."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"používání kláves a tlaÄítek"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Umožňuje aplikaci doruÄit své vlastní vstupní události (stisknutí tlaÄítek, apod.) dalším aplikacím. Å kodlivé aplikace mohou pomocí tohoto nastavení pÅ™evzít kontrolu nad telefonem."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"zaznamenání psaného textu a provádÄ›ných Äinností"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Umožňuje aplikacím sledovat, které klávesy používáte, a to i při práci s jinými aplikacemi (například při zadávání hesla). Běžné aplikace by toto nastavení nikdy neměly vyžadovat."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vazba k metodě zadávání dat"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Umožňuje držiteli vázat se na nejvyšší úroveň rozhraní pro zadávání dat. Běžné aplikace by toto nastavení nikdy neměly využívat."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"změna orientace obrazovky"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Umožňuje aplikaci kdykoli změnit orientaci obrazovky. Běžné aplikace by toto nastavení nikdy neměly využívat."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"odeslání signálů Linux aplikacím"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Umožňuje aplikaci vyžádat zaslání poskytnutého signálu všem trvalým procesům."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"trvalé spuštění aplikace"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Umožňuje aplikaci uÄinit své Äásti trvalými, takže je systém nemůže použít pro jiné aplikace."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"smazání aplikací"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Umožňuje aplikaci smazat balíÄky systému Android. Å kodlivé aplikace mohou pomocí tohoto nastavení smazat důležité aplikace."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"smazání dat ostatních aplikací"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Umožňuje aplikaci smazat data uživatele."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"smazání mezipaměti ostatních aplikací"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Umožňuje aplikaci smazat soubory v mezipaměti."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"výpoÄet místa pro ukládání aplikací"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Umožňuje aplikaci naÄtení svého kódu, dat a velikostí mezipamÄ›ti"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"přímá instalace aplikací"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Umožňuje aplikaci nainstalovat nové Äi aktualizované balíÄky systému Android. Å kodlivé aplikace mohou pomocí tohoto nastavení pÅ™idat nové aplikace s libovolnými oprávnÄ›ními."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"smazání všech dat v mezipaměti aplikace"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Umožňuje aplikaci uvolnit paměť telefonu smazáním souborů v adresáři mezipaměti aplikace. Přístup je velmi omezený, většinou pouze pro systémové procesy."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"Ätení systémových souborů protokolu"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Umožňuje aplikaci Äíst různé systémové soubory protokolů. Toto nastavení aplikaci umožní získat obecné informace o Äinnostech s telefonem, ale nemÄ›ly by obsahovat žádné osobní Äi soukromé informace."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"Ätení nebo zápis do prostÅ™edků funkce diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Umožňuje aplikaci Äíst libovolné prostÅ™edky ve skupinÄ› diag, napÅ™. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnÄ›ní stability a bezpeÄnosti systému. Toto nastavení by mÄ›l používat pouze výrobce Äi operátor pro diagnostiku hardwaru."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"povolení Äi zakázání komponent aplikací"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Umožňuje aplikaci zmÄ›nit, zda je komponenta jiné aplikace povolena nebo ne. Å kodlivé aplikace mohou pomocí tohoto nastavení vypnout důležité funkce telefonu. Je tÅ™eba postupovat opatrnÄ›, protože je možné způsobit nepoužitelnost, nekonzistenci Äi nestabilitu komponent aplikací."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"nastavení upřednostňovaných aplikací"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Umožňuje aplikaci zmÄ›nit vaÅ¡e upÅ™ednostňované aplikace. Toto nastavení může Å¡kodlivým aplikacím umožnit nepozorovanÄ› zmÄ›nit spouÅ¡tÄ›né aplikace a oklamat vaÅ¡e existující aplikace tak, aby shromažÄovaly vaÅ¡e soukromá data."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"změna globálních nastavení systému"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Umožňuje aplikaci upravit data nastavení systému. Škodlivé aplikace mohou poškodit konfiguraci vašeho systému."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"zmÄ›ny zabezpeÄených nastavení systému"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Umožňuje aplikaci zmÄ›nit data zabezpeÄených nastavení systému. Běžné aplikace toto nastavení nevyužívají."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"změna mapy služeb Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Umožňuje aplikaci změnit mapu služeb Google. Běžné aplikace toto nastavení nevyužívají."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"automatické spuštění při startu"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Umožňuje aplikaci spuštění ihned po spuštění systému. Toto nastavení může zpomalit spuštění telefonu a umožnit aplikaci celkově zpomalit telefon, protože bude neustále spuštěna."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"odeslání trvalého vysílání"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Umožňuje aplikaci odeslat trvalá vysílání, která pÅ™etrvávají i po skonÄení vysílání. Å kodlivé aplikace mohou telefon zpomalit Äi způsobit jeho nestabilitu, protože bude používat příliÅ¡ mnoho pamÄ›ti."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"Ätení dat kontaktů"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Umožňuje aplikaci naÄíst vÅ¡echna data kontaktů (adresy) uložená ve vaÅ¡em telefonu. Å kodlivé aplikace poté mohou dalším lidem odeslat vaÅ¡e data."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"zápis dat kontaktů"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Umožňuje aplikaci zmÄ›nit kontaktní údaje (adresu) uložené v telefonu. Å kodlivé aplikace mohou pomocí tohoto nastavení vymazat Äi pozmÄ›nit kontaktní údaje."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"zápis informací o vlastníkovi"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Umožňuje aplikaci zmÄ›nit informace o vlastníkovi telefonu uložené v telefonu. Å kodlivé aplikace mohou pomocí tohoto nastavení vymazat Äi pozmÄ›nit informace o vlastníkovi."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"Ätení informací o vlastníkovi"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Umožňuje aplikaci Äíst informace o vlastníkovi telefonu uložená v telefonu. Å kodlivé aplikace mohou pomocí tohoto nastavení naÄíst informace o vlastníkovi."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"Ätení dat kalendáře"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Umožňuje aplikaci naÄíst vÅ¡echny události kalendáře uložené ve vaÅ¡em telefonu. Å kodlivé aplikace poté mohou dalším lidem odeslat události z vaÅ¡eho kalendáře."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"zápis dat kalendáře"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Umožňuje aplikaci zmÄ›nit události kalendáře uložené v telefonu. Å kodlivé aplikace mohou pomocí tohoto nastavení vymazat Äi pozmÄ›nit vaÅ¡e data v kalendáři."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"simulace zdrojů polohy pro úÄely testování"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Vytváří simulované zdroje polohy pro úÄely testování. Å kodlivé aplikace mohou pomocí tohoto nastavení zmÄ›nit polohu Äi stav vrácený zdroji skuteÄné polohy, jako je napÅ™. jednotka GPS Äi poskytovatelé sítÄ›."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"přístup k dalším příkazům poskytovatele polohy"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Umožňuje získat přístup k dalším příkazům poskytovatele polohy. Å kodlivé aplikace mohou pomocí tohoto nastavení naruÅ¡it funkci GPS Äi jiných zdrojů polohy."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"oprávnění k instalaci poskytovatele polohy"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"VytvoÅ™it simulace zdrojů polohy pro úÄely testování. Å kodlivé aplikace mohou toto nastavení využít k pÅ™epsání polohy nebo stavu vráceného zdroji skuteÄné polohy, například systémem GPS nebo poskytovateli sítí. Mohou také monitorovat polohu a ohlásit ji externímu zdroji."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"upřesnění polohy (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Umožňuje aplikaci přístup ke zdrojům přesné polohy v telefonu, jako je například systém GPS, je-li k dispozici. Škodlivé aplikace mohou pomocí tohoto nastavení zjistit vaši polohu a mohou zvýšit spotřebu baterie."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"přibližná poloha (pomocí sítě)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Umožňuje získat přístup ke zdrojům pÅ™ibližné polohy, jako je například databáze mobilní sítÄ›, je-li k dispozici, a urÄit pÅ™ibližnou pozici telefonu. Å kodlivé aplikace takto mohou zjistit, kde se pÅ™ibližnÄ› nacházíte."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"přístup ke službě SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Umožňuje aplikaci používat nízkoúrovňové funkce SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Ätení vyrovnávací pamÄ›ti snímků"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Umožňuje aplikaci naÄíst obsah vyrovnávací pamÄ›ti snímků."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"změna vašeho nastavení zvuku"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Umožňuje aplikaci zmÄ›nit globální nastavení zvuku, například hlasitost Äi smÄ›rování."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"nahrání zvuku"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Umožňuje aplikaci získat přístup k nahrávání zvuku."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"pořizování fotografií"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Umožňuje aplikaci poÅ™izovat fotografie pomocí fotoaparátu. Toto nastavení aplikaci umožní shromažÄovat fotografie toho, na co je zrovna fotoaparát namířen."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"trvalé vypnutí telefonu"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Umožňuje aplikaci trvale vypnout celý telefon. Toto je velmi nebezpeÄné nastavení."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"vynucení restartování telefonu"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Umožňuje aplikaci vynutit restartování telefonu."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"připojení a odpojení souborových systémů"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Umožňuje aplikaci pÅ™ipojit Äi odpojit souborové systémy ve vymÄ›nitelných úložiÅ¡tích."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formátovat externí úložiště"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Umožňuje aplikaci formátovat vyměnitelná úložiště."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"ovládání vibrací"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Umožňuje aplikaci ovládat vibrace."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ovládání kontrolky"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Umožňuje aplikaci ovládat kontrolku."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"testování hardwaru"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Umožňuje aplikaci ovládat různé periferie pro úÄely testování hardwaru."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"přímé volání na telefonní Äísla"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Umožňuje aplikaci bez vaÅ¡eho zásahu volat na telefonní Äísla. Å kodlivé aplikace mohou na váš telefonní úÄet pÅ™ipsat neoÄekávané hovory. Toto nastavení aplikaci neumožňuje volat na tísňové linky."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"přímé volání na libovolná telefonní Äísla"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Umožňuje aplikaci bez vaÅ¡eho zásahu vytoÄit jakékoli telefonní Äíslo, vÄetnÄ› Äísel tísňového volání. Å kodlivé aplikace mohou provádÄ›t zbyteÄná a nezákonná volání na tísňové linky."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"ovládání oznámení o aktualizaci polohy"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Umožňuje povolit Äi zakázat aktualizace polohy prostÅ™ednictvím bezdrátového pÅ™ipojení. Aplikace toto nastavení obvykle nepoužívají."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"přístup k vlastnostem Checkin"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Umožňuje Ätení i zápis vlastností nahraných službou Checkin. Běžné aplikace toto nastavení obvykle nevyužívají."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"zvolit widgety"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Umožňuje aplikaci sdÄ›lit systému, které aplikace mohou používat které widgety. Aplikace s tímto oprávnÄ›ním mohou zpřístupnit osobní údaje jiným aplikacím. Není urÄeno pro běžné aplikace."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"změna stavu telefonu"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Umožňuje aplikaci ovládat telefonní funkce zařízení. Aplikace s tímto oprávnÄ›ním může pÅ™epínat sítÄ› nebo zapnout Äi vypnout bezdrátové pÅ™ipojení telefonu bez vaÅ¡eho svolení."</string>
- <string name="permlab_readPhoneState" msgid="2326172951448691631">"Ätení stavu a identity telefonu"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"Umožňuje aplikaci získat přístup k telefonním funkcím zařízení. Aplikace s tímto oprávnÄ›ním mohou urÄit telefonní a sériové Äíslo tohoto telefonu, zda zrovna probíhá hovor, volané telefonní Äíslo a podobnÄ›."</string>
- <string name="permlab_wakeLock" msgid="573480187941496130">"zabránění přechodu telefonu do režimu spánku"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Umožňuje aplikaci zabránit přechodu telefonu do režimu spánku."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"zapnutí Äi vypnutí telefonu"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Umožňuje aplikaci zapnout Äi vypnout telefon."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"spuštění v režimu továrního testu"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Umožňuje aplikaci spuštění v režimu nízkoúrovňového testu výrobce a povolí přístup k hardwaru telefonu. K dispozici pouze, je-li telefon spuštěn v režimu testování výrobce."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"nastavení tapety"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Umožňuje aplikaci nastavit tapetu systému."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"nastavení nápovědy pro velikost tapety"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Umožňuje aplikaci nastavit nápovědu pro velikost tapety systému."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"obnovení továrního nastavení systému"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Umožňuje aplikaci kompletně obnovit systém do továrního nastavení a vymazat všechna data, konfiguraci a nainstalované aplikace."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"nastavení Äasového pásma"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Umožňuje aplikaci zmÄ›nit Äasové pásmo telefonu."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"odhalení známých úÄtů"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Umožňuje aplikaci získat seznam úÄtů v telefonu."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"zobrazení stavu sítě"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Umožňuje aplikaci zobrazit stav všech sítí."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"plný přístup k Internetu"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Umožňuje aplikaci vytvořit síťové sokety."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"zápis nastavení názvu přístupového bodu (APN)"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Umožňuje aplikaci zmÄ›nit nastavení APN, jako je například proxy Äi port APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"změna připojení k síti"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Umožňuje aplikaci změnit stav připojení k síti."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"změnit nastavení použití dat na pozadí"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Umožňuje aplikaci změnit nastavení použití dat na pozadí."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"zobrazení stavu WiFi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Umožňuje aplikaci zobrazit informace o stavu připojení WiFi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"změna stavu WiFi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Umožňuje aplikaci pÅ™ipojit se k přístupovým bodům WiFi Äi se od nich odpojit a provádÄ›t zmÄ›ny nakonfigurovaných sítí WiFi."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"povolení příjmu Wi-Fi Multicast"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Povoluje aplikaci přijímat pakety, které nebyly adresovány přímo vašemu zařízení. Pomocí této možnosti můžete objevit služby nabízené ve vaší blízkosti. Spotřeba energie je vyšší než u režimu bez vícesměrového vysílání (multicast)."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"správa rozhraní Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Umožňuje aplikaci konfigurovat místní telefon s rozhraním Bluetooth a vyhledávat a párovat vzdálená zařízení."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"vytvoření připojení Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Umožňuje aplikaci zobrazit konfiguraci místního telefonu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"vypnutí zámku kláves"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Umožňuje aplikaci vypnout zámek kláves a související zabezpeÄení heslem. Příkladem oprávnÄ›ného použití této funkce je vypnutí zámku klávesnice pÅ™i příchozím hovoru a jeho opÄ›tovné zapnutí po skonÄení hovoru."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Ätení nastavení synchronizace"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Umožňuje aplikaci naÄíst nastavení synchronizace, napÅ™. zda má být povolena synchronizace kontaktů."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"zápis nastavení synchronizace"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Umožňuje aplikaci změnit nastavení synchronizace, např. zda má být povolena synchronizace kontaktů."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"Ätení statistických údajů o synchronizaci"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Umožňuje aplikaci Äíst statistické informace o synchronizaci, napÅ™. historii probÄ›hlých synchronizací."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"Ätení zdrojů pÅ™ihlášených k odbÄ›ru"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Umožňuje aplikaci získat podrobnosti o aktuálně synchronizovaných zdrojích."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"zápis odebíraných zdrojů"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Umožňuje aplikaci upravit vaše aktuálně synchronizované zdroje. To může škodlivým aplikacím umožnit změnu vašich synchronizovaných zdrojů."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"Älení slovníku definovaného uživatelem"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Umožní aplikaci Äíst soukromá slova, jména a fráze, která uživatel mohl uložit do svého slovníku."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"zápis do slovníku definovaného uživatelem"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Umožní aplikaci zapisovat nová slova do uživatelského slovníku."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"změna/smazání obsah karty SD"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Umožní aplikaci zápis na kartu SD."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"kB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"&lt;bez názvu&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(žádné telefonní Äíslo)"</string>
+ <string name="unknownName">"(Neznámé)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Hlasová schránka"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problém s připojením nebo neplatný kód MMI."</string>
+ <string name="serviceEnabled">"Služba byla zapnuta."</string>
+ <string name="serviceEnabledFor">"Služba byla zapnuta pro:"</string>
+ <string name="serviceDisabled">"Služba byla vypnuta."</string>
+ <string name="serviceRegistered">"Registrace byla úspěšná."</string>
+ <string name="serviceErased">"Smazaní proběhlo úspěšně."</string>
+ <string name="passwordIncorrect">"Nesprávné heslo."</string>
+ <string name="mmiComplete">"Funkce MMI byla dokonÄena."</string>
+ <string name="badPin">"Původní kód PIN byl zadán nesprávně."</string>
+ <string name="badPuk">"Kód PUK byl zadán nesprávně."</string>
+ <string name="mismatchPin">"Zadané kódy PIN se neshodují."</string>
+ <string name="invalidPin">"Zadejte kód PIN o délce 4-8 Äíslic."</string>
+ <string name="needPuk">"Karta SIM je blokována pomocí kódu PUK. Odblokujete ji zadáním kódu PUK."</string>
+ <string name="needPuk2">"Chcete-li odblokovat kartu SIM, zadejte kód PUK2."</string>
+ <string name="ClipMmi">"Příchozí identifikace volajícího"</string>
+ <string name="ClirMmi">"Odchozí identifikace volajícího"</string>
+ <string name="CfMmi">"Přesměrování hovorů"</string>
+ <string name="CwMmi">"Další hovor na lince"</string>
+ <string name="BaMmi">"Blokování hovorů"</string>
+ <string name="PwdMmi">"Změna hesla"</string>
+ <string name="PinMmi">"Změna kódu PIN"</string>
+ <string name="CnipMmi">"Volané Äíslo uvedeno"</string>
+ <string name="CnirMmi">"Volání Äísla omezeno"</string>
+ <string name="ThreeWCMmi">"Konference tří úÄastníků"</string>
+ <string name="RuacMmi">"Odmítnutí nevyžádaných obtěžujících hovorů"</string>
+ <string name="CndMmi">"DoruÄení volaného Äísla"</string>
+ <string name="DndMmi">"Nerušit"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Ve výchozím nastavení je identifikace volajícího omezena. Příští hovor: Omezeno"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Ve výchozím nastavení je identifikace volajícího omezena. Příští hovor: Neomezeno"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Omezeno"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Ve výchozím nastavení není identifikace volajícího omezena. Příští hovor: Neomezeno"</string>
+ <string name="serviceNotProvisioned">"Služba není zřízena."</string>
+ <string name="CLIRPermanent">"Nelze změnit nastavení identifikace volajícího."</string>
+ <string name="RestrictedChangedTitle">"Omezený přístup byl změněn."</string>
+ <string name="RestrictedOnData">"Datová služba je zablokována."</string>
+ <string name="RestrictedOnEmergency">"Tísňová linka je zablokována."</string>
+ <string name="RestrictedOnNormal">"Hlasová služba a služba SMS jsou zablokovány."</string>
+ <string name="RestrictedOnAll">"Veškeré hlasové služby a služby SMS jsou zablokovány."</string>
+ <string name="serviceClassVoice">"Hlas"</string>
+ <string name="serviceClassData">"Data"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Async"</string>
+ <string name="serviceClassDataSync">"Synchronizace"</string>
+ <string name="serviceClassPacket">"Pakety"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Indikátor roamingu svítí"</string>
+ <string name="roamingText1">"Indikátor roamingu nesvítí"</string>
+ <string name="roamingText2">"Indikátor roamingu bliká"</string>
+ <string name="roamingText3">"Není v blízkosti"</string>
+ <string name="roamingText4">"Mimo budovu"</string>
+ <string name="roamingText5">"Roaming – preferovaný systém"</string>
+ <string name="roamingText6">"Roaming – dostupný systém"</string>
+ <string name="roamingText7">"Roaming – alianÄní partner"</string>
+ <string name="roamingText8">"Roaming – prémiový partner"</string>
+ <string name="roamingText9">"Roaming – úplná funkÄnost služby"</string>
+ <string name="roamingText10">"Roaming – ÄásteÄná funkÄnost služby"</string>
+ <string name="roamingText11">"Banner roamingu je zapnutý"</string>
+ <string name="roamingText12">"Banner roamingu je vypnutý"</string>
+ <string name="roamingTextSearching">"Vyhledávání služby"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sek."</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
+ <string name="fcComplete">"Požadavek zadaný pomocí kódu funkce byl úspěšnÄ› dokonÄen."</string>
+ <string name="fcError">"Problém s připojením nebo neplatný kód funkce."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Webová stránka obsahuje chybu."</string>
+ <string name="httpErrorLookup">"Adresu URL nelze najít."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Schéma ověření webu není podporováno."</string>
+ <string name="httpErrorAuth">"Ověření nebylo úspěšné."</string>
+ <string name="httpErrorProxyAuth">"Ověření pomocí serveru proxy bylo neúspěšné."</string>
+ <string name="httpErrorConnect">"Připojení k serveru bylo neúspěšné."</string>
+ <string name="httpErrorIO">"Komunikace se serverem se nezdařila. Opakujte akci později."</string>
+ <string name="httpErrorTimeout">"Spojení se serverem vypršelo."</string>
+ <string name="httpErrorRedirectLoop">"Stránka obsahuje příliš mnoho přesměrování serveru."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokol není podporován."</string>
+ <string name="httpErrorFailedSslHandshake">"Nelze navázat zabezpeÄené spojení."</string>
+ <string name="httpErrorBadUrl">"Stránku nelze otevřít, protože adresa URL je neplatná."</string>
+ <string name="httpErrorFile">"K souboru nelze získat přístup."</string>
+ <string name="httpErrorFileNotFound">"Požadovaný soubor nebyl nalezen."</string>
+ <string name="httpErrorTooManyRequests">"Je zpracováváno příliš mnoho požadavků. Opakujte akci později."</string>
+ <string name="contentServiceSync">"Synchronizace"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchronizace"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Příliš mnoho smazaných položek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Paměť telefonu je plná. Smažte některé soubory a uvolněte místo."</string>
+ <string name="me">"Já"</string>
+ <string name="power_dialog">"Možnosti telefonu"</string>
+ <string name="silent_mode">"Tichý režim"</string>
+ <string name="turn_on_radio">"Zapnout bezdrátové připojení"</string>
+ <string name="turn_off_radio">"Vypnout bezdrátové připojení"</string>
+ <string name="screen_lock">"Zámek obrazovky"</string>
+ <string name="power_off">"Vypnout"</string>
+ <string name="shutdown_progress">"Vypínání..."</string>
+ <string name="shutdown_confirm">"Váš telefon bude vypnut."</string>
+ <string name="no_recent_tasks">"Žádné nedávno použité aplikace."</string>
+ <string name="global_actions">"Možnosti telefonu"</string>
+ <string name="global_action_lock">"Zámek obrazovky"</string>
+ <string name="global_action_power_off">"Vypnout"</string>
+ <string name="global_action_toggle_silent_mode">"Tichý režim"</string>
+ <string name="global_action_silent_mode_on_status">"Zvuk je VYPNUTÃ."</string>
+ <string name="global_action_silent_mode_off_status">"Zvuk je zapnutý"</string>
+ <string name="global_actions_toggle_airplane_mode">"Režim V letadle"</string>
+ <string name="global_actions_airplane_mode_on_status">"Režim V letadle je ZAPNUTÃ"</string>
+ <string name="global_actions_airplane_mode_off_status">"Režim V letadle je VYPNUTÃ"</string>
+ <string name="safeMode">"Nouzový režim"</string>
+ <string name="android_system_label">"Systém Android"</string>
+ <string name="permgrouplab_costMoney">"Zpoplatněné služby"</string>
+ <string name="permgroupdesc_costMoney">"Umožňuje aplikacím provádÄ›t Äinnosti, které vás mohou stát peníze."</string>
+ <string name="permgrouplab_messages">"Vaše zprávy"</string>
+ <string name="permgroupdesc_messages">"Čtení a zápis zpráv SMS, e-mailů a dalších zpráv."</string>
+ <string name="permgrouplab_personalInfo">"Vaše osobní informace"</string>
+ <string name="permgroupdesc_personalInfo">"Přímý přístup k vašim kontaktům a kalendáři v telefonu."</string>
+ <string name="permgrouplab_location">"Vaše poloha"</string>
+ <string name="permgroupdesc_location">"Sleduje vaši fyzickou polohu"</string>
+ <string name="permgrouplab_network">"Síťová komunikace"</string>
+ <string name="permgroupdesc_network">"Umožňuje aplikacím získat přístup k různým funkcím sítě."</string>
+ <string name="permgrouplab_accounts">"VaÅ¡e úÄty Google"</string>
+ <string name="permgroupdesc_accounts">"Přístup k dostupným úÄtům Google."</string>
+ <string name="permgrouplab_hardwareControls">"Řízení hardwaru"</string>
+ <string name="permgroupdesc_hardwareControls">"Přímý přístup k hardwaru telefonu."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonní hovory"</string>
+ <string name="permgroupdesc_phoneCalls">"Sledování, záznam a zpracování telefonních hovorů."</string>
+ <string name="permgrouplab_systemTools">"Systémové nástroje"</string>
+ <string name="permgroupdesc_systemTools">"Nízkoúrovňový přístup a kontrola nad systémem."</string>
+ <string name="permgrouplab_developmentTools">"Nástroje pro vývojáře"</string>
+ <string name="permgroupdesc_developmentTools">"Funkce pouze pro vývojáře aplikací"</string>
+ <string name="permgrouplab_storage">"Úložiště"</string>
+ <string name="permgroupdesc_storage">"Přístup ke kartě SD."</string>
+ <string name="permlab_statusBar">"zakázání Äi zmÄ›ny stavového řádku"</string>
+ <string name="permdesc_statusBar">"Umožňuje aplikaci zakázat stavový řádek nebo pÅ™idat Äi odebrat systémové ikony."</string>
+ <string name="permlab_expandStatusBar">"rozbalení a sbalení stavového řádku"</string>
+ <string name="permdesc_expandStatusBar">"Umožňuje aplikaci rozbalit Äi sbalit stavový řádek."</string>
+ <string name="permlab_processOutgoingCalls">"zachycení odchozích hovorů"</string>
+ <string name="permdesc_processOutgoingCalls">"Umožňuje aplikaci zpracovat odchozí hovory a zmÄ›nit Äíslo, které má být vytoÄeno. Å kodlivé aplikace mohou sledovat Äi pÅ™esmÄ›rovat odchozí hovory nebo jim zabránit."</string>
+ <string name="permlab_receiveSms">"příjem zpráv SMS"</string>
+ <string name="permdesc_receiveSms">"Umožňuje aplikaci přijímat a zpracovávat zprávy SMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
+ <string name="permlab_receiveMms">"příjem zpráv MMS"</string>
+ <string name="permdesc_receiveMms">"Umožňuje aplikaci přijímat a zpracovávat zprávy MMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
+ <string name="permlab_sendSms">"odesílat zprávy SMS"</string>
+ <string name="permdesc_sendSms">"Umožňuje aplikaci odesílat zprávy SMS. Škodlivé aplikace mohou bez vašeho potvrzení odesílat zpoplatněné zprávy."</string>
+ <string name="permlab_readSms">"Ätení zpráv SMS a MMS"</string>
+ <string name="permdesc_readSms">"Umožňuje aplikaci Äíst zprávy SMS uložené ve vaÅ¡em telefonu nebo na kartÄ› SIM. Å kodlivé aplikace mohou naÄíst vaÅ¡e soukromé zprávy."</string>
+ <string name="permlab_writeSms">"úprava zpráv SMS a MMS"</string>
+ <string name="permdesc_writeSms">"Umožňuje aplikaci zapisovat do zpráv SMS uložených ve vašem telefonu nebo na kartě SIM. Škodlivé aplikace mohou smazat vaše zprávy."</string>
+ <string name="permlab_receiveWapPush">"příjem WAP"</string>
+ <string name="permdesc_receiveWapPush">"Umožňuje aplikaci přijímat a zpracovávat zprávy WAP. Škodlivé aplikace mohou sledovat vaše zprávy nebo je smazat, aniž by vám byly zobrazeny."</string>
+ <string name="permlab_getTasks">"naÄtení spuÅ¡tÄ›ných aplikací"</string>
+ <string name="permdesc_getTasks">"Umožňuje aplikaci naÄíst informace o aktuálnÄ› a nedávno spuÅ¡tÄ›ných úlohách. Toto nastavení může Å¡kodlivým aplikacím umožnit odhalení soukromých informací o jiných aplikacích."</string>
+ <string name="permlab_reorderTasks">"změna uspořádání spuštěných aplikací"</string>
+ <string name="permdesc_reorderTasks">"Umožňuje aplikaci pÅ™esouvat úlohy do popÅ™edí Äi pozadí. Å kodlivé aplikace mohou vynutit své pÅ™esunutí do popÅ™edí bez vaÅ¡eho pÅ™iÄinÄ›ní."</string>
+ <string name="permlab_setDebugApp">"povolit ladění aplikací"</string>
+ <string name="permdesc_setDebugApp">"Umožňuje aplikaci povolit ladÄ›ní jiné aplikace. Å kodlivé aplikace mohou pomocí tohoto nastavení ukonÄit jiné aplikace."</string>
+ <string name="permlab_changeConfiguration">"změny vašeho nastavení uživatelského rozhraní"</string>
+ <string name="permdesc_changeConfiguration">"Umožňuje aplikaci zmÄ›nit aktuální konfiguraci, napÅ™. národní prostÅ™edí Äi obecnou velikost písma."</string>
+ <string name="permlab_restartPackages">"restartování ostatních aplikací"</string>
+ <string name="permdesc_restartPackages">"Umožňuje aplikaci vynutit restartování jiných aplikací."</string>
+ <string name="permlab_forceBack">"vynucení zavření aplikace"</string>
+ <string name="permdesc_forceBack">"Umožňuje aplikaci vynutit zavÅ™ení a pÅ™esunutí libovolné Äinnosti v popÅ™edí na pozadí. Běžné aplikace by toto nastavení nemÄ›ly nikdy využívat."</string>
+ <string name="permlab_dump">"naÄtení interního stavu systému"</string>
+ <string name="permdesc_dump">"Umožňuje aplikaci naÄíst interní stav systému. Å kodlivé aplikace mohou naÄíst řádu soukromých a zabezpeÄených informací, které by nikdy nemÄ›ly potÅ™ebovat."</string>
+ <string name="permlab_shutdown">"ČásteÄné vypnutí"</string>
+ <string name="permdesc_shutdown">"Uvede správce Äinností do vypnutého stavu. Nedojde vÅ¡ak k úplnému vypnutí."</string>
+ <string name="permlab_stopAppSwitches">"Zabránit přepínání aplikací"</string>
+ <string name="permdesc_stopAppSwitches">"Zabrání uživateli přepnout na jinou aplikaci."</string>
+ <string name="permlab_runSetActivityWatcher">"sledování a řízení spouštění všech aplikací"</string>
+ <string name="permdesc_runSetActivityWatcher">"Umožňuje aplikaci sledovat a řídit spouÅ¡tÄ›ní Äinností systémem. Å kodlivé aplikace mohou zcela ovládnout systém. Toto oprávnÄ›ní je zapotÅ™ebí pouze pro úÄely vývoje, nikdy pro běžné použití telefonu."</string>
+ <string name="permlab_broadcastPackageRemoved">"odeslání vysílání o odstranÄ›ní balíÄku"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Umožňuje aplikaci vysílat oznámení o odstranÄ›ní balíÄku aplikace. Å kodlivé aplikace mohou pomocí tohoto nastavení ukonÄit libovolnou další spuÅ¡tÄ›nou aplikaci."</string>
+ <string name="permlab_broadcastSmsReceived">"odeslání vysílání o přijaté zprávě SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy SMS. Škodlivé aplikace mohou pomocí tohoto nastavení falšovat příchozí zprávy SMS."</string>
+ <string name="permlab_broadcastWapPush">"odeslání vysílání typu WAP-PUSH-received"</string>
+ <string name="permdesc_broadcastWapPush">"Umožňuje aplikaci vysílat oznámení o pÅ™ijetí zprávy WAP PUSH. Å kodlivé aplikace mohou pomocí tohoto nastavení zfalÅ¡ovat výpis o doruÄení zprávy MMS nebo nepozorovanÄ› nahradit obsah jakékoli webové stránky Å¡kodlivým obsahem."</string>
+ <string name="permlab_setProcessLimit">"omezení poÄtu spuÅ¡tÄ›ných procesů"</string>
+ <string name="permdesc_setProcessLimit">"Umožňuje aplikaci řídit maximální poÄet spuÅ¡tÄ›ných procesů. Běžné aplikace toto nastavení nikdy nevyužívají."</string>
+ <string name="permlab_setAlwaysFinish">"zavření všech aplikací na pozadí"</string>
+ <string name="permdesc_setAlwaysFinish">"Umožňuje aplikaci ovládat, zda jsou Äinnosti vždy dokonÄeny po pÅ™esunutí do pozadí. Běžné aplikace toto nastavení nikdy nevyužívají."</string>
+ <string name="permlab_batteryStats">"změna statistických údajů o baterii"</string>
+ <string name="permdesc_batteryStats">"Umožňuje zmÄ›nu shromáždÄ›ných statistických údajů o baterii. Není urÄeno pro běžné aplikace."</string>
+ <string name="permlab_backup">"Ovládat zálohování a obnovu systému"</string>
+ <string name="permdesc_backup">"Umožňuje aplikaci ovládat mechanizmus zálohování a obnovy systému. Není urÄeno k použití v běžných aplikacích."</string>
+ <string name="permlab_internalSystemWindow">"zobrazení nepovolených oken"</string>
+ <string name="permdesc_internalSystemWindow">"Umožňuje vytvoření oken, která mají být použita interním systémem uživatelského rozhraní. Běžné aplikace toto nastavení nepoužívají."</string>
+ <string name="permlab_systemAlertWindow">"zobrazení upozornění systémové úrovně"</string>
+ <string name="permdesc_systemAlertWindow">"Umožňuje aplikaci zobrazit okna s výstrahami systému. Škodlivé aplikace mohou převzít kontrolu nad celou obrazovkou telefonu."</string>
+ <string name="permlab_setAnimationScale">"globální změny rychlosti animace"</string>
+ <string name="permdesc_setAnimationScale">"Umožňuje aplikaci kdykoli globálnÄ› zmÄ›nit rychlost animace (rychlejší Äi pomalejší animace)."</string>
+ <string name="permlab_manageAppTokens">"správa tokenů aplikací"</string>
+ <string name="permdesc_manageAppTokens">"Umožňuje aplikaci vytvořit a spravovat své vlastní tokeny a obejít jejich obvyklé řazení typu Z. Toto nastavení by nikdy nemělo být potřeba pro běžné aplikace."</string>
+ <string name="permlab_injectEvents">"používání kláves a tlaÄítek"</string>
+ <string name="permdesc_injectEvents">"Umožňuje aplikaci doruÄit své vlastní vstupní události (stisknutí tlaÄítek, apod.) dalším aplikacím. Å kodlivé aplikace mohou pomocí tohoto nastavení pÅ™evzít kontrolu nad telefonem."</string>
+ <string name="permlab_readInputState">"zaznamenání psaného textu a provádÄ›ných Äinností"</string>
+ <string name="permdesc_readInputState">"Umožňuje aplikacím sledovat, které klávesy používáte, a to i při práci s jinými aplikacemi (například při zadávání hesla). Běžné aplikace by toto nastavení nikdy neměly vyžadovat."</string>
+ <string name="permlab_bindInputMethod">"vazba k metodě zadávání dat"</string>
+ <string name="permdesc_bindInputMethod">"Umožňuje držiteli vázat se na nejvyšší úroveň rozhraní pro zadávání dat. Běžné aplikace by toto nastavení nikdy neměly využívat."</string>
+ <string name="permlab_setOrientation">"změna orientace obrazovky"</string>
+ <string name="permdesc_setOrientation">"Umožňuje aplikaci kdykoli změnit orientaci obrazovky. Běžné aplikace by toto nastavení nikdy neměly využívat."</string>
+ <string name="permlab_signalPersistentProcesses">"odeslání signálů Linux aplikacím"</string>
+ <string name="permdesc_signalPersistentProcesses">"Umožňuje aplikaci vyžádat zaslání poskytnutého signálu všem trvalým procesům."</string>
+ <string name="permlab_persistentActivity">"trvalé spuštění aplikace"</string>
+ <string name="permdesc_persistentActivity">"Umožňuje aplikaci uÄinit své Äásti trvalými, takže je systém nemůže použít pro jiné aplikace."</string>
+ <string name="permlab_deletePackages">"smazání aplikací"</string>
+ <string name="permdesc_deletePackages">"Umožňuje aplikaci smazat balíÄky systému Android. Å kodlivé aplikace mohou pomocí tohoto nastavení smazat důležité aplikace."</string>
+ <string name="permlab_clearAppUserData">"smazání dat ostatních aplikací"</string>
+ <string name="permdesc_clearAppUserData">"Umožňuje aplikaci smazat data uživatele."</string>
+ <string name="permlab_deleteCacheFiles">"smazání mezipaměti ostatních aplikací"</string>
+ <string name="permdesc_deleteCacheFiles">"Umožňuje aplikaci smazat soubory v mezipaměti."</string>
+ <string name="permlab_getPackageSize">"výpoÄet místa pro ukládání aplikací"</string>
+ <string name="permdesc_getPackageSize">"Umožňuje aplikaci naÄtení svého kódu, dat a velikostí mezipamÄ›ti"</string>
+ <string name="permlab_installPackages">"přímá instalace aplikací"</string>
+ <string name="permdesc_installPackages">"Umožňuje aplikaci nainstalovat nové Äi aktualizované balíÄky systému Android. Å kodlivé aplikace mohou pomocí tohoto nastavení pÅ™idat nové aplikace s libovolnými oprávnÄ›ními."</string>
+ <string name="permlab_clearAppCache">"smazání všech dat v mezipaměti aplikace"</string>
+ <string name="permdesc_clearAppCache">"Umožňuje aplikaci uvolnit paměť telefonu smazáním souborů v adresáři mezipaměti aplikace. Přístup je velmi omezený, většinou pouze pro systémové procesy."</string>
+ <string name="permlab_readLogs">"Ätení systémových souborů protokolu"</string>
+ <string name="permdesc_readLogs">"Umožňuje aplikaci Äíst různé systémové soubory protokolů. Toto nastavení aplikaci umožní získat obecné informace o Äinnostech s telefonem, ale nemÄ›ly by obsahovat žádné osobní Äi soukromé informace."</string>
+ <string name="permlab_diagnostic">"Ätení nebo zápis do prostÅ™edků funkce diag"</string>
+ <string name="permdesc_diagnostic">"Umožňuje aplikaci Äíst libovolné prostÅ™edky ve skupinÄ› diag, napÅ™. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnÄ›ní stability a bezpeÄnosti systému. Toto nastavení by mÄ›l používat pouze výrobce Äi operátor pro diagnostiku hardwaru."</string>
+ <string name="permlab_changeComponentState">"povolení Äi zakázání komponent aplikací"</string>
+ <string name="permdesc_changeComponentState">"Umožňuje aplikaci zmÄ›nit, zda je komponenta jiné aplikace povolena nebo ne. Å kodlivé aplikace mohou pomocí tohoto nastavení vypnout důležité funkce telefonu. Je tÅ™eba postupovat opatrnÄ›, protože je možné způsobit nepoužitelnost, nekonzistenci Äi nestabilitu komponent aplikací."</string>
+ <string name="permlab_setPreferredApplications">"nastavení upřednostňovaných aplikací"</string>
+ <string name="permdesc_setPreferredApplications">"Umožňuje aplikaci zmÄ›nit vaÅ¡e upÅ™ednostňované aplikace. Toto nastavení může Å¡kodlivým aplikacím umožnit nepozorovanÄ› zmÄ›nit spouÅ¡tÄ›né aplikace a oklamat vaÅ¡e existující aplikace tak, aby shromažÄovaly vaÅ¡e soukromá data."</string>
+ <string name="permlab_writeSettings">"změny globálních nastavení systému"</string>
+ <string name="permdesc_writeSettings">"Umožňuje aplikaci upravit data nastavení systému. Škodlivé aplikace mohou poškodit konfiguraci vašeho systému."</string>
+ <string name="permlab_writeSecureSettings">"zmÄ›ny zabezpeÄených nastavení systému"</string>
+ <string name="permdesc_writeSecureSettings">"Umožňuje aplikaci zmÄ›nit data zabezpeÄených nastavení systému. Běžné aplikace toto nastavení nevyužívají."</string>
+ <string name="permlab_writeGservices">"změny mapy služeb Google"</string>
+ <string name="permdesc_writeGservices">"Umožňuje aplikaci změnit mapu služeb Google. Běžné aplikace toto nastavení nevyužívají."</string>
+ <string name="permlab_receiveBootCompleted">"automatické spuštění při startu"</string>
+ <string name="permdesc_receiveBootCompleted">"Umožňuje aplikaci spuštění ihned po spuštění systému. Toto nastavení může zpomalit spuštění telefonu a umožnit aplikaci celkově zpomalit telefon, protože bude neustále spuštěna."</string>
+ <string name="permlab_broadcastSticky">"odeslání trvalého vysílání"</string>
+ <string name="permdesc_broadcastSticky">"Umožňuje aplikaci odeslat trvalá vysílání, která pÅ™etrvávají i po skonÄení vysílání. Å kodlivé aplikace mohou telefon zpomalit Äi způsobit jeho nestabilitu, protože bude používat příliÅ¡ mnoho pamÄ›ti."</string>
+ <string name="permlab_readContacts">"Ätení dat kontaktů"</string>
+ <string name="permdesc_readContacts">"Umožňuje aplikaci naÄíst vÅ¡echna data kontaktů (adresy) uložená ve vaÅ¡em telefonu. Å kodlivé aplikace poté mohou dalším lidem odeslat vaÅ¡e data."</string>
+ <string name="permlab_writeContacts">"zápis dat kontaktů"</string>
+ <string name="permdesc_writeContacts">"Umožňuje aplikaci zmÄ›nit kontaktní údaje (adresu) uložené v telefonu. Å kodlivé aplikace mohou pomocí tohoto nastavení vymazat Äi pozmÄ›nit kontaktní údaje."</string>
+ <string name="permlab_writeOwnerData">"zápis informací o vlastníkovi"</string>
+ <string name="permdesc_writeOwnerData">"Umožňuje aplikaci zmÄ›nit informace o vlastníkovi telefonu uložené v telefonu. Å kodlivé aplikace mohou pomocí tohoto nastavení vymazat Äi pozmÄ›nit informace o vlastníkovi."</string>
+ <string name="permlab_readOwnerData">"Ätení informací o vlastníkovi"</string>
+ <string name="permdesc_readOwnerData">"Umožňuje aplikaci Äíst informace o vlastníkovi telefonu uložená v telefonu. Å kodlivé aplikace mohou pomocí tohoto nastavení naÄíst informace o vlastníkovi."</string>
+ <string name="permlab_readCalendar">"Ätení dat kalendáře"</string>
+ <string name="permdesc_readCalendar">"Umožňuje aplikaci naÄíst vÅ¡echny události kalendáře uložené ve vaÅ¡em telefonu. Å kodlivé aplikace poté mohou dalším lidem odeslat události z vaÅ¡eho kalendáře."</string>
+ <string name="permlab_writeCalendar">"zápis dat kalendáře"</string>
+ <string name="permdesc_writeCalendar">"Umožňuje aplikaci zmÄ›nit události kalendáře uložené v telefonu. Å kodlivé aplikace mohou pomocí tohoto nastavení vymazat Äi pozmÄ›nit vaÅ¡e data v kalendáři."</string>
+ <string name="permlab_accessMockLocation">"simulace zdrojů polohy pro úÄely testování"</string>
+ <string name="permdesc_accessMockLocation">"Vytváří simulované zdroje polohy pro úÄely testování. Å kodlivé aplikace mohou pomocí tohoto nastavení zmÄ›nit polohu Äi stav vrácený zdroji skuteÄné polohy, jako je napÅ™. jednotka GPS Äi poskytovatelé sítÄ›."</string>
+ <string name="permlab_accessLocationExtraCommands">"přístup k dalším příkazům poskytovatele polohy"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Umožňuje získat přístup k dalším příkazům poskytovatele polohy. Å kodlivé aplikace mohou pomocí tohoto nastavení naruÅ¡it funkci GPS Äi jiných zdrojů polohy."</string>
+ <string name="permlab_installLocationProvider">"Oprávnění k instalaci poskytovatele polohy"</string>
+ <string name="permdesc_installLocationProvider">"VytvoÅ™it simulace zdrojů polohy pro úÄely testování. Å kodlivé aplikace mohou toto nastavení využít k pÅ™epsání polohy nebo stavu vráceného zdroji skuteÄné polohy, například systémem GPS nebo poskytovateli sítí. Mohou také monitorovat polohu a ohlásit ji externímu zdroji."</string>
+ <string name="permlab_accessFineLocation">"upřesnění polohy (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Umožňuje aplikaci přístup ke zdrojům přesné polohy v telefonu, jako je například systém GPS, je-li k dispozici. Škodlivé aplikace mohou pomocí tohoto nastavení zjistit vaši polohu a mohou zvýšit spotřebu baterie."</string>
+ <string name="permlab_accessCoarseLocation">"přibližná poloha (pomocí sítě)"</string>
+ <string name="permdesc_accessCoarseLocation">"Umožňuje získat přístup ke zdrojům pÅ™ibližné polohy, jako je například databáze mobilní sítÄ›, je-li k dispozici, a urÄit pÅ™ibližnou pozici telefonu. Å kodlivé aplikace takto mohou zjistit, kde se pÅ™ibližnÄ› nacházíte."</string>
+ <string name="permlab_accessSurfaceFlinger">"přístup ke službě SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Umožňuje aplikaci používat nízkoúrovňové funkce SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"Ätení vyrovnávací pamÄ›ti snímků"</string>
+ <string name="permdesc_readFrameBuffer">"Umožňuje aplikaci naÄíst obsah vyrovnávací pamÄ›ti snímků."</string>
+ <string name="permlab_modifyAudioSettings">"změna vašeho nastavení zvuku"</string>
+ <string name="permdesc_modifyAudioSettings">"Umožňuje aplikaci zmÄ›nit globální nastavení zvuku, například hlasitost Äi smÄ›rování."</string>
+ <string name="permlab_recordAudio">"nahrání zvuku"</string>
+ <string name="permdesc_recordAudio">"Umožňuje aplikaci získat přístup k nahrávání zvuku."</string>
+ <string name="permlab_camera">"pořizování fotografií"</string>
+ <string name="permdesc_camera">"Umožňuje aplikaci poÅ™izovat fotografie pomocí fotoaparátu. Toto nastavení aplikaci umožní shromažÄovat fotografie toho, na co je zrovna fotoaparát namířen."</string>
+ <string name="permlab_brick">"trvalé vypnutí telefonu"</string>
+ <string name="permdesc_brick">"Umožňuje aplikaci trvale vypnout celý telefon. Toto je velmi nebezpeÄné nastavení."</string>
+ <string name="permlab_reboot">"vynucení restartování telefonu"</string>
+ <string name="permdesc_reboot">"Umožňuje aplikaci vynutit restartování telefonu."</string>
+ <string name="permlab_mount_unmount_filesystems">"připojení a odpojení souborových systémů"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Umožňuje aplikaci pÅ™ipojit Äi odpojit souborové systémy ve vymÄ›nitelných úložiÅ¡tích."</string>
+ <string name="permlab_mount_format_filesystems">"formátovat externí úložiště"</string>
+ <string name="permdesc_mount_format_filesystems">"Umožňuje aplikaci formátovat vyměnitelná úložiště."</string>
+ <string name="permlab_vibrate">"ovládání vibrací"</string>
+ <string name="permdesc_vibrate">"Umožňuje aplikaci ovládat vibrace."</string>
+ <string name="permlab_flashlight">"ovládání kontrolky"</string>
+ <string name="permdesc_flashlight">"Umožňuje aplikaci ovládat kontrolku."</string>
+ <string name="permlab_hardware_test">"testování hardwaru"</string>
+ <string name="permdesc_hardware_test">"Umožňuje aplikaci ovládat různé periferie pro úÄely testování hardwaru."</string>
+ <string name="permlab_callPhone">"přímé volání na telefonní Äísla"</string>
+ <string name="permdesc_callPhone">"Umožňuje aplikaci bez vaÅ¡eho zásahu volat na telefonní Äísla. Å kodlivé aplikace mohou na váš telefonní úÄet pÅ™ipsat neoÄekávané hovory. Toto nastavení aplikaci neumožňuje volat na tísňové linky."</string>
+ <string name="permlab_callPrivileged">"přímé volání na libovolná telefonní Äísla"</string>
+ <string name="permdesc_callPrivileged">"Umožňuje aplikaci bez vaÅ¡eho zásahu vytoÄit jakékoli telefonní Äíslo, vÄetnÄ› Äísel tísňového volání. Å kodlivé aplikace mohou provádÄ›t zbyteÄná a nezákonná volání na tísňové linky."</string>
+ <string name="permlab_locationUpdates">"ovládání oznámení o aktualizaci polohy"</string>
+ <string name="permdesc_locationUpdates">"Umožňuje povolit Äi zakázat aktualizace polohy prostÅ™ednictvím bezdrátového pÅ™ipojení. Aplikace toto nastavení obvykle nepoužívají."</string>
+ <string name="permlab_checkinProperties">"přístup k vlastnostem Checkin"</string>
+ <string name="permdesc_checkinProperties">"Umožňuje Ätení i zápis vlastností nahraných službou Checkin. Běžné aplikace toto nastavení obvykle nevyužívají."</string>
+ <string name="permlab_bindGadget">"zvolit widgety"</string>
+ <string name="permdesc_bindGadget">"Umožňuje aplikaci sdÄ›lit systému, které aplikace mohou používat které widgety. Aplikace s tímto oprávnÄ›ním mohou zpřístupnit osobní údaje jiným aplikacím. Není urÄeno pro běžné aplikace."</string>
+ <string name="permlab_modifyPhoneState">"změny stavu telefonu"</string>
+ <string name="permdesc_modifyPhoneState">"Umožňuje aplikaci ovládat telefonní funkce zařízení. Aplikace s tímto oprávnÄ›ním může pÅ™epínat sítÄ› nebo zapnout Äi vypnout bezdrátové pÅ™ipojení telefonu bez vaÅ¡eho svolení."</string>
+ <string name="permlab_readPhoneState">"zjistit stav telefonu"</string>
+ <string name="permdesc_readPhoneState">"Umožňuje aplikaci získat přístup k telefonním funkcím zařízení. Aplikace s tímto oprávnÄ›ním mohou urÄit telefonní Äíslo tohoto telefonu, zda zrovna probíhá hovor, spojené telefonní Äíslo a podobnÄ›."</string>
+ <string name="permlab_wakeLock">"zabránění přechodu telefonu do režimu spánku"</string>
+ <string name="permdesc_wakeLock">"Umožňuje aplikaci zabránit přechodu telefonu do režimu spánku."</string>
+ <string name="permlab_devicePower">"zapnutí Äi vypnutí telefonu"</string>
+ <string name="permdesc_devicePower">"Umožňuje aplikaci zapnout Äi vypnout telefon."</string>
+ <string name="permlab_factoryTest">"spuštění v režimu továrního testu"</string>
+ <string name="permdesc_factoryTest">"Umožňuje aplikaci spuštění v režimu nízkoúrovňového testu výrobce a povolí přístup k hardwaru telefonu. K dispozici pouze, je-li telefon spuštěn v režimu testování výrobce."</string>
+ <string name="permlab_setWallpaper">"nastavení tapety"</string>
+ <string name="permdesc_setWallpaper">"Umožňuje aplikaci nastavit tapetu systému."</string>
+ <string name="permlab_setWallpaperHints">"nastavení nápovědy pro velikost tapety"</string>
+ <string name="permdesc_setWallpaperHints">"Umožňuje aplikaci nastavit nápovědu pro velikost tapety systému."</string>
+ <string name="permlab_masterClear">"obnovení továrního nastavení systému"</string>
+ <string name="permdesc_masterClear">"Umožňuje aplikaci kompletně obnovit systém do továrního nastavení a vymazat všechna data, konfiguraci a nainstalované aplikace."</string>
+ <string name="permlab_setTimeZone">"nastavení Äasového pásma"</string>
+ <string name="permdesc_setTimeZone">"Umožňuje aplikaci zmÄ›nit Äasové pásmo telefonu."</string>
+ <string name="permlab_getAccounts">"odhalení známých úÄtů"</string>
+ <string name="permdesc_getAccounts">"Umožňuje aplikaci získat seznam úÄtů v telefonu."</string>
+ <string name="permlab_accessNetworkState">"zobrazení stavu sítě"</string>
+ <string name="permdesc_accessNetworkState">"Umožňuje aplikaci zobrazit stav všech sítí."</string>
+ <string name="permlab_createNetworkSockets">"plný přístup k Internetu"</string>
+ <string name="permdesc_createNetworkSockets">"Umožňuje aplikaci vytvořit síťové sokety."</string>
+ <string name="permlab_writeApnSettings">"zápis nastavení pro název přístupového bodu (APN)"</string>
+ <string name="permdesc_writeApnSettings">"Umožňuje aplikaci zmÄ›nit nastavení APN, jako je například proxy Äi port APN."</string>
+ <string name="permlab_changeNetworkState">"změna připojení k síti"</string>
+ <string name="permdesc_changeNetworkState">"Umožňuje aplikaci změnit stav připojení k síti."</string>
+ <string name="permlab_changeBackgroundDataSetting">"změnit nastavení použití dat na pozadí"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Umožňuje aplikaci změnit nastavení použití dat na pozadí."</string>
+ <string name="permlab_accessWifiState">"zobrazení stavu WiFi"</string>
+ <string name="permdesc_accessWifiState">"Umožňuje aplikaci zobrazit informace o stavu připojení WiFi."</string>
+ <string name="permlab_changeWifiState">"Změnit stav WiFi"</string>
+ <string name="permdesc_changeWifiState">"Umožňuje aplikaci pÅ™ipojit se k přístupovým bodům WiFi Äi se od nich odpojit a provádÄ›t zmÄ›ny nakonfigurovaných sítí WiFi."</string>
+ <string name="permlab_changeWifiMulticastState">"Povolit příjem Wi-Fi Multicast"</string>
+ <string name="permdesc_changeWifiMulticastState">"Povoluje aplikaci přijímat pakety, které nebyly adresovány přímo vašemu zařízení. Pomocí této možnosti můžete objevit služby nabízené ve vaší blízkosti. Spotřeba energie je vyšší než u režimu bez vícesměrového vysílání (multicast)."</string>
+ <string name="permlab_bluetoothAdmin">"správa rozhraní Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Umožňuje aplikaci konfigurovat místní telefon s rozhraním Bluetooth a vyhledávat a párovat vzdálená zařízení."</string>
+ <string name="permlab_bluetooth">"vytvoření připojení Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Umožňuje aplikaci zobrazit konfiguraci místního telefonu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
+ <string name="permlab_disableKeyguard">"vypnutí zámku kláves"</string>
+ <string name="permdesc_disableKeyguard">"Umožňuje aplikaci vypnout zámek kláves a související zabezpeÄení heslem. Příkladem oprávnÄ›ného použití této funkce je vypnutí zámku klávesnice pÅ™i příchozím hovoru a jeho opÄ›tovné zapnutí po skonÄení hovoru."</string>
+ <string name="permlab_readSyncSettings">"Ätení nastavení synchronizace"</string>
+ <string name="permdesc_readSyncSettings">"Umožňuje aplikaci naÄíst nastavení synchronizace, napÅ™. zda má být povolena synchronizace kontaktů."</string>
+ <string name="permlab_writeSyncSettings">"zápis nastavení synchronizace"</string>
+ <string name="permdesc_writeSyncSettings">"Umožňuje aplikaci změnit nastavení synchronizace, např. zda má být povolena synchronizace kontaktů."</string>
+ <string name="permlab_readSyncStats">"Ätení statistických údajů o synchronizaci"</string>
+ <string name="permdesc_readSyncStats">"Umožňuje aplikaci Äíst statistické informace o synchronizaci, napÅ™. historii probÄ›hlých synchronizací."</string>
+ <string name="permlab_subscribedFeedsRead">"Ätení zdrojů pÅ™ihlášených k odbÄ›ru"</string>
+ <string name="permdesc_subscribedFeedsRead">"Umožňuje aplikaci získat podrobnosti o aktuálně synchronizovaných zdrojích."</string>
+ <string name="permlab_subscribedFeedsWrite">"zápis odebíraných zdrojů"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Umožňuje aplikaci upravit vaše aktuálně synchronizované zdroje. To může škodlivým aplikacím umožnit změnu vašich synchronizovaných zdrojů."</string>
+ <string name="permlab_readDictionary">"Äíst slovník definovaný uživatelem"</string>
+ <string name="permdesc_readDictionary">"Umožní aplikaci Äíst soukromá slova, jména a fráze, která uživatel mohl uložit do svého slovníku."</string>
+ <string name="permlab_writeDictionary">"zapisovat do slovníku definovaného uživatelem"</string>
+ <string name="permdesc_writeDictionary">"Umožní aplikaci zapisovat nová slova do uživatelského slovníku."</string>
+ <string name="permlab_sdcardWrite">"Změnit/smazat obsah karty SD"</string>
+ <string name="permdesc_sdcardWrite">"Umožní aplikaci zápis na kartu SD."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Domů"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Práce"</item>
- <item msgid="1103601433382158155">"Pracovní fax"</item>
- <item msgid="1735177144948329370">"Fax domů"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Ostatní"</item>
- <item msgid="9192514806975898961">"Vlastní"</item>
+ <item>"Domů"</item>
+ <item>"Mobil"</item>
+ <item>"Práce"</item>
+ <item>"Pracovní fax"</item>
+ <item>"Fax domů"</item>
+ <item>"Pager"</item>
+ <item>"Ostatní"</item>
+ <item>"Vlastní"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Domů"</item>
- <item msgid="7084237356602625604">"Práce"</item>
- <item msgid="1112044410659011023">"Ostatní"</item>
- <item msgid="2374913952870110618">"Vlastní"</item>
+ <item>"Domů"</item>
+ <item>"Práce"</item>
+ <item>"Ostatní"</item>
+ <item>"Vlastní"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobilní"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Domů"</item>
- <item msgid="5629153956045109251">"Práce"</item>
- <item msgid="4966604264500343469">"Ostatní"</item>
- <item msgid="4932682847595299369">"Vlastní"</item>
+ <item>"Domů"</item>
+ <item>"Práce"</item>
+ <item>"Ostatní"</item>
+ <item>"Vlastní"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Domů"</item>
- <item msgid="1359644565647383708">"Práce"</item>
- <item msgid="7868549401053615677">"Ostatní"</item>
- <item msgid="3145118944639869809">"Vlastní"</item>
+ <item>"Domů"</item>
+ <item>"Práce"</item>
+ <item>"Ostatní"</item>
+ <item>"Vlastní"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Práce"</item>
- <item msgid="4378074129049520373">"Ostatní"</item>
- <item msgid="3455047468583965104">"Vlastní"</item>
+ <item>"Práce"</item>
+ <item>"Ostatní"</item>
+ <item>"Vlastní"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo!"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo!"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Zadejte kód PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Nesprávný kód PIN"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Chcete-li telefon odemknout, stiskněte Menu a poté 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Číslo tísňové linky"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Není signál)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Obrazovka uzamÄena."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Chcete-li odemknout telefon nebo provést tísňové volání, stiskněte Menu."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Telefon odemknete stisknutím tlaÄítka Menu."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Odblokujte pomocí gesta"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Tísňové volání"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Správně!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Zkuste to prosím znovu"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Nabíjení (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Nabito."</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Připojte dobíjecí zařízení."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Není vložena SIM karta."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"V telefonu není žádná karta SIM."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Prosím vložte kartu SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Síť je blokována"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Karta SIM je zablokována pomocí kódu PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Další informace naleznete v uživatelské příruÄce, nebo kontaktujte podporu zákazníků."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Karta SIM je zablokována."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Odblokování karty SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nakreslili nesprávné bezpeÄnostní gesto. "\n\n"Opakujte prosím akci za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávnÄ› nakreslili své bezpeÄnostní gesto. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemÄení telefonu pomocí pÅ™ihlášení do úÄtu Google."\n\n" Akci prosím opakujte za nÄ›kolik sekund (<xliff:g id="NUMBER_2">%d</xliff:g>)."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Sekundy zbývající do dalšího pokusu: <xliff:g id="NUMBER">%d</xliff:g>."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zapomněli jste gesto?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Gesta: Příliš mnoho pokusů"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Chcete-li telefon odemknout, pÅ™ihlaste se pomocí svého úÄtu Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Uživatelské jméno (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Heslo"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Přihlásit se"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Neplatné uživatelské jméno nebo heslo."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Vymazat"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Žádná oznámení"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Probíhající"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Oznámení"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Nabíjení..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Prosím připojte dobíjecí zařízení"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Baterie je vybitá:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"zbývá méně než <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"ProÄ?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Test továrního nastavení se nezdařil"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Test FACTORY_TEST lze provést pouze u balíÄků nainstalovaných ve složce /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Nebyl nalezen žádný balíÄek umožňující test FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Restartovat"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Stránka <xliff:g id="TITLE">%s</xliff:g> uvádí:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Chcete opustit tuto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Vyberte OK, chcete-li pokraÄovat, nebo ZruÅ¡it, chcete-li na stránce zůstat."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Potvrdit"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Ätení historie a záložek ProhlížeÄe"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Umožňuje aplikaci Äíst vÅ¡echny navÅ¡tívené adresy URL a záložky ProhlížeÄe."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"zápis do historie a záložek ProhlížeÄe"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Umožní aplikaci zmÄ›nit historii Äi záložky prohlížeÄe uložené v telefonu. Å kodlivé aplikace mohou pomocí tohoto nastavení vymazat Äi pozmÄ›nit data ProhlížeÄe."</string>
- <string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prohlížeÄ zapamatoval toto heslo?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Nyní ne"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Zapamatovat"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nikdy"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Nemáte povolení otevřít tuto stránku."</string>
- <string name="text_copied" msgid="4985729524670131385">"Text byl zkopírován do schránky."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Více"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"mezerník"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"smazat"</string>
- <string name="search_go" msgid="8298016669822141719">"Hledat"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"před 1 měsícem"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Déle než před 1 měsícem"</string>
+ <string name="keyguard_password_enter_pin_code">"Zadejte kód PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Nesprávný kód PIN"</string>
+ <string name="keyguard_label_text">"Chcete-li telefon odemknout, stiskněte Menu a poté 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Číslo tísňové linky"</string>
+ <string name="lockscreen_carrier_default">"(Není signál)"</string>
+ <string name="lockscreen_screen_locked">"Obrazovka uzamÄena."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Chcete-li odemknout telefon nebo provést tísňové volání, stiskněte Menu."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Telefon odemknete stisknutím tlaÄítka Menu."</string>
+ <string name="lockscreen_pattern_instructions">"Odblokujte pomocí gesta"</string>
+ <string name="lockscreen_emergency_call">"Tísňové volání"</string>
+ <string name="lockscreen_pattern_correct">"Správně!"</string>
+ <string name="lockscreen_pattern_wrong">"Zkuste to prosím znovu"</string>
+ <string name="lockscreen_plugged_in">"Nabíjení (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Připojte dobíjecí zařízení."</string>
+ <string name="lockscreen_missing_sim_message_short">"Není vložena SIM karta."</string>
+ <string name="lockscreen_missing_sim_message">"V telefonu není žádná karta SIM."</string>
+ <string name="lockscreen_missing_sim_instructions">"Prosím vložte kartu SIM."</string>
+ <string name="lockscreen_network_locked_message">"Síť je blokována"</string>
+ <string name="lockscreen_sim_puk_locked_message">"Karta SIM je zablokována pomocí kódu PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Další informace naleznete v uživatelské příruÄce, nebo kontaktujte podporu zákazníků."</string>
+ <string name="lockscreen_sim_locked_message">"Karta SIM je zablokována."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Odblokování karty SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nakreslili nesprávné bezpeÄnostní gesto. "\n\n"Opakujte prosím akci za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávnÄ› nakreslili své bezpeÄnostní gesto. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemÄení telefonu pomocí pÅ™ihlášení do úÄtu Google."\n\n" Akci prosím opakujte za nÄ›kolik sekund (<xliff:g id="NUMBER_2">%d</xliff:g>)."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Sekundy zbývající do dalšího pokusu: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Zapomněli jste gesto?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Gesta: Příliš mnoho pokusů"</string>
+ <string name="lockscreen_glogin_instructions">"Chcete-li telefon odemknout, pÅ™ihlaste se pomocí svého úÄtu Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Uživatelské jméno (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Heslo"</string>
+ <string name="lockscreen_glogin_submit_button">"Přihlásit se"</string>
+ <string name="lockscreen_glogin_invalid_input">"Neplatné uživatelské jméno nebo heslo."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Žádná oznámení"</string>
+ <string name="status_bar_ongoing_events_title">"Probíhající"</string>
+ <string name="status_bar_latest_events_title">"Oznámení"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Nabíjení..."</string>
+ <string name="battery_low_title">"Prosím připojte dobíjecí zařízení"</string>
+ <string name="battery_low_subtitle">"Baterie je vybitá:"</string>
+ <string name="battery_low_percent_format">"zbývá méně než <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="battery_low_why">"ProÄ?"</string>
+ <string name="factorytest_failed">"Test továrního nastavení se nezdařil"</string>
+ <string name="factorytest_not_system">"Test FACTORY_TEST lze provést pouze u balíÄků nainstalovaných ve složce /system/app."</string>
+ <string name="factorytest_no_action">"Nebyl nalezen žádný balíÄek umožňující test FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Restartovat"</string>
+ <string name="js_dialog_title">"Stránka <xliff:g id="TITLE">%s</xliff:g> uvádí:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Chcete opustit tuto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Vyberte OK, chcete-li pokraÄovat, nebo ZruÅ¡it, chcete-li na stránce zůstat."</string>
+ <string name="save_password_label">"Potvrdit"</string>
+ <string name="permlab_readHistoryBookmarks">"ÄŒtení historie a záložek prohlížeÄe"</string>
+ <string name="permdesc_readHistoryBookmarks">"Umožňuje aplikaci Äíst vÅ¡echny navÅ¡tívené adresy URL a záložky prohlížeÄe."</string>
+ <string name="permlab_writeHistoryBookmarks">"Zapisovat historii a záložky prohlížeÄe"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Umožní aplikaci zmÄ›nit historii Äi záložky prohlížeÄe uložené v telefonu. Å kodlivé aplikace mohou pomocí tohoto nastavení vymazat Äi pozmÄ›nit data prohlížeÄe."</string>
+ <string name="save_password_message">"Chcete, aby si prohlížeÄ zapamatoval toto heslo?"</string>
+ <string name="save_password_notnow">"Nyní ne"</string>
+ <string name="save_password_remember">"Zapamatovat"</string>
+ <string name="save_password_never">"Nikdy"</string>
+ <string name="open_permission_deny">"Nemáte povolení otevřít tuto stránku."</string>
+ <string name="text_copied">"Text byl zkopírován do schránky."</string>
+ <string name="more_item_label">"Více"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"mezerník"</string>
+ <string name="menu_enter_shortcut_label">"enter"</string>
+ <string name="menu_delete_shortcut_label">"smazat"</string>
+ <string name="search_go">"Hledat"</string>
+ <string name="oneMonthDurationPast">"před 1 měsícem"</string>
+ <string name="beforeOneMonthDurationPast">"Déle než před 1 měsícem"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"před 1 sekundou"</item>
- <item quantity="other" msgid="3903706804349556379">"před <xliff:g id="COUNT">%d</xliff:g> sek."</item>
+ <item quantity="one">"před 1 sekundou"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> sek."</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"před 1 minutou"</item>
- <item quantity="other" msgid="2176942008915455116">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ <item quantity="one">"před 1 minutou"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"před 1 hodinou"</item>
- <item quantity="other" msgid="2467273239587587569">"před <xliff:g id="COUNT">%d</xliff:g> hod."</item>
+ <item quantity="one">"před 1 hodinou"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> hod."</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"vÄera"</item>
- <item quantity="other" msgid="2479586466153314633">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
+ <item quantity="one">"vÄera"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"za 1 sekundu"</item>
- <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
+ <item quantity="one">"za 1 sekundu"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"za 1 minutu"</item>
- <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ <item quantity="one">"za 1 minutu"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"za 1 hodinu"</item>
- <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
+ <item quantity="one">"za 1 hodinu"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"zítra"</item>
- <item quantity="other" msgid="5109449375100953247">"zbývající poÄet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ <item quantity="one">"zítra"</item>
+ <item quantity="other">"zbývající poÄet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"před 1 s"</item>
- <item quantity="other" msgid="3699169366650930415">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
+ <item quantity="one">"před 1 s"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"před 1 min."</item>
- <item quantity="other" msgid="851164968597150710">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ <item quantity="one">"před 1 min."</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"před 1 hodinou"</item>
- <item quantity="other" msgid="6889970745748538901">"před <xliff:g id="COUNT">%d</xliff:g> hod."</item>
+ <item quantity="one">"před 1 hodinou"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> hod."</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"vÄera"</item>
- <item quantity="other" msgid="3453342639616481191">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
+ <item quantity="one">"vÄera"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"za 1 s"</item>
- <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
+ <item quantity="one">"za 1 s"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"za 1 min."</item>
- <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ <item quantity="one">"za 1 min."</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"za 1 hodinu"</item>
- <item quantity="other" msgid="3705373766798013406">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
+ <item quantity="one">"za 1 hodinu"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"zítra"</item>
- <item quantity="other" msgid="2973062968038355991">"zbývající poÄet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ <item quantity="one">"zítra"</item>
+ <item quantity="other">"zbývající poÄet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"v roce %s"</string>
- <string name="day" msgid="8144195776058119424">"den"</string>
- <string name="days" msgid="4774547661021344602">"d."</string>
- <string name="hour" msgid="2126771916426189481">"hodina"</string>
- <string name="hours" msgid="894424005266852993">"hod."</string>
- <string name="minute" msgid="9148878657703769868">"min."</string>
- <string name="minutes" msgid="5646001005827034509">"min."</string>
- <string name="second" msgid="3184235808021478">"s"</string>
- <string name="seconds" msgid="3161515347216589235">"s"</string>
- <string name="week" msgid="5617961537173061583">"týden"</string>
- <string name="weeks" msgid="6509623834583944518">"týd."</string>
- <string name="year" msgid="4001118221013892076">"rokem"</string>
- <string name="years" msgid="6881577717993213522">"lety"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Každý pracovní den (Po – Pá)"</string>
- <string name="daily" msgid="5738949095624133403">"DennÄ›"</string>
- <string name="weekly" msgid="983428358394268344">"Každý týden v <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"MÄ›síÄnÄ›"</string>
- <string name="yearly" msgid="1519577999407493836">"RoÄnÄ›"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Video nelze přehrát"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Omlouváme se, ale toto video nelze přenášet datovým proudem do tohoto zařízení."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Toto video bohužel nelze přehrát."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"poledne"</string>
- <string name="Noon" msgid="3342127745230013127">"Poledne"</string>
- <string name="midnight" msgid="7166259508850457595">"půlnoc"</string>
- <string name="Midnight" msgid="5630806906897892201">"Půlnoc"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Vybrat vše"</string>
- <string name="selectText" msgid="3889149123626888637">"OznaÄit text"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Zastavit oznaÄování textu"</string>
- <string name="cut" msgid="3092569408438626261">"Vyjmout"</string>
- <string name="cutAll" msgid="2436383270024931639">"Vyjmout vše"</string>
- <string name="copy" msgid="2681946229533511987">"Kopírovat"</string>
- <string name="copyAll" msgid="2590829068100113057">"Kopírovat vše"</string>
- <string name="paste" msgid="5629880836805036433">"Vložit"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Kopírovat adresu URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Metoda zadávání dat"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Přidat „%s“ do slovníku"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Úpravy textu"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Málo paměti"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"V telefonu zbývá málo místa pro ukládání dat."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Zrušit"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Upozornění"</string>
- <string name="capital_on" msgid="1544682755514494298">"ZAPNUTO"</string>
- <string name="capital_off" msgid="6815870386972805832">"VYPNOUT"</string>
- <string name="whichApplication" msgid="4533185947064773386">"DokonÄit akci pomocí aplikace"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Použít jako výchozí nastavení pro tuto Äinnost."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Vymažte výchozí hodnoty v Nastavení plochy &gt; Aplikace &gt; Správa aplikací."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Vyberte akci"</string>
- <string name="noApplications" msgid="1691104391758345586">"Tuto Äinnost nemohou provádÄ›t žádné aplikace."</string>
- <string name="aerr_title" msgid="653922989522758100">"Omlouváme se"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) byla neoÄekávanÄ› ukonÄena. Zkuste to znovu."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> byl neoÄekávanÄ› ukonÄen. Opakujte prosím akci."</string>
- <string name="anr_title" msgid="3100070910664756057">"Omlouváme se"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Činnost <xliff:g id="ACTIVITY">%1$s</xliff:g> (v aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>) neodpovídá."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Služba <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>) nereaguje."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Služba <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>) nereaguje."</string>
- <string name="anr_process" msgid="1246866008169975783">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> neodpovídá."</string>
- <string name="force_close" msgid="3653416315450806396">"UkonÄit aplikaci"</string>
- <string name="report" msgid="4060218260984795706">"Nahlásit"</string>
- <string name="wait" msgid="7147118217226317732">"PoÄkat"</string>
- <string name="debug" msgid="9103374629678531849">"Ladit"</string>
- <string name="sendText" msgid="5132506121645618310">"Vyberte Äinnost s textem"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Hlasitost vyzvánění"</string>
- <string name="volume_music" msgid="5421651157138628171">"Hlasitost médií"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Přehrávání pomocí rozhraní Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Hlasitost hovoru"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Hlasitost příchozích hovorů při připojení Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Hlasitost budíku"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Hlasitost oznámení"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Hlasitost"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Výchozí vyzváněcí tón"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Výchozí vyzváněcí tón (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Ticho"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Vyzváněcí tóny"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Neznámý vyzváněcí tón"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"v roce %s"</string>
+ <string name="day">"den"</string>
+ <string name="days">"d."</string>
+ <string name="hour">"hodina"</string>
+ <string name="hours">"hod."</string>
+ <string name="minute">"min."</string>
+ <string name="minutes">"min."</string>
+ <string name="second">"s"</string>
+ <string name="seconds">"s"</string>
+ <string name="week">"týden"</string>
+ <string name="weeks">"týd."</string>
+ <string name="year">"rokem"</string>
+ <string name="years">"lety"</string>
+ <string name="every_weekday">"Každý pracovní den (Po – Pá)"</string>
+ <string name="daily">"DennÄ›"</string>
+ <string name="weekly">"Každý týden v <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"MÄ›síÄnÄ›"</string>
+ <string name="yearly">"RoÄnÄ›"</string>
+ <string name="VideoView_error_title">"Video nelze přehrát"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Omlouváme se, ale toto video nelze přenášet datovým proudem do tohoto zařízení."</string>
+ <string name="VideoView_error_text_unknown">"Toto video bohužel nelze přehrát."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"poledne"</string>
+ <string name="Noon">"Poledne"</string>
+ <string name="midnight">"půlnoc"</string>
+ <string name="Midnight">"Půlnoc"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Vybrat vše"</string>
+ <string name="selectText">"OznaÄit text"</string>
+ <string name="stopSelectingText">"Zastavit oznaÄování textu"</string>
+ <string name="cut">"Vyjmout"</string>
+ <string name="cutAll">"Vyjmout vše"</string>
+ <string name="copy">"Kopírovat"</string>
+ <string name="copyAll">"Kopírovat vše"</string>
+ <string name="paste">"Vložit"</string>
+ <string name="copyUrl">"Kopírovat adresu URL"</string>
+ <string name="inputMethod">"Metoda zadávání dat"</string>
+ <string name="addToDictionary">"Přidat „%s“ do slovníku"</string>
+ <string name="editTextMenuTitle">"Úpravy textu"</string>
+ <string name="low_internal_storage_view_title">"Málo paměti"</string>
+ <string name="low_internal_storage_view_text">"V telefonu zbývá málo místa pro ukládání dat."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Zrušit"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Zrušit"</string>
+ <string name="dialog_alert_title">"Upozornění"</string>
+ <string name="capital_on">"ZAPNUTO"</string>
+ <string name="capital_off">"VYPNOUT"</string>
+ <string name="whichApplication">"DokonÄit akci pomocí aplikace"</string>
+ <string name="alwaysUse">"Použít jako výchozí nastavení pro tuto Äinnost."</string>
+ <string name="clearDefaultHintMsg">"Vymažte výchozí hodnoty v Nastavení plochy &gt; Aplikace &gt; Správa aplikací."</string>
+ <string name="chooseActivity">"Vyberte akci"</string>
+ <string name="noApplications">"Tuto Äinnost nemohou provádÄ›t žádné aplikace."</string>
+ <string name="aerr_title">"Omlouváme se"</string>
+ <string name="aerr_application">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) byla neoÄekávanÄ› ukonÄena. Zkuste to znovu."</string>
+ <string name="aerr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> byl neoÄekávanÄ› ukonÄen. Opakujte prosím akci."</string>
+ <string name="anr_title">"Omlouváme se"</string>
+ <string name="anr_activity_application">"Činnost <xliff:g id="ACTIVITY">%1$s</xliff:g> (v aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>) neodpovídá."</string>
+ <string name="anr_activity_process">"Služba <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>) nereaguje."</string>
+ <string name="anr_application_process">"Služba <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>) nereaguje."</string>
+ <string name="anr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> neodpovídá."</string>
+ <string name="force_close">"UkonÄit aplikaci"</string>
+ <string name="report">"Nahlásit"</string>
+ <string name="wait">"PoÄkat"</string>
+ <string name="debug">"Ladit"</string>
+ <string name="sendText">"Vyberte Äinnost s textem"</string>
+ <string name="volume_ringtone">"Hlasitost vyzvánění"</string>
+ <string name="volume_music">"Hlasitost médií"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Přehrávání pomocí rozhraní Bluetooth"</string>
+ <string name="volume_call">"Hlasitost hovoru"</string>
+ <string name="volume_bluetooth_call">"Hlasitost příchozích hovorů při připojení Bluetooth"</string>
+ <string name="volume_alarm">"Hlasitost upozornění a budíku"</string>
+ <string name="volume_notification">"Hlasitost oznámení"</string>
+ <string name="volume_unknown">"Hlasitost"</string>
+ <string name="ringtone_default">"Výchozí vyzváněcí tón"</string>
+ <string name="ringtone_default_with_actual">"Výchozí vyzváněcí tón (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Ticho"</string>
+ <string name="ringtone_picker_title">"Vyzváněcí tóny"</string>
+ <string name="ringtone_unknown">"Neznámý vyzváněcí tón"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"K dispozici je síť WiFi."</item>
- <item quantity="other" msgid="4192424489168397386">"Jsou k dispozici sítě WiFi."</item>
+ <item quantity="one">"K dispozici je síť WiFi."</item>
+ <item quantity="other">"Jsou k dispozici sítě WiFi."</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"K dispozici je veřejná síť WiFi"</item>
- <item quantity="other" msgid="7915895323644292768">"Jsou k dispozici veřejné sítě WiFi"</item>
+ <item quantity="one">"K dispozici je veřejná síť WiFi"</item>
+ <item quantity="other">"Jsou k dispozici veřejné sítě WiFi"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Vkládání znaků"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Neznámá aplikace"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Odesílání zpráv SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Je odesílán velký poÄet zpráv SMS. Vyberte OK, chcete-li pokraÄovat, nebo ZruÅ¡it, chcete-li odesílání ukonÄit."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Zrušit"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Nastavit"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Výchozí"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Nejsou vyžadována žádná oprávnění"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Skrýt"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Zobrazit vše"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"NaÄítání..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB připojeno"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"PÅ™ipojili jste svůj telefon k poÄítaÄi pomocí USB. Vyberte možnost PÅ™ipojit, chcete-li zkopírovat soubory mezi vaším poÄítaÄem a kartou SD v telefonu."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Připojit"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Nepřipojovat"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Při používání vaší karty SD jako úložiště USB došlo k problému."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB připojeno"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Vyberte, chcete-li kopírovat soubory do nebo z poÄítaÄe."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Vypnout úložiště USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Vyberte, chcete-li vypnout úložiště USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Vypnout úložiště USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"PÅ™ed vypnutím úložiÅ¡tÄ› USB se pÅ™esvÄ›dÄte, zda byl hostitel USB odpojen. ÚložiÅ¡tÄ› USB vypnete volbou Vypnout."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Vypnout"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Zrušit"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Při vypínání úložiště USB došlo k problémům. Zkontrolujte, zda byl hostitel USB odpojen, a zkuste to znovu."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formátovat kartu SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Opravdu chcete kartu SD naformátovat? Všechna data na kartě budou ztracena."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formátovat"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladění přes rozhraní USB připojeno"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"K vaÅ¡emu telefonu je pÅ™ipojen poÄítaÄ."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Výběr metody zadávání dat"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÃBCÄŒDÄŽEÉĚFGHCHIÃJKLMNŇOÓPQRŘSÅ TŤUÚVWXYÃZŽ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÃBCÄŒDÄŽEÉĚFGHCHIÃJKLMNŇOÓPQRŘSÅ TŤUÚVWXYÃZŽ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Příprava karty SD"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Kontrola chyb."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Prázdná karta SD"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"Karta SD je prázdná nebo obsahuje nepodporovaný systém souborů."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Poškozená karta SD"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"Karta SD je poškozená. Bude pravděpodobně nutné ji přeformátovat."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Karta SD byla neoÄekávanÄ› odebrána"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Chcete-li zabránit ztrátě dat, kartu SD před odebráním odpojte."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Kartu SD je možné bezpeÄnÄ› odebrat"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Kartu SD lze bezpeÄnÄ› odebrat."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Karta SD byla odstraněna"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"Karta SD byla odebrána. Vložte novou kartu."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Nebyly nalezeny žádné odpovídající aktivity."</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"aktualizovat statistiku použití souÄástí"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Umožňuje zmÄ›nu shromáždÄ›ných statistických údajů o použití souÄástí. Není urÄeno pro běžné aplikace."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Poklepáním můžete ovládat přiblížení"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Chyba při spouštění widgetu"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Přejít"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Hledat"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Odeslat"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Další"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Hotovo"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Spustit"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"VytoÄit Äíslo"\n" <xliff:g id="NUMBER">%s</xliff:g>."</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Vytvořit kontakt"\n"pro <xliff:g id="NUMBER">%s</xliff:g>."</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"Zaškrtnuto"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"Nezaškrtnuto"</string>
+ <string name="select_character">"Vkládání znaků"</string>
+ <string name="sms_control_default_app_name">"Neznámá aplikace"</string>
+ <string name="sms_control_title">"Odesílání zpráv SMS"</string>
+ <string name="sms_control_message">"Je odesílán velký poÄet zpráv SMS. Vyberte OK, chcete-li pokraÄovat, nebo ZruÅ¡it, chcete-li odesílání ukonÄit."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Zrušit"</string>
+ <string name="date_time_set">"Nastavit"</string>
+ <string name="default_permission_group">"Výchozí"</string>
+ <string name="no_permissions">"Nejsou vyžadována žádná oprávnění"</string>
+ <string name="perms_hide"><b>"Skrýt"</b></string>
+ <string name="perms_show_all"><b>"Zobrazit vše"</b></string>
+ <string name="googlewebcontenthelper_loading">"NaÄítání..."</string>
+ <string name="usb_storage_title">"USB připojeno"</string>
+ <string name="usb_storage_message">"PÅ™ipojili jste svůj telefon k poÄítaÄi pomocí USB. Vyberte možnost PÅ™ipojit, chcete-li zkopírovat soubory mezi vaším poÄítaÄem a kartou SD v telefonu."</string>
+ <string name="usb_storage_button_mount">"Připojit"</string>
+ <string name="usb_storage_button_unmount">"Nepřipojovat"</string>
+ <string name="usb_storage_error_message">"Při používání vaší karty SD jako úložiště USB došlo k problému."</string>
+ <string name="usb_storage_notification_title">"USB připojeno"</string>
+ <string name="usb_storage_notification_message">"Vyberte, chcete-li kopírovat soubory do nebo z poÄítaÄe."</string>
+ <string name="usb_storage_stop_notification_title">"Vypnout úložiště USB"</string>
+ <string name="usb_storage_stop_notification_message">"Vyberte, chcete-li vypnout úložiště USB."</string>
+ <string name="usb_storage_stop_title">"Vypnout úložiště USB"</string>
+ <string name="usb_storage_stop_message">"PÅ™ed vypnutím úložiÅ¡tÄ› USB se pÅ™esvÄ›dÄte, zda byl hostitel USB odpojen. ÚložiÅ¡tÄ› USB vypnete volbou Vypnout."</string>
+ <string name="usb_storage_stop_button_mount">"Vypnout"</string>
+ <string name="usb_storage_stop_button_unmount">"Zrušit"</string>
+ <string name="usb_storage_stop_error_message">"Při vypínání úložiště USB došlo k problémům. Zkontrolujte, zda byl hostitel USB odpojen, a zkuste to znovu."</string>
+ <string name="extmedia_format_title">"Formátovat kartu SD"</string>
+ <string name="extmedia_format_message">"Opravdu chcete kartu SD naformátovat? Všechna data na kartě budou ztracena."</string>
+ <string name="extmedia_format_button_format">"Formátovat"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Výběr metody zadávání dat"</string>
+ <string name="fast_scroll_alphabet">" AÃBCÄŒDÄŽEÉĚFGHCHIÃJKLMNŇOÓPQRŘSÅ TŤUÚVWXYÃZŽ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789AÃBCÄŒDÄŽEÉĚFGHCHIÃJKLMNŇOÓPQRŘSÅ TŤUÚVWXYÃZŽ"</string>
+ <string name="candidates_style"><u>"kandidáti"</u></string>
+ <string name="ext_media_checking_notification_title">"Příprava karty SD"</string>
+ <string name="ext_media_checking_notification_message">"Kontrola chyb."</string>
+ <string name="ext_media_nofs_notification_title">"Prázdná karta SD"</string>
+ <string name="ext_media_nofs_notification_message">"Karta SD je prázdná nebo obsahuje nepodporovaný systém souborů."</string>
+ <string name="ext_media_unmountable_notification_title">"Poškozená karta SD"</string>
+ <string name="ext_media_unmountable_notification_message">"Karta SD je poškozená. Bude pravděpodobně nutné ji přeformátovat."</string>
+ <string name="ext_media_badremoval_notification_title">"Karta SD byla neoÄekávanÄ› odebrána"</string>
+ <string name="ext_media_badremoval_notification_message">"Chcete-li zabránit ztrátě dat, kartu SD před odebráním odpojte."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Kartu SD je možné bezpeÄnÄ› odebrat"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Kartu SD lze bezpeÄnÄ› odebrat."</string>
+ <string name="ext_media_nomedia_notification_title">"Karta SD byla odstraněna"</string>
+ <string name="ext_media_nomedia_notification_message">"Karta SD byla odebrána. Vložte novou kartu."</string>
+ <string name="activity_list_empty">"Nebyly nalezeny žádné odpovídající aktivity."</string>
+ <string name="permlab_pkgUsageStats">"aktualizovat statistiku použití souÄástí"</string>
+ <string name="permdesc_pkgUsageStats">"Umožňuje zmÄ›nu shromáždÄ›ných statistických údajů o použití souÄástí. Není urÄeno pro běžné aplikace."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Poklepáním můžete ovládat přiblížení"</string>
+ <string name="gadget_host_error_inflating">"Chyba při spouštění widgetu"</string>
+ <string name="ime_action_go">"Přejít"</string>
+ <string name="ime_action_search">"Hledat"</string>
+ <string name="ime_action_send">"Odeslat"</string>
+ <string name="ime_action_next">"Další"</string>
+ <string name="ime_action_done">"Hotovo"</string>
+ <string name="ime_action_default">"Spustit"</string>
+ <string name="dial_number_using">"VytoÄit Äíslo"\n" <xliff:g id="NUMBER">%s</xliff:g>."</string>
+ <string name="create_contact_using">"Vytvořit kontakt"\n"pro <xliff:g id="NUMBER">%s</xliff:g>."</string>
+ <string name="accessibility_compound_button_selected">"Zaškrtnuto"</string>
+ <string name="accessibility_compound_button_unselected">"Nezaškrtnuto"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index ef8490b..4add1f8 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"Kb"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"Mb"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"Gb"</string>
- <string name="terabyteShort" msgid="231613018159186962">"Tb"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"Pb"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"Kb"</string>
+ <string name="megabyteShort">"Mb"</string>
+ <string name="gigabyteShort">"Gb"</string>
+ <string name="terabyteShort">"Tb"</string>
+ <string name="petabyteShort">"Pb"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"&lt;uden navn&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Intet telefonnummer)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Ukendt)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Voicemail"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Forbindelsesproblemer eller ugyldigt MMI-nummer."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Tjenesten blev aktiveret."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Tjenesten blev aktiveret for:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Tjenesten er deaktiveret."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registreringen er afsluttet."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Sletning afsluttet."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Forkert adgangskode."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI-nummer afsluttet."</string>
- <string name="badPin" msgid="5085454289896032547">"Den gamle PIN-kode, du indtastede, er ikke korrekt."</string>
- <string name="badPuk" msgid="5702522162746042460">"Den indtastede PUK-kode er ikke korrekt."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"De indtastede PIN-koder stemmer ikke overens."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Indtast en PIN-kode på mellem 4 og 8 tal."</string>
- <string name="needPuk" msgid="919668385956251611">"Dit SIM-kort er låst med PUK-koden. Indtast PUK-koden for at låse den op."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Indtast PUK2-koden for at låse op for SIM-kortet."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Indgående opkalds-id"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Udgående opkalds-id"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Viderestilling af opkald"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Ventende opkald"</string>
- <string name="BaMmi" msgid="455193067926770581">"Opkaldsspærring"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Ændring af adgangskode"</string>
- <string name="PinMmi" msgid="3113117780361190304">"ændring af PIN-kode"</string>
+ <string name="untitled">"&lt;uden navn&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Intet telefonnummer)"</string>
+ <string name="unknownName">"(Ukendt)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Voicemail"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Forbindelsesproblemer eller ugyldigt MMI-nummer."</string>
+ <string name="serviceEnabled">"Tjenesten blev aktiveret."</string>
+ <string name="serviceEnabledFor">"Tjenesten blev aktiveret for:"</string>
+ <string name="serviceDisabled">"Tjenesten er deaktiveret."</string>
+ <string name="serviceRegistered">"Registreringen er afsluttet."</string>
+ <string name="serviceErased">"Sletning afsluttet."</string>
+ <string name="passwordIncorrect">"Forkert adgangskode."</string>
+ <string name="mmiComplete">"MMI-nummer afsluttet."</string>
+ <string name="badPin">"Den gamle PIN-kode, du indtastede, er ikke korrekt."</string>
+ <string name="badPuk">"Den indtastede PUK-kode er ikke korrekt."</string>
+ <string name="mismatchPin">"De indtastede PIN-koder stemmer ikke overens."</string>
+ <string name="invalidPin">"Indtast en PIN-kode på mellem 4 og 8 tal."</string>
+ <string name="needPuk">"Dit SIM-kort er låst med PUK-koden. Indtast PUK-koden for at låse den op."</string>
+ <string name="needPuk2">"Indtast PUK2-koden for at låse op for SIM-kortet."</string>
+ <string name="ClipMmi">"Indgående opkalds-id"</string>
+ <string name="ClirMmi">"Udgående opkalds-id"</string>
+ <string name="CfMmi">"Viderestilling af opkald"</string>
+ <string name="CwMmi">"Ventende opkald"</string>
+ <string name="BaMmi">"Opkaldsspærring"</string>
+ <string name="PwdMmi">"Ændring af adgangskode"</string>
+ <string name="PinMmi">"ændring af PIN-kode"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Standarder for opkalds-id til begrænset. Næste opkald: Begrænset"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Standarder for opkalds-id til begrænset. Næste opkald: Ikke begrænset"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Begrænset"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Ikke begrænset"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Tjenesten leveres ikke!"</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Indstillingen for opkalds-id kan ikke ændres."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Begrænset adgang ændret"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Datatjeneste er blokeret."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Nødtjeneste er blokeret."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Stemme-/SMS-tjeneste er blokeret."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Alle stemme-/SMS-tjenester er blokerede."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Stemme"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Data"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynkroniser"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synkroniser"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pakke"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Standarder for opkalds-id til begrænset. Næste opkald: Begrænset"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Standarder for opkalds-id til begrænset. Næste opkald: Ikke begrænset"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Begrænset"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Ikke begrænset"</string>
+ <string name="serviceNotProvisioned">"Tjenesten leveres ikke!"</string>
+ <string name="CLIRPermanent">"Indstillingen for opkalds-id kan ikke ændres."</string>
+ <string name="RestrictedChangedTitle">"Begrænset adgang ændret"</string>
+ <string name="RestrictedOnData">"Datatjeneste er blokeret."</string>
+ <string name="RestrictedOnEmergency">"Nødtjeneste er blokeret."</string>
+ <string name="RestrictedOnNormal">"Stemme-/SMS-tjeneste er blokeret."</string>
+ <string name="RestrictedOnAll">"Alle stemme-/SMS-tjenester er blokerede."</string>
+ <string name="serviceClassVoice">"Stemme"</string>
+ <string name="serviceClassData">"Data"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynkroniser"</string>
+ <string name="serviceClassDataSync">"Synkroniser"</string>
+ <string name="serviceClassPacket">"Pakke"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke videresendt"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Websiden indeholder en fejl."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Webadressen kunne ikke findes."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Planen for webstedsgodkendelse er ikke understøttet."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Godkendelse mislykkedes."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Godkendelse via proxyserveren mislykkedes."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Der kunne ikke oprettes forbindelse til serveren."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Serveren kunne ikke kommunikere. Prøv igen senere."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Der opstod timeout for forbindelsen til serveren."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Siden indeholder for mange serveromdirigeringer."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokollen understøttes ikke."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Der kunne ikke etableres en sikker forbindelse."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Siden kunne ikke åbnes, fordi webadressen er ugyldig."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Der kunne ikke oprettes adgang til filen."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Den anmodede fil blev ikke fundet."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Der behandles for mange anmodninger. Prøv igen senere."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synkroniser"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkroniser"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange <xliff:g id="CONTENT_TYPE">%s</xliff:g> sletninger"</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefonens lagerplads er fuld. Slet nogle filer for at frigøre plads."</string>
- <string name="me" msgid="6545696007631404292">"Mig"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefonvalgmuligheder"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Lydløs"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Slå trådløs til"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Slå trådløs fra"</string>
- <string name="screen_lock" msgid="799094655496098153">"Skærmlås"</string>
- <string name="power_off" msgid="4266614107412865048">"Sluk"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Lukker ned ..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Din telefon lukkes ned."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Der er ingen nye programmer."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefonvalgmuligheder"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Skærmlås"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lydløs"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er FRA"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er TIL"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flytilstand"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flytilstand er TIL"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flytilstand er FRA"</string>
- <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tjenester, der koster dig penge"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Tillader et program at gøre ting, som kan koste penge."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Dine beskeder"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Læs og skriv dine SMS-, e-mail- og andre beskeder."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Dine personlige oplysninger"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Få direkte adgang til dine kontakter og din kalender, der er gemt på telefonen."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Din placering"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Overvåg din fysiske placering"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Netværkskommunikation"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Tillader programmer at få adgang til forskellige netværksfunktioner."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Dine Google-konti"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Få adgang til tilgængelige Google-konti."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Hardwarekontroller"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Direkte adgang til hardware på håndsættet."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefonopkald"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Overvåg, registrer og behandl telefonopkald."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Systemværktøjer"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Adgang og kontrol til systemet på lavere niveau."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Udviklingsværktøjer"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funktioner kun til programudviklere."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Websiden indeholder en fejl."</string>
+ <string name="httpErrorLookup">"Webadressen kunne ikke findes."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Planen for webstedsgodkendelse er ikke understøttet."</string>
+ <string name="httpErrorAuth">"Godkendelse mislykkedes."</string>
+ <string name="httpErrorProxyAuth">"Godkendelse via proxyserveren mislykkedes."</string>
+ <string name="httpErrorConnect">"Der kunne ikke oprettes forbindelse til serveren."</string>
+ <string name="httpErrorIO">"Serveren kunne ikke kommunikere. Prøv igen senere."</string>
+ <string name="httpErrorTimeout">"Der opstod timeout for forbindelsen til serveren."</string>
+ <string name="httpErrorRedirectLoop">"Siden indeholder for mange serveromdirigeringer."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokollen understøttes ikke."</string>
+ <string name="httpErrorFailedSslHandshake">"Der kunne ikke etableres en sikker forbindelse."</string>
+ <string name="httpErrorBadUrl">"Siden kunne ikke åbnes, fordi webadressen er ugyldig."</string>
+ <string name="httpErrorFile">"Der kunne ikke oprettes adgang til filen."</string>
+ <string name="httpErrorFileNotFound">"Den anmodede fil blev ikke fundet."</string>
+ <string name="httpErrorTooManyRequests">"Der behandles for mange anmodninger. Prøv igen senere."</string>
+ <string name="contentServiceSync">"Synkroniser"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synkroniser"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"For mange <xliff:g id="CONTENT_TYPE">%s</xliff:g> sletninger"</string>
+ <string name="low_memory">"Telefonens lagerplads er fuld. Slet nogle filer for at frigøre plads."</string>
+ <string name="me">"Mig"</string>
+ <string name="power_dialog">"Telefonvalgmuligheder"</string>
+ <string name="silent_mode">"Lydløs"</string>
+ <string name="turn_on_radio">"Slå trådløs til"</string>
+ <string name="turn_off_radio">"Slå trådløs fra"</string>
+ <string name="screen_lock">"Skærmlås"</string>
+ <string name="power_off">"Sluk"</string>
+ <string name="shutdown_progress">"Lukker ned ..."</string>
+ <string name="shutdown_confirm">"Din telefon lukkes ned."</string>
+ <string name="no_recent_tasks">"Der er ingen nye programmer."</string>
+ <string name="global_actions">"Telefonvalgmuligheder"</string>
+ <string name="global_action_lock">"Skærmlås"</string>
+ <string name="global_action_power_off">"Sluk"</string>
+ <string name="global_action_toggle_silent_mode">"Lydløs"</string>
+ <string name="global_action_silent_mode_on_status">"Lyden er FRA"</string>
+ <string name="global_action_silent_mode_off_status">"Lyden er TIL"</string>
+ <string name="global_actions_toggle_airplane_mode">"Flytilstand"</string>
+ <string name="global_actions_airplane_mode_on_status">"Flytilstand er TIL"</string>
+ <string name="global_actions_airplane_mode_off_status">"Flytilstand er FRA"</string>
+ <string name="safeMode">"Sikker tilstand"</string>
+ <string name="android_system_label">"Android-system"</string>
+ <string name="permgrouplab_costMoney">"Tjenester, der koster dig penge"</string>
+ <string name="permgroupdesc_costMoney">"Tillader et program at gøre ting, som kan koste penge."</string>
+ <string name="permgrouplab_messages">"Dine beskeder"</string>
+ <string name="permgroupdesc_messages">"Læs og skriv dine SMS-, e-mail- og andre beskeder."</string>
+ <string name="permgrouplab_personalInfo">"Dine personlige oplysninger"</string>
+ <string name="permgroupdesc_personalInfo">"Få direkte adgang til dine kontaktpersoner og din kalender, der er gemt på telefonen."</string>
+ <string name="permgrouplab_location">"Din placering"</string>
+ <string name="permgroupdesc_location">"Overvåg din fysiske placering"</string>
+ <string name="permgrouplab_network">"Netværkskommunikation"</string>
+ <string name="permgroupdesc_network">"Tillader programmer at få adgang til forskellige netværksfunktioner."</string>
+ <string name="permgrouplab_accounts">"Dine Google-konti"</string>
+ <string name="permgroupdesc_accounts">"Få adgang til tilgængelige Google-konti."</string>
+ <string name="permgrouplab_hardwareControls">"Hardwarekontroller"</string>
+ <string name="permgroupdesc_hardwareControls">"Direkte adgang til hardware på håndsættet."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonopkald"</string>
+ <string name="permgroupdesc_phoneCalls">"Overvåg, registrer og behandl telefonopkald."</string>
+ <string name="permgrouplab_systemTools">"Systemværktøjer"</string>
+ <string name="permgroupdesc_systemTools">"Adgang og kontrol til systemet på lavere niveau."</string>
+ <string name="permgrouplab_developmentTools">"Udviklingsværktøjer"</string>
+ <string name="permgroupdesc_developmentTools">"Funktioner kun til programudviklere."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"deaktiver eller rediger statuslinje"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Tillader et program at deaktivere statuslinjen eller tilføje eller fjerne systemikoner."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"udvid/skjul statuslinje"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Tillader et program at udvide eller skjule statuslinjen."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"opfang udgående opkald"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Tillader et program at behandle udgående opkald og ændre nummeret, der skal ringes til. Ondsindede programmer kan overvåge, omdirigere eller forhindre udgående opkald."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"modtag SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Tillader et program at modtage og behandle SMS-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"modtag MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Tillader et program at modtage og behandle MMS-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"send SMS-beskeder"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Tillader et program at sende SMS-beskeder. Ondsindede programmer kan eventuelt koste dig penge ved at sende beskeder uden din bekræftelse."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"læs SMS eller MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Tillader et program at læse SMS-beskeder, der er gemt på din telefon eller dit SIM-kort. Ondsindede programmer kan eventuelt læse dine fortrolige beskeder."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"rediger SMS eller MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Tillader et program at skrive til SMS-beskeder, der er gemt på din telefon eller dit SIM-kort. Ondsindede programmer kan eventuelt slette dine beskeder."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"modtag WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Tillader et program at modtage og behandle WAP-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"hent kørende programmer"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Tillader et program at hente oplysninger om nuværende og for nyligt kørende opgaver. Tillader eventuelt ondsindede programmer at finde private oplysninger om andre programmer."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"omorganiser kørende programmer"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillader et program at flytte opgaver til forgrunden og baggrunden. Ondsindede programmer kan tvinge dem selv til forgrunden uden din kontrol."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"aktiver programfejlretning"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Tillader et program at slå fejlretning af andet program til. Ondsindede programmer kan bruge dette til at standse andre programmer."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"skift dine UI-indstillinger"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Tillader et program at ændre den nuværende konfiguration, som f.eks. den lokale eller overordnede skrifttypestørrelse."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"genstart andre programmer"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Tillader et program at tvangsgenstarte andre programmer."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"tving programmet til at lukke"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Tillader et program at tvinge alle programmer, der er i forgrunden, til at lukke og gå tilbage. Bør aldrig være nødvendigt til normale programmer."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"hent intern systemtilstand"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Tillader et program at hente systemets interne tilstand. Ondsindede programmer kan hente en række private og sikre oplysninger, som de normalt aldrig bør have brug for."</string>
+ <string name="permlab_statusBar">"deaktiver eller rediger statuslinje"</string>
+ <string name="permdesc_statusBar">"Tillader et program at deaktivere statuslinjen eller tilføje eller fjerne systemikoner."</string>
+ <string name="permlab_expandStatusBar">"udvid/skjul statuslinje"</string>
+ <string name="permdesc_expandStatusBar">"Tillader et program at udvide eller skjule statuslinjen."</string>
+ <string name="permlab_processOutgoingCalls">"opfang udgående opkald"</string>
+ <string name="permdesc_processOutgoingCalls">"Tillader et program at behandle udgående opkald og ændre nummeret, der skal ringes til. Ondsindede programmer kan overvåge, omdirigere eller forhindre udgående opkald."</string>
+ <string name="permlab_receiveSms">"modtag SMS"</string>
+ <string name="permdesc_receiveSms">"Tillader et program at modtage og behandle SMS-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
+ <string name="permlab_receiveMms">"modtag MMS"</string>
+ <string name="permdesc_receiveMms">"Tillader et program at modtage og behandle MMS-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
+ <string name="permlab_sendSms">"send SMS-beskeder"</string>
+ <string name="permdesc_sendSms">"Tillader et program at sende SMS-beskeder. Ondsindede programmer kan eventuelt koste dig penge ved at sende beskeder uden din bekræftelse."</string>
+ <string name="permlab_readSms">"læs SMS eller MMS"</string>
+ <string name="permdesc_readSms">"Tillader et program at læse SMS-beskeder, der er gemt på din telefon eller dit SIM-kort. Ondsindede programmer kan eventuelt læse dine fortrolige beskeder."</string>
+ <string name="permlab_writeSms">"rediger SMS eller MMS"</string>
+ <string name="permdesc_writeSms">"Tillader et program at skrive til SMS-beskeder, der er gemt på din telefon eller dit SIM-kort. Ondsindede programmer kan eventuelt slette dine beskeder."</string>
+ <string name="permlab_receiveWapPush">"modtag WAP"</string>
+ <string name="permdesc_receiveWapPush">"Tillader et program at modtage og behandle WAP-beskeder. Ondsindede programmer kan overvåge dine beskeder eller slette dem uden at vise dem til dig."</string>
+ <string name="permlab_getTasks">"hent kørende programmer"</string>
+ <string name="permdesc_getTasks">"Tillader et program at hente oplysninger om nuværende og for nyligt kørende opgaver. Tillader eventuelt ondsindede programmer at finde private oplysninger om andre programmer."</string>
+ <string name="permlab_reorderTasks">"omorganiser kørende programmer"</string>
+ <string name="permdesc_reorderTasks">"Tillader et program at flytte opgaver til forgrunden og baggrunden. Ondsindede programmer kan tvinge dem selv til forgrunden uden din kontrol."</string>
+ <string name="permlab_setDebugApp">"aktiver programfejlretning"</string>
+ <string name="permdesc_setDebugApp">"Tillader et program at slå fejlretning af andet program til. Ondsindede programmer kan bruge dette til at standse andre programmer."</string>
+ <string name="permlab_changeConfiguration">"skift dine UI-indstillinger"</string>
+ <string name="permdesc_changeConfiguration">"Tillader et program at ændre den nuværende konfiguration, som f.eks. den lokale eller overordnede skrifttypestørrelse."</string>
+ <string name="permlab_restartPackages">"genstart andre programmer"</string>
+ <string name="permdesc_restartPackages">"Tillader et program at tvangsgenstarte andre programmer."</string>
+ <string name="permlab_forceBack">"tving programmet til at lukke"</string>
+ <string name="permdesc_forceBack">"Tillader et program at tvinge alle programmer, der er i forgrunden, til at lukke og gå tilbage. Bør aldrig være nødvendigt til normale programmer."</string>
+ <string name="permlab_dump">"hent intern systemtilstand"</string>
+ <string name="permdesc_dump">"Tillader et program at hente systemets interne tilstand. Ondsindede programmer kan hente en række private og sikre oplysninger, som de normalt aldrig bør have brug for."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"overvåg og kontroller start af alle programmer"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Tillader et program at overvåge og kontrollere, hvordan systemet starter aktiviteter. Ondsindede programmer kan fuldstændig kompromittere systemet. Denne tilladelse er kun nødvendig til udvikling, aldrig til normal telefonbrug."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"send udsendelse om fjernet pakke"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Tillader et program at udsende en meddelelse om, at en programpakke er fjernet. Ondsindede programmer kan bruge dette til at afslutte et andet kørende program."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"send SMS-modtaget udsendelse"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Tillader et program at udsende en meddelelse om, at der er modtaget en SMS-besked. Ondsindede programmer kan eventuelt bruge dette til at forfalske indgående SMS-beskeder."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-modtaget udsendelse"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Tillader et program at udsende en meddelelse om, at der er modtaget en WAP PUSH-besked. Ondsindede programmer kan eventuelt bruge dette til at forfalske modtagelse af MMS-besked eller i det skjulte erstatte indholdet på alle websider med ondsindede varianter."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"begræns antallet af kørende processer"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Tillader et program at kontrollere det maksimale antal processer, der kan køre. Er aldrig nødvendigt til normale programmer."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"få alle baggrundsprogrammer til at lukke"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Tillader et program at kontrollere, om aktiviteter altid afsluttes, så snart de går i baggrunden. Aldrig nødvendigt til normale programmer."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"rediger batteristatistikker"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Tillader ændring af indsamlede batteristatistikker. Ikke til brug for normale programmer."</string>
+ <string name="permlab_runSetActivityWatcher">"overvåg og kontroller start af alle programmer"</string>
+ <string name="permdesc_runSetActivityWatcher">"Tillader et program at overvåge og kontrollere, hvordan systemet starter aktiviteter. Ondsindede programmer kan fuldstændig kompromittere systemet. Denne tilladelse er kun nødvendig til udvikling, aldrig til normal telefonbrug."</string>
+ <string name="permlab_broadcastPackageRemoved">"send udsendelse om fjernet pakke"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Tillader et program at udsende en meddelelse om, at en programpakke er fjernet. Ondsindede programmer kan bruge dette til at afslutte et andet kørende program."</string>
+ <string name="permlab_broadcastSmsReceived">"send SMS-modtaget udsendelse"</string>
+ <string name="permdesc_broadcastSmsReceived">"Tillader et program at udsende en meddelelse om, at der er modtaget en SMS-besked. Ondsindede programmer kan eventuelt bruge dette til at forfalske indgående SMS-beskeder."</string>
+ <string name="permlab_broadcastWapPush">"send WAP-PUSH-modtaget udsendelse"</string>
+ <string name="permdesc_broadcastWapPush">"Tillader et program at udsende en meddelelse om, at der er modtaget en WAP PUSH-besked. Ondsindede programmer kan eventuelt bruge dette til at forfalske modtagelse af MMS-besked eller i det skjulte erstatte indholdet på alle websider med ondsindede varianter."</string>
+ <string name="permlab_setProcessLimit">"begræns antallet af kørende processer"</string>
+ <string name="permdesc_setProcessLimit">"Tillader et program at kontrollere det maksimale antal processer, der kan køre. Er aldrig nødvendigt til normale programmer."</string>
+ <string name="permlab_setAlwaysFinish">"få alle baggrundsprogrammer til at lukke"</string>
+ <string name="permdesc_setAlwaysFinish">"Tillader et program at kontrollere, om aktiviteter altid afsluttes, så snart de går i baggrunden. Aldrig nødvendigt til normale programmer."</string>
+ <string name="permlab_batteryStats">"rediger batteristatistikker"</string>
+ <string name="permdesc_batteryStats">"Tillader ændring af indsamlede batteristatistikker. Ikke til brug for normale programmer."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"vis uautoriserede vinduer"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Tillader oprettelse af vinduer, der er beregnet til at blive brugt af den interne systembrugergrænseflade. Ikke til brug for normale programmer."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"vis underretninger på systemniveau"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Tillader et program at vise systemunderretningsvinduer. Ondsindede programmer kan overtage hele telefonens skærm."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"rediger global animationshastighed"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Tillader et program at ændre den globale animationshastighed (hurtigere eller langsommere animationer) når som helst."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"administrer programtokens"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Tillader programmet at oprette og administrere deres egen tokens og gå uden om deres normale Z-rækkefølge. Bør aldrig være nødvendigt til normale programmer."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"tryk på taster og kontrolknapper"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Tillader et program at levere sine egne inputbegivenheder (tastetryk osv.) til andre programmer. Ondsindede programmer kan bruge dette til at overtage telefonen."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"registrerer, hvad du indtaster, og hvilke handlinger du foretager dig"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Tillader et program at holde øje med de taster, du trykker på, selv når du interagerer med andre programmer (som f.eks. indtastning af adgangskode). Bør aldrig være nødvendigt til normale programmer."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"forpligt til en inputmetode"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Tillader brugeren at forpligte sig på en inputmetodes grænseflade på øverste niveau. Bør aldrig være nødvendig til normale programmer."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"skift skærmretning"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Tillader et program at ændre rotationen af skærmen når som helst. Bør aldrig være nødvendigt til normale programmer."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"send Linux-signaler til programmer"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Tillader program at anmode om, at det leverede signal sendes til alle vedholdende processer."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"lad altid programmet køre"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Tillader et program at gøre dele af sig selv vedholdende, så systemet ikke kan bruge det til andre programmer."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"slet programmer"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Tillader et program at slette Android-pakker. Ondsindede programmer kan bruge dette til at slette vigtige programmer."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"slet andre programmers data"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Lader et program rydde brugerdata."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"slet andre programmers cacher"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Tillader et program at slette cachefiler."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"måler programmets lagerplads"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Tillader et program at hente dets kode, data og cachestørrelser"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"installer programmer direkte"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Tillader et program at installere nye eller opdaterede Android-pakker. Ondsindede programmer kan bruge dette til at tilføje nye programmer med vilkårlige, effektive tilladelser."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"slet alle cachedata for programmet"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Tillader et program at frigøre plads på telefonen ved at slette filer i programmets cachemappe. Adgang er normalt meget begrænset til systemprocesser."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"læs systemlogfiler"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Tillader et program at læse fra systemets forskellige logfiler. Dermed kan generelle oplysninger om, hvad du laver med telefonen, opdages, men logfilerne skulle ikke indeholde personlige eller private oplysninger."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Tillader et program at læse og skrive til alle ressourcer, der ejes af diag-gruppen, som f.eks. flier i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifikke diagnosticeringer foretaget af producent eller udbyder."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"aktiver eller deaktiver programkomponenter"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Tillader et program at ændre, om en komponent fra et andet program er aktiveret eller ej. Ondsindede programmer kan bruge dette til at deaktivere vigtige telefonfunktioner. Denne tilladelse skal anvendes med forsigtighed, da det kan forårsage ubrugelige, inkonsekvente eller ustabile programkomponenter."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"indstil foretrukne programmer"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Tillader et program at ændre dine foretrukne programmer. Dette kan tillade, at ondsindede programmer ændrer kørende programmer i det skjulte og narrer dine eksisterende programmer til at indsamle personlige data fra dig."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"rediger globale systemindstillinger"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Tillader et program at ændre systemets indstillingsdata. Ondsindede programmer kan skade systemets konfiguration."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"rediger sikre systemindstillinger"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Tillader et program at ændre systemernes sikre indstillingsdata. Ikke til brug til almindelige programmer."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"rediger kortet over Google-tjenester"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Tillader et program at ændre kortet over Google-tjenester. Ikke til brug til normale programmer."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"start automatisk ved opstart"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Tillader et program at starte selv, når systemet er færdig med at starte. Dette kan gøre start af telefonen langsommere og generelt gøre telefonen langsommere ved altid at lade programmet køre."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"send klæbende udsendelse"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Tillader et program at sende klæbende udsendelser, der bliver tilbage, efter udsendelsen er slut. Ondsindede programmer kan gøre telefonen langsom eller ustabil ved at få den til at bruge for meget hukommelse."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"læs kontaktdata"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Tillader et program at læse alle kontaktdata (adresse), der er gemt på din telefon. Ondsindede programmer kan bruge dette til at sende dine data til andre mennesker."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"skriv kontaktdata"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Tillader et program at ændre telefonens kontaktdata (adresse), der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre kontaktdata."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"skriv ejerdata"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Tillader et program at ændre telefonens ejerdata, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre ejerdata."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"læs ejerdata"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Tillader et program at læse telefonens ejerdata, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at læse ejerdata."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"læs kalenderdata"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Tillader et program at læse alle kalenderbegivenheder, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at sende dine kalenderbegivenheder til andre mennesker."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"skriv kalenderdata"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Tillader et program at ændre telefonens kalenderbegivenheder, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre kalenderdata."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"imiterede placeringskilder til test"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Opret imiterede placeringskilder til testning. Ondsindede programmer kan bruge dette til at tilsidesætte den returnerede placering og/eller status fra rigtige placeringskilder som f.eks. GPS eller netværksudbydere."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"få adgang til ekstra kommandoer for placeringsudbyder"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"FÃ¥ adgang til ekstra kommandoer fra placeringsudbyder. Ondsindede programmer kan bruge dette til at gribe ind i driften af GPS\'en eller andre placeringskilder."</string>
+ <string name="permlab_internalSystemWindow">"vis uautoriserede vinduer"</string>
+ <string name="permdesc_internalSystemWindow">"Tillader oprettelse af vinduer, der er beregnet til at blive brugt af den interne systembrugergrænseflade. Ikke til brug for normale programmer."</string>
+ <string name="permlab_systemAlertWindow">"vis underretninger på systemniveau"</string>
+ <string name="permdesc_systemAlertWindow">"Tillader et program at vise systemunderretningsvinduer. Ondsindede programmer kan overtage hele telefonens skærm."</string>
+ <string name="permlab_setAnimationScale">"rediger global animationshastighed"</string>
+ <string name="permdesc_setAnimationScale">"Tillader et program at ændre den globale animationshastighed (hurtigere eller langsommere animationer) når som helst."</string>
+ <string name="permlab_manageAppTokens">"administrer programtokens"</string>
+ <string name="permdesc_manageAppTokens">"Tillader programmet at oprette og administrere deres egen tokens og gå uden om deres normale Z-rækkefølge. Bør aldrig være nødvendigt til normale programmer."</string>
+ <string name="permlab_injectEvents">"tryk på taster og kontrolknapper"</string>
+ <string name="permdesc_injectEvents">"Tillader et program at levere sine egne inputbegivenheder (tastetryk osv.) til andre programmer. Ondsindede programmer kan bruge dette til at overtage telefonen."</string>
+ <string name="permlab_readInputState">"registrerer, hvad du indtaster, og hvilke handlinger du foretager dig"</string>
+ <string name="permdesc_readInputState">"Tillader et program at holde øje med de taster, du trykker på, selv når du interagerer med andre programmer (som f.eks. indtastning af adgangskode). Bør aldrig være nødvendigt til normale programmer."</string>
+ <string name="permlab_bindInputMethod">"forpligt til en inputmetode"</string>
+ <string name="permdesc_bindInputMethod">"Tillader brugeren at forpligte sig på en inputmetodes grænseflade på øverste niveau. Bør aldrig være nødvendig til normale programmer."</string>
+ <string name="permlab_setOrientation">"skift skærmretning"</string>
+ <string name="permdesc_setOrientation">"Tillader et program at ændre rotationen af skærmen når som helst. Bør aldrig være nødvendigt til normale programmer."</string>
+ <string name="permlab_signalPersistentProcesses">"send Linux-signaler til programmer"</string>
+ <string name="permdesc_signalPersistentProcesses">"Tillader program at anmode om, at det leverede signal sendes til alle vedholdende processer."</string>
+ <string name="permlab_persistentActivity">"lad altid programmet køre"</string>
+ <string name="permdesc_persistentActivity">"Tillader et program at gøre dele af sig selv vedholdende, så systemet ikke kan bruge det til andre programmer."</string>
+ <string name="permlab_deletePackages">"slet programmer"</string>
+ <string name="permdesc_deletePackages">"Tillader et program at slette Android-pakker. Ondsindede programmer kan bruge dette til at slette vigtige programmer."</string>
+ <string name="permlab_clearAppUserData">"slet andre programmers data"</string>
+ <string name="permdesc_clearAppUserData">"Lader et program rydde brugerdata."</string>
+ <string name="permlab_deleteCacheFiles">"slet andre programmers cacher"</string>
+ <string name="permdesc_deleteCacheFiles">"Tillader et program at slette cachefiler."</string>
+ <string name="permlab_getPackageSize">"måler programmets lagerplads"</string>
+ <string name="permdesc_getPackageSize">"Tillader et program at hente dets kode, data og cachestørrelser"</string>
+ <string name="permlab_installPackages">"installer programmer direkte"</string>
+ <string name="permdesc_installPackages">"Tillader et program at installere nye eller opdaterede Android-pakker. Ondsindede programmer kan bruge dette til at tilføje nye programmer med vilkårlige, effektive tilladelser."</string>
+ <string name="permlab_clearAppCache">"slet alle cachedata for programmet"</string>
+ <string name="permdesc_clearAppCache">"Tillader et program at frigøre plads på telefonen ved at slette filer i programmets cachemappe. Adgang er normalt meget begrænset til systemprocesser."</string>
+ <string name="permlab_readLogs">"læs systemlogfiler"</string>
+ <string name="permdesc_readLogs">"Tillader et program at læse fra systemets forskellige logfiler. Dermed kan generelle oplysninger om, hvad du laver med telefonen, opdages, men logfilerne skulle ikke indeholde personlige eller private oplysninger."</string>
+ <string name="permlab_diagnostic">"læs/skriv til ressourcer ejet af diag"</string>
+ <string name="permdesc_diagnostic">"Tillader et program at læse og skrive til alle ressourcer, der ejes af diag-gruppen, som f.eks. flier i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifikke diagnosticeringer foretaget af producent eller udbyder."</string>
+ <string name="permlab_changeComponentState">"aktiver eller deaktiver programkomponenter"</string>
+ <string name="permdesc_changeComponentState">"Tillader et program at ændre, om en komponent fra et andet program er aktiveret eller ej. Ondsindede programmer kan bruge dette til at deaktivere vigtige telefonfunktioner. Denne tilladelse skal anvendes med forsigtighed, da det kan forårsage ubrugelige, inkonsekvente eller ustabile programkomponenter."</string>
+ <string name="permlab_setPreferredApplications">"indstil foretrukne programmer"</string>
+ <string name="permdesc_setPreferredApplications">"Tillader et program at ændre dine foretrukne programmer. Dette kan tillade, at ondsindede programmer ændrer kørende programmer i det skjulte og narrer dine eksisterende programmer til at indsamle personlige data fra dig."</string>
+ <string name="permlab_writeSettings">"rediger globale systemindstillinger"</string>
+ <string name="permdesc_writeSettings">"Tillader et program at ændre systemets indstillingsdata. Ondsindede programmer kan skade systemets konfiguration."</string>
+ <string name="permlab_writeSecureSettings">"rediger sikre systemindstillinger"</string>
+ <string name="permdesc_writeSecureSettings">"Tillader et program at ændre systemernes sikre indstillingsdata. Ikke til brug til almindelige programmer."</string>
+ <string name="permlab_writeGservices">"rediger kortet over Google-tjenester"</string>
+ <string name="permdesc_writeGservices">"Tillader et program at ændre kortet over Google-tjenester. Ikke til brug til normale programmer."</string>
+ <string name="permlab_receiveBootCompleted">"start automatisk ved opstart"</string>
+ <string name="permdesc_receiveBootCompleted">"Tillader et program at starte selv, når systemet er færdig med at starte. Dette kan gøre start af telefonen langsommere og generelt gøre telefonen langsommere ved altid at lade programmet køre."</string>
+ <string name="permlab_broadcastSticky">"send klæbende udsendelse"</string>
+ <string name="permdesc_broadcastSticky">"Tillader et program at sende klæbende udsendelser, der bliver tilbage, efter udsendelsen er slut. Ondsindede programmer kan gøre telefonen langsom eller ustabil ved at få den til at bruge for meget hukommelse."</string>
+ <string name="permlab_readContacts">"læs kontaktpersondata"</string>
+ <string name="permdesc_readContacts">"Tillader et program at læse alle kontaktpersondata (adresse), der er gemt på din telefon. Ondsindede programmer kan bruge dette til at sende dine data til andre mennesker."</string>
+ <string name="permlab_writeContacts">"skriv kontaktpersondata"</string>
+ <string name="permdesc_writeContacts">"Tillader et program at ændre telefonens kontaktpersondata (adresse), der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre kontaktpersondata."</string>
+ <string name="permlab_writeOwnerData">"skriv ejerdata"</string>
+ <string name="permdesc_writeOwnerData">"Tillader et program at ændre telefonens ejerdata, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre ejerdata."</string>
+ <string name="permlab_readOwnerData">"læs ejerdata"</string>
+ <string name="permdesc_readOwnerData">"Tillader et program at læse telefonens ejerdata, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at læse ejerdata."</string>
+ <string name="permlab_readCalendar">"læs kalenderdata"</string>
+ <string name="permdesc_readCalendar">"Tillader et program at læse alle kalenderbegivenheder, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at sende dine kalenderbegivenheder til andre mennesker."</string>
+ <string name="permlab_writeCalendar">"skriv kalenderdata"</string>
+ <string name="permdesc_writeCalendar">"Tillader et program at ændre telefonens kalenderbegivenheder, der er gemt på din telefon. Ondsindede programmer kan bruge dette til at slette eller ændre kalenderdata."</string>
+ <string name="permlab_accessMockLocation">"imiterede placeringskilder til test"</string>
+ <string name="permdesc_accessMockLocation">"Opret imiterede placeringskilder til testning. Ondsindede programmer kan bruge dette til at tilsidesætte den returnerede placering og/eller status fra rigtige placeringskilder som f.eks. GPS eller netværksudbydere."</string>
+ <string name="permlab_accessLocationExtraCommands">"få adgang til ekstra kommandoer for placeringsudbyder"</string>
+ <string name="permdesc_accessLocationExtraCommands">"FÃ¥ adgang til ekstra kommandoer fra placeringsudbyder. Ondsindede programmer kan bruge dette til at gribe ind i driften af GPS\'en eller andre placeringskilder."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"fin (GPS) placering"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Få adgang til gode placeringskilder, som f.eks. Global Positioning System på telefonen, når det er tilgængeligt. Ondsindede programmer kan bruge dette til at finde ud af, hvor du er og kan eventuelt bruge yderligere batterikapacitet."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"grov (netværksbaseret) placering"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Få adgang til grove placeringskilder som f.eks. den mobile netværksdatabase for at finde en omtrentlig placering for telefonen, hvor det er muligt. Ondsindede programmer kan bruge dette til at finde ud af, hvor du omtrent er."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"få adgang til SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Tillader et program at bruge SurfaceFlinger-funktioner på lavt niveau."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"læs rammebuffer"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Tillader et program at læse/bruge indholdet fra rammebufferen."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"skift dine lydindstillinger"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Tillader et program at ændre globale lydindstillinger som f.eks. lydstyrke og kanalisering."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"optag lyd"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Tillader et program at få adgang til lydregistreringsstien."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"tag billeder"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Tillader programmet at tage billeder med kameraet. Dette tillader programmet til hver en tid at indsamle de billeder, kameraet ser."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"deaktiver telefonen permanent"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Tillader programmet at deaktivere hele telefonen permanent. Dette er meget farligt."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"tving telefon til at genstarte"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Tillader programmet at tvinge telefonen til at genstarte."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"monter eller demonter filsystemer"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Tillader programmet at montere eller demontere filsystemer til flytbar lagring."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formater ekstern lagring"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Tillader et program at formatere flytbar lagring."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"kontroller vibrator"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Lader programmet kontrollere vibratoren."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontroller lommelygte"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Tillader programmet at kontrollere lommelygten."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"test hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Tillader et program at kontrollere forskellige perifere enheder med det formål at teste hardwaren."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"ring direkte op til telefonnumre"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Tillader programmet at ringe til telefonnumre uden din indgriben. Ondsindede programmer kan forårsage uventede opkald på din telefonregning. Vær opmærksom på, at det ikke tillader programmet at ringe til nødnumre."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"ring direkte op til alle telefonnumre"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Tillader programmet at ringe til alle telefonnumre inklusive nødnumre uden din indgriben. Ondsindede programmer kan eventuelt foretage unødvendige og ulovlige opkald til nødtjenester."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontroller meddelelser om placeringsopdatering"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Tillader aktivering/deaktivering af placeringsdata fra radioen. Ikke til brug til normale programmer."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"egenskaber for adgangskontrol"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Tillader læse/skrive-adgang til egenskaber, der er uploadet af kontroltjenesten. Ikke til brug til normale programmer."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"vælg widgets"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Tillader programmet at fortælle systemet, hvilke widgets der kan bruges af hvilke programmer. Med denne tilladelse kan programmer give adgang til personlige data til andre programmer. Ikke til brug til normale programmer."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"rediger telefontilstand"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Tillader programmet at kontrollere enhedens telefonfunktioner. Et program med denne tilladelse kan skifte netværk, slå telefonens radio til og fra og lignende uden nogensinde at underrette dig."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"afhold telefonen fra at gå i dvale"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Tillader et program at forhindre telefonen i at gå i dvale."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"Tænd eller sluk for telefonen"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Tillader programmet at slå telefonen til eller fra."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"kør i fabriksindstillet testtilstand"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Kør som en producenttest på lavt niveau. Giver fuld adgang til telefonens hardware. Kun tilgængeligt når en telefon kører i producenttesttilstand."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"angiv tapet"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Tillader programmet at opsætte systemets tapet."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"opsæt tip til tapetstørrelse"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Tillader programmet at opsætte størrelsestip for systemets tapet."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"nulstil system til fabriksstandarder"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Tillader et program fuldstændig at nulstille systemet til fabriksindstillingerne, slette alle data, konfigurationen og installerede programmer."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"indstil tidszone"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Tillader et program at ændre telefonens tidszone."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"opdag kendte konti"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Tillader et program at hente listen over konti, der er kendt af telefonen."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"vis netværkstilstand"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Tillader et program at vise tilstanden for alle netværk."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"Fuld internetadgang"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Tillader et program at oprette netværks-sockets."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"skriv indstillinger for adgangspunktnavn"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Tillader et program at ændre APN-indstillingerne, som f.eks. enhver APNs Proxy og Port."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"skift netværksforbindelse"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Tillader et program at ændre netværksforbindelsens tilstand."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"skift brugerindstilling for baggrundsdata"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Tillader et program at ændre brugerindstillingerne for baggrundsdata."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"vis Wi-Fi-tilstand"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Tillader et program at vise oplysninger om Wi-Fi-tilstanden."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"skift Wi-Fi-tilstand"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Tillader et program at oprette og afbryde forbindelse fra Wi-Fi-adgangspunkter og foretage ændringer til konfigurerede Wi-Fi-netværk."</string>
+ <string name="permlab_accessFineLocation">"fin (GPS) placering"</string>
+ <string name="permdesc_accessFineLocation">"Få adgang til gode placeringskilder, som f.eks. Global Positioning System på telefonen, når det er tilgængeligt. Ondsindede programmer kan bruge dette til at finde ud af, hvor du er og kan eventuelt bruge yderligere batterikapacitet."</string>
+ <string name="permlab_accessCoarseLocation">"grov (netværksbaseret) placering"</string>
+ <string name="permdesc_accessCoarseLocation">"Få adgang til grove placeringskilder som f.eks. den mobile netværksdatabase for at finde en omtrentlig placering for telefonen, hvor det er muligt. Ondsindede programmer kan bruge dette til at finde ud af, hvor du omtrent er."</string>
+ <string name="permlab_accessSurfaceFlinger">"få adgang til SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Tillader et program at bruge SurfaceFlinger-funktioner på lavt niveau."</string>
+ <string name="permlab_readFrameBuffer">"læs rammebuffer"</string>
+ <string name="permdesc_readFrameBuffer">"Tillader et program at læse/bruge indholdet fra rammebufferen."</string>
+ <string name="permlab_modifyAudioSettings">"skift dine lydindstillinger"</string>
+ <string name="permdesc_modifyAudioSettings">"Tillader et program at ændre globale lydindstillinger som f.eks. lydstyrke og kanalisering."</string>
+ <string name="permlab_recordAudio">"optag lyd"</string>
+ <string name="permdesc_recordAudio">"Tillader et program at få adgang til lydregistreringsstien."</string>
+ <string name="permlab_camera">"tag billeder"</string>
+ <string name="permdesc_camera">"Tillader programmet at tage billeder med kameraet. Dette tillader programmet til hver en tid at indsamle de billeder, kameraet ser."</string>
+ <string name="permlab_brick">"deaktiver telefonen permanent"</string>
+ <string name="permdesc_brick">"Tillader programmet at deaktivere hele telefonen permanent. Dette er meget farligt."</string>
+ <string name="permlab_reboot">"tving telefon til at genstarte"</string>
+ <string name="permdesc_reboot">"Tillader programmet at tvinge telefonen til at genstarte."</string>
+ <string name="permlab_mount_unmount_filesystems">"monter eller demonter filsystemer"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Tillader programmet at montere eller demontere filsystemer til flytbar lagring."</string>
+ <string name="permlab_mount_format_filesystems">"formater ekstern lagring"</string>
+ <string name="permdesc_mount_format_filesystems">"Tillader et program at formatere flytbar lagring."</string>
+ <string name="permlab_vibrate">"kontroller vibrator"</string>
+ <string name="permdesc_vibrate">"Lader programmet kontrollere vibratoren."</string>
+ <string name="permlab_flashlight">"kontroller lommelygte"</string>
+ <string name="permdesc_flashlight">"Tillader programmet at kontrollere lommelygten."</string>
+ <string name="permlab_hardware_test">"test hardware"</string>
+ <string name="permdesc_hardware_test">"Tillader et program at kontrollere forskellige perifere enheder med det formål at teste hardwaren."</string>
+ <string name="permlab_callPhone">"ring direkte op til telefonnumre"</string>
+ <string name="permdesc_callPhone">"Tillader programmet at ringe til telefonnumre uden din indgriben. Ondsindede programmer kan forårsage uventede opkald på din telefonregning. Vær opmærksom på, at det ikke tillader programmet at ringe til nødnumre."</string>
+ <string name="permlab_callPrivileged">"ring direkte op til alle telefonnumre"</string>
+ <string name="permdesc_callPrivileged">"Tillader programmet at ringe til alle telefonnumre inklusive nødnumre uden din indgriben. Ondsindede programmer kan eventuelt foretage unødvendige og ulovlige opkald til nødtjenester."</string>
+ <string name="permlab_locationUpdates">"kontroller meddelelser om placeringsopdatering"</string>
+ <string name="permdesc_locationUpdates">"Tillader aktivering/deaktivering af placeringsdata fra radioen. Ikke til brug til normale programmer."</string>
+ <string name="permlab_checkinProperties">"egenskaber for adgangskontrol"</string>
+ <string name="permdesc_checkinProperties">"Tillader læse/skrive-adgang til egenskaber, der er uploadet af kontroltjenesten. Ikke til brug til normale programmer."</string>
+ <string name="permlab_bindGadget">"vælg widgets"</string>
+ <string name="permdesc_bindGadget">"Tillader programmet at fortælle systemet, hvilke widgets der kan bruges af hvilke programmer. Med denne tilladelse kan programmer give adgang til personlige data til andre programmer. Ikke til brug til normale programmer."</string>
+ <string name="permlab_modifyPhoneState">"rediger telefontilstand"</string>
+ <string name="permdesc_modifyPhoneState">"Tillader programmet at kontrollere enhedens telefonfunktioner. Et program med denne tilladelse kan skifte netværk, slå telefonens radio til og fra og lignende uden nogensinde at underrette dig."</string>
+ <string name="permlab_readPhoneState">"læs telefontilstand"</string>
+ <string name="permdesc_readPhoneState">"Tillader programmet at få adgang til enhedens telefonfunktioner. Et program med denne tilladelse kan afgøre denne telefons nummer, om et opkald er aktivt, nummeret som opkaldet er forbundet til osv."</string>
+ <string name="permlab_wakeLock">"afhold telefonen fra at gå i dvale"</string>
+ <string name="permdesc_wakeLock">"Tillader et program at forhindre telefonen i at gå i dvale."</string>
+ <string name="permlab_devicePower">"Tænd eller sluk for telefonen"</string>
+ <string name="permdesc_devicePower">"Tillader programmet at slå telefonen til eller fra."</string>
+ <string name="permlab_factoryTest">"kør i fabriksindstillet testtilstand"</string>
+ <string name="permdesc_factoryTest">"Kør som en producenttest på lavt niveau. Giver fuld adgang til telefonens hardware. Kun tilgængeligt når en telefon kører i producenttesttilstand."</string>
+ <string name="permlab_setWallpaper">"angiv tapet"</string>
+ <string name="permdesc_setWallpaper">"Tillader programmet at opsætte systemets tapet."</string>
+ <string name="permlab_setWallpaperHints">"opsæt tip til tapetstørrelse"</string>
+ <string name="permdesc_setWallpaperHints">"Tillader programmet at opsætte størrelsestip for systemets tapet."</string>
+ <string name="permlab_masterClear">"nulstil system til fabriksstandarder"</string>
+ <string name="permdesc_masterClear">"Tillader et program fuldstændig at nulstille systemet til fabriksindstillingerne, slette alle data, konfigurationen og installerede programmer."</string>
+ <string name="permlab_setTimeZone">"indstil tidszone"</string>
+ <string name="permdesc_setTimeZone">"Tillader et program at ændre telefonens tidszone."</string>
+ <string name="permlab_getAccounts">"opdag kendte konti"</string>
+ <string name="permdesc_getAccounts">"Tillader et program at hente listen over konti, der er kendt af telefonen."</string>
+ <string name="permlab_accessNetworkState">"vis netværkstilstand"</string>
+ <string name="permdesc_accessNetworkState">"Tillader et program at vise tilstanden for alle netværk."</string>
+ <string name="permlab_createNetworkSockets">"Fuld internetadgang"</string>
+ <string name="permdesc_createNetworkSockets">"Tillader et program at oprette netværks-sockets."</string>
+ <string name="permlab_writeApnSettings">"skriv indstillinger for adgangspunktnavn"</string>
+ <string name="permdesc_writeApnSettings">"Tillader et program at ændre APN-indstillingerne, som f.eks. enhver APNs Proxy og Port."</string>
+ <string name="permlab_changeNetworkState">"skift netværksforbindelse"</string>
+ <string name="permdesc_changeNetworkState">"Tillader et program at ændre netværksforbindelsens tilstand."</string>
+ <string name="permlab_changeBackgroundDataSetting">"skift brugerindstilling for baggrundsdata"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Tillader et program at ændre brugerindstillingerne for baggrundsdata."</string>
+ <string name="permlab_accessWifiState">"vis Wi-Fi-tilstand"</string>
+ <string name="permdesc_accessWifiState">"Tillader et program at vise oplysninger om Wi-Fi-tilstanden."</string>
+ <string name="permlab_changeWifiState">"skift Wi-Fi-tilstand"</string>
+ <string name="permdesc_changeWifiState">"Tillader et program at oprette og afbryde forbindelse fra Wi-Fi-adgangspunkter og foretage ændringer til konfigurerede Wi-Fi-netværk."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth-administration"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Tillader et program at konfigurere den lokale Bluetooth-telefon samt at opdage og parre med fjerne enheder."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"opret Bluetooth-forbindelser"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Tillader et program at vise konfigurationen af den lokale Bluetooth-telefon samt at oprette og acceptere forbindelse med parrede enheder."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"deaktiver tastaturlås"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Tillader et program at deaktivere tastaturlåsen og al associeret adgangskodesikkerhed. Et legitimt eksempel på dette er, at telefonen deaktiverer tastaturlåsen, når der modtages et indgående telefonopkald, og genaktiverer tastaturlåsen, når opkaldet er afsluttet."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"læs synkroniseringsindstillinger"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Tillader et program at læse synkroniseringsindstillingerne, som f.eks. om synkronisering er aktiveret for kontakter."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"skriv synkroniseringsindstillinger"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Tillader et program at ændre synkroniseringsindstillingerne, som f.eks. om synkronisering er aktiveret for kontakter."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"læs synkroniseringsstatistikker"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Tillader et program at læse synkroniseringsstatistikkerne, som f.eks. oversigt over forekomne synkroniseringer."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"læs abonnerede feeds"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Lader et program få detaljer om de aktuelt synkroniserede feeds."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"skriv abonnerede feeds"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Tillader et program at ændre dine aktuelle synkroniserede feeds. Dette kan muligvis lade et ondsindet program ændre dine synkroniserede feeds."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"læs brugerdefineret ordbog"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Tillader et program at læse alle private ord, navne og sætninger, som brugeren eventuelt har gemt i brugerordbogen."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"skriv til den brugerdefinerede mappe"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Tillader et program at skrive nye ord i brugermappen."</string>
+ <string name="permlab_bluetoothAdmin">"bluetooth-administration"</string>
+ <string name="permdesc_bluetoothAdmin">"Tillader et program at konfigurere den lokale Bluetooth-telefon samt at opdage og parre med fjerne enheder."</string>
+ <string name="permlab_bluetooth">"opret Bluetooth-forbindelser"</string>
+ <string name="permdesc_bluetooth">"Tillader et program at vise konfigurationen af den lokale Bluetooth-telefon samt at oprette og acceptere forbindelse med parrede enheder."</string>
+ <string name="permlab_disableKeyguard">"deaktiver tastaturlås"</string>
+ <string name="permdesc_disableKeyguard">"Tillader et program at deaktivere tastaturlåsen og al associeret adgangskodesikkerhed. Et legitimt eksempel på dette er, at telefonen deaktiverer tastaturlåsen, når der modtages et indgående telefonopkald, og genaktiverer tastaturlåsen, når opkaldet er afsluttet."</string>
+ <string name="permlab_readSyncSettings">"læs synkroniseringsindstillinger"</string>
+ <string name="permdesc_readSyncSettings">"Tillader et program at læse synkroniseringsindstillingerne, som f.eks. om synkronisering er aktiveret for kontaktpersoner."</string>
+ <string name="permlab_writeSyncSettings">"skriv synkroniseringsindstillinger"</string>
+ <string name="permdesc_writeSyncSettings">"Tillader et program at ændre synkroniseringsindstillingerne, som f.eks. om synkronisering er aktiveret for kontaktpersoner."</string>
+ <string name="permlab_readSyncStats">"læs synkroniseringsstatistikker"</string>
+ <string name="permdesc_readSyncStats">"Tillader et program at læse synkroniseringsstatistikkerne, som f.eks. oversigt over forekomne synkroniseringer."</string>
+ <string name="permlab_subscribedFeedsRead">"læs abonnerede feeds"</string>
+ <string name="permdesc_subscribedFeedsRead">"Lader et program få detaljer om de aktuelt synkroniserede feeds."</string>
+ <string name="permlab_subscribedFeedsWrite">"skriv abonnerede feeds"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Tillader et program at ændre dine aktuelle synkroniserede feeds. Dette kan muligvis lade et ondsindet program ændre dine synkroniserede feeds."</string>
+ <string name="permlab_readDictionary">"læs brugerdefineret ordbog"</string>
+ <string name="permdesc_readDictionary">"Tillader et program at læse alle private ord, navne og sætninger, som brugeren eventuelt har gemt i brugerordbogen."</string>
+ <string name="permlab_writeDictionary">"skriv til den brugerdefinerede mappe"</string>
+ <string name="permdesc_writeDictionary">"Tillader et program at skrive nye ord i brugermappen."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Start"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Arbejde"</item>
- <item msgid="1103601433382158155">"Arbejdsfax"</item>
- <item msgid="1735177144948329370">"Hjemmefax"</item>
- <item msgid="603878674477207394">"Personsøger"</item>
- <item msgid="1650824275177931637">"Andet"</item>
- <item msgid="9192514806975898961">"Tilpasset"</item>
+ <item>"Start"</item>
+ <item>"Mobil"</item>
+ <item>"Arbejde"</item>
+ <item>"Arbejdsfax"</item>
+ <item>"Hjemmefax"</item>
+ <item>"Personsøger"</item>
+ <item>"Andet"</item>
+ <item>"Tilpasset"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Start"</item>
- <item msgid="7084237356602625604">"Arbejde"</item>
- <item msgid="1112044410659011023">"Andre"</item>
- <item msgid="2374913952870110618">"Tilpasset"</item>
+ <item>"Start"</item>
+ <item>"Arbejde"</item>
+ <item>"Anden"</item>
+ <item>"Tilpasset"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobil"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Start"</item>
- <item msgid="5629153956045109251">"Arbejde"</item>
- <item msgid="4966604264500343469">"Andre"</item>
- <item msgid="4932682847595299369">"Tilpasset"</item>
+ <item>"Start"</item>
+ <item>"Arbejde"</item>
+ <item>"Anden"</item>
+ <item>"Tilpasset"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Start"</item>
- <item msgid="1359644565647383708">"Arbejde"</item>
- <item msgid="7868549401053615677">"Anden"</item>
- <item msgid="3145118944639869809">"Tilpasset"</item>
+ <item>"Start"</item>
+ <item>"Arbejde"</item>
+ <item>"Anden"</item>
+ <item>"Tilpasset"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Arbejde"</item>
- <item msgid="4378074129049520373">"Andre"</item>
- <item msgid="3455047468583965104">"Tilpasset"</item>
+ <item>"Arbejde"</item>
+ <item>"Anden"</item>
+ <item>"Tilpasset"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Indtast PIN-kode"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Forkert PIN-kode!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Tryk på Menu og dernæst på 0 for at låse op."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nødnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Ingen tjeneste)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skærmen er låst."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tryk på Menu for at låse op eller foretage et nødopkald."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryk på Menu for at låse op."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Tegn mønster til at låse op"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Nødopkald"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Rigtigt!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Beklager! Prøv igen"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Oplader (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Indtast PIN-kode"</string>
+ <string name="keyguard_password_wrong_pin_code">"Forkert PIN-kode!"</string>
+ <string name="keyguard_label_text">"Tryk på Menu og dernæst på 0 for at låse op."</string>
+ <string name="emergency_call_dialog_number_for_display">"Nødnummer"</string>
+ <string name="lockscreen_carrier_default">"(Ingen tjeneste)"</string>
+ <string name="lockscreen_screen_locked">"Skærmen er låst."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Tryk på Menu for at låse op eller foretage et nødopkald."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Tryk på Menu for at låse op."</string>
+ <string name="lockscreen_pattern_instructions">"Tegn mønster til at låse op"</string>
+ <string name="lockscreen_emergency_call">"Nødopkald"</string>
+ <string name="lockscreen_pattern_correct">"Rigtigt!"</string>
+ <string name="lockscreen_pattern_wrong">"Beklager! Prøv igen"</string>
+ <string name="lockscreen_plugged_in">"Oplader (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Tilslut din oplader."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Der er ikke noget SIM-kort."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Der er ikke noget SIM-kort i telefonen."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Indsæt et SIM-kort."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netværket er låst"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-kort er låst med PUK-koden."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Se brugervejledningen, eller kontakt kundeservice."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kortet er låst."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"LÃ¥ser SIM-kortet op ..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Du har tegnet dit mønster til at låse op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Du har tegnet dit mønster til at låse op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> forsøg mere vil du blive bedt om at låse din telefon op ved hjælp af dit Google-login"\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Prøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Har du glemt mønster?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"For mange mønsterforsøg!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"For at låse op skal du logge ind med din Google-konto"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Brugernavn (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Adgangskode"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Log ind"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ugyldigt brugernavn eller ugyldig adgangskode."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Tilslut din oplader."</string>
+ <string name="lockscreen_missing_sim_message_short">"Der er ikke noget SIM-kort."</string>
+ <string name="lockscreen_missing_sim_message">"Der er ikke noget SIM-kort i telefonen."</string>
+ <string name="lockscreen_missing_sim_instructions">"Indsæt et SIM-kort."</string>
+ <string name="lockscreen_network_locked_message">"Netværket er låst"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-kort er låst med PUK-koden."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Se brugervejledningen, eller kontakt kundeservice."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-kortet er låst."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"LÃ¥ser SIM-kortet op ..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Du har tegnet dit mønster til at låse op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Du har tegnet dit mønster til at låse op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> forsøg mere vil du blive bedt om at låse din telefon op ved hjælp af dit Google-login"\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Prøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Har du glemt mønster?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"For mange mønsterforsøg!"</string>
+ <string name="lockscreen_glogin_instructions">"For at låse op skal du logge ind med din Google-konto"</string>
+ <string name="lockscreen_glogin_username_hint">"Brugernavn (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Adgangskode"</string>
+ <string name="lockscreen_glogin_submit_button">"Log ind"</string>
+ <string name="lockscreen_glogin_invalid_input">"Ugyldigt brugernavn eller ugyldig adgangskode."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen meddelelser"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Løbende"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelelser"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Oplader ..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Forbind oplader"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet er ved at blive tomt:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"mindre end <xliff:g id="NUMBER">%d%%</xliff:g> tilbage."</string>
+ <string name="status_bar_no_notifications_title">"Ingen meddelelser"</string>
+ <string name="status_bar_ongoing_events_title">"Løbende"</string>
+ <string name="status_bar_latest_events_title">"Meddelelser"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Oplader ..."</string>
+ <string name="battery_low_title">"Forbind oplader"</string>
+ <string name="battery_low_subtitle">"Batteriet er ved at blive tomt:"</string>
+ <string name="battery_low_percent_format">"mindre end <xliff:g id="NUMBER">%d%%</xliff:g> tilbage."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Fabrikstest mislykkedes"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Handlingen FACTORY_TEST understøttes kun af pakker installeret i /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Der blev ikke fundet nogen pakke, som leverer handlingen FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Genstart"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Siden på \'<xliff:g id="TITLE">%s</xliff:g>\' siger:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"Javascript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Naviger væk fra denne side?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" Vælg OK for at fortsætte eller Annuller for at blive på den aktuelle side."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Bekræft"</string>
+ <string name="factorytest_failed">"Fabrikstest mislykkedes"</string>
+ <string name="factorytest_not_system">"Handlingen FACTORY_TEST understøttes kun af pakker installeret i /system/app."</string>
+ <string name="factorytest_no_action">"Der blev ikke fundet nogen pakke, som leverer handlingen FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Genstart"</string>
+ <string name="js_dialog_title">"Siden på \'<xliff:g id="TITLE">%s</xliff:g>\' siger:"</string>
+ <string name="js_dialog_title_default">"Javascript"</string>
+ <string name="js_dialog_before_unload">"Naviger væk fra denne side?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" Vælg OK for at fortsætte eller Annuller for at blive på den aktuelle side."</string>
+ <string name="save_password_label">"Bekræft"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Ønsker du, at browseren skal huske denne adgangskode?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nu"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Aldrig"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Du har ikke tilladelse til at åbne denne side."</string>
- <string name="text_copied" msgid="4985729524670131385">"Teksten er kopieret til udklipsholderen."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Flere"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"plads"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"indtast"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"slet"</string>
- <string name="search_go" msgid="8298016669822141719">"Søg"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"For 1 måned siden"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Før for 1 måned siden"</string>
+ <string name="save_password_message">"Ønsker du, at browseren skal huske denne adgangskode?"</string>
+ <string name="save_password_notnow">"Ikke nu"</string>
+ <string name="save_password_remember">"Husk"</string>
+ <string name="save_password_never">"Aldrig"</string>
+ <string name="open_permission_deny">"Du har ikke tilladelse til at åbne denne side."</string>
+ <string name="text_copied">"Teksten er kopieret til udklipsholderen."</string>
+ <string name="more_item_label">"Flere"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"plads"</string>
+ <string name="menu_enter_shortcut_label">"indtast"</string>
+ <string name="menu_delete_shortcut_label">"slet"</string>
+ <string name="search_go">"Søg"</string>
+ <string name="oneMonthDurationPast">"For 1 måned siden"</string>
+ <string name="beforeOneMonthDurationPast">"Før for 1 måned siden"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"For 1 sekund siden"</item>
- <item quantity="other" msgid="3903706804349556379">"For <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
+ <item quantity="one">"For 1 sekund siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"For 1 minut siden"</item>
- <item quantity="other" msgid="2176942008915455116">"For <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
+ <item quantity="one">"For 1 minut siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"For 1 time siden"</item>
- <item quantity="other" msgid="2467273239587587569">"For <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
+ <item quantity="one">"For 1 time siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"i går"</item>
- <item quantity="other" msgid="2479586466153314633">"For <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
+ <item quantity="one">"i går"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"om 1 sekund"</item>
- <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ <item quantity="one">"om 1 sekund"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"om 1 minut"</item>
- <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
+ <item quantity="one">"om 1 minut"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"om 1 time"</item>
- <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
+ <item quantity="one">"om 1 time"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"i morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
+ <item quantity="one">"i morgen"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"For 1 sek. siden"</item>
- <item quantity="other" msgid="3699169366650930415">"For <xliff:g id="COUNT">%d</xliff:g> sek. siden"</item>
+ <item quantity="one">"For 1 sek. siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> sek. siden"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"For 1 min. siden"</item>
- <item quantity="other" msgid="851164968597150710">"For <xliff:g id="COUNT">%d</xliff:g> min. siden"</item>
+ <item quantity="one">"For 1 min. siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> min. siden"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"For 1 time siden"</item>
- <item quantity="other" msgid="6889970745748538901">"For <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
+ <item quantity="one">"For 1 time siden"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"i går"</item>
- <item quantity="other" msgid="3453342639616481191">"For <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
+ <item quantity="one">"i går"</item>
+ <item quantity="other">"For <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"om 1 sek."</item>
- <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ <item quantity="one">"om 1 sek."</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"om 1 min."</item>
- <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ <item quantity="one">"om 1 min."</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> min."</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"om 1 time"</item>
- <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
+ <item quantity="one">"om 1 time"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"i morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
+ <item quantity="one">"i morgen"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"den %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"kl. %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"i %s"</string>
- <string name="day" msgid="8144195776058119424">"dag"</string>
- <string name="days" msgid="4774547661021344602">"dage"</string>
- <string name="hour" msgid="2126771916426189481">"time"</string>
- <string name="hours" msgid="894424005266852993">"timer"</string>
- <string name="minute" msgid="9148878657703769868">"min."</string>
- <string name="minutes" msgid="5646001005827034509">"min."</string>
- <string name="second" msgid="3184235808021478">"sek."</string>
- <string name="seconds" msgid="3161515347216589235">"sek."</string>
- <string name="week" msgid="5617961537173061583">"uge"</string>
- <string name="weeks" msgid="6509623834583944518">"uger"</string>
- <string name="year" msgid="4001118221013892076">"Ã¥r"</string>
- <string name="years" msgid="6881577717993213522">"Ã¥r"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Hver ugedag (man.-fre.)"</string>
- <string name="daily" msgid="5738949095624133403">"Dagligt"</string>
- <string name="weekly" msgid="983428358394268344">"Ugentlig hver <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"MÃ¥nedligt"</string>
- <string name="yearly" msgid="1519577999407493836">"Ã…rligt"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Video kan ikke afspilles"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Beklager! Denne video er ikke gyldig til streaming på denne enhed."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Beklager! Denne video kan ikke afspilles."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"middag"</string>
- <string name="Noon" msgid="3342127745230013127">"Middag"</string>
- <string name="midnight" msgid="7166259508850457595">"midnat"</string>
- <string name="Midnight" msgid="5630806906897892201">"Midnat"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Vælg alle"</string>
- <string name="selectText" msgid="3889149123626888637">"Vælg tekst"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Stands med at vælge tekst"</string>
- <string name="cut" msgid="3092569408438626261">"Klip"</string>
- <string name="cutAll" msgid="2436383270024931639">"Klip alle"</string>
- <string name="copy" msgid="2681946229533511987">"Kopier"</string>
- <string name="copyAll" msgid="2590829068100113057">"Kopier alle"</string>
- <string name="paste" msgid="5629880836805036433">"Indsæt"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Kopier webadresse"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Inputmetode"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Føj \"%s\" til ordbog"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Rediger tekst"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Der er ikke så meget plads tilbage"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Der er næsten ikke mere plads på telefonen."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Annuller"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Annuller"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Bemærk"</string>
- <string name="capital_on" msgid="1544682755514494298">"TIL"</string>
- <string name="capital_off" msgid="6815870386972805832">"FRA"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Afslut handling ved hjælp af"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Brug som standard til denne handling."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Ryd standard i Startindstillinger &gt; Programmer &gt; Administrer programmer."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Vælg en handling"</string>
- <string name="noApplications" msgid="1691104391758345586">"Der er ingen programmer, der kan foretage denne handling."</string>
- <string name="aerr_title" msgid="653922989522758100">"Beklager!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) er standset uventet. Prøv igen."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> er standset uventet. Prøv igen."</string>
- <string name="anr_title" msgid="3100070910664756057">"Beklager!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Aktivitet <xliff:g id="ACTIVITY">%1$s</xliff:g> (i programmet <xliff:g id="APPLICATION">%2$s</xliff:g>) svarer ikke."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Aktivitet <xliff:g id="ACTIVITY">%1$s</xliff:g> (igangværende <xliff:g id="PROCESS">%2$s</xliff:g>) svarer ikke."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (igangværende <xliff:g id="PROCESS">%2$s</xliff:g>) svarer ikke."</string>
- <string name="anr_process" msgid="1246866008169975783">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarer ikke."</string>
- <string name="force_close" msgid="3653416315450806396">"Tving til at lukke"</string>
+ <string name="preposition_for_date">"den %s"</string>
+ <string name="preposition_for_time">"kl. %s"</string>
+ <string name="preposition_for_year">"i %s"</string>
+ <string name="day">"dag"</string>
+ <string name="days">"dage"</string>
+ <string name="hour">"time"</string>
+ <string name="hours">"timer"</string>
+ <string name="minute">"min."</string>
+ <string name="minutes">"min."</string>
+ <string name="second">"sek."</string>
+ <string name="seconds">"sek."</string>
+ <string name="week">"uge"</string>
+ <string name="weeks">"uger"</string>
+ <string name="year">"Ã¥r"</string>
+ <string name="years">"Ã¥r"</string>
+ <string name="every_weekday">"Hver ugedag (man.-fre.)"</string>
+ <string name="daily">"Dagligt"</string>
+ <string name="weekly">"Ugentlig hver <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"MÃ¥nedligt"</string>
+ <string name="yearly">"Ã…rligt"</string>
+ <string name="VideoView_error_title">"Video kan ikke afspilles"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Beklager! Denne video er ikke gyldig til streaming på denne enhed."</string>
+ <string name="VideoView_error_text_unknown">"Beklager! Denne video kan ikke afspilles."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"middag"</string>
+ <string name="Noon">"Middag"</string>
+ <string name="midnight">"midnat"</string>
+ <string name="Midnight">"Midnat"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Vælg alle"</string>
+ <string name="selectText">"Vælg tekst"</string>
+ <string name="stopSelectingText">"Stands med at vælge tekst"</string>
+ <string name="cut">"Klip"</string>
+ <string name="cutAll">"Klip alle"</string>
+ <string name="copy">"Kopier"</string>
+ <string name="copyAll">"Kopier alle"</string>
+ <string name="paste">"Indsæt"</string>
+ <string name="copyUrl">"Kopier webadresse"</string>
+ <string name="inputMethod">"Inputmetode"</string>
+ <string name="addToDictionary">"Føj \"%s\" til ordbog"</string>
+ <string name="editTextMenuTitle">"Rediger tekst"</string>
+ <string name="low_internal_storage_view_title">"Der er ikke så meget plads tilbage"</string>
+ <string name="low_internal_storage_view_text">"Der er næsten ikke mere plads på telefonen."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Annuller"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Annuller"</string>
+ <string name="dialog_alert_title">"Bemærk"</string>
+ <string name="capital_on">"TIL"</string>
+ <string name="capital_off">"FRA"</string>
+ <string name="whichApplication">"Afslut handling ved hjælp af"</string>
+ <string name="alwaysUse">"Brug som standard til denne handling."</string>
+ <string name="clearDefaultHintMsg">"Ryd standard i Startindstillinger &gt; Programmer &gt; Administrer programmer."</string>
+ <string name="chooseActivity">"Vælg en handling"</string>
+ <string name="noApplications">"Der er ingen programmer, der kan foretage denne handling."</string>
+ <string name="aerr_title">"Beklager!"</string>
+ <string name="aerr_application">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) er standset uventet. Prøv igen."</string>
+ <string name="aerr_process">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> er standset uventet. Prøv igen."</string>
+ <string name="anr_title">"Beklager!"</string>
+ <string name="anr_activity_application">"Aktivitet <xliff:g id="ACTIVITY">%1$s</xliff:g> (i programmet <xliff:g id="APPLICATION">%2$s</xliff:g>) svarer ikke."</string>
+ <string name="anr_activity_process">"Aktivitet <xliff:g id="ACTIVITY">%1$s</xliff:g> (igangværende <xliff:g id="PROCESS">%2$s</xliff:g>) svarer ikke."</string>
+ <string name="anr_application_process">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (igangværende <xliff:g id="PROCESS">%2$s</xliff:g>) svarer ikke."</string>
+ <string name="anr_process">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarer ikke."</string>
+ <string name="force_close">"Tving til at lukke"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Vent"</string>
- <string name="debug" msgid="9103374629678531849">"Fejlretning"</string>
- <string name="sendText" msgid="5132506121645618310">"Vælg en handling for teksten"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Opkaldslydstyrke"</string>
- <string name="volume_music" msgid="5421651157138628171">"Medielydstyrke"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Spiller gennem Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Opkaldslydstyrke"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth-lydstyrke under opkald"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Alarmlydstyrke"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Meddelelseslydstyrke"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Lydstyrke"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Standardringetone"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standardringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Lydløs"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Ukendt ringetone"</string>
+ <string name="wait">"Vent"</string>
+ <string name="debug">"Fejlretning"</string>
+ <string name="sendText">"Vælg en handling for teksten"</string>
+ <string name="volume_ringtone">"Opkaldslydstyrke"</string>
+ <string name="volume_music">"Medielydstyrke"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Spiller gennem Bluetooth"</string>
+ <string name="volume_call">"Opkaldslydstyrke"</string>
+ <string name="volume_bluetooth_call">"Bluetooth-lydstyrke under opkald"</string>
+ <string name="volume_alarm">"Alarmlydstyrke"</string>
+ <string name="volume_notification">"Meddelelseslydstyrke"</string>
+ <string name="volume_unknown">"Lydstyrke"</string>
+ <string name="ringtone_default">"Standardringetone"</string>
+ <string name="ringtone_default_with_actual">"Standardringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Lydløs"</string>
+ <string name="ringtone_picker_title">"Ringetoner"</string>
+ <string name="ringtone_unknown">"Ukendt ringetone"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fi-netværk tilgængeligt"</item>
- <item quantity="other" msgid="4192424489168397386">"Tilgængelige Wi-Fi-netværk"</item>
+ <item quantity="one">"Wi-Fi-netværk tilgængeligt"</item>
+ <item quantity="other">"Tilgængelige Wi-Fi-netværk"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Åbent Wi-Fi-netværk tilgængeligt"</item>
- <item quantity="other" msgid="7915895323644292768">"Der er åbne Wi-Fi-netværk tilgængelige"</item>
+ <item quantity="one">"Åbent Wi-Fi-netværk tilgængeligt"</item>
+ <item quantity="other">"Der er åbne Wi-Fi-netværk tilgængelige"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Indsæt tegn"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Ukendt program"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Sender SMS-beskeder"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Der sendes et stort antal SMS-beskeder. Vælg \"OK\" for at fortsætte eller \"Annuller\" for at stoppe med at sende."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annuller"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Indstil"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Der kræves ingen tilladelser"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Skjul"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Vis alle"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Indlæser ..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB forbundet"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Du har forbundet din telefon til din computer via USB. Vælg \"Monter\", hvis du ønsker at kopiere filer mellem din computer og din telefons SD-kort."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Monter"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Indsæt ikke"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Der opstod et problem med at bruge dit SD-kort til USB-lagring."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB forbundet"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Vælg for at kopiere filer til/fra din computer."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Slå USB-lagringen fra"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Vælg for at slå USB-lagring fra."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Slå USB-lagring fra"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Inden du slår USB-lagringen fra, skal du sørge for, at du demonterer USB-værten. Vælg \"Slå fra\" for at slå USB-lagringen fra."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Slå fra"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Annuller"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Der opstod et problem med at slå USB-lagringen fra. Sørg for, at du har demonteret USB-værten, og prøv så igen."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formater SD-kort"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Er du sikker på, du ønsker at formatere SD-kortet? Alle data på kortet mistes."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formater"</string>
+ <string name="select_character">"Indsæt tegn"</string>
+ <string name="sms_control_default_app_name">"Ukendt program"</string>
+ <string name="sms_control_title">"Sender SMS-beskeder"</string>
+ <string name="sms_control_message">"Der sendes et stort antal SMS-beskeder. Vælg \"OK\" for at fortsætte eller \"Annuller\" for at stoppe med at sende."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Annuller"</string>
+ <string name="date_time_set">"Indstil"</string>
+ <string name="default_permission_group">"Standard"</string>
+ <string name="no_permissions">"Der kræves ingen tilladelser"</string>
+ <string name="perms_hide"><b>"Skjul"</b></string>
+ <string name="perms_show_all"><b>"Vis alle"</b></string>
+ <string name="googlewebcontenthelper_loading">"Indlæser ..."</string>
+ <string name="usb_storage_title">"USB forbundet"</string>
+ <string name="usb_storage_message">"Du har forbundet din telefon til din computer via USB. Vælg \"Monter\", hvis du ønsker at kopiere filer mellem din computer og din telefons SD-kort."</string>
+ <string name="usb_storage_button_mount">"Monter"</string>
+ <string name="usb_storage_button_unmount">"Indsæt ikke"</string>
+ <string name="usb_storage_error_message">"Der opstod et problem med at bruge dit SD-kort til USB-lagring."</string>
+ <string name="usb_storage_notification_title">"USB forbundet"</string>
+ <string name="usb_storage_notification_message">"Vælg for at kopiere filer til/fra din computer."</string>
+ <string name="usb_storage_stop_notification_title">"Slå USB-lagringen fra"</string>
+ <string name="usb_storage_stop_notification_message">"Vælg for at slå USB-lagring fra."</string>
+ <string name="usb_storage_stop_title">"Slå USB-lagring fra"</string>
+ <string name="usb_storage_stop_message">"Inden du slår USB-lagringen fra, skal du sørge for, at du demonterer USB-værten. Vælg \"Slå fra\" for at slå USB-lagringen fra."</string>
+ <string name="usb_storage_stop_button_mount">"Slå fra"</string>
+ <string name="usb_storage_stop_button_unmount">"Annuller"</string>
+ <string name="usb_storage_stop_error_message">"Der opstod et problem med at slå USB-lagringen fra. Sørg for, at du har demonteret USB-værten, og prøv så igen."</string>
+ <string name="extmedia_format_title">"Formater SD-kort"</string>
+ <string name="extmedia_format_message">"Er du sikker på, du ønsker at formatere SD-kortet? Alle data på kortet mistes."</string>
+ <string name="extmedia_format_button_format">"Formater"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Vælg inputmetode"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Forbereder SD-kort"</string>
+ <string name="select_input_method">"Vælg inputmetode"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"kandidater"</u></string>
+ <string name="ext_media_checking_notification_title">"Forbereder SD-kort"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Blankt SD-kort"</string>
+ <string name="ext_media_nofs_notification_title">"Blankt SD-kort"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Beskadiget SD-kort"</string>
+ <string name="ext_media_unmountable_notification_title">"Beskadiget SD-kort"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD-kort blev uventet fjernet"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Demonter SD-kortet inden fjernelse for at undgå tab af data."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SD-kortet kan fjernes sikkert"</string>
+ <string name="ext_media_badremoval_notification_title">"SD-kort blev uventet fjernet"</string>
+ <string name="ext_media_badremoval_notification_message">"Demonter SD-kortet inden fjernelse for at undgå tab af data."</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD-kortet kan fjernes sikkert"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SD-kortet er fjernet"</string>
+ <string name="ext_media_nomedia_notification_title">"SD-kortet er fjernet"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Der blev ikke fundet nogen matchende aktiviteter"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"opdater brugerstatistikker for komponenter"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Tillader ændring af indsamlede brugerstatistikker for komponenter. Ikke til brug til normale programmer."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tryk to gange for zoomkontrol"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Der opstod en fejl under forøgelsen af widgeten"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"GÃ¥"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Søg"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Send"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Næste"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Færdig"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Udfør"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Ring til nummer"\n"ved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Opret kontakt"\n"ved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Der blev ikke fundet nogen matchende aktiviteter"</string>
+ <string name="permlab_pkgUsageStats">"opdater brugerstatistikker for komponenter"</string>
+ <string name="permdesc_pkgUsageStats">"Tillader ændring af indsamlede brugerstatistikker for komponenter. Ikke til brug til normale programmer."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Tryk to gange for zoomkontrol"</string>
+ <string name="gadget_host_error_inflating">"Der opstod en fejl under forøgelsen af widgeten"</string>
+ <string name="ime_action_go">"GÃ¥"</string>
+ <string name="ime_action_search">"Søg"</string>
+ <string name="ime_action_send">"Send"</string>
+ <string name="ime_action_next">"Næste"</string>
+ <string name="ime_action_done">"Færdig"</string>
+ <string name="ime_action_default">"Udfør"</string>
+ <string name="dial_number_using">"Ring til nummer"\n"ved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Opret kontaktperson"\n"ved hjælp af <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 10a736c..9163c61 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -15,695 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"&lt;Unbenannt&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Keine Telefonnummer)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Unbekannt)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Mailbox"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Verbindungsproblem oder ungültiger MMI-Code."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Dienst wurde aktiviert."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Dienst wurde aktiviert für:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Dienst wurde deaktiviert."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registrierung war erfolgreich."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Löschvorgang erfolgreich."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Falsches Passwort."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI abgeschlossen."</string>
- <string name="badPin" msgid="5085454289896032547">"Die von Ihnen eingegebene alte PIN ist nicht korrekt."</string>
- <string name="badPuk" msgid="5702522162746042460">"Der von Ihnen eingegebene PUK ist nicht korrekt."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Die von Ihnen eingegebenen PIN-Nummern stimmen nicht überein."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Geben Sie eine PIN ein, die 4 bis 8 Zahlen enthält."</string>
- <string name="needPuk" msgid="919668385956251611">"Ihre SIM-Karte ist mit einem PUK gesperrt. Geben Sie zum Entsperren den PUK-Code ein."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Geben Sie zum Entsperren der SIM-Karte den PUK2 ein."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Anrufer-ID für eingehenden Anruf"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Anrufer-ID für abgehenden Anruf"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Rufweiterleitung"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Anklopfen"</string>
- <string name="BaMmi" msgid="455193067926770581">"Anrufsperre"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Passwort-Änderung"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN-Änderung"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Rufnummer vorhanden"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Rufnummer begrenzt"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Dreierkonferenz"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Ablehnung unerwünschter Anrufe"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Rufnummernübermittlung"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Bitte nicht stören"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Beschränkt"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Nicht beschränkt"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Beschränkt"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Dienst nicht eingerichtet."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Die Einstellung für die Anrufer-ID kann nicht geändert werden."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Eingeschränkter Zugriff geändert"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Daten-Dienst ist gesperrt."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Notruf ist gesperrt."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Sprach-/SMS-Dienst ist gesperrt."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Alle Sprach-/SMS-Dienste sind gesperrt."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Sprachnotiz"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Daten"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynchron"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synchron"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paket"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Roaming-Anzeige ein"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Roaming-Anzeige aus"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Roaming-Anzeige blinkend"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Außerhalb der Netzwerkumgebung"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Außerhalb des Gebäudes"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming - Bevorzugtes System"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming - Verfügbares System"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming - Allianzpartner"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming - Premiumpartner"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming - Volle Dienstfunktionalität"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming - Partielle Dienstfunktionalität"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Roaming-Banner ein"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Roaming-Banner aus"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Suche nach Dienst"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> nach <xliff:g id="TIME_DELAY">{2}</xliff:g> Sekunden."</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Funktionscode abgeschlossen"</string>
- <string name="fcError" msgid="3327560126588500777">"Verbindungsproblem oder ungültiger Funktionscode"</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Auf der Webseite ist ein Fehler aufgetreten."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Die URL konnte nicht gefunden werden."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Das Authentifizierungsschema für die Site wird nicht unterstützt."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Authentifizierung ist fehlgeschlagen."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Authentifizierung via Proxy-Server ist fehlgeschlagen."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Es konnte keine Verbindung zum Server hergestellt werden."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Die Server-Kommunikation ist fehlgeschlagen. Versuchen Sie es später erneut."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Zeitüberschreitung bei Serververbindung."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Die Seite enthält zu viele Server-Redirects."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Das Protokoll wird nicht unterstützt."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Es konnte keine sichere Verbindung aufgebaut werden."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Die Seite konnte nicht geöffnet werden, weil die URL ungültig ist."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Auf die Datei konnte nicht zugegriffen werden."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Die angeforderte Datei wurde nicht gefunden."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuchen Sie es später erneut."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synchronisieren"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisieren"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefonspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
- <string name="me" msgid="6545696007631404292">"Eigene"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefonoptionen"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Lautlos-Modus"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Funk einschalten"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Funk ausschalten"</string>
- <string name="screen_lock" msgid="799094655496098153">"Bildschirmsperre"</string>
- <string name="power_off" msgid="4266614107412865048">"Ausschalten"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Herunterfahren..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Ihr Telefon wird heruntergefahren."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Keine neuen Anwendungen."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefonoptionen"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Bildschirmsperre"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lautlos"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ton ist bereits AUS"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ton ist momentan AN"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flugmodus"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flugmodus ist AN"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS"</string>
- <string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Kostenpflichtige Dienste"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Ihre Nachrichten"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Lesen und schreiben Sie Ihre SMS, E-Mails und anderen Nachrichten."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Ihre persönlichen Informationen"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Ihr Standort"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Ihren physischen Standort überwachen"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Netzwerkkommunikation"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Ihre Google-Konten"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Greift auf verfügbare Google-Konten zu."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Hardware-Steuerelemente"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Direkter Zugriff auf Hardware über Headset"</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Anrufe"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Ãœberwachen, Aufzeichnen und Verarbeiten von Telefonanrufen"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"System-Tools"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Zugriff und Steuerung des Systems auf niedrigerer Ebene."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Entwickler-Tools"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funktionen nur für Anwendungsentwickler vorgesehen."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Speicher"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Greift auf die SD-Karte zu."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"Statusleiste ein-/ausblenden"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"Abgehende Anrufe abfangen"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Ermöglicht einer Anwendung, abgehende Anrufe zu verarbeiten und die zu wählende Nummer zu ändern. Schädliche Anwendungen können so abgehende Anrufe eventuell überwachen, umleiten oder verhindern."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"SMS empfangen"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Ermöglicht der Anwendung, Kurzmitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"MMS empfangen"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Ermöglicht der Anwendung, MMS-Mitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"Kurznachrichten senden"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Ermöglicht Anwendungen das Senden von SMS-Nachrichten. Bei schädlichen Anwendungen können Kosten entstehen, wenn diese Nachrichten ohne Ihre Zustimmung versenden."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"SMS oder MMS lesen"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Ermöglicht einer Anwendung, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte Kurznachrichten zu lesen. Schädliche Anwendungen lesen so möglicherweise Ihre vertraulichen Nachrichten."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"SMS oder MMS bearbeiten"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Ermöglicht einer Anwendung, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte Kurznachrichten zu bearbeiten. Schädliche Anwendungen löschen möglicherweise Ihre Nachrichten."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP-Nachrichten empfangen"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Ermöglicht der Anwendung, WAP-Mitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"Laufende Anwendungen abrufen"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Ermöglicht der Anwendung, Informationen zu aktuellen und kürzlich ausführten Aufgaben abzurufen. Schädliche Anwendungen können so eventuell geheime Informationen zu anderen Anwendungen entdecken."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"Laufende Anwendungen neu ordnen"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Ermöglicht einer Anwendung, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Anwendungen können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"Fehlerbeseitigung für Anwendung aktivieren"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"Andere Anwendungen neu starten"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Ermöglicht einer Anwendung, den Neustart anderer Anwendungen zu erzwingen."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"Schließen von Anwendung erzwingen"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Ermöglicht einer Anwendung, alle Aktivitäten, die im Vordergrund ablaufen, zu beenden und in den Hintergrund zu schieben. Sollte nicht für normale Anwendungen benötigt werden."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"Systeminternen Status abrufen"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Ermöglicht einer Anwendung, den internen Status des Systems abzurufen. Schädliche Anwendungen rufen hierbei möglicherweise eine Vielzahl an privaten und geschützten Daten ab, die Sie in der Regel nicht benötigen würden."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"partielles Herunterfahren"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Versetzt den Aktivitätsmanager in einen heruntergefahrenen Zustand. Führt kein vollständiges Herunterfahren aus."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"Anwendungswechsel verhindern"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hindert den Nutzer daran, zu einer anderen Anwendung zu wechseln"</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"Start von Anwendungen überwachen und steuern"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Ermöglicht der Anwendung, den Start von Systemaktivitäten zu überwachen und zu steuern. Schädliche Anwendungen können so das gesamte System beeinträchtigen. Diese Berechtigung wird nur zu Entwicklungszwecken und nie für die normale Telefonnutzung benötigt."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"Broadcast ohne Paket senden"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Ermöglicht einer Anwendung, eine Benachrichtigung zur Entfernung eines Anwendungspakets zu senden. Schädliche Anwendungen können so laufende Anwendungen beenden."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"per SMS empfangenen Broadcast senden"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Ermöglicht einer Anwendung, eine Benachrichtigung zu senden, dass eine Kurzmitteilung empfangen wurde. Schädliche Anwendungen könnten diese Option verwenden, um den Eingang von Kurzmitteilungen zu erzwingen."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"von WAP-PUSH empfangenen Broadcast senden"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Ermöglicht einer Anwendung, eine Benachrichtigung zu senden, dass eine WAP PUSH-Nachricht empfangen wurde. Schädliche Anwendungen könnten diese Option verwenden, um den Erhalt von MMS-Mitteilungen zu erzwingen, oder um unbemerkt den Inhalt einer beliebigen Webseite durch schädliche Inhalte zu ersetzen."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"Anzahl der laufenden Prozesse beschränken"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Ermöglicht einer Anwendung, die maximale Anzahl an laufenden Prozessen zu steuern. Wird nicht für normale Anwendungen benötigt."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"alle Anwendungen im Hintergrund schließen"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Überlässt einer Anwendung die Entscheidung, ob Aktivitäten beendet werden, sobald Sie in den Hintergrund rücken. Wird nicht für normale Anwendungen benötigt."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"Akku-Daten ändern"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Ermöglicht die Änderung von gesammelten Akku-Daten. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_backup" msgid="470013022865453920">"Systemsicherung und -wiederherstellung kontrollieren"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Ermöglicht der Anwendung, den Sicherungs- und Wiederherstellungsmechanismus des Systems zu kontrollieren. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"nicht autorisierte Fenster anzeigen"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Ermöglicht die Erstellung von Fenstern, die von der Benutzeroberfläche des internen Systems verwendet werden. Nicht für normale Anwendungen geeignet."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"Warnungen auf Systemebene anzeigen"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Ermöglicht einer Anwendung, Fenster mit Systemwarnungen anzuzeigen. Schädliche Anwendungen können so das gesamte Display des Telefons einnehmen."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"Allgemeine Animationsgeschwindigkeit einstellen"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"Anwendungs-Tokens verwalten"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Ermöglicht Anwendungen, Ihre eigenen Tokens zu erstellen und zu verwalten. Hierbei wird die normale Z-Reihenfolge umgangen. Dies sollte nicht für normale Anwendungen benötigt werden."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"Tasten und Steuerungstasten drücken"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Ermöglicht einer Anwendung, ihre eigenen Eingabeaktionen (Drücken von Tasten etc.) an andere Anwendungen zu liefern. Schädliche Anwendungen können so die Kontrolle über Ihr Telefon übernehmen."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"Tastatureingaben und Aktionen aufzeichnen"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Ermöglicht Anwendungen, die von Ihnen gedrückten Tasten zu überwachen (etwa die Eingabe eines Passworts). Dies gilt auch für die Interaktion mit anderen Anwendungen. Sollte für normale Anwendungen nicht benötigt werden."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"An eine Eingabemethode binden"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Ermöglicht dem Halter, sich an die Oberfläche einer Eingabemethode auf oberster Ebene zu binden. Sollte nie für normale Anwendungen benötigt werden."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Ermöglicht der Anwendung, die Bildschirmdrehung jederzeit zu ändern. Sollte nicht für normale Anwendungen benötigt werden."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-Signale an Anwendungen senden"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"Anwendungen permanent ausführen"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"Anwendungen löschen"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Ermöglicht einer Anwendung, Android-Pakete zu löschen. Schädliche Anwendungen können so wichtige Anwendungen löschen."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"Daten anderer Anwendungen löschen"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"Caches anderer Anwendungen löschen"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"Speicherplatz der Anwendung abrufen"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"Anwendungen direkt installieren"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Ermöglicht einer Anwendung, neue oder aktualisierte Android-Pakete zu installieren. Schädliche Anwendungen können so neue Anwendungen mit beliebig umfangreichen Berechtigungen hinzufügen."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"Alle Cache-Daten der Anwendung löschen"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Ermöglicht einer Anwendung, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"System-Protokolldateien lesen"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden, diese sollten jedoch keine persönlichen oder geheimen Daten enthalten."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Ermöglicht einer Anwendung, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für Hardware-spezifische Diagnosen des Herstellers oder Netzbetreibers verwendet werden."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"Anwendungskomponenten aktivieren oder deaktivieren"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Ermöglicht einer Anwendung, die Komponente einer anderen Anwendung nach Belieben zu aktivieren oder zu deaktivieren. Schädliche Anwendungen können so wichtige Funktionen des Telefons deaktivieren. Bei der Erteilung von Berechtigungen ist daher Vorsicht geboten, da die Anwendungskomponenten unbrauchbar, inkonsistent und unstabil werden können."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"Bevorzugte Einstellungen festlegen"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Ermöglicht einer Anwendung, Ihre bevorzugten Einstellungen zu ändern. Schädliche Anwendungen können so laufende Anwendungen ohne Ihr Wissen ändern, damit die vorhandenen Anwendungen private Daten von Ihnen sammeln."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"Allgemeine Systemeinstellungen ändern"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Ermöglicht einer Anwendung, die Einstellungsdaten des Systems zu ändern. Schädliche Anwendungen können so die Systemkonfiguration beschädigen."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"Sicherheitseinstellungen für das System ändern"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Ermöglicht einer Anwendung, die Daten der Sicherheitseinstellungen des Systems zu ändern. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Google Services Map ändern"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Ermöglicht einer Anwendung, Änderungen an der Google Services Map vorzunehmen. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"Automatisch nach dem Booten starten"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Ermöglicht einer Anwendung, sich selbst zu starten, sobald das System gebootet wurde. Dadurch kann es länger dauern, bis das Telefon gestartet wird, und durch die ständige Aktivität der Anwendung wird die gesamte Leistung des Telefons beeinträchtigt."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"dauerhaften Broadcast senden"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Telefon langsam oder unstabil machen, da zuviel Speicherplatz belegt ist."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"Kontaktdaten lesen"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu lesen. Schädliche Anwendungen können so Ihre Daten an andere Personen senden."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"Kontaktdaten schreiben"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu ändern. Schädliche Anwendungen können so Ihre Kontaktdaten löschen oder verändern."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"Eigentümerdaten schreiben"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Eigentümerdaten zu ändern. Schädliche Anwendungen können so Eigentümerdaten löschen oder verändern."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"Eigentümerdaten lesen"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Eigentümerdaten zu lesen. Schädliche Anwendungen können so Eigentümerdaten lesen."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"Kalenderdaten lesen"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kalenderereignisse zu lesen. Schädliche Anwendungen können so Ihre Kalenderereignisse an andere Personen senden."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"Kalenderdaten schreiben"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Kalenderereignisse zu ändern. Schädliche Anwendungen können so Ihre Kalenderdaten löschen oder verändern."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"Falsche Standortquellen für Testzwecke"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Auf zusätzliche Dienstanbieterbefehle für Standort zugreifen"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Zugriff auf zusätzliche Dienstanbieterbefehle für Standort. Schädliche Anwendungen könnten so die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"Berechtigung zur Installation eines Standortanbieters"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben oder Ihren Standort überwachen und an eine externe Quelle weitergeben."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"genauer (GPS-) Standort"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Zugriff auf genaue Standortquellen wie GPS auf dem Telefon (falls verfügbar). Schädliche Anwendungen können damit bestimmen, so Sie sich befinden und so Ihren Akku zusätzlich belasten."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ungefährer (netzwerkbasierter) Standort"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzwerks zu, um falls möglich den ungefähren Standort des Telefons zu bestimmen. Schädliche Anwendungen können damit herauszufinden, wo Sie sich ungefähr befinden."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Auf SurfaceFlinger zugreifen"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Frame-Puffer lesen"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Ermöglicht einer Anwendung, den Inhalt des Frame-Puffers zu lesen."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Audio-Einstellungen ändern"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"Audio aufnehmen"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"Fotos aufnehmen"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Ermöglicht der Anwendung, Fotos mit der Kamera aufzunehmen. So kann die Anwendung jederzeit Bilder zusammentragen, die von der Kamera erfasst werden."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"Telefon dauerhaft deaktivieren."</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Ermöglicht der Anwendung, das gesamte Telefon dauerhaft zu deaktivieren. Dies birgt hohe Risiken."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"Neustart des Telefons erzwingen"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Dateisysteme bereitstellen oder Bereitstellung aufheben"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Speicherplätze bereitzustellen oder die Bereitstellung aufzuheben."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"Externen Speicher formatieren"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Erlaubt der Anwendung, austauschbaren Speicher zu formatieren."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"Vibrationsalarm steuern"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"Lichtanzeige steuern"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"Hardware testen"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"Telefonnummern direkt anrufen"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Ermöglicht dem Anwendungen, Rufnummern ohne Ihr Eingreifen zu wählen. Schädliche Anwendungen können für unerwartete Anrufe auf Ihrer Telefonrechnung verantwortlich sein. Das Wählen von Notrufnummern ist allerdings nicht möglich."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"Alle Telefonnummern direkt anrufen"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Ermöglicht der Anwendung, ohne Ihr Eingreifen eine beliebige Telefonnummer zu wählen, einschließlich Notfallnummern. Schädliche Anwendungen können so unnötige und illegale Anrufe an Notdienste tätigen."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"Benachrichtigungen für Standortaktualisierung steuern"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Ermöglicht die Aktivierung/Deaktivierung der Mobilfunkbenachrichtigungen über Standort-Updates. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"Auf Check-In-Eigenschaften zugreifen"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Ermöglicht den Schreib-/Lesezugriff auf vom Check-In-Service hochgeladene Elemente. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"Widgets auswählen"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Ermöglicht der Anwendung, dem System zu melden, welche Widgets von welcher Anwendung verwendet werden können. Mit dieser Berechtigung können Anwendungen anderen Anwendungen Zugriff auf persönliche Daten gewähren. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"Telefonstatus ändern"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Ermöglicht einer Anwendung, die Telefonfunktionen des Gerätes zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder die Mobilfunkverbindung des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
- <string name="permlab_readPhoneState" msgid="2326172951448691631">"Telefonstatus lesen und identifizieren"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"Ermöglicht der Anwendung, auf die Telefonfunktionen des Gerätes zuzugreifen. Eine Anwendung mit dieser Berechtigung kann unter anderem bestimmen, welche Telefonnummer dieses Telefon verwendet, ob ein Anruf aktiv ist oder mit welcher Nummer der Anrufer verbunden ist."</string>
- <string name="permlab_wakeLock" msgid="573480187941496130">"Standby-Modus deaktivieren"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"Gerät ein- oder ausschalten"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"In Werkstestmodus ausführen"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Telefonhardware zugegriffen werden kann. Nur verfügbar, wenn ein Telefon im Werkstestmodus ausgeführt wird."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"Hintergrundbild festlegen"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Ermöglicht der Anwendung, das System-Hintergrundbild festzulegen."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"Größenhinweise für Hintergrundbild festlegen"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Ermöglicht der Anwendung, die Größenhinweise für das Hintergrundbild festzulegen."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"System auf Werkseinstellung zurücksetzen"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Ermöglicht einer Anwendung, das System komplett auf Werkseinstellung zurückzusetzen. Hierbei werden alle Daten, Konfigurationen und installierten Anwendungen gelöscht."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"Zeitzone festlegen"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"bekannte Konten suchen"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"Netzwerkstatus anzeigen"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"Uneingeschränkter Internetzugriff"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"Einstellungen für Zugriffspunktname schreiben"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"Netzwerkkonnektivität ändern"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"Einstellung zur Verwendung von Hintergrunddaten ändern"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"WLAN-Status anzeigen"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"WLAN-Status ändern"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"WLAN-Multicast-Empfang zulassen"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Ermöglicht einer Anwendung, Datenpakete zu empfangen, die nicht direkt an Ihr Gerät gerichtet sind. Dies kann bei der Erkennung von in der Nähe angebotenen Diensten hilfreich sein. Diese Einstellung verbraucht mehr Energie als der Nicht-Multicast-Modus."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth-Verwaltung"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth-Verbindungen herstellen"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"Tastensperre deaktivieren"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Ermöglicht einer Anwendung, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. So wird die Tastensperre vom Telefon deaktiviert, wenn ein Anruf eingeht, und nach Beendigung des Anrufs wieder aktiviert."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"Synchronisierungseinstellungen schreiben"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"Synchronisierungsstatistiken lesen"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"Abonnierte Feeds lesen"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"Abonnierte Feeds schreiben"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Ermöglicht einer Anwendung, Änderungen an den kürzlich synchronisierten Feeds vorzunehmen. Schädliche Anwendungen könnten so Ihre synchronisierten Feeds ändern."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"Nutzerdefiniertes Wörterbuch lesen"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Erlaubt einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"in nutzerdefiniertes Wörterbuch schreiben"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Erlaubt einer Anwendung, neue Wörter in das Wörterbuch des Nutzers zu schreiben."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"SD-Karten-Inhalt ändern/löschen"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Ermöglicht einer Anwendung, auf die SD-Karte zu schreiben"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"&lt;Unbenannt&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Keine Telefonnummer)"</string>
+ <string name="unknownName">"(Unbekannt)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Mailbox"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Verbindungsproblem oder ungültiger MMI-Code."</string>
+ <string name="serviceEnabled">"Dienst wurde aktiviert."</string>
+ <string name="serviceEnabledFor">"Dienst wurde aktiviert für:"</string>
+ <string name="serviceDisabled">"Dienst wurde deaktiviert."</string>
+ <string name="serviceRegistered">"Registrierung war erfolgreich."</string>
+ <string name="serviceErased">"Löschvorgang erfolgreich."</string>
+ <string name="passwordIncorrect">"Falsches Passwort."</string>
+ <string name="mmiComplete">"MMI abgeschlossen."</string>
+ <string name="badPin">"Die von Ihnen eingegebene alte PIN ist nicht korrekt."</string>
+ <string name="badPuk">"Der von Ihnen eingegebene PUK ist nicht korrekt."</string>
+ <string name="mismatchPin">"Die von Ihnen eingegebenen PIN-Nummern stimmen nicht überein."</string>
+ <string name="invalidPin">"Geben Sie eine PIN ein, die 4 bis 8 Zahlen enthält."</string>
+ <string name="needPuk">"Ihre SIM-Karte ist mit einem PUK gesperrt. Geben Sie zum Entsperren den PUK-Code ein."</string>
+ <string name="needPuk2">"Geben Sie zum Entsperren der SIM-Karte den PUK2 ein."</string>
+ <string name="ClipMmi">"Anrufer-ID für eingehenden Anruf"</string>
+ <string name="ClirMmi">"Anrufer-ID für abgehenden Anruf"</string>
+ <string name="CfMmi">"Rufweiterleitung"</string>
+ <string name="CwMmi">"Anklopfen"</string>
+ <string name="BaMmi">"Anrufsperre"</string>
+ <string name="PwdMmi">"Passwort-Änderung"</string>
+ <string name="PinMmi">"PIN-Änderung"</string>
+ <string name="CnipMmi">"Rufnummer vorhanden"</string>
+ <string name="CnirMmi">"Rufnummer begrenzt"</string>
+ <string name="ThreeWCMmi">"Dreierkonferenz"</string>
+ <string name="RuacMmi">"Ablehnung unerwünschter Anrufe"</string>
+ <string name="CndMmi">"Rufnummernübermittlung"</string>
+ <string name="DndMmi">"Bitte nicht stören"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Beschränkt"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Anrufer-ID ist standardmäßig beschränkt. Nächster Anruf: Nicht beschränkt"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Beschränkt"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt"</string>
+ <string name="serviceNotProvisioned">"Dienst nicht eingerichtet."</string>
+ <string name="CLIRPermanent">"Die Einstellung für die Anrufer-ID kann nicht geändert werden."</string>
+ <string name="RestrictedChangedTitle">"Eingeschränkter Zugriff geändert"</string>
+ <string name="RestrictedOnData">"Daten-Dienst ist gesperrt."</string>
+ <string name="RestrictedOnEmergency">"Notruf ist gesperrt."</string>
+ <string name="RestrictedOnNormal">"Sprach-/SMS-Dienst ist gesperrt."</string>
+ <string name="RestrictedOnAll">"Alle Sprach-/SMS-Dienste sind gesperrt."</string>
+ <string name="serviceClassVoice">"Sprachnotiz"</string>
+ <string name="serviceClassData">"Daten"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynchron"</string>
+ <string name="serviceClassDataSync">"Synchron"</string>
+ <string name="serviceClassPacket">"Paket"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Roaming-Anzeige ein"</string>
+ <string name="roamingText1">"Roaming-Anzeige aus"</string>
+ <string name="roamingText2">"Roaming-Anzeige blinkend"</string>
+ <string name="roamingText3">"Außerhalb der Netzwerkumgebung"</string>
+ <string name="roamingText4">"Außerhalb des Gebäudes"</string>
+ <string name="roamingText5">"Roaming - Bevorzugtes System"</string>
+ <string name="roamingText6">"Roaming - Verfügbares System"</string>
+ <string name="roamingText7">"Roaming - Allianzpartner"</string>
+ <string name="roamingText8">"Roaming - Premiumpartner"</string>
+ <string name="roamingText9">"Roaming - Volle Dienstfunktionalität"</string>
+ <string name="roamingText10">"Roaming - Partielle Dienstfunktionalität"</string>
+ <string name="roamingText11">"Roaming-Banner ein"</string>
+ <string name="roamingText12">"Roaming-Banner aus"</string>
+ <string name="roamingTextSearching">"Suche nach Dienst"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> nach <xliff:g id="TIME_DELAY">{2}</xliff:g> Sekunden."</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
+ <string name="fcComplete">"Funktionscode abgeschlossen"</string>
+ <string name="fcError">"Verbindungsproblem oder ungültiger Funktionscode"</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Auf der Webseite ist ein Fehler aufgetreten."</string>
+ <string name="httpErrorLookup">"Die URL konnte nicht gefunden werden."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Das Authentifizierungsschema für die Site wird nicht unterstützt."</string>
+ <string name="httpErrorAuth">"Authentifizierung ist fehlgeschlagen."</string>
+ <string name="httpErrorProxyAuth">"Authentifizierung via Proxy-Server ist fehlgeschlagen."</string>
+ <string name="httpErrorConnect">"Es konnte keine Verbindung zum Server hergestellt werden."</string>
+ <string name="httpErrorIO">"Die Server-Kommunikation ist fehlgeschlagen. Versuchen Sie es später erneut."</string>
+ <string name="httpErrorTimeout">"Zeitüberschreitung bei Serververbindung."</string>
+ <string name="httpErrorRedirectLoop">"Die Seite enthält zu viele Server-Redirects."</string>
+ <string name="httpErrorUnsupportedScheme">"Das Protokoll wird nicht unterstützt."</string>
+ <string name="httpErrorFailedSslHandshake">"Es konnte keine sichere Verbindung aufgebaut werden."</string>
+ <string name="httpErrorBadUrl">"Die Seite konnte nicht geöffnet werden, weil die URL ungültig ist."</string>
+ <string name="httpErrorFile">"Auf die Datei konnte nicht zugegriffen werden."</string>
+ <string name="httpErrorFileNotFound">"Die angeforderte Datei wurde nicht gefunden."</string>
+ <string name="httpErrorTooManyRequests">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuchen Sie es später erneut."</string>
+ <string name="contentServiceSync">"Synchronisieren"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchronisieren"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
+ <string name="low_memory">"Telefonspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
+ <string name="me">"Eigene"</string>
+ <string name="power_dialog">"Telefonoptionen"</string>
+ <string name="silent_mode">"Lautlos-Modus"</string>
+ <string name="turn_on_radio">"Funk einschalten"</string>
+ <string name="turn_off_radio">"Funk ausschalten"</string>
+ <string name="screen_lock">"Bildschirmsperre"</string>
+ <string name="power_off">"Ausschalten"</string>
+ <string name="shutdown_progress">"Herunterfahren..."</string>
+ <string name="shutdown_confirm">"Ihr Telefon wird heruntergefahren."</string>
+ <string name="no_recent_tasks">"Keine neuen Anwendungen."</string>
+ <string name="global_actions">"Telefonoptionen"</string>
+ <string name="global_action_lock">"Bildschirmsperre"</string>
+ <string name="global_action_power_off">"Ausschalten"</string>
+ <string name="global_action_toggle_silent_mode">"Lautlos"</string>
+ <string name="global_action_silent_mode_on_status">"Ton ist bereits AUS"</string>
+ <string name="global_action_silent_mode_off_status">"Ton ist momentan AN"</string>
+ <string name="global_actions_toggle_airplane_mode">"Flugmodus"</string>
+ <string name="global_actions_airplane_mode_on_status">"Flugmodus ist AN"</string>
+ <string name="global_actions_airplane_mode_off_status">"Flugmodus ist AUS"</string>
+ <string name="safeMode">"Abgesicherter Modus"</string>
+ <string name="android_system_label">"Android System"</string>
+ <string name="permgrouplab_costMoney">"Kostenpflichtige Dienste"</string>
+ <string name="permgroupdesc_costMoney">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen."</string>
+ <string name="permgrouplab_messages">"Ihre Nachrichten"</string>
+ <string name="permgroupdesc_messages">"Lesen und schreiben Sie Ihre SMS, E-Mails und anderen Nachrichten."</string>
+ <string name="permgrouplab_personalInfo">"Ihre persönlichen Informationen"</string>
+ <string name="permgroupdesc_personalInfo">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons."</string>
+ <string name="permgrouplab_location">"Ihr Standort"</string>
+ <string name="permgroupdesc_location">"Ihren physischen Standort überwachen"</string>
+ <string name="permgrouplab_network">"Netzwerkkommunikation"</string>
+ <string name="permgroupdesc_network">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen."</string>
+ <string name="permgrouplab_accounts">"Ihre Google-Konten"</string>
+ <string name="permgroupdesc_accounts">"Greift auf verfügbare Google-Konten zu."</string>
+ <string name="permgrouplab_hardwareControls">"Hardware-Steuerelemente"</string>
+ <string name="permgroupdesc_hardwareControls">"Direkter Zugriff auf Hardware über Headset"</string>
+ <string name="permgrouplab_phoneCalls">"Anrufe"</string>
+ <string name="permgroupdesc_phoneCalls">"Ãœberwachen, Aufzeichnen und Verarbeiten von Telefonanrufen"</string>
+ <string name="permgrouplab_systemTools">"System-Tools"</string>
+ <string name="permgroupdesc_systemTools">"Zugriff und Steuerung des Systems auf niedrigerer Ebene."</string>
+ <string name="permgrouplab_developmentTools">"Entwickler-Tools"</string>
+ <string name="permgroupdesc_developmentTools">"Funktionen nur für Anwendungsentwickler vorgesehen."</string>
+ <string name="permgrouplab_storage">"Speicher"</string>
+ <string name="permgroupdesc_storage">"Greift auf die SD-Karte zu."</string>
+ <string name="permlab_statusBar">"Statusleiste deaktivieren oder ändern"</string>
+ <string name="permdesc_statusBar">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen."</string>
+ <string name="permlab_expandStatusBar">"Statusleiste ein-/ausblenden"</string>
+ <string name="permdesc_expandStatusBar">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden."</string>
+ <string name="permlab_processOutgoingCalls">"Abgehende Anrufe abfangen"</string>
+ <string name="permdesc_processOutgoingCalls">"Ermöglicht einer Anwendung, abgehende Anrufe zu verarbeiten und die zu wählende Nummer zu ändern. Schädliche Anwendungen können so abgehende Anrufe eventuell überwachen, umleiten oder verhindern."</string>
+ <string name="permlab_receiveSms">"SMS empfangen"</string>
+ <string name="permdesc_receiveSms">"Ermöglicht der Anwendung, Kurzmitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
+ <string name="permlab_receiveMms">"MMS empfangen"</string>
+ <string name="permdesc_receiveMms">"Ermöglicht der Anwendung, MMS-Mitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
+ <string name="permlab_sendSms">"Kurznachrichten senden"</string>
+ <string name="permdesc_sendSms">"Ermöglicht Anwendungen das Senden von SMS-Nachrichten. Bei schädlichen Anwendungen können Kosten entstehen, wenn diese Nachrichten ohne Ihre Zustimmung versenden."</string>
+ <string name="permlab_readSms">"SMS oder MMS lesen"</string>
+ <string name="permdesc_readSms">"Ermöglicht einer Anwendung, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte Kurznachrichten zu lesen. Schädliche Anwendungen lesen so möglicherweise Ihre vertraulichen Nachrichten."</string>
+ <string name="permlab_writeSms">"SMS oder MMS bearbeiten"</string>
+ <string name="permdesc_writeSms">"Ermöglicht einer Anwendung, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte Kurznachrichten zu bearbeiten. Schädliche Anwendungen löschen möglicherweise Ihre Nachrichten."</string>
+ <string name="permlab_receiveWapPush">"WAP-Nachrichten empfangen"</string>
+ <string name="permdesc_receiveWapPush">"Ermöglicht der Anwendung, WAP-Mitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
+ <string name="permlab_getTasks">"Laufende Anwendungen abrufen"</string>
+ <string name="permdesc_getTasks">"Ermöglicht der Anwendung, Informationen zu aktuellen und kürzlich ausführten Aufgaben abzurufen. Schädliche Anwendungen können so eventuell geheime Informationen zu anderen Anwendungen entdecken."</string>
+ <string name="permlab_reorderTasks">"Laufende Anwendungen neu ordnen"</string>
+ <string name="permdesc_reorderTasks">"Ermöglicht einer Anwendung, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Anwendungen können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
+ <string name="permlab_setDebugApp">"Fehlerbeseitigung für Anwendung aktivieren"</string>
+ <string name="permdesc_setDebugApp">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
+ <string name="permlab_changeConfiguration">"UI-Einstellungen ändern"</string>
+ <string name="permdesc_changeConfiguration">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße."</string>
+ <string name="permlab_restartPackages">"Andere Anwendungen neu starten"</string>
+ <string name="permdesc_restartPackages">"Ermöglicht einer Anwendung, den Neustart anderer Anwendungen zu erzwingen."</string>
+ <string name="permlab_forceBack">"Schließen von Anwendung erzwingen"</string>
+ <string name="permdesc_forceBack">"Ermöglicht einer Anwendung, alle Aktivitäten, die im Vordergrund ablaufen, zu beenden und in den Hintergrund zu schieben. Sollte nicht für normale Anwendungen benötigt werden."</string>
+ <string name="permlab_dump">"Systeminternen Status abrufen"</string>
+ <string name="permdesc_dump">"Ermöglicht einer Anwendung, den internen Status des Systems abzurufen. Schädliche Anwendungen rufen hierbei möglicherweise eine Vielzahl an privaten und geschützten Daten ab, die Sie in der Regel nicht benötigen würden."</string>
+ <string name="permlab_shutdown">"partielles Herunterfahren"</string>
+ <string name="permdesc_shutdown">"Versetzt den Aktivitätsmanager in einen heruntergefahrenen Zustand. Führt kein vollständiges Herunterfahren aus."</string>
+ <string name="permlab_stopAppSwitches">"Anwendungswechsel verhindern"</string>
+ <string name="permdesc_stopAppSwitches">"Hindert den Nutzer daran, zu einer anderen Anwendung zu wechseln"</string>
+ <string name="permlab_runSetActivityWatcher">"Start von Anwendungen überwachen und steuern"</string>
+ <string name="permdesc_runSetActivityWatcher">"Ermöglicht der Anwendung, den Start von Systemaktivitäten zu überwachen und zu steuern. Schädliche Anwendungen können so das gesamte System beeinträchtigen. Diese Berechtigung wird nur zu Entwicklungszwecken und nie für die normale Telefonnutzung benötigt."</string>
+ <string name="permlab_broadcastPackageRemoved">"Broadcast ohne Paket senden"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Ermöglicht einer Anwendung, eine Benachrichtigung zur Entfernung eines Anwendungspakets zu senden. Schädliche Anwendungen können so laufende Anwendungen beenden."</string>
+ <string name="permlab_broadcastSmsReceived">"per SMS empfangenen Broadcast senden"</string>
+ <string name="permdesc_broadcastSmsReceived">"Ermöglicht einer Anwendung, eine Benachrichtigung zu senden, dass eine Kurzmitteilung empfangen wurde. Schädliche Anwendungen könnten diese Option verwenden, um den Eingang von Kurzmitteilungen zu erzwingen."</string>
+ <string name="permlab_broadcastWapPush">"von WAP-PUSH empfangenen Broadcast senden"</string>
+ <string name="permdesc_broadcastWapPush">"Ermöglicht einer Anwendung, eine Benachrichtigung zu senden, dass eine WAP PUSH-Nachricht empfangen wurde. Schädliche Anwendungen könnten diese Option verwenden, um den Erhalt von MMS-Mitteilungen zu erzwingen, oder um unbemerkt den Inhalt einer beliebigen Webseite durch schädliche Inhalte zu ersetzen."</string>
+ <string name="permlab_setProcessLimit">"Anzahl der laufenden Prozesse beschränken"</string>
+ <string name="permdesc_setProcessLimit">"Ermöglicht einer Anwendung, die maximale Anzahl an laufenden Prozessen zu steuern. Wird nicht für normale Anwendungen benötigt."</string>
+ <string name="permlab_setAlwaysFinish">"alle Anwendungen im Hintergrund schließen"</string>
+ <string name="permdesc_setAlwaysFinish">"Überlässt einer Anwendung die Entscheidung, ob Aktivitäten beendet werden, sobald Sie in den Hintergrund rücken. Wird nicht für normale Anwendungen benötigt."</string>
+ <string name="permlab_batteryStats">"Akku-Daten ändern"</string>
+ <string name="permdesc_batteryStats">"Ermöglicht die Änderung von gesammelten Akku-Daten. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_backup">"Systemsicherung und -wiederherstellung kontrollieren"</string>
+ <string name="permdesc_backup">"Ermöglicht der Anwendung, den Sicherungs- und Wiederherstellungsmechanismus des Systems zu kontrollieren. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_internalSystemWindow">"nicht autorisierte Fenster anzeigen"</string>
+ <string name="permdesc_internalSystemWindow">"Ermöglicht die Erstellung von Fenstern, die von der Benutzeroberfläche des internen Systems verwendet werden. Nicht für normale Anwendungen geeignet."</string>
+ <string name="permlab_systemAlertWindow">"Warnungen auf Systemebene anzeigen"</string>
+ <string name="permdesc_systemAlertWindow">"Ermöglicht einer Anwendung, Fenster mit Systemwarnungen anzuzeigen. Schädliche Anwendungen können so das gesamte Display des Telefons einnehmen."</string>
+ <string name="permlab_setAnimationScale">"Allgemeine Animationsgeschwindigkeit einstellen"</string>
+ <string name="permdesc_setAnimationScale">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen."</string>
+ <string name="permlab_manageAppTokens">"Anwendungs-Tokens verwalten"</string>
+ <string name="permdesc_manageAppTokens">"Ermöglicht Anwendungen, Ihre eigenen Tokens zu erstellen und zu verwalten. Hierbei wird die normale Z-Reihenfolge umgangen. Dies sollte nicht für normale Anwendungen benötigt werden."</string>
+ <string name="permlab_injectEvents">"Tasten und Steuerungstasten drücken"</string>
+ <string name="permdesc_injectEvents">"Ermöglicht einer Anwendung, ihre eigenen Eingabeaktionen (Drücken von Tasten etc.) an andere Anwendungen zu liefern. Schädliche Anwendungen können so die Kontrolle über Ihr Telefon übernehmen."</string>
+ <string name="permlab_readInputState">"Tastatureingaben und Aktionen aufzeichnen"</string>
+ <string name="permdesc_readInputState">"Ermöglicht Anwendungen, die von Ihnen gedrückten Tasten zu überwachen (etwa die Eingabe eines Passworts). Dies gilt auch für die Interaktion mit anderen Anwendungen. Sollte für normale Anwendungen nicht benötigt werden."</string>
+ <string name="permlab_bindInputMethod">"An eine Eingabemethode binden"</string>
+ <string name="permdesc_bindInputMethod">"Ermöglicht dem Halter, sich an die Oberfläche einer Eingabemethode auf oberster Ebene zu binden. Sollte nie für normale Anwendungen benötigt werden."</string>
+ <string name="permlab_setOrientation">"Bildschirmausrichtung ändern"</string>
+ <string name="permdesc_setOrientation">"Ermöglicht der Anwendung, die Bildschirmdrehung jederzeit zu ändern. Sollte nicht für normale Anwendungen benötigt werden."</string>
+ <string name="permlab_signalPersistentProcesses">"Linux-Signale an Anwendungen senden"</string>
+ <string name="permdesc_signalPersistentProcesses">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern."</string>
+ <string name="permlab_persistentActivity">"Anwendungen permanent ausführen"</string>
+ <string name="permdesc_persistentActivity">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann."</string>
+ <string name="permlab_deletePackages">"Anwendungen löschen"</string>
+ <string name="permdesc_deletePackages">"Ermöglicht einer Anwendung, Android-Pakete zu löschen. Schädliche Anwendungen können so wichtige Anwendungen löschen."</string>
+ <string name="permlab_clearAppUserData">"Daten anderer Anwendungen löschen"</string>
+ <string name="permdesc_clearAppUserData">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten."</string>
+ <string name="permlab_deleteCacheFiles">"Caches anderer Anwendungen löschen"</string>
+ <string name="permdesc_deleteCacheFiles">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen."</string>
+ <string name="permlab_getPackageSize">"Speicherplatz der Anwendung abrufen"</string>
+ <string name="permdesc_getPackageSize">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen."</string>
+ <string name="permlab_installPackages">"Anwendungen direkt installieren"</string>
+ <string name="permdesc_installPackages">"Ermöglicht einer Anwendung, neue oder aktualisierte Android-Pakete zu installieren. Schädliche Anwendungen können so neue Anwendungen mit beliebig umfangreichen Berechtigungen hinzufügen."</string>
+ <string name="permlab_clearAppCache">"Alle Cache-Daten der Anwendung löschen"</string>
+ <string name="permdesc_clearAppCache">"Ermöglicht einer Anwendung, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
+ <string name="permlab_readLogs">"System-Protokolldateien lesen"</string>
+ <string name="permdesc_readLogs">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden, diese sollten jedoch keine persönlichen oder geheimen Daten enthalten."</string>
+ <string name="permlab_diagnostic">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
+ <string name="permdesc_diagnostic">"Ermöglicht einer Anwendung, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für Hardware-spezifische Diagnosen des Herstellers oder Netzbetreibers verwendet werden."</string>
+ <string name="permlab_changeComponentState">"Anwendungskomponenten aktivieren oder deaktivieren"</string>
+ <string name="permdesc_changeComponentState">"Ermöglicht einer Anwendung, die Komponente einer anderen Anwendung nach Belieben zu aktivieren oder zu deaktivieren. Schädliche Anwendungen können so wichtige Funktionen des Telefons deaktivieren. Bei der Erteilung von Berechtigungen ist daher Vorsicht geboten, da die Anwendungskomponenten unbrauchbar, inkonsistent und unstabil werden können."</string>
+ <string name="permlab_setPreferredApplications">"Bevorzugte Einstellungen festlegen"</string>
+ <string name="permdesc_setPreferredApplications">"Ermöglicht einer Anwendung, Ihre bevorzugten Einstellungen zu ändern. Schädliche Anwendungen können so laufende Anwendungen ohne Ihr Wissen ändern, damit die vorhandenen Anwendungen private Daten von Ihnen sammeln."</string>
+ <string name="permlab_writeSettings">"Allgemeine Systemeinstellungen ändern"</string>
+ <string name="permdesc_writeSettings">"Ermöglicht einer Anwendung, die Einstellungsdaten des Systems zu ändern. Schädliche Anwendungen können so die Systemkonfiguration beschädigen."</string>
+ <string name="permlab_writeSecureSettings">"Sicherheitseinstellungen für das System ändern"</string>
+ <string name="permdesc_writeSecureSettings">"Ermöglicht einer Anwendung, die Daten der Sicherheitseinstellungen des Systems zu ändern. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_writeGservices">"Google Services Map ändern"</string>
+ <string name="permdesc_writeGservices">"Ermöglicht einer Anwendung, Änderungen an der Google Services Map vorzunehmen. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_receiveBootCompleted">"Automatisch nach dem Booten starten"</string>
+ <string name="permdesc_receiveBootCompleted">"Ermöglicht einer Anwendung, sich selbst zu starten, sobald das System gebootet wurde. Dadurch kann es länger dauern, bis das Telefon gestartet wird, und durch die ständige Aktivität der Anwendung wird die gesamte Leistung des Telefons beeinträchtigt."</string>
+ <string name="permlab_broadcastSticky">"dauerhaften Broadcast senden"</string>
+ <string name="permdesc_broadcastSticky">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Telefon langsam oder unstabil machen, da zuviel Speicherplatz belegt ist."</string>
+ <string name="permlab_readContacts">"Kontaktdaten lesen"</string>
+ <string name="permdesc_readContacts">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu lesen. Schädliche Anwendungen können so Ihre Daten an andere Personen senden."</string>
+ <string name="permlab_writeContacts">"Kontaktdaten schreiben"</string>
+ <string name="permdesc_writeContacts">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu ändern. Schädliche Anwendungen können so Ihre Kontaktdaten löschen oder verändern."</string>
+ <string name="permlab_writeOwnerData">"Eigentümerdaten schreiben"</string>
+ <string name="permdesc_writeOwnerData">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Eigentümerdaten zu ändern. Schädliche Anwendungen können so Eigentümerdaten löschen oder verändern."</string>
+ <string name="permlab_readOwnerData">"Eigentümerdaten lesen"</string>
+ <string name="permdesc_readOwnerData">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Eigentümerdaten zu lesen. Schädliche Anwendungen können so Eigentümerdaten lesen."</string>
+ <string name="permlab_readCalendar">"Kalenderdaten lesen"</string>
+ <string name="permdesc_readCalendar">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kalenderereignisse zu lesen. Schädliche Anwendungen können so Ihre Kalenderereignisse an andere Personen senden."</string>
+ <string name="permlab_writeCalendar">"Kalenderdaten schreiben"</string>
+ <string name="permdesc_writeCalendar">"Ermöglicht einer Anwendung, die auf Ihrem Telefon gespeicherten Kalenderereignisse zu ändern. Schädliche Anwendungen können so Ihre Kalenderdaten löschen oder verändern."</string>
+ <string name="permlab_accessMockLocation">"Falsche Standortquellen für Testzwecke"</string>
+ <string name="permdesc_accessMockLocation">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben."</string>
+ <string name="permlab_accessLocationExtraCommands">"Auf zusätzliche Dienstanbieterbefehle für Standort zugreifen"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Zugriff auf zusätzliche Dienstanbieterbefehle für Standort. Schädliche Anwendungen könnten so die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
+ <string name="permlab_installLocationProvider">"Berechtigung zur Installation eines Standortanbieters"</string>
+ <string name="permdesc_installLocationProvider">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben oder Ihren Standort überwachen und an eine externe Quelle weitergeben."</string>
+ <string name="permlab_accessFineLocation">"genauer (GPS-) Standort"</string>
+ <string name="permdesc_accessFineLocation">"Zugriff auf genaue Standortquellen wie GPS auf dem Telefon (falls verfügbar). Schädliche Anwendungen können damit bestimmen, so Sie sich befinden und so Ihren Akku zusätzlich belasten."</string>
+ <string name="permlab_accessCoarseLocation">"ungefährer (netzwerkbasierter) Standort"</string>
+ <string name="permdesc_accessCoarseLocation">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzwerks zu, um falls möglich den ungefähren Standort des Telefons zu bestimmen. Schädliche Anwendungen können damit herauszufinden, wo Sie sich ungefähr befinden."</string>
+ <string name="permlab_accessSurfaceFlinger">"Auf SurfaceFlinger zugreifen"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden."</string>
+ <string name="permlab_readFrameBuffer">"Frame-Puffer lesen"</string>
+ <string name="permdesc_readFrameBuffer">"Ermöglicht einer Anwendung, den Inhalt des Frame-Puffers zu lesen."</string>
+ <string name="permlab_modifyAudioSettings">"Audio-Einstellungen ändern"</string>
+ <string name="permdesc_modifyAudioSettings">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen."</string>
+ <string name="permlab_recordAudio">"Audio aufnehmen"</string>
+ <string name="permdesc_recordAudio">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen."</string>
+ <string name="permlab_camera">"Fotos aufnehmen"</string>
+ <string name="permdesc_camera">"Ermöglicht der Anwendung, Fotos mit der Kamera aufzunehmen. So kann die Anwendung jederzeit Bilder zusammentragen, die von der Kamera erfasst werden."</string>
+ <string name="permlab_brick">"Telefon dauerhaft deaktivieren."</string>
+ <string name="permdesc_brick">"Ermöglicht der Anwendung, das gesamte Telefon dauerhaft zu deaktivieren. Dies birgt hohe Risiken."</string>
+ <string name="permlab_reboot">"Neustart des Telefons erzwingen"</string>
+ <string name="permdesc_reboot">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen."</string>
+ <string name="permlab_mount_unmount_filesystems">"Dateisysteme bereitstellen oder Bereitstellung aufheben"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Speicherplätze bereitzustellen oder die Bereitstellung aufzuheben."</string>
+ <string name="permlab_mount_format_filesystems">"Externen Speicher formatieren"</string>
+ <string name="permdesc_mount_format_filesystems">"Erlaubt der Anwendung, austauschbaren Speicher zu formatieren."</string>
+ <string name="permlab_vibrate">"Vibrationsalarm steuern"</string>
+ <string name="permdesc_vibrate">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern."</string>
+ <string name="permlab_flashlight">"Lichtanzeige steuern"</string>
+ <string name="permdesc_flashlight">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern."</string>
+ <string name="permlab_hardware_test">"Hardware testen"</string>
+ <string name="permdesc_hardware_test">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern."</string>
+ <string name="permlab_callPhone">"Telefonnummern direkt anrufen"</string>
+ <string name="permdesc_callPhone">"Ermöglicht dem Anwendungen, Rufnummern ohne Ihr Eingreifen zu wählen. Schädliche Anwendungen können für unerwartete Anrufe auf Ihrer Telefonrechnung verantwortlich sein. Das Wählen von Notrufnummern ist allerdings nicht möglich."</string>
+ <string name="permlab_callPrivileged">"Alle Telefonnummern direkt anrufen"</string>
+ <string name="permdesc_callPrivileged">"Ermöglicht der Anwendung, ohne Ihr Eingreifen eine beliebige Telefonnummer zu wählen, einschließlich Notfallnummern. Schädliche Anwendungen können so unnötige und illegale Anrufe an Notdienste tätigen."</string>
+ <string name="permlab_locationUpdates">"Benachrichtigungen für Standortaktualisierung steuern"</string>
+ <string name="permdesc_locationUpdates">"Ermöglicht die Aktivierung/Deaktivierung der Mobilfunkbenachrichtigungen über Standort-Updates. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_checkinProperties">"Auf Check-In-Eigenschaften zugreifen"</string>
+ <string name="permdesc_checkinProperties">"Ermöglicht den Schreib-/Lesezugriff auf vom Check-In-Service hochgeladene Elemente. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_bindGadget">"Widgets auswählen"</string>
+ <string name="permdesc_bindGadget">"Ermöglicht der Anwendung, dem System zu melden, welche Widgets von welcher Anwendung verwendet werden können. Mit dieser Berechtigung können Anwendungen anderen Anwendungen Zugriff auf persönliche Daten gewähren. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_modifyPhoneState">"Telefonstatus ändern"</string>
+ <string name="permdesc_modifyPhoneState">"Ermöglicht einer Anwendung, die Telefonfunktionen des Gerätes zu steuern. Eine Anwendung mit dieser Berechtigung kann unter anderem das Netzwerk wechseln oder die Mobilfunkverbindung des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
+ <string name="permlab_readPhoneState">"Telefonstatus lesen"</string>
+ <string name="permdesc_readPhoneState">"Ermöglicht der Anwendung, auf die Telefonfunktionen des Gerätes zuzugreifen. Eine Anwendung mit dieser Berechtigung kann unter anderem bestimmen, welche Telefonnummer dieses Telefon verwendet, ob ein Anruf aktiv ist oder mit welcher Nummer der Anrufer verbunden ist."</string>
+ <string name="permlab_wakeLock">"Standby-Modus deaktivieren"</string>
+ <string name="permdesc_wakeLock">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren."</string>
+ <string name="permlab_devicePower">"Gerät ein- oder ausschalten"</string>
+ <string name="permdesc_devicePower">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten."</string>
+ <string name="permlab_factoryTest">"In Werkstestmodus ausführen"</string>
+ <string name="permdesc_factoryTest">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Telefonhardware zugegriffen werden kann. Nur verfügbar, wenn ein Telefon im Werkstestmodus ausgeführt wird."</string>
+ <string name="permlab_setWallpaper">"Hintergrundbild festlegen"</string>
+ <string name="permdesc_setWallpaper">"Ermöglicht der Anwendung, das System-Hintergrundbild festzulegen."</string>
+ <string name="permlab_setWallpaperHints">"Größenhinweise für Hintergrundbild festlegen"</string>
+ <string name="permdesc_setWallpaperHints">"Ermöglicht der Anwendung, die Größenhinweise für das Hintergrundbild festzulegen."</string>
+ <string name="permlab_masterClear">"System auf Werkseinstellung zurücksetzen"</string>
+ <string name="permdesc_masterClear">"Ermöglicht einer Anwendung, das System komplett auf Werkseinstellung zurückzusetzen. Hierbei werden alle Daten, Konfigurationen und installierten Anwendungen gelöscht."</string>
+ <string name="permlab_setTimeZone">"Zeitzone festlegen"</string>
+ <string name="permdesc_setTimeZone">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern."</string>
+ <string name="permlab_getAccounts">"bekannte Konten suchen"</string>
+ <string name="permdesc_getAccounts">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen."</string>
+ <string name="permlab_accessNetworkState">"Netzwerkstatus anzeigen"</string>
+ <string name="permdesc_accessNetworkState">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen."</string>
+ <string name="permlab_createNetworkSockets">"Uneingeschränkter Internetzugriff"</string>
+ <string name="permdesc_createNetworkSockets">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten."</string>
+ <string name="permlab_writeApnSettings">"Einstellungen für Zugriffspunktname schreiben"</string>
+ <string name="permdesc_writeApnSettings">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern."</string>
+ <string name="permlab_changeNetworkState">"Netzwerkkonnektivität ändern"</string>
+ <string name="permdesc_changeNetworkState">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern."</string>
+ <string name="permlab_changeBackgroundDataSetting">"Einstellung zur Verwendung von Hintergrunddaten ändern"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern."</string>
+ <string name="permlab_accessWifiState">"WLAN-Status anzeigen"</string>
+ <string name="permdesc_accessWifiState">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen."</string>
+ <string name="permlab_changeWifiState">"WLAN-Status ändern"</string>
+ <string name="permdesc_changeWifiState">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen."</string>
+ <string name="permlab_changeWifiMulticastState">"WLAN-Multicast-Empfang zulassen"</string>
+ <string name="permdesc_changeWifiMulticastState">"Ermöglicht einer Anwendung, Datenpakete zu empfangen, die nicht direkt an Ihr Gerät gerichtet sind. Dies kann bei der Erkennung von in der Nähe angebotenen Diensten hilfreich sein. Diese Einstellung verbraucht mehr Energie als der Nicht-Multicast-Modus."</string>
+ <string name="permlab_bluetoothAdmin">"Bluetooth-Verwaltung"</string>
+ <string name="permdesc_bluetoothAdmin">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen."</string>
+ <string name="permlab_bluetooth">"Bluetooth-Verbindungen herstellen"</string>
+ <string name="permdesc_bluetooth">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren."</string>
+ <string name="permlab_disableKeyguard">"Tastensperre deaktivieren"</string>
+ <string name="permdesc_disableKeyguard">"Ermöglicht einer Anwendung, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. So wird die Tastensperre vom Telefon deaktiviert, wenn ein Anruf eingeht, und nach Beendigung des Anrufs wieder aktiviert."</string>
+ <string name="permlab_readSyncSettings">"Synchronisierungseinstellungen lesen"</string>
+ <string name="permdesc_readSyncSettings">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+ <string name="permlab_writeSyncSettings">"Synchronisierungseinstellungen schreiben"</string>
+ <string name="permdesc_writeSyncSettings">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+ <string name="permlab_readSyncStats">"Synchronisierungsstatistiken lesen"</string>
+ <string name="permdesc_readSyncStats">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen."</string>
+ <string name="permlab_subscribedFeedsRead">"Abonnierte Feeds lesen"</string>
+ <string name="permdesc_subscribedFeedsRead">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen."</string>
+ <string name="permlab_subscribedFeedsWrite">"Abonnierte Feeds schreiben"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Ermöglicht einer Anwendung, Änderungen an den kürzlich synchronisierten Feeds vorzunehmen. Schädliche Anwendungen könnten so Ihre synchronisierten Feeds ändern."</string>
+ <string name="permlab_readDictionary">"Nutzerdefiniertes Wörterbuch lesen"</string>
+ <string name="permdesc_readDictionary">"Erlaubt einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat."</string>
+ <string name="permlab_writeDictionary">"in nutzerdefiniertes Wörterbuch schreiben"</string>
+ <string name="permdesc_writeDictionary">"Erlaubt einer Anwendung, neue Wörter in das Wörterbuch des Nutzers zu schreiben."</string>
+ <string name="permlab_sdcardWrite">"SD-Karten-Inhalt ändern/löschen"</string>
+ <string name="permdesc_sdcardWrite">"Ermöglicht einer Anwendung, auf die SD-Karte zu schreiben"</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Privat"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Arbeit"</item>
- <item msgid="1103601433382158155">"Fax (Arbeit)"</item>
- <item msgid="1735177144948329370">"Fax (privat)"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Andere"</item>
- <item msgid="9192514806975898961">"Benutzerdefiniert"</item>
+ <item>"Privat"</item>
+ <item>"Mobil"</item>
+ <item>"Arbeit"</item>
+ <item>"Fax (Arbeit)"</item>
+ <item>"Fax (privat)"</item>
+ <item>"Pager"</item>
+ <item>"Andere"</item>
+ <item>"Benutzerdefiniert"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Privat"</item>
- <item msgid="7084237356602625604">"Arbeit"</item>
- <item msgid="1112044410659011023">"Andere"</item>
- <item msgid="2374913952870110618">"Benutzerdefiniert"</item>
+ <item>"Privat"</item>
+ <item>"Arbeit"</item>
+ <item>"Andere"</item>
+ <item>"Benutzerdefiniert"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobil"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Privat"</item>
- <item msgid="5629153956045109251">"Arbeit"</item>
- <item msgid="4966604264500343469">"Andere"</item>
- <item msgid="4932682847595299369">"Benutzerdefiniert"</item>
+ <item>"Privat"</item>
+ <item>"Arbeit"</item>
+ <item>"Andere"</item>
+ <item>"Benutzerdefiniert"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Privat"</item>
- <item msgid="1359644565647383708">"Arbeit"</item>
- <item msgid="7868549401053615677">"Andere"</item>
- <item msgid="3145118944639869809">"Benutzerdefiniert"</item>
+ <item>"Privat"</item>
+ <item>"Arbeit"</item>
+ <item>"Andere"</item>
+ <item>"Benutzerdefiniert"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Arbeit"</item>
- <item msgid="4378074129049520373">"Andere"</item>
- <item msgid="3455047468583965104">"Benutzerdefiniert"</item>
+ <item>"Arbeit"</item>
+ <item>"Andere"</item>
+ <item>"Benutzerdefiniert"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN-Code eingeben"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Falscher PIN-Code!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Notrufnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(kein Dienst)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Display gesperrt."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Drücken Sie die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Zum Entsperren die Menütaste drücken"</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Schema für Entsperrung zeichnen"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Notruf"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Korrekt!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Tut uns leid. Versuchen Sie es noch einmal."</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Wird geladen (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Aufgeladen"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Bitte Ladegerät anschließen"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Keine SIM-Karte."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Keine SIM-Karte im Telefon."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Bitte legen Sie eine SIM-Karte ein."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netzwerk gesperrt"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Weitere Informationen finden Sie in der Bedienungsanleitung oder wenden Sie sich an den Kundendienst."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Bitte PIN-Code eingeben"</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-Karte wird entsperrt..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Muster vergessen?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Zu viele Versuche!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Melden Sie sich zum Entsperren mit Ihrem Google-Konto an."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nutzername (E-Mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Passwort"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Anmelden"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ungültiger Nutzername oder ungültiges Passwort."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Löschen"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Keine Benachrichtigungen"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktuell"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Benachrichtigungen"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Wird aufgeladen..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Ladegerät anschließen"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Akku ist fast leer."</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"Nur noch weniger als <xliff:g id="NUMBER">%d%%</xliff:g> vorhanden."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Warum?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Werkstest fehlgeschlagen"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Die Aktion FACTORY_TEST wird nur für unter \"/system/app\" gespeicherte Pakete unterstützt."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Es wurden kein Paket mit der Aktion FACTORY_TEST gefunden."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Neu booten"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Die Seite auf \'<xliff:g id="TITLE">%s</xliff:g>\' sagt:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Von dieser Seite navigieren?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wählen Sie \"OK\", um fortzufahren, oder wählen Sie \"Abbrechen\", um auf der aktuellen Seite zu bleiben."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Bestätigen"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Browserverlauf und Lesezeichen lesen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ermöglicht der Anwendung, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"Browserverlauf und Lesezeichen schreiben"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Ermöglicht einer Anwendung, den auf Ihrem Telefon gespeicherten Browserverlauf und die Lesezeichen zu ändern. Schädliche Anwendungen können so Ihre Browserdaten löschen oder ändern."</string>
- <string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Niemals"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Sie sind zum Öffnen dieser Seite nicht berechtigt."</string>
- <string name="text_copied" msgid="4985729524670131385">"Text in Zwischenablage kopiert."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Mehr"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menü+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"Leerzeichen"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"löschen"</string>
- <string name="search_go" msgid="8298016669822141719">"Suche"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
+ <string name="keyguard_password_enter_pin_code">"PIN-Code eingeben"</string>
+ <string name="keyguard_password_wrong_pin_code">"Falscher PIN-Code!"</string>
+ <string name="keyguard_label_text">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
+ <string name="emergency_call_dialog_number_for_display">"Notrufnummer"</string>
+ <string name="lockscreen_carrier_default">"(kein Dienst)"</string>
+ <string name="lockscreen_screen_locked">"Display gesperrt."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Drücken Sie die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Zum Entsperren die Menütaste drücken"</string>
+ <string name="lockscreen_pattern_instructions">"Schema für Entsperrung zeichnen"</string>
+ <string name="lockscreen_emergency_call">"Notruf"</string>
+ <string name="lockscreen_pattern_correct">"Korrekt!"</string>
+ <string name="lockscreen_pattern_wrong">"Tut uns leid. Versuchen Sie es noch einmal."</string>
+ <string name="lockscreen_plugged_in">"Wird geladen (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Bitte Ladegerät anschließen"</string>
+ <string name="lockscreen_missing_sim_message_short">"Keine SIM-Karte."</string>
+ <string name="lockscreen_missing_sim_message">"Keine SIM-Karte im Telefon."</string>
+ <string name="lockscreen_missing_sim_instructions">"Bitte legen Sie eine SIM-Karte ein."</string>
+ <string name="lockscreen_network_locked_message">"Netzwerk gesperrt"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Weitere Informationen finden Sie in der Bedienungsanleitung oder wenden Sie sich an den Kundendienst."</string>
+ <string name="lockscreen_sim_locked_message">"Bitte PIN-Code eingeben"</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM-Karte wird entsperrt..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Muster vergessen?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Zu viele Versuche!"</string>
+ <string name="lockscreen_glogin_instructions">"Melden Sie sich zum Entsperren mit Ihrem Google-Konto an."</string>
+ <string name="lockscreen_glogin_username_hint">"Nutzername (E-Mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Passwort"</string>
+ <string name="lockscreen_glogin_submit_button">"Anmelden"</string>
+ <string name="lockscreen_glogin_invalid_input">"Ungültiger Nutzername oder ungültiges Passwort."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Keine Benachrichtigungen"</string>
+ <string name="status_bar_ongoing_events_title">"Aktuell"</string>
+ <string name="status_bar_latest_events_title">"Benachrichtigungen"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Wird aufgeladen..."</string>
+ <string name="battery_low_title">"Ladegerät anschließen"</string>
+ <string name="battery_low_subtitle">"Akku ist fast leer."</string>
+ <string name="battery_low_percent_format">"Nur noch weniger als <xliff:g id="NUMBER">%d%%</xliff:g> vorhanden."</string>
+ <string name="battery_low_why">"Warum?"</string>
+ <string name="factorytest_failed">"Werkstest fehlgeschlagen"</string>
+ <string name="factorytest_not_system">"Die Aktion FACTORY_TEST wird nur für unter \"/system/app\" gespeicherte Pakete unterstützt."</string>
+ <string name="factorytest_no_action">"Es wurden kein Paket mit der Aktion FACTORY_TEST gefunden."</string>
+ <string name="factorytest_reboot">"Neu booten"</string>
+ <string name="js_dialog_title">"Die Seite auf \'<xliff:g id="TITLE">%s</xliff:g>\' sagt:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Von dieser Seite navigieren?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wählen Sie \"OK\", um fortzufahren, oder wählen Sie \"Abbrechen\", um auf der aktuellen Seite zu bleiben."</string>
+ <string name="save_password_label">"Bestätigen"</string>
+ <string name="permlab_readHistoryBookmarks">"Browserverlauf und Lesezeichen lesen"</string>
+ <string name="permdesc_readHistoryBookmarks">"Ermöglicht der Anwendung, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen."</string>
+ <string name="permlab_writeHistoryBookmarks">"Browserverlauf und Lesezeichen schreiben"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Ermöglicht einer Anwendung, den auf Ihrem Telefon gespeicherten Browserverlauf und die Lesezeichen zu ändern. Schädliche Anwendungen können so Ihre Browserdaten löschen oder ändern."</string>
+ <string name="save_password_message">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
+ <string name="save_password_notnow">"Nicht jetzt"</string>
+ <string name="save_password_remember">"Speichern"</string>
+ <string name="save_password_never">"Niemals"</string>
+ <string name="open_permission_deny">"Sie sind zum Öffnen dieser Seite nicht berechtigt."</string>
+ <string name="text_copied">"Text in Zwischenablage kopiert."</string>
+ <string name="more_item_label">"Mehr"</string>
+ <string name="prepend_shortcut_label">"Menü+"</string>
+ <string name="menu_space_shortcut_label">"Leerzeichen"</string>
+ <string name="menu_enter_shortcut_label">"Enter"</string>
+ <string name="menu_delete_shortcut_label">"löschen"</string>
+ <string name="search_go">"Suche"</string>
+ <string name="oneMonthDurationPast">"Vor 1 Monat"</string>
+ <string name="beforeOneMonthDurationPast">"Vor mehr als 1 Monat"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Vor 1 Sekunde"</item>
- <item quantity="other" msgid="3903706804349556379">"Vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ <item quantity="one">"Vor 1 Sekunde"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Vor 1 Minute"</item>
- <item quantity="other" msgid="2176942008915455116">"Vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ <item quantity="one">"Vor 1 Minute"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Vor 1 Stunde"</item>
- <item quantity="other" msgid="2467273239587587569">"Vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ <item quantity="one">"Vor 1 Stunde"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"Gestern"</item>
- <item quantity="other" msgid="2479586466153314633">"Vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+ <item quantity="one">"Gestern"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"in 1 Sekunde"</item>
- <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ <item quantity="one">"in 1 Sekunde"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"in 1 Minute"</item>
- <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ <item quantity="one">"in 1 Minute"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"in 1 Stunde"</item>
- <item quantity="other" msgid="547290677353727389">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ <item quantity="one">"in 1 Stunde"</item>
+ <item quantity="other">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+ <item quantity="one">"morgen"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"vor 1 Sekunde"</item>
- <item quantity="other" msgid="3699169366650930415">"Vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ <item quantity="one">"vor 1 Sekunde"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"vor 1 Minute"</item>
- <item quantity="other" msgid="851164968597150710">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ <item quantity="one">"vor 1 Minute"</item>
+ <item quantity="other">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Vor 1 Stunde"</item>
- <item quantity="other" msgid="6889970745748538901">"Vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ <item quantity="one">"Vor 1 Stunde"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"Gestern"</item>
- <item quantity="other" msgid="3453342639616481191">"Vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+ <item quantity="one">"Gestern"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"in 1 Sekunde"</item>
- <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ <item quantity="one">"in 1 Sekunde"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"in 1 Minute"</item>
- <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ <item quantity="one">"in 1 Minute"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"in 1 Stunde"</item>
- <item quantity="other" msgid="3705373766798013406">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ <item quantity="one">"in 1 Stunde"</item>
+ <item quantity="other">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+ <item quantity="one">"morgen"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"am %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"am %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"in %s"</string>
- <string name="day" msgid="8144195776058119424">"Tag"</string>
- <string name="days" msgid="4774547661021344602">"Tage"</string>
- <string name="hour" msgid="2126771916426189481">"Stunde"</string>
- <string name="hours" msgid="894424005266852993">"Stunden"</string>
- <string name="minute" msgid="9148878657703769868">"Min"</string>
- <string name="minutes" msgid="5646001005827034509">"Minuten"</string>
- <string name="second" msgid="3184235808021478">"Sek"</string>
- <string name="seconds" msgid="3161515347216589235">"s"</string>
- <string name="week" msgid="5617961537173061583">"Woche"</string>
- <string name="weeks" msgid="6509623834583944518">"Wochen"</string>
- <string name="year" msgid="4001118221013892076">"Jahr"</string>
- <string name="years" msgid="6881577717993213522">"Jahre"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Jeden Wochentag (Mo-Fr)"</string>
- <string name="daily" msgid="5738949095624133403">"Täglich"</string>
- <string name="weekly" msgid="983428358394268344">"Jede Woche am <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Monatlich"</string>
- <string name="yearly" msgid="1519577999407493836">"Jährlich"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Video kann nicht wiedergegeben werden."</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Leider ist dieses Video nicht für Streaming auf diesem Gerät gültig."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Dieses Video kann leider nicht abgespielt werden."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"Mittag"</string>
- <string name="Noon" msgid="3342127745230013127">"Mittag"</string>
- <string name="midnight" msgid="7166259508850457595">"Mitternacht"</string>
- <string name="Midnight" msgid="5630806906897892201">"Mitternacht"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Alles auswählen"</string>
- <string name="selectText" msgid="3889149123626888637">"Text auswählen"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Textauswahl beenden"</string>
- <string name="cut" msgid="3092569408438626261">"Ausschneiden"</string>
- <string name="cutAll" msgid="2436383270024931639">"Alles ausschneiden"</string>
- <string name="copy" msgid="2681946229533511987">"Kopieren"</string>
- <string name="copyAll" msgid="2590829068100113057">"Alles kopieren"</string>
- <string name="paste" msgid="5629880836805036433">"Einfügen"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URL kopieren"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Eingabemethode"</string>
- <string name="addToDictionary" msgid="726256909274177272">"\"%s\" dem Wörterbuch hinzufügen"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Text bearbeiten"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Geringer Speicher"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Kaum noch freier Telefonspeicher verfügbar."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Abbrechen"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Achtung"</string>
- <string name="capital_on" msgid="1544682755514494298">"EIN"</string>
- <string name="capital_off" msgid="6815870386972805832">"AUS"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Aktion durchführen mit"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Standardmäßig für diese Aktion verwenden."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Löschen Sie die Standardeinstellungen unter \"Starteinstellungen &gt; Anwendungen &gt; Anwendungen verwalten\"."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Aktion auswählen"</string>
- <string name="noApplications" msgid="1691104391758345586">"Diese Aktion kann von keiner Anwendung ausgeführt werden."</string>
- <string name="aerr_title" msgid="653922989522758100">"Tut uns leid!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) wurde unerwartet beendet. Versuchen Sie es erneut."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> wurde unerwartet beendet. Versuchen Sie es erneut."</string>
- <string name="anr_title" msgid="3100070910664756057">"Tut uns leid!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> (in Anwendung <xliff:g id="APPLICATION">%2$s</xliff:g>) reagiert nicht."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> (in Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) reagiert nicht."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (in Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) reagiert nicht."</string>
- <string name="anr_process" msgid="1246866008169975783">"Prozess <xliff:g id="PROCESS">%1$s</xliff:g> reagiert nicht."</string>
- <string name="force_close" msgid="3653416315450806396">"Schließen erzwingen"</string>
- <string name="report" msgid="4060218260984795706">"Bericht"</string>
- <string name="wait" msgid="7147118217226317732">"Warten"</string>
- <string name="debug" msgid="9103374629678531849">"Fehler suchen"</string>
- <string name="sendText" msgid="5132506121645618310">"Aktion für Text auswählen"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Klingeltonlautstärke"</string>
- <string name="volume_music" msgid="5421651157138628171">"Medienlautstärke"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Wiedergabe durch Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Hörerlautstärke"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Lautstärke bei eingehendem Bluetooth-Anruf"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Lautstärke für Alarm"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Benachrichtigungslautstärke"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Lautstärke"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Standard-Klingelton"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standard-Klingelton (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Lautlos"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Klingeltöne"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Unbekannter Klingelton"</string>
+ <string name="preposition_for_date">"am %s"</string>
+ <string name="preposition_for_time">"am %s"</string>
+ <string name="preposition_for_year">"in %s"</string>
+ <string name="day">"Tag"</string>
+ <string name="days">"Tage"</string>
+ <string name="hour">"Stunde"</string>
+ <string name="hours">"Stunden"</string>
+ <string name="minute">"Min"</string>
+ <string name="minutes">"Minuten"</string>
+ <string name="second">"Sek"</string>
+ <string name="seconds">"s"</string>
+ <string name="week">"Woche"</string>
+ <string name="weeks">"Wochen"</string>
+ <string name="year">"Jahr"</string>
+ <string name="years">"Jahre"</string>
+ <string name="every_weekday">"Jeden Wochentag (Mo-Fr)"</string>
+ <string name="daily">"Täglich"</string>
+ <string name="weekly">"Jede Woche am <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Monatlich"</string>
+ <string name="yearly">"Jährlich"</string>
+ <string name="VideoView_error_title">"Video kann nicht wiedergegeben werden."</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Leider ist dieses Video nicht für Streaming auf diesem Gerät gültig."</string>
+ <string name="VideoView_error_text_unknown">"Dieses Video kann leider nicht abgespielt werden."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"Mittag"</string>
+ <string name="Noon">"Mittag"</string>
+ <string name="midnight">"Mitternacht"</string>
+ <string name="Midnight">"Mitternacht"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Alles auswählen"</string>
+ <string name="selectText">"Text auswählen"</string>
+ <string name="stopSelectingText">"Textauswahl beenden"</string>
+ <string name="cut">"Ausschneiden"</string>
+ <string name="cutAll">"Alles ausschneiden"</string>
+ <string name="copy">"Kopieren"</string>
+ <string name="copyAll">"Alles kopieren"</string>
+ <string name="paste">"Einfügen"</string>
+ <string name="copyUrl">"URL kopieren"</string>
+ <string name="inputMethod">"Eingabemethode"</string>
+ <string name="addToDictionary">"\"%s\" dem Wörterbuch hinzufügen"</string>
+ <string name="editTextMenuTitle">"Text bearbeiten"</string>
+ <string name="low_internal_storage_view_title">"Geringer Speicher"</string>
+ <string name="low_internal_storage_view_text">"Kaum noch freier Telefonspeicher verfügbar."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Abbrechen"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Abbrechen"</string>
+ <string name="dialog_alert_title">"Achtung"</string>
+ <string name="capital_on">"EIN"</string>
+ <string name="capital_off">"AUS"</string>
+ <string name="whichApplication">"Aktion durchführen mit"</string>
+ <string name="alwaysUse">"Standardmäßig für diese Aktion verwenden."</string>
+ <string name="clearDefaultHintMsg">"Löschen Sie die Standardeinstellungen unter \"Starteinstellungen &gt; Anwendungen &gt; Anwendungen verwalten\"."</string>
+ <string name="chooseActivity">"Aktion auswählen"</string>
+ <string name="noApplications">"Diese Aktion kann von keiner Anwendung ausgeführt werden."</string>
+ <string name="aerr_title">"Tut uns leid!"</string>
+ <string name="aerr_application">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) wurde unerwartet beendet. Versuchen Sie es erneut."</string>
+ <string name="aerr_process">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> wurde unerwartet beendet. Versuchen Sie es erneut."</string>
+ <string name="anr_title">"Tut uns leid!"</string>
+ <string name="anr_activity_application">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> (in Anwendung <xliff:g id="APPLICATION">%2$s</xliff:g>) reagiert nicht."</string>
+ <string name="anr_activity_process">"Aktivität <xliff:g id="ACTIVITY">%1$s</xliff:g> (in Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) reagiert nicht."</string>
+ <string name="anr_application_process">"Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (in Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) reagiert nicht."</string>
+ <string name="anr_process">"Prozess <xliff:g id="PROCESS">%1$s</xliff:g> reagiert nicht."</string>
+ <string name="force_close">"Schließen erzwingen"</string>
+ <string name="report">"Bericht"</string>
+ <string name="wait">"Warten"</string>
+ <string name="debug">"Fehler suchen"</string>
+ <string name="sendText">"Aktion für Text auswählen"</string>
+ <string name="volume_ringtone">"Klingeltonlautstärke"</string>
+ <string name="volume_music">"Medienlautstärke"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Wiedergabe durch Bluetooth"</string>
+ <string name="volume_call">"Hörerlautstärke"</string>
+ <string name="volume_bluetooth_call">"Lautstärke bei eingehendem Bluetooth-Anruf"</string>
+ <string name="volume_alarm">"Lautstärke für Alarm"</string>
+ <string name="volume_notification">"Benachrichtigungslautstärke"</string>
+ <string name="volume_unknown">"Lautstärke"</string>
+ <string name="ringtone_default">"Standard-Klingelton"</string>
+ <string name="ringtone_default_with_actual">"Standard-Klingelton (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Lautlos"</string>
+ <string name="ringtone_picker_title">"Klingeltöne"</string>
+ <string name="ringtone_unknown">"Unbekannter Klingelton"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"WLAN-Netzwerk verfügbar"</item>
- <item quantity="other" msgid="4192424489168397386">"WLAN-Netzwerke verfügbar"</item>
+ <item quantity="one">"WLAN-Netzwerk verfügbar"</item>
+ <item quantity="other">"WLAN-Netzwerke verfügbar"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Verfügbares WLAN-Netzwerk öffnen"</item>
- <item quantity="other" msgid="7915895323644292768">"Verfügbare WLAN-Netzwerke öffnen"</item>
+ <item quantity="one">"Verfügbares WLAN-Netzwerk öffnen"</item>
+ <item quantity="other">"Verfügbare WLAN-Netzwerke öffnen"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Zeichen einfügen"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Unbekannte Anwendung"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Kurznachrichten werden gesendet"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Es werden eine große Anzahl an Kurznachrichten versendet. Wählen Sie \"OK\", um fortzufahren, oder drücken Sie auf \"Abbrechen\", um den Sendevorgang zu beenden."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Abbrechen"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Einstellen"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Keine Berechtigungen erforderlich"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ausblenden"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Alle anzeigen"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Ladevorgang läuft..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB-Verbindung"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Sie haben Ihr Telefon über einen USB-Anschluss mit Ihrem Computer verbunden. Wählen Sie \"Bereitstellen\", wenn Sie Dateien auf Ihren Computer oder die SD-Karte Ihres Telefons kopieren möchten."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Bereitstellen"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Nicht bereitstellen"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Bei der Verwendung Ihrer SD-Karte als USB-Speicher ist ein Problem aufgetreten."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-Verbindung"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Wählen Sie die Dateien aus, die von Ihrem oder auf Ihren Computer kopiert werden sollen."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB-Speicher deaktivieren"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Auswählen, um USB-Speicher zu deaktivieren."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"USB-Speicher deaktivieren"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Bevor Sie den USB-Speicher deaktivieren, stellen Sie sicher, dass Sie Ihn vom USB-Host getrennt haben. Wählen Sie \"Deaktivieren\", um den USB-Speicher zu deaktivieren."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Ausschalten"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Abbrechen"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Wir haben beim Deaktivieren des USB-Speichers ein Problem festgestellt. Überprüfen Sie, ob Sie den USB-Host getrennt haben, und versuchen Sie es erneut."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"SD-Karte formatieren"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Möchten Sie die SD-Karte wirklich formatieren? Alle Daten auf Ihrer Karte gehen dann verloren."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging verbunden"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Ihr Telefon ist mit einem Computer verbunden."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Eingabemethode auswählen"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SD-Karte wird vorbereitet"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Nach Fehlern wird gesucht."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"SD-Karte leer"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"SD-Karte ist leer oder verfügt über ein nicht unterstütztes Dateisystem."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Beschädigte SD-Karte"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"Die SD-Karte ist beschädigt. Sie müssen Ihre Karte eventuell neu formatieren."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD-Karte unerwartet entfernt"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"SD-Karte vor dem Entnehmen trennen, um Datenverlust zu vermeiden."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SD-Karte\nkann entfernt werden."</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Die SD-Karte kann entfernt werden."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SD-Karte entfernt"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"SD-Karte entfernt. Legen Sie eine neue ein."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Keine passenden Aktivitäten gefunden"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"Nutzungsstatistik der Komponente aktualisieren"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Ermöglicht die Änderung von gesammelten Nutzungsstatistiken der Komponente. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Für Zoomeinstellung zweimal berühren"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Fehler beim Vergrößern des Widgets"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Los"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Suchen"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Senden"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Weiter"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Fertig"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Ausführen"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Nummer"\n"mit <xliff:g id="NUMBER">%s</xliff:g> wählen"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Neuer Kontakt"\n"mit <xliff:g id="NUMBER">%s</xliff:g> erstellen"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"aktiviert"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"nicht aktiviert"</string>
+ <string name="select_character">"Zeichen einfügen"</string>
+ <string name="sms_control_default_app_name">"Unbekannte Anwendung"</string>
+ <string name="sms_control_title">"Kurznachrichten werden gesendet"</string>
+ <string name="sms_control_message">"Es werden eine große Anzahl an Kurznachrichten versendet. Wählen Sie \"OK\", um fortzufahren, oder drücken Sie auf \"Abbrechen\", um den Sendevorgang zu beenden."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Abbrechen"</string>
+ <string name="date_time_set">"Einstellen"</string>
+ <string name="default_permission_group">"Standard"</string>
+ <string name="no_permissions">"Keine Berechtigungen erforderlich"</string>
+ <string name="perms_hide"><b>"Ausblenden"</b></string>
+ <string name="perms_show_all"><b>"Alle anzeigen"</b></string>
+ <string name="googlewebcontenthelper_loading">"Ladevorgang läuft..."</string>
+ <string name="usb_storage_title">"USB-Verbindung"</string>
+ <string name="usb_storage_message">"Sie haben Ihr Telefon über einen USB-Anschluss mit Ihrem Computer verbunden. Wählen Sie \"Bereitstellen\", wenn Sie Dateien auf Ihren Computer oder die SD-Karte Ihres Telefons kopieren möchten."</string>
+ <string name="usb_storage_button_mount">"Bereitstellen"</string>
+ <string name="usb_storage_button_unmount">"Nicht bereitstellen"</string>
+ <string name="usb_storage_error_message">"Bei der Verwendung Ihrer SD-Karte als USB-Speicher ist ein Problem aufgetreten."</string>
+ <string name="usb_storage_notification_title">"USB-Verbindung"</string>
+ <string name="usb_storage_notification_message">"Wählen Sie die Dateien aus, die von Ihrem oder auf Ihren Computer kopiert werden sollen."</string>
+ <string name="usb_storage_stop_notification_title">"USB-Speicher deaktivieren"</string>
+ <string name="usb_storage_stop_notification_message">"Auswählen, um USB-Speicher zu deaktivieren."</string>
+ <string name="usb_storage_stop_title">"USB-Speicher deaktivieren"</string>
+ <string name="usb_storage_stop_message">"Bevor Sie den USB-Speicher deaktivieren, stellen Sie sicher, dass Sie Ihn vom USB-Host getrennt haben. Wählen Sie \"Deaktivieren\", um den USB-Speicher zu deaktivieren."</string>
+ <string name="usb_storage_stop_button_mount">"Ausschalten"</string>
+ <string name="usb_storage_stop_button_unmount">"Abbrechen"</string>
+ <string name="usb_storage_stop_error_message">"Wir haben beim Deaktivieren des USB-Speichers ein Problem festgestellt. Überprüfen Sie, ob Sie den USB-Host getrennt haben, und versuchen Sie es erneut."</string>
+ <string name="extmedia_format_title">"SD-Karte formatieren"</string>
+ <string name="extmedia_format_message">"Möchten Sie die SD-Karte wirklich formatieren? Alle Daten auf Ihrer Karte gehen dann verloren."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Eingabemethode auswählen"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"Kandidaten"</u></string>
+ <string name="ext_media_checking_notification_title">"SD-Karte wird vorbereitet"</string>
+ <string name="ext_media_checking_notification_message">"Nach Fehlern wird gesucht."</string>
+ <string name="ext_media_nofs_notification_title">"SD-Karte leer"</string>
+ <string name="ext_media_nofs_notification_message">"SD-Karte ist leer oder verfügt über ein nicht unterstütztes Dateisystem."</string>
+ <string name="ext_media_unmountable_notification_title">"Beschädigte SD-Karte"</string>
+ <string name="ext_media_unmountable_notification_message">"Die SD-Karte ist beschädigt. Sie müssen Ihre Karte eventuell neu formatieren."</string>
+ <string name="ext_media_badremoval_notification_title">"SD-Karte unerwartet entfernt"</string>
+ <string name="ext_media_badremoval_notification_message">"SD-Karte vor dem Entnehmen trennen, um Datenverlust zu vermeiden."</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD-Karte\nkann entfernt werden."</string>
+ <string name="ext_media_safe_unmount_notification_message">"Die SD-Karte kann entfernt werden."</string>
+ <string name="ext_media_nomedia_notification_title">"SD-Karte entfernt"</string>
+ <string name="ext_media_nomedia_notification_message">"SD-Karte entfernt. Legen Sie eine neue ein."</string>
+ <string name="activity_list_empty">"Keine passenden Aktivitäten gefunden"</string>
+ <string name="permlab_pkgUsageStats">"Nutzungsstatistik der Komponente aktualisieren"</string>
+ <string name="permdesc_pkgUsageStats">"Ermöglicht die Änderung von gesammelten Nutzungsstatistiken der Komponente. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Für Zoomeinstellung zweimal berühren"</string>
+ <string name="gadget_host_error_inflating">"Fehler beim Vergrößern des Widgets"</string>
+ <string name="ime_action_go">"Los"</string>
+ <string name="ime_action_search">"Suchen"</string>
+ <string name="ime_action_send">"Senden"</string>
+ <string name="ime_action_next">"Weiter"</string>
+ <string name="ime_action_done">"Fertig"</string>
+ <string name="ime_action_default">"Ausführen"</string>
+ <string name="dial_number_using">"Nummer"\n"mit <xliff:g id="NUMBER">%s</xliff:g> wählen"</string>
+ <string name="create_contact_using">"Neuer Kontakt"\n"mit <xliff:g id="NUMBER">%s</xliff:g> erstellen"</string>
+ <string name="accessibility_compound_button_selected">"aktiviert"</string>
+ <string name="accessibility_compound_button_unselected">"nicht aktiviert"</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ba39b94..3158a37 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"&lt;χωÏίς τίτλο&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Δεν υπάÏχει τηλεφωνικός αÏιθμός)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Άγνωστο)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Αυτόματος τηλεφωνητής"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"ΠÏόβλημα σÏνδεσης ή μη έγκυÏος κώδικας MMI."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Η υπηÏεσία ενεÏγοποιήθηκε."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Η υπηÏεσία ενεÏγοποιήθηκε για:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Η υπηÏεσία έχει απενεÏγοποιηθεί."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Η εγγÏαφή ήταν επιτυχής."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Η διαγÏαφή ήταν επιτυχής."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Εσφαλμένος κωδικός Ï€Ïόσβασης."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"Το MMI ολοκληÏώθηκε."</string>
- <string name="badPin" msgid="5085454289896032547">"Ο παλιός αÏιθμός PIN που πληκτÏολογήσατε είναι εσφαλμένος."</string>
- <string name="badPuk" msgid="5702522162746042460">"Ο κωδικός PUK που πληκτÏολογήσατε είναι εσφαλμένος."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Οι αÏιθμοί PIN που πληκτÏολογήσατε δεν ταιÏιάζουν."</string>
- <string name="invalidPin" msgid="3850018445187475377">"ΠληκτÏολογήστε έναν αÏιθμό PIN μεγέθους 4 έως 8 αÏιθμών."</string>
- <string name="needPuk" msgid="919668385956251611">"Η κάÏτα SIM έχει κλειδωθεί με κωδικό PUK. ΠληκτÏολογήστε τον κωδικό PUK για να την ξεκλειδώσετε."</string>
- <string name="needPuk2" msgid="4526033371987193070">"ΠληκτÏολογήστε τον κωδικό PUK2 για την κατάÏγηση Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Ï„Î·Ï‚ κάÏτας SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"ΕισεÏχόμενη αναγνώÏιση κλήσης"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"ΕξεÏχόμενη αναγνώÏιση κλήσης"</string>
- <string name="CfMmi" msgid="5123218989141573515">"ΠÏοώθηση κλήσεων"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Αναμ. κλήσ."</string>
- <string name="BaMmi" msgid="455193067926770581">"ΦÏαγή κλήσεων"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Αλλαγή ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Αλλαγή αÏÎ¹Î¸Î¼Î¿Ï PIN"</string>
+ <string name="untitled">"&lt;χωÏίς τίτλο&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Δεν υπάÏχει τηλεφωνικός αÏιθμός)"</string>
+ <string name="unknownName">"(Άγνωστο)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Αυτόματος τηλεφωνητής"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"ΠÏόβλημα σÏνδεσης ή μη έγκυÏος κώδικας MMI."</string>
+ <string name="serviceEnabled">"Η υπηÏεσία ενεÏγοποιήθηκε."</string>
+ <string name="serviceEnabledFor">"Η υπηÏεσία ενεÏγοποιήθηκε για:"</string>
+ <string name="serviceDisabled">"Η υπηÏεσία έχει απενεÏγοποιηθεί."</string>
+ <string name="serviceRegistered">"Η εγγÏαφή ήταν επιτυχής."</string>
+ <string name="serviceErased">"Η διαγÏαφή ήταν επιτυχής."</string>
+ <string name="passwordIncorrect">"Εσφαλμένος κωδικός Ï€Ïόσβασης."</string>
+ <string name="mmiComplete">"Το MMI ολοκληÏώθηκε."</string>
+ <string name="badPin">"Ο παλιός αÏιθμός PIN που πληκτÏολογήσατε είναι εσφαλμένος."</string>
+ <string name="badPuk">"Ο κωδικός PUK που πληκτÏολογήσατε είναι εσφαλμένος."</string>
+ <string name="mismatchPin">"Οι αÏιθμοί PIN που πληκτÏολογήσατε δεν ταιÏιάζουν."</string>
+ <string name="invalidPin">"ΠληκτÏολογήστε έναν αÏιθμό PIN μεγέθους 4 έως 8 αÏιθμών."</string>
+ <string name="needPuk">"Η κάÏτα SIM έχει κλειδωθεί με κωδικό PUK. ΠληκτÏολογήστε τον κωδικό PUK για να την ξεκλειδώσετε."</string>
+ <string name="needPuk2">"ΠληκτÏολογήστε τον κωδικό PUK2 για την κατάÏγηση Î±Ï€Î¿ÎºÎ»ÎµÎ¹ÏƒÎ¼Î¿Ï Ï„Î·Ï‚ κάÏτας SIM."</string>
+ <string name="ClipMmi">"ΕισεÏχόμενη αναγνώÏιση κλήσης"</string>
+ <string name="ClirMmi">"ΕξεÏχόμενη αναγνώÏιση κλήσης"</string>
+ <string name="CfMmi">"ΠÏοώθηση κλήσεων"</string>
+ <string name="CwMmi">"Αναμονή κλήσης"</string>
+ <string name="BaMmi">"ΦÏαγή κλήσεων"</string>
+ <string name="PwdMmi">"Αλλαγή ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης"</string>
+ <string name="PinMmi">"Αλλαγή αÏÎ¹Î¸Î¼Î¿Ï PIN"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Η αναγνώÏιση κλήσης βÏίσκεται από Ï€Ïοεπιλογή στην \"πεÏιοÏισμένη\". Επόμενη κλήση: ΠεÏιοÏισμένη."</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Η αναγνώÏιση κλήσης βÏίσκεται από Ï€Ïοεπιλογή στην \"πεÏιοÏισμένη\". Επόμενη κλήση: Μη πεÏιοÏισμένη"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Η αναγνώÏιση κλήσης βÏίσκεται από Ï€Ïοεπιλογή στην \"μη πεÏιοÏισμένη\". Επόμενη κλήση: ΠεÏιοÏισμένη."</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Η αναγνώÏιση κλήσης βÏίσκεται από Ï€Ïοεπιλογή στην \"μη πεÏιοÏισμένη\". Επόμενη κλήση: Μη πεÏιοÏισμένη"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Η υπηÏεσία δεν Ï€Ïοβλέπεται."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Δεν είναι δυνατή η αλλαγή της ÏÏθμισης αναγνώÏισης κλήσης."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Η πεÏιοÏισμένη Ï€Ïόσβαση άλλαξε"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Η υπηÏεσία δεδομένων είναι αποκλεισμένη."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Η υπηÏεσία έκτακτης ανάγκης είναι αποκλεισμένη."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Η φωνητική υπηÏεσία/υπηÏεσία SMS είναι αποκλεισμένη."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Όλες οι φωνητικές υπηÏεσίες/υπηÏεσίες SMS έχουν αποκλειστεί."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Φωνή"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Δεδομένα"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"ΦΑΞ"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Μη συγχÏονισμένα"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"ΣυγχÏονισμός"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Πακέτο"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Η αναγνώÏιση κλήσης βÏίσκεται από Ï€Ïοεπιλογή στην \"πεÏιοÏισμένη\". Επόμενη κλήση: ΠεÏιοÏισμένη."</string>
+ <string name="CLIRDefaultOnNextCallOff">"Η αναγνώÏιση κλήσης βÏίσκεται από Ï€Ïοεπιλογή στην \"πεÏιοÏισμένη\". Επόμενη κλήση: Μη πεÏιοÏισμένη"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Η αναγνώÏιση κλήσης βÏίσκεται από Ï€Ïοεπιλογή στην \"μη πεÏιοÏισμένη\". Επόμενη κλήση: ΠεÏιοÏισμένη."</string>
+ <string name="CLIRDefaultOffNextCallOff">"Η αναγνώÏιση κλήσης βÏίσκεται από Ï€Ïοεπιλογή στην \"μη πεÏιοÏισμένη\". Επόμενη κλήση: Μη πεÏιοÏισμένη"</string>
+ <string name="serviceNotProvisioned">"Η υπηÏεσία δεν Ï€Ïοβλέπεται."</string>
+ <string name="CLIRPermanent">"Δεν είναι δυνατή η αλλαγή της ÏÏθμισης αναγνώÏισης κλήσης."</string>
+ <string name="RestrictedChangedTitle">"Η πεÏιοÏισμένη Ï€Ïόσβαση άλλαξε"</string>
+ <string name="RestrictedOnData">"Η υπηÏεσία δεδομένων είναι αποκλεισμένη."</string>
+ <string name="RestrictedOnEmergency">"Η υπηÏεσία έκτακτης ανάγκης είναι αποκλεισμένη."</string>
+ <string name="RestrictedOnNormal">"Η φωνητική υπηÏεσία/υπηÏεσία SMS είναι αποκλεισμένη."</string>
+ <string name="RestrictedOnAll">"Όλες οι φωνητικές υπηÏεσίες/υπηÏεσίες SMS έχουν αποκλειστεί."</string>
+ <string name="serviceClassVoice">"Φωνή"</string>
+ <string name="serviceClassData">"Δεδομένα"</string>
+ <string name="serviceClassFAX">"ΦΑΞ"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Μη συγχÏονισμένα"</string>
+ <string name="serviceClassDataSync">"ΣυγχÏονισμός"</string>
+ <string name="serviceClassPacket">"Πακέτο"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν Ï€Ïοωθήθηκε"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> μετά από <xliff:g id="TIME_DELAY">{2}</xliff:g> δευτεÏόλεπτα"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν Ï€Ïοωθήθηκε"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν Ï€Ïοωθήθηκε"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν Ï€Ïοωθήθηκε"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> μετά από <xliff:g id="TIME_DELAY">{2}</xliff:g> δευτεÏόλεπτα"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν Ï€Ïοωθήθηκε"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν Ï€Ïοωθήθηκε"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Η ιστοσελίδα πεÏιέχει ένα σφάλμα."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Δεν ήταν δυνατή η εÏÏεση της διεÏθυνσης URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Το πλάνο ελέγχου ταυτότητας ιστοτόπου δεν υποστηÏίζεται."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Ο έλεγχος ταυτότητας δεν ήταν επιτυχής."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Ο έλεγχος ταυτότητας μέσω του διακομιστή μεσολάβησης δεν ήταν επιτυχής."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Η σÏνδεση στον διακομιστή δεν ήταν επιτυχής."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Η επικοινωνία με τον διακομιστή απέτυχε. ΠÏοσπαθήστε ξανά αÏγότεÏα."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Το ÏŒÏιο χÏόνου της σÏνδεσης στον διακομιστή έληξε."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Αυτή η σελίδα πεÏιέχει πάÏα πολλές ανακατευθÏνσεις διακομιστή."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Το Ï€Ïωτόκολλο δεν υποστηÏίζεται."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Δεν ήταν δυνατή η επίτευξη ασφαλοÏÏ‚ σÏνδεσης."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Δεν ήταν δυνατό το άνοιγμα της σελίδας επειδή η διεÏθυνση URL δεν είναι έγκυÏη."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Η Ï€Ïόσβαση στο αÏχείο δεν ήταν δυνατή."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Το αÏχείο που ζητήθηκε δεν βÏέθηκε."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"ΠÏαγματοποιείται επεξεÏγασία πάÏα πολλών αιτημάτων. ΠÏοσπαθήστε ξανά αÏγότεÏα."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"ΣυγχÏονισμός"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ΣυγχÏονισμός"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"ΠάÏα πολλές <xliff:g id="CONTENT_TYPE">%s</xliff:g> διαγÏαφές."</string>
- <string name="low_memory" msgid="6632412458436461203">"Ο αποθηκευτικός χώÏος του τηλεφώνου είναι πλήÏης! ΔιαγÏάψτε μεÏικά αÏχεία για να δημιουÏγήσετε ελεÏθεÏο χώÏο."</string>
- <string name="me" msgid="6545696007631404292">"Για εμένα"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Επιλογές τηλεφώνου"</string>
- <string name="silent_mode" msgid="7167703389802618663">"ΛειτουÏγία σίγασης"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"ΕνεÏγοποίηση ασÏÏματου"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"ΑπενεÏγοποίηση ασÏÏματου"</string>
- <string name="screen_lock" msgid="799094655496098153">"Κλείδωμα οθόνης"</string>
- <string name="power_off" msgid="4266614107412865048">"ΑπενεÏγοποίηση"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"ΑπενεÏγοποίηση..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Το τηλέφωνό σας θα απενεÏγοποιηθεί."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Δεν υπάÏχουν Ï€Ïόσφατες εφαÏμογές."</string>
- <string name="global_actions" msgid="2406416831541615258">"Επιλογές τηλεφώνου"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Κλείδωμα οθόνης"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"ΑπενεÏγοποίηση"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"ΛειτουÏγία σίγασης"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ο ήχος είναι απενεÏγοποιημένος"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ο ήχος είναι ενεÏγοποιημένος"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ΛειτουÏγία πτήσης"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Η λειτουÏγία πτήσης είναι ενεÏγοποιημένη."</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Η λειτουÏγία πτήσης είναι απενεÏγοποιημένη"</string>
- <string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουÏγία"</string>
- <string name="android_system_label" msgid="6577375335728551336">"ΣÏστημα Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"ΥπηÏεσίες επί πληÏωμή"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"ΕπιτÏέπει σε εφαÏμογές να Ï€Ïαγματοποιήσουν ενέÏγειες για τις οποίες ενδέχεται να χÏεωθείτε."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Τα μηνÏματά σας"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Ανάγνωση και εγγÏαφή των μηνυμάτων SMS, των μηνυμάτων ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου και άλλων μηνυμάτων."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Οι Ï€Ïοσωπικές σας πληÏοφοÏίες"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Άμεση Ï€Ïόσβαση στις επαφές και στο ημεÏολόγιό σας που είναι αποθηκευμένα στο τηλέφωνο."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Η τοποθεσία σας"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"ΠαÏακολοÏθηση της φυσικής τοποθεσίας σας"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Επικοινωνία δικτÏου"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"ΕπιτÏέπει σε εφαÏμογές να αποκτήσουν Ï€Ïόσβαση σε διάφοÏες λειτουÏγίες δικτÏου."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Οι λογαÏιασμοί σας Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"ΠÏόσβαση στους διαθέσιμους λογαÏιασμοÏÏ‚ Google."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Στοιχεία ελέγχου υλικοÏ"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Άμεση Ï€Ïόσβαση στο υλικό της συσκευής τηλεφώνου."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Τηλεφωνικές κλήσεις"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"ΠαÏακολοÏθηση, καταγÏαφή και επεξεÏγασία τηλεφωνικών κλήσεων."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"ΕÏγαλεία συστήματος"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Î§Î±Î¼Î·Î»Î¿Ï ÎµÏ€Î¹Ï€Î­Î´Î¿Ï… Ï€Ïόσβαση και έλεγχος του συστήματος."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"ΕÏγαλεία ανάπτυξης"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Δυνατότητες που είναι απαÏαίτητες μόνο σε Ï€ÏογÏαμματιστές εφαÏμογών."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Η ιστοσελίδα πεÏιέχει ένα σφάλμα."</string>
+ <string name="httpErrorLookup">"Δεν ήταν δυνατή η εÏÏεση της διεÏθυνσης URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Το πλάνο ελέγχου ταυτότητας ιστοτόπου δεν υποστηÏίζεται."</string>
+ <string name="httpErrorAuth">"Ο έλεγχος ταυτότητας δεν ήταν επιτυχής."</string>
+ <string name="httpErrorProxyAuth">"Ο έλεγχος ταυτότητας μέσω του διακομιστή μεσολάβησης δεν ήταν επιτυχής."</string>
+ <string name="httpErrorConnect">"Η σÏνδεση στον διακομιστή δεν ήταν επιτυχής."</string>
+ <string name="httpErrorIO">"Η επικοινωνία με τον διακομιστή απέτυχε. ΠÏοσπαθήστε ξανά αÏγότεÏα."</string>
+ <string name="httpErrorTimeout">"Το ÏŒÏιο χÏόνου της σÏνδεσης στον διακομιστή έληξε."</string>
+ <string name="httpErrorRedirectLoop">"Αυτή η σελίδα πεÏιέχει πάÏα πολλές ανακατευθÏνσεις διακομιστή."</string>
+ <string name="httpErrorUnsupportedScheme">"Το Ï€Ïωτόκολλο δεν υποστηÏίζεται."</string>
+ <string name="httpErrorFailedSslHandshake">"Δεν ήταν δυνατή η επίτευξη ασφαλοÏÏ‚ σÏνδεσης."</string>
+ <string name="httpErrorBadUrl">"Δεν ήταν δυνατό το άνοιγμα της σελίδας επειδή η διεÏθυνση URL δεν είναι έγκυÏη."</string>
+ <string name="httpErrorFile">"Η Ï€Ïόσβαση στο αÏχείο δεν ήταν δυνατή."</string>
+ <string name="httpErrorFileNotFound">"Το αÏχείο που ζητήθηκε δεν βÏέθηκε."</string>
+ <string name="httpErrorTooManyRequests">"ΠÏαγματοποιείται επεξεÏγασία πάÏα πολλών αιτημάτων. ΠÏοσπαθήστε ξανά αÏγότεÏα."</string>
+ <string name="contentServiceSync">"ΣυγχÏονισμός"</string>
+ <string name="contentServiceSyncNotificationTitle">"ΣυγχÏονισμός"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"ΠάÏα πολλές <xliff:g id="CONTENT_TYPE">%s</xliff:g> διαγÏαφές."</string>
+ <string name="low_memory">"Ο αποθηκευτικός χώÏος του τηλεφώνου είναι πλήÏης! ΔιαγÏάψτε μεÏικά αÏχεία για να δημιουÏγήσετε ελεÏθεÏο χώÏο."</string>
+ <string name="me">"Για εμένα"</string>
+ <string name="power_dialog">"Επιλογές τηλεφώνου"</string>
+ <string name="silent_mode">"ΛειτουÏγία σίγασης"</string>
+ <string name="turn_on_radio">"ΕνεÏγοποίηση ασÏÏματου"</string>
+ <string name="turn_off_radio">"ΑπενεÏγοποίηση ασÏÏματου"</string>
+ <string name="screen_lock">"Κλείδωμα οθόνης"</string>
+ <string name="power_off">"ΑπενεÏγοποίηση"</string>
+ <string name="shutdown_progress">"ΑπενεÏγοποίηση..."</string>
+ <string name="shutdown_confirm">"Το τηλέφωνό σας θα απενεÏγοποιηθεί."</string>
+ <string name="no_recent_tasks">"Δεν υπάÏχουν Ï€Ïόσφατες εφαÏμογές."</string>
+ <string name="global_actions">"Επιλογές τηλεφώνου"</string>
+ <string name="global_action_lock">"Κλείδωμα οθόνης"</string>
+ <string name="global_action_power_off">"ΑπενεÏγοποίηση"</string>
+ <string name="global_action_toggle_silent_mode">"ΛειτουÏγία σίγασης"</string>
+ <string name="global_action_silent_mode_on_status">"Ο ήχος είναι απενεÏγοποιημένος"</string>
+ <string name="global_action_silent_mode_off_status">"Ο ήχος είναι ενεÏγοποιημένος"</string>
+ <string name="global_actions_toggle_airplane_mode">"ΛειτουÏγία πτήσης"</string>
+ <string name="global_actions_airplane_mode_on_status">"Η λειτουÏγία πτήσης είναι ενεÏγοποιημένη."</string>
+ <string name="global_actions_airplane_mode_off_status">"Η λειτουÏγία πτήσης είναι απενεÏγοποιημένη"</string>
+ <string name="safeMode">"Ασφαλής λειτουÏγία"</string>
+ <string name="android_system_label">"ΣÏστημα Android"</string>
+ <string name="permgrouplab_costMoney">"ΥπηÏεσίες επί πληÏωμή."</string>
+ <string name="permgroupdesc_costMoney">"ΕπιτÏέπει σε εφαÏμογές να Ï€Ïαγματοποιήσουν ενέÏγειες για τις οποίες ενδέχεται να χÏεωθείτε."</string>
+ <string name="permgrouplab_messages">"Τα μηνÏματά σας"</string>
+ <string name="permgroupdesc_messages">"Ανάγνωση και εγγÏαφή των μηνυμάτων SMS, των μηνυμάτων ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου και άλλων μηνυμάτων."</string>
+ <string name="permgrouplab_personalInfo">"Οι Ï€Ïοσωπικές σας πληÏοφοÏίες"</string>
+ <string name="permgroupdesc_personalInfo">"Άμεση Ï€Ïόσβαση στις επαφές και στο ημεÏολόγιό σας που είναι αποθηκευμένα στο τηλέφωνο."</string>
+ <string name="permgrouplab_location">"Η τοποθεσία σας"</string>
+ <string name="permgroupdesc_location">"ΠαÏακολοÏθηση της φυσικής τοποθεσίας σας"</string>
+ <string name="permgrouplab_network">"Επικοινωνία δικτÏου"</string>
+ <string name="permgroupdesc_network">"ΕπιτÏέπει σε εφαÏμογές να αποκτήσουν Ï€Ïόσβαση σε διάφοÏες λειτουÏγίες δικτÏου."</string>
+ <string name="permgrouplab_accounts">"Οι λογαÏιασμοί σας Google"</string>
+ <string name="permgroupdesc_accounts">"ΠÏόσβαση στους διαθέσιμους λογαÏιασμοÏÏ‚ Google."</string>
+ <string name="permgrouplab_hardwareControls">"Στοιχεία ελέγχου υλικοÏ"</string>
+ <string name="permgroupdesc_hardwareControls">"Άμεση Ï€Ïόσβαση στο υλικό της συσκευής τηλεφώνου."</string>
+ <string name="permgrouplab_phoneCalls">"Τηλεφωνικές κλήσεις"</string>
+ <string name="permgroupdesc_phoneCalls">"ΠαÏακολοÏθηση, καταγÏαφή και επεξεÏγασία τηλεφωνικών κλήσεων."</string>
+ <string name="permgrouplab_systemTools">"ΕÏγαλεία συστήματος"</string>
+ <string name="permgroupdesc_systemTools">"Î§Î±Î¼Î·Î»Î¿Ï ÎµÏ€Î¹Ï€Î­Î´Î¿Ï… Ï€Ïόσβαση και έλεγχος του συστήματος."</string>
+ <string name="permgrouplab_developmentTools">"ΕÏγαλεία ανάπτυξης"</string>
+ <string name="permgroupdesc_developmentTools">"Δυνατότητες που είναι απαÏαίτητες μόνο σε Ï€ÏογÏαμματιστές εφαÏμογών."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"απενεÏγοποίηση ή Ï„Ïοποποίηση γÏαμμής κατάστασης"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"ΕπιτÏέπει στην εφαÏμογή να απενεÏγοποιεί τη γÏαμμή κατάστασης ή να Ï€Ïοσθέτει και να αφαιÏεί εικονίδια συστήματος."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"ανάπτυξη/σÏμπτυξη γÏαμμής κατάστασης"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"ΕπιτÏέπει σε μια εφαÏμογή να αναπτÏξει ή να συμπτÏξει την γÏαμμή κατάστασης."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"φÏαγή εξεÏχόμενων κλήσεων"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"ΕπιτÏέπει σε μια εφαÏμογή την επεξεÏγασία εξεÏχόμενων κλήσεων και την αλλαγή του αÏÎ¹Î¸Î¼Î¿Ï Ï€Î¿Ï… Ï€Ïόκειται να κληθεί. Κακόβουλες εφαÏμογές ενδέχεται να παÏακολουθοÏν, να ανακατευθÏνουν ή να παÏεμποδίζουν εξεÏχόμενες κλήσεις."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"λήψη SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"ΕπιτÏέπει σε μια εφαÏμογή τη λήψη και την επεξεÏγασία μηνυμάτων SMS. Κακόβουλες εφαÏμογές ενδέχεται να παÏακολουθοÏν τα μηνÏματά σας ή να τα διαγÏάφουν χωÏίς να σας ειδοποιοÏν."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"λήψη MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"ΕπιτÏέπει σε μια εφαÏμογή την λήψη και την επεξεÏγασία μηνυμάτων MMS. Κακόβουλες εφαÏμογές ενδέχεται να παÏακολουθοÏν τα μηνÏματά σας ή να τα διαγÏάφουν χωÏίς να σας ειδοποιοÏν."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"αποστολή μηνυμάτων SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"ΕπιτÏέπει σε μια εφαÏμογή την αποστολή μηνυμάτων SMS. Κακόβουλες εφαÏμογές ενδέχεται να σας χÏεώσουν αποστέλλοντας μηνÏματα χωÏίς την έγκÏισή σας."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"ανάγνωση μηνυμάτων SMS ή MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση μηνυμάτων SMS που είναι αποθηκευμένα στο τηλέφωνό σας ή στην κάÏτα SIM. Κακόβουλες εφαÏμογές ενδέχεται να αναγνώσουν τα εμπιστευτικά σας μηνÏματα."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"επεξεÏγασία SMS ή MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"ΕπιτÏέπει σε μια εφαÏμογή την εγγÏαφή σε μηνÏματα SMS που είναι αποθηκευμένα στο τηλέφωνό σας ή στην κάÏτα SIM. Κακόβουλες εφαÏμογές ενδέχεται να διαγÏάψουν τα μηνÏματά σας."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"λήψη WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"ΕπιτÏέπει σε μια εφαÏμογή τη λήψη και την επεξεÏγασία μηνυμάτων WAP. Κακόβουλες εφαÏμογές ενδέχεται να παÏακολουθοÏν τα μηνÏματά σας ή να τα διαγÏάφουν χωÏίς να σας ειδοποιοÏν."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"ανάκτηση εκτελοÏμενων εφαÏμογών"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"ΕπιτÏέπει σε μια εφαÏμογή να ανακτήσει πληÏοφοÏίες σχετικά με τις Ï„Ïέχουσες εκτελοÏμενες εÏγασίες και στις εÏγασίες που έχουν Ï€Ïόσφατα εκτελεστεί. Ενδέχεται να δώσει τη δυνατότητα σε κακόβουλες εφαÏμογές να ανακαλÏψουν ιδιωτικές πληÏοφοÏίες σχετικά με άλλες εφαÏμογές."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"αναδιάταξη εκτελοÏμενων εφαÏμογών"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"ΕπιτÏέπει σε μια εφαÏμογή τη μετακίνηση εÏγασιών στο Ï€Ïοσκήνιο και στο φόντο. Κακόβουλες εφαÏμογές μποÏοÏν να Ï€ÏοωθηθοÏν στο Ï€Ïοσκήνιο χωÏίς να μποÏείτε να τις ελέγξετε."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"ενεÏγοποίηση ÎµÎ½Ï„Î¿Ï€Î¹ÏƒÎ¼Î¿Ï ÏƒÏ†Î±Î»Î¼Î¬Ï„Ï‰Î½ εφαÏμογής"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"ΕπιτÏέπει σε μια εφαÏμογή να ενεÏγοποιήσει τον εντοπισμό σφαλμάτων για μια άλλη εφαÏμογή. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να τεÏματίσουν άλλες εφαÏμογές."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"αλλαγή των Ïυθμίσεων του UI"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της Ï„Ïέχουσας διαμόÏφωσης, όπως οι τοπικές Ïυθμίσεις ή το μέγεθος γÏαμματοσειÏάς γενικά."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"επανεκκίνηση άλλων εφαÏμογών"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"ΕπιτÏέπει σε μια εφαÏμογή να Ï€Ïαγματοποιήσει αναγκαστική επανεκκίνηση άλλων εφαÏμογών."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"αναγκαστικός τεÏματισμός εφαÏμογής"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"ΕπιτÏέπει σε μια εφαÏμογή να εξαναγκάσει οποιαδήποτε δÏαστηÏιότητα που βÏίσκεται στο Ï€Ïοσκήνιο να κλείσει και να μεταβεί στο φόντο. Δεν είναι απαÏαίτητο για κανονικές εφαÏμογές."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"ανάκτηση εσωτεÏικής κατάστασης συστήματος"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"ΕπιτÏέπει σε μια εφαÏμογή να ανακτήσει την εσωτεÏική κατάσταση του συστήματος. Κακόβουλες εφαÏμογές ενδέχεται να ανακτήσουν μεγάλο εÏÏος ιδιωτικών και ασφαλών πληÏοφοÏιών, τις οποίες δεν χÏειάζονται."</string>
+ <string name="permlab_statusBar">"απενεÏγοποίηση ή Ï„Ïοποποίηση γÏαμμής κατάστασης"</string>
+ <string name="permdesc_statusBar">"ΕπιτÏέπει στην εφαÏμογή να απενεÏγοποιεί τη γÏαμμή κατάστασης ή να Ï€Ïοσθέτει και να αφαιÏεί εικονίδια συστήματος."</string>
+ <string name="permlab_expandStatusBar">"ανάπτυξη/σÏμπτυξη γÏαμμής κατάστασης"</string>
+ <string name="permdesc_expandStatusBar">"ΕπιτÏέπει σε μια εφαÏμογή να αναπτÏξει ή να συμπτÏξει την γÏαμμή κατάστασης."</string>
+ <string name="permlab_processOutgoingCalls">"φÏαγή εξεÏχόμενων κλήσεων"</string>
+ <string name="permdesc_processOutgoingCalls">"ΕπιτÏέπει σε μια εφαÏμογή την επεξεÏγασία εξεÏχόμενων κλήσεων και την αλλαγή του αÏÎ¹Î¸Î¼Î¿Ï Ï€Î¿Ï… Ï€Ïόκειται να κληθεί. Κακόβουλες εφαÏμογές ενδέχεται να παÏακολουθοÏν, να ανακατευθÏνουν ή να παÏεμποδίζουν εξεÏχόμενες κλήσεις."</string>
+ <string name="permlab_receiveSms">"λήψη SMS"</string>
+ <string name="permdesc_receiveSms">"ΕπιτÏέπει σε μια εφαÏμογή τη λήψη και την επεξεÏγασία μηνυμάτων SMS. Κακόβουλες εφαÏμογές ενδέχεται να παÏακολουθοÏν τα μηνÏματά σας ή να τα διαγÏάφουν χωÏίς να σας ειδοποιοÏν."</string>
+ <string name="permlab_receiveMms">"λήψη MMS"</string>
+ <string name="permdesc_receiveMms">"ΕπιτÏέπει σε μια εφαÏμογή την λήψη και την επεξεÏγασία μηνυμάτων MMS. Κακόβουλες εφαÏμογές ενδέχεται να παÏακολουθοÏν τα μηνÏματά σας ή να τα διαγÏάφουν χωÏίς να σας ειδοποιοÏν."</string>
+ <string name="permlab_sendSms">"αποστολή μηνυμάτων SMS"</string>
+ <string name="permdesc_sendSms">"ΕπιτÏέπει σε μια εφαÏμογή την αποστολή μηνυμάτων SMS. Κακόβουλες εφαÏμογές ενδέχεται να σας χÏεώσουν αποστέλλοντας μηνÏματα χωÏίς την έγκÏισή σας."</string>
+ <string name="permlab_readSms">"ανάγνωση μηνυμάτων SMS ή MMS"</string>
+ <string name="permdesc_readSms">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση μηνυμάτων SMS που είναι αποθηκευμένα στο τηλέφωνό σας ή στην κάÏτα SIM. Κακόβουλες εφαÏμογές ενδέχεται να αναγνώσουν τα εμπιστευτικά σας μηνÏματα."</string>
+ <string name="permlab_writeSms">"επεξεÏγασία SMS ή MMS"</string>
+ <string name="permdesc_writeSms">"ΕπιτÏέπει σε μια εφαÏμογή την εγγÏαφή σε μηνÏματα SMS που είναι αποθηκευμένα στο τηλέφωνό σας ή στην κάÏτα SIM. Κακόβουλες εφαÏμογές ενδέχεται να διαγÏάψουν τα μηνÏματά σας."</string>
+ <string name="permlab_receiveWapPush">"λήψη WAP"</string>
+ <string name="permdesc_receiveWapPush">"ΕπιτÏέπει σε μια εφαÏμογή τη λήψη και την επεξεÏγασία μηνυμάτων WAP. Κακόβουλες εφαÏμογές ενδέχεται να παÏακολουθοÏν τα μηνÏματά σας ή να τα διαγÏάφουν χωÏίς να σας ειδοποιοÏν."</string>
+ <string name="permlab_getTasks">"ανάκτηση εκτελοÏμενων εφαÏμογών"</string>
+ <string name="permdesc_getTasks">"ΕπιτÏέπει σε μια εφαÏμογή να ανακτήσει πληÏοφοÏίες σχετικά με τις Ï„Ïέχουσες εκτελοÏμενες εÏγασίες και στις εÏγασίες που έχουν Ï€Ïόσφατα εκτελεστεί. Ενδέχεται να δώσει τη δυνατότητα σε κακόβουλες εφαÏμογές να ανακαλÏψουν ιδιωτικές πληÏοφοÏίες σχετικά με άλλες εφαÏμογές."</string>
+ <string name="permlab_reorderTasks">"αναδιάταξη εκτελοÏμενων εφαÏμογών"</string>
+ <string name="permdesc_reorderTasks">"ΕπιτÏέπει σε μια εφαÏμογή τη μετακίνηση εÏγασιών στο Ï€Ïοσκήνιο και στο φόντο. Κακόβουλες εφαÏμογές μποÏοÏν να Ï€ÏοωθηθοÏν στο Ï€Ïοσκήνιο χωÏίς να μποÏείτε να τις ελέγξετε."</string>
+ <string name="permlab_setDebugApp">"ενεÏγοποίηση ÎµÎ½Ï„Î¿Ï€Î¹ÏƒÎ¼Î¿Ï ÏƒÏ†Î±Î»Î¼Î¬Ï„Ï‰Î½ εφαÏμογής"</string>
+ <string name="permdesc_setDebugApp">"ΕπιτÏέπει σε μια εφαÏμογή να ενεÏγοποιήσει τον εντοπισμό σφαλμάτων για μια άλλη εφαÏμογή. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να τεÏματίσουν άλλες εφαÏμογές."</string>
+ <string name="permlab_changeConfiguration">"αλλαγή των Ïυθμίσεων του UI"</string>
+ <string name="permdesc_changeConfiguration">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της Ï„Ïέχουσας διαμόÏφωσης, όπως οι τοπικές Ïυθμίσεις ή το μέγεθος γÏαμματοσειÏάς γενικά."</string>
+ <string name="permlab_restartPackages">"επανεκκίνηση άλλων εφαÏμογών"</string>
+ <string name="permdesc_restartPackages">"ΕπιτÏέπει σε μια εφαÏμογή να Ï€Ïαγματοποιήσει αναγκαστική επανεκκίνηση άλλων εφαÏμογών."</string>
+ <string name="permlab_forceBack">"αναγκαστικός τεÏματισμός εφαÏμογής"</string>
+ <string name="permdesc_forceBack">"ΕπιτÏέπει σε μια εφαÏμογή να εξαναγκάσει οποιαδήποτε δÏαστηÏιότητα που βÏίσκεται στο Ï€Ïοσκήνιο να κλείσει και να μεταβεί στο φόντο. Δεν είναι απαÏαίτητο για κανονικές εφαÏμογές."</string>
+ <string name="permlab_dump">"ανάκτηση εσωτεÏικής κατάστασης συστήματος"</string>
+ <string name="permdesc_dump">"ΕπιτÏέπει σε μια εφαÏμογή να ανακτήσει την εσωτεÏική κατάσταση του συστήματος. Κακόβουλες εφαÏμογές ενδέχεται να ανακτήσουν μεγάλο εÏÏος ιδιωτικών και ασφαλών πληÏοφοÏιών, τις οποίες δεν χÏειάζονται."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"παÏακολοÏθηση και έλεγχος όλων των εκκινήσεων εφαÏμογών"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"ΕπιτÏέπει σε μια εφαÏμογή να παÏακολουθεί και να ελέγχει τον Ï„Ïόπο με τον οποίο το σÏστημα εκκινεί δÏαστηÏιότητες. Κακόβουλες εφαÏμογές ενδέχεται να θέσουν σε κίνδυνο το σÏστημα. Αυτή η άδεια είναι απαÏαίτητη μόνο για ανάπτυξη και ποτέ για κανονική χÏήση τηλεφώνου."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"αποστολή εκπομπής χωÏίς πακέτο"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"ΕπιτÏέπει σε μια εφαÏμογή την εκπομπή μια ειδοποίησης σχετικά με την κατάÏγηση ενός πακέτου εφαÏμογών. Κακόβουλες εφαÏμογές ενδέχεται να το χÏησιμοποιήσουν για να τεÏματίσουν άλλες εκτελοÏμενες εφαÏμογές."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"αποστολή εκπομπής που έχει ληφθεί με μήνυμα SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"ΕπιτÏέπει σε μια εφαÏμογή την εκπομπή ειδοποίησης σχετικά με τη λήψη μηνÏματος SMS. Κακόβουλες εφαÏμογές ενδέχεται να το χÏησιμοποιήσουν για την δημιουÏγία πλαστών εισεÏχόμενων μηνυμάτων SMS."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"αποστολή εκπομπής που έχει ληφθεί με WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"ΕπιτÏέπει σε μια εφαÏμογή να εκπέμψει μια ειδοποίηση σχετικά με τη λήψη μηνÏματος WAP PUSH. Κακόβουλες εφαÏμογές ενδέχεται να το χÏησιμοποιήσουν για να δημιουÏγήσουν ψευδείς λήψεις μηνυμάτων MMS ή για να αντικαταστήσουν χωÏίς ειδοποίηση το πεÏιεχόμενο μιας ιστοσελίδας με κακόβουλες παÏαλλαγές."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"πεÏιοÏισμός αÏÎ¹Î¸Î¼Î¿Ï ÎµÎºÏ„ÎµÎ»Î¿Ïμενων διαδικασιών"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"ΕπιτÏέπει σε μια εφαÏμογή τον έλεγχο του μέγιστου αÏÎ¹Î¸Î¼Î¿Ï Î´Î¹Î±Î´Î¹ÎºÎ±ÏƒÎ¹ÏŽÎ½ που θα εκτελοÏνται. Δεν είναι ποτέ απαÏαίτητο για κανονικές εφαÏμογές."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"κλείσιμο όλων των εφαÏμογών στο φόντο"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"ΕπιτÏέπει σε μια εφαÏμογή να ελέγχει εάν οι δÏαστηÏιότητες ολοκληÏώνονται πάντοτε μόλις μεταβοÏν στο φόντο. Δεν είναι ποτέ απαÏαίτητο για κανονικές εφαÏμογές."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"Ï„Ïοποποίηση στατιστικών μπαταÏίας"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"ΕπιτÏέπει την Ï„Ïοποποίηση στατιστικών μπαταÏίας που έχουν συλλεχθεί. Δεν Ï€Ïέπει να χÏησιμοποιείται από συνήθεις εφαÏμογές."</string>
+ <string name="permlab_runSetActivityWatcher">"παÏακολοÏθηση και έλεγχος όλων των εκκινήσεων εφαÏμογών"</string>
+ <string name="permdesc_runSetActivityWatcher">"ΕπιτÏέπει σε μια εφαÏμογή να παÏακολουθεί και να ελέγχει τον Ï„Ïόπο με τον οποίο το σÏστημα εκκινεί δÏαστηÏιότητες. Κακόβουλες εφαÏμογές ενδέχεται να θέσουν σε κίνδυνο το σÏστημα. Αυτή η άδεια είναι απαÏαίτητη μόνο για ανάπτυξη και ποτέ για κανονική χÏήση τηλεφώνου."</string>
+ <string name="permlab_broadcastPackageRemoved">"αποστολή εκπομπής χωÏίς πακέτο"</string>
+ <string name="permdesc_broadcastPackageRemoved">"ΕπιτÏέπει σε μια εφαÏμογή την εκπομπή μια ειδοποίησης σχετικά με την κατάÏγηση ενός πακέτου εφαÏμογών. Κακόβουλες εφαÏμογές ενδέχεται να το χÏησιμοποιήσουν για να τεÏματίσουν άλλες εκτελοÏμενες εφαÏμογές."</string>
+ <string name="permlab_broadcastSmsReceived">"αποστολή εκπομπής που έχει ληφθεί με μήνυμα SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"ΕπιτÏέπει σε μια εφαÏμογή την εκπομπή ειδοποίησης σχετικά με τη λήψη μηνÏματος SMS. Κακόβουλες εφαÏμογές ενδέχεται να το χÏησιμοποιήσουν για την δημιουÏγία πλαστών εισεÏχόμενων μηνυμάτων SMS."</string>
+ <string name="permlab_broadcastWapPush">"αποστολή εκπομπής που έχει ληφθεί με WAP-PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"ΕπιτÏέπει σε μια εφαÏμογή να εκπέμψει μια ειδοποίηση σχετικά με τη λήψη μηνÏματος WAP PUSH. Κακόβουλες εφαÏμογές ενδέχεται να το χÏησιμοποιήσουν για να δημιουÏγήσουν ψευδείς λήψεις μηνυμάτων MMS ή για να αντικαταστήσουν χωÏίς ειδοποίηση το πεÏιεχόμενο μιας ιστοσελίδας με κακόβουλες παÏαλλαγές."</string>
+ <string name="permlab_setProcessLimit">"πεÏιοÏισμός αÏÎ¹Î¸Î¼Î¿Ï ÎµÎºÏ„ÎµÎ»Î¿Ïμενων διαδικασιών"</string>
+ <string name="permdesc_setProcessLimit">"ΕπιτÏέπει σε μια εφαÏμογή τον έλεγχο του μέγιστου αÏÎ¹Î¸Î¼Î¿Ï Î´Î¹Î±Î´Î¹ÎºÎ±ÏƒÎ¹ÏŽÎ½ που θα εκτελοÏνται. Δεν είναι ποτέ απαÏαίτητο για κανονικές εφαÏμογές."</string>
+ <string name="permlab_setAlwaysFinish">"κλείσιμο όλων των εφαÏμογών στο φόντο"</string>
+ <string name="permdesc_setAlwaysFinish">"ΕπιτÏέπει σε μια εφαÏμογή να ελέγχει εάν οι δÏαστηÏιότητες ολοκληÏώνονται πάντοτε μόλις μεταβοÏν στο φόντο. Δεν είναι ποτέ απαÏαίτητο για κανονικές εφαÏμογές."</string>
+ <string name="permlab_batteryStats">"Ï„Ïοποποίηση στατιστικών μπαταÏίας"</string>
+ <string name="permdesc_batteryStats">"ΕπιτÏέπει την Ï„Ïοποποίηση στατιστικών μπαταÏίας που έχουν συλλεχθεί. Δεν Ï€Ïέπει να χÏησιμοποιείται από συνήθεις εφαÏμογές."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"Ï€Ïοβολή μη εξουσιοδοτημένων παÏαθÏÏων"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"ΕπιτÏέπει τη δημιουÏγία παÏαθÏÏων που Ï€Ïόκειται να χÏησιμοποιηθοÏν από την εσωτεÏική διεπαφή χÏήστη του συστήματος. Δεν Ï€Ïέπει να χÏησιμοποιείται από κανονικές εφαÏμογές."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"εμφάνιση ειδοποιήσεων επιπέδου συστήματος"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"ΕπιτÏέπει σε μια εφαÏμογή την Ï€Ïοβολή παÏαθÏÏων ειδοποίησης συστήματος. Κακόβουλες εφαÏμογές μποÏοÏν να εμφανιστοÏν σε ολόκληÏη την οθόνη του τηλεφώνου."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"Ï„Ïοποποίηση καθολικής ταχÏτητας κίνησης εικόνας"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της καθολικής ταχÏτητας κίνησης εικόνας (ταχÏτεÏη ή βÏαδÏτεÏη κίνηση) οποιαδήποτε στιγμή."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"διαχείÏιση αναγνωÏιστικών εφαÏμογής"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"ΕπιτÏέπει σε εφαÏμογές τη δημιουÏγία και τη διαχείÏιση των δικών τους αναγνωÏιστικών, παÏακάμπτοντας την κανονική διάταξη Z. Δεν είναι απαÏαίτητο για κανονικές εφαÏμογές."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"πάτημα πλήκτÏων και κουμπιών ελέγχου"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"ΕπιτÏέπει σε μια εφαÏμογή την απόδοση των γεγονότων εισόδου της (πατήματα πλήκτÏων κ.λπ.) σε άλλες εφαÏμογές. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να αναλάβουν τον έλεγχο του τηλεφώνου."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"καταγÏαφή των ενεÏγειών σας και των στοιχείων που πληκτÏολογείτε"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"ΕπιτÏέπει σε εφαÏμογές να παÏακολουθοÏν τα πλήκτÏα που πατάτε, ακόμη και σε μια άλλη εφαÏμογή (όπως Ï€.χ. η καταχώÏηση ενός ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης). Δεν είναι απαÏαίτητο για συνήθεις εφαÏμογές."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"δέσμευση σε μέθοδο εισόδου"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"ΕπιτÏέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας μεθόδου εισόδου. Δεν είναι απαÏαίτητο για συνήθεις εφαÏμογές."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"αλλαγή Ï€ÏÎ¿ÏƒÎ±Î½Î±Ï„Î¿Î»Î¹ÏƒÎ¼Î¿Ï Î¿Î¸ÏŒÎ½Î·Ï‚"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της πεÏιστÏοφής της οθόνης οποιαδήποτε στιγμή. Δεν είναι απαÏαίτητο για κανονικές εφαÏμογές."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"αποστολή σημάτων Linux σε εφαÏμογές"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"ΕπιτÏέπει σε μια εφαÏμογή την αποστολή αιτήματος για την αποστολή του παÏεχόμενου σήματος σε όλες τις υπάÏχουσες διαδικασίες."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"η εφαÏμογή να εκτελείται συνεχώς"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"ΕπιτÏέπει σε μια εφαÏμογή την μετατÏοπή τμημάτων της σε συνεχή, ώστε το σÏστημα να μην μποÏεί να τη χÏησιμοποιήσει για άλλες εφαÏμογές."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"διαγÏαφή εφαÏμογών"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"ΕπιτÏέπει σε μια εφαÏμογή τη διαγÏαφή πακέτων Android. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να διαγÏάψουν σημαντικές εφαÏμογές."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"διαγÏαφή δεδομένων άλλων εφαÏμογών"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"ΕπιτÏέπει σε μια εφαÏμογή να εκκαθαÏίζει τα δεδομένα χÏήστη."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"διαγÏαφή Ï€ÏοσωÏινών μνημών άλλων εφαÏμογών"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"ΕπιτÏέπει σε μια εφαÏμογή τη διαγÏαφή αÏχείων Ï€ÏοσωÏινής μνήμης."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"μέτÏηση Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου εφαÏμογής"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"ΕπιτÏέπει σε μια εφαÏμογή να ανακτήσει τα μεγέθη κώδικα, δεδομένων και Ï€ÏοσωÏινής μνήμης"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"απευθείας εγκατάσταση εφαÏμογών"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"ΕπιτÏέπει σε μια εφαÏμογή την εγκατάσταση νέων ή ενημεÏωμένων πακέτων Android. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να Ï€Ïοσθέσουν νέες εφαÏμογές με πολλές αυθαίÏετες άδειες."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"διαγÏαφή όλων των δεδομένων Ï€ÏοσωÏινής μνήμης εφαÏμογής"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"ΕπιτÏέπει σε μια εφαÏμογή να αυξήσει τον ελεÏθεÏο χώÏο αποθήκευσης του τηλεφώνου διαγÏάφοντας αÏχεία από τον κατάλογο Ï€ÏοσωÏινής μνήμης της εφαÏμογής. Η Ï€Ïόσβαση είναι συνήθως Ï€Î¿Î»Ï Ï€ÎµÏιοÏισμένη στη διαδικασία συστήματος."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"ανάγνωση αÏχείων καταγÏαφής συστήματος"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"ΕπιτÏέπει σε μια εφαÏμογή να αναγνώσει τα αÏχεία καταγÏαφής του συστήματος. Έτσι μποÏεί να ανακαλÏψει γενικές πληÏοφοÏίες σχετικά με τις δÏαστηÏιότητές σας στο τηλέφωνο, όμως δεν θα Ï€Ïέπει να πεÏιέχουν Ï€Ïοσωπικές ή ιδιωτικές πληÏοφοÏίες."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγÏαφή σε πόÏους που ανήκουν στο διαγνωστικό"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση και την εγγÏαφή σε πόÏο που ανήκει στην ομάδα Î´Î¹Î±Î³Î½Ï‰ÏƒÏ„Î¹ÎºÎ¿Ï (Ï€.χ. αÏχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηÏεάσει την σταθεÏότητα και την ασφάλεια του συστήματος. Θα Ï€Ïέπει να χÏησιμοποιείται ΜΟÎΟ για διαγνωστικά Ï…Î»Î¹ÎºÎ¿Ï Ï„Î¿Ï… κατασκευαστή ή του χειÏιστή."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"ενεÏγοποίηση ή απενεÏγοποίηση στοιχείων εφαÏμογής"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"ΕπιτÏέπει σε μια εφαÏμογή την επιλογή ενεÏγοποίησης ή μη ενός στοιχείου μιας άλλης εφαÏμογής. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να απενεÏγοποιήσουν σημαντικές δυνατότητες του τηλεφώνου. Η χοÏήγηση άδειας Ï€Ïέπει να γίνεται με Ï€Ïοσοχή, καθώς είναι πιθανό τα στοιχεία μιας εφαÏμογής να καταστοÏν ασυνεχή, ασταθή ή να είναι αδÏνατον να χÏησιμοποιηθοÏν."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"οÏισμός Ï€Ïοτιμώμενων εφαÏμογών"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιεί τις εφαÏμογές που Ï€Ïοτιμάτε. Αυτό ενδέχεται να δώσει τη δυνατότητα σε κακόβουλες εφαÏμογές να αλλάξουν χωÏίς ειδοποίηση τις εφαÏμογές που εκτελοÏνται, \"ξεγελώντας\" τις υπάÏχουσες εφαÏμογές ώστε να συλλέξουν ιδιωτικά δεδομένα."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"Ï„Ïοποποίηση καθολικών Ïυθμίσεων συστήματος"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"ΕπιτÏέπει σε μια εφαÏμογή την Ï„Ïοποποίηση των δεδομένων των Ïυθμίσεων του συστήματος. Κακόβουλες εφαÏμογές μποÏοÏν να καταστÏέψουν τη διαμόÏφωση του συστήματός σας."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"Ï„Ïοποποίηση ασφαλών Ïυθμίσεων συστήματος"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιεί τα δεδομένα ασφαλών Ïυθμίσεων συστήματος. Δεν Ï€Ïέπει να χÏησιμοποιείται από κανονικές εφαÏμογές."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"μετατÏοπή του χάÏτη υπηÏεσιών Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"ΕπιτÏέπει σε μια εφαÏμογή την Ï„Ïοποποίηση του χάÏτη υπηÏεσιών Google. Δεν Ï€Ïέπει να χÏησιμοποιείται από κανονικές εφαÏμογές."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"αυτόματη εκκίνηση κατά την εκκίνηση του υπολογιστή"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"ΕπιτÏέπει σε μια εφαÏμογή να ξεκινήσει αυτόματα μόλις ολοκληÏωθεί η εκκίνηση του συστήματος. Αυτό ενδέχεται να καθυστεÏήσει την εκκίνηση του τηλεφώνου και να Ï€Ïοκαλέσει γενική μείωση της ταχÏτητας λειτουÏγίας του τηλεφώνου, καθώς η εφαÏμογή θα εκτελείται συνεχώς."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"αποστολή εκπομπής sticky"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"ΕπιτÏέπει σε μια εφαÏμογή την αποστολή εκπομπών sticky, οι οποίες παÏαμένουν μετά το τέλος της εκπομπής. Κακόβουλες εφαÏμογές μποÏοÏν να μειώσουν την ταχÏτητα λειτουÏγίας του τηλεφώνου ή να την καταστήσουν ασταθή χÏησιμοποιώντας Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿ ποσό μνήμης."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"ανάγνωση δεδομένων επαφής"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση όλων των δεδομένων επαφής (διεÏθυνσης) που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να αποστείλουν τα δεδομένα σας σε Ï„Ïίτους."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"εγγÏαφή δεδομένων επαφής"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιεί τα δεδομένα επαφής (διεÏθυνσης) που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να διαγÏάψουν ή να Ï„Ïοποποιήσουν τα δεδομένα επαφών σας."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"εγγÏαφή δεδομένων κατόχου"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιήσει τα δεδομένα κατόχου τηλεφώνου στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να Ï„Ïοποποιήσουν τα δεδομένα κατόχου."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"ανάγνωση δεδομένων κατόχου"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση των δεδομένων κατόχου τηλεφώνου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για την ανάγνωση δεδομένων κατόχου τηλεφώνου."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"ανάγνωση δεδομένων ημεÏολογίου"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"ΕπιτÏέπει σε μια εφαÏμογή να αναγνώσει όλα τα συμβάντα ημεÏολογίου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να αποστείλουν συμβάντα ημεÏολογίου σε άλλους χÏήστες."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"εγγÏαφή δεδομένων ημεÏολογίου"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"ΕπιτÏέπει σε μια εφαÏμογή την Ï„Ïοποποίηση των συμβάντων ημεÏολογίου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να διαγÏάψουν ή για να Ï„Ïοποποιήσουν τα δεδομένα ημεÏολογίου σας."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"δημιουÏγία ψευδών πηγών τοποθεσίας για δοκιμή"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"ΔημιουÏγία εικονικών πηγών τοποθεσίας για δοκιμή. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να παÏακάμψουν την τοποθεσία και/ή την κατάσταση που βÏίσκουν Ï€Ïαγματικές πηγές τοποθεσίας, όπως πάÏοχοι GPS ή πάÏοχοι δικτÏου."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Ï€Ïόσβαση σε επιπλέον εντολές παÏόχου τοποθεσίας"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"ΠÏόσβαση σε επιπλέον εντολές παÏόχου τοποθεσίας. Κακόβουλες εφαÏμογές ενδέχεται να το χÏησιμοποιήσουν ώστε να παÏέμβουν στη λειτουÏγία του GPS ή άλλων πηγών τοποθεσίας."</string>
+ <string name="permlab_internalSystemWindow">"Ï€Ïοβολή μη εξουσιοδοτημένων παÏαθÏÏων"</string>
+ <string name="permdesc_internalSystemWindow">"ΕπιτÏέπει τη δημιουÏγία παÏαθÏÏων που Ï€Ïόκειται να χÏησιμοποιηθοÏν από την εσωτεÏική διεπαφή χÏήστη του συστήματος. Δεν Ï€Ïέπει να χÏησιμοποιείται από κανονικές εφαÏμογές."</string>
+ <string name="permlab_systemAlertWindow">"εμφάνιση ειδοποιήσεων επιπέδου συστήματος"</string>
+ <string name="permdesc_systemAlertWindow">"ΕπιτÏέπει σε μια εφαÏμογή την Ï€Ïοβολή παÏαθÏÏων ειδοποίησης συστήματος. Κακόβουλες εφαÏμογές μποÏοÏν να εμφανιστοÏν σε ολόκληÏη την οθόνη του τηλεφώνου."</string>
+ <string name="permlab_setAnimationScale">"Ï„Ïοποποίηση καθολικής ταχÏτητας κίνησης εικόνας"</string>
+ <string name="permdesc_setAnimationScale">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της καθολικής ταχÏτητας κίνησης εικόνας (ταχÏτεÏη ή βÏαδÏτεÏη κίνηση) οποιαδήποτε στιγμή."</string>
+ <string name="permlab_manageAppTokens">"διαχείÏιση αναγνωÏιστικών εφαÏμογής"</string>
+ <string name="permdesc_manageAppTokens">"ΕπιτÏέπει σε εφαÏμογές τη δημιουÏγία και τη διαχείÏιση των δικών τους αναγνωÏιστικών, παÏακάμπτοντας την κανονική διάταξη Z. Δεν είναι απαÏαίτητο για κανονικές εφαÏμογές."</string>
+ <string name="permlab_injectEvents">"πάτημα πλήκτÏων και κουμπιών ελέγχου"</string>
+ <string name="permdesc_injectEvents">"ΕπιτÏέπει σε μια εφαÏμογή την απόδοση των γεγονότων εισόδου της (πατήματα πλήκτÏων κ.λπ.) σε άλλες εφαÏμογές. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να αναλάβουν τον έλεγχο του τηλεφώνου."</string>
+ <string name="permlab_readInputState">"καταγÏαφή των ενεÏγειών σας και των στοιχείων που πληκτÏολογείτε"</string>
+ <string name="permdesc_readInputState">"ΕπιτÏέπει σε εφαÏμογές να παÏακολουθοÏν τα πλήκτÏα που πατάτε, ακόμη και σε μια άλλη εφαÏμογή (όπως Ï€.χ. η καταχώÏηση ενός ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης). Δεν είναι απαÏαίτητο για συνήθεις εφαÏμογές."</string>
+ <string name="permlab_bindInputMethod">"δέσμευση σε μέθοδο εισόδου"</string>
+ <string name="permdesc_bindInputMethod">"ΕπιτÏέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας μεθόδου εισόδου. Δεν είναι απαÏαίτητο για συνήθεις εφαÏμογές."</string>
+ <string name="permlab_setOrientation">"αλλαγή Ï€ÏÎ¿ÏƒÎ±Î½Î±Ï„Î¿Î»Î¹ÏƒÎ¼Î¿Ï Î¿Î¸ÏŒÎ½Î·Ï‚"</string>
+ <string name="permdesc_setOrientation">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της πεÏιστÏοφής της οθόνης οποιαδήποτε στιγμή. Δεν είναι απαÏαίτητο για κανονικές εφαÏμογές."</string>
+ <string name="permlab_signalPersistentProcesses">"αποστολή σημάτων Linux σε εφαÏμογές"</string>
+ <string name="permdesc_signalPersistentProcesses">"ΕπιτÏέπει σε μια εφαÏμογή την αποστολή αιτήματος για την αποστολή του παÏεχόμενου σήματος σε όλες τις υπάÏχουσες διαδικασίες."</string>
+ <string name="permlab_persistentActivity">"η εφαÏμογή να εκτελείται συνεχώς"</string>
+ <string name="permdesc_persistentActivity">"ΕπιτÏέπει σε μια εφαÏμογή την μετατÏοπή τμημάτων της σε συνεχή, ώστε το σÏστημα να μην μποÏεί να τη χÏησιμοποιήσει για άλλες εφαÏμογές."</string>
+ <string name="permlab_deletePackages">"διαγÏαφή εφαÏμογών"</string>
+ <string name="permdesc_deletePackages">"ΕπιτÏέπει σε μια εφαÏμογή τη διαγÏαφή πακέτων Android. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να διαγÏάψουν σημαντικές εφαÏμογές."</string>
+ <string name="permlab_clearAppUserData">"διαγÏαφή δεδομένων άλλων εφαÏμογών"</string>
+ <string name="permdesc_clearAppUserData">"ΕπιτÏέπει σε μια εφαÏμογή να εκκαθαÏίζει τα δεδομένα χÏήστη."</string>
+ <string name="permlab_deleteCacheFiles">"διαγÏαφή Ï€ÏοσωÏινών μνημών άλλων εφαÏμογών"</string>
+ <string name="permdesc_deleteCacheFiles">"ΕπιτÏέπει σε μια εφαÏμογή τη διαγÏαφή αÏχείων Ï€ÏοσωÏινής μνήμης."</string>
+ <string name="permlab_getPackageSize">"μέτÏηση Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου εφαÏμογής"</string>
+ <string name="permdesc_getPackageSize">"ΕπιτÏέπει σε μια εφαÏμογή να ανακτήσει τα μεγέθη κώδικα, δεδομένων και Ï€ÏοσωÏινής μνήμης"</string>
+ <string name="permlab_installPackages">"απευθείας εγκατάσταση εφαÏμογών"</string>
+ <string name="permdesc_installPackages">"ΕπιτÏέπει σε μια εφαÏμογή την εγκατάσταση νέων ή ενημεÏωμένων πακέτων Android. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να Ï€Ïοσθέσουν νέες εφαÏμογές με πολλές αυθαίÏετες άδειες."</string>
+ <string name="permlab_clearAppCache">"διαγÏαφή όλων των δεδομένων Ï€ÏοσωÏινής μνήμης εφαÏμογής"</string>
+ <string name="permdesc_clearAppCache">"ΕπιτÏέπει σε μια εφαÏμογή να αυξήσει τον ελεÏθεÏο χώÏο αποθήκευσης του τηλεφώνου διαγÏάφοντας αÏχεία από τον κατάλογο Ï€ÏοσωÏινής μνήμης της εφαÏμογής. Η Ï€Ïόσβαση είναι συνήθως Ï€Î¿Î»Ï Ï€ÎµÏιοÏισμένη στη διαδικασία συστήματος."</string>
+ <string name="permlab_readLogs">"ανάγνωση αÏχείων καταγÏαφής συστήματος"</string>
+ <string name="permdesc_readLogs">"ΕπιτÏέπει σε μια εφαÏμογή να αναγνώσει τα αÏχεία καταγÏαφής του συστήματος. Έτσι μποÏεί να ανακαλÏψει γενικές πληÏοφοÏίες σχετικά με τις δÏαστηÏιότητές σας στο τηλέφωνο, όμως δεν θα Ï€Ïέπει να πεÏιέχουν Ï€Ïοσωπικές ή ιδιωτικές πληÏοφοÏίες."</string>
+ <string name="permlab_diagnostic">"ανάγνωση/εγγÏαφή σε πόÏους που ανήκουν στο διαγνωστικό"</string>
+ <string name="permdesc_diagnostic">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση και την εγγÏαφή σε πόÏο που ανήκει στην ομάδα Î´Î¹Î±Î³Î½Ï‰ÏƒÏ„Î¹ÎºÎ¿Ï (Ï€.χ. αÏχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηÏεάσει την σταθεÏότητα και την ασφάλεια του συστήματος. Θα Ï€Ïέπει να χÏησιμοποιείται ΜΟÎΟ για διαγνωστικά Ï…Î»Î¹ÎºÎ¿Ï Ï„Î¿Ï… κατασκευαστή ή του χειÏιστή."</string>
+ <string name="permlab_changeComponentState">"ενεÏγοποίηση ή απενεÏγοποίηση στοιχείων εφαÏμογής"</string>
+ <string name="permdesc_changeComponentState">"ΕπιτÏέπει σε μια εφαÏμογή την επιλογή ενεÏγοποίησης ή μη ενός στοιχείου μιας άλλης εφαÏμογής. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να απενεÏγοποιήσουν σημαντικές δυνατότητες του τηλεφώνου. Η χοÏήγηση άδειας Ï€Ïέπει να γίνεται με Ï€Ïοσοχή, καθώς είναι πιθανό τα στοιχεία μιας εφαÏμογής να καταστοÏν ασυνεχή, ασταθή ή να είναι αδÏνατον να χÏησιμοποιηθοÏν."</string>
+ <string name="permlab_setPreferredApplications">"οÏισμός Ï€Ïοτιμώμενων εφαÏμογών"</string>
+ <string name="permdesc_setPreferredApplications">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιεί τις εφαÏμογές που Ï€Ïοτιμάτε. Αυτό ενδέχεται να δώσει τη δυνατότητα σε κακόβουλες εφαÏμογές να αλλάξουν χωÏίς ειδοποίηση τις εφαÏμογές που εκτελοÏνται, \"ξεγελώντας\" τις υπάÏχουσες εφαÏμογές ώστε να συλλέξουν ιδιωτικά δεδομένα."</string>
+ <string name="permlab_writeSettings">"Ï„Ïοποποίηση καθολικών Ïυθμίσεων συστήματος"</string>
+ <string name="permdesc_writeSettings">"ΕπιτÏέπει σε μια εφαÏμογή την Ï„Ïοποποίηση των δεδομένων των Ïυθμίσεων του συστήματος. Κακόβουλες εφαÏμογές μποÏοÏν να καταστÏέψουν τη διαμόÏφωση του συστήματός σας."</string>
+ <string name="permlab_writeSecureSettings">"Ï„Ïοποποίηση ασφαλών Ïυθμίσεων συστήματος"</string>
+ <string name="permdesc_writeSecureSettings">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιεί τα δεδομένα ασφαλών Ïυθμίσεων συστήματος. Δεν Ï€Ïέπει να χÏησιμοποιείται από κανονικές εφαÏμογές."</string>
+ <string name="permlab_writeGservices">"μετατÏοπή του χάÏτη υπηÏεσιών Google"</string>
+ <string name="permdesc_writeGservices">"ΕπιτÏέπει σε μια εφαÏμογή την Ï„Ïοποποίηση του χάÏτη υπηÏεσιών Google. Δεν Ï€Ïέπει να χÏησιμοποιείται από κανονικές εφαÏμογές."</string>
+ <string name="permlab_receiveBootCompleted">"αυτόματη εκκίνηση κατά την εκκίνηση του υπολογιστή"</string>
+ <string name="permdesc_receiveBootCompleted">"ΕπιτÏέπει σε μια εφαÏμογή να ξεκινήσει αυτόματα μόλις ολοκληÏωθεί η εκκίνηση του συστήματος. Αυτό ενδέχεται να καθυστεÏήσει την εκκίνηση του τηλεφώνου και να Ï€Ïοκαλέσει γενική μείωση της ταχÏτητας λειτουÏγίας του τηλεφώνου, καθώς η εφαÏμογή θα εκτελείται συνεχώς."</string>
+ <string name="permlab_broadcastSticky">"αποστολή εκπομπής sticky"</string>
+ <string name="permdesc_broadcastSticky">"ΕπιτÏέπει σε μια εφαÏμογή την αποστολή εκπομπών sticky, οι οποίες παÏαμένουν μετά το τέλος της εκπομπής. Κακόβουλες εφαÏμογές μποÏοÏν να μειώσουν την ταχÏτητα λειτουÏγίας του τηλεφώνου ή να την καταστήσουν ασταθή χÏησιμοποιώντας Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿ ποσό μνήμης."</string>
+ <string name="permlab_readContacts">"ανάγνωση δεδομένων επαφής"</string>
+ <string name="permdesc_readContacts">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση όλων των δεδομένων επαφής (διεÏθυνσης) που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να αποστείλουν τα δεδομένα σας σε Ï„Ïίτους."</string>
+ <string name="permlab_writeContacts">"εγγÏαφή δεδομένων επαφής"</string>
+ <string name="permdesc_writeContacts">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιεί τα δεδομένα επαφής (διεÏθυνσης) που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να διαγÏάψουν ή να Ï„Ïοποποιήσουν τα δεδομένα επαφών σας."</string>
+ <string name="permlab_writeOwnerData">"εγγÏαφή δεδομένων κατόχου"</string>
+ <string name="permdesc_writeOwnerData">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιήσει τα δεδομένα κατόχου τηλεφώνου στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να Ï„Ïοποποιήσουν τα δεδομένα κατόχου."</string>
+ <string name="permlab_readOwnerData">"ανάγνωση δεδομένων κατόχου"</string>
+ <string name="permdesc_readOwnerData">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση των δεδομένων κατόχου τηλεφώνου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για την ανάγνωση δεδομένων κατόχου τηλεφώνου."</string>
+ <string name="permlab_readCalendar">"ανάγνωση δεδομένων ημεÏολογίου"</string>
+ <string name="permdesc_readCalendar">"ΕπιτÏέπει σε μια εφαÏμογή να αναγνώσει όλα τα συμβάντα ημεÏολογίου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να αποστείλουν συμβάντα ημεÏολογίου σε άλλους χÏήστες."</string>
+ <string name="permlab_writeCalendar">"εγγÏαφή δεδομένων ημεÏολογίου"</string>
+ <string name="permdesc_writeCalendar">"ΕπιτÏέπει σε μια εφαÏμογή την Ï„Ïοποποίηση των συμβάντων ημεÏολογίου που είναι αποθηκευμένα στο τηλέφωνό σας. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να διαγÏάψουν ή για να Ï„Ïοποποιήσουν τα δεδομένα ημεÏολογίου σας."</string>
+ <string name="permlab_accessMockLocation">"δημιουÏγία ψευδών πηγών τοποθεσίας για δοκιμή"</string>
+ <string name="permdesc_accessMockLocation">"ΔημιουÏγία εικονικών πηγών τοποθεσίας για δοκιμή. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να παÏακάμψουν την τοποθεσία και/ή την κατάσταση που βÏίσκουν Ï€Ïαγματικές πηγές τοποθεσίας, όπως πάÏοχοι GPS ή πάÏοχοι δικτÏου."</string>
+ <string name="permlab_accessLocationExtraCommands">"Ï€Ïόσβαση σε επιπλέον εντολές παÏόχου τοποθεσίας"</string>
+ <string name="permdesc_accessLocationExtraCommands">"ΠÏόσβαση σε επιπλέον εντολές παÏόχου τοποθεσίας. Κακόβουλες εφαÏμογές ενδέχεται να το χÏησιμοποιήσουν ώστε να παÏέμβουν στη λειτουÏγία του GPS ή άλλων πηγών τοποθεσίας."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"ακÏιβής τοποθεσία (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"ΠÏόσβαση σε πηγές ακÏιβοÏÏ‚ τοποθεσίας, όπως το Παγκόσμιο ΣÏστημα Î•Î½Ï„Î¿Ï€Î¹ÏƒÎ¼Î¿Ï (GPS) στο τηλέφωνο, όπου αυτό είναι διαθέσιμο. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να Ï€ÏοσδιοÏίσουν τη θέση που βÏίσκεστε και ενδέχεται να καταναλώσουν επιπλέον Î¹ÏƒÏ‡Ï Î¼Ï€Î±Ï„Î±Ïίας."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"κατά Ï€Ïοσέγγιση (βασισμένη στο δίκτυο) τοποθεσία"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"ΠÏόσβαση σε πηγές κατά Ï€Ïοσέγγιση τοποθεσίας, όπως η βάση δεδομένων δικτÏου κινητής τηλεφωνίας για τον κατά Ï€Ïοσέγγιση Ï€ÏοσδιοÏισμό της τοποθεσίας του τηλεφώνου, όπου αυτό είναι διαθέσιμο. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να Ï€ÏοσδιοÏίσουν κατά Ï€Ïοσέγγιση τη θέση σας."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Ï€Ïόσβαση στο SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"ΕπιτÏέπει σε μια εφαÏμογή να χÏησιμοποιεί λειτουÏγίες SurfaceFlinger Ï‡Î±Î¼Î·Î»Î¿Ï ÎµÏ€Î¹Ï€Î­Î´Î¿Ï…."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ανάγνωση Ï€ÏοσωÏινής μνήμης πλαισίου"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"ΕπιτÏέπει στην εφαÏμογή να χÏησιμοποιήσει και να αναγνώσει το πεÏιεχόμενο της Ï€ÏοσωÏινής μνήμης πλαισίου."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"αλλαγή των Ïυθμίσεων ήχου"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιήσει καθολικές Ïυθμίσεις ήχου όπως ένταση ήχου και δÏομολόγηση ήχου."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"εγγÏαφή ήχου"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"ΕπιτÏέπει σε μια εφαÏμογή την Ï€Ïόσβαση στη διαδÏομή εγγÏαφής ήχου."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"λήψη φωτογÏαφιών"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"ΕπιτÏέπει σε μια εφαÏμογή τη λήψη φωτογÏαφιών με την κάμεÏα. Αυτό επιτÏέπει στην εφαÏμογή να συλλέξει εικόνες, στις οποίες εστιάζει η κάμεÏα οποιαδήποτε στιγμή."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"μόνιμη απενεÏγοποίηση τηλεφώνου"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"ΕπιτÏέπει στην εφαÏμογή τη μόνιμη απενεÏγοποίηση όλων των λειτουÏγιών του τηλεφώνου, το οποίο είναι εξαιÏετικά επικίνδυνο."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"αναγκαστική επανεκκίνηση τηλεφώνου"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"ΕπιτÏέπει στην εφαÏμογή να Ï€Ïοκαλέσει αναγκαστική επανεκκίνηση του τηλεφώνου."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"σÏνδεση και αποσÏνδεση συστημάτων αÏχείων"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"ΕπιτÏέπει στην εφαÏμογή την Ï€ÏοσάÏτηση και αποπÏοσάÏτηση συστημάτων αÏχείων για αφαιÏοÏμενο αποθηκευτικό χώÏο."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"διαμόÏφωση εξωτεÏÎ¹ÎºÎ¿Ï Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"ΕπιτÏέπει στην εφαÏμογή τη διαμόÏφωση αφαιÏοÏμενου Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"έλεγχος δόνησης"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"ΕπιτÏέπει στην εφαÏμογή τον έλεγχο του δονητή."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"έλεγχος φακοÏ"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"ΕπιτÏέπει στην εφαÏμογή τον έλεγχο του φακοÏ."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"δοκιμή υλικοÏ"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"ΕπιτÏέπει σε μια εφαÏμογή τον έλεγχο διαφόÏων πεÏιφεÏειακών για την εκτέλεση δοκιμών υλικοÏ."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"απευθείας κλήση τηλεφωνικών αÏιθμών"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"ΕπιτÏέπει σε μια εφαÏμογή την κλήση τηλεφωνικών αÏιθμών χωÏίς την παÏέμβασή σας. Κακόβουλες εφαÏμογές ενδέχεται να ευθÏνονται για μη αναμενόμενες κλήσεις στον λογαÏιασμό τηλεφώνου σας. Λάβετε υπόψη ότι αυτό δεν επιτÏέπει την κλήση αÏιθμών έκτακτης ανάγκης."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"απευθείας κλήση τηλεφωνικών αÏιθμών"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"ΕπιτÏέπει στην εφαÏμογή την κλήση Ï„Î·Î»ÎµÏ†Ï‰Î½Î¹ÎºÎ¿Ï Î±ÏιθμοÏ, συμπεÏιλαμβανομένων και αÏιθμών έκτακτης ανάγκης, χωÏίς την παÏέμβασή σας. Κακόβουλες εφαÏμογές ενδέχεται να Ï€Ïαγματοποιήσουν μη αναγκαίες και παÏάνομες κλήσεις σε υπηÏεσίες έκτακτης ανάγκης."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"έλεγχος ειδοποιήσεων ενημέÏωσης τοποθεσίας"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"ΕπιτÏέπει την ενεÏγοποίηση/απενεÏγοποίηση ειδοποιήσεων ενημέÏωσης τοποθεσίας από τον πομπό. Δεν Ï€Ïέπει να χÏησιμοποιείται από κανονικές εφαÏμογές."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"Ï€Ïόσβαση σε ιδιότητες ελέγχου εισόδου"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"ΕπιτÏέπει την Ï€Ïόσβαση για ανάγνωση/εγγÏαφή σε ιδιότητες που έχουν μεταφοÏτωθεί από την υπηÏεσία ελέγχου εισόδου. Δεν Ï€Ïέπει να χÏησιμοποιείται από συνήθεις εφαÏμογές."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"επιλογή γÏαφικών στοιχείων"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"ΕπιτÏέπει στην εφαÏμογή να οÏίσει στο σÏστημα ποια γÏαφικά στοιχεία μποÏεί να χÏησιμοποιήσει κάθε εφαÏμογή. Με αυτή την άδεια, οι εφαÏμογές μποÏοÏν να παÏέχουν Ï€Ïόσβαση σε Ï€Ïοσωπικά δεδομένα σε άλλες εφαÏμογές. Δεν Ï€Ïέπει να χÏησιμοποιείται από συνήθεις εφαÏμογές."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"Ï„Ïοποποίηση κατάστασης τηλεφώνου"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"ΕπιτÏέπει στην εφαÏμογή τον έλεγχο των τηλεφωνικών δυνατοτήτων της συσκευής. Μια εφαÏμογή με αυτήν την άδεια μποÏεί να Ï€Ïαγματοποιήσει εναλλαγή Î¼ÎµÏ„Î±Î¾Ï Î´Î¹ÎºÏ„Ïων, να ενεÏγοποιήσει και να απενεÏγοποιήσει τον πομπό του τηλεφώνου κ.λπ. χωÏίς να σας ειδοποιήσει."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"παÏεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδÏάνειας"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"ΕπιτÏέπει σε μια εφαÏμογή την παÏεμπόδιση της μετάβασης του τηλεφώνου σε κατάσταση αδÏάνειας."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"ενεÏγοποίηση και απενεÏγοποίηση τηλεφώνου"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"ΕπιτÏέπει σε μια εφαÏμογή να ενεÏγοποιήσει ή να απενεÏγοποιήσει το τηλέφωνο."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"εκτέλεση σε λειτουÏγία εÏγοστασιακής δοκιμής"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Εκτέλεση ως Ï‡Î±Î¼Î·Î»Î¿Ï ÎµÏ€Î¹Ï€Î­Î´Î¿Ï… δοκιμή κατασκευαστή, ώστε να επιτÏέπεται πλήÏης Ï€Ïόσβαση στο υλικό του τηλεφώνου. Διαθέσιμο μόνο όταν το τηλέφωνο βÏίσκεται σε λειτουÏγία δοκιμής κατασκευαστή."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"οÏισμός ταπετσαÏίας"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"ΕπιτÏέπει στην εφαÏμογή τον οÏισμό της ταπετσαÏίας συστήματος."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"οÏισμός συμβουλών μεγέθους ταπετσαÏίας"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"ΕπιτÏέπει στην εφαÏμογή τον οÏισμό συμβουλών μεγέθους ταπετσαÏίας συστήματος."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"επαναφοÏά συστήματος στις εÏγοστασιακές Ï€Ïοεπιλογές"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"ΕπιτÏέπει σε μια εφαÏμογή να επαναφέÏει πλήÏως το σÏστημα στις εÏγοστασιακές Ïυθμίσεις, διαγÏάφοντας όλα τα δεδομένα, τις διαμοÏφώσεις και τις εγκατεστημένες εφαÏμογές."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"οÏισμός ζώνης ÏŽÏας"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της ζώνης ÏŽÏας του τηλεφώνου."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"ανακάλυψη γνωστών λογαÏιασμών"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"ΕπιτÏέπει σε μια εφαÏμογή να λάβει τη λίστα λογαÏιασμών του τηλεφώνου."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"Ï€Ïοβολή κατάστασης δικτÏου"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"ΕπιτÏέπει σε μια εφαÏμογή την Ï€Ïοβολή της κατάστασης όλων των δικτÏων."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"πλήÏης Ï€Ïόσβαση στο Διαδίκτυο"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"ΕπιτÏέπει σε μια εφαÏμογή τη δημιουÏγία υποδοχών δικτÏου (sockets)."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"εγγÏαφή Ïυθμίσεων Ονόματος σημείου Ï€Ïόσβασης (APN)"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιήσει τις Ïυθμίσεις APN, όπως Διακομιστής μεσολάβησης και ΘÏÏα για ένα APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"αλλαγή συνδεσιμότητας δικτÏου"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της κατάστασης συνδεσιμότητας δικτÏου."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"αλλαγή ÏÏθμισης της χÏήσης δεδομένων στο παÏασκήνιο"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της ÏÏθμισης χÏήσης δεδομένων φόντου."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Ï€Ïοβολή κατάστασης Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"ΕπιτÏέπει σε μια εφαÏμογή την Ï€Ïοβολή των πληÏοφοÏιών σχετικά με την κατάσταση του Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"αλλαγή κατάστασης Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"ΕπιτÏέπει σε μια εφαÏμογή τη σÏνδεση σε σημεία Ï€Ïόσβασης Wi-Fi και την αποσÏνδεση από αυτά, καθώς και την Ï€Ïαγματοποίηση αλλαγών σε διαμοÏφωμένα δίκτυα Wi-Fi."</string>
+ <string name="permlab_accessFineLocation">"ακÏιβής τοποθεσία (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"ΠÏόσβαση σε πηγές ακÏιβοÏÏ‚ τοποθεσίας, όπως το Παγκόσμιο ΣÏστημα Î•Î½Ï„Î¿Ï€Î¹ÏƒÎ¼Î¿Ï (GPS) στο τηλέφωνο, όπου αυτό είναι διαθέσιμο. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να Ï€ÏοσδιοÏίσουν τη θέση που βÏίσκεστε και ενδέχεται να καταναλώσουν επιπλέον Î¹ÏƒÏ‡Ï Î¼Ï€Î±Ï„Î±Ïίας."</string>
+ <string name="permlab_accessCoarseLocation">"κατά Ï€Ïοσέγγιση (βασισμένη στο δίκτυο) τοποθεσία"</string>
+ <string name="permdesc_accessCoarseLocation">"ΠÏόσβαση σε πηγές κατά Ï€Ïοσέγγιση τοποθεσίας, όπως η βάση δεδομένων δικτÏου κινητής τηλεφωνίας για τον κατά Ï€Ïοσέγγιση Ï€ÏοσδιοÏισμό της τοποθεσίας του τηλεφώνου, όπου αυτό είναι διαθέσιμο. Κακόβουλες εφαÏμογές μποÏοÏν να το χÏησιμοποιήσουν για να Ï€ÏοσδιοÏίσουν κατά Ï€Ïοσέγγιση τη θέση σας."</string>
+ <string name="permlab_accessSurfaceFlinger">"Ï€Ïόσβαση στο SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"ΕπιτÏέπει σε μια εφαÏμογή να χÏησιμοποιεί λειτουÏγίες SurfaceFlinger Ï‡Î±Î¼Î·Î»Î¿Ï ÎµÏ€Î¹Ï€Î­Î´Î¿Ï…."</string>
+ <string name="permlab_readFrameBuffer">"ανάγνωση Ï€ÏοσωÏινής μνήμης πλαισίου"</string>
+ <string name="permdesc_readFrameBuffer">"ΕπιτÏέπει στην εφαÏμογή να χÏησιμοποιήσει και να αναγνώσει το πεÏιεχόμενο της Ï€ÏοσωÏινής μνήμης πλαισίου."</string>
+ <string name="permlab_modifyAudioSettings">"αλλαγή των Ïυθμίσεων ήχου"</string>
+ <string name="permdesc_modifyAudioSettings">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιήσει καθολικές Ïυθμίσεις ήχου όπως ένταση ήχου και δÏομολόγηση ήχου."</string>
+ <string name="permlab_recordAudio">"εγγÏαφή ήχου"</string>
+ <string name="permdesc_recordAudio">"ΕπιτÏέπει σε μια εφαÏμογή την Ï€Ïόσβαση στη διαδÏομή εγγÏαφής ήχου."</string>
+ <string name="permlab_camera">"λήψη φωτογÏαφιών"</string>
+ <string name="permdesc_camera">"ΕπιτÏέπει σε μια εφαÏμογή τη λήψη φωτογÏαφιών με την κάμεÏα. Αυτό επιτÏέπει στην εφαÏμογή να συλλέξει εικόνες, στις οποίες εστιάζει η κάμεÏα οποιαδήποτε στιγμή."</string>
+ <string name="permlab_brick">"μόνιμη απενεÏγοποίηση τηλεφώνου"</string>
+ <string name="permdesc_brick">"ΕπιτÏέπει στην εφαÏμογή τη μόνιμη απενεÏγοποίηση όλων των λειτουÏγιών του τηλεφώνου, το οποίο είναι εξαιÏετικά επικίνδυνο."</string>
+ <string name="permlab_reboot">"αναγκαστική επανεκκίνηση τηλεφώνου"</string>
+ <string name="permdesc_reboot">"ΕπιτÏέπει στην εφαÏμογή να Ï€Ïοκαλέσει αναγκαστική επανεκκίνηση του τηλεφώνου."</string>
+ <string name="permlab_mount_unmount_filesystems">"ΠÏοσάÏτηση και αποπÏοσάÏτηση συστημάτων αÏχείων"</string>
+ <string name="permdesc_mount_unmount_filesystems">"ΕπιτÏέπει στην εφαÏμογή την Ï€ÏοσάÏτηση και αποπÏοσάÏτηση συστημάτων αÏχείων για αφαιÏοÏμενο αποθηκευτικό χώÏο."</string>
+ <string name="permlab_mount_format_filesystems">"διαμόÏφωση εξωτεÏÎ¹ÎºÎ¿Ï Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου"</string>
+ <string name="permdesc_mount_format_filesystems">"ΕπιτÏέπει στην εφαÏμογή τη διαμόÏφωση αφαιÏοÏμενου Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου."</string>
+ <string name="permlab_vibrate">"έλεγχος δόνησης"</string>
+ <string name="permdesc_vibrate">"ΕπιτÏέπει στην εφαÏμογή τον έλεγχο του δονητή."</string>
+ <string name="permlab_flashlight">"έλεγχος φακοÏ"</string>
+ <string name="permdesc_flashlight">"ΕπιτÏέπει στην εφαÏμογή τον έλεγχο του φακοÏ."</string>
+ <string name="permlab_hardware_test">"δοκιμή υλικοÏ"</string>
+ <string name="permdesc_hardware_test">"ΕπιτÏέπει σε μια εφαÏμογή τον έλεγχο διαφόÏων πεÏιφεÏειακών για την εκτέλεση δοκιμών υλικοÏ."</string>
+ <string name="permlab_callPhone">"απευθείας κλήση τηλεφωνικών αÏιθμών"</string>
+ <string name="permdesc_callPhone">"ΕπιτÏέπει σε μια εφαÏμογή την κλήση τηλεφωνικών αÏιθμών χωÏίς την παÏέμβασή σας. Κακόβουλες εφαÏμογές ενδέχεται να ευθÏνονται για μη αναμενόμενες κλήσεις στον λογαÏιασμό τηλεφώνου σας. Λάβετε υπόψη ότι αυτό δεν επιτÏέπει την κλήση αÏιθμών έκτακτης ανάγκης."</string>
+ <string name="permlab_callPrivileged">"απευθείας κλήση τηλεφωνικών αÏιθμών"</string>
+ <string name="permdesc_callPrivileged">"ΕπιτÏέπει στην εφαÏμογή την κλήση Ï„Î·Î»ÎµÏ†Ï‰Î½Î¹ÎºÎ¿Ï Î±ÏιθμοÏ, συμπεÏιλαμβανομένων και αÏιθμών έκτακτης ανάγκης, χωÏίς την παÏέμβασή σας. Κακόβουλες εφαÏμογές ενδέχεται να Ï€Ïαγματοποιήσουν μη αναγκαίες και παÏάνομες κλήσεις σε υπηÏεσίες έκτακτης ανάγκης."</string>
+ <string name="permlab_locationUpdates">"έλεγχος ειδοποιήσεων ενημέÏωσης τοποθεσίας"</string>
+ <string name="permdesc_locationUpdates">"ΕπιτÏέπει την ενεÏγοποίηση/απενεÏγοποίηση ειδοποιήσεων ενημέÏωσης τοποθεσίας από τον πομπό. Δεν Ï€Ïέπει να χÏησιμοποιείται από κανονικές εφαÏμογές."</string>
+ <string name="permlab_checkinProperties">"Ï€Ïόσβαση σε ιδιότητες ελέγχου εισόδου"</string>
+ <string name="permdesc_checkinProperties">"ΕπιτÏέπει την Ï€Ïόσβαση για ανάγνωση/εγγÏαφή σε ιδιότητες που έχουν μεταφοÏτωθεί από την υπηÏεσία ελέγχου εισόδου. Δεν Ï€Ïέπει να χÏησιμοποιείται από συνήθεις εφαÏμογές."</string>
+ <string name="permlab_bindGadget">"επιλογή γÏαφικών στοιχείων"</string>
+ <string name="permdesc_bindGadget">"ΕπιτÏέπει στην εφαÏμογή να οÏίσει στο σÏστημα ποια γÏαφικά στοιχεία μποÏεί να χÏησιμοποιήσει κάθε εφαÏμογή. Με αυτή την άδεια, οι εφαÏμογές μποÏοÏν να παÏέχουν Ï€Ïόσβαση σε Ï€Ïοσωπικά δεδομένα σε άλλες εφαÏμογές. Δεν Ï€Ïέπει να χÏησιμοποιείται από συνήθεις εφαÏμογές."</string>
+ <string name="permlab_modifyPhoneState">"Ï„Ïοποποίηση κατάστασης τηλεφώνου"</string>
+ <string name="permdesc_modifyPhoneState">"ΕπιτÏέπει στην εφαÏμογή τον έλεγχο των τηλεφωνικών δυνατοτήτων της συσκευής. Μια εφαÏμογή με αυτήν την άδεια μποÏεί να Ï€Ïαγματοποιήσει εναλλαγή Î¼ÎµÏ„Î±Î¾Ï Î´Î¹ÎºÏ„Ïων, να ενεÏγοποιήσει και να απενεÏγοποιήσει τον πομπό του τηλεφώνου κ.λπ. χωÏίς να σας ειδοποιήσει."</string>
+ <string name="permlab_readPhoneState">"ανάγνωση κατάστασης τηλεφώνου"</string>
+ <string name="permdesc_readPhoneState">"ΕπιτÏέπει στην εφαÏμογή την Ï€Ïόσβαση στις λειτουÏγίες τηλεφώνου της συσκευής. Μια εφαÏμογή με αυτή την άδεια μποÏεί να Ï€ÏοσδιοÏίσει τον τηλεφωνικό αÏιθμό του τηλεφώνου, αν μια κλήση είναι ενεÏγή ή όχι, τον τηλεφωνικό αÏιθμό της κλήσης κ.λπ.."</string>
+ <string name="permlab_wakeLock">"παÏεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδÏάνειας"</string>
+ <string name="permdesc_wakeLock">"ΕπιτÏέπει σε μια εφαÏμογή την παÏεμπόδιση της μετάβασης του τηλεφώνου σε κατάσταση αδÏάνειας."</string>
+ <string name="permlab_devicePower">"ενεÏγοποίηση και απενεÏγοποίηση τηλεφώνου"</string>
+ <string name="permdesc_devicePower">"ΕπιτÏέπει σε μια εφαÏμογή να ενεÏγοποιήσει ή να απενεÏγοποιήσει το τηλέφωνο."</string>
+ <string name="permlab_factoryTest">"εκτέλεση σε λειτουÏγία εÏγοστασιακής δοκιμής"</string>
+ <string name="permdesc_factoryTest">"Εκτέλεση ως Ï‡Î±Î¼Î·Î»Î¿Ï ÎµÏ€Î¹Ï€Î­Î´Î¿Ï… δοκιμή κατασκευαστή, ώστε να επιτÏέπεται πλήÏης Ï€Ïόσβαση στο υλικό του τηλεφώνου. Διαθέσιμο μόνο όταν το τηλέφωνο βÏίσκεται σε λειτουÏγία δοκιμής κατασκευαστή."</string>
+ <string name="permlab_setWallpaper">"οÏισμός ταπετσαÏίας"</string>
+ <string name="permdesc_setWallpaper">"ΕπιτÏέπει στην εφαÏμογή τον οÏισμό της ταπετσαÏίας συστήματος."</string>
+ <string name="permlab_setWallpaperHints">"οÏισμός συμβουλών μεγέθους ταπετσαÏίας"</string>
+ <string name="permdesc_setWallpaperHints">"ΕπιτÏέπει στην εφαÏμογή τον οÏισμό συμβουλών μεγέθους ταπετσαÏίας συστήματος."</string>
+ <string name="permlab_masterClear">"επαναφοÏά συστήματος στις εÏγοστασιακές Ï€Ïοεπιλογές"</string>
+ <string name="permdesc_masterClear">"ΕπιτÏέπει σε μια εφαÏμογή να επαναφέÏει πλήÏως το σÏστημα στις εÏγοστασιακές Ïυθμίσεις, διαγÏάφοντας όλα τα δεδομένα, τις διαμοÏφώσεις και τις εγκατεστημένες εφαÏμογές."</string>
+ <string name="permlab_setTimeZone">"οÏισμός ζώνης ÏŽÏας"</string>
+ <string name="permdesc_setTimeZone">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της ζώνης ÏŽÏας του τηλεφώνου."</string>
+ <string name="permlab_getAccounts">"ανακάλυψη γνωστών λογαÏιασμών"</string>
+ <string name="permdesc_getAccounts">"ΕπιτÏέπει σε μια εφαÏμογή να λάβει τη λίστα λογαÏιασμών του τηλεφώνου."</string>
+ <string name="permlab_accessNetworkState">"Ï€Ïοβολή κατάστασης δικτÏου"</string>
+ <string name="permdesc_accessNetworkState">"ΕπιτÏέπει σε μια εφαÏμογή την Ï€Ïοβολή της κατάστασης όλων των δικτÏων."</string>
+ <string name="permlab_createNetworkSockets">"πλήÏης Ï€Ïόσβαση στο Διαδίκτυο"</string>
+ <string name="permdesc_createNetworkSockets">"ΕπιτÏέπει σε μια εφαÏμογή τη δημιουÏγία υποδοχών δικτÏου (sockets)."</string>
+ <string name="permlab_writeApnSettings">"εγγÏαφή Ïυθμίσεων Ονόματος σημείου Ï€Ïόσβασης (APN)"</string>
+ <string name="permdesc_writeApnSettings">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιήσει τις Ïυθμίσεις APN, όπως Διακομιστής μεσολάβησης και ΘÏÏα για ένα APN."</string>
+ <string name="permlab_changeNetworkState">"αλλαγή συνδεσιμότητας δικτÏου"</string>
+ <string name="permdesc_changeNetworkState">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της κατάστασης συνδεσιμότητας δικτÏου."</string>
+ <string name="permlab_changeBackgroundDataSetting">"αλλαγή ÏÏθμισης της χÏήσης δεδομένων στο παÏασκήνιο"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"ΕπιτÏέπει σε μια εφαÏμογή την αλλαγή της ÏÏθμισης χÏήσης δεδομένων φόντου."</string>
+ <string name="permlab_accessWifiState">"Ï€Ïοβολή κατάστασης Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"ΕπιτÏέπει σε μια εφαÏμογή την Ï€Ïοβολή των πληÏοφοÏιών σχετικά με την κατάσταση του Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"αλλαγή κατάστασης Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"ΕπιτÏέπει σε μια εφαÏμογή τη σÏνδεση σε σημεία Ï€Ïόσβασης Wi-Fi και την αποσÏνδεση από αυτά, καθώς και την Ï€Ïαγματοποίηση αλλαγών σε διαμοÏφωμένα δίκτυα Wi-Fi."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"διαχείÏιση Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"ΕπιτÏέπει σε μια εφαÏμογή τη διαμόÏφωση του Ï„Î¿Ï€Î¹ÎºÎ¿Ï Ï„Î·Î»ÎµÏ†ÏŽÎ½Î¿Ï… Bluetooth και την ανακάλυψη και σÏζευξη με απομακÏυσμένες συσκευές."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"δημιουÏγία συνδέσεων Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"ΕπιτÏέπει σε μια εφαÏμογή να Ï€Ïοβάλει τη διαμόÏφωση του Ï„Î¿Ï€Î¹ÎºÎ¿Ï Ï„Î·Î»ÎµÏ†ÏŽÎ½Î¿Ï… Bluetooth και επίσης να Ï€Ïαγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"απενεÏγοποίηση κλειδώματος πληκτÏολογίου"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"ΕπιτÏέπει σε μια εφαÏμογή την απενεÏγοποίηση του κλειδώματος πληκτÏολογίου και άλλης σχετικής ασφάλειας με κωδικό Ï€Ïόσβασης. Για παÏάδειγμα, η απενεÏγοποίηση του κλειδώματος πληκτÏολογίου όταν λαμβάνεται εισεÏχόμενη τηλεφωνική κλήση και η επανενεÏγοποίηση του κλειδώματος πληκτÏολογίου όταν η κλήση τεÏματιστεί."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ανάγνωση Ïυθμίσεων συγχÏονισμοÏ"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση των Ïυθμίσεων συγχÏονισμοÏ, όπως Ï€.χ. εάν ο συγχÏονισμός είναι ενεÏγοποιημένος για τις Επαφές."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"καταγÏαφή Ïυθμίσεων συγχÏονισμοÏ"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"ΕπιτÏέπει σε μια εφαÏμογή την Ï„Ïοποποίηση των Ïυθμίσεων συγχÏÎ¿Î½Î¹ÏƒÎ¼Î¿Ï (Ï€.χ. εάν ο συγχÏονισμός είναι ενεÏγοποιημένος για τις Επαφές)."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"ανάγνωση στατιστικών συγχÏονισμοÏ"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση των στατιστικών συγχÏÎ¿Î½Î¹ÏƒÎ¼Î¿Ï (Ï€.χ. το ιστοÏικό των συγχÏονισμών που έχουν Ï€Ïαγματοποιηθεί)."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ανάγνωση Ïοών δεδομένων στις οποίες έχετε εγγÏαφεί"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"ΕπιτÏέπει σε μια εφαÏμογή τη λήψη λεπτομεÏειών σχετικά με τις Ï„Ïέχουσες συγχÏονισμένες Ïοές δεδομένων."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"εγγÏαφή Ïοών δεδομένων στις οποίες έχετε εγγÏαφεί"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιήσει τις Ïοές δεδομένων, με τις οποίες είστε συγχÏονισμένοι αυτή τη στιγμή. Αυτό θα μποÏοÏσε να δώσει τη δυνατότητα σε μια κακόβουλη εφαÏμογή να αλλάξει τις συγχÏονισμένες Ïοές δεδομένων σας."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"ανάγνωση καθοÏισμένου από το χÏήστη λεξικοÏ"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"ΕπιτÏέπει σε μια εφαÏμογή να αναγνώσει ιδιωτικές λέξεις και φÏάσεις και ιδιωτικά ονόματα, τα οποία ο χÏήστης ενδέχεται να έχει αποθηκεÏσει στο λεξικό χÏήστη."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"εγγÏαφή σε καθοÏισμένο από τον χÏήστη λεξικό"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"ΕπιτÏέπει σε μια εφαÏμογή την εγγÏαφή νέων λέξεων στο λεξικό χÏήστη."</string>
+ <string name="permlab_bluetoothAdmin">"διαχείÏιση bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"ΕπιτÏέπει σε μια εφαÏμογή τη διαμόÏφωση του Ï„Î¿Ï€Î¹ÎºÎ¿Ï Ï„Î·Î»ÎµÏ†ÏŽÎ½Î¿Ï… Bluetooth και την ανακάλυψη και σÏζευξη με απομακÏυσμένες συσκευές."</string>
+ <string name="permlab_bluetooth">"δημιουÏγία συνδέσεων Bluetooth"</string>
+ <string name="permdesc_bluetooth">"ΕπιτÏέπει σε μια εφαÏμογή να Ï€Ïοβάλει τη διαμόÏφωση του Ï„Î¿Ï€Î¹ÎºÎ¿Ï Ï„Î·Î»ÎµÏ†ÏŽÎ½Î¿Ï… Bluetooth και επίσης να Ï€Ïαγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
+ <string name="permlab_disableKeyguard">"απενεÏγοποίηση κλειδώματος πληκτÏολογίου"</string>
+ <string name="permdesc_disableKeyguard">"ΕπιτÏέπει σε μια εφαÏμογή την απενεÏγοποίηση του κλειδώματος πληκτÏολογίου και άλλης σχετικής ασφάλειας με κωδικό Ï€Ïόσβασης. Για παÏάδειγμα, η απενεÏγοποίηση του κλειδώματος πληκτÏολογίου όταν λαμβάνεται εισεÏχόμενη τηλεφωνική κλήση και η επανενεÏγοποίηση του κλειδώματος πληκτÏολογίου όταν η κλήση τεÏματιστεί."</string>
+ <string name="permlab_readSyncSettings">"ανάγνωση Ïυθμίσεων συγχÏονισμοÏ"</string>
+ <string name="permdesc_readSyncSettings">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση των Ïυθμίσεων συγχÏονισμοÏ, όπως Ï€.χ. εάν ο συγχÏονισμός είναι ενεÏγοποιημένος για τις Επαφές."</string>
+ <string name="permlab_writeSyncSettings">"καταγÏαφή Ïυθμίσεων συγχÏονισμοÏ"</string>
+ <string name="permdesc_writeSyncSettings">"ΕπιτÏέπει σε μια εφαÏμογή την Ï„Ïοποποίηση των Ïυθμίσεων συγχÏÎ¿Î½Î¹ÏƒÎ¼Î¿Ï (Ï€.χ. εάν ο συγχÏονισμός είναι ενεÏγοποιημένος για τις Επαφές)."</string>
+ <string name="permlab_readSyncStats">"ανάγνωση στατιστικών συγχÏονισμοÏ"</string>
+ <string name="permdesc_readSyncStats">"ΕπιτÏέπει σε μια εφαÏμογή την ανάγνωση των στατιστικών συγχÏÎ¿Î½Î¹ÏƒÎ¼Î¿Ï (Ï€.χ. το ιστοÏικό των συγχÏονισμών που έχουν Ï€Ïαγματοποιηθεί)."</string>
+ <string name="permlab_subscribedFeedsRead">"ανάγνωση Ïοών δεδομένων στις οποίες έχετε εγγÏαφεί"</string>
+ <string name="permdesc_subscribedFeedsRead">"ΕπιτÏέπει σε μια εφαÏμογή τη λήψη λεπτομεÏειών σχετικά με τις Ï„Ïέχουσες συγχÏονισμένες Ïοές δεδομένων."</string>
+ <string name="permlab_subscribedFeedsWrite">"εγγÏαφή Ïοών δεδομένων στις οποίες έχετε εγγÏαφεί"</string>
+ <string name="permdesc_subscribedFeedsWrite">"ΕπιτÏέπει σε μια εφαÏμογή να Ï„Ïοποποιήσει τις Ïοές δεδομένων, με τις οποίες είστε συγχÏονισμένοι αυτή τη στιγμή. Αυτό θα μποÏοÏσε να δώσει τη δυνατότητα σε μια κακόβουλη εφαÏμογή να αλλάξει τις συγχÏονισμένες Ïοές δεδομένων σας."</string>
+ <string name="permlab_readDictionary">"ανάγνωση καθοÏισμένου από τον χÏήστη λεξικοÏ"</string>
+ <string name="permdesc_readDictionary">"ΕπιτÏέπει σε μια εφαÏμογή να αναγνώσει ιδιωτικές λέξεις και φÏάσεις και ιδιωτικά ονόματα, τα οποία ο χÏήστης ενδέχεται να έχει αποθηκεÏσει στο λεξικό χÏήστη."</string>
+ <string name="permlab_writeDictionary">"εγγÏαφή σε καθοÏισμένο από τον χÏήστη λεξικό"</string>
+ <string name="permdesc_writeDictionary">"ΕπιτÏέπει σε μια εφαÏμογή την εγγÏαφή νέων λέξεων στο λεξικό χÏήστη."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Οικία"</item>
- <item msgid="869923650527136615">"Κινητό"</item>
- <item msgid="7897544654242874543">"ΕÏγασία"</item>
- <item msgid="1103601433382158155">"Φαξ εÏγασίας"</item>
- <item msgid="1735177144948329370">"Φαξ οικίας"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Άλλο"</item>
- <item msgid="9192514806975898961">"ΠÏοσαÏμοσμένο"</item>
+ <item>"Οικία"</item>
+ <item>"Κινητό"</item>
+ <item>"ΕÏγασία"</item>
+ <item>"Φαξ εÏγασίας"</item>
+ <item>"Φαξ οικίας"</item>
+ <item>"Pager"</item>
+ <item>"Άλλο"</item>
+ <item>"ΠÏοσαÏμοσμένο"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Οικία"</item>
- <item msgid="7084237356602625604">"ΕÏγασία"</item>
- <item msgid="1112044410659011023">"Άλλο"</item>
- <item msgid="2374913952870110618">"ΠÏοσαÏμοσμένο"</item>
+ <item>"Οικία"</item>
+ <item>"ΕÏγασία"</item>
+ <item>"Άλλο"</item>
+ <item>"ΠÏοσαÏμοσμένο"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Κινητό"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Οικία"</item>
- <item msgid="5629153956045109251">"ΕÏγασία"</item>
- <item msgid="4966604264500343469">"Άλλο"</item>
- <item msgid="4932682847595299369">"ΠÏοσαÏμοσμένο"</item>
+ <item>"Οικία"</item>
+ <item>"ΕÏγασία"</item>
+ <item>"Άλλο"</item>
+ <item>"ΠÏοσαÏμοσμένο"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Οικία"</item>
- <item msgid="1359644565647383708">"ΕÏγασία"</item>
- <item msgid="7868549401053615677">"Άλλο"</item>
- <item msgid="3145118944639869809">"ΠÏοσαÏμοσμένο"</item>
+ <item>"Οικία"</item>
+ <item>"ΕÏγασία"</item>
+ <item>"Άλλο"</item>
+ <item>"ΠÏοσαÏμοσμένο"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"ΕÏγασία"</item>
- <item msgid="4378074129049520373">"Άλλο"</item>
- <item msgid="3455047468583965104">"ΠÏοσαÏμοσμένο"</item>
+ <item>"ΕÏγασία"</item>
+ <item>"Άλλο"</item>
+ <item>"ΠÏοσαÏμοσμένο"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"ΠληκτÏολογήστε τον κωδικό αÏιθμό PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Εσφαλμένος κωδικός αÏιθμός PIN!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Για ξεκλείδωμα, πατήστε το πλήκτÏο Menu και, στη συνέχεια, το πλήκτÏο 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ΑÏιθμός έκτακτης ανάγκης"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Καμία υπηÏεσία)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Η οθόνη κλειδώθηκε."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Πατήστε \"Menu\" για ξεκλείδωμα ή για κλήση έκτακτης ανάγκης."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Πατήστε \"ΜενοÏ\" για ξεκλείδωμα."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Σχεδιασμός μοτίβου για ξεκλείδωμα"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Κλήση έκτακτης ανάγκης"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Σωστό!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"ΠÏοσπαθήστε αÏγότεÏα"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"ΦόÏτιση (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"ΠληκτÏολογήστε τον κωδικό αÏιθμό PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Εσφαλμένος κωδικός αÏιθμός PIN!"</string>
+ <string name="keyguard_label_text">"Για ξεκλείδωμα, πατήστε το πλήκτÏο Menu και, στη συνέχεια, το πλήκτÏο 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"ΑÏιθμός έκτακτης ανάγκης"</string>
+ <string name="lockscreen_carrier_default">"(Καμία υπηÏεσία)"</string>
+ <string name="lockscreen_screen_locked">"Η οθόνη κλειδώθηκε."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Πατήστε \"Menu\" για ξεκλείδωμα ή για κλήση έκτακτης ανάγκης."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Πατήστε \"ΜενοÏ\" για ξεκλείδωμα."</string>
+ <string name="lockscreen_pattern_instructions">"Σχεδιασμός μοτίβου για ξεκλείδωμα"</string>
+ <string name="lockscreen_emergency_call">"Κλήση έκτακτης ανάγκης"</string>
+ <string name="lockscreen_pattern_correct">"Σωστό!"</string>
+ <string name="lockscreen_pattern_wrong">"ΠÏοσπαθήστε αÏγότεÏα"</string>
+ <string name="lockscreen_plugged_in">"ΦόÏτιση (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Συνδέστε τον φοÏτιστή."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Δεν υπάÏχει κάÏτα SIM."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Δεν υπάÏχει κάÏτα SIM στο τηλέφωνο."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Τοποθετήστε μια κάÏτα SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Το δίκτυο κλειδώθηκε"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Η κάÏτα SIM είναι κλειδωμένη με κωδικό PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"ΑνατÏέξτε στον οδηγό χÏήσης ή επικοινωνήστε με την εξυπηÏέτηση πελατών."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Η κάÏτα SIM είναι κλειδωμένη."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Ξεκλείδωμα κάÏτας SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος<xliff:g id="NUMBER_0">%d</xliff:g> φοÏές. "\n\n"ΠÏοσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτεÏόλεπτα."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φοÏές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς Ï€Ïοσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χÏήση της σÏνδεσής σας Google."\n\n" ΠÏοσπαθήστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> \nδευτεÏόλεπτα."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"ΠÏοσπαθήστε ξανά σε <xliff:g id="NUMBER">%d</xliff:g> δευτεÏόλεπτα."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Ξεχάσατε το μοτίβο;"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"ΠάÏα πολλές Ï€Ïοσπάθειες μοτίβου!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Για ξεκλείδωμα, συνδεθείτε με τον λογαÏιασμό σας Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Όνομα χÏήστη (διεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Κωδικός Ï€Ïόσβασης"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ΣÏνδεση"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Μη έγκυÏο όνομα χÏήστη ή κωδικός Ï€Ïόσβασης."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Συνδέστε τον φοÏτιστή."</string>
+ <string name="lockscreen_missing_sim_message_short">"Δεν υπάÏχει κάÏτα SIM."</string>
+ <string name="lockscreen_missing_sim_message">"Δεν υπάÏχει κάÏτα SIM στο τηλέφωνο."</string>
+ <string name="lockscreen_missing_sim_instructions">"Τοποθετήστε μια κάÏτα SIM."</string>
+ <string name="lockscreen_network_locked_message">"Το δίκτυο κλειδώθηκε"</string>
+ <string name="lockscreen_sim_puk_locked_message">"Η κάÏτα SIM είναι κλειδωμένη με κωδικό PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"ΑνατÏέξτε στον οδηγό χÏήσης ή επικοινωνήστε με την εξυπηÏέτηση πελατών."</string>
+ <string name="lockscreen_sim_locked_message">"Η κάÏτα SIM είναι κλειδωμένη."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Ξεκλείδωμα κάÏτας SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος<xliff:g id="NUMBER_0">%d</xliff:g> φοÏές. "\n\n"ΠÏοσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτεÏόλεπτα."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φοÏές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς Ï€Ïοσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χÏήση της σÏνδεσής σας Google."\n\n" ΠÏοσπαθήστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> \nδευτεÏόλεπτα."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"ΠÏοσπαθήστε ξανά σε <xliff:g id="NUMBER">%d</xliff:g> δευτεÏόλεπτα."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Ξεχάσατε το μοτίβο;"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"ΠάÏα πολλές Ï€Ïοσπάθειες μοτίβου!"</string>
+ <string name="lockscreen_glogin_instructions">"Για ξεκλείδωμα, συνδεθείτε με τον λογαÏιασμό σας Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Όνομα χÏήστη (διεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου)"</string>
+ <string name="lockscreen_glogin_password_hint">"Κωδικός Ï€Ïόσβασης"</string>
+ <string name="lockscreen_glogin_submit_button">"ΣÏνδεση"</string>
+ <string name="lockscreen_glogin_invalid_input">"Μη έγκυÏο όνομα χÏήστη ή κωδικός Ï€Ïόσβασης."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Δεν υπάÏχουν ειδοποιήσεις"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Εν εξελίξει"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ειδοποιήσεις"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"ΦόÏτιση..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Συνδέστε τον φοÏτιστή"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Η στάθμη της μπαταÏίας είναι χαμηλή:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"απομένουν λιγότεÏο από <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="status_bar_no_notifications_title">"Δεν υπάÏχουν ειδοποιήσεις"</string>
+ <string name="status_bar_ongoing_events_title">"Εν εξελίξει"</string>
+ <string name="status_bar_latest_events_title">"Ειδοποιήσεις"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"ΦόÏτιση..."</string>
+ <string name="battery_low_title">"Συνδέστε τον φοÏτιστή"</string>
+ <string name="battery_low_subtitle">"Η στάθμη της μπαταÏίας είναι χαμηλή:"</string>
+ <string name="battery_low_percent_format">"απομένουν λιγότεÏο από <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Η εÏγοστασιακή δοκιμή απέτυχε"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Η ενέÏγεια FACTORY_TEST υποστηÏίζεται μόνο για πακέτα που είναι εγκατεστημένα στον κατάλογο /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Δεν βÏέθηκε πακέτο που να παÏέχει την ενέÏγεια FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Επανεκκίνηση"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Η σελίδα στο \'<xliff:g id="TITLE">%s</xliff:g>\' λέει:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"ΑπομάκÏυνση από αυτή τη σελίδα;"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Επιλέξτε OK για συνέχεια, ή ΑκÏÏωση για παÏαμονή στην Ï„Ïέχουσα σελίδα."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Επιβεβαίωση"</string>
+ <string name="factorytest_failed">"Η εÏγοστασιακή δοκιμή απέτυχε"</string>
+ <string name="factorytest_not_system">"Η ενέÏγεια FACTORY_TEST υποστηÏίζεται μόνο για πακέτα που είναι εγκατεστημένα στον κατάλογο /system/app."</string>
+ <string name="factorytest_no_action">"Δεν βÏέθηκε πακέτο που να παÏέχει την ενέÏγεια FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Επανεκκίνηση"</string>
+ <string name="js_dialog_title">"Η σελίδα στο \'<xliff:g id="TITLE">%s</xliff:g>\' λέει:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"ΑπομάκÏυνση από αυτή τη σελίδα;"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Επιλέξτε OK για συνέχεια, ή ΑκÏÏωση για παÏαμονή στην Ï„Ïέχουσα σελίδα."</string>
+ <string name="save_password_label">"Επιβεβαίωση"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Θέλετε το Ï€ÏόγÏαμμα πεÏιήγησης να διατηÏήσει αυτόν τον κωδικό Ï€Ïόσβασης;"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Îα μην γίνει Ï„ÏŽÏα"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"ΔιατήÏηση"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Ποτέ"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Δεν έχετε άδεια για να ανοίξετε αυτή τη σελίδα."</string>
- <string name="text_copied" msgid="4985729524670131385">"Το κείμενο αντιγÏάφηκε στο Ï€ÏόχειÏο."</string>
- <string name="more_item_label" msgid="4650918923083320495">"ΠεÏισσότεÏα"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"ΠλήκτÏο Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"διάστημα"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"εισαγωγή"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"διαγÏαφή"</string>
- <string name="search_go" msgid="8298016669822141719">"Αναζήτηση"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"Ï€Ïιν από 1 μήνα"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ΠαλαιότεÏα από 1 μήνα"</string>
+ <string name="save_password_message">"Θέλετε το Ï€ÏόγÏαμμα πεÏιήγησης να διατηÏήσει αυτόν τον κωδικό Ï€Ïόσβασης;"</string>
+ <string name="save_password_notnow">"Îα μην γίνει Ï„ÏŽÏα"</string>
+ <string name="save_password_remember">"ΔιατήÏηση"</string>
+ <string name="save_password_never">"Ποτέ"</string>
+ <string name="open_permission_deny">"Δεν έχετε άδεια για να ανοίξετε αυτή τη σελίδα."</string>
+ <string name="text_copied">"Το κείμενο αντιγÏάφηκε στο Ï€ÏόχειÏο."</string>
+ <string name="more_item_label">"ΠεÏισσότεÏα"</string>
+ <string name="prepend_shortcut_label">"ΠλήκτÏο Menu+"</string>
+ <string name="menu_space_shortcut_label">"διάστημα"</string>
+ <string name="menu_enter_shortcut_label">"εισαγωγή"</string>
+ <string name="menu_delete_shortcut_label">"διαγÏαφή"</string>
+ <string name="search_go">"Αναζήτηση"</string>
+ <string name="oneMonthDurationPast">"Ï€Ïιν από 1 μήνα"</string>
+ <string name="beforeOneMonthDurationPast">"ΠαλαιότεÏα από 1 μήνα"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Ï€Ïιν από 1 δευτεÏόλεπτο"</item>
- <item quantity="other" msgid="3903706804349556379">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> δευτεÏόλεπτα"</item>
+ <item quantity="one">"Ï€Ïιν από 1 δευτεÏόλεπτο"</item>
+ <item quantity="other">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> δευτεÏόλεπτα"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Ï€Ïιν από 1 λεπτό"</item>
- <item quantity="other" msgid="2176942008915455116">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
+ <item quantity="one">"Ï€Ïιν από 1 λεπτό"</item>
+ <item quantity="other">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Ï€Ïιν από 1 ÏŽÏα"</item>
- <item quantity="other" msgid="2467273239587587569">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> ÏŽÏες"</item>
+ <item quantity="one">"Ï€Ïιν από 1 ÏŽÏα"</item>
+ <item quantity="other">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> ÏŽÏες"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"χθες"</item>
- <item quantity="other" msgid="2479586466153314633">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> ημέÏες"</item>
+ <item quantity="one">"χθες"</item>
+ <item quantity="other">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> ημέÏες"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"σε 1 δευτεÏόλεπτο"</item>
- <item quantity="other" msgid="1241926116443974687">"σε <xliff:g id="COUNT">%d</xliff:g> δευτεÏόλεπτα"</item>
+ <item quantity="one">"σε 1 δευτεÏόλεπτο"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> δευτεÏόλεπτα"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"σε 1 λεπτό"</item>
- <item quantity="other" msgid="3330713936399448749">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
+ <item quantity="one">"σε 1 λεπτό"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"σε 1 ÏŽÏα"</item>
- <item quantity="other" msgid="547290677353727389">"σε <xliff:g id="COUNT">%d</xliff:g> ÏŽÏες"</item>
+ <item quantity="one">"σε 1 ÏŽÏα"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> ÏŽÏες"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"αÏÏιο"</item>
- <item quantity="other" msgid="5109449375100953247">"σε <xliff:g id="COUNT">%d</xliff:g> ημέÏες"</item>
+ <item quantity="one">"αÏÏιο"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> ημέÏες"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Ï€Ïιν από 1 δευτεÏόλεπτο"</item>
- <item quantity="other" msgid="3699169366650930415">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> δευτεÏόλεπτα"</item>
+ <item quantity="one">"Ï€Ïιν από 1 δευτεÏόλεπτο"</item>
+ <item quantity="other">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> δευτεÏόλεπτα"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"Ï€Ïιν από 1 λεπτό"</item>
- <item quantity="other" msgid="851164968597150710">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
+ <item quantity="one">"Ï€Ïιν από 1 λεπτό"</item>
+ <item quantity="other">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Ï€Ïιν από 1 ÏŽÏα"</item>
- <item quantity="other" msgid="6889970745748538901">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> ÏŽÏες"</item>
+ <item quantity="one">"Ï€Ïιν από 1 ÏŽÏα"</item>
+ <item quantity="other">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> ÏŽÏες"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"χθες"</item>
- <item quantity="other" msgid="3453342639616481191">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> ημέÏες"</item>
+ <item quantity="one">"χθες"</item>
+ <item quantity="other">"Ï€Ïιν από <xliff:g id="COUNT">%d</xliff:g> ημέÏες"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"σε 1 δευτεÏόλεπτο"</item>
- <item quantity="other" msgid="5495880108825805108">"σε <xliff:g id="COUNT">%d</xliff:g> δευτεÏόλεπτα"</item>
+ <item quantity="one">"σε 1 δευτεÏόλεπτο"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> δευτεÏόλεπτα"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"σε 1 λεπτό"</item>
- <item quantity="other" msgid="4216113292706568726">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
+ <item quantity="one">"σε 1 λεπτό"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"σε 1 ÏŽÏα"</item>
- <item quantity="other" msgid="3705373766798013406">"σε <xliff:g id="COUNT">%d</xliff:g> ÏŽÏες"</item>
+ <item quantity="one">"σε 1 ÏŽÏα"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> ÏŽÏες"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"αÏÏιο"</item>
- <item quantity="other" msgid="2973062968038355991">"σε <xliff:g id="COUNT">%d</xliff:g> ημέÏες"</item>
+ <item quantity="one">"αÏÏιο"</item>
+ <item quantity="other">"σε <xliff:g id="COUNT">%d</xliff:g> ημέÏες"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"σε %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"στο %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"σε %s"</string>
- <string name="day" msgid="8144195776058119424">"ημέÏα"</string>
- <string name="days" msgid="4774547661021344602">"ημέÏες"</string>
- <string name="hour" msgid="2126771916426189481">"ÏŽÏα"</string>
- <string name="hours" msgid="894424005266852993">"ÏŽÏες"</string>
- <string name="minute" msgid="9148878657703769868">"λεπτά"</string>
- <string name="minutes" msgid="5646001005827034509">"λεπτά"</string>
- <string name="second" msgid="3184235808021478">"δευτεÏόλεπτο"</string>
- <string name="seconds" msgid="3161515347216589235">"δευτεÏόλεπτα"</string>
- <string name="week" msgid="5617961537173061583">"εβδομάδα"</string>
- <string name="weeks" msgid="6509623834583944518">"εβδομάδες"</string>
- <string name="year" msgid="4001118221013892076">"έτος"</string>
- <string name="years" msgid="6881577717993213522">"έτη"</string>
- <string name="every_weekday" msgid="8777593878457748503">"ΚαθημεÏινές (Δευ-ΠαÏ)"</string>
- <string name="daily" msgid="5738949095624133403">"ΚαθημεÏινά"</string>
- <string name="weekly" msgid="983428358394268344">"Κάθε εβδομάδα στο <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Μηνιαία"</string>
- <string name="yearly" msgid="1519577999407493836">"Ετήσια"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Δεν είναι δυνατή η αναπαÏαγωγή βίντεο"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Αυτό το βίντεο δεν είναι έγκυÏο για Ïοή σε αυτή τη συσκευή."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Δεν είναι δυνατή η Ï€Ïοβολή Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… βίντεο."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"μεσημέÏι"</string>
- <string name="Noon" msgid="3342127745230013127">"ΜεσημέÏι"</string>
- <string name="midnight" msgid="7166259508850457595">"μεσάνυχτα"</string>
- <string name="Midnight" msgid="5630806906897892201">"Μεσάνυχτα"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Επιλογή όλων"</string>
- <string name="selectText" msgid="3889149123626888637">"Επιλογή κειμένου"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Διακοπή επιλογής κειμένου"</string>
- <string name="cut" msgid="3092569408438626261">"Αποκοπή"</string>
- <string name="cutAll" msgid="2436383270024931639">"Αποκοπή όλων"</string>
- <string name="copy" msgid="2681946229533511987">"ΑντιγÏαφή"</string>
- <string name="copyAll" msgid="2590829068100113057">"ΑντιγÏαφή όλων"</string>
- <string name="paste" msgid="5629880836805036433">"Επικόλληση"</string>
- <string name="copyUrl" msgid="2538211579596067402">"ΑντιγÏαφή διεÏθυνσης URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Μέθοδος εισόδου"</string>
- <string name="addToDictionary" msgid="726256909274177272">"ΠÏοσθήκη \"%s\" στο λεξικό"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"ΕπεξεÏγασία κειμένου"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Απομένει λίγος ελεÏθεÏος χώÏος"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Έχει απομείνει λίγος ελεÏθεÏος αποθηκευτικός χώÏος στο τηλέφωνο."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"ΑκÏÏωση"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"ΑκÏÏωση"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"ΠÏοσοχή"</string>
- <string name="capital_on" msgid="1544682755514494298">"ΕνεÏγοποιημένο"</string>
- <string name="capital_off" msgid="6815870386972805832">"ΑπενεÏγοποίηση"</string>
- <string name="whichApplication" msgid="4533185947064773386">"ΟλοκλήÏωση ενέÏγειας με τη χÏήση"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"ΧÏήση από Ï€Ïοεπιλογή για αυτήν την ενέÏγεια."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"ΕκκαθάÏιση Ï€Ïοεπιλεγμένων σε Ρυθμίσεις αÏχικής σελίδας &gt; ΕφαÏμογές &gt; ΔιαχείÏιση εφαÏμογών."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Επιλέξτε μια ενέÏγεια"</string>
- <string name="noApplications" msgid="1691104391758345586">"Δεν υπάÏχουν εφαÏμογές, οι οποίες μποÏοÏν να εκτελέσουν αυτήν την ενέÏγεια."</string>
- <string name="aerr_title" msgid="653922989522758100">"ΛυποÏμαστε!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"ΥπήÏξε μη αναμενόμενη διακοπή της εφαÏμογής <xliff:g id="APPLICATION">%1$s</xliff:g> (διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>). ΠÏοσπαθήστε ξανά."</string>
- <string name="aerr_process" msgid="1551785535966089511">"ΥπήÏξε μη αναμενόμενη διακοπή της διαδικασίας <xliff:g id="PROCESS">%1$s</xliff:g>. ΠÏοσπαθήστε αÏγότεÏα."</string>
- <string name="anr_title" msgid="3100070910664756057">"ΛυποÏμαστε!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Η δÏαστηÏιότητα <xliff:g id="ACTIVITY">%1$s</xliff:g> (στην εφαÏμογή <xliff:g id="APPLICATION">%2$s</xliff:g>) δεν αποκÏίνεται."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Η δÏαστηÏιότητα <xliff:g id="ACTIVITY">%1$s</xliff:g> (στη διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>) δεν αποκÏίνεται."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Η εφαÏμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (στη διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>) δεν αποκÏίνεται."</string>
- <string name="anr_process" msgid="1246866008169975783">"Η διαδικασία <xliff:g id="PROCESS">%1$s</xliff:g> δεν αποκÏίνεται."</string>
- <string name="force_close" msgid="3653416315450806396">"Αναγκαστικό κλείσιμο"</string>
+ <string name="preposition_for_date">"σε %s"</string>
+ <string name="preposition_for_time">"στο %s"</string>
+ <string name="preposition_for_year">"σε %s"</string>
+ <string name="day">"ημέÏα"</string>
+ <string name="days">"ημέÏες"</string>
+ <string name="hour">"ÏŽÏα"</string>
+ <string name="hours">"ÏŽÏες"</string>
+ <string name="minute">"λεπτά"</string>
+ <string name="minutes">"λεπτά"</string>
+ <string name="second">"δευτεÏόλεπτο"</string>
+ <string name="seconds">"δευτεÏόλεπτα"</string>
+ <string name="week">"εβδομάδα"</string>
+ <string name="weeks">"εβδομάδες"</string>
+ <string name="year">"έτος"</string>
+ <string name="years">"έτη"</string>
+ <string name="every_weekday">"ΚαθημεÏινές (Δευ-ΠαÏ)"</string>
+ <string name="daily">"ΚαθημεÏινά"</string>
+ <string name="weekly">"Κάθε εβδομάδα στο <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Μηνιαία"</string>
+ <string name="yearly">"Ετήσια"</string>
+ <string name="VideoView_error_title">"Δεν είναι δυνατή η αναπαÏαγωγή βίντεο"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Αυτό το βίντεο δεν είναι έγκυÏο για Ïοή σε αυτή τη συσκευή."</string>
+ <string name="VideoView_error_text_unknown">"Δεν είναι δυνατή η Ï€Ïοβολή Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… βίντεο."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"μεσημέÏι"</string>
+ <string name="Noon">"ΜεσημέÏι"</string>
+ <string name="midnight">"μεσάνυχτα"</string>
+ <string name="Midnight">"Μεσάνυχτα"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Επιλογή όλων"</string>
+ <string name="selectText">"Επιλογή κειμένου"</string>
+ <string name="stopSelectingText">"Διακοπή επιλογής κειμένου"</string>
+ <string name="cut">"Αποκοπή"</string>
+ <string name="cutAll">"Αποκοπή όλων"</string>
+ <string name="copy">"ΑντιγÏαφή"</string>
+ <string name="copyAll">"ΑντιγÏαφή όλων"</string>
+ <string name="paste">"Επικόλληση"</string>
+ <string name="copyUrl">"ΑντιγÏαφή διεÏθυνσης URL"</string>
+ <string name="inputMethod">"Μέθοδος εισόδου"</string>
+ <string name="addToDictionary">"ΠÏοσθήκη \"%s\" στο λεξικό"</string>
+ <string name="editTextMenuTitle">"ΕπεξεÏγασία κειμένου"</string>
+ <string name="low_internal_storage_view_title">"Απομένει λίγος ελεÏθεÏος χώÏος"</string>
+ <string name="low_internal_storage_view_text">"Έχει απομείνει λίγος ελεÏθεÏος αποθηκευτικός χώÏος στο τηλέφωνο."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"ΑκÏÏωση"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"ΑκÏÏωση"</string>
+ <string name="dialog_alert_title">"ΠÏοσοχή"</string>
+ <string name="capital_on">"ΕνεÏγοποιημένο"</string>
+ <string name="capital_off">"ΑπενεÏγοποίηση"</string>
+ <string name="whichApplication">"ΟλοκλήÏωση ενέÏγειας με τη χÏήση"</string>
+ <string name="alwaysUse">"ΧÏήση από Ï€Ïοεπιλογή για αυτήν την ενέÏγεια."</string>
+ <string name="clearDefaultHintMsg">"ΕκκαθάÏιση Ï€Ïοεπιλεγμένων σε Ρυθμίσεις αÏχικής σελίδας &gt; ΕφαÏμογές &gt; ΔιαχείÏιση εφαÏμογών."</string>
+ <string name="chooseActivity">"Επιλέξτε μια ενέÏγεια"</string>
+ <string name="noApplications">"Δεν υπάÏχουν εφαÏμογές, οι οποίες μποÏοÏν να εκτελέσουν αυτήν την ενέÏγεια."</string>
+ <string name="aerr_title">"ΛυποÏμαστε!"</string>
+ <string name="aerr_application">"ΥπήÏξε μη αναμενόμενη διακοπή της εφαÏμογής <xliff:g id="APPLICATION">%1$s</xliff:g> (διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>). ΠÏοσπαθήστε ξανά."</string>
+ <string name="aerr_process">"ΥπήÏξε μη αναμενόμενη διακοπή της διαδικασίας <xliff:g id="PROCESS">%1$s</xliff:g>. ΠÏοσπαθήστε αÏγότεÏα."</string>
+ <string name="anr_title">"ΛυποÏμαστε!"</string>
+ <string name="anr_activity_application">"Η δÏαστηÏιότητα <xliff:g id="ACTIVITY">%1$s</xliff:g> (στην εφαÏμογή <xliff:g id="APPLICATION">%2$s</xliff:g>) δεν αποκÏίνεται."</string>
+ <string name="anr_activity_process">"Η δÏαστηÏιότητα <xliff:g id="ACTIVITY">%1$s</xliff:g> (στη διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>) δεν αποκÏίνεται."</string>
+ <string name="anr_application_process">"Η εφαÏμογή <xliff:g id="APPLICATION">%1$s</xliff:g> (στη διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>) δεν αποκÏίνεται."</string>
+ <string name="anr_process">"Η διαδικασία <xliff:g id="PROCESS">%1$s</xliff:g> δεν αποκÏίνεται."</string>
+ <string name="force_close">"Αναγκαστικό κλείσιμο"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Αναμονή"</string>
- <string name="debug" msgid="9103374629678531849">"Εντοπισμός σφαλμάτων"</string>
- <string name="sendText" msgid="5132506121645618310">"Επιλέξτε μια ενέÏγεια για το κείμενο"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Ένταση ειδοποίησης ήχου"</string>
- <string name="volume_music" msgid="5421651157138628171">"Ένταση ήχου πολυμέσων"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"ΑναπαÏαγωγή μέσω Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Ένταση ήχου κλήσης"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Ένταση ήχου για εισεÏχόμενη κληση μέσω Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Ένταση ήχου ξυπνητηÏιοÏ"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Ένταση ήχου ειδοποίησης"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Ένταση ήχου"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"ΠÏοεπιλεγμένος ήχος κλήσης"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ΠÏοεπιλεγμένος ήχος κλήσης (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Σίγαση"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Ήχοι κλήσης"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Άγνωστος ήχος κλήσης"</string>
+ <string name="wait">"Αναμονή"</string>
+ <string name="debug">"Εντοπισμός σφαλμάτων"</string>
+ <string name="sendText">"Επιλέξτε μια ενέÏγεια για το κείμενο"</string>
+ <string name="volume_ringtone">"Ένταση ειδοποίησης ήχου"</string>
+ <string name="volume_music">"Ένταση ήχου πολυμέσων"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"ΑναπαÏαγωγή μέσω Bluetooth"</string>
+ <string name="volume_call">"Ένταση ήχου κλήσης"</string>
+ <string name="volume_bluetooth_call">"Ένταση ήχου για εισεÏχόμενη κληση μέσω Bluetooth"</string>
+ <string name="volume_alarm">"Ένταση ήχου ξυπνητηÏιοÏ"</string>
+ <string name="volume_notification">"Ένταση ήχου ειδοποίησης"</string>
+ <string name="volume_unknown">"Ένταση ήχου"</string>
+ <string name="ringtone_default">"ΠÏοεπιλεγμένος ήχος κλήσης"</string>
+ <string name="ringtone_default_with_actual">"ΠÏοεπιλεγμένος ήχος κλήσης (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Σίγαση"</string>
+ <string name="ringtone_picker_title">"Ήχοι κλήσης"</string>
+ <string name="ringtone_unknown">"Άγνωστος ήχος κλήσης"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"ΥπάÏχει διαθέσιμο δίκτυο Wi-Fi"</item>
- <item quantity="other" msgid="4192424489168397386">"ΥπάÏχουν διαθέσιμα δίκτυα Wi-Fi"</item>
+ <item quantity="one">"ΥπάÏχει διαθέσιμο δίκτυο Wi-Fi"</item>
+ <item quantity="other">"ΥπάÏχουν διαθέσιμα δίκτυα Wi-Fi"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"ΥπάÏχει διαθέσιμο ανοικτό δίκτυο Wi-Fi"</item>
- <item quantity="other" msgid="7915895323644292768">"ΥπάÏχουν διαθέσιμα ανοικτά δίκτυα Wi-Fi"</item>
+ <item quantity="one">"ΥπάÏχει διαθέσιμο ανοικτό δίκτυο Wi-Fi"</item>
+ <item quantity="other">"ΥπάÏχουν διαθέσιμα ανοικτά δίκτυα Wi-Fi"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Εισαγωγή χαÏακτήÏα"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Άγνωστη εφαÏμογή"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Αποστολή μηνυμάτων SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Αποστέλλεται μεγάλος αÏιθμός μηνυμάτων SMS. Επιλέξτε \"OK\" για συνέχεια, ή \"ΑκÏÏωση\" για διακοπή αποστολής."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"ΑκÏÏωση"</string>
- <string name="date_time_set" msgid="5777075614321087758">"ΟÏισμός"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"ΠÏοεπιλεγμένο"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Δεν απαιτοÏνται άδειες"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"ΑπόκÏυψη"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Εμφάνιση όλων"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"ΦόÏτωση..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Το USB είναι συνδεδεμένο"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Συνδέσατε το τηλέφωνό σας στον υπολογιστή μέσω USB. Επιλέξτε \"ΠÏοσάÏτηση\" αν θέλετε να αντιγÏάψετε αÏχεία Î¼ÎµÏ„Î±Î¾Ï Ï„Î¿Ï… υπολογιστή και της κάÏτας SD του τηλεφώνου."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"ΠÏοσάÏτηση"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Îα μην γίνει Ï€ÏοσάÏτηση"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"ΠαÏουσιάστηκε ένα Ï€Ïόβλημα στη χÏήση της κάÏτας SD ως αποθηκευτικό χώÏο USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Το USB είναι συνδεδεμένο"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Επιλέξτε για αντιγÏαφή Ï€Ïος/από τον υπολογιστή σας."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"ΑπενεÏγοποίηση Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Επιλογή για απενεÏγοποίηση Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"ΑπενεÏγοποίηση Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"ΠÏιν από την απενεÏγοποίηση του Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου USB, βεβαιωθείτε ότι έχετε αποπÏοσαÏτήσει την υποδοχή USB. Επιλέξτε \"ΑπενεÏγοποίηση\" για να απενεÏγοποιήσετε τον αποθηκευτικό χώÏο USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"ΑπενεÏγοποίηση"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"ΑκÏÏωση"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"ΠαÏουσιάστηκε ένα Ï€Ïόβλημα κατά την απενεÏγοποίηση του Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου USB. Βεβαιωθείτε ότι έχετε αποπÏοσαÏτήσει την υποδοχή USB και Ï€Ïοσπαθήστε ξανά."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"ΔιαμόÏφωση κάÏτας SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Είστε βέβαιοι ότι θέλετε να διαμοÏφώσετε την κάÏτα SD; Όλα τα δεδομένα στην κάÏτα σας θα χαθοÏν."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"ΔιαμόÏφωση"</string>
+ <string name="select_character">"Εισαγωγή χαÏακτήÏα"</string>
+ <string name="sms_control_default_app_name">"Άγνωστη εφαÏμογή"</string>
+ <string name="sms_control_title">"Αποστολή μηνυμάτων SMS"</string>
+ <string name="sms_control_message">"Αποστέλλεται μεγάλος αÏιθμός μηνυμάτων SMS. Επιλέξτε \"OK\" για συνέχεια, ή \"ΑκÏÏωση\" για διακοπή αποστολής."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"ΑκÏÏωση"</string>
+ <string name="date_time_set">"ΟÏισμός"</string>
+ <string name="default_permission_group">"ΠÏοεπιλεγμένο"</string>
+ <string name="no_permissions">"Δεν απαιτοÏνται άδειες"</string>
+ <string name="perms_hide"><b>"ΑπόκÏυψη"</b></string>
+ <string name="perms_show_all"><b>"Εμφάνιση όλων"</b></string>
+ <string name="googlewebcontenthelper_loading">"ΦόÏτωση..."</string>
+ <string name="usb_storage_title">"Το USB είναι συνδεδεμένο"</string>
+ <string name="usb_storage_message">"Συνδέσατε το τηλέφωνό σας στον υπολογιστή μέσω USB. Επιλέξτε \"ΠÏοσάÏτηση\" αν θέλετε να αντιγÏάψετε αÏχεία Î¼ÎµÏ„Î±Î¾Ï Ï„Î¿Ï… υπολογιστή και της κάÏτας SD του τηλεφώνου."</string>
+ <string name="usb_storage_button_mount">"ΠÏοσάÏτηση"</string>
+ <string name="usb_storage_button_unmount">"Îα μην γίνει Ï€ÏοσάÏτηση"</string>
+ <string name="usb_storage_error_message">"ΠαÏουσιάστηκε ένα Ï€Ïόβλημα στη χÏήση της κάÏτας SD ως αποθηκευτικό χώÏο USB."</string>
+ <string name="usb_storage_notification_title">"Το USB είναι συνδεδεμένο"</string>
+ <string name="usb_storage_notification_message">"Επιλέξτε για αντιγÏαφή Ï€Ïος/από τον υπολογιστή σας."</string>
+ <string name="usb_storage_stop_notification_title">"ΑπενεÏγοποίηση Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου USB"</string>
+ <string name="usb_storage_stop_notification_message">"Επιλογή για απενεÏγοποίηση Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου USB."</string>
+ <string name="usb_storage_stop_title">"ΑπενεÏγοποίηση Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου USB"</string>
+ <string name="usb_storage_stop_message">"ΠÏιν από την απενεÏγοποίηση του Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου USB, βεβαιωθείτε ότι έχετε αποπÏοσαÏτήσει την υποδοχή USB. Επιλέξτε \"ΑπενεÏγοποίηση\" για να απενεÏγοποιήσετε τον αποθηκευτικό χώÏο USB."</string>
+ <string name="usb_storage_stop_button_mount">"ΑπενεÏγοποίηση"</string>
+ <string name="usb_storage_stop_button_unmount">"ΑκÏÏωση"</string>
+ <string name="usb_storage_stop_error_message">"ΠαÏουσιάστηκε ένα Ï€Ïόβλημα κατά την απενεÏγοποίηση του Î±Ï€Î¿Î¸Î·ÎºÎµÏ…Ï„Î¹ÎºÎ¿Ï Ï‡ÏŽÏου USB. Βεβαιωθείτε ότι έχετε αποπÏοσαÏτήσει την υποδοχή USB και Ï€Ïοσπαθήστε ξανά."</string>
+ <string name="extmedia_format_title">"ΔιαμόÏφωση κάÏτας SD"</string>
+ <string name="extmedia_format_message">"Είστε βέβαιοι ότι θέλετε να διαμοÏφώσετε την κάÏτα SD; Όλα τα δεδομένα στην κάÏτα σας θα χαθοÏν."</string>
+ <string name="extmedia_format_button_format">"ΔιαμόÏφωση"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Επιλογή μεθόδου εισόδου"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"ΠÏοετοιμασία κάÏτας SD"</string>
+ <string name="select_input_method">"Επιλογή μεθόδου εισόδου"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"υποψήφιοι"</u></string>
+ <string name="ext_media_checking_notification_title">"ΠÏοετοιμασία κάÏτας SD"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Κενή κάÏτα SD"</string>
+ <string name="ext_media_nofs_notification_title">"Κενή κάÏτα SD"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"ΚατεστÏαμμένη κάÏτα SD"</string>
+ <string name="ext_media_unmountable_notification_title">"ΚατεστÏαμμένη κάÏτα SD"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Μη αναμενόμενη αφαίÏεση κάÏτας SD"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"ΑποπÏοσαÏτήστε την κάÏτα SD Ï€Ïιν την αφαιÏέσετε για την αποφυγή απώλειας δεδομένων."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Η κάÏτα SD μποÏεί να αφαιÏεθεί με ασφάλεια"</string>
+ <string name="ext_media_badremoval_notification_title">"Μη αναμενόμενη αφαίÏεση κάÏτας SD"</string>
+ <string name="ext_media_badremoval_notification_message">"ΑποπÏοσαÏτήστε την κάÏτα SD Ï€Ïιν την αφαιÏέσετε για την αποφυγή απώλειας δεδομένων."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Η κάÏτα SD μποÏεί να αφαιÏεθεί με ασφάλεια"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Η κάÏτα SD αφαιÏέθηκε"</string>
+ <string name="ext_media_nomedia_notification_title">"Η κάÏτα SD αφαιÏέθηκε"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Δεν βÏέθηκαν δÏαστηÏιότητες που να αντιστοιχοÏν"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"ενημέÏωση στατιστικών χÏήσης στοιχείου"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"ΕπιτÏέπει την Ï„Ïοποποίηση στατιστικών χÏήσης στοιχείων που έχουν συλλεχθεί. Δεν Ï€Ïέπει να χÏησιμοποιείται από κανονικές εφαÏμογές."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Πατήστε δÏο φοÏές για έλεγχο εστίασης"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Σφάλμα αÏξησης μεγέθους γÏÎ±Ï†Î¹ÎºÎ¿Ï ÏƒÏ„Î¿Î¹Ï‡ÎµÎ¯Î¿Ï…"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Μετάβαση"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Αναζήτηση"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Αποστολή"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Επόμενο"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Τέλος"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Εκτέλεση"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Κλήση αÏιθμοÏ"\n"με τη χÏήση <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"ΔημιουÏγία επαφής"\n"με τη χÏήση του <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Δεν βÏέθηκαν δÏαστηÏιότητες που να αντιστοιχοÏν"</string>
+ <string name="permlab_pkgUsageStats">"ενημέÏωση στατιστικών χÏήσης στοιχείου"</string>
+ <string name="permdesc_pkgUsageStats">"ΕπιτÏέπει την Ï„Ïοποποίηση στατιστικών χÏήσης στοιχείων που έχουν συλλεχθεί. Δεν Ï€Ïέπει να χÏησιμοποιείται από κανονικές εφαÏμογές."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Πατήστε δÏο φοÏές για έλεγχο εστίασης"</string>
+ <string name="gadget_host_error_inflating">"Σφάλμα αÏξησης μεγέθους γÏÎ±Ï†Î¹ÎºÎ¿Ï ÏƒÏ„Î¿Î¹Ï‡ÎµÎ¯Î¿Ï…"</string>
+ <string name="ime_action_go">"Μετάβαση"</string>
+ <string name="ime_action_search">"Αναζήτηση"</string>
+ <string name="ime_action_send">"Αποστολή"</string>
+ <string name="ime_action_next">"Επόμενο"</string>
+ <string name="ime_action_done">"ΟλοκληÏώθηκε"</string>
+ <string name="ime_action_default">"Εκτέλεση"</string>
+ <string name="dial_number_using">"Κλήση αÏιθμοÏ"\n"με τη χÏήση <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"ΔημιουÏγία επαφής"\n"με τη χÏήση του <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-en-rUS/donottranslate-names.xml b/core/res/res/values-en-rUS/donottranslate-names.xml
new file mode 100644
index 0000000..42c8ab4
--- /dev/null
+++ b/core/res/res/values-en-rUS/donottranslate-names.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- various string resources for Contacts -->
+ <string-array name="common_nicknames">
+ <item>Albert, Al, Bert, Bertie</item>
+ <item>Alexander, Al, Alex, Lex, Sasha</item>
+ <item>Alexandra, Al, Alex, Allie, Ally, Lex, Lexie, Sandra, Sandy, Sasha</item>
+ <item>Alice, Allie, Ally</item>
+ <item>Alison, Allie, Ally</item>
+ <item>Allison, Allie, Ally</item>
+ <item>Amanda, Mandi, Mandy</item>
+ <item>Andrea, Andie</item>
+ <item>Andrew, Andy, Drew</item>
+ <item>Anthony, Tony, Toni, Tone</item>
+ <item>Arthur, Art, Arty</item>
+ <item>Barbara, Babs, Barb, Barbie</item>
+ <item>Benjamin, Ben, Benji, Benny</item>
+ <item>Bernard, Bern, Bernie</item>
+ <item>Bertram, Bert, Bertie</item>
+ <item>Bradly, Brad</item>
+ <item>Catherine, Cat, Cate, Cath, Catie, Cathy, Kat, Kate, Katie, Kathy</item>
+ <item>Charles, Chuck, Chaz, Charlie, Buck</item>
+ <item>Christine, Chris, Chrissy, Chrissie</item>
+ <item>Christopher, Chris</item>
+ <item>Cynthia, Cindy, Cynth</item>
+ <item>Daniel, Dan, Danny</item>
+ <item>David, Dave</item>
+ <item>Deborah, Deb, Debbie</item>
+ <item>Dennis, Den, Denny, Dean</item>
+ <item>Dolores, Dolly</item>
+ <item>Donald, Don, Donny</item>
+ <item>Donnatella, Donna</item>
+ <item>Dorothea, Dot, Dotty</item>
+ <item>Dorothy, Dot, Dotty</item>
+ <item>Douglas, Doug</item>
+ <item>Edward, Ed, Eddie, Ned, Neddie, Neddy, Ted, Teddy, Teddie</item>
+ <item>Eleanor, Ella, Ellie, Elle</item>
+ <item>Elisabetta, Betta</item>
+ <item>Elizabeth, Beth, Bess, Bessie, Betsy, Betty, Bette, Eliza, Lisa, Liza, Liz</item>
+ <item>Emily, Em, Ems, Emmy</item>
+ <item>Emma, Em, Ems, Emmy</item>
+ <item>Erica, Rikki, Rikkie, Ricky</item>
+ <item>Eugene, Gene</item>
+ <item>Florence, Flo</item>
+ <item>Frances, Fran, Francie</item>
+ <item>Francis, Fran, Frank</item>
+ <item>Frederick, Fred, Freddy</item>
+ <item>Gabriel, Gabe</item>
+ <item>Geoffrey, Jeff</item>
+ <item>Gerald, Gerry</item>
+ <item>Gerard, Gerry</item>
+ <item>Gregory, Greg</item>
+ <item>Harold, Hal, Hank, Harry</item>
+ <item>Henry, Hal, Hank, Harry</item>
+ <item>Herbert, Bert, Bertie</item>
+ <item>Irving, Irv</item>
+ <item>Isabella, Isa, Izzy</item>
+ <item>Jacob, Jake</item>
+ <item>Jacqueline, Jackie</item>
+ <item>James, Jim, Jimmy, Jamie, Jock</item>
+ <item>Janet, Jan</item>
+ <item>Janice, Jan</item>
+ <item>Jason, Jay</item>
+ <item>Jefferson, Jeff</item>
+ <item>Jeffrey, Jeff</item>
+ <item>Jennifer, Jen, Jenny</item>
+ <item>Jerome, Jerry</item>
+ <item>Jessica, Jessie</item>
+ <item>John, Jack, Jacky, Johnny, Jon</item>
+ <item>Jonathan, Jon, John</item>
+ <item>Joseph, Joe, Joey</item>
+ <item>Joshua, Josh</item>
+ <item>Kaitlyn, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+ <item>Katherine, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+ <item>Kathleen, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+ <item>Katrina, Cat, Cate, Catie, Cath, Cathy, Kat, Kate, Katie, Kathy</item>
+ <item>Kenneth, Ken</item>
+ <item>Kevin, Kev</item>
+ <item>Laura, Lauri, Laurie</item>
+ <item>Lauren, Lauri, Laurie</item>
+ <item>Laurence, Larry, Lauri, Laurie</item>
+ <item>Lawrence, Larry, Lauri, Laurie</item>
+ <item>Leonard, Leo, Len, Lenny</item>
+ <item>Leopold, Leo, Len, Lenny</item>
+ <item>Madeline, Maddie, Maddy</item>
+ <item>Margaret, Marge, Marg, Maggie, Mags, Meg, Peggy</item>
+ <item>Matthew, Matt, Mattie</item>
+ <item>Maureen, Mo</item>
+ <item>Maurice, Mo</item>
+ <item>Megan, Meg</item>
+ <item>Michael, Mickey, Mick, Mike, Mikey</item>
+ <item>Morris, Mo</item>
+ <item>Nancy, Nan</item>
+ <item>Nathan, Nat, Nate</item>
+ <item>Nathaniel, Nat, Nate</item>
+ <item>Nicholas, Nick</item>
+ <item>Pamela, Pam</item>
+ <item>Patricia, Pat, Patsy, Patty, Trish, Tricia</item>
+ <item>Patrick, Paddy, Pat, Patty, Patter, Rick, Ricky</item>
+ <item>Peter, Pete</item>
+ <item>Raymond, Ray</item>
+ <item>Philip, Phil</item>
+ <item>Rebecca, Becca</item>
+ <item>Richard, Rick, Rich, Dick</item>
+ <item>Robert, Bob, Rob, Robbie, Bobby, Rab</item>
+ <item>Roberta, Bobbie</item>
+ <item>Rodney. Rod</item>
+ <item>Ronald, Ron, Ronnie</item>
+ <item>Rosemary, Rosie, Rose</item>
+ <item>Russell, Russ, Rusty</item>
+ <item>Ryan, Ry</item>
+ <item>Samantha, Sam</item>
+ <item>Samuel, Sam, Sammy</item>
+ <item>Sophia, Sophie</item>
+ <item>Stephanie, Steph, Stephie</item>
+ <item>Stephen, Steve</item>
+ <item>Steven, Steve</item>
+ <item>Stuart, Stu</item>
+ <item>Susan, Sue, Susie, Suzie</item>
+ <item>Suzanne, Sue, Susie, Suzie</item>
+ <item>Teresa, Terrie, Terry</item>
+ <item>Theodora, Teddie, Thea, Theo</item>
+ <item>Theodore, Ted, Teddy, Theo</item>
+ <item>Thomas, Tom, Thom, Tommy</item>
+ <item>Timothy, Tim, Timmy</item>
+ <item>Valerie, Val</item>
+ <item>Veronica, Ronnie, Roni, Nica, Nikki, Nikka</item>
+ <item>Victor, Vic</item>
+ <item>Victoria, Vicky, Vicki, Vickie, Tori</item>
+ <item>Vincent, Vince, Vin, Vinnie</item>
+ <item>Vivian, Vivi</item>
+ <item>Walter, Walt, Wally</item>
+ <item>Wendy, Wen, Wendel</item>
+ <item>William, Bill, Billy, Will, Willy, Liam</item>
+ <item>Yvonna, Vonna</item>
+ <item>Zachary, Zach, Zack, Zac</item>
+ </string-array>
+ <string name="common_name_prefixes">
+ 1LT, 1ST, 2LT, 2ND, 3RD, ADMIRAL, CAPT, CAPTAIN, COL, CPT, DR,
+ GEN, GENERAL, LCDR, LT, LTC, LTG, LTJG, MAJ, MAJOR, MG, MR,
+ MRS, MS, PASTOR, PROF, REP, REVEREND, REV, SEN, ST
+ </string>
+ <string name="common_name_suffixes">
+ B.A., BA, D.D.S., DDS, I, II, III, IV, IX, JR, M.A., M.D, MA,
+ MD, MS, PH.D., PHD, SR, V, VI, VII, VIII, X
+ </string>
+ <string name="common_last_name_prefixes">
+ D', DE, DEL, DI, LA, LE, MC, SAN, ST, TER, VAN, VON
+ </string>
+ <string name="common_name_conjunctions">
+ &amp;, AND, OR
+ </string>
+</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f34adcb..ee28403 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"&lt;sin título&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(No hay número de teléfono)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Desconocida)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correo de voz"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problema de conexión o código incorrecto de MMI."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Se ha activado el servicio."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Se activó el servicio para:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Se ha desactivado el servicio."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"El registro se ha realizado correctamente."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Se ha borrado correctamente."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Contraseña incorrecta."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI completa."</string>
- <string name="badPin" msgid="5085454289896032547">"El PIN anterior que escribiste no es correcto."</string>
- <string name="badPuk" msgid="5702522162746042460">"La PUK que escribiste no es correcta."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Los PIN que has ingresado no coinciden."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Escribir un PIN que contenga entre 4 y 8 números."</string>
- <string name="needPuk" msgid="919668385956251611">"Tu tarjeta SIM está bloqueada con PUK. Escribe el código PUK para desbloquearla."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Escribir PUK2 para desbloquear la tarjeta SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Identificador de llamadas entrantes"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Identificador de llamadas salientes"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Desvío de llamadas"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Llamada en espera"</string>
- <string name="BaMmi" msgid="455193067926770581">"Restricción de llamadas"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Cambio de contraseña"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Cambio de PIN"</string>
+ <string name="untitled">"&lt;sin título&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(No hay número de teléfono)"</string>
+ <string name="unknownName">"(Desconocida)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Correo de voz"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problema de conexión o código incorrecto de MMI."</string>
+ <string name="serviceEnabled">"Se ha activado el servicio."</string>
+ <string name="serviceEnabledFor">"Se activó el servicio para:"</string>
+ <string name="serviceDisabled">"Se ha desactivado el servicio."</string>
+ <string name="serviceRegistered">"El registro se ha realizado correctamente."</string>
+ <string name="serviceErased">"Se ha borrado correctamente."</string>
+ <string name="passwordIncorrect">"Contraseña incorrecta."</string>
+ <string name="mmiComplete">"MMI completa."</string>
+ <string name="badPin">"El PIN anterior que escribiste no es correcto."</string>
+ <string name="badPuk">"La PUK que escribiste no es correcta."</string>
+ <string name="mismatchPin">"Los PIN que has ingresado no coinciden."</string>
+ <string name="invalidPin">"Escribir un PIN que contenga entre 4 y 8 números."</string>
+ <string name="needPuk">"Tu tarjeta SIM está bloqueada con PUK. Escribe el código PUK para desbloquearla."</string>
+ <string name="needPuk2">"Escribir PUK2 para desbloquear la tarjeta SIM."</string>
+ <string name="ClipMmi">"Identificador de llamadas entrantes"</string>
+ <string name="ClirMmi">"Identificador de llamadas salientes"</string>
+ <string name="CfMmi">"Desvío de llamadas"</string>
+ <string name="CwMmi">"Llamada en espera"</string>
+ <string name="BaMmi">"Restricción de llamadas"</string>
+ <string name="PwdMmi">"Cambio de contraseña"</string>
+ <string name="PinMmi">"Cambio de PIN"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"El identificador de llamadas está predeterminado en restringido. Llamada siguiente: restringida"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"El Identificador de llamadas está predeterminado en restringido. Llamada siguiente: no restringido"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"El identificador de llamadas está predeterminado en no restringido. Llamada siguiente: restringida"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"El Identificador de llamadas está predeterminado en no restringido. Llamada siguiente: no restringido"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Servicio no suministrado."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"La configuración del identificador de llamadas no se puede cambiar."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Se ha cambiado el acceso restringido"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"El servicio de datos está bloqueado."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"El servicio de emergencias está bloqueado."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"El servicio de voz/SMS está bloqueado."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Todos los servicios de voz/SMS están bloqueados."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voz"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Datos"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Datos asíncronos"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Sincronización"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paquete"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"El identificador de llamadas está predeterminado en restringido. Llamada siguiente: restringida"</string>
+ <string name="CLIRDefaultOnNextCallOff">"El Identificador de llamadas está predeterminado en restringido. Llamada siguiente: no restringido"</string>
+ <string name="CLIRDefaultOffNextCallOn">"El identificador de llamadas está predeterminado en no restringido. Llamada siguiente: restringida"</string>
+ <string name="CLIRDefaultOffNextCallOff">"El Identificador de llamadas está predeterminado en no restringido. Llamada siguiente: no restringido"</string>
+ <string name="serviceNotProvisioned">"Servicio no suministrado."</string>
+ <string name="CLIRPermanent">"La configuración del identificador de llamadas no se puede cambiar."</string>
+ <string name="RestrictedChangedTitle">"Se ha cambiado el acceso restringido"</string>
+ <string name="RestrictedOnData">"El servicio de datos está bloqueado."</string>
+ <string name="RestrictedOnEmergency">"El servicio de emergencias está bloqueado."</string>
+ <string name="RestrictedOnNormal">"El servicio de voz/SMS está bloqueado."</string>
+ <string name="RestrictedOnAll">"Todos los servicios de voz/SMS están bloqueados."</string>
+ <string name="serviceClassVoice">"Voz"</string>
+ <string name="serviceClassData">"Datos"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Datos asíncronos"</string>
+ <string name="serviceClassDataSync">"Sincronización"</string>
+ <string name="serviceClassPacket">"Paquete"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> después de <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> después de <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"Aceptar"</string>
- <string name="httpError" msgid="2567300624552921790">"La página web contiene un error."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"No se ha podido encontrar la URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"No se admite el programa de autenticación del sitio."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"La autenticación no se ha realizado correctamente."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"La autenticación a través del servidor proxy no se ha realizado correctamente."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"La conexión al servidor no se ha realizado correctamente."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"El servidor no envía comunicaciones. Vuelve a intentarlo más tarde."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Se ha agotado el tiempo de espera para la conexión al servidor."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"La página contiene demasiados redireccionamientos de servidor."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"No se admite el protocolo."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"No se ha podido establecer una conexión segura."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"No se ha podido abrir la página debido a que la URL es incorrecta."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"No se ha podido acceder al archivo."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"No se ha encontrado el archivo solicitado."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Sincronización"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
- <string name="low_memory" msgid="6632412458436461203">"¡El espacio de almacenamiento está completo! Elimina algunos archivos para liberar espacio."</string>
- <string name="me" msgid="6545696007631404292">"Yo"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opciones de teléfono"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Modo silencioso"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Encender el teléfono inalámbrico"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Apagar el teléfono inalámbrico"</string>
- <string name="screen_lock" msgid="799094655496098153">"Bloqueo de pantalla"</string>
- <string name="power_off" msgid="4266614107412865048">"Apagar"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Apagando…"</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Tu teléfono se apagará."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"No hay aplicaciones recientes."</string>
- <string name="global_actions" msgid="2406416831541615258">"Opciones de teléfono"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"El sonido está Apagado"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El sonido está Encendido"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Encendido"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Apagado"</string>
- <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Sistema Androide"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios que te cuestan dinero"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Admite aplicaciones que realizan actividades que te pueden costar dinero."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Lee y escribe tu SMS, mensaje de correo electrónico y otros mensajes."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Tu información personal"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Acceso directo a tus contactos y calendario guardado en el teléfono."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Tu ubicación"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Controla tu ubicación física"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicación de red"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Admite aplicaciones que acceden a varias funciones de red."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Tus cuentas de Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Acceder a las cuentas disponibles de Google."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controles de hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acceso directo al hardware en el teléfono."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Llamadas telefónicas"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Controlar, grabar y procesar llamadas telefónicas."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Herramientas del sistema"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Acceso y control de nivel más bajo del sistema."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Herramientas de desarrollo"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Las funciones sólo son necesarias para los desarrolladores de aplicaciones."</string>
+ <string name="httpErrorOk">"Aceptar"</string>
+ <string name="httpError">"La página web contiene un error."</string>
+ <string name="httpErrorLookup">"No se ha podido encontrar la URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"No se admite el programa de autenticación del sitio."</string>
+ <string name="httpErrorAuth">"La autenticación no se ha realizado correctamente."</string>
+ <string name="httpErrorProxyAuth">"La autenticación a través del servidor proxy no se ha realizado correctamente."</string>
+ <string name="httpErrorConnect">"La conexión al servidor no se ha realizado correctamente."</string>
+ <string name="httpErrorIO">"El servidor no envía comunicaciones. Vuelve a intentarlo más tarde."</string>
+ <string name="httpErrorTimeout">"Se ha agotado el tiempo de espera para la conexión al servidor."</string>
+ <string name="httpErrorRedirectLoop">"La página contiene demasiados redireccionamientos de servidor."</string>
+ <string name="httpErrorUnsupportedScheme">"No se admite el protocolo."</string>
+ <string name="httpErrorFailedSslHandshake">"No se ha podido establecer una conexión segura."</string>
+ <string name="httpErrorBadUrl">"No se ha podido abrir la página debido a que la URL es incorrecta."</string>
+ <string name="httpErrorFile">"No se ha podido acceder al archivo."</string>
+ <string name="httpErrorFileNotFound">"No se ha encontrado el archivo solicitado."</string>
+ <string name="httpErrorTooManyRequests">"Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde."</string>
+ <string name="contentServiceSync">"Sincronización"</string>
+ <string name="contentServiceSyncNotificationTitle">"Sincronización"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
+ <string name="low_memory">"¡El espacio de almacenamiento está completo! Elimina algunos archivos para liberar espacio."</string>
+ <string name="me">"Yo"</string>
+ <string name="power_dialog">"Opciones de teléfono"</string>
+ <string name="silent_mode">"Modo silencioso"</string>
+ <string name="turn_on_radio">"Encender el teléfono inalámbrico"</string>
+ <string name="turn_off_radio">"Apagar el teléfono inalámbrico"</string>
+ <string name="screen_lock">"Bloqueo de pantalla"</string>
+ <string name="power_off">"Apagar"</string>
+ <string name="shutdown_progress">"Apagando…"</string>
+ <string name="shutdown_confirm">"Tu teléfono se apagará."</string>
+ <string name="no_recent_tasks">"No hay aplicaciones recientes."</string>
+ <string name="global_actions">"Opciones de teléfono"</string>
+ <string name="global_action_lock">"Bloqueo de pantalla"</string>
+ <string name="global_action_power_off">"Apagar"</string>
+ <string name="global_action_toggle_silent_mode">"Modo silencioso"</string>
+ <string name="global_action_silent_mode_on_status">"El sonido está Apagado"</string>
+ <string name="global_action_silent_mode_off_status">"El sonido está Encendido"</string>
+ <string name="global_actions_toggle_airplane_mode">"Modo avión"</string>
+ <string name="global_actions_airplane_mode_on_status">"El modo avión está Encendido"</string>
+ <string name="global_actions_airplane_mode_off_status">"El modo avión está Apagado"</string>
+ <string name="safeMode">"Modo seguro"</string>
+ <string name="android_system_label">"Sistema Androide"</string>
+ <string name="permgrouplab_costMoney">"Servicios que te cuestan dinero"</string>
+ <string name="permgroupdesc_costMoney">"Admite aplicaciones que realizan actividades que te pueden costar dinero."</string>
+ <string name="permgrouplab_messages">"Tus mensajes"</string>
+ <string name="permgroupdesc_messages">"Lee y escribe tu SMS, mensaje de correo electrónico y otros mensajes."</string>
+ <string name="permgrouplab_personalInfo">"Tu información personal"</string>
+ <string name="permgroupdesc_personalInfo">"Acceso directo a tus contactos y calendario guardado en el teléfono."</string>
+ <string name="permgrouplab_location">"Tu ubicación"</string>
+ <string name="permgroupdesc_location">"Controla tu ubicación física"</string>
+ <string name="permgrouplab_network">"Comunicación de red"</string>
+ <string name="permgroupdesc_network">"Admite aplicaciones que acceden a varias funciones de red."</string>
+ <string name="permgrouplab_accounts">"Tus cuentas de Google"</string>
+ <string name="permgroupdesc_accounts">"Acceder a las cuentas disponibles de Google."</string>
+ <string name="permgrouplab_hardwareControls">"Controles de hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Acceso directo al hardware en el teléfono."</string>
+ <string name="permgrouplab_phoneCalls">"Llamadas telefónicas"</string>
+ <string name="permgroupdesc_phoneCalls">"Controlar, grabar y procesar llamadas telefónicas."</string>
+ <string name="permgrouplab_systemTools">"Herramientas del sistema"</string>
+ <string name="permgroupdesc_systemTools">"Acceso y control de nivel más bajo del sistema."</string>
+ <string name="permgrouplab_developmentTools">"Herramientas de desarrollo"</string>
+ <string name="permgroupdesc_developmentTools">"Las funciones sólo son necesarias para los desarrolladores de aplicaciones."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar o modificar la barra de estado"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Admite que la aplicación desactive la barra de estado, o agregue y elimine íconos del sistema."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expandir o reducir la barra de estado"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Admite que la aplicación expanda o reduzca la barra de estado."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"interceptar llamadas salientes"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Admite que la aplicación procese las llamadas salientes y cambie el número que se debe marcar. Las aplicaciones maliciosas pueden controlar, redireccionar o prevenir llamadas salientes."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"recibir SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Admite que la aplicación reciba y procese mensajes SMS. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"recibir MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Admite que la aplicación reciba y procese mensajes MMS. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"enviar mensajes SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Admite que la aplicación envíe mensajes SMS. Las aplicaciones maliciosas te pueden costar dinero si envías mensajes sin su confirmación."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"leer SMS o MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Admite que la aplicación lea los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS o MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Admite que la aplicación escriba a los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden borrar tus mensajes."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"recibir WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Admite que la aplicación reciba y procese mensajes WAP. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"recuperar aplicaciones en ejecución"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Admite que la aplicación recupere información sobre tareas en ejecución actuales y recientes. Puede permitir que las aplicaciones maliciosas descubran información privada sobre otras aplicaciones."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"reorganizar aplicaciones en ejecución"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Admite una aplicación que mueve tareas hacia el frente y el fondo. Las aplicaciones maliciosas pueden provocar su propio movimiento hacia el frente sin tu control."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"activar la depuración de la aplicación"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Admite una aplicación que activa la depuración en otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para suprimir otras aplicaciones."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar tu configuración de la interfaz de usuario"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Admite una aplicación para cambiar la configuración actual, como el tamaño de fuente local o general."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"reiniciar otras aplicaciones"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Admite una aplicación que reinicia otras aplicaciones por la fuerza."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"provocar que la aplicación se acerque"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Admite una aplicación que provoca que cualquier actividad del fondo se acerque y vuelva a alejarse. Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"recuperar el estado interno del sistema"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Admite que la aplicación recupere el estado interno del sistema. Las aplicaciones maliciosas pueden recuperar una gran variedad de información privada y segura que normalmente nunca necesitaría."</string>
+ <string name="permlab_statusBar">"desactivar o modificar la barra de estado"</string>
+ <string name="permdesc_statusBar">"Admite que la aplicación desactive la barra de estado, o agregue y elimine íconos del sistema."</string>
+ <string name="permlab_expandStatusBar">"expandir o reducir la barra de estado"</string>
+ <string name="permdesc_expandStatusBar">"Admite que la aplicación expanda o reduzca la barra de estado."</string>
+ <string name="permlab_processOutgoingCalls">"interceptar llamadas salientes"</string>
+ <string name="permdesc_processOutgoingCalls">"Admite que la aplicación procese las llamadas salientes y cambie el número que se debe marcar. Las aplicaciones maliciosas pueden controlar, redireccionar o prevenir llamadas salientes."</string>
+ <string name="permlab_receiveSms">"recibir SMS"</string>
+ <string name="permdesc_receiveSms">"Admite que la aplicación reciba y procese mensajes SMS. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
+ <string name="permlab_receiveMms">"recibir MMS"</string>
+ <string name="permdesc_receiveMms">"Admite que la aplicación reciba y procese mensajes MMS. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
+ <string name="permlab_sendSms">"enviar mensajes SMS"</string>
+ <string name="permdesc_sendSms">"Admite que la aplicación envíe mensajes SMS. Las aplicaciones maliciosas te pueden costar dinero si envías mensajes sin su confirmación."</string>
+ <string name="permlab_readSms">"leer SMS o MMS"</string>
+ <string name="permdesc_readSms">"Admite que la aplicación lea los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
+ <string name="permlab_writeSms">"editar SMS o MMS"</string>
+ <string name="permdesc_writeSms">"Admite que la aplicación escriba a los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden borrar tus mensajes."</string>
+ <string name="permlab_receiveWapPush">"recibir WAP"</string>
+ <string name="permdesc_receiveWapPush">"Admite que la aplicación reciba y procese mensajes WAP. Es posible que las aplicaciones maliciosas controlen tus mensajes o los eliminen sin mostrártelos."</string>
+ <string name="permlab_getTasks">"recuperar aplicaciones en ejecución"</string>
+ <string name="permdesc_getTasks">"Admite que la aplicación recupere información sobre tareas en ejecución actuales y recientes. Puede permitir que las aplicaciones maliciosas descubran información privada sobre otras aplicaciones."</string>
+ <string name="permlab_reorderTasks">"reorganizar aplicaciones en ejecución"</string>
+ <string name="permdesc_reorderTasks">"Admite una aplicación que mueve tareas hacia el frente y el fondo. Las aplicaciones maliciosas pueden provocar su propio movimiento hacia el frente sin tu control."</string>
+ <string name="permlab_setDebugApp">"activar la depuración de la aplicación"</string>
+ <string name="permdesc_setDebugApp">"Admite una aplicación que activa la depuración en otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para suprimir otras aplicaciones."</string>
+ <string name="permlab_changeConfiguration">"cambiar tu configuración de la interfaz de usuario"</string>
+ <string name="permdesc_changeConfiguration">"Admite una aplicación para cambiar la configuración actual, como el tamaño de fuente local o general."</string>
+ <string name="permlab_restartPackages">"reiniciar otras aplicaciones"</string>
+ <string name="permdesc_restartPackages">"Admite una aplicación que reinicia otras aplicaciones por la fuerza."</string>
+ <string name="permlab_forceBack">"provocar que la aplicación se acerque"</string>
+ <string name="permdesc_forceBack">"Admite una aplicación que provoca que cualquier actividad del fondo se acerque y vuelva a alejarse. Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <string name="permlab_dump">"recuperar el estado interno del sistema"</string>
+ <string name="permdesc_dump">"Admite que la aplicación recupere el estado interno del sistema. Las aplicaciones maliciosas pueden recuperar una gran variedad de información privada y segura que normalmente nunca necesitaría."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"verificar y controlar todos los lanzamientos de actividades"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Admite una aplicación que verifica y controla el lanzamiento de actividades por parte del sistema. Las aplicaciones maliciosas pueden comprometer totalmente al sistema. Este permiso sólo es necesario para el desarrollo, nunca para el uso normal del teléfono."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar emisión de paquete eliminado"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Admite una aplicación que emite una notificación acerca de que se ha eliminado un paquete de aplicación. Las aplicaciones maliciosas pueden utilizarlo para suprimir cualquier otra aplicación en ejecución."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"enviar emisiones de SMS recibidos"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Admite una aplicación que envía una notificación acerca de que se ha recibido un mensaje SMS. Las aplicaciones maliciosas pueden utilizarlo para falsificar los mensajes SMS entrantes."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar emisiones WAP-PUSH-recibido"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Admite una aplicación que emite una notificación acerca de que se ha recibido un mensaje WAP PUSH. Las aplicaciones maliciosas pueden utilizarlo para falsificar la recepción de mensajes MMS o para reemplazar silenciosamente el contenido de cualquier página web con variantes maliciosas."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar la cantidad de procesos en ejecución"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Admite una aplicación que controla la cantidad máxima de procesos que se ejecutarán. No se utiliza nunca en aplicaciones normales."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"cerrar todas las aplicaciones del fondo"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Admite una aplicación que controla si las actividades siempre finalizan cuando van al fondo. No se utiliza nunca en aplicaciones normales."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"modificar la estadística de la batería"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Admite la modificación de estadísticas recopiladas sobre la batería. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_runSetActivityWatcher">"verificar y controlar todos los lanzamientos de actividades"</string>
+ <string name="permdesc_runSetActivityWatcher">"Admite una aplicación que verifica y controla el lanzamiento de actividades por parte del sistema. Las aplicaciones maliciosas pueden comprometer totalmente al sistema. Este permiso sólo es necesario para el desarrollo, nunca para el uso normal del teléfono."</string>
+ <string name="permlab_broadcastPackageRemoved">"enviar emisión de paquete eliminado"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Admite una aplicación que emite una notificación acerca de que se ha eliminado un paquete de aplicación. Las aplicaciones maliciosas pueden utilizarlo para suprimir cualquier otra aplicación en ejecución."</string>
+ <string name="permlab_broadcastSmsReceived">"enviar emisiones de SMS recibidos"</string>
+ <string name="permdesc_broadcastSmsReceived">"Admite una aplicación que envía una notificación acerca de que se ha recibido un mensaje SMS. Las aplicaciones maliciosas pueden utilizarlo para falsificar los mensajes SMS entrantes."</string>
+ <string name="permlab_broadcastWapPush">"enviar emisiones WAP-PUSH-recibido"</string>
+ <string name="permdesc_broadcastWapPush">"Admite una aplicación que emite una notificación acerca de que se ha recibido un mensaje WAP PUSH. Las aplicaciones maliciosas pueden utilizarlo para falsificar la recepción de mensajes MMS o para reemplazar silenciosamente el contenido de cualquier página web con variantes maliciosas."</string>
+ <string name="permlab_setProcessLimit">"limitar la cantidad de procesos en ejecución"</string>
+ <string name="permdesc_setProcessLimit">"Admite una aplicación que controla la cantidad máxima de procesos que se ejecutarán. No se utiliza nunca en aplicaciones normales."</string>
+ <string name="permlab_setAlwaysFinish">"cerrar todas las aplicaciones del fondo"</string>
+ <string name="permdesc_setAlwaysFinish">"Admite una aplicación que controla si las actividades siempre finalizan cuando van al fondo. No se utiliza nunca en aplicaciones normales."</string>
+ <string name="permlab_batteryStats">"modificar la estadística de la batería"</string>
+ <string name="permdesc_batteryStats">"Admite la modificación de estadísticas recopiladas sobre la batería. Las aplicaciones normales no deben utilizarlo."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mostrar ventanas no autorizadas"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite la creación de ventanas que la interfaz interna del usuario del sistema pretenda utilizar. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"mostrar alertas a nivel del sistema"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Admite una aplicación que muestra ventanas de alerta del sistema. Las aplicaciones maliciosas pueden tomar el control de toda la pantalla del teléfono."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar la velocidad de la animación global"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Admite una aplicación que cambia la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"administrar tokens de aplicación"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Admite que las aplicaciones creen y administren sus propios tokens y desvíen su curva normal de llenado del espacio. Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"presionar teclas y botones de control"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Admite una aplicación que ofrece sus propios eventos de entrada (presionar teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizarlo para tomar el control del teléfono."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"grabar tu tipo y las medidas que tomes"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Admite que las aplicaciones observen las teclas que presionas, incluso al interactuar con otra aplicación (como el ingreso de una contraseña). Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a un método de entrada"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permite al propietario vincularse a la interfaz de nivel superior de un método de entrada. Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Admite una aplicación que cambia la rotación de la pantalla en cualquier momento. Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar señales de Linux a las aplicaciones"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Admite que la aplicación solicite el envío de la señal suministrada a todos los procesos continuos."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"hacer que siempre se ejecute la aplicación"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Admite una aplicación que hace continuas sus propias partes, de modo que el sistema no puede utilizarla para otras aplicaciones."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"eliminar aplicaciones"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Admite una aplicación que borra paquetes Android. Las aplicaciones maliciosas pueden utilizarlo para eliminar aplicaciones importantes."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"eliminar los datos de otras aplicaciones"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Admite una aplicación que borra los datos del usuario."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"eliminar las memorias caché de otras aplicaciones"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Admite una aplicación que borra archivos de memoria caché."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"medir el espacio de almacenamiento de la aplicación"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Admite una aplicación que recupera su código, datos y tamaños de memoria caché"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicaciones directamente"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Admite una aplicación que instala paquetes de Android nuevos o actualizados. Las aplicaciones maliciosas pueden utilizarlo para agregar aplicaciones nuevas con permisos arbitrariamente potentes."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos los datos de memoria caché de la aplicación"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Admite una aplicación que libera espacio de almacenamiento en el teléfono al eliminar archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"leer archivos de registro del sistema"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto le permite descubrir información general sobre lo que haces con el teléfono, pero no debe contener información personal ni privada."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Admite una aplicación que lee y escribe a cualquier recurso dentro del grupo de diagnóstico; por ejemplo, archivos con /dev. Esto puede afectar potencialmente la estabilidad y la seguridad del sistema. Debe utilizarlo SÓLO el fabricante o el operador en los diagnósticos específicos del hardware."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"activar o desactivar componentes de la aplicación"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Admite una aplicación que cambia si se debe activar o no un componente de otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para desactivar funciones importantes del teléfono. Se debe tener cuidado con el permiso, ya que es posible que los componentes de la aplicación alcancen un estado inservible, imperfecto e inestable."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"establecer aplicaciones preferidas"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Admite una aplicación que modifica tus aplicaciones preferidas. Puede admitir aplicaciones maliciosas que cambien silenciosamente las aplicaciones que se ejecutan e imiten tus aplicaciones existentes para recopilar tus datos privados."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modificar la configuración global del sistema"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Admite una aplicación que modifica los datos de configuración del sistema. Las aplicaciones maliciosas pueden corromper la configuración de tu sistema."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificar la configuración segura del sistema"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Admite una aplicación que modifica los datos de la configuración segura de los sistemas. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"modificar el mapa de servicios de Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Admite una aplicación que modifica el mapa de servicios de Google. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"iniciar automáticamente durante la inicialización"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Admite una aplicación que se inicia cuando el sistema haya finalizado la inicialización. Esto puede ocasionar que se demore más tiempo en inicializar el teléfono y que la aplicación retarde el funcionamiento total del teléfono al estar en ejecución constante."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar emisiones pegajosas"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Admite una aplicación que envía emisiones pegajosas, las cuales permanecen luego de que finaliza la emisión. Las aplicaciones maliciosas pueden hacer lento e inestable al teléfono, ya que ocasiona que utilice demasiada memoria."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"leer datos de contacto"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Admite una aplicación que lee todos los datos de (direcciones) de contactos almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"escribir datos de contacto"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Admite una aplicación que modifica los datos de (dirección de) contacto guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"escribir datos del propietario"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Admite una aplicación que modifica los datos del propietario del teléfono guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos del propietario."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"leer datos del propietario"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Admite una aplicación que lee los datos del propietario del teléfono guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para leer los datos del propietario del teléfono."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"leer datos de calendario"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Admite que una aplicación lea todos los eventos de calendario almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"escribir datos de calendario"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Admite una aplicación que modifica los eventos de calendario guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar tus datos de calendario."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"crear fuentes de ubicación de prueba"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Crea fuentes de ubicación de prueba. Las aplicaciones maliciosas pueden utilizarlo para invalidar la ubicación o el estado que arrojen las fuentes de ubicación real, como GPS o proveedores de red."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acceder a comandos adicionales del proveedor del lugar"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Accede a comandos adicionales del proveedor del lugar. Las aplicaciones maliciosas pueden utilizarlo para interferir en la operación del GPS u otras fuentes de ubicación."</string>
+ <string name="permlab_internalSystemWindow">"mostrar ventanas no autorizadas"</string>
+ <string name="permdesc_internalSystemWindow">"Permite la creación de ventanas que la interfaz interna del usuario del sistema pretenda utilizar. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_systemAlertWindow">"mostrar alertas a nivel del sistema"</string>
+ <string name="permdesc_systemAlertWindow">"Admite una aplicación que muestra ventanas de alerta del sistema. Las aplicaciones maliciosas pueden tomar el control de toda la pantalla del teléfono."</string>
+ <string name="permlab_setAnimationScale">"modificar la velocidad de la animación global"</string>
+ <string name="permdesc_setAnimationScale">"Admite una aplicación que cambia la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
+ <string name="permlab_manageAppTokens">"administrar tokens de aplicación"</string>
+ <string name="permdesc_manageAppTokens">"Admite que las aplicaciones creen y administren sus propios tokens y desvíen su curva normal de llenado del espacio. Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <string name="permlab_injectEvents">"presionar teclas y botones de control"</string>
+ <string name="permdesc_injectEvents">"Admite una aplicación que ofrece sus propios eventos de entrada (presionar teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizarlo para tomar el control del teléfono."</string>
+ <string name="permlab_readInputState">"grabar tu tipo y las medidas que tomes"</string>
+ <string name="permdesc_readInputState">"Admite que las aplicaciones observen las teclas que presionas, incluso al interactuar con otra aplicación (como el ingreso de una contraseña). Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <string name="permlab_bindInputMethod">"vincular a un método de entrada"</string>
+ <string name="permdesc_bindInputMethod">"Permite al propietario vincularse a la interfaz de nivel superior de un método de entrada. Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <string name="permlab_setOrientation">"cambiar la orientación de la pantalla"</string>
+ <string name="permdesc_setOrientation">"Admite una aplicación que cambia la rotación de la pantalla en cualquier momento. Se debe evitar utilizarlo en aplicaciones normales."</string>
+ <string name="permlab_signalPersistentProcesses">"enviar señales de Linux a las aplicaciones"</string>
+ <string name="permdesc_signalPersistentProcesses">"Admite que la aplicación solicite el envío de la señal suministrada a todos los procesos continuos."</string>
+ <string name="permlab_persistentActivity">"hacer que siempre se ejecute la aplicación"</string>
+ <string name="permdesc_persistentActivity">"Admite una aplicación que hace continuas sus propias partes, de modo que el sistema no puede utilizarla para otras aplicaciones."</string>
+ <string name="permlab_deletePackages">"eliminar aplicaciones"</string>
+ <string name="permdesc_deletePackages">"Admite una aplicación que borra paquetes Android. Las aplicaciones maliciosas pueden utilizarlo para eliminar aplicaciones importantes."</string>
+ <string name="permlab_clearAppUserData">"eliminar los datos de otras aplicaciones"</string>
+ <string name="permdesc_clearAppUserData">"Admite una aplicación que borra los datos del usuario."</string>
+ <string name="permlab_deleteCacheFiles">"eliminar las memorias caché de otras aplicaciones"</string>
+ <string name="permdesc_deleteCacheFiles">"Admite una aplicación que borra archivos de memoria caché."</string>
+ <string name="permlab_getPackageSize">"medir el espacio de almacenamiento de la aplicación"</string>
+ <string name="permdesc_getPackageSize">"Admite una aplicación que recupera su código, datos y tamaños de memoria caché"</string>
+ <string name="permlab_installPackages">"instalar aplicaciones directamente"</string>
+ <string name="permdesc_installPackages">"Admite una aplicación que instala paquetes de Android nuevos o actualizados. Las aplicaciones maliciosas pueden utilizarlo para agregar aplicaciones nuevas con permisos arbitrariamente potentes."</string>
+ <string name="permlab_clearAppCache">"eliminar todos los datos de memoria caché de la aplicación"</string>
+ <string name="permdesc_clearAppCache">"Admite una aplicación que libera espacio de almacenamiento en el teléfono al eliminar archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
+ <string name="permlab_readLogs">"leer archivos de registro del sistema"</string>
+ <string name="permdesc_readLogs">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto le permite descubrir información general sobre lo que haces con el teléfono, pero no debe contener información personal ni privada."</string>
+ <string name="permlab_diagnostic">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
+ <string name="permdesc_diagnostic">"Admite una aplicación que lee y escribe a cualquier recurso dentro del grupo de diagnóstico; por ejemplo, archivos con /dev. Esto puede afectar potencialmente la estabilidad y la seguridad del sistema. Debe utilizarlo SÓLO el fabricante o el operador en los diagnósticos específicos del hardware."</string>
+ <string name="permlab_changeComponentState">"activar o desactivar componentes de la aplicación"</string>
+ <string name="permdesc_changeComponentState">"Admite una aplicación que cambia si se debe activar o no un componente de otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para desactivar funciones importantes del teléfono. Se debe tener cuidado con el permiso, ya que es posible que los componentes de la aplicación alcancen un estado inservible, imperfecto e inestable."</string>
+ <string name="permlab_setPreferredApplications">"establecer aplicaciones preferidas"</string>
+ <string name="permdesc_setPreferredApplications">"Admite una aplicación que modifica tus aplicaciones preferidas. Puede admitir aplicaciones maliciosas que cambien silenciosamente las aplicaciones que se ejecutan e imiten tus aplicaciones existentes para recopilar tus datos privados."</string>
+ <string name="permlab_writeSettings">"modificar la configuración global del sistema"</string>
+ <string name="permdesc_writeSettings">"Admite una aplicación que modifica los datos de configuración del sistema. Las aplicaciones maliciosas pueden corromper la configuración de tu sistema."</string>
+ <string name="permlab_writeSecureSettings">"modificar la configuración segura del sistema"</string>
+ <string name="permdesc_writeSecureSettings">"Admite una aplicación que modifica los datos de la configuración segura de los sistemas. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_writeGservices">"modificar el mapa de servicios de Google"</string>
+ <string name="permdesc_writeGservices">"Admite una aplicación que modifica el mapa de servicios de Google. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_receiveBootCompleted">"iniciar automáticamente durante la inicialización"</string>
+ <string name="permdesc_receiveBootCompleted">"Admite una aplicación que se inicia cuando el sistema haya finalizado la inicialización. Esto puede ocasionar que se demore más tiempo en inicializar el teléfono y que la aplicación retarde el funcionamiento total del teléfono al estar en ejecución constante."</string>
+ <string name="permlab_broadcastSticky">"enviar emisiones pegajosas"</string>
+ <string name="permdesc_broadcastSticky">"Admite una aplicación que envía emisiones pegajosas, las cuales permanecen luego de que finaliza la emisión. Las aplicaciones maliciosas pueden hacer lento e inestable al teléfono, ya que ocasiona que utilice demasiada memoria."</string>
+ <string name="permlab_readContacts">"leer datos de contacto"</string>
+ <string name="permdesc_readContacts">"Admite una aplicación que lee todos los datos de (direcciones) de contactos almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
+ <string name="permlab_writeContacts">"escribir datos de contacto"</string>
+ <string name="permdesc_writeContacts">"Admite una aplicación que modifica los datos de (dirección de) contacto guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
+ <string name="permlab_writeOwnerData">"escribir datos del propietario"</string>
+ <string name="permdesc_writeOwnerData">"Admite una aplicación que modifica los datos del propietario del teléfono guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos del propietario."</string>
+ <string name="permlab_readOwnerData">"leer datos del propietario"</string>
+ <string name="permdesc_readOwnerData">"Admite una aplicación que lee los datos del propietario del teléfono guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para leer los datos del propietario del teléfono."</string>
+ <string name="permlab_readCalendar">"leer datos de calendario"</string>
+ <string name="permdesc_readCalendar">"Admite que una aplicación lea todos los eventos de calendario almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
+ <string name="permlab_writeCalendar">"escribir datos de calendario"</string>
+ <string name="permdesc_writeCalendar">"Admite una aplicación que modifica los eventos de calendario guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar tus datos de calendario."</string>
+ <string name="permlab_accessMockLocation">"crear fuentes de ubicación de prueba"</string>
+ <string name="permdesc_accessMockLocation">"Crea fuentes de ubicación de prueba. Las aplicaciones maliciosas pueden utilizarlo para invalidar la ubicación o el estado que arrojen las fuentes de ubicación real, como GPS o proveedores de red."</string>
+ <string name="permlab_accessLocationExtraCommands">"acceder a comandos adicionales del proveedor del lugar"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Accede a comandos adicionales del proveedor del lugar. Las aplicaciones maliciosas pueden utilizarlo para interferir en la operación del GPS u otras fuentes de ubicación."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"ubicación precisa (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Accede a las fuentes de ubicación precisa, como el Sistema de posicionamiento global en el teléfono, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar donde te encuentras y puede consumir energía adicional de la batería."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ubicación aproximada (basada en la red)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Accede a las fuentes de ubicación aproximada, como la base de datos de la red de celulares, para determinar una ubicación telefónica aproximada, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar aproximadamente donde te encuentras."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"acceder a SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Admite que la aplicación utilice funciones de bajo nivel de SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer el búfer de tramas"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Admite que la aplicación que se utilizará lea el contenido del búfer de marco."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"cambiar tu configuración de audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Admite que la aplicación modifique la configuración global de audio, como el volumen y el enrutamiento."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"grabar audio"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Admite que la aplicación acceda a la ruta de grabación de audio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"tomar fotografías"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Admite una aplicación que toma fotografías con la cámara. Esto permite que la aplicación en cualquier momento recopile imágenes que esté viendo la cámara."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"desactivar teléfono de manera permanente"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Admite que la aplicación desactive todo el teléfono de manera permanente. Esto es muy peligroso."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"provocar el reinicio del teléfono"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Admite que la aplicación provoque que el teléfono se reinicie."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar y desmontar filesystems"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Admite que la aplicación monte y desmonte filesystems para obtener almacenamiento extraíble."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"espacio de almacenamiento externo del formato"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Admite que la aplicación formatee el espacio de almacenamiento extraíble."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"vibrador de control"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Admite que la aplicación controle el vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Admite que la aplicación controle la linterna."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"probar el hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Admite que la aplicación controle diversos periféricos con el fin de probar el hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Admite que la aplicación llame a ciertos números de teléfono sin tu permiso. Las aplicaciones maliciosas pueden ocasionar llamadas imprevistas en tu factura telefónica. Ten en cuenta que esto no admite que la aplicación llame a los números de emergencia."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"llamar directamente a cualquier número de teléfono"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Admite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin tu intervención. Las aplicaciones maliciosas pueden realizar llamadas innecesarias e ilegales a los servicios de emergencia."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de ubicación"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite activar y desactivar las notificaciones de actualización de ubicación de la radio. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"acceder a las propiedades de protección"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Admite el acceso de lectura y escritura a las propiedades subidas por el servicio de protección. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"elegir controles"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Admite que la aplicación indique al sistema cuáles controles puede utilizar cada aplicación. Con este permiso, las aplicaciones pueden brindar acceso a los datos personales a otras aplicaciones. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar el estado del teléfono"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Admite que la aplicación controle las funciones telefónicas del dispositivo. Una aplicación con este permiso puede cambiar las redes, encender y apagar la radio del teléfono y funciones similares sin notificarte en ningún momento."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"evitar que el teléfono entre en estado de inactividad"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Admite una aplicación que evita que el teléfono entre en estado de inactividad."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"apagar o encender el teléfono"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Admite que la aplicación encienda o apague el teléfono."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"ejecutar en el modo de prueba de fábrica"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del teléfono. Sólo disponible cuando un teléfono se ejecuta en el modo de prueba de fábrica."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"establecer papel tapiz"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Admite que la aplicación establezca el papel tapiz del sistema."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"establecer sugerencias de tamaño del papel tapiz"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Admite que la aplicación establezca las sugerencias de tamaño del papel tapiz del sistema."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"restablecer el sistema a las configuraciones predeterminadas de fábrica"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Admite una aplicación que restablece el sistema completamente con su configuración de fábrica, y borra todos los datos, las configuraciones y las aplicaciones instaladas."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"establecer zona horaria"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Admite una aplicación que cambia la zona horaria del teléfono."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"descubrir cuentas conocidas"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Admite una aplicación que obtiene la lista de cuentas conocidas del teléfono."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ver estado de la red"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Admite una aplicación que ve el estado de todas las redes."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"acceso total a Internet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Admite una aplicación que crea conectores de red."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"escribir configuración del Nombre del punto de acceso"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Admite una aplicación que modifica la configuración de APN, como el proxy y el puerto de cualquier APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"cambiar la conectividad de la red"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Admite una aplicación que cambia la conectividad de red del estado."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiar la configuración del uso de datos del fondo"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Admite una aplicación que cambia la configuración del uso de datos del fondo."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"ver el estado de Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Admite una aplicación que observa la información sobre el estado de Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"cambiar el estado de Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Admite una aplicación que se conecta y desconecta de los puntos de acceso de Wi-Fi y que hace cambios en las redes de Wi-Fi configuradas."</string>
+ <string name="permlab_accessFineLocation">"ubicación precisa (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Accede a las fuentes de ubicación precisa, como el Sistema de posicionamiento global en el teléfono, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar donde te encuentras y puede consumir energía adicional de la batería."</string>
+ <string name="permlab_accessCoarseLocation">"ubicación aproximada (basada en la red)"</string>
+ <string name="permdesc_accessCoarseLocation">"Accede a las fuentes de ubicación aproximada, como la base de datos de la red de celulares, para determinar una ubicación telefónica aproximada, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar aproximadamente donde te encuentras."</string>
+ <string name="permlab_accessSurfaceFlinger">"acceder a SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Admite que la aplicación utilice funciones de bajo nivel de SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"leer el búfer de tramas"</string>
+ <string name="permdesc_readFrameBuffer">"Admite que la aplicación que se utilizará lea el contenido del búfer de marco."</string>
+ <string name="permlab_modifyAudioSettings">"cambiar tu configuración de audio"</string>
+ <string name="permdesc_modifyAudioSettings">"Admite que la aplicación modifique la configuración global de audio, como el volumen y el enrutamiento."</string>
+ <string name="permlab_recordAudio">"grabar audio"</string>
+ <string name="permdesc_recordAudio">"Admite que la aplicación acceda a la ruta de grabación de audio."</string>
+ <string name="permlab_camera">"tomar fotografías"</string>
+ <string name="permdesc_camera">"Admite una aplicación que toma fotografías con la cámara. Esto permite que la aplicación en cualquier momento recopile imágenes que esté viendo la cámara."</string>
+ <string name="permlab_brick">"desactivar teléfono de manera permanente"</string>
+ <string name="permdesc_brick">"Admite que la aplicación desactive todo el teléfono de manera permanente. Esto es muy peligroso."</string>
+ <string name="permlab_reboot">"provocar el reinicio del teléfono"</string>
+ <string name="permdesc_reboot">"Admite que la aplicación provoque que el teléfono se reinicie."</string>
+ <string name="permlab_mount_unmount_filesystems">"montar y desmontar filesystems"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Admite que la aplicación monte y desmonte filesystems para obtener almacenamiento extraíble."</string>
+ <string name="permlab_mount_format_filesystems">"espacio de almacenamiento externo del formato"</string>
+ <string name="permdesc_mount_format_filesystems">"Admite que la aplicación formatee el espacio de almacenamiento extraíble."</string>
+ <string name="permlab_vibrate">"vibrador de control"</string>
+ <string name="permdesc_vibrate">"Admite que la aplicación controle el vibrador."</string>
+ <string name="permlab_flashlight">"controlar linterna"</string>
+ <string name="permdesc_flashlight">"Admite que la aplicación controle la linterna."</string>
+ <string name="permlab_hardware_test">"probar el hardware"</string>
+ <string name="permdesc_hardware_test">"Admite que la aplicación controle diversos periféricos con el fin de probar el hardware."</string>
+ <string name="permlab_callPhone">"llamar directamente a números de teléfono"</string>
+ <string name="permdesc_callPhone">"Admite que la aplicación llame a ciertos números de teléfono sin tu permiso. Las aplicaciones maliciosas pueden ocasionar llamadas imprevistas en tu factura telefónica. Ten en cuenta que esto no admite que la aplicación llame a los números de emergencia."</string>
+ <string name="permlab_callPrivileged">"llamar directamente a cualquier número de teléfono"</string>
+ <string name="permdesc_callPrivileged">"Admite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin tu intervención. Las aplicaciones maliciosas pueden realizar llamadas innecesarias e ilegales a los servicios de emergencia."</string>
+ <string name="permlab_locationUpdates">"controlar las notificaciones de actualización de ubicación"</string>
+ <string name="permdesc_locationUpdates">"Permite activar y desactivar las notificaciones de actualización de ubicación de la radio. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_checkinProperties">"acceder a las propiedades de protección"</string>
+ <string name="permdesc_checkinProperties">"Admite el acceso de lectura y escritura a las propiedades subidas por el servicio de protección. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_bindGadget">"elegir controles"</string>
+ <string name="permdesc_bindGadget">"Admite que la aplicación indique al sistema cuáles controles puede utilizar cada aplicación. Con este permiso, las aplicaciones pueden brindar acceso a los datos personales a otras aplicaciones. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="permlab_modifyPhoneState">"modificar el estado del teléfono"</string>
+ <string name="permdesc_modifyPhoneState">"Admite que la aplicación controle las funciones telefónicas del dispositivo. Una aplicación con este permiso puede cambiar las redes, encender y apagar la radio del teléfono y funciones similares sin notificarte en ningún momento."</string>
+ <string name="permlab_readPhoneState">"leer estado del teléfono"</string>
+ <string name="permdesc_readPhoneState">"Admite que la aplicación acceda a las funciones telefónicas del dispositivo. Una aplicación con este permiso puede determinar el número de este teléfono, si una llamada está activa, el número al cual está conectado esa llamada y funciones similares."</string>
+ <string name="permlab_wakeLock">"evitar que el teléfono entre en estado de inactividad"</string>
+ <string name="permdesc_wakeLock">"Admite una aplicación que evita que el teléfono entre en estado de inactividad."</string>
+ <string name="permlab_devicePower">"apagar o encender el teléfono"</string>
+ <string name="permdesc_devicePower">"Admite que la aplicación encienda o apague el teléfono."</string>
+ <string name="permlab_factoryTest">"ejecutar en el modo de prueba de fábrica"</string>
+ <string name="permdesc_factoryTest">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del teléfono. Sólo disponible cuando un teléfono se ejecuta en el modo de prueba de fábrica."</string>
+ <string name="permlab_setWallpaper">"establecer papel tapiz"</string>
+ <string name="permdesc_setWallpaper">"Admite que la aplicación establezca el papel tapiz del sistema."</string>
+ <string name="permlab_setWallpaperHints">"establecer sugerencias de tamaño del papel tapiz"</string>
+ <string name="permdesc_setWallpaperHints">"Admite que la aplicación establezca las sugerencias de tamaño del papel tapiz del sistema."</string>
+ <string name="permlab_masterClear">"restablecer el sistema a las configuraciones predeterminadas de fábrica"</string>
+ <string name="permdesc_masterClear">"Admite una aplicación que restablece el sistema completamente con su configuración de fábrica, y borra todos los datos, las configuraciones y las aplicaciones instaladas."</string>
+ <string name="permlab_setTimeZone">"establecer zona horaria"</string>
+ <string name="permdesc_setTimeZone">"Admite una aplicación que cambia la zona horaria del teléfono."</string>
+ <string name="permlab_getAccounts">"descubrir cuentas conocidas"</string>
+ <string name="permdesc_getAccounts">"Admite una aplicación que obtiene la lista de cuentas conocidas del teléfono."</string>
+ <string name="permlab_accessNetworkState">"ver estado de la red"</string>
+ <string name="permdesc_accessNetworkState">"Admite una aplicación que ve el estado de todas las redes."</string>
+ <string name="permlab_createNetworkSockets">"acceso total a Internet"</string>
+ <string name="permdesc_createNetworkSockets">"Admite una aplicación que crea conectores de red."</string>
+ <string name="permlab_writeApnSettings">"escribir configuración del Nombre del punto de acceso"</string>
+ <string name="permdesc_writeApnSettings">"Admite una aplicación que modifica la configuración de APN, como el proxy y el puerto de cualquier APN."</string>
+ <string name="permlab_changeNetworkState">"cambiar la conectividad de la red"</string>
+ <string name="permdesc_changeNetworkState">"Admite una aplicación que cambia la conectividad de red del estado."</string>
+ <string name="permlab_changeBackgroundDataSetting">"cambiar la configuración del uso de datos del fondo"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Admite una aplicación que cambia la configuración del uso de datos del fondo."</string>
+ <string name="permlab_accessWifiState">"ver el estado de Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Admite una aplicación que observa la información sobre el estado de Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"cambiar el estado de Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Admite una aplicación que se conecta y desconecta de los puntos de acceso de Wi-Fi y que hace cambios en las redes de Wi-Fi configuradas."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administración de bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Admite una aplicación que configura el teléfono Bluetooth local y descubre y se vincula con dispositivos remotos."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"crear conexiones de Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Admite una aplicación que ve la configuración del teléfono Bluetooth local, y realiza y acepta conexiones con dispositivos vinculados."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"desactivar el bloqueo"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Admite una aplicación que desactiva el bloqueo y cualquier seguridad con contraseña relacionada. Un ejemplo legítimo de esto es el bloqueo desactivado por el teléfono cuando recibe una llamada telefónica entrante, y luego la reactivación del bloqueo cuando finaliza la llamada."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Admite una aplicación que lee la configuración de sincronización, como si está activada la sincronización para los Contactos."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"escribir configuración de sincronización"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Admite una aplicación que modifica la configuración de sincronización, como si está activada la sincronización para los Contactos."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"leer estadística de sincronización"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Admite una aplicación que lee la estadística de sincronización; por ejemplo, el historial de sincronizaciones que se han producido."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"leer canales suscritos"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Admite una aplicación que obtiene detalles sobre los canales actualmente sincronizados."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"escribir canales suscritos"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Admite una aplicación que modifica tus canales actualmente sincronizados, lo cual podría permitir que una aplicación maliciosa también lo haga."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"leer diccionario definido por el usuario"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Admite una aplicación para leer palabras, nombres y frases privadas que posiblemente el usuario haya almacenado en el diccionario del usuario."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"escribir al diccionario definido por el usuario"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Admite una aplicación que escribe palabras nuevas en el diccionario del usuario."</string>
+ <string name="permlab_bluetoothAdmin">"administración de bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Admite una aplicación que configura el teléfono Bluetooth local y descubre y se vincula con dispositivos remotos."</string>
+ <string name="permlab_bluetooth">"crear conexiones de Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Admite una aplicación que ve la configuración del teléfono Bluetooth local, y realiza y acepta conexiones con dispositivos vinculados."</string>
+ <string name="permlab_disableKeyguard">"desactivar el bloqueo"</string>
+ <string name="permdesc_disableKeyguard">"Admite una aplicación que desactiva el bloqueo y cualquier seguridad con contraseña relacionada. Un ejemplo legítimo de esto es el bloqueo desactivado por el teléfono cuando recibe una llamada telefónica entrante, y luego la reactivación del bloqueo cuando finaliza la llamada."</string>
+ <string name="permlab_readSyncSettings">"leer la configuración de sincronización"</string>
+ <string name="permdesc_readSyncSettings">"Admite una aplicación que lee la configuración de sincronización, como si está activada la sincronización para los Contactos."</string>
+ <string name="permlab_writeSyncSettings">"escribir configuración de sincronización"</string>
+ <string name="permdesc_writeSyncSettings">"Admite una aplicación que modifica la configuración de sincronización, como si está activada la sincronización para los Contactos."</string>
+ <string name="permlab_readSyncStats">"leer estadística de sincronización"</string>
+ <string name="permdesc_readSyncStats">"Admite una aplicación que lee la estadística de sincronización; por ejemplo, el historial de sincronizaciones que se han producido."</string>
+ <string name="permlab_subscribedFeedsRead">"leer canales suscritos"</string>
+ <string name="permdesc_subscribedFeedsRead">"Admite una aplicación que obtiene detalles sobre los canales actualmente sincronizados."</string>
+ <string name="permlab_subscribedFeedsWrite">"escribir canales suscritos"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Admite una aplicación que modifica tus canales actualmente sincronizados, lo cual podría permitir que una aplicación maliciosa también lo haga."</string>
+ <string name="permlab_readDictionary">"leer diccionario definido por el usuario"</string>
+ <string name="permdesc_readDictionary">"Admite una aplicación para leer palabras, nombres y frases privadas que posiblemente el usuario haya almacenado en el diccionario del usuario."</string>
+ <string name="permlab_writeDictionary">"escribir al diccionario definido por el usuario"</string>
+ <string name="permdesc_writeDictionary">"Admite una aplicación que escribe palabras nuevas en el diccionario del usuario."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Página principal"</item>
- <item msgid="869923650527136615">"Celular"</item>
- <item msgid="7897544654242874543">"Trabajo"</item>
- <item msgid="1103601433382158155">"Fax laboral"</item>
- <item msgid="1735177144948329370">"Fax residencial"</item>
- <item msgid="603878674477207394">"Localizador"</item>
- <item msgid="1650824275177931637">"Otros"</item>
- <item msgid="9192514806975898961">"Personalización"</item>
+ <item>"Página principal"</item>
+ <item>"Celular"</item>
+ <item>"Trabajo"</item>
+ <item>"Fax laboral"</item>
+ <item>"Fax residencial"</item>
+ <item>"Localizador"</item>
+ <item>"Otros"</item>
+ <item>"Personalización"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Página principal"</item>
- <item msgid="7084237356602625604">"Trabajo"</item>
- <item msgid="1112044410659011023">"Otros"</item>
- <item msgid="2374913952870110618">"Personalización"</item>
+ <item>"Página principal"</item>
+ <item>"Trabajo"</item>
+ <item>"Otros"</item>
+ <item>"Personalización"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Celular"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Página principal"</item>
- <item msgid="5629153956045109251">"Trabajo"</item>
- <item msgid="4966604264500343469">"Otros"</item>
- <item msgid="4932682847595299369">"Personalización"</item>
+ <item>"Página principal"</item>
+ <item>"Trabajo"</item>
+ <item>"Otros"</item>
+ <item>"Personalización"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Pág. ppal."</item>
- <item msgid="1359644565647383708">"Trabajo"</item>
- <item msgid="7868549401053615677">"Otros"</item>
- <item msgid="3145118944639869809">"Personalización"</item>
+ <item>"Página principal"</item>
+ <item>"Trabajo"</item>
+ <item>"Otros"</item>
+ <item>"Personalización"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Trabajo"</item>
- <item msgid="4378074129049520373">"Otros"</item>
- <item msgid="3455047468583965104">"Personalización"</item>
+ <item>"Trabajo"</item>
+ <item>"Otros"</item>
+ <item>"Personalización"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Ingresar el código de PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"¡Código de PIN incorrecto!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, presiona el menú y luego 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergencia"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Sin servicio)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Pantalla bloqueada."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Presionar Menú para desbloquear."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Extraer el patrón para desbloquear"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Llamada de emergencia"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correcto"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Lo sentimos, vuelve a intentarlo"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Ingresar el código de PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"¡Código de PIN incorrecto!"</string>
+ <string name="keyguard_label_text">"Para desbloquear, presiona el menú y luego 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Número de emergencia"</string>
+ <string name="lockscreen_carrier_default">"(Sin servicio)"</string>
+ <string name="lockscreen_screen_locked">"Pantalla bloqueada."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Presionar Menú para desbloquear."</string>
+ <string name="lockscreen_pattern_instructions">"Extraer el patrón para desbloquear"</string>
+ <string name="lockscreen_emergency_call">"Llamada de emergencia"</string>
+ <string name="lockscreen_pattern_correct">"Correcto"</string>
+ <string name="lockscreen_pattern_wrong">"Lo sentimos, vuelve a intentarlo"</string>
+ <string name="lockscreen_plugged_in">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"No hay tarjeta SIM."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"No hay tarjeta SIM en el teléfono."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Inserta una tarjeta SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Red bloqueada"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La tarjeta SIM está bloqueada con PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Consulta la guía del usuario o comunícate con el servicio de atención al cliente."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La tarjeta SIM está bloqueada."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando tarjeta SIM…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu teléfono al iniciar sesión en Google. "\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"¿Olvidaste el patrón?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Demasiados intentos de patrón."</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Para desbloquear, regístrate en tu cuenta de Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nombre de usuario (correo electrónico)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Contraseña"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inicia sesión"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nombre de usuario o contraseña incorrecta."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Conecta tu cargador."</string>
+ <string name="lockscreen_missing_sim_message_short">"No hay tarjeta SIM."</string>
+ <string name="lockscreen_missing_sim_message">"No hay tarjeta SIM en el teléfono."</string>
+ <string name="lockscreen_missing_sim_instructions">"Inserta una tarjeta SIM."</string>
+ <string name="lockscreen_network_locked_message">"Red bloqueada"</string>
+ <string name="lockscreen_sim_puk_locked_message">"La tarjeta SIM está bloqueada con PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Consulta la guía del usuario o comunícate con el servicio de atención al cliente."</string>
+ <string name="lockscreen_sim_locked_message">"La tarjeta SIM está bloqueada."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Desbloqueando tarjeta SIM…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu teléfono al iniciar sesión en Google. "\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"¿Olvidaste el patrón?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Demasiados intentos de patrón."</string>
+ <string name="lockscreen_glogin_instructions">"Para desbloquear, regístrate en tu cuenta de Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Nombre de usuario (correo electrónico)"</string>
+ <string name="lockscreen_glogin_password_hint">"Contraseña"</string>
+ <string name="lockscreen_glogin_submit_button">"Inicia sesión"</string>
+ <string name="lockscreen_glogin_invalid_input">"Nombre de usuario o contraseña incorrecta."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No hay notificaciones"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continuo"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Cargando..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Conecta el cargador"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Hay poca batería:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"menos de <xliff:g id="NUMBER">%d%%</xliff:g> restante."</string>
+ <string name="status_bar_no_notifications_title">"No hay notificaciones"</string>
+ <string name="status_bar_ongoing_events_title">"Continuo"</string>
+ <string name="status_bar_latest_events_title">"Notificaciones"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Cargando..."</string>
+ <string name="battery_low_title">"Conecta el cargador"</string>
+ <string name="battery_low_subtitle">"Hay poca batería:"</string>
+ <string name="battery_low_percent_format">"menos de <xliff:g id="NUMBER">%d%%</xliff:g> restante."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Error en la prueba de fábrica"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"La acción FACTORY_TEST se admite solamente en paquetes instalados en /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST ."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"La página en \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"¿Deseas salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
+ <string name="factorytest_failed">"Error en la prueba de fábrica"</string>
+ <string name="factorytest_not_system">"La acción FACTORY_TEST se admite solamente en paquetes instalados en /system/app."</string>
+ <string name="factorytest_no_action">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST ."</string>
+ <string name="factorytest_reboot">"Reiniciar"</string>
+ <string name="js_dialog_title">"La página en \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"¿Deseas salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
+ <string name="save_password_label">"Confirmar"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"¿Quieres recordar esta contraseña en el navegador?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no."</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Recuerda"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nunca"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"No dispones de permiso para abrir esta página."</string>
- <string name="text_copied" msgid="4985729524670131385">"Texto copiado en el portapapeles."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Más"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menú+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"espacio"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"ingresar"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"borrar"</string>
- <string name="search_go" msgid="8298016669822141719">"Buscar"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"hace 1 mes"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Anterior a 1 mes atrás"</string>
+ <string name="save_password_message">"¿Quieres recordar esta contraseña en el navegador?"</string>
+ <string name="save_password_notnow">"Ahora no."</string>
+ <string name="save_password_remember">"Recuerda"</string>
+ <string name="save_password_never">"Nunca"</string>
+ <string name="open_permission_deny">"No dispones de permiso para abrir esta página."</string>
+ <string name="text_copied">"Texto copiado en el portapapeles."</string>
+ <string name="more_item_label">"Más"</string>
+ <string name="prepend_shortcut_label">"Menú+"</string>
+ <string name="menu_space_shortcut_label">"espacio"</string>
+ <string name="menu_enter_shortcut_label">"ingresar"</string>
+ <string name="menu_delete_shortcut_label">"borrar"</string>
+ <string name="search_go">"Buscar"</string>
+ <string name="oneMonthDurationPast">"hace 1 mes"</string>
+ <string name="beforeOneMonthDurationPast">"Anterior a 1 mes atrás"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"hace 1 segundo"</item>
- <item quantity="other" msgid="3903706804349556379">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"hace 1 segundo"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"hace 1 minuto"</item>
- <item quantity="other" msgid="2176942008915455116">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"hace 1 minuto"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"hace 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"hace 1 hora"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ayer"</item>
- <item quantity="other" msgid="2479586466153314633">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"ayer"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"en 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"en 1 segundo"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"en 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"en 1 minuto"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"en 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"en 1 hora"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"mañana"</item>
- <item quantity="other" msgid="5109449375100953247">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"mañana"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"hace 1 segundo"</item>
- <item quantity="other" msgid="3699169366650930415">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"hace 1 segundo"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"hace 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"hace 1 min"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"hace 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"hace 1 hora"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ayer"</item>
- <item quantity="other" msgid="3453342639616481191">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"ayer"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"en 1 segundo"</item>
- <item quantity="other" msgid="5495880108825805108">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"en 1 segundo"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"en 1 minuto"</item>
- <item quantity="other" msgid="4216113292706568726">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"en 1 minuto"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"en 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"en 1 hora"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"mañana"</item>
- <item quantity="other" msgid="2973062968038355991">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"mañana"</item>
+ <item quantity="other">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"en %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"en %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"en %s"</string>
- <string name="day" msgid="8144195776058119424">"día"</string>
- <string name="days" msgid="4774547661021344602">"días"</string>
- <string name="hour" msgid="2126771916426189481">"hora"</string>
- <string name="hours" msgid="894424005266852993">"horas"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"mins"</string>
- <string name="second" msgid="3184235808021478">"segundo"</string>
- <string name="seconds" msgid="3161515347216589235">"segundos"</string>
- <string name="week" msgid="5617961537173061583">"semana"</string>
- <string name="weeks" msgid="6509623834583944518">"semanas"</string>
- <string name="year" msgid="4001118221013892076">"año"</string>
- <string name="years" msgid="6881577717993213522">"años"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Los días de semana (lunes a viernes)"</string>
- <string name="daily" msgid="5738949095624133403">"Diariamente"</string>
- <string name="weekly" msgid="983428358394268344">"Semanalmente el día <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Mensual"</string>
- <string name="yearly" msgid="1519577999407493836">"Anual"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"No se puede reproducir el video"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Lo sentimos, este video no es válido para las transmisiones a este dispositivo."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Lo sentimos, no se puede reproducir este video."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"Aceptar"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"mediodía"</string>
- <string name="Noon" msgid="3342127745230013127">"Mediodía"</string>
- <string name="midnight" msgid="7166259508850457595">"medianoche"</string>
- <string name="Midnight" msgid="5630806906897892201">"Medianoche"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Seleccionar todos"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Detener la selección de texto"</string>
- <string name="cut" msgid="3092569408438626261">"Cortar"</string>
- <string name="cutAll" msgid="2436383270024931639">"Cortar llamada"</string>
- <string name="copy" msgid="2681946229533511987">"Copiar"</string>
- <string name="copyAll" msgid="2590829068100113057">"Copiar todo"</string>
- <string name="paste" msgid="5629880836805036433">"Pegar"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Método de entrada"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Agregar \"%s\" al diccionario"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Editar texto"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Poco espacio de almacenamiento"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Hay poco espacio de almacenamiento en el teléfono."</string>
- <string name="ok" msgid="5970060430562524910">"Aceptar"</string>
- <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
- <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
- <string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
- <string name="capital_on" msgid="1544682755514494298">"Encendido"</string>
- <string name="capital_off" msgid="6815870386972805832">"APAGADO"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Completar la acción mediante"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Utilizar de manera predeterminada en esta acción."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Borrar la predeterminación en Configuración de la página principal &gt; Aplicaciones &gt; Administrar aplicaciones."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Seleccionar una acción"</string>
- <string name="noApplications" msgid="1691104391758345586">"Ninguna aplicación puede realizar esta acción."</string>
- <string name="aerr_title" msgid="653922989522758100">"¡Lo sentimos!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha detenido de forma imprevista. Vuelve a intentarlo."</string>
- <string name="aerr_process" msgid="1551785535966089511">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> se ha detenido de forma imprevista. Vuelve a intentarlo."</string>
- <string name="anr_title" msgid="3100070910664756057">"¡Lo sentimos!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (en la aplicación <xliff:g id="APPLICATION">%2$s</xliff:g>) no responde."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (en proceso <xliff:g id="PROCESS">%2$s</xliff:g>) no responde."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (en proceso <xliff:g id="PROCESS">%2$s</xliff:g>) no responde."</string>
- <string name="anr_process" msgid="1246866008169975783">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no responde."</string>
- <string name="force_close" msgid="3653416315450806396">"Provocar acercamiento"</string>
+ <string name="preposition_for_date">"en %s"</string>
+ <string name="preposition_for_time">"en %s"</string>
+ <string name="preposition_for_year">"en %s"</string>
+ <string name="day">"día"</string>
+ <string name="days">"días"</string>
+ <string name="hour">"hora"</string>
+ <string name="hours">"horas"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"mins"</string>
+ <string name="second">"segundo"</string>
+ <string name="seconds">"segundos"</string>
+ <string name="week">"semana"</string>
+ <string name="weeks">"semanas"</string>
+ <string name="year">"año"</string>
+ <string name="years">"años"</string>
+ <string name="every_weekday">"Los días de semana (lunes a viernes)"</string>
+ <string name="daily">"Diariamente"</string>
+ <string name="weekly">"Semanalmente el día <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Mensual"</string>
+ <string name="yearly">"Anual"</string>
+ <string name="VideoView_error_title">"No se puede reproducir el video"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Lo sentimos, este video no es válido para las transmisiones a este dispositivo."</string>
+ <string name="VideoView_error_text_unknown">"Lo sentimos, no se puede reproducir este video."</string>
+ <string name="VideoView_error_button">"Aceptar"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"mediodía"</string>
+ <string name="Noon">"Mediodía"</string>
+ <string name="midnight">"medianoche"</string>
+ <string name="Midnight">"Medianoche"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Seleccionar todos"</string>
+ <string name="selectText">"Seleccionar texto"</string>
+ <string name="stopSelectingText">"Detener la selección de texto"</string>
+ <string name="cut">"Cortar"</string>
+ <string name="cutAll">"Cortar llamada"</string>
+ <string name="copy">"Copiar"</string>
+ <string name="copyAll">"Copiar todo"</string>
+ <string name="paste">"Pegar"</string>
+ <string name="copyUrl">"Copiar URL"</string>
+ <string name="inputMethod">"Método de entrada"</string>
+ <string name="addToDictionary">"Agregar \"%s\" al diccionario"</string>
+ <string name="editTextMenuTitle">"Editar texto"</string>
+ <string name="low_internal_storage_view_title">"Poco espacio de almacenamiento"</string>
+ <string name="low_internal_storage_view_text">"Hay poco espacio de almacenamiento en el teléfono."</string>
+ <string name="ok">"Aceptar"</string>
+ <string name="cancel">"Cancelar"</string>
+ <string name="yes">"Aceptar"</string>
+ <string name="no">"Cancelar"</string>
+ <string name="dialog_alert_title">"Atención"</string>
+ <string name="capital_on">"Encendido"</string>
+ <string name="capital_off">"APAGADO"</string>
+ <string name="whichApplication">"Completar la acción mediante"</string>
+ <string name="alwaysUse">"Utilizar de manera predeterminada en esta acción."</string>
+ <string name="clearDefaultHintMsg">"Borrar la predeterminación en Configuración de la página principal &gt; Aplicaciones &gt; Administrar aplicaciones."</string>
+ <string name="chooseActivity">"Seleccionar una acción"</string>
+ <string name="noApplications">"Ninguna aplicación puede realizar esta acción."</string>
+ <string name="aerr_title">"¡Lo sentimos!"</string>
+ <string name="aerr_application">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha detenido de forma imprevista. Vuelve a intentarlo."</string>
+ <string name="aerr_process">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> se ha detenido de forma imprevista. Vuelve a intentarlo."</string>
+ <string name="anr_title">"¡Lo sentimos!"</string>
+ <string name="anr_activity_application">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (en la aplicación <xliff:g id="APPLICATION">%2$s</xliff:g>) no responde."</string>
+ <string name="anr_activity_process">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (en proceso <xliff:g id="PROCESS">%2$s</xliff:g>) no responde."</string>
+ <string name="anr_application_process">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (en proceso <xliff:g id="PROCESS">%2$s</xliff:g>) no responde."</string>
+ <string name="anr_process">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no responde."</string>
+ <string name="force_close">"Provocar acercamiento"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Espera"</string>
- <string name="debug" msgid="9103374629678531849">"Depurar"</string>
- <string name="sendText" msgid="5132506121645618310">"Selecciona una acción para el texto"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volumen del timbre"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volumen de los medios"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Reproduciendo a través de Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volumen de llamadas entrantes"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volumen en llamada de Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volumen de la alarma"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volumen de notificación"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volumen"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Tono de llamada predeterminado"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono de llamada predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silencioso"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos de llamada"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Tono de llamada desconocido"</string>
+ <string name="wait">"Espera"</string>
+ <string name="debug">"Depurar"</string>
+ <string name="sendText">"Selecciona una acción para el texto"</string>
+ <string name="volume_ringtone">"Volumen del timbre"</string>
+ <string name="volume_music">"Volumen de los medios"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Reproduciendo a través de Bluetooth"</string>
+ <string name="volume_call">"Volumen de llamadas entrantes"</string>
+ <string name="volume_bluetooth_call">"Volumen en llamada de Bluetooth"</string>
+ <string name="volume_alarm">"Volumen de la alarma"</string>
+ <string name="volume_notification">"Volumen de notificación"</string>
+ <string name="volume_unknown">"Volumen"</string>
+ <string name="ringtone_default">"Tono de llamada predeterminado"</string>
+ <string name="ringtone_default_with_actual">"Tono de llamada predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silencioso"</string>
+ <string name="ringtone_picker_title">"Tonos de llamada"</string>
+ <string name="ringtone_unknown">"Tono de llamada desconocido"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Red disponible de Wi-Fi"</item>
- <item quantity="other" msgid="4192424489168397386">"redes disponibles de Wi-Fi"</item>
+ <item quantity="one">"Red disponible de Wi-Fi"</item>
+ <item quantity="other">"redes disponibles de Wi-Fi"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Abrir red disponible de Wi-Fi"</item>
- <item quantity="other" msgid="7915895323644292768">"Abrir redes disponibles de Wi-Fi"</item>
+ <item quantity="one">"Abrir red disponible de Wi-Fi"</item>
+ <item quantity="other">"Abrir redes disponibles de Wi-Fi"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Insertar caracteres"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Aplicación desconocida"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Se envía una gran cantidad de mensajes SMS. Selecciona \"Aceptar\" para continuar o \"Cancelar\" para detener el envío."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Aceptar"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Establecer"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Predeterminado"</string>
- <string name="no_permissions" msgid="7283357728219338112">"No se requieren permisos"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ocultar"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar todos"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Cargando…"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"conectado al USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Has conectado tu teléfono a tu computadora a través de USB. Selecciona \"Montar\" si deseas copiar archivos entre tu computadora y la tarjeta SD de tu teléfono."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Montar"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"No montar"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Hay un problema para utilizar tu tarjeta SD en el almacenamiento USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"conectado al USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Seleccionar para copiar archivos desde o hacia tu computadora."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Apagar el almacenamiento USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Seleccionar para desactivar el almacenamiento USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Apagar el almacenamiento USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Antes de desactivar el almacenamiento USB, asegúrate de haberlo desmontado en el servidor USB al seleccionar \"Desactivar\"."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Apagar"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Cancelar"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Se ha producido un problema al desactivar el almacenamiento USB. Verifica para asegurarte de haber desmontado el servidor USB, luego vuelve a intentarlo."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatear tarjeta SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"¿Estás seguro de que quieres formatear la tarjeta SD? Se perderán todos los datos de tu tarjeta."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formato"</string>
+ <string name="select_character">"Insertar caracteres"</string>
+ <string name="sms_control_default_app_name">"Aplicación desconocida"</string>
+ <string name="sms_control_title">"Enviando mensajes SMS"</string>
+ <string name="sms_control_message">"Se envía una gran cantidad de mensajes SMS. Selecciona \"Aceptar\" para continuar o \"Cancelar\" para detener el envío."</string>
+ <string name="sms_control_yes">"Aceptar"</string>
+ <string name="sms_control_no">"Cancelar"</string>
+ <string name="date_time_set">"Establecer"</string>
+ <string name="default_permission_group">"Predeterminado"</string>
+ <string name="no_permissions">"No se requieren permisos"</string>
+ <string name="perms_hide"><b>"Ocultar"</b></string>
+ <string name="perms_show_all"><b>"Mostrar todos"</b></string>
+ <string name="googlewebcontenthelper_loading">"Cargando…"</string>
+ <string name="usb_storage_title">"conectado al USB"</string>
+ <string name="usb_storage_message">"Has conectado tu teléfono a tu computadora a través de USB. Selecciona \"Montar\" si deseas copiar archivos entre tu computadora y la tarjeta SD de tu teléfono."</string>
+ <string name="usb_storage_button_mount">"Montar"</string>
+ <string name="usb_storage_button_unmount">"No montar"</string>
+ <string name="usb_storage_error_message">"Hay un problema para utilizar tu tarjeta SD en el almacenamiento USB."</string>
+ <string name="usb_storage_notification_title">"conectado al USB"</string>
+ <string name="usb_storage_notification_message">"Seleccionar para copiar archivos desde o hacia tu computadora."</string>
+ <string name="usb_storage_stop_notification_title">"Apagar el almacenamiento USB"</string>
+ <string name="usb_storage_stop_notification_message">"Seleccionar para desactivar el almacenamiento USB."</string>
+ <string name="usb_storage_stop_title">"Apagar el almacenamiento USB"</string>
+ <string name="usb_storage_stop_message">"Antes de desactivar el almacenamiento USB, asegúrate de haberlo desmontado en el servidor USB al seleccionar \"Desactivar\"."</string>
+ <string name="usb_storage_stop_button_mount">"Apagar"</string>
+ <string name="usb_storage_stop_button_unmount">"Cancelar"</string>
+ <string name="usb_storage_stop_error_message">"Se ha producido un problema al desactivar el almacenamiento USB. Verifica para asegurarte de haber desmontado el servidor USB, luego vuelve a intentarlo."</string>
+ <string name="extmedia_format_title">"Formatear tarjeta SD"</string>
+ <string name="extmedia_format_message">"¿Estás seguro de que quieres formatear la tarjeta SD? Se perderán todos los datos de tu tarjeta."</string>
+ <string name="extmedia_format_button_format">"Formato"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Seleccionar método de entrada"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Preparación de la tarjeta SD"</string>
+ <string name="select_input_method">"Seleccionar método de entrada"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidatos"</u></string>
+ <string name="ext_media_checking_notification_title">"Preparación de la tarjeta SD"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Tarjeta SD vacía"</string>
+ <string name="ext_media_nofs_notification_title">"Tarjeta SD vacía"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Tarjeta SD dañada"</string>
+ <string name="ext_media_unmountable_notification_title">"Tarjeta SD dañada"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Tarjeta SD extraída de forma imprevista"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Desmontar la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Tarjeta SD fácil de extraer"</string>
+ <string name="ext_media_badremoval_notification_title">"Tarjeta SD extraída de forma imprevista"</string>
+ <string name="ext_media_badremoval_notification_message">"Desmontar la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Tarjeta SD fácil de extraer"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Tarjeta SD extraída"</string>
+ <string name="ext_media_nomedia_notification_title">"Tarjeta SD extraída"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"No se encontraron actividades coincidentes"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualizar la estadística de uso de los componentes"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Presiona dos veces para obtener el control del zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Error al aumentar el control"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Buscar"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Enviar"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Siguiente"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Hecho"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Ejecutar"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Marcar el número"\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Crear contacto "\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"No se encontraron actividades coincidentes"</string>
+ <string name="permlab_pkgUsageStats">"actualizar la estadística de uso de los componentes"</string>
+ <string name="permdesc_pkgUsageStats">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. Las aplicaciones normales no deben utilizarlo."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Presiona dos veces para obtener el control del zoom"</string>
+ <string name="gadget_host_error_inflating">"Error al aumentar el control"</string>
+ <string name="ime_action_go">"Ir"</string>
+ <string name="ime_action_search">"Buscar"</string>
+ <string name="ime_action_send">"Enviar"</string>
+ <string name="ime_action_next">"Siguiente"</string>
+ <string name="ime_action_done">"Finalizado"</string>
+ <string name="ime_action_default">"Ejecutar"</string>
+ <string name="dial_number_using">"Marcar el número"\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Crear contacto "\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c00a4be..f3ff316 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -15,695 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"&lt;sin título&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Sin número de teléfono)"</string>
- <string name="unknownName" msgid="2277556546742746522">"Desconocido"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Buzón de voz"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Se ha producido un problema de conexión o el código MMI no es válido."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"El servicio se ha habilitado."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Se ha habilitado el servicio para:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"El servicio se ha inhabilitado."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"El registro se ha realizado correctamente."</string>
- <string name="serviceErased" msgid="1288584695297200972">"El elemento se ha borrado correctamente."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Contraseña incorrecta"</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI completo"</string>
- <string name="badPin" msgid="5085454289896032547">"El PIN antiguo que has introducido no es correcto."</string>
- <string name="badPuk" msgid="5702522162746042460">"El código PUK que has introducido no es correcto."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Los códigos PIN introducidos no coinciden."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Introduce un código PIN con una longitud comprendida entre cuatro y ocho dígitos."</string>
- <string name="needPuk" msgid="919668385956251611">"La tarjeta SIM está bloqueada con el código PUK. Introduce el código PUK para desbloquearla."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Introduce el código PUK2 para desbloquear la tarjeta SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"ID de emisor de llamada entrante"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"ID de emisor de llamada saliente"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Desvío de llamada"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Llamada en espera"</string>
- <string name="BaMmi" msgid="455193067926770581">"Bloqueo de llamada"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Cambio de contraseña"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Cambio de PIN"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Número de llamada entrante presente"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Número de llamada entrante restringido"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Llamada a tres"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Rechazo de llamadas molestas no deseadas"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Entrega de número de llamada entrante"</string>
- <string name="DndMmi" msgid="1265478932418334331">"No molestar"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"El ID de emisor presenta el valor predeterminado de restringido. Siguiente llamada: Restringido"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"El ID de emisor presenta el valor predeterminado de restringido. Siguiente llamada: No restringido"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: Restringido"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: No restringido"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"El servicio no se suministra."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"El ID de emisor no se puede modificar."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"El acceso restringido se ha modificado."</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"El servicio de datos está bloqueado."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"El servicio de emergencia está bloqueado."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"El servicio de voz y SMS está bloqueado."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Todos los servicios de voz y SMS están bloqueados."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voz"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Datos"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asíncronos"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Sincronización"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paquete"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Indicador de itinerancia activado"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Indicador de itinerancia desactivado"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Indicador de itinerancia parpadeante"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Fuera del vecindario"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Fuera del edificio"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Itinerancia: sistema preferido"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Itinerancia: sistema disponible"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Itinerancia: partner de alianza"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Itinerancia: partner de gran calidad"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Itinerancia: funcionalidad de servicio completa"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Itinerancia: funcionalidad de servicio parcial"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Banner de itinerancia activado"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Banner de itinerancia desactivado"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Buscando servicio"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> transcurridos <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Código de función completo"</string>
- <string name="fcError" msgid="3327560126588500777">"Se ha producido un problema de conexión o el código de la función no es válido."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"Aceptar"</string>
- <string name="httpError" msgid="2567300624552921790">"La página web contiene un error."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"No se ha podido encontrar la URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"No se admite el esquema de autenticación del sitio."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"La autenticación no se ha realizado correctamente."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"La autenticación mediante el servidor proxy no se ha realizado correctamente."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"La conexión al servidor no se ha realizado correctamente."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"El servidor no ha podido establecer la comunicación. Vuelve a intentarlo más tarde."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Se ha agotado el tiempo de espera de conexión al servidor."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"La página contiene demasiados redireccionamientos de servidor."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protocolo no admitido"</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"No se ha podido establecer una conexión segura."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"La página no se ha podido abrir porque la URL no es válida."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"No se ha podido acceder al archivo."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"No se ha encontrado el archivo solicitado."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Sincronización"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
- <string name="low_memory" msgid="6632412458436461203">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
- <string name="me" msgid="6545696007631404292">"Yo"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opciones del teléfono"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Modo silencio"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Activar conexión inalámbrica"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Desactivar función inalámbrica"</string>
- <string name="screen_lock" msgid="799094655496098153">"Bloqueo de pantalla"</string>
- <string name="power_off" msgid="4266614107412865048">"Apagar"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Apagando..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"El teléfono se apagará."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"No hay aplicaciones recientes"</string>
- <string name="global_actions" msgid="2406416831541615258">"Opciones del teléfono"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencio"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"El sonido está desactivado. Activar."</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El sonido está activado. Desactivar."</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avión desactivado. Activar."</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avión desactivado. Activar."</string>
- <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios por los que tienes que pagar"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Permite que las aplicaciones realicen acciones por las que puede que tengas que pagar."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Leer y escribir SMS, mensajes de correo electrónico y otros mensajes"</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Tu información personal"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Acceso directo al calendario y a los contactos almacenados en el teléfono"</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Tu ubicación"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Controlar su ubicación física"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicación de red"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Permite que las aplicaciones accedan a distintas funciones de red."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Tus cuentas de Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Acceder a las cuentas de Google disponibles"</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controles de hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acceso directo al hardware del móvil"</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Llamadas de teléfono"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Controlar, registrar y procesar llamadas telefónicas"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Herramientas del sistema"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Acceso de nivel inferior y control del sistema"</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Herramientas de desarrollo"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funciones necesarias sólo para desarrolladores de aplicaciones"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Almacenamiento"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Acceder a la tarjeta SD"</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"inhabilitar o modificar la barra de estado"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Permite que las aplicaciones inhabiliten la barra de estado, o añadan y eliminen iconos del sistema."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expandir/contraer la barra de estado"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Permite que la aplicación expanda y contraiga la barra de estado."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"interceptar llamadas salientes"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Permite que la aplicación procese llamadas salientes y cambie el número que se va a marcar. Las aplicaciones malintencionadas pueden controlar, redirigir o impedir las llamadas salientes."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"recibir SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Permite que la aplicación reciba y procese mensajes SMS. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"recibir MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Permite que la aplicación reciba y procese mensajes MMS. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"enviar mensajes SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Permite que la aplicación envíe mensajes SMS. Es posible que tengas que pagar si las aplicaciones malintencionadas envían mensajes sin tu confirmación."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"leer SMS o MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Permite que la aplicación lea mensajes SMS almacenados en el teléfono o en la tarjeta SIM. Las aplicaciones malintencionadas pueden leer los mensajes confidenciales."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS o MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Permite que la aplicación escriba en mensajes SMS almacenados en el teléfono o en la tarjeta SIM. Las aplicaciones malintencionadas pueden borrar los mensajes."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"recibir WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Permite que la aplicación reciba y procese mensajes WAP. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"recuperar aplicaciones en ejecución"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Permite que la aplicación recupere información sobre tareas que se están ejecutando en este momento o que se han ejecutado recientemente. Puede permitir que las aplicaciones malintencionadas vean información privada sobre otras aplicaciones."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"reorganizar aplicaciones en ejecución"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite que una aplicación mueva tareas a segundo plano y a primer plano. Las aplicaciones malintencionadas pueden aparecer en primer plano sin su control."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"habilitar depuración de aplicación"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite que una aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden utilizar este permiso para desactivar otras aplicaciones."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar la configuración de la interfaz de usuario"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Permite que una aplicación cambie la configuración actual como, por ejemplo, la configuración local o el tamaño de fuente general."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"reiniciar otras aplicaciones"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Permite que una aplicación reinicie de forma forzosa otras aplicaciones."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"forzar el cierre de la aplicación"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Permite que una aplicación fuerce a cualquier actividad en segundo plano a cerrarse y volver a la pantalla anterior. No debería ser necesario nunca para las aplicaciones normales."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"recuperar estado interno del sistema"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Permite que la aplicación recupere el estado interno del sistema. Las aplicaciones malintencionadas pueden recuperar una amplia variedad de información protegida y privada que normalmente no deberían necesitar."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"cierre parcial"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Pone el administrador de actividades en estado de cierre. No realiza un cierre completo."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar cambios de aplicación"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Evita que el usuario cambie a otra aplicación."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"supervisar y controlar la ejecución de todas las aplicaciones"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Permite que una aplicación supervise y controle la ejecución de las actividades por parte del sistema. Las aplicaciones malintencionadas pueden vulnerar la seguridad del sistema. Este permiso sólo es necesario para tareas de desarrollo, nunca para el uso habitual del teléfono."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar emisión eliminada de paquete"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Permite que una aplicación emita una notificación de que se ha eliminado un paquete de aplicación. Las aplicaciones malintencionadas pueden utilizar este permiso para interrumpir la ejecución de cualquier otra aplicación."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"enviar una emisión recibida mediante SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Permite que una aplicación emita una notificación de que se ha recibido un mensaje SMS. Las aplicaciones malintencionadas pueden utilizar este permiso para falsificar mensajes SMS entrantes."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar emisión recibida mediante mensaje WAP PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Permite que una aplicación emita una notificación de que se ha recibido un mensaje WAP PUSH. Las aplicaciones malintencionadas pueden utilizar este permiso para falsificar la recepción de un mensaje MMS o para reemplazar de forma silenciosa el contenido de cualquier página web con variantes malintencionadas."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar el número de procesos en ejecución"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Permite que una aplicación controle el número máximo de procesos que se ejecutarán. No es necesario nunca para las aplicaciones normales."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"hacer que se cierren todas las aplicaciones en segundo plano"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Permite que una aplicación controle si las actividades finalizan siempre en cuanto pasan a segundo plano. No es necesario nunca para las aplicaciones normales."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"modificar estadísticas de la batería"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Permite la modificación de estadísticas recopiladas sobre la batería. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_backup" msgid="470013022865453920">"controlar las copias de seguridad y las restauraciones del sistema"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Permite que la aplicación controle el mecanismo de copia de seguridad y restauración del sistema. Este permiso no está destinado a aplicaciones normales."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mostrar ventanas no autorizadas"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite la creación de ventanas destinadas al uso por parte de la interfaz de usuario interna del sistema. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"mostrar alertas de nivel del sistema"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Permite que una aplicación muestre ventanas de alerta del sistema. Las aplicaciones malintencionadas pueden controlar toda la pantalla del teléfono."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar velocidad de animación global"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Permite que una aplicación cambie la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"administrar tokens de aplicación"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Permite que las aplicaciones creen y administren sus propios tokens, ignorando su orden z normal. Nunca debería ser necesario para las aplicaciones normales."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"pulsar teclas y botones de control"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Permite que la aplicación proporcione sus propios eventos de entrada (pulsación de teclas, etc.) a otras aplicaciones. Las aplicaciones malintencionadas pueden utilizar este permiso para controlar el teléfono."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"registrar lo que se escribe y las acciones que se realizan"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Permite que las aplicaciones observen las teclas que pulsas incluso cuando interactúas con otra aplicación (como, por ejemplo, al introducir una contraseña). No debería ser necesario nunca para las aplicaciones normales."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"enlazar con un método de introducción de texto"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permite enlazar con la interfaz de nivel superior de un método de introducción de texto. No debe ser necesario para las aplicaciones normales."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar orientación de la pantalla"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite que una aplicación cambie la rotación de la pantalla en cualquier momento. No debería ser necesario nunca para las aplicaciones normales."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar señales Linux a aplicaciones"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite que la aplicación solicite que la señal suministrada se envíe a todos los procesos persistentes."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"hacer que la aplicación se ejecute siempre"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Permite que una aplicación vuelva persistentes algunas de sus partes, de forma que el sistema no la pueda utilizar para otras aplicaciones."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"eliminar aplicaciones"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Permite que una aplicación elimine paquetes Android. Las aplicaciones malintencionadas pueden utilizar este permiso para eliminar aplicaciones importantes."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"eliminar los datos de otras aplicaciones"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Permite que una aplicación borre los datos de usuario."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"eliminar las cachés de otras aplicaciones"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Permite que una aplicación elimine archivos de caché."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"medir el espacio de almacenamiento de la aplicación"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Permite que la aplicación recupere su código, sus datos y los tamaños de caché."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicaciones directamente"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Permite que una aplicación instale paquetes Android nuevos o actualizados. Las aplicaciones malintencionadas pueden utilizar este permiso para añadir aplicaciones nuevas con permisos arbitrariamente potentes."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos los datos de caché de la aplicación"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite que una aplicación libere espacio de almacenamiento en el teléfono mediante la eliminación de archivos en el directorio de caché de la aplicación. El acceso al proceso del sistema suele estar muy restringido."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"leer archivos de registro del sistema"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Permite que una aplicación lea los distintos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que realiza el usuario con el teléfono, pero los registros no deberían contener información personal o privada."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite que una aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SÓLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"habilitar o inhabilitar componentes de la aplicación"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Permite que una aplicación cambie si un componente de otra aplicación está habilitado o inhabilitado. Las aplicaciones malintencionadas pueden utilizar este permiso para inhabilitar funciones importantes del teléfono. El permiso se debe utilizar con precaución, ya que es posible que los componentes se vuelvan inutilizables, inconsistentes o inestables."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"establecer aplicaciones preferidas"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Permite que una aplicación modifique las aplicaciones preferidas del usuario. De esta forma, las aplicaciones malintencionadas pueden cambiar de forma silenciosa las aplicaciones que se están ejecutando, falsificando las aplicaciones existentes para recopilar datos privados del usuario."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modificar la configuración global del sistema"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Permite que una aplicación modifique los datos de configuración del sistema. Las aplicaciones malintencionadas pueden dañar la configuración del sistema."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificar la configuración segura del sistema"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Permite que una aplicación modifique los datos de configuración segura del sistema. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"modificar la asignación de servicios de Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Permite que una aplicación modifique la asignación de servicios de Google. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"ejecutar automáticamente al iniciar"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Permite que una aplicación se ejecute automáticamente en cuanto se haya terminado de iniciar el sistema. Esto puede provocar que el teléfono tarde más en iniciarse y permite que la aplicación ralentice el funcionamiento global del teléfono al ejecutarse continuamente."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar emisión persistente"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Permite que una aplicación envíe emisiones persistentes, que permanecen en el teléfono una vez que la emisión finaliza. Las aplicaciones malintencionadas pueden ralentizar el teléfono o volverlo inestable al hacer que emplee demasiada memoria."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"leer los datos de contacto"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Permite que una aplicación lea todos los datos de contacto (direcciones) almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus datos a otras personas."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"escribir datos de contacto"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Permite que una aplicación modifique los datos de contacto (direcciones) almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar tus datos de contacto."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"escribir datos de propietario"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Permite que una aplicación modifique los datos del propietario del teléfono almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del propietario."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"leer datos del propietario"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Permite que una aplicación lea los datos del propietario del teléfono almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para leer los datos del propietario del teléfono."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"leer datos de calendario"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Permite que una aplicación lea todos los eventos de calendario almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus eventos de calendario a otras personas."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"escribir datos de calendario"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Permite que una aplicación modifique los eventos de calendario almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar tus datos de calendario."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"simular fuentes de ubicación para prueba"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Crear fuentes de origen simuladas para realizar pruebas. Las aplicaciones malintencionadas pueden utilizar este permiso para sobrescribir la ubicación o el estado devueltos por orígenes de ubicación reales, tales como los proveedores de red o GPS."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acceder a comandos de proveedor de ubicación adicional"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Acceder a comandos de proveedor de ubicación adicional. Las aplicaciones malintencionadas podrían utilizar este permiso para interferir en el funcionamiento del sistema GPS o de otras fuentes de ubicación."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"permiso para instalar un proveedor de ubicación"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Crear fuentes de origen simuladas para realizar pruebas. Las aplicaciones malintencionadas pueden utilizar este permiso para sobrescribir la ubicación o el estado devueltos por orígenes de ubicación reales, tales como los proveedores de red o GPS, o para controlar y notificar tu ubicación a una fuente externa."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"precisar la ubicación (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Permite precisar las fuentes de ubicación como, por ejemplo, el sistema de posicionamiento global, en el teléfono, en los casos en que estén disponibles. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar dónde se encuentra en usuario y pueden consumir batería adicional."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ubicación común (basada en red)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Acceder a fuentes de ubicación comunes como, por ejemplo, la base de datos de red de un teléfono móvil, para determinar una ubicación telefónica aproximada, en los casos en que esté disponible. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar dónde te encuentras aproximadamente."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"acceder a SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permite que la aplicación utilice funciones de SurfaceFlinger de nivel inferior."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer memoria de almacenamiento intermedio"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Permite que la aplicación que se va a utilizar lea el contenido de la memoria de almacenamiento intermedio."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"cambiar la configuración de audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Permite que la aplicación modifique la configuración de audio global como, por ejemplo, el volumen y la salida."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"grabar sonido"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Permite que la aplicación acceda a la ruta de grabación de audio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"realizar fotografías"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Permite que la aplicación realice fotografías con la cámara. De esta forma, la aplicación puede recopilar en cualquier momento las imágenes que ve la cámara."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"inhabilitar el teléfono de forma permanente"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Permite que la aplicación inhabilite todas las funciones del teléfono de forma permanente. Este permiso es muy peligroso."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"forzar reinicio del teléfono"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Permite que la aplicación fuerce al teléfono a reiniciarse."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"activar y desactivar sistemas de archivos"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permite que las aplicaciones activen y desactiven sistemas de archivos para un almacenamiento extraíble."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatear almacenamiento externo"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Permite a la aplicación formatear un almacenamiento extraíble."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"controlar vibración"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Permite que la aplicación controle la función de vibración."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Permite que la aplicación controle la función de linterna."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"probar hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite que la aplicación controle distintos periféricos con fines de prueba del hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Permite que la aplicación llame a números de teléfono sin la intervención del usuario. Las aplicaciones malintencionadas pueden originar llamadas inesperadas en la factura telefónica. Ten en cuenta que con este permiso la aplicación no puede realizar llamadas a números de emergencia."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"llamar directamente a cualquier número de teléfono"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Permite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin que el usuario intervenga. Las aplicaciones malintencionadas pueden realizar llamadas innecesarias e ilícitas a los servicios de emergencias."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de la ubicación"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite habilitar/inhabilitar las notificaciones de actualización de la señal móvil. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"acceder a propiedades de registro"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Permite el acceso de lectura/escritura a las propiedades cargadas por el servicio de registro. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"seleccionar widgets"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Permite que una aplicación indique al sistema los widgets que puede utilizar cada aplicación. Se trata de un permiso que no pueden utilizar las aplicaciones normales y que permite que una aplicación conceda acceso a datos personales a otras aplicaciones."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar estado del teléfono"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, activar y desactivar la señal móvil, etc., sin necesidad de notificar al usuario."</string>
- <string name="permlab_readPhoneState" msgid="2326172951448691631">"leer la identidad y el estado del teléfono"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. Una aplicación con este permiso puede determinar el número de teléfono y el número de serie de este teléfono, si una llamada está activa, el número al que está vinculada esa llamada, etc."</string>
- <string name="permlab_wakeLock" msgid="573480187941496130">"impedir que el teléfono entre en modo de suspensión"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Permite que una aplicación impida que el teléfono entre en modo de suspensión."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"encender o apagar el teléfono"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Permite que la aplicación active o desactive el teléfono."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"ejecutar en modo de prueba de fábrica"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Ejecutar como prueba de fabricante de nivel inferior, permitiendo un acceso íntegro al hardware del teléfono. Sólo está disponible cuando un teléfono se está ejecutando en modo de prueba."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"establecer fondo de pantalla"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permite que la aplicación establezca el fondo de pantalla del sistema."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"establecer el tamaño del fondo de pantalla"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Permite que la aplicación establezca el tamaño del fondo de pantalla del sistema."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"restablecer el sistema a los valores predeterminados de fábrica"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Permite que una aplicación restablezca por completo el sistema a su configuración de fábrica, borrando todos los datos, la configuración y las aplicaciones instaladas."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"establecer zona horaria"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Permite que una aplicación cambie la zona horaria del teléfono."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"ver cuentas reconocidas"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Permite que una aplicación obtenga una lista de cuentas reconocidas por el teléfono."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ver estado de la red"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Permite que una aplicación vea el estado de todas las redes."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"acceso íntegro a Internet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Permite que una aplicación cree sockets de red."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"escribir la configuración de nombre de punto de acceso"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Permite que una aplicación modifique los valores de configuración de un APN como, por ejemplo, el proxy y el puerto de cualquier APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"cambiar la conectividad de red"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Permite que una aplicación cambie la conectividad de red de estado."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiar configuración de uso de datos de referencia"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Permite a una aplicación cambiar la configuración de uso de los datos de referencia."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"ver estado de la conectividad Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Permite que una aplicación vea la información sobre el estado de la conectividad Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"cambiar estado de Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite que una aplicación se conecte a puntos de acceso Wi-Fi y se desconecte de ellos, y realice modificaciones en las redes Wi-Fi configuradas."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recepción multidifusión Wi-Fi"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite que una aplicación reciba paquetes no dirigidos directamente a tu dispositivo. Esta función puede resultar útil para descubrir servicios cercanos. Utiliza más energía que el modo de no multidifusión."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administración de Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permite que una aplicación configure el teléfono Bluetooth local, y vea dispositivos remotos y sincronice el teléfono con ellos."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"crear conexiones de Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Permite que una aplicación vea la configuración del teléfono Bluetooth local, y cree y acepte conexiones con los dispositivos sincronizados."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"inhabilitar bloqueo del teclado"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permite que una aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Un ejemplo legítimo de este permiso es la inhabilitación por parte del teléfono del bloqueo del teclado cuando recibe una llamada telefónica entrante y su posterior habilitación cuando finaliza la llamada."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Permite que una aplicación lea la configuración de sincronización como, por ejemplo, si la sincronización está habilitada para el menú \"Contactos\"."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"escribir configuración de sincronización"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Permite que una aplicación modifique la configuración de sincronización como, por ejemplo, si la sincronización está habilitada para el menú \"Contactos\"."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"leer estadísticas de sincronización"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Permite que una aplicación lea las estadísticas de sincronización como, por ejemplo, el historial de sincronizaciones que se han realizado."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"leer feeds a los que está suscrito el usuario"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Permite que una aplicación obtenga detalles sobre los feeds sincronizados en este momento."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"escribir feeds a los que está suscrito el usuario"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Permite que una aplicación modifique los feeds sincronizados actualmente. Este permiso podría provocar que una aplicación malintencionada cambie los feeds sincronizados."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"leer diccionario definido por el usuario"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Permite a una aplicación leer cualquier frase, palabra o nombre privado que el usuario haya almacenado en su diccionario."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"escribir en el diccionario definido por el usuario"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Permite a una aplicación escribir palabras nuevas en el diccionario del usuario."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"modificar/eliminar contenido de la tarjeta SD"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Permite que una aplicación escriba en la tarjeta SD."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"&lt;sin título&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Sin número de teléfono)"</string>
+ <string name="unknownName">"Desconocido"</string>
+ <string name="defaultVoiceMailAlphaTag">"Buzón de voz"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Se ha producido un problema de conexión o el código MMI no es válido."</string>
+ <string name="serviceEnabled">"El servicio se ha habilitado."</string>
+ <string name="serviceEnabledFor">"Se ha habilitado el servicio para:"</string>
+ <string name="serviceDisabled">"El servicio se ha inhabilitado."</string>
+ <string name="serviceRegistered">"El registro se ha realizado correctamente."</string>
+ <string name="serviceErased">"El elemento se ha borrado correctamente."</string>
+ <string name="passwordIncorrect">"Contraseña incorrecta"</string>
+ <string name="mmiComplete">"MMI completo"</string>
+ <string name="badPin">"El PIN antiguo que has introducido no es correcto."</string>
+ <string name="badPuk">"El código PUK que has introducido no es correcto."</string>
+ <string name="mismatchPin">"Los códigos PIN introducidos no coinciden."</string>
+ <string name="invalidPin">"Introduce un código PIN con una longitud comprendida entre cuatro y ocho dígitos."</string>
+ <string name="needPuk">"La tarjeta SIM está bloqueada con el código PUK. Introduce el código PUK para desbloquearla."</string>
+ <string name="needPuk2">"Introduce el código PUK2 para desbloquear la tarjeta SIM."</string>
+ <string name="ClipMmi">"ID de emisor de llamada entrante"</string>
+ <string name="ClirMmi">"ID de emisor de llamada saliente"</string>
+ <string name="CfMmi">"Desvío de llamada"</string>
+ <string name="CwMmi">"Llamada en espera"</string>
+ <string name="BaMmi">"Bloqueo de llamada"</string>
+ <string name="PwdMmi">"Cambio de contraseña"</string>
+ <string name="PinMmi">"Cambio de PIN"</string>
+ <string name="CnipMmi">"Número de llamada entrante presente"</string>
+ <string name="CnirMmi">"Número de llamada entrante restringido"</string>
+ <string name="ThreeWCMmi">"Llamada a tres"</string>
+ <string name="RuacMmi">"Rechazo de llamadas molestas no deseadas"</string>
+ <string name="CndMmi">"Entrega de número de llamada entrante"</string>
+ <string name="DndMmi">"No molestar"</string>
+ <string name="CLIRDefaultOnNextCallOn">"El ID de emisor presenta el valor predeterminado de restringido. Siguiente llamada: Restringido"</string>
+ <string name="CLIRDefaultOnNextCallOff">"El ID de emisor presenta el valor predeterminado de restringido. Siguiente llamada: No restringido"</string>
+ <string name="CLIRDefaultOffNextCallOn">"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: Restringido"</string>
+ <string name="CLIRDefaultOffNextCallOff">"El ID de emisor presenta el valor predeterminado de no restringido. Siguiente llamada: No restringido"</string>
+ <string name="serviceNotProvisioned">"El servicio no se suministra."</string>
+ <string name="CLIRPermanent">"El ID de emisor no se puede modificar."</string>
+ <string name="RestrictedChangedTitle">"El acceso restringido se ha modificado."</string>
+ <string name="RestrictedOnData">"El servicio de datos está bloqueado."</string>
+ <string name="RestrictedOnEmergency">"El servicio de emergencia está bloqueado."</string>
+ <string name="RestrictedOnNormal">"El servicio de voz y SMS está bloqueado."</string>
+ <string name="RestrictedOnAll">"Todos los servicios de voz y SMS están bloqueados."</string>
+ <string name="serviceClassVoice">"Voz"</string>
+ <string name="serviceClassData">"Datos"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asíncronos"</string>
+ <string name="serviceClassDataSync">"Sincronización"</string>
+ <string name="serviceClassPacket">"Paquete"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Indicador de itinerancia activado"</string>
+ <string name="roamingText1">"Indicador de itinerancia desactivado"</string>
+ <string name="roamingText2">"Indicador de itinerancia parpadeante"</string>
+ <string name="roamingText3">"Fuera del vecindario"</string>
+ <string name="roamingText4">"Fuera del edificio"</string>
+ <string name="roamingText5">"Itinerancia: sistema preferido"</string>
+ <string name="roamingText6">"Itinerancia: sistema disponible"</string>
+ <string name="roamingText7">"Itinerancia: partner de alianza"</string>
+ <string name="roamingText8">"Itinerancia: partner de gran calidad"</string>
+ <string name="roamingText9">"Itinerancia: funcionalidad de servicio completa"</string>
+ <string name="roamingText10">"Itinerancia: funcionalidad de servicio parcial"</string>
+ <string name="roamingText11">"Banner de itinerancia activado"</string>
+ <string name="roamingText12">"Banner de itinerancia desactivado"</string>
+ <string name="roamingTextSearching">"Buscando servicio"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> transcurridos <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
+ <string name="fcComplete">"Código de función completo"</string>
+ <string name="fcError">"Se ha producido un problema de conexión o el código de la función no es válido."</string>
+ <string name="httpErrorOk">"Aceptar"</string>
+ <string name="httpError">"La página web contiene un error."</string>
+ <string name="httpErrorLookup">"No se ha podido encontrar la URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"No se admite el esquema de autenticación del sitio."</string>
+ <string name="httpErrorAuth">"La autenticación no se ha realizado correctamente."</string>
+ <string name="httpErrorProxyAuth">"La autenticación mediante el servidor proxy no se ha realizado correctamente."</string>
+ <string name="httpErrorConnect">"La conexión al servidor no se ha realizado correctamente."</string>
+ <string name="httpErrorIO">"El servidor no ha podido establecer la comunicación. Vuelve a intentarlo más tarde."</string>
+ <string name="httpErrorTimeout">"Se ha agotado el tiempo de espera de conexión al servidor."</string>
+ <string name="httpErrorRedirectLoop">"La página contiene demasiados redireccionamientos de servidor."</string>
+ <string name="httpErrorUnsupportedScheme">"Protocolo no admitido"</string>
+ <string name="httpErrorFailedSslHandshake">"No se ha podido establecer una conexión segura."</string>
+ <string name="httpErrorBadUrl">"La página no se ha podido abrir porque la URL no es válida."</string>
+ <string name="httpErrorFile">"No se ha podido acceder al archivo."</string>
+ <string name="httpErrorFileNotFound">"No se ha encontrado el archivo solicitado."</string>
+ <string name="httpErrorTooManyRequests">"Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde."</string>
+ <string name="contentServiceSync">"Sincronización"</string>
+ <string name="contentServiceSyncNotificationTitle">"Sincronización"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
+ <string name="low_memory">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
+ <string name="me">"Yo"</string>
+ <string name="power_dialog">"Opciones del teléfono"</string>
+ <string name="silent_mode">"Modo silencio"</string>
+ <string name="turn_on_radio">"Activar conexión inalámbrica"</string>
+ <string name="turn_off_radio">"Desactivar función inalámbrica"</string>
+ <string name="screen_lock">"Bloqueo de pantalla"</string>
+ <string name="power_off">"Apagar"</string>
+ <string name="shutdown_progress">"Apagando..."</string>
+ <string name="shutdown_confirm">"El teléfono se apagará."</string>
+ <string name="no_recent_tasks">"No hay aplicaciones recientes"</string>
+ <string name="global_actions">"Opciones del teléfono"</string>
+ <string name="global_action_lock">"Bloqueo de pantalla"</string>
+ <string name="global_action_power_off">"Apagar"</string>
+ <string name="global_action_toggle_silent_mode">"Modo silencio"</string>
+ <string name="global_action_silent_mode_on_status">"El sonido está desactivado. Activar."</string>
+ <string name="global_action_silent_mode_off_status">"El sonido está activado. Desactivar."</string>
+ <string name="global_actions_toggle_airplane_mode">"Modo avión"</string>
+ <string name="global_actions_airplane_mode_on_status">"Modo avión desactivado. Activar."</string>
+ <string name="global_actions_airplane_mode_off_status">"Modo avión desactivado. Activar."</string>
+ <string name="safeMode">"Modo seguro"</string>
+ <string name="android_system_label">"Sistema Android"</string>
+ <string name="permgrouplab_costMoney">"Servicios por los que tienes que pagar"</string>
+ <string name="permgroupdesc_costMoney">"Permite que las aplicaciones realicen acciones por las que puede que tengas que pagar."</string>
+ <string name="permgrouplab_messages">"Tus mensajes"</string>
+ <string name="permgroupdesc_messages">"Leer y escribir SMS, mensajes de correo electrónico y otros mensajes"</string>
+ <string name="permgrouplab_personalInfo">"Tu información personal"</string>
+ <string name="permgroupdesc_personalInfo">"Acceso directo al calendario y a los contactos almacenados en el teléfono"</string>
+ <string name="permgrouplab_location">"Tu ubicación"</string>
+ <string name="permgroupdesc_location">"Controlar su ubicación física"</string>
+ <string name="permgrouplab_network">"Comunicación de red"</string>
+ <string name="permgroupdesc_network">"Permite que las aplicaciones accedan a distintas funciones de red."</string>
+ <string name="permgrouplab_accounts">"Tus cuentas de Google"</string>
+ <string name="permgroupdesc_accounts">"Acceder a las cuentas de Google disponibles"</string>
+ <string name="permgrouplab_hardwareControls">"Controles de hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Acceso directo al hardware del móvil"</string>
+ <string name="permgrouplab_phoneCalls">"Llamadas de teléfono"</string>
+ <string name="permgroupdesc_phoneCalls">"Controlar, registrar y procesar llamadas telefónicas"</string>
+ <string name="permgrouplab_systemTools">"Herramientas del sistema"</string>
+ <string name="permgroupdesc_systemTools">"Acceso de nivel inferior y control del sistema"</string>
+ <string name="permgrouplab_developmentTools">"Herramientas de desarrollo"</string>
+ <string name="permgroupdesc_developmentTools">"Funciones necesarias sólo para desarrolladores de aplicaciones"</string>
+ <string name="permgrouplab_storage">"Almacenamiento"</string>
+ <string name="permgroupdesc_storage">"Acceder a la tarjeta SD"</string>
+ <string name="permlab_statusBar">"inhabilitar o modificar la barra de estado"</string>
+ <string name="permdesc_statusBar">"Permite que las aplicaciones inhabiliten la barra de estado, o añadan y eliminen iconos del sistema."</string>
+ <string name="permlab_expandStatusBar">"expandir/contraer la barra de estado"</string>
+ <string name="permdesc_expandStatusBar">"Permite que la aplicación expanda y contraiga la barra de estado."</string>
+ <string name="permlab_processOutgoingCalls">"interceptar llamadas salientes"</string>
+ <string name="permdesc_processOutgoingCalls">"Permite que la aplicación procese llamadas salientes y cambie el número que se va a marcar. Las aplicaciones malintencionadas pueden controlar, redirigir o impedir las llamadas salientes."</string>
+ <string name="permlab_receiveSms">"recibir SMS"</string>
+ <string name="permdesc_receiveSms">"Permite que la aplicación reciba y procese mensajes SMS. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
+ <string name="permlab_receiveMms">"recibir MMS"</string>
+ <string name="permdesc_receiveMms">"Permite que la aplicación reciba y procese mensajes MMS. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
+ <string name="permlab_sendSms">"enviar mensajes SMS"</string>
+ <string name="permdesc_sendSms">"Permite que la aplicación envíe mensajes SMS. Es posible que tengas que pagar si las aplicaciones malintencionadas envían mensajes sin tu confirmación."</string>
+ <string name="permlab_readSms">"leer SMS o MMS"</string>
+ <string name="permdesc_readSms">"Permite que la aplicación lea mensajes SMS almacenados en el teléfono o en la tarjeta SIM. Las aplicaciones malintencionadas pueden leer los mensajes confidenciales."</string>
+ <string name="permlab_writeSms">"editar SMS o MMS"</string>
+ <string name="permdesc_writeSms">"Permite que la aplicación escriba en mensajes SMS almacenados en el teléfono o en la tarjeta SIM. Las aplicaciones malintencionadas pueden borrar los mensajes."</string>
+ <string name="permlab_receiveWapPush">"recibir WAP"</string>
+ <string name="permdesc_receiveWapPush">"Permite que la aplicación reciba y procese mensajes WAP. Las aplicaciones malintencionadas pueden controlar los mensajes o eliminarlos sin mostrarlos al usuario."</string>
+ <string name="permlab_getTasks">"recuperar aplicaciones en ejecución"</string>
+ <string name="permdesc_getTasks">"Permite que la aplicación recupere información sobre tareas que se están ejecutando en este momento o que se han ejecutado recientemente. Puede permitir que las aplicaciones malintencionadas vean información privada sobre otras aplicaciones."</string>
+ <string name="permlab_reorderTasks">"reorganizar aplicaciones en ejecución"</string>
+ <string name="permdesc_reorderTasks">"Permite que una aplicación mueva tareas a segundo plano y a primer plano. Las aplicaciones malintencionadas pueden aparecer en primer plano sin su control."</string>
+ <string name="permlab_setDebugApp">"habilitar depuración de aplicación"</string>
+ <string name="permdesc_setDebugApp">"Permite que una aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden utilizar este permiso para desactivar otras aplicaciones."</string>
+ <string name="permlab_changeConfiguration">"cambiar la configuración de la interfaz de usuario"</string>
+ <string name="permdesc_changeConfiguration">"Permite que una aplicación cambie la configuración actual como, por ejemplo, la configuración local o el tamaño de fuente general."</string>
+ <string name="permlab_restartPackages">"reiniciar otras aplicaciones"</string>
+ <string name="permdesc_restartPackages">"Permite que una aplicación reinicie de forma forzosa otras aplicaciones."</string>
+ <string name="permlab_forceBack">"forzar el cierre de la aplicación"</string>
+ <string name="permdesc_forceBack">"Permite que una aplicación fuerce a cualquier actividad en segundo plano a cerrarse y volver a la pantalla anterior. No debería ser necesario nunca para las aplicaciones normales."</string>
+ <string name="permlab_dump">"recuperar estado interno del sistema"</string>
+ <string name="permdesc_dump">"Permite que la aplicación recupere el estado interno del sistema. Las aplicaciones malintencionadas pueden recuperar una amplia variedad de información protegida y privada que normalmente no deberían necesitar."</string>
+ <string name="permlab_shutdown">"cierre parcial"</string>
+ <string name="permdesc_shutdown">"Pone el administrador de actividades en estado de cierre. No realiza un cierre completo."</string>
+ <string name="permlab_stopAppSwitches">"evitar cambios de aplicación"</string>
+ <string name="permdesc_stopAppSwitches">"Evita que el usuario cambie a otra aplicación."</string>
+ <string name="permlab_runSetActivityWatcher">"supervisar y controlar la ejecución de todas las aplicaciones"</string>
+ <string name="permdesc_runSetActivityWatcher">"Permite que una aplicación supervise y controle la ejecución de las actividades por parte del sistema. Las aplicaciones malintencionadas pueden vulnerar la seguridad del sistema. Este permiso sólo es necesario para tareas de desarrollo, nunca para el uso habitual del teléfono."</string>
+ <string name="permlab_broadcastPackageRemoved">"enviar emisión eliminada de paquete"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Permite que una aplicación emita una notificación de que se ha eliminado un paquete de aplicación. Las aplicaciones malintencionadas pueden utilizar este permiso para interrumpir la ejecución de cualquier otra aplicación."</string>
+ <string name="permlab_broadcastSmsReceived">"enviar una emisión recibida mediante SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Permite que una aplicación emita una notificación de que se ha recibido un mensaje SMS. Las aplicaciones malintencionadas pueden utilizar este permiso para falsificar mensajes SMS entrantes."</string>
+ <string name="permlab_broadcastWapPush">"enviar emisión recibida mediante mensaje WAP PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Permite que una aplicación emita una notificación de que se ha recibido un mensaje WAP PUSH. Las aplicaciones malintencionadas pueden utilizar este permiso para falsificar la recepción de un mensaje MMS o para reemplazar de forma silenciosa el contenido de cualquier página web con variantes malintencionadas."</string>
+ <string name="permlab_setProcessLimit">"limitar el número de procesos en ejecución"</string>
+ <string name="permdesc_setProcessLimit">"Permite que una aplicación controle el número máximo de procesos que se ejecutarán. No es necesario nunca para las aplicaciones normales."</string>
+ <string name="permlab_setAlwaysFinish">"hacer que se cierren todas las aplicaciones en segundo plano"</string>
+ <string name="permdesc_setAlwaysFinish">"Permite que una aplicación controle si las actividades finalizan siempre en cuanto pasan a segundo plano. No es necesario nunca para las aplicaciones normales."</string>
+ <string name="permlab_batteryStats">"modificar estadísticas de la batería"</string>
+ <string name="permdesc_batteryStats">"Permite la modificación de estadísticas recopiladas sobre la batería. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_backup">"controlar las copias de seguridad y las restauraciones del sistema"</string>
+ <string name="permdesc_backup">"Permite que la aplicación controle el mecanismo de copia de seguridad y restauración del sistema. Este permiso no está destinado a aplicaciones normales."</string>
+ <string name="permlab_internalSystemWindow">"mostrar ventanas no autorizadas"</string>
+ <string name="permdesc_internalSystemWindow">"Permite la creación de ventanas destinadas al uso por parte de la interfaz de usuario interna del sistema. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_systemAlertWindow">"mostrar alertas de nivel del sistema"</string>
+ <string name="permdesc_systemAlertWindow">"Permite que una aplicación muestre ventanas de alerta del sistema. Las aplicaciones malintencionadas pueden controlar toda la pantalla del teléfono."</string>
+ <string name="permlab_setAnimationScale">"modificar velocidad de animación global"</string>
+ <string name="permdesc_setAnimationScale">"Permite que una aplicación cambie la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
+ <string name="permlab_manageAppTokens">"administrar tokens de aplicación"</string>
+ <string name="permdesc_manageAppTokens">"Permite que las aplicaciones creen y administren sus propios tokens, ignorando su orden z normal. Nunca debería ser necesario para las aplicaciones normales."</string>
+ <string name="permlab_injectEvents">"pulsar teclas y botones de control"</string>
+ <string name="permdesc_injectEvents">"Permite que la aplicación proporcione sus propios eventos de entrada (pulsación de teclas, etc.) a otras aplicaciones. Las aplicaciones malintencionadas pueden utilizar este permiso para controlar el teléfono."</string>
+ <string name="permlab_readInputState">"registrar lo que se escribe y las acciones que se realizan"</string>
+ <string name="permdesc_readInputState">"Permite que las aplicaciones observen las teclas que pulsas incluso cuando interactúas con otra aplicación (como, por ejemplo, al introducir una contraseña). No debería ser necesario nunca para las aplicaciones normales."</string>
+ <string name="permlab_bindInputMethod">"enlazar con un método de introducción de texto"</string>
+ <string name="permdesc_bindInputMethod">"Permite enlazar con la interfaz de nivel superior de un método de introducción de texto. No debe ser necesario para las aplicaciones normales."</string>
+ <string name="permlab_setOrientation">"cambiar orientación de la pantalla"</string>
+ <string name="permdesc_setOrientation">"Permite que una aplicación cambie la rotación de la pantalla en cualquier momento. No debería ser necesario nunca para las aplicaciones normales."</string>
+ <string name="permlab_signalPersistentProcesses">"enviar señales Linux a aplicaciones"</string>
+ <string name="permdesc_signalPersistentProcesses">"Permite que la aplicación solicite que la señal suministrada se envíe a todos los procesos persistentes."</string>
+ <string name="permlab_persistentActivity">"hacer que la aplicación se ejecute siempre"</string>
+ <string name="permdesc_persistentActivity">"Permite que una aplicación vuelva persistentes algunas de sus partes, de forma que el sistema no la pueda utilizar para otras aplicaciones."</string>
+ <string name="permlab_deletePackages">"eliminar aplicaciones"</string>
+ <string name="permdesc_deletePackages">"Permite que una aplicación elimine paquetes Android. Las aplicaciones malintencionadas pueden utilizar este permiso para eliminar aplicaciones importantes."</string>
+ <string name="permlab_clearAppUserData">"eliminar los datos de otras aplicaciones"</string>
+ <string name="permdesc_clearAppUserData">"Permite que una aplicación borre los datos de usuario."</string>
+ <string name="permlab_deleteCacheFiles">"eliminar las cachés de otras aplicaciones"</string>
+ <string name="permdesc_deleteCacheFiles">"Permite que una aplicación elimine archivos de caché."</string>
+ <string name="permlab_getPackageSize">"medir el espacio de almacenamiento de la aplicación"</string>
+ <string name="permdesc_getPackageSize">"Permite que la aplicación recupere su código, sus datos y los tamaños de caché."</string>
+ <string name="permlab_installPackages">"instalar aplicaciones directamente"</string>
+ <string name="permdesc_installPackages">"Permite que una aplicación instale paquetes Android nuevos o actualizados. Las aplicaciones malintencionadas pueden utilizar este permiso para añadir aplicaciones nuevas con permisos arbitrariamente potentes."</string>
+ <string name="permlab_clearAppCache">"eliminar todos los datos de caché de la aplicación"</string>
+ <string name="permdesc_clearAppCache">"Permite que una aplicación libere espacio de almacenamiento en el teléfono mediante la eliminación de archivos en el directorio de caché de la aplicación. El acceso al proceso del sistema suele estar muy restringido."</string>
+ <string name="permlab_readLogs">"leer archivos de registro del sistema"</string>
+ <string name="permdesc_readLogs">"Permite que una aplicación lea los distintos archivos de registro del sistema. Con este permiso, la aplicación puede ver información general sobre las acciones que realiza el usuario con el teléfono, pero los registros no deberían contener información personal o privada."</string>
+ <string name="permlab_diagnostic">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
+ <string name="permdesc_diagnostic">"Permite que una aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SÓLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
+ <string name="permlab_changeComponentState">"habilitar o inhabilitar componentes de la aplicación"</string>
+ <string name="permdesc_changeComponentState">"Permite que una aplicación cambie si un componente de otra aplicación está habilitado o inhabilitado. Las aplicaciones malintencionadas pueden utilizar este permiso para inhabilitar funciones importantes del teléfono. El permiso se debe utilizar con precaución, ya que es posible que los componentes se vuelvan inutilizables, inconsistentes o inestables."</string>
+ <string name="permlab_setPreferredApplications">"establecer aplicaciones preferidas"</string>
+ <string name="permdesc_setPreferredApplications">"Permite que una aplicación modifique las aplicaciones preferidas del usuario. De esta forma, las aplicaciones malintencionadas pueden cambiar de forma silenciosa las aplicaciones que se están ejecutando, falsificando las aplicaciones existentes para recopilar datos privados del usuario."</string>
+ <string name="permlab_writeSettings">"modificar la configuración global del sistema"</string>
+ <string name="permdesc_writeSettings">"Permite que una aplicación modifique los datos de configuración del sistema. Las aplicaciones malintencionadas pueden dañar la configuración del sistema."</string>
+ <string name="permlab_writeSecureSettings">"modificar la configuración segura del sistema"</string>
+ <string name="permdesc_writeSecureSettings">"Permite que una aplicación modifique los datos de configuración segura del sistema. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_writeGservices">"modificar la asignación de servicios de Google"</string>
+ <string name="permdesc_writeGservices">"Permite que una aplicación modifique la asignación de servicios de Google. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_receiveBootCompleted">"ejecutar automáticamente al iniciar"</string>
+ <string name="permdesc_receiveBootCompleted">"Permite que una aplicación se ejecute automáticamente en cuanto se haya terminado de iniciar el sistema. Esto puede provocar que el teléfono tarde más en iniciarse y permite que la aplicación ralentice el funcionamiento global del teléfono al ejecutarse continuamente."</string>
+ <string name="permlab_broadcastSticky">"enviar emisión persistente"</string>
+ <string name="permdesc_broadcastSticky">"Permite que una aplicación envíe emisiones persistentes, que permanecen en el teléfono una vez que la emisión finaliza. Las aplicaciones malintencionadas pueden ralentizar el teléfono o volverlo inestable al hacer que emplee demasiada memoria."</string>
+ <string name="permlab_readContacts">"leer los datos de contacto"</string>
+ <string name="permdesc_readContacts">"Permite que una aplicación lea todos los datos de contacto (direcciones) almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus datos a otras personas."</string>
+ <string name="permlab_writeContacts">"escribir datos de contacto"</string>
+ <string name="permdesc_writeContacts">"Permite que una aplicación modifique los datos de contacto (direcciones) almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar tus datos de contacto."</string>
+ <string name="permlab_writeOwnerData">"escribir datos de propietario"</string>
+ <string name="permdesc_writeOwnerData">"Permite que una aplicación modifique los datos del propietario del teléfono almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del propietario."</string>
+ <string name="permlab_readOwnerData">"leer datos del propietario"</string>
+ <string name="permdesc_readOwnerData">"Permite que una aplicación lea los datos del propietario del teléfono almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para leer los datos del propietario del teléfono."</string>
+ <string name="permlab_readCalendar">"leer datos de calendario"</string>
+ <string name="permdesc_readCalendar">"Permite que una aplicación lea todos los eventos de calendario almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para enviar tus eventos de calendario a otras personas."</string>
+ <string name="permlab_writeCalendar">"escribir datos de calendario"</string>
+ <string name="permdesc_writeCalendar">"Permite que una aplicación modifique los eventos de calendario almacenados en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar tus datos de calendario."</string>
+ <string name="permlab_accessMockLocation">"simular fuentes de ubicación para prueba"</string>
+ <string name="permdesc_accessMockLocation">"Crear fuentes de origen simuladas para realizar pruebas. Las aplicaciones malintencionadas pueden utilizar este permiso para sobrescribir la ubicación o el estado devueltos por orígenes de ubicación reales, tales como los proveedores de red o GPS."</string>
+ <string name="permlab_accessLocationExtraCommands">"acceder a comandos de proveedor de ubicación adicional"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Acceder a comandos de proveedor de ubicación adicional. Las aplicaciones malintencionadas podrían utilizar este permiso para interferir en el funcionamiento del sistema GPS o de otras fuentes de ubicación."</string>
+ <string name="permlab_installLocationProvider">"permiso para instalar un proveedor de ubicación"</string>
+ <string name="permdesc_installLocationProvider">"Crear fuentes de origen simuladas para realizar pruebas. Las aplicaciones malintencionadas pueden utilizar este permiso para sobrescribir la ubicación o el estado devueltos por orígenes de ubicación reales, tales como los proveedores de red o GPS, o para controlar y notificar tu ubicación a una fuente externa."</string>
+ <string name="permlab_accessFineLocation">"precisar la ubicación (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Permite precisar las fuentes de ubicación como, por ejemplo, el sistema de posicionamiento global, en el teléfono, en los casos en que estén disponibles. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar dónde se encuentra en usuario y pueden consumir batería adicional."</string>
+ <string name="permlab_accessCoarseLocation">"ubicación común (basada en red)"</string>
+ <string name="permdesc_accessCoarseLocation">"Acceder a fuentes de ubicación comunes como, por ejemplo, la base de datos de red de un teléfono móvil, para determinar una ubicación telefónica aproximada, en los casos en que esté disponible. Las aplicaciones malintencionadas pueden utilizar este permiso para determinar dónde te encuentras aproximadamente."</string>
+ <string name="permlab_accessSurfaceFlinger">"acceder a SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Permite que la aplicación utilice funciones de SurfaceFlinger de nivel inferior."</string>
+ <string name="permlab_readFrameBuffer">"leer memoria de almacenamiento intermedio"</string>
+ <string name="permdesc_readFrameBuffer">"Permite que la aplicación que se va a utilizar lea el contenido de la memoria de almacenamiento intermedio."</string>
+ <string name="permlab_modifyAudioSettings">"cambiar la configuración de audio"</string>
+ <string name="permdesc_modifyAudioSettings">"Permite que la aplicación modifique la configuración de audio global como, por ejemplo, el volumen y la salida."</string>
+ <string name="permlab_recordAudio">"grabar sonido"</string>
+ <string name="permdesc_recordAudio">"Permite que la aplicación acceda a la ruta de grabación de audio."</string>
+ <string name="permlab_camera">"realizar fotografías"</string>
+ <string name="permdesc_camera">"Permite que la aplicación realice fotografías con la cámara. De esta forma, la aplicación puede recopilar en cualquier momento las imágenes que ve la cámara."</string>
+ <string name="permlab_brick">"inhabilitar el teléfono de forma permanente"</string>
+ <string name="permdesc_brick">"Permite que la aplicación inhabilite todas las funciones del teléfono de forma permanente. Este permiso es muy peligroso."</string>
+ <string name="permlab_reboot">"forzar reinicio del teléfono"</string>
+ <string name="permdesc_reboot">"Permite que la aplicación fuerce al teléfono a reiniciarse."</string>
+ <string name="permlab_mount_unmount_filesystems">"activar y desactivar sistemas de archivos"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Permite que las aplicaciones activen y desactiven sistemas de archivos para un almacenamiento extraíble."</string>
+ <string name="permlab_mount_format_filesystems">"formatear almacenamiento externo"</string>
+ <string name="permdesc_mount_format_filesystems">"Permite a la aplicación formatear un almacenamiento extraíble."</string>
+ <string name="permlab_vibrate">"controlar vibración"</string>
+ <string name="permdesc_vibrate">"Permite que la aplicación controle la función de vibración."</string>
+ <string name="permlab_flashlight">"controlar linterna"</string>
+ <string name="permdesc_flashlight">"Permite que la aplicación controle la función de linterna."</string>
+ <string name="permlab_hardware_test">"probar hardware"</string>
+ <string name="permdesc_hardware_test">"Permite que la aplicación controle distintos periféricos con fines de prueba del hardware."</string>
+ <string name="permlab_callPhone">"llamar directamente a números de teléfono"</string>
+ <string name="permdesc_callPhone">"Permite que la aplicación llame a números de teléfono sin la intervención del usuario. Las aplicaciones malintencionadas pueden originar llamadas inesperadas en la factura telefónica. Ten en cuenta que con este permiso la aplicación no puede realizar llamadas a números de emergencia."</string>
+ <string name="permlab_callPrivileged">"llamar directamente a cualquier número de teléfono"</string>
+ <string name="permdesc_callPrivileged">"Permite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin que el usuario intervenga. Las aplicaciones malintencionadas pueden realizar llamadas innecesarias e ilícitas a los servicios de emergencias."</string>
+ <string name="permlab_locationUpdates">"controlar las notificaciones de actualización de la ubicación"</string>
+ <string name="permdesc_locationUpdates">"Permite habilitar/inhabilitar las notificaciones de actualización de la señal móvil. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_checkinProperties">"acceder a propiedades de registro"</string>
+ <string name="permdesc_checkinProperties">"Permite el acceso de lectura/escritura a las propiedades cargadas por el servicio de registro. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permlab_bindGadget">"seleccionar widgets"</string>
+ <string name="permdesc_bindGadget">"Permite que una aplicación indique al sistema los widgets que puede utilizar cada aplicación. Se trata de un permiso que no pueden utilizar las aplicaciones normales y que permite que una aplicación conceda acceso a datos personales a otras aplicaciones."</string>
+ <string name="permlab_modifyPhoneState">"modificar estado del teléfono"</string>
+ <string name="permdesc_modifyPhoneState">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, activar y desactivar la señal móvil, etc., sin necesidad de notificar al usuario."</string>
+ <string name="permlab_readPhoneState">"leer el estado del teléfono"</string>
+ <string name="permdesc_readPhoneState">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. Una aplicación con este permiso puede determinar el número de teléfono de este teléfono, si una llamada está activa, el número al que está vinculado esa llamada, etc."</string>
+ <string name="permlab_wakeLock">"impedir que el teléfono entre en modo de suspensión"</string>
+ <string name="permdesc_wakeLock">"Permite que una aplicación impida que el teléfono entre en modo de suspensión."</string>
+ <string name="permlab_devicePower">"encender o apagar el teléfono"</string>
+ <string name="permdesc_devicePower">"Permite que la aplicación active o desactive el teléfono."</string>
+ <string name="permlab_factoryTest">"ejecutar en modo de prueba de fábrica"</string>
+ <string name="permdesc_factoryTest">"Ejecutar como prueba de fabricante de nivel inferior, permitiendo un acceso íntegro al hardware del teléfono. Sólo está disponible cuando un teléfono se está ejecutando en modo de prueba."</string>
+ <string name="permlab_setWallpaper">"establecer fondo de pantalla"</string>
+ <string name="permdesc_setWallpaper">"Permite que la aplicación establezca el fondo de pantalla del sistema."</string>
+ <string name="permlab_setWallpaperHints">"establecer el tamaño del fondo de pantalla"</string>
+ <string name="permdesc_setWallpaperHints">"Permite que la aplicación establezca el tamaño del fondo de pantalla del sistema."</string>
+ <string name="permlab_masterClear">"restablecer el sistema a los valores predeterminados de fábrica"</string>
+ <string name="permdesc_masterClear">"Permite que una aplicación restablezca por completo el sistema a su configuración de fábrica, borrando todos los datos, la configuración y las aplicaciones instaladas."</string>
+ <string name="permlab_setTimeZone">"establecer zona horaria"</string>
+ <string name="permdesc_setTimeZone">"Permite que una aplicación cambie la zona horaria del teléfono."</string>
+ <string name="permlab_getAccounts">"ver cuentas reconocidas"</string>
+ <string name="permdesc_getAccounts">"Permite que una aplicación obtenga una lista de cuentas reconocidas por el teléfono."</string>
+ <string name="permlab_accessNetworkState">"ver estado de la red"</string>
+ <string name="permdesc_accessNetworkState">"Permite que una aplicación vea el estado de todas las redes."</string>
+ <string name="permlab_createNetworkSockets">"acceso íntegro a Internet"</string>
+ <string name="permdesc_createNetworkSockets">"Permite que una aplicación cree sockets de red."</string>
+ <string name="permlab_writeApnSettings">"escribir la configuración de nombre de punto de acceso"</string>
+ <string name="permdesc_writeApnSettings">"Permite que una aplicación modifique los valores de configuración de un APN como, por ejemplo, el proxy y el puerto de cualquier APN."</string>
+ <string name="permlab_changeNetworkState">"cambiar la conectividad de red"</string>
+ <string name="permdesc_changeNetworkState">"Permite que una aplicación cambie la conectividad de red de estado."</string>
+ <string name="permlab_changeBackgroundDataSetting">"cambiar configuración de uso de datos de referencia"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Permite a una aplicación cambiar la configuración de uso de los datos de referencia."</string>
+ <string name="permlab_accessWifiState">"ver estado de la conectividad Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Permite que una aplicación vea la información sobre el estado de la conectividad Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"cambiar estado de Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Permite que una aplicación se conecte a puntos de acceso Wi-Fi y se desconecte de ellos, y realice modificaciones en las redes Wi-Fi configuradas."</string>
+ <string name="permlab_changeWifiMulticastState">"permitir recepción multidifusión Wi-Fi"</string>
+ <string name="permdesc_changeWifiMulticastState">"Permite que una aplicación reciba paquetes no dirigidos directamente a tu dispositivo. Esta función puede resultar útil para descubrir servicios cercanos. Utiliza más energía que el modo de no multidifusión."</string>
+ <string name="permlab_bluetoothAdmin">"administración de Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Permite que una aplicación configure el teléfono Bluetooth local, y vea dispositivos remotos y sincronice el teléfono con ellos."</string>
+ <string name="permlab_bluetooth">"crear conexiones de Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Permite que una aplicación vea la configuración del teléfono Bluetooth local, y cree y acepte conexiones con los dispositivos sincronizados."</string>
+ <string name="permlab_disableKeyguard">"inhabilitar bloqueo del teclado"</string>
+ <string name="permdesc_disableKeyguard">"Permite que una aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Un ejemplo legítimo de este permiso es la inhabilitación por parte del teléfono del bloqueo del teclado cuando recibe una llamada telefónica entrante y su posterior habilitación cuando finaliza la llamada."</string>
+ <string name="permlab_readSyncSettings">"leer la configuración de sincronización"</string>
+ <string name="permdesc_readSyncSettings">"Permite que una aplicación lea la configuración de sincronización como, por ejemplo, si la sincronización está habilitada para el menú \"Contactos\"."</string>
+ <string name="permlab_writeSyncSettings">"escribir configuración de sincronización"</string>
+ <string name="permdesc_writeSyncSettings">"Permite que una aplicación modifique la configuración de sincronización como, por ejemplo, si la sincronización está habilitada para el menú \"Contactos\"."</string>
+ <string name="permlab_readSyncStats">"leer estadísticas de sincronización"</string>
+ <string name="permdesc_readSyncStats">"Permite que una aplicación lea las estadísticas de sincronización como, por ejemplo, el historial de sincronizaciones que se han realizado."</string>
+ <string name="permlab_subscribedFeedsRead">"leer feeds a los que está suscrito el usuario"</string>
+ <string name="permdesc_subscribedFeedsRead">"Permite que una aplicación obtenga detalles sobre los feeds sincronizados en este momento."</string>
+ <string name="permlab_subscribedFeedsWrite">"escribir feeds a los que está suscrito el usuario"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Permite que una aplicación modifique los feeds sincronizados actualmente. Este permiso podría provocar que una aplicación malintencionada cambie los feeds sincronizados."</string>
+ <string name="permlab_readDictionary">"leer diccionario definido por el usuario"</string>
+ <string name="permdesc_readDictionary">"Permite a una aplicación leer cualquier frase, palabra o nombre privado que el usuario haya almacenado en su diccionario."</string>
+ <string name="permlab_writeDictionary">"escribir en el diccionario definido por el usuario"</string>
+ <string name="permdesc_writeDictionary">"Permite a una aplicación escribir palabras nuevas en el diccionario del usuario."</string>
+ <string name="permlab_sdcardWrite">"modificar/eliminar contenido de la tarjeta SD"</string>
+ <string name="permdesc_sdcardWrite">"Permite que una aplicación escriba en la tarjeta SD."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Casa"</item>
- <item msgid="869923650527136615">"Móvil"</item>
- <item msgid="7897544654242874543">"Trabajo"</item>
- <item msgid="1103601433382158155">"Fax del trabajo"</item>
- <item msgid="1735177144948329370">"Fax de casa"</item>
- <item msgid="603878674477207394">"Buscapersonas"</item>
- <item msgid="1650824275177931637">"Otro"</item>
- <item msgid="9192514806975898961">"Personalizar"</item>
+ <item>"Casa"</item>
+ <item>"Móvil"</item>
+ <item>"Trabajo"</item>
+ <item>"Fax del trabajo"</item>
+ <item>"Fax de casa"</item>
+ <item>"Buscapersonas"</item>
+ <item>"Otro"</item>
+ <item>"Personalizar"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Personal"</item>
- <item msgid="7084237356602625604">"Trabajo"</item>
- <item msgid="1112044410659011023">"Otra"</item>
- <item msgid="2374913952870110618">"Personalizar"</item>
+ <item>"Personal"</item>
+ <item>"Trabajo"</item>
+ <item>"Otra"</item>
+ <item>"Personalizar"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Móvil"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Casa"</item>
- <item msgid="5629153956045109251">"Trabajo"</item>
- <item msgid="4966604264500343469">"Otra"</item>
- <item msgid="4932682847595299369">"Personalizar"</item>
+ <item>"Casa"</item>
+ <item>"Trabajo"</item>
+ <item>"Otra"</item>
+ <item>"Personalizar"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Casa"</item>
- <item msgid="1359644565647383708">"Trabajo"</item>
- <item msgid="7868549401053615677">"Otro"</item>
- <item msgid="3145118944639869809">"Personalizar"</item>
+ <item>"Casa"</item>
+ <item>"Trabajo"</item>
+ <item>"Otro"</item>
+ <item>"Personalizar"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Trabajo"</item>
- <item msgid="4378074129049520373">"Otra"</item>
- <item msgid="3455047468583965104">"Personalizar"</item>
+ <item>"Trabajo"</item>
+ <item>"Otra"</item>
+ <item>"Personalizar"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo!"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo!"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Introduce el código PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"El código PIN es incorrecto."</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergencia"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Sin cobertura)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Pantalla bloqueada"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pulsa la tecla de menú para desbloquear la pantalla."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Dibujar patrón de desbloqueo"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Llamada de emergencia"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correcto"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Inténtalo de nuevo"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Cargado"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta el cargador"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Falta la tarjeta SIM"</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Inserta una tarjeta SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Bloqueada para la red"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La tarjeta SIM está bloqueada con el código PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Consulta la guía del usuario o ponte en contacto con el servicio de atención al cliente."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Introduce el código PIN."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando tarjeta SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación de un patrón de desbloqueo. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación del patrón de desbloqueo. Si realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos fallidos más, se te pedirá que desbloquees el teléfono con tus credenciales de acceso de Google."\n\n" Espera <xliff:g id="NUMBER_2">%d</xliff:g> segundos e inténtalo de nuevo."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Espera <xliff:g id="NUMBER">%d</xliff:g> segundos y vuelve a intentarlo."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"¿Has olvidado el patrón?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Se han realizado demasiados intentos incorrectos de creación del patrón."</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Para desbloquear el teléfono, accede a tu cuenta de Google."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nombre de usuario (correo electrónico)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Contraseña"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Acceder"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nombre de usuario o contraseña no válido"</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No tienes notificaciones"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Entrante"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Cargando..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Conecta el cargador"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Se está agotando la batería:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"menos del <xliff:g id="NUMBER">%d%%</xliff:g> disponible."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"¿Por qué?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Fallo en la prueba de fábrica"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"La acción FACTORY_TEST sólo es compatible con los paquetes instalados en /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"¿Quieres salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona \"Aceptar\" para continuar o \"Cancelar\" para permanecer en la página actual."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"leer información de marcadores y del historial del navegador"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Permite que la aplicación lea todas las URL que ha visitado el navegador y todos sus marcadores."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"escribir en marcadores y en el historial del navegador"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Permite que una aplicación modifique la información de los marcadores o del historial del navegador almacenada en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del navegador."</string>
- <string name="save_password_message" msgid="767344687139195790">"¿Deseas que el navegador recuerde esta contraseña?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Recordar"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nunca"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"No dispones de permiso para abrir esta página."</string>
- <string name="text_copied" msgid="4985729524670131385">"Texto copiado al portapapeles."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Más"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"MENU+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"espacio"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"intro"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"suprimir"</string>
- <string name="search_go" msgid="8298016669822141719">"Buscar"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"Hace un mes"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Hace más de un mes"</string>
+ <string name="keyguard_password_enter_pin_code">"Introduce el código PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"El código PIN es incorrecto."</string>
+ <string name="keyguard_label_text">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Número de emergencia"</string>
+ <string name="lockscreen_carrier_default">"(Sin cobertura)"</string>
+ <string name="lockscreen_screen_locked">"Pantalla bloqueada"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Pulsa la tecla de menú para desbloquear la pantalla."</string>
+ <string name="lockscreen_pattern_instructions">"Dibujar patrón de desbloqueo"</string>
+ <string name="lockscreen_emergency_call">"Llamada de emergencia"</string>
+ <string name="lockscreen_pattern_correct">"Correcto"</string>
+ <string name="lockscreen_pattern_wrong">"Inténtalo de nuevo"</string>
+ <string name="lockscreen_plugged_in">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Conecta el cargador"</string>
+ <string name="lockscreen_missing_sim_message_short">"Falta la tarjeta SIM"</string>
+ <string name="lockscreen_missing_sim_message">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string>
+ <string name="lockscreen_missing_sim_instructions">"Inserta una tarjeta SIM."</string>
+ <string name="lockscreen_network_locked_message">"Bloqueada para la red"</string>
+ <string name="lockscreen_sim_puk_locked_message">"La tarjeta SIM está bloqueada con el código PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Consulta la guía del usuario o ponte en contacto con el servicio de atención al cliente."</string>
+ <string name="lockscreen_sim_locked_message">"Introduce el código PIN."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Desbloqueando tarjeta SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación de un patrón de desbloqueo. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación del patrón de desbloqueo. Si realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos fallidos más, se te pedirá que desbloquees el teléfono con tus credenciales de acceso de Google."\n\n" Espera <xliff:g id="NUMBER_2">%d</xliff:g> segundos e inténtalo de nuevo."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Espera <xliff:g id="NUMBER">%d</xliff:g> segundos y vuelve a intentarlo."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"¿Has olvidado el patrón?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Se han realizado demasiados intentos incorrectos de creación del patrón."</string>
+ <string name="lockscreen_glogin_instructions">"Para desbloquear el teléfono, accede a tu cuenta de Google."</string>
+ <string name="lockscreen_glogin_username_hint">"Nombre de usuario (correo electrónico)"</string>
+ <string name="lockscreen_glogin_password_hint">"Contraseña"</string>
+ <string name="lockscreen_glogin_submit_button">"Acceder"</string>
+ <string name="lockscreen_glogin_invalid_input">"Nombre de usuario o contraseña no válido"</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"No tienes notificaciones"</string>
+ <string name="status_bar_ongoing_events_title">"Entrante"</string>
+ <string name="status_bar_latest_events_title">"Notificaciones"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Cargando..."</string>
+ <string name="battery_low_title">"Conecta el cargador"</string>
+ <string name="battery_low_subtitle">"Se está agotando la batería:"</string>
+ <string name="battery_low_percent_format">"menos del <xliff:g id="NUMBER">%d%%</xliff:g> disponible."</string>
+ <string name="battery_low_why">"¿Por qué?"</string>
+ <string name="factorytest_failed">"Fallo en la prueba de fábrica"</string>
+ <string name="factorytest_not_system">"La acción FACTORY_TEST sólo es compatible con los paquetes instalados en /system/app."</string>
+ <string name="factorytest_no_action">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Reiniciar"</string>
+ <string name="js_dialog_title">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"¿Quieres salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona \"Aceptar\" para continuar o \"Cancelar\" para permanecer en la página actual."</string>
+ <string name="save_password_label">"Confirmar"</string>
+ <string name="permlab_readHistoryBookmarks">"leer información de marcadores y del historial del navegador"</string>
+ <string name="permdesc_readHistoryBookmarks">"Permite que la aplicación lea todas las URL que ha visitado el navegador y todos sus marcadores."</string>
+ <string name="permlab_writeHistoryBookmarks">"escribir en marcadores y en el historial del navegador"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Permite que una aplicación modifique la información de los marcadores o del historial del navegador almacenada en el teléfono. Las aplicaciones malintencionadas pueden utilizar este permiso para borrar o modificar los datos del navegador."</string>
+ <string name="save_password_message">"¿Deseas que el navegador recuerde esta contraseña?"</string>
+ <string name="save_password_notnow">"Ahora no"</string>
+ <string name="save_password_remember">"Recordar"</string>
+ <string name="save_password_never">"Nunca"</string>
+ <string name="open_permission_deny">"No dispones de permiso para abrir esta página."</string>
+ <string name="text_copied">"Texto copiado al portapapeles."</string>
+ <string name="more_item_label">"Más"</string>
+ <string name="prepend_shortcut_label">"MENU+"</string>
+ <string name="menu_space_shortcut_label">"espacio"</string>
+ <string name="menu_enter_shortcut_label">"intro"</string>
+ <string name="menu_delete_shortcut_label">"suprimir"</string>
+ <string name="search_go">"Buscar"</string>
+ <string name="oneMonthDurationPast">"Hace un mes"</string>
+ <string name="beforeOneMonthDurationPast">"Hace más de un mes"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Hace 1 segundo"</item>
- <item quantity="other" msgid="3903706804349556379">"Hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"Hace 1 segundo"</item>
+ <item quantity="other">"Hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Hace 1 minuto"</item>
- <item quantity="other" msgid="2176942008915455116">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"Hace 1 minuto"</item>
+ <item quantity="other">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Hace 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"Hace 1 hora"</item>
+ <item quantity="other">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ayer"</item>
- <item quantity="other" msgid="2479586466153314633">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"ayer"</item>
+ <item quantity="other">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"dentro de 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"dentro de 1 segundo"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"dentro de 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"dentro de 1 minuto"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"dentro de 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"dentro de 1 hora"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"mañana"</item>
- <item quantity="other" msgid="5109449375100953247">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"mañana"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"hace 1 segundo"</item>
- <item quantity="other" msgid="3699169366650930415">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"hace 1 segundo"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"hace 1 minuto"</item>
- <item quantity="other" msgid="851164968597150710">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"hace 1 minuto"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"hace 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"hace 1 hora"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ayer"</item>
- <item quantity="other" msgid="3453342639616481191">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"ayer"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"dentro de 1 segundo"</item>
- <item quantity="other" msgid="5495880108825805108">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"dentro de 1 segundo"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"dentro de 1 minuto"</item>
- <item quantity="other" msgid="4216113292706568726">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"dentro de 1 minuto"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"dentro de 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"dentro de 1 hora"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"mañana"</item>
- <item quantity="other" msgid="2973062968038355991">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ <item quantity="one">"mañana"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"el %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"a las %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"en %s"</string>
- <string name="day" msgid="8144195776058119424">"día"</string>
- <string name="days" msgid="4774547661021344602">"días"</string>
- <string name="hour" msgid="2126771916426189481">"hora"</string>
- <string name="hours" msgid="894424005266852993">"horas"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"minutos"</string>
- <string name="second" msgid="3184235808021478">"segundos"</string>
- <string name="seconds" msgid="3161515347216589235">"segundos"</string>
- <string name="week" msgid="5617961537173061583">"semana"</string>
- <string name="weeks" msgid="6509623834583944518">"semanas"</string>
- <string name="year" msgid="4001118221013892076">"año"</string>
- <string name="years" msgid="6881577717993213522">"años"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Todos los días laborables (Lun-Vie)"</string>
- <string name="daily" msgid="5738949095624133403">"Diariamente"</string>
- <string name="weekly" msgid="983428358394268344">"Semanalmente, el <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Mensualmente"</string>
- <string name="yearly" msgid="1519577999407493836">"Anualmente"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"No se puede reproducir el vídeo."</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Este vídeo no se puede transmitir al dispositivo."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Este vídeo no se puede reproducir."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"Aceptar"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"mediodía"</string>
- <string name="Noon" msgid="3342127745230013127">"Mediodía"</string>
- <string name="midnight" msgid="7166259508850457595">"medianoche"</string>
- <string name="Midnight" msgid="5630806906897892201">"Medianoche"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Seleccionar todo"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Detener selección de texto"</string>
- <string name="cut" msgid="3092569408438626261">"Cortar"</string>
- <string name="cutAll" msgid="2436383270024931639">"Cortar todo"</string>
- <string name="copy" msgid="2681946229533511987">"Copiar"</string>
- <string name="copyAll" msgid="2590829068100113057">"Copiar todo"</string>
- <string name="paste" msgid="5629880836805036433">"Pegar"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Método de introducción de texto"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Añadir \"%s\" al diccionario"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Editar texto"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Poco espacio"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Se está agotando el espacio de almacenamiento del teléfono."</string>
- <string name="ok" msgid="5970060430562524910">"Aceptar"</string>
- <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
- <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
- <string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Atención"</string>
- <string name="capital_on" msgid="1544682755514494298">"Activado"</string>
- <string name="capital_off" msgid="6815870386972805832">"Desconectado"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Completar acción utilizando"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Utilizar de forma predeterminada para esta acción"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Borrar valores predeterminados en la página de configuración de la pantalla de inicio del teléfono &gt; Aplicaciones &gt; Administrar aplicaciones\"."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Seleccionar una acción"</string>
- <string name="noApplications" msgid="1691104391758345586">"Ninguna aplicación puede realizar esta acción."</string>
- <string name="aerr_title" msgid="653922989522758100">"Lo sentimos."</string>
- <string name="aerr_application" msgid="4683614104336409186">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha interrumpido inesperadamente. Inténtalo de nuevo."</string>
- <string name="aerr_process" msgid="1551785535966089511">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> se ha interrumpido inesperadamente. Inténtalo de nuevo."</string>
- <string name="anr_title" msgid="3100070910664756057">"Lo sentimos."</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="APPLICATION">%2$s</xliff:g> en aplicación) no está respondiendo."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g> en curso) no está respondiendo."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g> en curso) no está respondiendo."</string>
- <string name="anr_process" msgid="1246866008169975783">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no está respondiendo."</string>
- <string name="force_close" msgid="3653416315450806396">"Forzar cierre"</string>
- <string name="report" msgid="4060218260984795706">"Informe"</string>
- <string name="wait" msgid="7147118217226317732">"Esperar"</string>
- <string name="debug" msgid="9103374629678531849">"Depurar"</string>
- <string name="sendText" msgid="5132506121645618310">"Seleccionar la opción para compartir"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volumen del timbre"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volumen multimedia"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Reproduciendo a través de Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volumen de la llamada"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volumen de la llamada de Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volumen de alarma"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volumen de notificaciones"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volumen"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Tono predeterminado"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Tono predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silencio"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Tono desconocido"</string>
+ <string name="preposition_for_date">"el %s"</string>
+ <string name="preposition_for_time">"a las %s"</string>
+ <string name="preposition_for_year">"en %s"</string>
+ <string name="day">"día"</string>
+ <string name="days">"días"</string>
+ <string name="hour">"hora"</string>
+ <string name="hours">"horas"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"minutos"</string>
+ <string name="second">"segundos"</string>
+ <string name="seconds">"segundos"</string>
+ <string name="week">"semana"</string>
+ <string name="weeks">"semanas"</string>
+ <string name="year">"año"</string>
+ <string name="years">"años"</string>
+ <string name="every_weekday">"Todos los días laborables (Lun-Vie)"</string>
+ <string name="daily">"Diariamente"</string>
+ <string name="weekly">"Semanalmente, el <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Mensualmente"</string>
+ <string name="yearly">"Anualmente"</string>
+ <string name="VideoView_error_title">"No se puede reproducir el vídeo."</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Este vídeo no se puede transmitir al dispositivo."</string>
+ <string name="VideoView_error_text_unknown">"Este vídeo no se puede reproducir."</string>
+ <string name="VideoView_error_button">"Aceptar"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"mediodía"</string>
+ <string name="Noon">"Mediodía"</string>
+ <string name="midnight">"medianoche"</string>
+ <string name="Midnight">"Medianoche"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Seleccionar todo"</string>
+ <string name="selectText">"Seleccionar texto"</string>
+ <string name="stopSelectingText">"Detener selección de texto"</string>
+ <string name="cut">"Cortar"</string>
+ <string name="cutAll">"Cortar todo"</string>
+ <string name="copy">"Copiar"</string>
+ <string name="copyAll">"Copiar todo"</string>
+ <string name="paste">"Pegar"</string>
+ <string name="copyUrl">"Copiar URL"</string>
+ <string name="inputMethod">"Método de introducción de texto"</string>
+ <string name="addToDictionary">"Añadir \"%s\" al diccionario"</string>
+ <string name="editTextMenuTitle">"Editar texto"</string>
+ <string name="low_internal_storage_view_title">"Poco espacio"</string>
+ <string name="low_internal_storage_view_text">"Se está agotando el espacio de almacenamiento del teléfono."</string>
+ <string name="ok">"Aceptar"</string>
+ <string name="cancel">"Cancelar"</string>
+ <string name="yes">"Aceptar"</string>
+ <string name="no">"Cancelar"</string>
+ <string name="dialog_alert_title">"Atención"</string>
+ <string name="capital_on">"Activado"</string>
+ <string name="capital_off">"Desconectado"</string>
+ <string name="whichApplication">"Completar acción utilizando"</string>
+ <string name="alwaysUse">"Utilizar de forma predeterminada para esta acción"</string>
+ <string name="clearDefaultHintMsg">"Borrar valores predeterminados en la página de configuración de la pantalla de inicio del teléfono &gt; Aplicaciones &gt; Administrar aplicaciones\"."</string>
+ <string name="chooseActivity">"Seleccionar una acción"</string>
+ <string name="noApplications">"Ninguna aplicación puede realizar esta acción."</string>
+ <string name="aerr_title">"Lo sentimos."</string>
+ <string name="aerr_application">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha interrumpido inesperadamente. Inténtalo de nuevo."</string>
+ <string name="aerr_process">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> se ha interrumpido inesperadamente. Inténtalo de nuevo."</string>
+ <string name="anr_title">"Lo sentimos."</string>
+ <string name="anr_activity_application">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="APPLICATION">%2$s</xliff:g> en aplicación) no está respondiendo."</string>
+ <string name="anr_activity_process">"La actividad <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g> en curso) no está respondiendo."</string>
+ <string name="anr_application_process">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g> en curso) no está respondiendo."</string>
+ <string name="anr_process">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> no está respondiendo."</string>
+ <string name="force_close">"Forzar cierre"</string>
+ <string name="report">"Informe"</string>
+ <string name="wait">"Esperar"</string>
+ <string name="debug">"Depurar"</string>
+ <string name="sendText">"Seleccionar la opción para compartir"</string>
+ <string name="volume_ringtone">"Volumen del timbre"</string>
+ <string name="volume_music">"Volumen multimedia"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Reproduciendo a través de Bluetooth"</string>
+ <string name="volume_call">"Volumen de la llamada"</string>
+ <string name="volume_bluetooth_call">"Volumen de la llamada de Bluetooth"</string>
+ <string name="volume_alarm">"Volumen de alarma"</string>
+ <string name="volume_notification">"Volumen de notificaciones"</string>
+ <string name="volume_unknown">"Volumen"</string>
+ <string name="ringtone_default">"Tono predeterminado"</string>
+ <string name="ringtone_default_with_actual">"Tono predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silencio"</string>
+ <string name="ringtone_picker_title">"Tonos"</string>
+ <string name="ringtone_unknown">"Tono desconocido"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Red Wi-Fi disponible"</item>
- <item quantity="other" msgid="4192424489168397386">"Redes Wi-Fi disponibles"</item>
+ <item quantity="one">"Red Wi-Fi disponible"</item>
+ <item quantity="other">"Redes Wi-Fi disponibles"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Red Wi-Fi abierta disponible"</item>
- <item quantity="other" msgid="7915895323644292768">"Redes Wi-Fi abiertas disponibles"</item>
+ <item quantity="one">"Red Wi-Fi abierta disponible"</item>
+ <item quantity="other">"Redes Wi-Fi abiertas disponibles"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Insertar carácter"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Aplicación desconocida"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS..."</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Se ha enviado un número elevado de mensajes SMS. Selecciona \"Aceptar\" para continuar o \"Cancelar\" para interrumpir el envío."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Aceptar"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Establecer"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Predeterminado"</string>
- <string name="no_permissions" msgid="7283357728219338112">"No es necesario ningún permiso"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ocultar"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar todos"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Cargando..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Conectado por USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Has conectado el teléfono al equipo mediante USB. Selecciona \"Activar\" si deseas copiar archivos entre el equipo y la tarjeta SD del teléfono."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Activar"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"No activar"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Se ha producido un problema al intentar utilizar la tarjeta SD para el almacenamiento USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Conectado por USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Para copiar archivos al/desde el equipo"</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desactivar almacenamiento USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Seleccionar para desactivar USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Desactivar almacenamiento USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Antes de desactivar el almacenamiento USB, asegúrate de haber desactivado el host USB. Selecciona \"Desactivar\" para desactivar el almacenamiento USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Desactivar"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Cancelar"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Se ha producido un problema al desactivar el almacenamiento USB. Asegúrate de que has desactivado el host USB e inténtalo de nuevo."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatear tarjeta SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"¿Estás seguro de que quieres formatear la tarjeta SD? Se perderán todos los datos de la tarjeta."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formato"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Dispositivo de depuración USB conectado"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Hay un equipo conectado al teléfono."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Seleccionar método de introducción de texto"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Preparando tarjeta SD"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Comprobando errores..."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Tarjeta SD vacía"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"La tarjeta SD está vacía o su sistema de archivos es incompatible."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Tarjeta SD dañada"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"La tarjeta SD está dañada. Es posible que sea necesario volver a formatearla."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"La tarjeta SD se ha extraído inesperadamente."</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Desactiva la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Es seguro extraer la tarjeta SD."</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Puedes extraer la tarjeta SD de forma segura."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Tarjeta SD extraída"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"La tarjeta SD se ha extraído. Inserta una nueva."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"No se ha encontrado ninguna actividad coincidente."</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualizar estadísticas de uso de componentes"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. No está destinado al uso por parte de aplicaciones normales."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Da dos toques para acceder al control de zoom."</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Error al aumentar el widget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Buscar"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Enviar"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Siguiente"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Hecho"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Ejecutar"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Marcar número"\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Crear un contacto"\n"a partir de <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"seleccionado"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"no seleccionado"</string>
+ <string name="select_character">"Insertar carácter"</string>
+ <string name="sms_control_default_app_name">"Aplicación desconocida"</string>
+ <string name="sms_control_title">"Enviando mensajes SMS..."</string>
+ <string name="sms_control_message">"Se ha enviado un número elevado de mensajes SMS. Selecciona \"Aceptar\" para continuar o \"Cancelar\" para interrumpir el envío."</string>
+ <string name="sms_control_yes">"Aceptar"</string>
+ <string name="sms_control_no">"Cancelar"</string>
+ <string name="date_time_set">"Establecer"</string>
+ <string name="default_permission_group">"Predeterminado"</string>
+ <string name="no_permissions">"No es necesario ningún permiso"</string>
+ <string name="perms_hide"><b>"Ocultar"</b></string>
+ <string name="perms_show_all"><b>"Mostrar todos"</b></string>
+ <string name="googlewebcontenthelper_loading">"Cargando..."</string>
+ <string name="usb_storage_title">"Conectado por USB"</string>
+ <string name="usb_storage_message">"Has conectado el teléfono al equipo mediante USB. Selecciona \"Activar\" si deseas copiar archivos entre el equipo y la tarjeta SD del teléfono."</string>
+ <string name="usb_storage_button_mount">"Activar"</string>
+ <string name="usb_storage_button_unmount">"No activar"</string>
+ <string name="usb_storage_error_message">"Se ha producido un problema al intentar utilizar la tarjeta SD para el almacenamiento USB."</string>
+ <string name="usb_storage_notification_title">"Conectado por USB"</string>
+ <string name="usb_storage_notification_message">"Para copiar archivos al/desde el equipo"</string>
+ <string name="usb_storage_stop_notification_title">"Desactivar almacenamiento USB"</string>
+ <string name="usb_storage_stop_notification_message">"Seleccionar para desactivar USB."</string>
+ <string name="usb_storage_stop_title">"Desactivar almacenamiento USB"</string>
+ <string name="usb_storage_stop_message">"Antes de desactivar el almacenamiento USB, asegúrate de haber desactivado el host USB. Selecciona \"Desactivar\" para desactivar el almacenamiento USB."</string>
+ <string name="usb_storage_stop_button_mount">"Desactivar"</string>
+ <string name="usb_storage_stop_button_unmount">"Cancelar"</string>
+ <string name="usb_storage_stop_error_message">"Se ha producido un problema al desactivar el almacenamiento USB. Asegúrate de que has desactivado el host USB e inténtalo de nuevo."</string>
+ <string name="extmedia_format_title">"Formatear tarjeta SD"</string>
+ <string name="extmedia_format_message">"¿Estás seguro de que quieres formatear la tarjeta SD? Se perderán todos los datos de la tarjeta."</string>
+ <string name="extmedia_format_button_format">"Formato"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Seleccionar método de introducción de texto"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidatos"</u></string>
+ <string name="ext_media_checking_notification_title">"Preparando tarjeta SD"</string>
+ <string name="ext_media_checking_notification_message">"Comprobando errores..."</string>
+ <string name="ext_media_nofs_notification_title">"Tarjeta SD vacía"</string>
+ <string name="ext_media_nofs_notification_message">"La tarjeta SD está vacía o su sistema de archivos es incompatible."</string>
+ <string name="ext_media_unmountable_notification_title">"Tarjeta SD dañada"</string>
+ <string name="ext_media_unmountable_notification_message">"La tarjeta SD está dañada. Es posible que sea necesario volver a formatearla."</string>
+ <string name="ext_media_badremoval_notification_title">"La tarjeta SD se ha extraído inesperadamente."</string>
+ <string name="ext_media_badremoval_notification_message">"Desactiva la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Es seguro extraer la tarjeta SD."</string>
+ <string name="ext_media_safe_unmount_notification_message">"Puedes extraer la tarjeta SD de forma segura."</string>
+ <string name="ext_media_nomedia_notification_title">"Tarjeta SD extraída"</string>
+ <string name="ext_media_nomedia_notification_message">"La tarjeta SD se ha extraído. Inserta una nueva."</string>
+ <string name="activity_list_empty">"No se ha encontrado ninguna actividad coincidente."</string>
+ <string name="permlab_pkgUsageStats">"actualizar estadísticas de uso de componentes"</string>
+ <string name="permdesc_pkgUsageStats">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Da dos toques para acceder al control de zoom."</string>
+ <string name="gadget_host_error_inflating">"Error al aumentar el widget"</string>
+ <string name="ime_action_go">"Ir"</string>
+ <string name="ime_action_search">"Buscar"</string>
+ <string name="ime_action_send">"Enviar"</string>
+ <string name="ime_action_next">"Siguiente"</string>
+ <string name="ime_action_done">"Hecho"</string>
+ <string name="ime_action_default">"Ejecutar"</string>
+ <string name="dial_number_using">"Marcar número"\n"con <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Crear un contacto"\n"a partir de <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="accessibility_compound_button_selected">"seleccionado"</string>
+ <string name="accessibility_compound_button_unselected">"no seleccionado"</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 377d202..ae3c807 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -15,695 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"O"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"Ko"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"Mo"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"Go"</string>
- <string name="terabyteShort" msgid="231613018159186962">"To"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"Po"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"&lt;sans titre&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Aucun numéro de téléphone)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Inconnu)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Messagerie vocale"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problème de connexion ou code IHM non valide."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Le service a été activé."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Ce service a été activé pour :"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Ce service a été désactivé."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Enregistrement réussi."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Effacement réussi."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Le mot de passe est incorrect."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"IHM terminée."</string>
- <string name="badPin" msgid="5085454289896032547">"L\'ancien code PIN saisi est incorrect."</string>
- <string name="badPuk" msgid="5702522162746042460">"La clé PUK saisie est incorrecte."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Les codes PIN saisis ne correspondent pas."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Le code PIN doit compter de 4 à 8 chiffres."</string>
- <string name="needPuk" msgid="919668385956251611">"Votre carte SIM est verrouillée par clé PUK. Saisissez la clé PUK pour la déverrouiller."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Saisissez la clé PUK2 pour débloquer la carte SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Numéro de l\'appelant (entrant)"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Numéro de l\'appelant (sortant)"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Transfert d\'appel"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Appel en attente"</string>
- <string name="BaMmi" msgid="455193067926770581">"Interdiction d\'appel"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Modification du mot de passe"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Modification du code PIN"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Présentation du numéro d\'appelant"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Numéro de l\'appelant masqué"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Conférence téléphonique à trois"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Rejeter les appels indésirables"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Livraison du numéro d\'appel"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Ne pas déranger"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : restreint"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : restreint"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Ce service n\'est pas pris en charge."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Le paramètre Numéro de l\'appelant ne peut pas être modifié."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"L\'accès limité a été modifié."</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Le service de données est bloqué."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Le service d\'appel d\'urgence est bloqué."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Le service vocal/SMS est bloqué."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Tous les services vocaux/SMS sont bloqués."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voix"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Données"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"Télécopie"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynchrones"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synchrones"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paquet"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Indicateur d\'itinérance activé"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Indicateur d\'itinérance désactivé"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Indicateur d\'itinérance clignotant"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Hors zone"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Hors du bâtiment"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Itinérance - Système préféré"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Itinérance - Système disponible"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Itinérance - Partenaire Alliance"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Itinérance - Partenaire Premium"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Itinérance - Tous services disponibles"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Itinérance - Services partiellement disponibles"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Bannière d\'itinérance activée"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Bannière d\'itinérance désactivée"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Recherche des services disponibles"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g> au bout de <xliff:g id="TIME_DELAY">{2}</xliff:g> secondes"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Code de service terminé"</string>
- <string name="fcError" msgid="3327560126588500777">"Problème de connexion ou code de service non valide"</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"La page Web contient une erreur."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"URL introuvable."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Le modèle d\'authentification du site n\'est pas pris en charge."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Échec de l\'authentification."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Échec de l\'authentification par un serveur proxy."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Échec de la connexion au serveur."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Échec de la communication avec le serveur. Veuillez réessayer ultérieurement."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Délai de connexion au serveur dépassé."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Cette page contient trop de redirections de serveurs."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Ce protocole n\'est pas pris en charge."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Aucune connexion sécurisée n\'a pu être établie."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Impossible d\'ouvrir cette page. L\'URL n\'est pas correcte."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Impossible d\'accéder au fichier."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Le fichier demandé est introuvable."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Trop de requêtes sont en cours de traitement. Veuillez réessayer ultérieurement."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synchroniser"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisation"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
- <string name="low_memory" msgid="6632412458436461203">"La mémoire du téléphone est pleine ! Supprimez des fichiers pour libérer de l\'espace."</string>
- <string name="me" msgid="6545696007631404292">"Moi"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Options du téléphone"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Mode silencieux"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Activer le mode sans fil"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Désactiver le mode sans fil"</string>
- <string name="screen_lock" msgid="799094655496098153">"Verrouillage de l\'écran"</string>
- <string name="power_off" msgid="4266614107412865048">"Éteindre"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Arrêt en cours..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Votre téléphone va s\'éteindre."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Aucune application récente"</string>
- <string name="global_actions" msgid="2406416831541615258">"Options du téléphone"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mode silencieux"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Le son est désactivé."</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Le son est activé."</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
- <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services payants"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Permet aux applications d\'effectuer des opérations payantes."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Permet de lire et rédiger vos SMS, e-mails et autres messages."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Vos informations personnelles"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Accédez directement aux contacts et à l\'agenda enregistrés sur votre téléphone."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Votre position"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Suivre votre position géographique"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Communications réseau"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Permet à des applications d\'accéder à différentes fonctionnalités du réseau."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Vos comptes Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Accédez aux comptes Google disponibles."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Commandes du matériel"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Permet d\'accéder directement au matériel de l\'appareil."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Appels"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Suivre, enregistrer et traiter les appels téléphoniques"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Outils système"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Accès et contrôle de faible niveau du système."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Outils de développement"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Ces fonctionnalités sont réservées aux développeurs d\'applications."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Stockage"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Accès à la carte SD"</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"Désactivation ou modification de la barre d\'état"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Permet à une application de désactiver la barre d\'état ou d\'ajouter/supprimer des icônes système."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"Agrandir/réduire la barre d\'état"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Permet à l\'application de réduire ou d\'agrandir la barre d\'état."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"Interception d\'appels sortants"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Permet à l\'application de traiter des appels en cours et de modifier le numéro à composer. Des applications malveillantes peuvent suivre, rediriger ou empêcher des appels sortants."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"Réception de SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Permet à une application de recevoir et traiter des messages SMS. Des applications malveillantes peuvent surveiller ou effacer vos messages sans que vous les ayez lus."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"Réception des MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Permet à une application de recevoir et traiter des messages MMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour surveiller ou effacer vos messages sans que vous les ayez lus."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"Envoi de messages SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Permet aux applications d\'envoyer des messages SMS. Des applications malveillantes peuvent entraîner des frais en envoyant des messages sans vous en demander la confirmation."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"Lecture des SMS ou MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Permet à l\'application de lire les SMS enregistrés dans la mémoire de votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent lire vos messages confidentiels."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"Modification de SMS ou de MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Permet à une application de modifier des messages SMS enregistrés sur votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent ainsi supprimer vos messages."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"Réception de WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Permet à l\'application de recevoir et de traiter des messages WAP. Des applications malveillantes peuvent ainsi surveiller vos messages ou les effacer sans que vous en ayez pris connaissance."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"Récupération des applications en cours d\'exécution"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Permet à l\'application de récupérer des informations sur des tâches en cours d\'exécution ou récemment utilisées. Des applications malveillantes peuvent ainsi obtenir des informations d\'ordre privé concernant d\'autres applications."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"Réorganisation des applications en cours d\'exécution"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Permet à une application de placer des tâches au premier plan ou en arrière-plan. Des applications malveillantes peuvent se placer inopinément au premier plan sans votre autorisation."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"Activation du débogage de l\'application"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permet à une application d\'activer le mode de débogage d\'une autre application. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications de façon inopinée."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"Modification des paramètres de l\'IU"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Permet à une application de modifier la configuration actuelle (par ex. : la taille de la police générale ou des paramètres régionaux)."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"Démarrage d\'autres applications"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Permet à une application de forcer le lancement d\'autres applications."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"Fermeture forcée de l\'application"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Permet à une application de forcer une autre application exécutée au premier plan à se fermer et à passer en arrière-plan. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"Vérification de l\'état interne du système"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Permet à l\'application de récupérer l\'état interne du système. Des applications malveillantes peuvent obtenir de nombreuses informations personnelles et sécurisées auxquelles elles ne devraient pas avoir accès."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"arrêt partiel"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Place le gestionnaire d\'activités en état d\'arrêt. N\'effectue pas un arrêt complet."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"empêcher les changements d\'applications"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Empêche l\'utilisateur de changer d\'application."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"Contrôle du lancement des applications"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Permet à une application de suivre et de contrôler la façon dont le système lance des activités. Des applications malveillantes peuvent entièrement déstabiliser le système. Cette autorisation est uniquement nécessaire au développement et non pour l\'utilisation normale du téléphone."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"Envoyer une diffusion sans paquet"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Permet à une application de diffuser une notification lorsqu\'un paquet d\'application a été supprimé. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications en cours d\'exécution."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"Envoyer une diffusion reçue par SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Permet à une application de diffuser une notification lors de la réception d\'un message SMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour falsifier des messages SMS entrants."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Envoi de diffusion de réception de WAP PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Web par des données malveillantes."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"Nombre maximal de processus en cours d\'exécution"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Permet à une application de contrôler le nombre de processus maximal exécutés en même temps. Les applications normales n\'ont jamais recours à cette fonctionnalité."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"Fermeture de toutes les applications en tâche de fond"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Permet à une application de vérifier si des activités sont systématiquement interrompues lorsqu\'elles sont placées en tâche de fond. Cette fonctionnalité n\'est jamais utilisée par les applications normales."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"Modification des statistiques de la batterie"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Autoriser la modification des statistiques de la batterie. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_backup" msgid="470013022865453920">"contrôler la sauvegarde et la restauration du système"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Autorise l\'application à contrôler le mécanisme de sauvegarde et de restauration du système. Ne pas utiliser pour les applications standard."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"Affichage de fenêtres non autorisées"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permet de créer des fenêtres conçues pour l\'interface utilisateur du système interne. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"Affichage d\'alertes système"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Permet à une application d\'afficher des fenêtres d\'alerte système. Des applications malveillantes peuvent masquer la totalité de l\'écran du téléphone."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"Réglage de la vitesse des animations"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Permet à une application de modifier à tout moment la vitesse générale des animations (pour les rendre plus lentes ou plus rapides)."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"Gestion des repères des applications"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Permet à des applications de créer et gérer leurs propres jetons en ignorant leur ordre de plan normal. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"Utilisation des touches ou contrôle des commandes"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Permet à une application de fournir ses propres commandes (touches enfoncées, etc.) à d\'autres applications. Des applications malveillantes peuvent utiliser cette fonctionnalité pour prendre le contrôle de votre téléphone."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"Enregistrer le texte saisi et les actions effectuées"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Permet à des applications d\'identifier les touches sur lesquelles vous appuyez même lorsque vous utilisez une autre application (lors de la saisie d\'un mot de passe, par exemple). Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"Association à un mode de saisie"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permet au support de se connecter à l\'interface de plus haut niveau d\'un mode de saisie. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permet à une application de modifier la rotation de l\'écran à tout moment. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Envoi de signaux Linux aux applications"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permet à une application de demander que le signal fourni soit envoyé à tous les processus persistants."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"Exécution de l\'application en continu"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Permet à une application de perdurer en partie afin que le système ne puisse pas l\'utiliser pour d\'autres applications."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"Supprimer des applications"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Permet à une application de supprimer des paquets de données Android. Des applications malveillantes peuvent utiliser cette fonctionnalité pour supprimer des applications importantes."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"Suppression des données d\'autres applications"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Permet à une application d\'effacer les données de l\'utilisateur."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"Suppression du cache d\'autres applications"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Permet à une application de supprimer des fichiers du cache."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"Évaluation de l\'espace de stockage de l\'application"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Permet à une application de récupérer la taille de son code, de ses données et de son cache."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"Installation directe d\'applications"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Permet à une application d\'installer des nouveaux paquets de données ou des mises à jour Android. Des applications malveillantes peuvent utiliser cette fonctionnalité pour ajouter de nouvelles applications disposant d\'autorisations anormalement élevées."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"Suppression des données du cache de toutes les applications"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permet à une application de libérer de l\'espace dans la mémoire du téléphone en supprimant des fichiers du répertoire du cache des applications. Cet accès est en général limité aux processus système."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"Lecture des fichiers journaux du système"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Permet à une application de lire les différents fichiers journaux du système afin d\'obtenir des informations générales sur la façon dont vous utilisez votre téléphone, sans pour autant récupérer des informations d\'ordre personnel ou privé."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permet à une application de lire et d\'éditer toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers in/dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"Activer ou désactiver des éléments de l\'application"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Web par des données malveillantes."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"Définition des applications préférées"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Permet à une application de modifier vos applications préférées. Des applications malveillantes peuvent utiliser cette fonctionnalité pour modifier discrètement les applications en cours d\'exécution, en imitant vos applications existantes afin de récupérer des données personnelles vous concernant."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"Modification des paramètres généraux du système"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Permet à une application de modifier les données des paramètres système. Des applications malveillantes peuvent utiliser cette fonctionnalité pour endommager la configuration de votre système."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"Modifier les paramètres de sécurité du système"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Permet à une application de modifier les données des paramètres de sécurité du système. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Modification de la carte des services Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Permet à une application de modifier la carte des services Google. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"Lancement automatique au démarrage"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Permet à une application de se lancer dès la fin du démarrage du système. Cela peut rallonger le temps de démarrage requis par le téléphone. L\'application étant alors constamment en cours d\'exécution, le fonctionnement général du téléphone risque d\'être ralenti."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"Envoi d\'une diffusion persistante"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Permet à une application d\'envoyer des diffusions \"persistantes\", qui perdurent après la fin de la diffusion. Des applications malveillantes peuvent ainsi ralentir le téléphone ou le rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"Accès aux données des contacts"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Permet à une application de lire toutes les données des contacts (adresses) enregistrées sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer vos données à d\'autres personnes."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"Édition des données d\'un contact"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Permet à une application de modifier toutes les données de contact (adresses) enregistrées sur le téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier vos données de contact."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"Édition les données du propriétaire"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Permet à une application de modifier les données du propriétaire du téléphone enregistrées sur votre appareil. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier ces données."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"Lecture des données du propriétaire"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Permet à une application de lire les données du propriétaire du téléphone enregistrées sur votre appareil. Des applications malveillantes peuvent utiliser cette fonctionnalité pour lire ces données."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"Lecture des données de l\'agenda"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Permet à une application de lire tous les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"Écriture des données de l\'agenda"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Permet à une application de modifier les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier les données de votre agenda."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"Création de sources de positionnement fictives à des fins de test"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Permet de créer des sources de positionnement fictives à des fins de test. Des applications malveillantes peuvent utiliser cette fonctionnalité pour remplacer la position géographique et/ou l\'état fournis par des sources réelles comme le GPS ou les fournisseurs d\'accès."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Accès aux commandes de fournisseur de position géographique supplémentaires"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Permet d\'accéder à des commandes de fournisseur de position géographique supplémentaires. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interférer avec l\'utilisation du GPS ou d\'autres sources de positionnement géographique."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"autoriser l\'installation d\'un fournisseur de services de localisation"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Créer des sources de données de localisation factices à des fins de test. Les applications malveillantes peuvent exploiter cette fonction pour remplacer la position géographique et/ou l\'état renvoyé par les sources de données de localisation réelles, telles que le GPS ou les fournisseurs réseau, ou pour surveiller et transmettre votre position géographique à une source externe."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"Localisation OK (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Permet d\'accéder à des sources de positionnement précises comme le Global Positioning System (GPS) sur le téléphone, lorsque ces services sont disponibles. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer l\'endroit où vous vous trouvez et augmenter la consommation de la batterie de votre téléphone."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"Position géo. approximative (selon le réseau)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Accès à des sources de positionnement approximatif (par ex. des bases de données de réseaux mobiles) pour déterminer la position géographique du téléphone, lorsque cette option est disponible. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer approximativement l\'endroit où vous vous trouvez."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Accès à SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permet à certaines applications d\'utiliser les fonctionnalités SurfaceFlinger de bas niveau."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Lecture de la mémoire tampon graphique"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Permet aux applications de lire/utiliser le contenu de la mémoire tampon graphique."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Modification de vos paramètres audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Permet à l\'application de modifier les paramètres audio généraux (p. ex. le volume et le routage)."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"Enregistrement de fichier audio"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Permet à l\'application d\'accéder au chemin de l\'enregistrement audio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"Prise de photos"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Permet à l\'application de prendre des clichés avec l\'appareil photo. Cette fonctionnalité permet à l\'application de récupérer à tout moment les images perçues par l\'appareil."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"Désactivation définitive du téléphone"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Permet à l\'application de désactiver définitivement le téléphone. Cette fonctionnalité est très dangereuse."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"Redémarrage forcé du téléphone"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Permet à l\'application de forcer le redémarrage du téléphone."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Monter et démonter des systèmes de fichiers"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permet à l\'application de monter et démonter des systèmes de fichiers pour des périphériques de stockage amovibles."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"Formatage du périphérique de stockage externe"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Permet à l\'application de formater le périphérique de stockage amovible."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"Contrôle du vibreur"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Permet à l\'application de contrôler le vibreur."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"Contrôle de la lampe de poche"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Permet à l\'application de contrôler la lampe de poche."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"Tests du matériel"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Permet à l\'application de contrôler différents périphériques à des fins de test matériel."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"Appel direct des numéros de téléphone"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Permet à l\'application d\'appeler des numéros sans votre intervention. Des applications malveillantes peuvent ainsi passer des appels à votre insu qui s\'ajoutent à votre facture téléphonique. Cette fonctionnalité ne permet pas à l\'application d\'appeler des numéros d\'urgence."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"Appel direct de tout numéro de téléphone"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Permet à une application d\'appeler tout numéro de téléphone (y compris les numéros d\'urgence) sans votre intervention. Des applications malveillantes peuvent passer des appels non nécessaires ou illégitimes à des services d\'urgence."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"Contrôle des notifications de mise à jour de position géo."</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permet l\'activation/la désactivation des notifications de mises à jour de la position géographique provenant du signal radio. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"Accès aux propriétés d\'enregistrement"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Permet un accès en lecture/écriture à des propriétés envoyées par le service d\'inscription. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"choisir les widgets"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Permet à l\'application de signaler au système quels widgets peuvent être utilisés par quelle application. Grâce à cette autorisation, les applications peuvent accorder l\'accès à des données personnelles à d\'autres applications. Cette option n\'est pas utilisée par les applications standard."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"Modification de l\'état du téléphone"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Permet à une application de contrôler les fonctionnalités téléphoniques de l\'appareil. Une application bénéficiant de cette autorisation peut changer de réseau, éteindre et allumer le signal radio du téléphone, etc., sans vous en avertir."</string>
- <string name="permlab_readPhoneState" msgid="2326172951448691631">"Lire l\'état et l\'identité du téléphone"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"Permet à l\'application d\'accéder aux fonctionnalités d\'appel du téléphone. L\'application peut alors déterminer le numéro de téléphone et le numéro de série de l\'appareil, savoir si un appel est en cours, identifier le numéro appelé, etc."</string>
- <string name="permlab_wakeLock" msgid="573480187941496130">"Arrêt du mode veille sur le téléphone"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Permet à une application d\'empêcher votre téléphone de passer en mode veille."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"Éteindre ou allumer le téléphone"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Permet à l\'application d\'éteindre et d\'allumer le téléphone."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"Exécution en mode Test d\'usine"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Permet d\'exécuter en tant que test fabricant de faible niveau en autorisant l\'accès au matériel du téléphone. Cette fonctionnalité est uniquement disponible lorsque le téléphone est en mode de test fabricant."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"Configuration du fond d\'écran"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permet à une application de définir le fond d\'écran du système."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"Sélection de la la taille du fond d\'écran"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Permet à une application de définir la taille du fond d\'écran."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"Réinitialisation du système à ses paramètres d\'usine"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Permet à une application de réinitialiser entièrement le système afin de rétablir ses valeurs d\'usine et d\'effacer toutes les données, configurations et applications installées."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"Sélection du fuseau horaire"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Permet à l\'application de modifier le fuseau horaire du téléphone."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"Identification des comptes connus"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Permet à une application d\'obtenir la liste des comptes connus du téléphone."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"Affichage de l\'état du réseau"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Permet à une application d\'afficher l\'état de tous les réseaux."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"Accès Internet complet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Permet à une application de créer des connecteurs réseau."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"Écriture des paramètres \"Nom des points d\'accès\""</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Permet à une application de modifier les paramètres APN (Nom des points d\'accès), comme le proxy ou le port de tout APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"Modification de la connectivité du réseau"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Permet à une application de modifier la connectivité du réseau."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"modifier le paramètre d\'utilisation des données en arrière-plan"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Permet à une application de modifier le paramètre d\'utilisation des données en arrière-plan."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Affichage de l\'état du Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Permet à une application d\'afficher des informations concernant l\'état du Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Modifier l\'état du Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permet à une application de se connecter à des points d\'accès Wi-Fi, de s\'en déconnecter et de modifier des réseaux Wi-Fi configurés."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"autoriser la réception de données en Wi-Fi multidiffusion"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Autorise une application à recevoir des paquets qui ne sont pas directement adressés à votre mobile. Cela peut être utile pour la recherche de services disponibles à proximité. Consomme plus que le mode non multidiffusion."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Gestion Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permet à une application de configurer le téléphone Bluetooth local, d\'identifier des périphériques distants et de les associer au téléphone."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Création de connexions Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Permet à une application d\'obtenir la configuration du téléphone Bluetooth local et de créer et accepter des connexions à des appareils associés."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"Désactivation du verrouillage des touches"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permet à une application de désactiver le verrouillage des touches et toute sécurité par mot de passe. Exemple : Votre téléphone désactive le verrouillage du clavier lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Lecture des paramètres de synchronisation"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Permet à une application de lire les paramètres de synchronisation (par ex. savoir si la synchronisation est activée pour les Contacts)."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"Écriture des paramètres de synchronisation"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Permet à une application de modifier les paramètres de synchronisation (p. ex. si la synchronisation est activée pour les contacts)."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"Lecture des statistiques de synchronisation"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Permet à une application de lire les statistiques de synchronisation (par ex. l\'historique des synchronisations effectuées)."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"Lecture des flux auxquels vous êtes abonné"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Permet à une application d\'obtenir des informations sur les flux récemment synchronisés."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"Écriture des flux auxquels vous êtes abonné"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Permet à une application de modifier vos flux synchronisés actuels. Cette fonctionnalité peut permettre à des applications malveillantes de modifier vos flux synchronisés."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"Lecture du dictionnaire défini par l\'utilisateur"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Permet à une application de lire tous les mots, noms et expressions que l\'utilisateur a pu enregistrer dans son dictionnaire personnel."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"Enregistrement dans le dictionnaire défini par l\'utilisateur"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Permet à une application d\'enregistrer de nouveaux mots dans le dictionnaire personnel de l\'utilisateur."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"modifier/supprimer le contenu de la carte SD"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Autorise une application à écrire sur la carte SD."</string>
+ <string name="byteShort">"O"</string>
+ <string name="kilobyteShort">"Ko"</string>
+ <string name="megabyteShort">"Mo"</string>
+ <string name="gigabyteShort">"Go"</string>
+ <string name="terabyteShort">"To"</string>
+ <string name="petabyteShort">"Po"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"&lt;sans titre&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Aucun numéro de téléphone)"</string>
+ <string name="unknownName">"(Inconnu)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Messagerie vocale"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problème de connexion ou code IHM non valide."</string>
+ <string name="serviceEnabled">"Le service a été activé."</string>
+ <string name="serviceEnabledFor">"Ce service a été activé pour :"</string>
+ <string name="serviceDisabled">"Ce service a été désactivé."</string>
+ <string name="serviceRegistered">"Enregistrement réussi."</string>
+ <string name="serviceErased">"Effacement réussi."</string>
+ <string name="passwordIncorrect">"Le mot de passe est incorrect."</string>
+ <string name="mmiComplete">"IHM terminée."</string>
+ <string name="badPin">"L\'ancien code PIN saisi est incorrect."</string>
+ <string name="badPuk">"La clé PUK saisie est incorrecte."</string>
+ <string name="mismatchPin">"Les codes PIN saisis ne correspondent pas."</string>
+ <string name="invalidPin">"Le code PIN doit compter de 4 à 8 chiffres."</string>
+ <string name="needPuk">"Votre carte SIM est verrouillée par clé PUK. Saisissez la clé PUK pour la déverrouiller."</string>
+ <string name="needPuk2">"Saisissez la clé PUK2 pour débloquer la carte SIM."</string>
+ <string name="ClipMmi">"Numéro de l\'appelant (entrant)"</string>
+ <string name="ClirMmi">"Numéro de l\'appelant (sortant)"</string>
+ <string name="CfMmi">"Transfert d\'appel"</string>
+ <string name="CwMmi">"Appel en attente"</string>
+ <string name="BaMmi">"Interdiction d\'appel"</string>
+ <string name="PwdMmi">"Modification du mot de passe"</string>
+ <string name="PinMmi">"Modification du code PIN"</string>
+ <string name="CnipMmi">"Présentation du numéro d\'appelant"</string>
+ <string name="CnirMmi">"Numéro de l\'appelant masqué"</string>
+ <string name="ThreeWCMmi">"Conférence téléphonique à trois"</string>
+ <string name="RuacMmi">"Rejeter les appels indésirables"</string>
+ <string name="CndMmi">"Livraison du numéro d\'appel"</string>
+ <string name="DndMmi">"Ne pas déranger"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : restreint"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : restreint"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
+ <string name="serviceNotProvisioned">"Ce service n\'est pas pris en charge."</string>
+ <string name="CLIRPermanent">"Le paramètre Numéro de l\'appelant ne peut pas être modifié."</string>
+ <string name="RestrictedChangedTitle">"L\'accès limité a été modifié."</string>
+ <string name="RestrictedOnData">"Le service de données est bloqué."</string>
+ <string name="RestrictedOnEmergency">"Le service d\'appel d\'urgence est bloqué."</string>
+ <string name="RestrictedOnNormal">"Le service vocal/SMS est bloqué."</string>
+ <string name="RestrictedOnAll">"Tous les services vocaux/SMS sont bloqués."</string>
+ <string name="serviceClassVoice">"Voix"</string>
+ <string name="serviceClassData">"Données"</string>
+ <string name="serviceClassFAX">"Télécopie"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynchrones"</string>
+ <string name="serviceClassDataSync">"Synchrones"</string>
+ <string name="serviceClassPacket">"Paquet"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Indicateur d\'itinérance activé"</string>
+ <string name="roamingText1">"Indicateur d\'itinérance désactivé"</string>
+ <string name="roamingText2">"Indicateur d\'itinérance clignotant"</string>
+ <string name="roamingText3">"Hors zone"</string>
+ <string name="roamingText4">"Hors du bâtiment"</string>
+ <string name="roamingText5">"Itinérance - Système préféré"</string>
+ <string name="roamingText6">"Itinérance - Système disponible"</string>
+ <string name="roamingText7">"Itinérance - Partenaire Alliance"</string>
+ <string name="roamingText8">"Itinérance - Partenaire Premium"</string>
+ <string name="roamingText9">"Itinérance - Tous services disponibles"</string>
+ <string name="roamingText10">"Itinérance - Services partiellement disponibles"</string>
+ <string name="roamingText11">"Bannière d\'itinérance activée"</string>
+ <string name="roamingText12">"Bannière d\'itinérance désactivée"</string>
+ <string name="roamingTextSearching">"Recherche des services disponibles"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g> au bout de <xliff:g id="TIME_DELAY">{2}</xliff:g> secondes"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
+ <string name="fcComplete">"Code de service terminé"</string>
+ <string name="fcError">"Problème de connexion ou code de service non valide"</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"La page Web contient une erreur."</string>
+ <string name="httpErrorLookup">"URL introuvable."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Le modèle d\'authentification du site n\'est pas pris en charge."</string>
+ <string name="httpErrorAuth">"Échec de l\'authentification."</string>
+ <string name="httpErrorProxyAuth">"Échec de l\'authentification par un serveur proxy."</string>
+ <string name="httpErrorConnect">"Échec de la connexion au serveur."</string>
+ <string name="httpErrorIO">"Échec de la communication avec le serveur. Veuillez réessayer ultérieurement."</string>
+ <string name="httpErrorTimeout">"Délai de connexion au serveur dépassé."</string>
+ <string name="httpErrorRedirectLoop">"Cette page contient trop de redirections de serveurs."</string>
+ <string name="httpErrorUnsupportedScheme">"Ce protocole n\'est pas pris en charge."</string>
+ <string name="httpErrorFailedSslHandshake">"Aucune connexion sécurisée n\'a pu être établie."</string>
+ <string name="httpErrorBadUrl">"Impossible d\'ouvrir cette page. L\'URL n\'est pas correcte."</string>
+ <string name="httpErrorFile">"Impossible d\'accéder au fichier."</string>
+ <string name="httpErrorFileNotFound">"Le fichier demandé est introuvable."</string>
+ <string name="httpErrorTooManyRequests">"Trop de requêtes sont en cours de traitement. Veuillez réessayer ultérieurement."</string>
+ <string name="contentServiceSync">"Synchroniser"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchronisation"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
+ <string name="low_memory">"La mémoire du téléphone est pleine ! Supprimez des fichiers pour libérer de l\'espace."</string>
+ <string name="me">"Moi"</string>
+ <string name="power_dialog">"Options du téléphone"</string>
+ <string name="silent_mode">"Mode silencieux"</string>
+ <string name="turn_on_radio">"Activer le mode sans fil"</string>
+ <string name="turn_off_radio">"Désactiver le mode sans fil"</string>
+ <string name="screen_lock">"Verrouillage de l\'écran"</string>
+ <string name="power_off">"Éteindre"</string>
+ <string name="shutdown_progress">"Arrêt en cours..."</string>
+ <string name="shutdown_confirm">"Votre téléphone va s\'éteindre."</string>
+ <string name="no_recent_tasks">"Aucune application récente"</string>
+ <string name="global_actions">"Options du téléphone"</string>
+ <string name="global_action_lock">"Verrouillage de l\'écran"</string>
+ <string name="global_action_power_off">"Éteindre"</string>
+ <string name="global_action_toggle_silent_mode">"Mode silencieux"</string>
+ <string name="global_action_silent_mode_on_status">"Le son est désactivé."</string>
+ <string name="global_action_silent_mode_off_status">"Le son est activé."</string>
+ <string name="global_actions_toggle_airplane_mode">"Mode Avion"</string>
+ <string name="global_actions_airplane_mode_on_status">"Le mode Avion est activé."</string>
+ <string name="global_actions_airplane_mode_off_status">"Le mode Avion est désactivé."</string>
+ <string name="safeMode">"Mode sécurisé"</string>
+ <string name="android_system_label">"Système Android"</string>
+ <string name="permgrouplab_costMoney">"Services payants"</string>
+ <string name="permgroupdesc_costMoney">"Permet aux applications d\'effectuer des opérations payantes."</string>
+ <string name="permgrouplab_messages">"Vos messages"</string>
+ <string name="permgroupdesc_messages">"Permet de lire et rédiger vos SMS, e-mails et autres messages."</string>
+ <string name="permgrouplab_personalInfo">"Vos informations personnelles"</string>
+ <string name="permgroupdesc_personalInfo">"Accédez directement aux contacts et à l\'agenda enregistrés sur votre téléphone."</string>
+ <string name="permgrouplab_location">"Votre position"</string>
+ <string name="permgroupdesc_location">"Suivre votre position géographique"</string>
+ <string name="permgrouplab_network">"Communications réseau"</string>
+ <string name="permgroupdesc_network">"Permet à des applications d\'accéder à différentes fonctionnalités du réseau."</string>
+ <string name="permgrouplab_accounts">"Vos comptes Google"</string>
+ <string name="permgroupdesc_accounts">"Accédez aux comptes Google disponibles."</string>
+ <string name="permgrouplab_hardwareControls">"Commandes du matériel"</string>
+ <string name="permgroupdesc_hardwareControls">"Permet d\'accéder directement au matériel de l\'appareil."</string>
+ <string name="permgrouplab_phoneCalls">"Appels"</string>
+ <string name="permgroupdesc_phoneCalls">"Suivre, enregistrer et traiter les appels téléphoniques"</string>
+ <string name="permgrouplab_systemTools">"Outils système"</string>
+ <string name="permgroupdesc_systemTools">"Accès et contrôle de faible niveau du système."</string>
+ <string name="permgrouplab_developmentTools">"Outils de développement"</string>
+ <string name="permgroupdesc_developmentTools">"Ces fonctionnalités sont réservées aux développeurs d\'applications."</string>
+ <string name="permgrouplab_storage">"Stockage"</string>
+ <string name="permgroupdesc_storage">"Accès à la carte SD"</string>
+ <string name="permlab_statusBar">"Désactivation ou modification de la barre d\'état"</string>
+ <string name="permdesc_statusBar">"Permet à une application de désactiver la barre d\'état ou d\'ajouter/supprimer des icônes système."</string>
+ <string name="permlab_expandStatusBar">"Agrandir/réduire la barre d\'état"</string>
+ <string name="permdesc_expandStatusBar">"Permet à l\'application de réduire ou d\'agrandir la barre d\'état."</string>
+ <string name="permlab_processOutgoingCalls">"Interception d\'appels sortants"</string>
+ <string name="permdesc_processOutgoingCalls">"Permet à l\'application de traiter des appels en cours et de modifier le numéro à composer. Des applications malveillantes peuvent suivre, rediriger ou empêcher des appels sortants."</string>
+ <string name="permlab_receiveSms">"Réception de SMS"</string>
+ <string name="permdesc_receiveSms">"Permet à une application de recevoir et traiter des messages SMS. Des applications malveillantes peuvent surveiller ou effacer vos messages sans que vous les ayez lus."</string>
+ <string name="permlab_receiveMms">"Réception des MMS"</string>
+ <string name="permdesc_receiveMms">"Permet à une application de recevoir et traiter des messages MMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour surveiller ou effacer vos messages sans que vous les ayez lus."</string>
+ <string name="permlab_sendSms">"Envoi de messages SMS"</string>
+ <string name="permdesc_sendSms">"Permet aux applications d\'envoyer des messages SMS. Des applications malveillantes peuvent entraîner des frais en envoyant des messages sans vous en demander la confirmation."</string>
+ <string name="permlab_readSms">"Lecture des SMS ou MMS"</string>
+ <string name="permdesc_readSms">"Permet à l\'application de lire les SMS enregistrés dans la mémoire de votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent lire vos messages confidentiels."</string>
+ <string name="permlab_writeSms">"Modification de SMS ou de MMS"</string>
+ <string name="permdesc_writeSms">"Permet à une application de modifier des messages SMS enregistrés sur votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent ainsi supprimer vos messages."</string>
+ <string name="permlab_receiveWapPush">"Réception de WAP"</string>
+ <string name="permdesc_receiveWapPush">"Permet à l\'application de recevoir et de traiter des messages WAP. Des applications malveillantes peuvent ainsi surveiller vos messages ou les effacer sans que vous en ayez pris connaissance."</string>
+ <string name="permlab_getTasks">"Récupération des applications en cours d\'exécution"</string>
+ <string name="permdesc_getTasks">"Permet à l\'application de récupérer des informations sur des tâches en cours d\'exécution ou récemment utilisées. Des applications malveillantes peuvent ainsi obtenir des informations d\'ordre privé concernant d\'autres applications."</string>
+ <string name="permlab_reorderTasks">"Réorganisation des applications en cours d\'exécution"</string>
+ <string name="permdesc_reorderTasks">"Permet à une application de placer des tâches au premier plan ou en arrière-plan. Des applications malveillantes peuvent se placer inopinément au premier plan sans votre autorisation."</string>
+ <string name="permlab_setDebugApp">"Activation du débogage de l\'application"</string>
+ <string name="permdesc_setDebugApp">"Permet à une application d\'activer le mode de débogage d\'une autre application. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications de façon inopinée."</string>
+ <string name="permlab_changeConfiguration">"Modification des paramètres de l\'IU"</string>
+ <string name="permdesc_changeConfiguration">"Permet à une application de modifier la configuration actuelle (par ex. : la taille de la police générale ou des paramètres régionaux)."</string>
+ <string name="permlab_restartPackages">"Démarrage d\'autres applications"</string>
+ <string name="permdesc_restartPackages">"Permet à une application de forcer le lancement d\'autres applications."</string>
+ <string name="permlab_forceBack">"Fermeture forcée de l\'application"</string>
+ <string name="permdesc_forceBack">"Permet à une application de forcer une autre application exécutée au premier plan à se fermer et à passer en arrière-plan. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_dump">"Vérification de l\'état interne du système"</string>
+ <string name="permdesc_dump">"Permet à l\'application de récupérer l\'état interne du système. Des applications malveillantes peuvent obtenir de nombreuses informations personnelles et sécurisées auxquelles elles ne devraient pas avoir accès."</string>
+ <string name="permlab_shutdown">"arrêt partiel"</string>
+ <string name="permdesc_shutdown">"Place le gestionnaire d\'activités en état d\'arrêt. N\'effectue pas un arrêt complet."</string>
+ <string name="permlab_stopAppSwitches">"empêcher les changements d\'applications"</string>
+ <string name="permdesc_stopAppSwitches">"Empêche l\'utilisateur de changer d\'application."</string>
+ <string name="permlab_runSetActivityWatcher">"Contrôle du lancement des applications"</string>
+ <string name="permdesc_runSetActivityWatcher">"Permet à une application de suivre et de contrôler la façon dont le système lance des activités. Des applications malveillantes peuvent entièrement déstabiliser le système. Cette autorisation est uniquement nécessaire au développement et non pour l\'utilisation normale du téléphone."</string>
+ <string name="permlab_broadcastPackageRemoved">"Envoyer une diffusion sans paquet"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Permet à une application de diffuser une notification lorsqu\'un paquet d\'application a été supprimé. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications en cours d\'exécution."</string>
+ <string name="permlab_broadcastSmsReceived">"Envoyer une diffusion reçue par SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Permet à une application de diffuser une notification lors de la réception d\'un message SMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour falsifier des messages SMS entrants."</string>
+ <string name="permlab_broadcastWapPush">"Envoi de diffusion de réception de WAP PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Web par des données malveillantes."</string>
+ <string name="permlab_setProcessLimit">"Nombre maximal de processus en cours d\'exécution"</string>
+ <string name="permdesc_setProcessLimit">"Permet à une application de contrôler le nombre de processus maximal exécutés en même temps. Les applications normales n\'ont jamais recours à cette fonctionnalité."</string>
+ <string name="permlab_setAlwaysFinish">"Fermeture de toutes les applications en tâche de fond"</string>
+ <string name="permdesc_setAlwaysFinish">"Permet à une application de vérifier si des activités sont systématiquement interrompues lorsqu\'elles sont placées en tâche de fond. Cette fonctionnalité n\'est jamais utilisée par les applications normales."</string>
+ <string name="permlab_batteryStats">"Modification des statistiques de la batterie"</string>
+ <string name="permdesc_batteryStats">"Autoriser la modification des statistiques de la batterie. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_backup">"contrôler la sauvegarde et la restauration du système"</string>
+ <string name="permdesc_backup">"Autorise l\'application à contrôler le mécanisme de sauvegarde et de restauration du système. Ne pas utiliser pour les applications standard."</string>
+ <string name="permlab_internalSystemWindow">"Affichage de fenêtres non autorisées"</string>
+ <string name="permdesc_internalSystemWindow">"Permet de créer des fenêtres conçues pour l\'interface utilisateur du système interne. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_systemAlertWindow">"Affichage d\'alertes système"</string>
+ <string name="permdesc_systemAlertWindow">"Permet à une application d\'afficher des fenêtres d\'alerte système. Des applications malveillantes peuvent masquer la totalité de l\'écran du téléphone."</string>
+ <string name="permlab_setAnimationScale">"Réglage de la vitesse des animations"</string>
+ <string name="permdesc_setAnimationScale">"Permet à une application de modifier à tout moment la vitesse générale des animations (pour les rendre plus lentes ou plus rapides)."</string>
+ <string name="permlab_manageAppTokens">"Gestion des repères des applications"</string>
+ <string name="permdesc_manageAppTokens">"Permet à des applications de créer et gérer leurs propres jetons en ignorant leur ordre de plan normal. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_injectEvents">"Utilisation des touches ou contrôle des commandes"</string>
+ <string name="permdesc_injectEvents">"Permet à une application de fournir ses propres commandes (touches enfoncées, etc.) à d\'autres applications. Des applications malveillantes peuvent utiliser cette fonctionnalité pour prendre le contrôle de votre téléphone."</string>
+ <string name="permlab_readInputState">"Enregistrer le texte saisi et les actions effectuées"</string>
+ <string name="permdesc_readInputState">"Permet à des applications d\'identifier les touches sur lesquelles vous appuyez même lorsque vous utilisez une autre application (lors de la saisie d\'un mot de passe, par exemple). Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_bindInputMethod">"Association à un mode de saisie"</string>
+ <string name="permdesc_bindInputMethod">"Permet au support de se connecter à l\'interface de plus haut niveau d\'un mode de saisie. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_setOrientation">"Changement d\'orientation de l\'écran"</string>
+ <string name="permdesc_setOrientation">"Permet à une application de modifier la rotation de l\'écran à tout moment. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_signalPersistentProcesses">"Envoi de signaux Linux aux applications"</string>
+ <string name="permdesc_signalPersistentProcesses">"Permet à une application de demander que le signal fourni soit envoyé à tous les processus persistants."</string>
+ <string name="permlab_persistentActivity">"Exécution de l\'application en continu"</string>
+ <string name="permdesc_persistentActivity">"Permet à une application de perdurer en partie afin que le système ne puisse pas l\'utiliser pour d\'autres applications."</string>
+ <string name="permlab_deletePackages">"Supprimer des applications"</string>
+ <string name="permdesc_deletePackages">"Permet à une application de supprimer des paquets de données Android. Des applications malveillantes peuvent utiliser cette fonctionnalité pour supprimer des applications importantes."</string>
+ <string name="permlab_clearAppUserData">"Suppression des données d\'autres applications"</string>
+ <string name="permdesc_clearAppUserData">"Permet à une application d\'effacer les données de l\'utilisateur."</string>
+ <string name="permlab_deleteCacheFiles">"Suppression du cache d\'autres applications"</string>
+ <string name="permdesc_deleteCacheFiles">"Permet à une application de supprimer des fichiers du cache."</string>
+ <string name="permlab_getPackageSize">"Évaluation de l\'espace de stockage de l\'application"</string>
+ <string name="permdesc_getPackageSize">"Permet à une application de récupérer la taille de son code, de ses données et de son cache."</string>
+ <string name="permlab_installPackages">"Installation directe d\'applications"</string>
+ <string name="permdesc_installPackages">"Permet à une application d\'installer des nouveaux paquets de données ou des mises à jour Android. Des applications malveillantes peuvent utiliser cette fonctionnalité pour ajouter de nouvelles applications disposant d\'autorisations anormalement élevées."</string>
+ <string name="permlab_clearAppCache">"Suppression des données du cache de toutes les applications"</string>
+ <string name="permdesc_clearAppCache">"Permet à une application de libérer de l\'espace dans la mémoire du téléphone en supprimant des fichiers du répertoire du cache des applications. Cet accès est en général limité aux processus système."</string>
+ <string name="permlab_readLogs">"Lecture des fichiers journaux du système"</string>
+ <string name="permdesc_readLogs">"Permet à une application de lire les différents fichiers journaux du système afin d\'obtenir des informations générales sur la façon dont vous utilisez votre téléphone, sans pour autant récupérer des informations d\'ordre personnel ou privé."</string>
+ <string name="permlab_diagnostic">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
+ <string name="permdesc_diagnostic">"Permet à une application de lire et d\'éditer toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers in/dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
+ <string name="permlab_changeComponentState">"Activer ou désactiver des éléments de l\'application"</string>
+ <string name="permdesc_changeComponentState">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Web par des données malveillantes."</string>
+ <string name="permlab_setPreferredApplications">"Définition des applications préférées"</string>
+ <string name="permdesc_setPreferredApplications">"Permet à une application de modifier vos applications préférées. Des applications malveillantes peuvent utiliser cette fonctionnalité pour modifier discrètement les applications en cours d\'exécution, en imitant vos applications existantes afin de récupérer des données personnelles vous concernant."</string>
+ <string name="permlab_writeSettings">"Modification des paramètres généraux du système"</string>
+ <string name="permdesc_writeSettings">"Permet à une application de modifier les données des paramètres système. Des applications malveillantes peuvent utiliser cette fonctionnalité pour endommager la configuration de votre système."</string>
+ <string name="permlab_writeSecureSettings">"Modifier les paramètres de sécurité du système"</string>
+ <string name="permdesc_writeSecureSettings">"Permet à une application de modifier les données des paramètres de sécurité du système. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_writeGservices">"Modification de la carte des services Google"</string>
+ <string name="permdesc_writeGservices">"Permet à une application de modifier la carte des services Google. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_receiveBootCompleted">"Lancement automatique au démarrage"</string>
+ <string name="permdesc_receiveBootCompleted">"Permet à une application de se lancer dès la fin du démarrage du système. Cela peut rallonger le temps de démarrage requis par le téléphone. L\'application étant alors constamment en cours d\'exécution, le fonctionnement général du téléphone risque d\'être ralenti."</string>
+ <string name="permlab_broadcastSticky">"Envoi d\'une diffusion persistante"</string>
+ <string name="permdesc_broadcastSticky">"Permet à une application d\'envoyer des diffusions \"persistantes\", qui perdurent après la fin de la diffusion. Des applications malveillantes peuvent ainsi ralentir le téléphone ou le rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
+ <string name="permlab_readContacts">"Accès aux données des contacts"</string>
+ <string name="permdesc_readContacts">"Permet à une application de lire toutes les données des contacts (adresses) enregistrées sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer vos données à d\'autres personnes."</string>
+ <string name="permlab_writeContacts">"Édition des données d\'un contact"</string>
+ <string name="permdesc_writeContacts">"Permet à une application de modifier toutes les données de contact (adresses) enregistrées sur le téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier vos données de contact."</string>
+ <string name="permlab_writeOwnerData">"Édition les données du propriétaire"</string>
+ <string name="permdesc_writeOwnerData">"Permet à une application de modifier les données du propriétaire du téléphone enregistrées sur votre appareil. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier ces données."</string>
+ <string name="permlab_readOwnerData">"Lecture des données du propriétaire"</string>
+ <string name="permdesc_readOwnerData">"Permet à une application de lire les données du propriétaire du téléphone enregistrées sur votre appareil. Des applications malveillantes peuvent utiliser cette fonctionnalité pour lire ces données."</string>
+ <string name="permlab_readCalendar">"Lecture des données de l\'agenda"</string>
+ <string name="permdesc_readCalendar">"Permet à une application de lire tous les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
+ <string name="permlab_writeCalendar">"Écriture des données de l\'agenda"</string>
+ <string name="permdesc_writeCalendar">"Permet à une application de modifier les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier les données de votre agenda."</string>
+ <string name="permlab_accessMockLocation">"Création de sources de positionnement fictives à des fins de test"</string>
+ <string name="permdesc_accessMockLocation">"Permet de créer des sources de positionnement fictives à des fins de test. Des applications malveillantes peuvent utiliser cette fonctionnalité pour remplacer la position géographique et/ou l\'état fournis par des sources réelles comme le GPS ou les fournisseurs d\'accès."</string>
+ <string name="permlab_accessLocationExtraCommands">"Accès aux commandes de fournisseur de position géographique supplémentaires"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Permet d\'accéder à des commandes de fournisseur de position géographique supplémentaires. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interférer avec l\'utilisation du GPS ou d\'autres sources de positionnement géographique."</string>
+ <string name="permlab_installLocationProvider">"autoriser l\'installation d\'un fournisseur de services de localisation"</string>
+ <string name="permdesc_installLocationProvider">"Créer des sources de données de localisation factices à des fins de test. Les applications malveillantes peuvent exploiter cette fonction pour remplacer la position géographique et/ou l\'état renvoyé par les sources de données de localisation réelles, telles que le GPS ou les fournisseurs réseau, ou pour surveiller et transmettre votre position géographique à une source externe."</string>
+ <string name="permlab_accessFineLocation">"Localisation OK (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Permet d\'accéder à des sources de positionnement précises comme le Global Positioning System (GPS) sur le téléphone, lorsque ces services sont disponibles. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer l\'endroit où vous vous trouvez et augmenter la consommation de la batterie de votre téléphone."</string>
+ <string name="permlab_accessCoarseLocation">"Position géo. approximative (selon le réseau)"</string>
+ <string name="permdesc_accessCoarseLocation">"Accès à des sources de positionnement approximatif (par ex. des bases de données de réseaux mobiles) pour déterminer la position géographique du téléphone, lorsque cette option est disponible. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer approximativement l\'endroit où vous vous trouvez."</string>
+ <string name="permlab_accessSurfaceFlinger">"Accès à SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Permet à certaines applications d\'utiliser les fonctionnalités SurfaceFlinger de bas niveau."</string>
+ <string name="permlab_readFrameBuffer">"Lecture de la mémoire tampon graphique"</string>
+ <string name="permdesc_readFrameBuffer">"Permet aux applications de lire/utiliser le contenu de la mémoire tampon graphique."</string>
+ <string name="permlab_modifyAudioSettings">"Modification de vos paramètres audio"</string>
+ <string name="permdesc_modifyAudioSettings">"Permet à l\'application de modifier les paramètres audio généraux (p. ex. le volume et le routage)."</string>
+ <string name="permlab_recordAudio">"Enregistrement de fichier audio"</string>
+ <string name="permdesc_recordAudio">"Permet à l\'application d\'accéder au chemin de l\'enregistrement audio."</string>
+ <string name="permlab_camera">"Prise de photos"</string>
+ <string name="permdesc_camera">"Permet à l\'application de prendre des clichés avec l\'appareil photo. Cette fonctionnalité permet à l\'application de récupérer à tout moment les images perçues par l\'appareil."</string>
+ <string name="permlab_brick">"Désactivation définitive du téléphone"</string>
+ <string name="permdesc_brick">"Permet à l\'application de désactiver définitivement le téléphone. Cette fonctionnalité est très dangereuse."</string>
+ <string name="permlab_reboot">"Redémarrage forcé du téléphone"</string>
+ <string name="permdesc_reboot">"Permet à l\'application de forcer le redémarrage du téléphone."</string>
+ <string name="permlab_mount_unmount_filesystems">"Monter et démonter des systèmes de fichiers"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Permet à l\'application de monter et démonter des systèmes de fichiers pour des périphériques de stockage amovibles."</string>
+ <string name="permlab_mount_format_filesystems">"Formatage du périphérique de stockage externe"</string>
+ <string name="permdesc_mount_format_filesystems">"Permet à l\'application de formater le périphérique de stockage amovible."</string>
+ <string name="permlab_vibrate">"Contrôle du vibreur"</string>
+ <string name="permdesc_vibrate">"Permet à l\'application de contrôler le vibreur."</string>
+ <string name="permlab_flashlight">"Contrôle de la lampe de poche"</string>
+ <string name="permdesc_flashlight">"Permet à l\'application de contrôler la lampe de poche."</string>
+ <string name="permlab_hardware_test">"Tests du matériel"</string>
+ <string name="permdesc_hardware_test">"Permet à l\'application de contrôler différents périphériques à des fins de test matériel."</string>
+ <string name="permlab_callPhone">"Appel direct des numéros de téléphone"</string>
+ <string name="permdesc_callPhone">"Permet à l\'application d\'appeler des numéros sans votre intervention. Des applications malveillantes peuvent ainsi passer des appels à votre insu qui s\'ajoutent à votre facture téléphonique. Cette fonctionnalité ne permet pas à l\'application d\'appeler des numéros d\'urgence."</string>
+ <string name="permlab_callPrivileged">"Appel direct de tout numéro de téléphone"</string>
+ <string name="permdesc_callPrivileged">"Permet à une application d\'appeler tout numéro de téléphone (y compris les numéros d\'urgence) sans votre intervention. Des applications malveillantes peuvent passer des appels non nécessaires ou illégitimes à des services d\'urgence."</string>
+ <string name="permlab_locationUpdates">"Contrôle des notifications de mise à jour de position géo."</string>
+ <string name="permdesc_locationUpdates">"Permet l\'activation/la désactivation des notifications de mises à jour de la position géographique provenant du signal radio. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_checkinProperties">"Accès aux propriétés d\'enregistrement"</string>
+ <string name="permdesc_checkinProperties">"Permet un accès en lecture/écriture à des propriétés envoyées par le service d\'inscription. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
+ <string name="permlab_bindGadget">"choisir les widgets"</string>
+ <string name="permdesc_bindGadget">"Permet à l\'application de signaler au système quels widgets peuvent être utilisés par quelle application. Grâce à cette autorisation, les applications peuvent accorder l\'accès à des données personnelles à d\'autres applications. Cette option n\'est pas utilisée par les applications standard."</string>
+ <string name="permlab_modifyPhoneState">"Modification de l\'état du téléphone"</string>
+ <string name="permdesc_modifyPhoneState">"Permet à une application de contrôler les fonctionnalités téléphoniques de l\'appareil. Une application bénéficiant de cette autorisation peut changer de réseau, éteindre et allumer le signal radio du téléphone, etc., sans vous en avertir."</string>
+ <string name="permlab_readPhoneState">"Lecture de l\'état du téléphone"</string>
+ <string name="permdesc_readPhoneState">"Permet à l\'application d\'accéder aux fonctionnalités d\'appel du téléphone. L\'application peut alors déterminer le numéro de téléphone de l\'appareil, savoir si un appel est en cours, identifier le numéro appelé, etc."</string>
+ <string name="permlab_wakeLock">"Arrêt du mode veille sur le téléphone"</string>
+ <string name="permdesc_wakeLock">"Permet à une application d\'empêcher votre téléphone de passer en mode veille."</string>
+ <string name="permlab_devicePower">"Éteindre ou allumer le téléphone"</string>
+ <string name="permdesc_devicePower">"Permet à l\'application d\'éteindre et d\'allumer le téléphone."</string>
+ <string name="permlab_factoryTest">"Exécution en mode Test d\'usine"</string>
+ <string name="permdesc_factoryTest">"Permet d\'exécuter en tant que test fabricant de faible niveau en autorisant l\'accès au matériel du téléphone. Cette fonctionnalité est uniquement disponible lorsque le téléphone est en mode de test fabricant."</string>
+ <string name="permlab_setWallpaper">"Configuration du fond d\'écran"</string>
+ <string name="permdesc_setWallpaper">"Permet à une application de définir le fond d\'écran du système."</string>
+ <string name="permlab_setWallpaperHints">"Sélection de la la taille du fond d\'écran"</string>
+ <string name="permdesc_setWallpaperHints">"Permet à une application de définir la taille du fond d\'écran."</string>
+ <string name="permlab_masterClear">"Réinitialisation du système à ses paramètres d\'usine"</string>
+ <string name="permdesc_masterClear">"Permet à une application de réinitialiser entièrement le système afin de rétablir ses valeurs d\'usine et d\'effacer toutes les données, configurations et applications installées."</string>
+ <string name="permlab_setTimeZone">"Sélection du fuseau horaire"</string>
+ <string name="permdesc_setTimeZone">"Permet à l\'application de modifier le fuseau horaire du téléphone."</string>
+ <string name="permlab_getAccounts">"Identification des comptes connus"</string>
+ <string name="permdesc_getAccounts">"Permet à une application d\'obtenir la liste des comptes connus du téléphone."</string>
+ <string name="permlab_accessNetworkState">"Affichage de l\'état du réseau"</string>
+ <string name="permdesc_accessNetworkState">"Permet à une application d\'afficher l\'état de tous les réseaux."</string>
+ <string name="permlab_createNetworkSockets">"Accès Internet complet"</string>
+ <string name="permdesc_createNetworkSockets">"Permet à une application de créer des connecteurs réseau."</string>
+ <string name="permlab_writeApnSettings">"Écriture des paramètres \"Nom des points d\'accès\""</string>
+ <string name="permdesc_writeApnSettings">"Permet à une application de modifier les paramètres APN (Nom des points d\'accès), comme le proxy ou le port de tout APN."</string>
+ <string name="permlab_changeNetworkState">"Modification de la connectivité du réseau"</string>
+ <string name="permdesc_changeNetworkState">"Permet à une application de modifier la connectivité du réseau."</string>
+ <string name="permlab_changeBackgroundDataSetting">"modifier le paramètre d\'utilisation des données en arrière-plan"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Permet à une application de modifier le paramètre d\'utilisation des données en arrière-plan."</string>
+ <string name="permlab_accessWifiState">"Affichage de l\'état du Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Permet à une application d\'afficher des informations concernant l\'état du Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"Modifier l\'état du Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Permet à une application de se connecter à des points d\'accès Wi-Fi, de s\'en déconnecter et de modifier des réseaux Wi-Fi configurés."</string>
+ <string name="permlab_changeWifiMulticastState">"autoriser la réception de données en Wi-Fi multidiffusion"</string>
+ <string name="permdesc_changeWifiMulticastState">"Autorise une application à recevoir des paquets qui ne sont pas directement adressés à votre mobile. Cela peut être utile pour la recherche de services disponibles à proximité. Consomme plus que le mode non multidiffusion."</string>
+ <string name="permlab_bluetoothAdmin">"Gestion Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Permet à une application de configurer le téléphone Bluetooth local, d\'identifier des périphériques distants et de les associer au téléphone."</string>
+ <string name="permlab_bluetooth">"Création de connexions Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Permet à une application d\'obtenir la configuration du téléphone Bluetooth local et de créer et accepter des connexions à des appareils associés."</string>
+ <string name="permlab_disableKeyguard">"Désactivation du verrouillage des touches"</string>
+ <string name="permdesc_disableKeyguard">"Permet à une application de désactiver le verrouillage des touches et toute sécurité par mot de passe. Exemple : Votre téléphone désactive le verrouillage du clavier lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
+ <string name="permlab_readSyncSettings">"Lecture des paramètres de synchronisation"</string>
+ <string name="permdesc_readSyncSettings">"Permet à une application de lire les paramètres de synchronisation (par ex. savoir si la synchronisation est activée pour les Contacts)."</string>
+ <string name="permlab_writeSyncSettings">"Écriture des paramètres de synchronisation"</string>
+ <string name="permdesc_writeSyncSettings">"Permet à une application de modifier les paramètres de synchronisation (p. ex. si la synchronisation est activée pour les contacts)."</string>
+ <string name="permlab_readSyncStats">"Lecture des statistiques de synchronisation"</string>
+ <string name="permdesc_readSyncStats">"Permet à une application de lire les statistiques de synchronisation (par ex. l\'historique des synchronisations effectuées)."</string>
+ <string name="permlab_subscribedFeedsRead">"Lecture des flux auxquels vous êtes abonné"</string>
+ <string name="permdesc_subscribedFeedsRead">"Permet à une application d\'obtenir des informations sur les flux récemment synchronisés."</string>
+ <string name="permlab_subscribedFeedsWrite">"Écriture des flux auxquels vous êtes abonné"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Permet à une application de modifier vos flux synchronisés actuels. Cette fonctionnalité peut permettre à des applications malveillantes de modifier vos flux synchronisés."</string>
+ <string name="permlab_readDictionary">"Lecture du dictionnaire défini par l\'utilisateur"</string>
+ <string name="permdesc_readDictionary">"Permet à une application de lire tous les mots, noms et expressions que l\'utilisateur a pu enregistrer dans son dictionnaire personnel."</string>
+ <string name="permlab_writeDictionary">"Enregistrement dans le dictionnaire défini par l\'utilisateur"</string>
+ <string name="permdesc_writeDictionary">"Permet à une application d\'enregistrer de nouveaux mots dans le dictionnaire personnel de l\'utilisateur."</string>
+ <string name="permlab_sdcardWrite">"modifier/supprimer le contenu de la carte SD"</string>
+ <string name="permdesc_sdcardWrite">"Autorise une application à écrire sur la carte SD."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Domicile"</item>
- <item msgid="869923650527136615">"Portable"</item>
- <item msgid="7897544654242874543">"Bureau"</item>
- <item msgid="1103601433382158155">"Télécopie bureau"</item>
- <item msgid="1735177144948329370">"Télécopie domicile"</item>
- <item msgid="603878674477207394">"Récepteur d\'appel"</item>
- <item msgid="1650824275177931637">"Autre"</item>
- <item msgid="9192514806975898961">"Personnalisé"</item>
+ <item>"Domicile"</item>
+ <item>"Portable"</item>
+ <item>"Bureau"</item>
+ <item>"Télécopie bureau"</item>
+ <item>"Télécopie domicile"</item>
+ <item>"Récepteur d\'appel"</item>
+ <item>"Autre"</item>
+ <item>"Personnalisé"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Domicile"</item>
- <item msgid="7084237356602625604">"Bureau"</item>
- <item msgid="1112044410659011023">"Autre"</item>
- <item msgid="2374913952870110618">"Personnalisée"</item>
+ <item>"Domicile"</item>
+ <item>"Bureau"</item>
+ <item>"Autre"</item>
+ <item>"Personnalisée"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobile"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Domicile"</item>
- <item msgid="5629153956045109251">"Bureau"</item>
- <item msgid="4966604264500343469">"Autre"</item>
- <item msgid="4932682847595299369">"Personnalisée"</item>
+ <item>"Domicile"</item>
+ <item>"Bureau"</item>
+ <item>"Autre"</item>
+ <item>"Personnalisée"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Domicile"</item>
- <item msgid="1359644565647383708">"Bureau"</item>
- <item msgid="7868549401053615677">"Autre"</item>
- <item msgid="3145118944639869809">"Personnalisé"</item>
+ <item>"Domicile"</item>
+ <item>"Bureau"</item>
+ <item>"Autre"</item>
+ <item>"Personnalisé"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Bureau"</item>
- <item msgid="4378074129049520373">"Autre"</item>
- <item msgid="3455047468583965104">"Personnalisée"</item>
+ <item>"Bureau"</item>
+ <item>"Autre"</item>
+ <item>"Personnalisée"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Saisissez le code PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Le code PIN est incorrect !"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Pour débloquer le clavier, appuyez sur \"Menu\" puis sur 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numéro d\'urgence"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Aucun service)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Écran verrouillé"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence"</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Dessinez un schéma pour déverrouiller le téléphone"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Appel d\'urgence"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Combinaison correcte !"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Désolé. Merci de réessayer."</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Chargement (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Chargé"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Branchez votre chargeur."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Aucune carte SIM n\'a été trouvée."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Insérez une carte SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Réseau verrouillé"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La carte SIM est verrouillée par clé PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Veuillez consulter le guide d\'utilisation ou contacter l\'assistance clientèle."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La carte SIM est verrouillée."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Déblocage de la carte SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Vous avez mal reproduit le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Vous avez mal saisi le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> tentatives supplémentaires, vous devrez débloquer votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Schéma oublié ?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Trop de tentatives !"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Pour déverrouiller le téléphone, connectez-vous à l\'aide de votre compte Google."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nom d\'utilisateur (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Mot de passe"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Se connecter"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nom d\'utilisateur ou mot de passe incorrect."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Effacer"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Aucune notification"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Chargement..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Branchez le chargeur"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Le niveau de la batterie est bas :"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"Batterie restante inférieure à <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Pourquoi ?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Échec du test usine"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"L\'action FACTORY_TEST est uniquement prise en charge pour les paquets de données installés dans in/system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Impossible de trouver un paquet proposant l\'action FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Redémarrer"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"La page \"<xliff:g id="TITLE">%s</xliff:g>\" affirme :"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Vous souhaitez quitter cette page ?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sélectionnez OK pour continuer ou Annuler pour rester sur la page actuelle."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmer"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lire l\'historique et les favoris du navigateur"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Autorise l\'application à lire toutes les URL auxquelles le navigateur a accédé et tous ses favoris."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"écrire dans l\'historique et les favoris du navigateur"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Autorise une application à modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonction pour effacer ou modifier les données de votre navigateur."</string>
- <string name="save_password_message" msgid="767344687139195790">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Pas maintenant"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Se souvenir du mot de passe"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Jamais"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Vous n\'êtes pas autorisé à ouvrir cette page."</string>
- <string name="text_copied" msgid="4985729524670131385">"Le texte a été copié dans le presse-papier."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Plus"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"espace"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"entrée"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"supprimer"</string>
- <string name="search_go" msgid="8298016669822141719">"Rechercher"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"Il y a 1 mois"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Il y a plus d\'un mois"</string>
+ <string name="keyguard_password_enter_pin_code">"Saisissez le code PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Le code PIN est incorrect !"</string>
+ <string name="keyguard_label_text">"Pour débloquer le clavier, appuyez sur \"Menu\" puis sur 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Numéro d\'urgence"</string>
+ <string name="lockscreen_carrier_default">"(Aucun service)"</string>
+ <string name="lockscreen_screen_locked">"Écran verrouillé"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string>
+ <string name="lockscreen_pattern_instructions">"Dessinez un schéma pour déverrouiller le téléphone"</string>
+ <string name="lockscreen_emergency_call">"Appel d\'urgence"</string>
+ <string name="lockscreen_pattern_correct">"Combinaison correcte !"</string>
+ <string name="lockscreen_pattern_wrong">"Désolé. Merci de réessayer."</string>
+ <string name="lockscreen_plugged_in">"Chargement (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Branchez votre chargeur."</string>
+ <string name="lockscreen_missing_sim_message_short">"Aucune carte SIM n\'a été trouvée."</string>
+ <string name="lockscreen_missing_sim_message">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
+ <string name="lockscreen_missing_sim_instructions">"Insérez une carte SIM."</string>
+ <string name="lockscreen_network_locked_message">"Réseau verrouillé"</string>
+ <string name="lockscreen_sim_puk_locked_message">"La carte SIM est verrouillée par clé PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Veuillez consulter le guide d\'utilisation ou contacter l\'assistance clientèle."</string>
+ <string name="lockscreen_sim_locked_message">"La carte SIM est verrouillée."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Déblocage de la carte SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Vous avez mal reproduit le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Vous avez mal saisi le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> tentatives supplémentaires, vous devrez débloquer votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Schéma oublié ?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Trop de tentatives !"</string>
+ <string name="lockscreen_glogin_instructions">"Pour déverrouiller le téléphone, connectez-vous à l\'aide de votre compte Google."</string>
+ <string name="lockscreen_glogin_username_hint">"Nom d\'utilisateur (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Mot de passe"</string>
+ <string name="lockscreen_glogin_submit_button">"Se connecter"</string>
+ <string name="lockscreen_glogin_invalid_input">"Nom d\'utilisateur ou mot de passe incorrect."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Aucune notification"</string>
+ <string name="status_bar_ongoing_events_title">"En cours"</string>
+ <string name="status_bar_latest_events_title">"Notifications"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Chargement..."</string>
+ <string name="battery_low_title">"Branchez le chargeur"</string>
+ <string name="battery_low_subtitle">"Le niveau de la batterie est bas :"</string>
+ <string name="battery_low_percent_format">"Batterie restante inférieure à <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="battery_low_why">"Pourquoi ?"</string>
+ <string name="factorytest_failed">"Échec du test usine"</string>
+ <string name="factorytest_not_system">"L\'action FACTORY_TEST est uniquement prise en charge pour les paquets de données installés dans in/system/app."</string>
+ <string name="factorytest_no_action">"Impossible de trouver un paquet proposant l\'action FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Redémarrer"</string>
+ <string name="js_dialog_title">"La page \"<xliff:g id="TITLE">%s</xliff:g>\" affirme :"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Vous souhaitez quitter cette page ?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sélectionnez OK pour continuer ou Annuler pour rester sur la page actuelle."</string>
+ <string name="save_password_label">"Confirmer"</string>
+ <string name="permlab_readHistoryBookmarks">"lire l\'historique et les favoris du navigateur"</string>
+ <string name="permdesc_readHistoryBookmarks">"Autorise l\'application à lire toutes les URL auxquelles le navigateur a accédé et tous ses favoris."</string>
+ <string name="permlab_writeHistoryBookmarks">"écrire dans l\'historique et les favoris du navigateur"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Autorise une application à modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonction pour effacer ou modifier les données de votre navigateur."</string>
+ <string name="save_password_message">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
+ <string name="save_password_notnow">"Pas maintenant"</string>
+ <string name="save_password_remember">"Se souvenir du mot de passe"</string>
+ <string name="save_password_never">"Jamais"</string>
+ <string name="open_permission_deny">"Vous n\'êtes pas autorisé à ouvrir cette page."</string>
+ <string name="text_copied">"Le texte a été copié dans le presse-papier."</string>
+ <string name="more_item_label">"Plus"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"espace"</string>
+ <string name="menu_enter_shortcut_label">"entrée"</string>
+ <string name="menu_delete_shortcut_label">"supprimer"</string>
+ <string name="search_go">"Rechercher"</string>
+ <string name="oneMonthDurationPast">"Il y a 1 mois"</string>
+ <string name="beforeOneMonthDurationPast">"Il y a plus d\'un mois"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Il y a 1 seconde"</item>
- <item quantity="other" msgid="3903706804349556379">"Il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ <item quantity="one">"Il y a 1 seconde"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Il y a 1 minute"</item>
- <item quantity="other" msgid="2176942008915455116">"Il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ <item quantity="one">"Il y a 1 minute"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"il y a 1 heure"</item>
- <item quantity="other" msgid="2467273239587587569">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ <item quantity="one">"il y a 1 heure"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"hier"</item>
- <item quantity="other" msgid="2479586466153314633">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
+ <item quantity="one">"hier"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"dans 1 seconde"</item>
- <item quantity="other" msgid="1241926116443974687">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ <item quantity="one">"dans 1 seconde"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"dans 1 minute"</item>
- <item quantity="other" msgid="3330713936399448749">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ <item quantity="one">"dans 1 minute"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"dans 1 heure"</item>
- <item quantity="other" msgid="547290677353727389">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ <item quantity="one">"dans 1 heure"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"demain"</item>
- <item quantity="other" msgid="5109449375100953247">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
+ <item quantity="one">"demain"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"il y a 1 seconde"</item>
- <item quantity="other" msgid="3699169366650930415">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ <item quantity="one">"il y a 1 seconde"</item>
+ <item quantity="other">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"il y a 1 minute"</item>
- <item quantity="other" msgid="851164968597150710">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ <item quantity="one">"il y a 1 minute"</item>
+ <item quantity="other">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"il y a 1 heure"</item>
- <item quantity="other" msgid="6889970745748538901">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ <item quantity="one">"il y a 1 heure"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"hier"</item>
- <item quantity="other" msgid="3453342639616481191">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
+ <item quantity="one">"hier"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"dans 1 seconde"</item>
- <item quantity="other" msgid="5495880108825805108">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ <item quantity="one">"dans 1 seconde"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"dans 1 minute"</item>
- <item quantity="other" msgid="4216113292706568726">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ <item quantity="one">"dans 1 minute"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"dans 1 heure"</item>
- <item quantity="other" msgid="3705373766798013406">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ <item quantity="one">"dans 1 heure"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"demain"</item>
- <item quantity="other" msgid="2973062968038355991">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
+ <item quantity="one">"demain"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"à %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"en %s"</string>
- <string name="day" msgid="8144195776058119424">"jour"</string>
- <string name="days" msgid="4774547661021344602">"jours"</string>
- <string name="hour" msgid="2126771916426189481">"heure"</string>
- <string name="hours" msgid="894424005266852993">"heures"</string>
- <string name="minute" msgid="9148878657703769868">"mn"</string>
- <string name="minutes" msgid="5646001005827034509">"mn"</string>
- <string name="second" msgid="3184235808021478">"s"</string>
- <string name="seconds" msgid="3161515347216589235">"s"</string>
- <string name="week" msgid="5617961537173061583">"semaine"</string>
- <string name="weeks" msgid="6509623834583944518">"semaines"</string>
- <string name="year" msgid="4001118221013892076">"année"</string>
- <string name="years" msgid="6881577717993213522">"années"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Tous les jours ouvrés (lun.- ven.)"</string>
- <string name="daily" msgid="5738949095624133403">"Tous les jours"</string>
- <string name="weekly" msgid="983428358394268344">"Toutes les semaines le <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Tous les mois"</string>
- <string name="yearly" msgid="1519577999407493836">"Tous les ans"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Échec de la lecture de la vidéo"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Désolé, cette vidéo ne peut être lue sur cet appareil."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Désolé, impossible de lire cette vidéo."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"midi"</string>
- <string name="Noon" msgid="3342127745230013127">"Midi"</string>
- <string name="midnight" msgid="7166259508850457595">"minuit"</string>
- <string name="Midnight" msgid="5630806906897892201">"Minuit"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Tout sélectionner"</string>
- <string name="selectText" msgid="3889149123626888637">"Sélectionner le texte"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Arrêter sélection de texte"</string>
- <string name="cut" msgid="3092569408438626261">"Couper"</string>
- <string name="cutAll" msgid="2436383270024931639">"Tout couper"</string>
- <string name="copy" msgid="2681946229533511987">"Copier"</string>
- <string name="copyAll" msgid="2590829068100113057">"Tout copier"</string>
- <string name="paste" msgid="5629880836805036433">"Coller"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copier l\'URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Mode de saisie"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Ajouter \"%s\" au dictionnaire"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Modifier le texte"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Espace disponible faible"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"La mémoire du téléphone commence à être pleine."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Annuler"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
- <string name="capital_on" msgid="1544682755514494298">"ON"</string>
- <string name="capital_off" msgid="6815870386972805832">"OFF"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Continuer avec"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Utiliser cette application par défaut pour cette action"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Effacer les paramètres par défaut dans les Paramètres de page d\'accueil &gt; Applications &gt; Gérer les applications."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Sélectionner une action"</string>
- <string name="noApplications" msgid="1691104391758345586">"Aucune application ne peut effectuer cette action."</string>
- <string name="aerr_title" msgid="653922989522758100">"Désolé !"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Fermeture soudaine de l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>). Merci de réessayer."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> s\'est interrompu de façon inopinée. Merci de réessayer."</string>
- <string name="anr_title" msgid="3100070910664756057">"Désolé !"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> (de l\'application <xliff:g id="APPLICATION">%2$s</xliff:g>) ne répond pas."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) ne répond pas."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) ne répond pas."</string>
- <string name="anr_process" msgid="1246866008169975783">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> ne répond pas."</string>
- <string name="force_close" msgid="3653416315450806396">"Forcer la fermeture"</string>
- <string name="report" msgid="4060218260984795706">"Rapport"</string>
- <string name="wait" msgid="7147118217226317732">"Attendre"</string>
- <string name="debug" msgid="9103374629678531849">"Débogage"</string>
- <string name="sendText" msgid="5132506121645618310">"Sélectionner une action pour le texte"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volume de la sonnerie"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volume"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Lecture via Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volume des appels entrants"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume d\'appels entrants sur Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volume"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volume des notifications"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Sonnerie par défaut"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Sonnerie par défaut (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silencieux"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Sonneries"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Sonnerie inconnue"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"à %s"</string>
+ <string name="preposition_for_year">"en %s"</string>
+ <string name="day">"jour"</string>
+ <string name="days">"jours"</string>
+ <string name="hour">"heure"</string>
+ <string name="hours">"heures"</string>
+ <string name="minute">"mn"</string>
+ <string name="minutes">"mn"</string>
+ <string name="second">"s"</string>
+ <string name="seconds">"s"</string>
+ <string name="week">"semaine"</string>
+ <string name="weeks">"semaines"</string>
+ <string name="year">"année"</string>
+ <string name="years">"années"</string>
+ <string name="every_weekday">"Tous les jours ouvrés (lun.- ven.)"</string>
+ <string name="daily">"Tous les jours"</string>
+ <string name="weekly">"Toutes les semaines le <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Tous les mois"</string>
+ <string name="yearly">"Tous les ans"</string>
+ <string name="VideoView_error_title">"Échec de la lecture de la vidéo"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Désolé, cette vidéo ne peut être lue sur cet appareil."</string>
+ <string name="VideoView_error_text_unknown">"Désolé, impossible de lire cette vidéo."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"midi"</string>
+ <string name="Noon">"Midi"</string>
+ <string name="midnight">"minuit"</string>
+ <string name="Midnight">"Minuit"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Tout sélectionner"</string>
+ <string name="selectText">"Sélectionner le texte"</string>
+ <string name="stopSelectingText">"Arrêter sélection de texte"</string>
+ <string name="cut">"Couper"</string>
+ <string name="cutAll">"Tout couper"</string>
+ <string name="copy">"Copier"</string>
+ <string name="copyAll">"Tout copier"</string>
+ <string name="paste">"Coller"</string>
+ <string name="copyUrl">"Copier l\'URL"</string>
+ <string name="inputMethod">"Mode de saisie"</string>
+ <string name="addToDictionary">"Ajouter \"%s\" au dictionnaire"</string>
+ <string name="editTextMenuTitle">"Modifier le texte"</string>
+ <string name="low_internal_storage_view_title">"Espace disponible faible"</string>
+ <string name="low_internal_storage_view_text">"La mémoire du téléphone commence à être pleine."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Annuler"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Annuler"</string>
+ <string name="dialog_alert_title">"Attention"</string>
+ <string name="capital_on">"ON"</string>
+ <string name="capital_off">"OFF"</string>
+ <string name="whichApplication">"Continuer avec"</string>
+ <string name="alwaysUse">"Utiliser cette application par défaut pour cette action"</string>
+ <string name="clearDefaultHintMsg">"Effacer les paramètres par défaut dans les Paramètres de page d\'accueil &gt; Applications &gt; Gérer les applications."</string>
+ <string name="chooseActivity">"Sélectionner une action"</string>
+ <string name="noApplications">"Aucune application ne peut effectuer cette action."</string>
+ <string name="aerr_title">"Désolé !"</string>
+ <string name="aerr_application">"Fermeture soudaine de l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>). Merci de réessayer."</string>
+ <string name="aerr_process">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> s\'est interrompu de façon inopinée. Merci de réessayer."</string>
+ <string name="anr_title">"Désolé !"</string>
+ <string name="anr_activity_application">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> (de l\'application <xliff:g id="APPLICATION">%2$s</xliff:g>) ne répond pas."</string>
+ <string name="anr_activity_process">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) ne répond pas."</string>
+ <string name="anr_application_process">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) ne répond pas."</string>
+ <string name="anr_process">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> ne répond pas."</string>
+ <string name="force_close">"Forcer la fermeture"</string>
+ <string name="report">"Rapport"</string>
+ <string name="wait">"Attendre"</string>
+ <string name="debug">"Débogage"</string>
+ <string name="sendText">"Sélectionner une action pour le texte"</string>
+ <string name="volume_ringtone">"Volume de la sonnerie"</string>
+ <string name="volume_music">"Volume"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Lecture via Bluetooth"</string>
+ <string name="volume_call">"Volume des appels entrants"</string>
+ <string name="volume_bluetooth_call">"Volume d\'appels entrants sur Bluetooth"</string>
+ <string name="volume_alarm">"Volume"</string>
+ <string name="volume_notification">"Volume des notifications"</string>
+ <string name="volume_unknown">"Volume"</string>
+ <string name="ringtone_default">"Sonnerie par défaut"</string>
+ <string name="ringtone_default_with_actual">"Sonnerie par défaut (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silencieux"</string>
+ <string name="ringtone_picker_title">"Sonneries"</string>
+ <string name="ringtone_unknown">"Sonnerie inconnue"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Réseau Wi-Fi disponible"</item>
- <item quantity="other" msgid="4192424489168397386">"Réseaux Wi-Fi disponibles"</item>
+ <item quantity="one">"Réseau Wi-Fi disponible"</item>
+ <item quantity="other">"Réseaux Wi-Fi disponibles"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Réseau Wi-Fi ouvert disponible"</item>
- <item quantity="other" msgid="7915895323644292768">"Réseaux Wi-Fi ouverts disponibles"</item>
+ <item quantity="one">"Réseau Wi-Fi ouvert disponible"</item>
+ <item quantity="other">"Réseaux Wi-Fi ouverts disponibles"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Insérer un caractère"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Application inconnue"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Envoi de messages SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Vous êtes sur le point d\'envoyer un grand nombre de messages SMS. Sélectionnez OK pour continuer ou Annuler pour interrompre l\'envoi."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annuler"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Définir"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Par défaut"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Masquer"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Tout afficher"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Chargement..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Connecté à l\'aide d\'un câble USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Vous avez connecté votre téléphone à votre ordinateur à l\'aide d\'un câble USB. Sélectionnez Monter pour copier des fichiers de votre ordinateur vers votre carte SD, ou inversement."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Monter"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Ne pas monter"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Un problème est survenu lors de l\'utilisation de votre carte SD en tant que périphérique de stockage USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Connecté avec un câble USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Activez pour copier des fichiers vers/de votre ordinateur."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Éteindre le périphérique de stockage USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Sélectionner pour éteindre le périphérique de stockage USB"</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Éteindre le périphérique de stockage USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Avant d\'éteindre le périphérique de stockage USB, assurez-vous d\'avoir désactivé l\'hôte USB. Sélectionnez \"Éteindre\" pour éteindre le périphérique de stockage USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Éteindre"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Annuler"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Un problème est survenu lors de la mise hors tension du périphérique de stockage USB. Assurez-vous que l\'hôte USB a bien été désactivé, puis essayez à nouveau."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formater la carte SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Voulez-vous vraiment formater la carte SD ? Toutes les données de cette carte seront perdues."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB connecté"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Un ordinateur est connecté à votre téléphone."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Sélectionner un mode de saisie"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Préparation de la carte SD"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Recherche d\'erreurs"</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Carte SD vide"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"La carte SD est vide ou son système de fichiers n\'est pas pris en charge."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Carte SD endommagée"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"La carte SD est endommagée. Vous devrez peut-être la reformater."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Carte SD retirée inopinément"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Désactiver la carte SD avant de la retirer pour éviter toute perte de données."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"La carte SD peut être retirée en toute sécurité"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Vous pouvez retirer la carte SD en toute sécurité."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Carte SD manquante"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"La carte SD a été retirée. Insérez-en une autre."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Aucune activité correspondante trouvée"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"mettre à jour les données statistiques du composant"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permet de modifier les données statistiques collectées du composant. Cette option n\'est pas utilisée par les applications standard."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Appuyer deux fois pour régler le zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Erreur lors de l\'agrandissement du widget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"OK"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Rechercher"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Envoyer"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Suivant"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"OK"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Exécuter"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Composer le numéro"\n"en utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Ajouter un contact"\n"en utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"sélectionné"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"non sélectionné"</string>
+ <string name="select_character">"Insérer un caractère"</string>
+ <string name="sms_control_default_app_name">"Application inconnue"</string>
+ <string name="sms_control_title">"Envoi de messages SMS"</string>
+ <string name="sms_control_message">"Vous êtes sur le point d\'envoyer un grand nombre de messages SMS. Sélectionnez OK pour continuer ou Annuler pour interrompre l\'envoi."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Annuler"</string>
+ <string name="date_time_set">"Définir"</string>
+ <string name="default_permission_group">"Par défaut"</string>
+ <string name="no_permissions">"Aucune autorisation requise"</string>
+ <string name="perms_hide"><b>"Masquer"</b></string>
+ <string name="perms_show_all"><b>"Tout afficher"</b></string>
+ <string name="googlewebcontenthelper_loading">"Chargement..."</string>
+ <string name="usb_storage_title">"Connecté à l\'aide d\'un câble USB"</string>
+ <string name="usb_storage_message">"Vous avez connecté votre téléphone à votre ordinateur à l\'aide d\'un câble USB. Sélectionnez Monter pour copier des fichiers de votre ordinateur vers votre carte SD, ou inversement."</string>
+ <string name="usb_storage_button_mount">"Monter"</string>
+ <string name="usb_storage_button_unmount">"Ne pas monter"</string>
+ <string name="usb_storage_error_message">"Un problème est survenu lors de l\'utilisation de votre carte SD en tant que périphérique de stockage USB."</string>
+ <string name="usb_storage_notification_title">"Connecté avec un câble USB"</string>
+ <string name="usb_storage_notification_message">"Activez pour copier des fichiers vers/de votre ordinateur."</string>
+ <string name="usb_storage_stop_notification_title">"Éteindre le périphérique de stockage USB"</string>
+ <string name="usb_storage_stop_notification_message">"Sélectionner pour éteindre le périphérique de stockage USB"</string>
+ <string name="usb_storage_stop_title">"Éteindre le périphérique de stockage USB"</string>
+ <string name="usb_storage_stop_message">"Avant d\'éteindre le périphérique de stockage USB, assurez-vous d\'avoir désactivé l\'hôte USB. Sélectionnez \"Éteindre\" pour éteindre le périphérique de stockage USB."</string>
+ <string name="usb_storage_stop_button_mount">"Éteindre"</string>
+ <string name="usb_storage_stop_button_unmount">"Annuler"</string>
+ <string name="usb_storage_stop_error_message">"Un problème est survenu lors de la mise hors tension du périphérique de stockage USB. Assurez-vous que l\'hôte USB a bien été désactivé, puis essayez à nouveau."</string>
+ <string name="extmedia_format_title">"Formater la carte SD"</string>
+ <string name="extmedia_format_message">"Voulez-vous vraiment formater la carte SD ? Toutes les données de cette carte seront perdues."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Sélectionner un mode de saisie"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidats"</u></string>
+ <string name="ext_media_checking_notification_title">"Préparation de la carte SD"</string>
+ <string name="ext_media_checking_notification_message">"Recherche d\'erreurs"</string>
+ <string name="ext_media_nofs_notification_title">"Carte SD vide"</string>
+ <string name="ext_media_nofs_notification_message">"La carte SD est vide ou son système de fichiers n\'est pas pris en charge."</string>
+ <string name="ext_media_unmountable_notification_title">"Carte SD endommagée"</string>
+ <string name="ext_media_unmountable_notification_message">"La carte SD est endommagée. Vous devrez peut-être la reformater."</string>
+ <string name="ext_media_badremoval_notification_title">"Carte SD retirée inopinément"</string>
+ <string name="ext_media_badremoval_notification_message">"Désactiver la carte SD avant de la retirer pour éviter toute perte de données."</string>
+ <string name="ext_media_safe_unmount_notification_title">"La carte SD peut être retirée en toute sécurité"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Vous pouvez retirer la carte SD en toute sécurité."</string>
+ <string name="ext_media_nomedia_notification_title">"Carte SD manquante"</string>
+ <string name="ext_media_nomedia_notification_message">"La carte SD a été retirée. Insérez-en une autre."</string>
+ <string name="activity_list_empty">"Aucune activité correspondante trouvée"</string>
+ <string name="permlab_pkgUsageStats">"mettre à jour les données statistiques du composant"</string>
+ <string name="permdesc_pkgUsageStats">"Permet de modifier les données statistiques collectées du composant. Cette option n\'est pas utilisée par les applications standard."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Appuyer deux fois pour régler le zoom"</string>
+ <string name="gadget_host_error_inflating">"Erreur lors de l\'agrandissement du widget"</string>
+ <string name="ime_action_go">"OK"</string>
+ <string name="ime_action_search">"Rechercher"</string>
+ <string name="ime_action_send">"Envoyer"</string>
+ <string name="ime_action_next">"Suivant"</string>
+ <string name="ime_action_done">"OK"</string>
+ <string name="ime_action_default">"Exécuter"</string>
+ <string name="dial_number_using">"Composer le numéro"\n"en utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Ajouter un contact"\n"en utilisant <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="accessibility_compound_button_selected">"sélectionné"</string>
+ <string name="accessibility_compound_button_unselected">"non sélectionné"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index fde4f23..778faac 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -15,695 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"&lt;senza nome&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nessun numero di telefono)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Sconosciuto)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Segreteria"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problema di connessione o codice MMI non valido."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Il servizio è stato attivato."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Il servizio è stato attivato per:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Il servizio è stato disattivato."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registrazione effettuata."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Eliminazione effettuata."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Password errata."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI completo."</string>
- <string name="badPin" msgid="5085454289896032547">"Il PIN attuale digitato è errato."</string>
- <string name="badPuk" msgid="5702522162746042460">"Il PUK digitato è errato."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"I PIN inseriti non corrispondono."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Il PIN deve essere di 4-8 numeri."</string>
- <string name="needPuk" msgid="919668385956251611">"La SIM è bloccata tramite PUK. Digita il codice PUK per sbloccarla."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Digita il PUK2 per sbloccare la SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"ID chiamante in entrata"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"ID chiamante in uscita"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Deviazione chiamate"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Avviso di chiamata"</string>
- <string name="BaMmi" msgid="455193067926770581">"Blocco chiamate"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Modifica password"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Modifica PIN"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Numero chiamante presente"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Numero chiamante con restrizioni"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Chiamata a tre"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Rifiuto di chiamate fastidiose non desiderate"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Recapito numero chiamante"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Non disturbare"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID chiamante generalmente limitato. Prossima chiamata: limitato"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ID chiamante generalmente limitato. Prossima chiamata: non limitato"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID chiamante generalmente non limitato. Prossima chiamata: limitato"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID chiamante generalmente non limitato. Prossima chiamata: non limitato"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Servizio non fornito."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Impossibile modificare l\'impostazione dell\'ID del chiamante."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Accesso limitato modificato"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Il servizio dati è bloccato."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Il servizio di emergenza è bloccato."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Il servizio vocale/SMS è bloccato."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Tutti i servizi vocali/SMS sono bloccati."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voce"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Dati"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asinc"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Sinc"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pacchetto"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Indicatore roaming attivato"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Indicatore roaming disattivato"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Indicatore roaming lampeggiante"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Fuori dal vicinato"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Fuori dall\'edificio"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming - Sistema preferito"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming - Sistema disponibile"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming - Partner Alliance"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming - Partner Premium"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming - Funzionalità servizio completo"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming - Funzionalità servizio parziale"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Banner roaming attivato"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Banner roaming disattivato"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Ricerca servizio"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> dopo <xliff:g id="TIME_DELAY">{2}</xliff:g> secondi"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Codice funzione completo."</string>
- <string name="fcError" msgid="3327560126588500777">"Problema di connessione o codice funzione non valido."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"La pagina web contiene un errore."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Impossibile trovare l\'URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Schema di autenticazione del sito non supportato."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Autenticazione non riuscita."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Autenticazione tramite il server proxy non riuscita."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Connessione al server non riuscita."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Impossibile comunicare con il server. Riprova più tardi."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Tempo esaurito per la connessione al server."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"La pagina contiene troppi reindirizzamenti sul server."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protocollo non supportato."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Impossibile stabilire una connessione protetta."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Impossibile aprire la pagina. URL non valido."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Impossibile accedere al file."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Impossibile trovare il file richiesto."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Troppe richieste in fase di elaborazione. Riprova più tardi."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Sinc"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizzazione"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Troppe eliminazioni di <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
- <string name="me" msgid="6545696007631404292">"Io"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opzioni telefono"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Modalità silenziosa"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Attiva wireless"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Disattiva wireless"</string>
- <string name="screen_lock" msgid="799094655496098153">"Blocco schermo"</string>
- <string name="power_off" msgid="4266614107412865048">"Spegni"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Spegnimento..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Il telefono verrà spento."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Nessuna applicazione recente."</string>
- <string name="global_actions" msgid="2406416831541615258">"Opzioni telefono"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Blocco schermo"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Spegni"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modalità silenziosa"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Audio non attivo"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Audio attivo"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modalità aereo attiva"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modalità aereo attiva"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modalità aereo non attiva"</string>
- <string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servizi che prevedono un costo"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Consentono alle applicazioni di svolgere operazioni che possono comportare un costo."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"I tuoi messaggi"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Leggere e scrivere SMS, email e altri messaggi."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Informazioni personali"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Accedere direttamente ai contatti e al calendario memorizzati sul telefono."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"La tua posizione"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Monitorare la posizione fisica dell\'utente"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicazione di rete"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Consentono l\'accesso delle applicazioni a varie funzionalità di rete."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"I tuoi account Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Accedere agli account Google disponibili."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controlli hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Accedere direttamente all\'hardware del ricevitore."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefonate"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitorare, registrare ed elaborare le telefonate."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Strumenti di sistema"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Accesso al sistema e controllo di livello inferiore."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Strumenti di sviluppo"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funzionalità necessarie soltanto agli sviluppatori di applicazioni."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Archiviazione"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Accesso alla scheda SD."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"disattivare o modificare la barra di stato"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"espansione/compressione barra di stato"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Consente all\'applicazione di espandere o comprimere la barra di stato."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"intercettazione chiamate in uscita"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Consente all\'applicazione di elaborare le chiamate in uscita e di modificare il numero da comporre. Le applicazioni dannose potrebbero monitorare, deviare o impedire le chiamate in uscita."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"ricezione SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Consente il ricevimento e l\'elaborazione di SMS da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"ricezione MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Consente il ricevimento e l\'elaborazione di MMS da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"invio SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Consente all\'applicazione di inviare messaggi SMS. Le applicazioni dannose potrebbero inviare messaggi a tua insaputa facendoti sostenere dei costi."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"lettura SMS o MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Consente all\'applicazione di leggere SMS memorizzati sul telefono o sulla SIM. Le applicazioni dannose potrebbero leggere messaggi riservati."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"modifica SMS o MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Consente all\'applicazione di rispondere a SMS memorizzati sul telefono o sulla SIM. Le applicazioni dannose potrebbero eliminare i messaggi."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"ricezione WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Consente il ricevimento e l\'elaborazione di messaggi WAP da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"recupero applicazioni in esecuzione"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Consente all\'applicazione di recuperare informazioni sulle attività in esecuzione ed eseguite di recente. Le applicazioni dannose potrebbero essere in grado di scoprire informazioni riservate su altre applicazioni."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"riordinamento applicazioni in esecuz."</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Consente a un\'applicazione di spostare attività in primo e secondo piano. Le applicazioni dannose possono imporsi ponendosi automaticamente in primo piano."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"attivazione debug delle applicazioni"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Consente a un\'applicazione di attivare il debug per un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per interrompere altre applicazioni."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"modifica impostazioni UI"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Consente a un\'applicazione di modificare la configurazione corrente, come le dimensioni dei caratteri locali o complessive."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"riavvio altre applicazioni"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Consente a un\'applicazione di riavviare forzatamente altre applicazioni."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"chiusura forzata dell\'applicazione"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Consente a un\'applicazione di forzare la chiusura di attività in primo piano. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"recupero stato interno del sistema"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Consente all\'applicazione di recuperare lo stato interno del sistema. Le applicazioni dannose potrebbero recuperare molte informazioni riservate e protette di cui non dovrebbero avere mai bisogno."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"chiusura parziale"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Mette il gestore delle attività in uno stato di chiusura. Non esegue una chiusura completa."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedire commutazione applicazione"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Impedisce all\'utente di passare a un\'altra applicazione."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"monitoraggio e controllo avvio applicazioni"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Consente a un\'applicazione di monitorare e controllare la modalità di avvio delle attività nel sistema. Le applicazioni dannose potrebbero compromettere totalmente il sistema. Questa autorizzazione è necessaria soltanto per lo sviluppo, mai per il normale utilizzo del telefono."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"invio broadcast rimossi dal pacchetto"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Consente a un\'applicazione di trasmettere una notifica di rimozione del pacchetto di un\'applicazione. Le applicazioni dannose potrebbero sfruttare questa possibilità per interrompere ogni altra applicazione in esecuzione."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"invio broadcast ricevuti tramite SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un SMS. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che siano stati ricevuti SMS."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"invio broadcast ricevuti tramite WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un messaggio WAP PUSH. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che sia stato ricevuto un MMS o per sostituire automaticamente contenuti di pagine web con varianti dannose."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"numero limite di processi in esecuzione"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Consente a un\'applicazione di stabilire il numero massimo di processi in esecuzione. Mai necessario per le normali applicazioni."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"chiusura applicazioni in background"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Consente a un\'applicazione di controllare se le attività sono sempre completate quando vengono messe in secondo piano. Mai necessario per le normali applicazioni."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"modifica statistiche batteria"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Consente la modifica delle statistiche sulla batteria raccolte. Da non usare per normali applicazioni."</string>
- <string name="permlab_backup" msgid="470013022865453920">"controllo del backup di sistema e ripristino"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Consente all\'applicazione di controllare i backup dei sistemi e il meccanismo di ripristino. Da non usare per normali applicazioni."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"visualizzazione finestre non autorizzate"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Consente la creazione di finestre destinate all\'uso nell\'interfaccia utente di sistema interna. Da non usare per normali applicazioni."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"visualizzazione avvisi di sistema"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Consente a un\'applicazione di visualizzare finestre di avviso del sistema. Le applicazioni dannose possono sfruttare questa opzione per riempire lo schermo del telefono di messaggi."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modifica velocità di animazione globale"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Consente a un\'applicazione di modificare la velocità di animazione globale (animazioni più veloci o più lente) in qualsiasi momento."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"gestione token applicazioni"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Consente alle applicazioni di creare e gestire i propri token, ignorando il normale ordinamento Z. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"uso tasti e pulsanti di controllo"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Consente a un\'applicazione di offrire i suoi eventi di input (pressioni di tasti etc.) ad altre applicazioni. Le applicazioni dannose possono sfruttare questa possibilità per assumere il controllo del telefono."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"registrazione testo digitato e azioni eseguite"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Consente il rilevamento da parte delle applicazioni dei tasti premuti anche durante l\'interazione con un\'altra applicazione (come nel caso di inserimento di una password). Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"associaz. a un metodo di inserimento"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Consente l\'associazione all\'interfaccia principale di un metodo di inserimento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"modifica orientamento dello schermo"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Consente a un\'applicazione di cambiare la rotazione dello schermo in qualsiasi momento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"invio segnali Linuz alle applicazioni"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Consente all\'applicazione di richiedere l\'invio del segnale fornito a tutti i processi persistenti."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"esecuzione permanente delle applicazioni"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Consente a un\'applicazione di rendere delle sue parti costanti in modo che il sistema non possa usarla per altre applicazioni."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"eliminazione applicazioni"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Consente a un\'applicazione di eliminare pacchetti Android. Le applicazioni dannose possono sfruttare questa possibilità per eliminare importanti applicazioni."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"eliminazione dati di altre applicazioni"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Consente a un\'applicazione di cancellare dati dell\'utente."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"eliminazione cache altre applicazioni"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Consente a un\'applicazione di eliminare file della cache."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"calcolo spazio di archiviazione applicazioni"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Consente a un\'applicazione di recuperare i suoi codici, dati e dimensioni della cache"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"installazione diretta di applicazioni"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Consente a un\'applicazione di installare nuovi pacchetti Android o aggiornamenti. Le applicazioni dannose possono sfruttare questa possibilità per aggiungere nuove applicazioni con potenti autorizzazioni arbitrarie."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminazione dati della cache applicazioni"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Consente a un\'applicazione di liberare spazio sul telefono eliminando file nella directory della cache dell\'applicazione. L\'accesso è generalmente limitato a processi di sistema."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"lettura file di registro sistema"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Consente a un\'applicazione di leggere vari file di registro del sistema per trovare informazioni generali sulle operazioni effettuate con il telefono. Tali file non dovrebbero contenere informazioni personali o riservate."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Consente a un\'applicazione di leggere le risorse del gruppo diag e scrivere a esse, per esempio i file in /dev. Questa capacità potrebbe influire sulla stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"attivazione/disattivazione componenti applicazioni"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Consente a un\'applicazione di attivare o disattivare un componente di un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per disattivare importanti funzionalità del telefono. Prestare attenzione con questa autorizzazione perché è possibile rendere inutilizzabili, incoerenti o instabili i componenti delle applicazioni."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"impostazione applicazioni preferite"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Consente la modifica da parte di un\'applicazione delle applicazioni preferite. Le applicazioni dannose potrebbero essere in grado di modificare automaticamente le applicazioni in esecuzione, effettuando lo spoofing delle applicazioni esistenti per raccogliere dati riservati."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modifica impostazioni di sistema globali"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Consente la modifica in un\'applicazione dei dati delle impostazioni del sistema. Le applicazioni dannose possono danneggiare la configurazione del sistema."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificare le impostazioni di protezione del sistema"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Consente a un\'applicazione di modificare i dati delle impostazioni di protezione del sistema. Da non usare per normali applicazioni."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"modifica mappa servizi Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Consente a un\'applicazione di modificare la mappa dei servizi Google. Da non usare per normali applicazioni."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"apertura automatica all\'avvio"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Consente a un\'applicazione di aprirsi automaticamente al termine dell\'avvio del sistema. Potrebbe essere necessario più tempo per l\'avvio del telefono e l\'applicazione potrebbe rallentare tutte le funzioni del telefono rimanendo sempre in esecuzione."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"invio broadcast permanenti"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Consente a un\'applicazione di inviare broadcast permanenti, che permangono anche al termine del broadcast. Le applicazioni dannose possono rendere il telefono lento o instabile tramite un uso eccessivo della memoria."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"lettura dati di contatto"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Consente la lettura da parte di un\'applicazione di tutti i dati (gli indirizzi) di contatto memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per inviare i dati ad altre persone."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"scrittura dati di contatto"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Consente a un\'applicazione di modificare i dati (gli indirizzi) di contatto memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati di contatto."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"scrittura dati proprietario"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Consente a un\'applicazione di modificare i dati del proprietario del telefono memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare tali dati."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"lettura dati proprietario"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Consente a un\'applicazione di leggere i dati del proprietario del telefono memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per leggere tali dati."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"lettura dati di calendario"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Consente la lettura da parte di un\'applicazione di tutti gli eventi di calendario memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per inviare i tuoi eventi di calendario ad altre persone."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"scrittura dati di calendario"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Consente a un\'applicazione di modificare gli eventi di calendario memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati del calendario."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fonti di localizzazione fittizie per test"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Creare fonti di localizzazione fittizie per test. Le applicazioni dannose possono sfruttare questa possibilità per sostituire la posizione e/o lo stato restituito da reali fonti di localizzazione come GPS o provider di rete."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi del provider di localizz."</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Accedere a comandi aggiuntivi del provider di localizzazione. Le applicazioni dannose possono sfruttare questa possibilità per interferire con il funzionamento del GPS o di altre fonti di localizzazione."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"autorizzazione a installare un provider di localizzazione"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Creare fonti di localizzazione fittizie per test. Le applicazioni dannose possono sfruttare questa possibilità per sostituire la posizione e/o lo stato restituito da reali fonti di localizzazione come GPS o provider di rete oppure per monitorare e segnalare la tua posizione a una fonte esterna."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"localizzazione precisa (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Consente l\'accesso a fonti di localizzazione precisa, come il sistema GPS del telefono, se disponibile. Le applicazioni dannose possono sfruttare questa possibilità per determinare la tua posizione e, nel farlo, far esaurire più in fretta la batteria."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"localizzazione approssimativa (basata sulla rete)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Consente l\'accesso a fonti di localizzazione geografica non puntuale (come il database della rete cellulare) per determinare una posizione approssimativa del telefono, quando possibile. Le applicazioni dannose possono sfruttare questa possibilità per determinare approssimativamente dove ti trovi."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"accesso a SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Consente l\'utilizzo dell\'applicazione di funzioni di basso livello SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lettura buffer di frame"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Consente la lettura da parte dell\'applicazione dei contenuti del buffer di frame."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifica impostazioni audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Consente all\'applicazione di modificare impostazioni audio globali come volume e routing."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"registrazione audio"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Consente l\'accesso dell\'applicazione al percorso di registrazione dell\'audio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"acquisizione foto"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Consente di scattare foto nell\'applicazione con la fotocamera. L\'applicazione può acquisire in qualsiasi momento le immagini rilevate dalla fotocamera."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"disattivazione telefono"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Consente all\'applicazione di disattivare l\'intero telefono in modo definitivo. Questa autorizzazione è molto pericolosa."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"riavvio forzato del telefono"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Consente all\'applicazione di imporre il riavvio del telefono."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"installazione/disinstallazione filesystem"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Consente montaggio e smontaggio da parte dell\'applicazione dei filesystem degli archivi rimovibili."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formattazione archivio esterno"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Consente all\'applicazione di formattare l\'archivio rimovibile."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"controllo vibrazione"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Consente all\'applicazione di controllare la vibrazione."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controllo flash"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Consente all\'applicazione di controllare il flash."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"esecuzione test hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Consente all\'applicazione di controllare varie periferiche per il test dell\'hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"chiamata diretta n. telefono"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Consente all\'applicazione di chiamare numeri automaticamente. Le applicazioni dannose potrebbero far risultare chiamate impreviste sulla bolletta telefonica. Questa autorizzazione non consente all\'applicazione di chiamare numeri di emergenza."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"chiamata diretta di tutti i n. telefono"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Consente all\'applicazione di chiamare qualsiasi numero, compresi quelli di emergenza, automaticamente. Le applicazioni dannose potrebbero effettuare chiamate non necessarie e illegali a servizi di emergenza."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"controllo notifiche aggiornamento posizione"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Consente l\'attivazione/disattivazione delle notifiche di aggiornamento della posizione dal segnale cellulare. Da non usare per normali applicazioni."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"accesso a proprietà di archiviazione"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Consente l\'accesso di lettura/scrittura alle proprietà caricate dal servizio di archiviazione. Da non usare per normali applicazioni."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"scegliere widget"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Consente all\'applicazione di indicare al sistema quali widget possono essere utilizzati e da quale applicazione. Con questa autorizzazione, le applicazioni possono consentire ad altre applicazioni di accedere a dati personali. Da non usare per normali applicazioni."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modifica stato del telefono"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Consente all\'applicazione di controllare le funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può cambiare rete, attivare e disattivare il segnale cellulare e così via, senza alcuna notifica."</string>
- <string name="permlab_readPhoneState" msgid="2326172951448691631">"lettura stato e identità del telefono"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"Consente l\'accesso dell\'applicazione alle funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può determinare il numero del telefono in uso e il suo numero di serie, se una chiamata è attiva o meno, il numero a cui è collegata la chiamata e simili."</string>
- <string name="permlab_wakeLock" msgid="573480187941496130">"disattivazione stand-by del telefono"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Consente a un\'applicazione di impedire lo stand-by del telefono."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"accensione o spegnimento del telefono"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Consente all\'applicazione di accendere o spegnere il telefono."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"esecuzione in modalità test di fabbrica"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"In esecuzione come test del produttore di basso livello, consentendo l\'accesso completo all\'hardware del telefono. Disponibile soltanto quando il telefono è in esecuzione in modalità test del produttore."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"impostazione sfondo"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Consente all\'applicazione di impostare lo sfondo del sistema."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"impostaz. suggerimenti dimensioni sfondo"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Consente all\'applicazione di impostare i suggerimenti per le dimensioni dello sfondo del sistema."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"ripristino impostazioni predef. di fabbrica"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Consente a un\'applicazione di ripristinare le impostazioni di fabbrica del sistema, eliminando tutti i dati, le configurazioni e le applicazioni installate."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"impostazione fuso orario"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Consente a un\'applicazione di modificare il fuso orario del telefono."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"rilevamento account noti"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Consente a un\'applicazione di recuperare l\'elenco di account memorizzati sul telefono."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"visualizzazione stato della rete"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Consente a un\'applicazione di visualizzare lo stato di tutte le reti."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"accesso completo a Internet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Consente a un\'applicazione di creare socket di rete."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"scrittura impostazioni APN"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Consente a un\'applicazione di modificare le impostazioni APN, come proxy e porta di qualsiasi APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"modifica connettività di rete"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Consente a un\'applicazione di modificare lo stato di connettività di rete."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiare l\'impostazione di utilizzo dei dati in background"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Consente a un\'applicazione di cambiare l\'impostazione di utilizzo dei dati in background."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"visualizzazione stato Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Consente a un\'applicazione di visualizzare le informazioni relative allo stato della connessione Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"modifica stato Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Consente a un\'applicazione di connettersi/disconnettersi da punti di accesso Wi-Fi e di apportare modifiche alle reti Wi-Fi configurate."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"consenti ricezione multicast Wi-Fi"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Consente a un\'applicazione di ricevere pacchetti non direttamente indirizzati al tuo dispositivo. Può essere utile durante la ricerca di servizi offerti nelle vicinanze. Consuma di più rispetto alla modalità non multicast."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"gestione Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Consente a un\'applicazione di configurare il telefono Bluetooth locale e di rilevare e abbinare dispositivi remoti."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"creazione connessioni Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Consente a un\'applicazione di visualizzare la configurazione del telefono Bluetooth locale e di stabilire e accettare connessioni con dispositivi associati."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"disattivazione blocco tastiera"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Consente la disattivazione da parte di un\'applicazione del blocco tastiera e di eventuali protezioni tramite password associate. Un valido esempio è la disattivazione da parte del telefono del blocco tastiera quando riceve una telefonata in entrata, e la successiva riattivazione del blocco al termine della chiamata."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lettura impostazioni di sincronizz."</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Consente a un\'applicazione di leggere le impostazioni di sincronizzazione, come l\'attivazione o meno della sincronizzazione per Contatti."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"scrittura impostazioni di sincronizz."</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Consente a un\'applicazione di modificare le impostazioni di sincronizzazione, come l\'attivazione o meno della sincronizzazione per Contatti."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"lettura statistiche di sincronizz."</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Consente a un\'applicazione di leggere le statistiche di sincronizzazione, per esempio la cronologia delle sincronizzazioni effettuate."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lettura feed sottoscritti"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Consente a un\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"scrittura feed sottoscritti"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Consente la modifica da parte di un\'applicazione dei feed attualmente sincronizzati. Le applicazioni dannose potrebbero essere in grado di modificare i feed sincronizzati."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"lettura dizionario definito dall\'utente"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Consente a un\'applicazione di leggere parole, nomi e frasi private che l\'utente potrebbe aver memorizzato nel dizionario utente."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"scrittura nel dizionario definito dall\'utente"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Consente a un\'applicazione di scrivere nuove parole nel dizionario utente."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"modificare/eliminare i contenuti della scheda SD"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Consente a un\'applicazione di scrivere sulla scheda SD."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"&lt;senza nome&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Nessun numero di telefono)"</string>
+ <string name="unknownName">"(Sconosciuto)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Segreteria"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problema di connessione o codice MMI non valido."</string>
+ <string name="serviceEnabled">"Il servizio è stato attivato."</string>
+ <string name="serviceEnabledFor">"Il servizio è stato attivato per:"</string>
+ <string name="serviceDisabled">"Il servizio è stato disattivato."</string>
+ <string name="serviceRegistered">"Registrazione effettuata."</string>
+ <string name="serviceErased">"Eliminazione effettuata."</string>
+ <string name="passwordIncorrect">"Password errata."</string>
+ <string name="mmiComplete">"MMI completo."</string>
+ <string name="badPin">"Il PIN attuale digitato è errato."</string>
+ <string name="badPuk">"Il PUK digitato è errato."</string>
+ <string name="mismatchPin">"I PIN inseriti non corrispondono."</string>
+ <string name="invalidPin">"Il PIN deve essere di 4-8 numeri."</string>
+ <string name="needPuk">"La SIM è bloccata tramite PUK. Digita il codice PUK per sbloccarla."</string>
+ <string name="needPuk2">"Digita il PUK2 per sbloccare la SIM."</string>
+ <string name="ClipMmi">"ID chiamante in entrata"</string>
+ <string name="ClirMmi">"ID chiamante in uscita"</string>
+ <string name="CfMmi">"Deviazione chiamate"</string>
+ <string name="CwMmi">"Avviso di chiamata"</string>
+ <string name="BaMmi">"Blocco chiamate"</string>
+ <string name="PwdMmi">"Modifica password"</string>
+ <string name="PinMmi">"Modifica PIN"</string>
+ <string name="CnipMmi">"Numero chiamante presente"</string>
+ <string name="CnirMmi">"Numero chiamante con restrizioni"</string>
+ <string name="ThreeWCMmi">"Chiamata a tre"</string>
+ <string name="RuacMmi">"Rifiuto di chiamate fastidiose non desiderate"</string>
+ <string name="CndMmi">"Recapito numero chiamante"</string>
+ <string name="DndMmi">"Non disturbare"</string>
+ <string name="CLIRDefaultOnNextCallOn">"ID chiamante generalmente limitato. Prossima chiamata: limitato"</string>
+ <string name="CLIRDefaultOnNextCallOff">"ID chiamante generalmente limitato. Prossima chiamata: non limitato"</string>
+ <string name="CLIRDefaultOffNextCallOn">"ID chiamante generalmente non limitato. Prossima chiamata: limitato"</string>
+ <string name="CLIRDefaultOffNextCallOff">"ID chiamante generalmente non limitato. Prossima chiamata: non limitato"</string>
+ <string name="serviceNotProvisioned">"Servizio non fornito."</string>
+ <string name="CLIRPermanent">"Impossibile modificare l\'impostazione dell\'ID del chiamante."</string>
+ <string name="RestrictedChangedTitle">"Accesso limitato modificato"</string>
+ <string name="RestrictedOnData">"Il servizio dati è bloccato."</string>
+ <string name="RestrictedOnEmergency">"Il servizio di emergenza è bloccato."</string>
+ <string name="RestrictedOnNormal">"Il servizio vocale/SMS è bloccato."</string>
+ <string name="RestrictedOnAll">"Tutti i servizi vocali/SMS sono bloccati."</string>
+ <string name="serviceClassVoice">"Voce"</string>
+ <string name="serviceClassData">"Dati"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asinc"</string>
+ <string name="serviceClassDataSync">"Sinc"</string>
+ <string name="serviceClassPacket">"Pacchetto"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Indicatore roaming attivato"</string>
+ <string name="roamingText1">"Indicatore roaming disattivato"</string>
+ <string name="roamingText2">"Indicatore roaming lampeggiante"</string>
+ <string name="roamingText3">"Fuori dal vicinato"</string>
+ <string name="roamingText4">"Fuori dall\'edificio"</string>
+ <string name="roamingText5">"Roaming - Sistema preferito"</string>
+ <string name="roamingText6">"Roaming - Sistema disponibile"</string>
+ <string name="roamingText7">"Roaming - Partner Alliance"</string>
+ <string name="roamingText8">"Roaming - Partner Premium"</string>
+ <string name="roamingText9">"Roaming - Funzionalità servizio completo"</string>
+ <string name="roamingText10">"Roaming - Funzionalità servizio parziale"</string>
+ <string name="roamingText11">"Banner roaming attivato"</string>
+ <string name="roamingText12">"Banner roaming disattivato"</string>
+ <string name="roamingTextSearching">"Ricerca servizio"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> dopo <xliff:g id="TIME_DELAY">{2}</xliff:g> secondi"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
+ <string name="fcComplete">"Codice funzione completo."</string>
+ <string name="fcError">"Problema di connessione o codice funzione non valido."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"La pagina web contiene un errore."</string>
+ <string name="httpErrorLookup">"Impossibile trovare l\'URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Schema di autenticazione del sito non supportato."</string>
+ <string name="httpErrorAuth">"Autenticazione non riuscita."</string>
+ <string name="httpErrorProxyAuth">"Autenticazione tramite il server proxy non riuscita."</string>
+ <string name="httpErrorConnect">"Connessione al server non riuscita."</string>
+ <string name="httpErrorIO">"Impossibile comunicare con il server. Riprova più tardi."</string>
+ <string name="httpErrorTimeout">"Tempo esaurito per la connessione al server."</string>
+ <string name="httpErrorRedirectLoop">"La pagina contiene troppi reindirizzamenti sul server."</string>
+ <string name="httpErrorUnsupportedScheme">"Protocollo non supportato."</string>
+ <string name="httpErrorFailedSslHandshake">"Impossibile stabilire una connessione protetta."</string>
+ <string name="httpErrorBadUrl">"Impossibile aprire la pagina. URL non valido."</string>
+ <string name="httpErrorFile">"Impossibile accedere al file."</string>
+ <string name="httpErrorFileNotFound">"Impossibile trovare il file richiesto."</string>
+ <string name="httpErrorTooManyRequests">"Troppe richieste in fase di elaborazione. Riprova più tardi."</string>
+ <string name="contentServiceSync">"Sinc"</string>
+ <string name="contentServiceSyncNotificationTitle">"Sincronizzazione"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Troppe eliminazioni di <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
+ <string name="me">"Io"</string>
+ <string name="power_dialog">"Opzioni telefono"</string>
+ <string name="silent_mode">"Modalità silenziosa"</string>
+ <string name="turn_on_radio">"Attiva wireless"</string>
+ <string name="turn_off_radio">"Disattiva wireless"</string>
+ <string name="screen_lock">"Blocco schermo"</string>
+ <string name="power_off">"Spegni"</string>
+ <string name="shutdown_progress">"Spegnimento..."</string>
+ <string name="shutdown_confirm">"Il telefono verrà spento."</string>
+ <string name="no_recent_tasks">"Nessuna applicazione recente."</string>
+ <string name="global_actions">"Opzioni telefono"</string>
+ <string name="global_action_lock">"Blocco schermo"</string>
+ <string name="global_action_power_off">"Spegni"</string>
+ <string name="global_action_toggle_silent_mode">"Modalità silenziosa"</string>
+ <string name="global_action_silent_mode_on_status">"Audio non attivo"</string>
+ <string name="global_action_silent_mode_off_status">"Audio attivo"</string>
+ <string name="global_actions_toggle_airplane_mode">"Modalità aereo attiva"</string>
+ <string name="global_actions_airplane_mode_on_status">"Modalità aereo attiva"</string>
+ <string name="global_actions_airplane_mode_off_status">"Modalità aereo non attiva"</string>
+ <string name="safeMode">"Modalità provvisoria"</string>
+ <string name="android_system_label">"Sistema Android"</string>
+ <string name="permgrouplab_costMoney">"Servizi che prevedono un costo"</string>
+ <string name="permgroupdesc_costMoney">"Consentono alle applicazioni di svolgere operazioni che possono comportare un costo."</string>
+ <string name="permgrouplab_messages">"I tuoi messaggi"</string>
+ <string name="permgroupdesc_messages">"Leggere e scrivere SMS, email e altri messaggi."</string>
+ <string name="permgrouplab_personalInfo">"Informazioni personali"</string>
+ <string name="permgroupdesc_personalInfo">"Accedere direttamente ai contatti e al calendario memorizzati sul telefono."</string>
+ <string name="permgrouplab_location">"La tua posizione"</string>
+ <string name="permgroupdesc_location">"Monitorare la posizione fisica dell\'utente"</string>
+ <string name="permgrouplab_network">"Comunicazione di rete"</string>
+ <string name="permgroupdesc_network">"Consentono l\'accesso delle applicazioni a varie funzionalità di rete."</string>
+ <string name="permgrouplab_accounts">"I tuoi account Google"</string>
+ <string name="permgroupdesc_accounts">"Accedere agli account Google disponibili."</string>
+ <string name="permgrouplab_hardwareControls">"Controlli hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Accedere direttamente all\'hardware del ricevitore."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonate"</string>
+ <string name="permgroupdesc_phoneCalls">"Monitorare, registrare ed elaborare le telefonate."</string>
+ <string name="permgrouplab_systemTools">"Strumenti di sistema"</string>
+ <string name="permgroupdesc_systemTools">"Accesso al sistema e controllo di livello inferiore."</string>
+ <string name="permgrouplab_developmentTools">"Strumenti di sviluppo"</string>
+ <string name="permgroupdesc_developmentTools">"Funzionalità necessarie soltanto agli sviluppatori di applicazioni."</string>
+ <string name="permgrouplab_storage">"Archiviazione"</string>
+ <string name="permgroupdesc_storage">"Accesso alla scheda SD."</string>
+ <string name="permlab_statusBar">"disattivare o modificare la barra di stato"</string>
+ <string name="permdesc_statusBar">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
+ <string name="permlab_expandStatusBar">"espansione/compressione barra di stato"</string>
+ <string name="permdesc_expandStatusBar">"Consente all\'applicazione di espandere o comprimere la barra di stato."</string>
+ <string name="permlab_processOutgoingCalls">"intercettazione chiamate in uscita"</string>
+ <string name="permdesc_processOutgoingCalls">"Consente all\'applicazione di elaborare le chiamate in uscita e di modificare il numero da comporre. Le applicazioni dannose potrebbero monitorare, deviare o impedire le chiamate in uscita."</string>
+ <string name="permlab_receiveSms">"ricezione SMS"</string>
+ <string name="permdesc_receiveSms">"Consente il ricevimento e l\'elaborazione di SMS da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
+ <string name="permlab_receiveMms">"ricezione MMS"</string>
+ <string name="permdesc_receiveMms">"Consente il ricevimento e l\'elaborazione di MMS da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
+ <string name="permlab_sendSms">"invio SMS"</string>
+ <string name="permdesc_sendSms">"Consente all\'applicazione di inviare messaggi SMS. Le applicazioni dannose potrebbero inviare messaggi a tua insaputa facendoti sostenere dei costi."</string>
+ <string name="permlab_readSms">"lettura SMS o MMS"</string>
+ <string name="permdesc_readSms">"Consente all\'applicazione di leggere SMS memorizzati sul telefono o sulla SIM. Le applicazioni dannose potrebbero leggere messaggi riservati."</string>
+ <string name="permlab_writeSms">"modifica SMS o MMS"</string>
+ <string name="permdesc_writeSms">"Consente all\'applicazione di rispondere a SMS memorizzati sul telefono o sulla SIM. Le applicazioni dannose potrebbero eliminare i messaggi."</string>
+ <string name="permlab_receiveWapPush">"ricezione WAP"</string>
+ <string name="permdesc_receiveWapPush">"Consente il ricevimento e l\'elaborazione di messaggi WAP da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
+ <string name="permlab_getTasks">"recupero applicazioni in esecuzione"</string>
+ <string name="permdesc_getTasks">"Consente all\'applicazione di recuperare informazioni sulle attività in esecuzione ed eseguite di recente. Le applicazioni dannose potrebbero essere in grado di scoprire informazioni riservate su altre applicazioni."</string>
+ <string name="permlab_reorderTasks">"riordinamento applicazioni in esecuz."</string>
+ <string name="permdesc_reorderTasks">"Consente a un\'applicazione di spostare attività in primo e secondo piano. Le applicazioni dannose possono imporsi ponendosi automaticamente in primo piano."</string>
+ <string name="permlab_setDebugApp">"attivazione debug delle applicazioni"</string>
+ <string name="permdesc_setDebugApp">"Consente a un\'applicazione di attivare il debug per un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per interrompere altre applicazioni."</string>
+ <string name="permlab_changeConfiguration">"modifica impostazioni UI"</string>
+ <string name="permdesc_changeConfiguration">"Consente a un\'applicazione di modificare la configurazione corrente, come le dimensioni dei caratteri locali o complessive."</string>
+ <string name="permlab_restartPackages">"riavvio altre applicazioni"</string>
+ <string name="permdesc_restartPackages">"Consente a un\'applicazione di riavviare forzatamente altre applicazioni."</string>
+ <string name="permlab_forceBack">"chiusura forzata dell\'applicazione"</string>
+ <string name="permdesc_forceBack">"Consente a un\'applicazione di forzare la chiusura di attività in primo piano. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <string name="permlab_dump">"recupero stato interno del sistema"</string>
+ <string name="permdesc_dump">"Consente all\'applicazione di recuperare lo stato interno del sistema. Le applicazioni dannose potrebbero recuperare molte informazioni riservate e protette di cui non dovrebbero avere mai bisogno."</string>
+ <string name="permlab_shutdown">"chiusura parziale"</string>
+ <string name="permdesc_shutdown">"Mette il gestore delle attività in uno stato di chiusura. Non esegue una chiusura completa."</string>
+ <string name="permlab_stopAppSwitches">"impedire commutazione applicazione"</string>
+ <string name="permdesc_stopAppSwitches">"Impedisce all\'utente di passare a un\'altra applicazione."</string>
+ <string name="permlab_runSetActivityWatcher">"monitoraggio e controllo avvio applicazioni"</string>
+ <string name="permdesc_runSetActivityWatcher">"Consente a un\'applicazione di monitorare e controllare la modalità di avvio delle attività nel sistema. Le applicazioni dannose potrebbero compromettere totalmente il sistema. Questa autorizzazione è necessaria soltanto per lo sviluppo, mai per il normale utilizzo del telefono."</string>
+ <string name="permlab_broadcastPackageRemoved">"invio broadcast rimossi dal pacchetto"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Consente a un\'applicazione di trasmettere una notifica di rimozione del pacchetto di un\'applicazione. Le applicazioni dannose potrebbero sfruttare questa possibilità per interrompere ogni altra applicazione in esecuzione."</string>
+ <string name="permlab_broadcastSmsReceived">"invio broadcast ricevuti tramite SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un SMS. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che siano stati ricevuti SMS."</string>
+ <string name="permlab_broadcastWapPush">"invio broadcast ricevuti tramite WAP-PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un messaggio WAP PUSH. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che sia stato ricevuto un MMS o per sostituire automaticamente contenuti di pagine web con varianti dannose."</string>
+ <string name="permlab_setProcessLimit">"numero limite di processi in esecuzione"</string>
+ <string name="permdesc_setProcessLimit">"Consente a un\'applicazione di stabilire il numero massimo di processi in esecuzione. Mai necessario per le normali applicazioni."</string>
+ <string name="permlab_setAlwaysFinish">"chiusura applicazioni in background"</string>
+ <string name="permdesc_setAlwaysFinish">"Consente a un\'applicazione di controllare se le attività sono sempre completate quando vengono messe in secondo piano. Mai necessario per le normali applicazioni."</string>
+ <string name="permlab_batteryStats">"modifica statistiche batteria"</string>
+ <string name="permdesc_batteryStats">"Consente la modifica delle statistiche sulla batteria raccolte. Da non usare per normali applicazioni."</string>
+ <string name="permlab_backup">"controllo del backup di sistema e ripristino"</string>
+ <string name="permdesc_backup">"Consente all\'applicazione di controllare i backup dei sistemi e il meccanismo di ripristino. Da non usare per normali applicazioni."</string>
+ <string name="permlab_internalSystemWindow">"visualizzazione finestre non autorizzate"</string>
+ <string name="permdesc_internalSystemWindow">"Consente la creazione di finestre destinate all\'uso nell\'interfaccia utente di sistema interna. Da non usare per normali applicazioni."</string>
+ <string name="permlab_systemAlertWindow">"visualizzazione avvisi di sistema"</string>
+ <string name="permdesc_systemAlertWindow">"Consente a un\'applicazione di visualizzare finestre di avviso del sistema. Le applicazioni dannose possono sfruttare questa opzione per riempire lo schermo del telefono di messaggi."</string>
+ <string name="permlab_setAnimationScale">"modifica velocità di animazione globale"</string>
+ <string name="permdesc_setAnimationScale">"Consente a un\'applicazione di modificare la velocità di animazione globale (animazioni più veloci o più lente) in qualsiasi momento."</string>
+ <string name="permlab_manageAppTokens">"gestione token applicazioni"</string>
+ <string name="permdesc_manageAppTokens">"Consente alle applicazioni di creare e gestire i propri token, ignorando il normale ordinamento Z. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <string name="permlab_injectEvents">"uso tasti e pulsanti di controllo"</string>
+ <string name="permdesc_injectEvents">"Consente a un\'applicazione di offrire i suoi eventi di input (pressioni di tasti etc.) ad altre applicazioni. Le applicazioni dannose possono sfruttare questa possibilità per assumere il controllo del telefono."</string>
+ <string name="permlab_readInputState">"registrazione testo digitato e azioni eseguite"</string>
+ <string name="permdesc_readInputState">"Consente il rilevamento da parte delle applicazioni dei tasti premuti anche durante l\'interazione con un\'altra applicazione (come nel caso di inserimento di una password). Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <string name="permlab_bindInputMethod">"associaz. a un metodo di inserimento"</string>
+ <string name="permdesc_bindInputMethod">"Consente l\'associazione all\'interfaccia principale di un metodo di inserimento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <string name="permlab_setOrientation">"modifica orientamento dello schermo"</string>
+ <string name="permdesc_setOrientation">"Consente a un\'applicazione di cambiare la rotazione dello schermo in qualsiasi momento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
+ <string name="permlab_signalPersistentProcesses">"invio segnali Linuz alle applicazioni"</string>
+ <string name="permdesc_signalPersistentProcesses">"Consente all\'applicazione di richiedere l\'invio del segnale fornito a tutti i processi persistenti."</string>
+ <string name="permlab_persistentActivity">"esecuzione permanente delle applicazioni"</string>
+ <string name="permdesc_persistentActivity">"Consente a un\'applicazione di rendere delle sue parti costanti in modo che il sistema non possa usarla per altre applicazioni."</string>
+ <string name="permlab_deletePackages">"eliminazione applicazioni"</string>
+ <string name="permdesc_deletePackages">"Consente a un\'applicazione di eliminare pacchetti Android. Le applicazioni dannose possono sfruttare questa possibilità per eliminare importanti applicazioni."</string>
+ <string name="permlab_clearAppUserData">"eliminazione dati di altre applicazioni"</string>
+ <string name="permdesc_clearAppUserData">"Consente a un\'applicazione di cancellare dati dell\'utente."</string>
+ <string name="permlab_deleteCacheFiles">"eliminazione cache altre applicazioni"</string>
+ <string name="permdesc_deleteCacheFiles">"Consente a un\'applicazione di eliminare file della cache."</string>
+ <string name="permlab_getPackageSize">"calcolo spazio di archiviazione applicazioni"</string>
+ <string name="permdesc_getPackageSize">"Consente a un\'applicazione di recuperare i suoi codici, dati e dimensioni della cache"</string>
+ <string name="permlab_installPackages">"installazione diretta di applicazioni"</string>
+ <string name="permdesc_installPackages">"Consente a un\'applicazione di installare nuovi pacchetti Android o aggiornamenti. Le applicazioni dannose possono sfruttare questa possibilità per aggiungere nuove applicazioni con potenti autorizzazioni arbitrarie."</string>
+ <string name="permlab_clearAppCache">"eliminazione dati della cache applicazioni"</string>
+ <string name="permdesc_clearAppCache">"Consente a un\'applicazione di liberare spazio sul telefono eliminando file nella directory della cache dell\'applicazione. L\'accesso è generalmente limitato a processi di sistema."</string>
+ <string name="permlab_readLogs">"lettura file di registro sistema"</string>
+ <string name="permdesc_readLogs">"Consente a un\'applicazione di leggere vari file di registro del sistema per trovare informazioni generali sulle operazioni effettuate con il telefono. Tali file non dovrebbero contenere informazioni personali o riservate."</string>
+ <string name="permlab_diagnostic">"lettura/scrittura risorse di proprietà di diag"</string>
+ <string name="permdesc_diagnostic">"Consente a un\'applicazione di leggere le risorse del gruppo diag e scrivere a esse, per esempio i file in /dev. Questa capacità potrebbe influire sulla stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
+ <string name="permlab_changeComponentState">"attivazione/disattivazione componenti applicazioni"</string>
+ <string name="permdesc_changeComponentState">"Consente a un\'applicazione di attivare o disattivare un componente di un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per disattivare importanti funzionalità del telefono. Prestare attenzione con questa autorizzazione perché è possibile rendere inutilizzabili, incoerenti o instabili i componenti delle applicazioni."</string>
+ <string name="permlab_setPreferredApplications">"impostazione applicazioni preferite"</string>
+ <string name="permdesc_setPreferredApplications">"Consente la modifica da parte di un\'applicazione delle applicazioni preferite. Le applicazioni dannose potrebbero essere in grado di modificare automaticamente le applicazioni in esecuzione, effettuando lo spoofing delle applicazioni esistenti per raccogliere dati riservati."</string>
+ <string name="permlab_writeSettings">"modifica impostazioni di sistema globali"</string>
+ <string name="permdesc_writeSettings">"Consente la modifica in un\'applicazione dei dati delle impostazioni del sistema. Le applicazioni dannose possono danneggiare la configurazione del sistema."</string>
+ <string name="permlab_writeSecureSettings">"modificare le impostazioni di protezione del sistema"</string>
+ <string name="permdesc_writeSecureSettings">"Consente a un\'applicazione di modificare i dati delle impostazioni di protezione del sistema. Da non usare per normali applicazioni."</string>
+ <string name="permlab_writeGservices">"modifica mappa servizi Google"</string>
+ <string name="permdesc_writeGservices">"Consente a un\'applicazione di modificare la mappa dei servizi Google. Da non usare per normali applicazioni."</string>
+ <string name="permlab_receiveBootCompleted">"apertura automatica all\'avvio"</string>
+ <string name="permdesc_receiveBootCompleted">"Consente a un\'applicazione di aprirsi automaticamente al termine dell\'avvio del sistema. Potrebbe essere necessario più tempo per l\'avvio del telefono e l\'applicazione potrebbe rallentare tutte le funzioni del telefono rimanendo sempre in esecuzione."</string>
+ <string name="permlab_broadcastSticky">"invio broadcast permanenti"</string>
+ <string name="permdesc_broadcastSticky">"Consente a un\'applicazione di inviare broadcast permanenti, che permangono anche al termine del broadcast. Le applicazioni dannose possono rendere il telefono lento o instabile tramite un uso eccessivo della memoria."</string>
+ <string name="permlab_readContacts">"lettura dati di contatto"</string>
+ <string name="permdesc_readContacts">"Consente la lettura da parte di un\'applicazione di tutti i dati (gli indirizzi) di contatto memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per inviare i dati ad altre persone."</string>
+ <string name="permlab_writeContacts">"scrittura dati di contatto"</string>
+ <string name="permdesc_writeContacts">"Consente a un\'applicazione di modificare i dati (gli indirizzi) di contatto memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati di contatto."</string>
+ <string name="permlab_writeOwnerData">"scrittura dati proprietario"</string>
+ <string name="permdesc_writeOwnerData">"Consente a un\'applicazione di modificare i dati del proprietario del telefono memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare tali dati."</string>
+ <string name="permlab_readOwnerData">"lettura dati proprietario"</string>
+ <string name="permdesc_readOwnerData">"Consente a un\'applicazione di leggere i dati del proprietario del telefono memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per leggere tali dati."</string>
+ <string name="permlab_readCalendar">"lettura dati di calendario"</string>
+ <string name="permdesc_readCalendar">"Consente la lettura da parte di un\'applicazione di tutti gli eventi di calendario memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per inviare i tuoi eventi di calendario ad altre persone."</string>
+ <string name="permlab_writeCalendar">"scrittura dati di calendario"</string>
+ <string name="permdesc_writeCalendar">"Consente a un\'applicazione di modificare gli eventi di calendario memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati del calendario."</string>
+ <string name="permlab_accessMockLocation">"fonti di localizzazione fittizie per test"</string>
+ <string name="permdesc_accessMockLocation">"Creare fonti di localizzazione fittizie per test. Le applicazioni dannose possono sfruttare questa possibilità per sostituire la posizione e/o lo stato restituito da reali fonti di localizzazione come GPS o provider di rete."</string>
+ <string name="permlab_accessLocationExtraCommands">"accesso a comandi aggiuntivi del provider di localizz."</string>
+ <string name="permdesc_accessLocationExtraCommands">"Accedere a comandi aggiuntivi del provider di localizzazione. Le applicazioni dannose possono sfruttare questa possibilità per interferire con il funzionamento del GPS o di altre fonti di localizzazione."</string>
+ <string name="permlab_installLocationProvider">"autorizzazione a installare un provider di localizzazione"</string>
+ <string name="permdesc_installLocationProvider">"Creare fonti di localizzazione fittizie per test. Le applicazioni dannose possono sfruttare questa possibilità per sostituire la posizione e/o lo stato restituito da reali fonti di localizzazione come GPS o provider di rete oppure per monitorare e segnalare la tua posizione a una fonte esterna."</string>
+ <string name="permlab_accessFineLocation">"localizzazione precisa (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Consente l\'accesso a fonti di localizzazione precisa, come il sistema GPS del telefono, se disponibile. Le applicazioni dannose possono sfruttare questa possibilità per determinare la tua posizione e, nel farlo, far esaurire più in fretta la batteria."</string>
+ <string name="permlab_accessCoarseLocation">"localizzazione approssimativa (basata sulla rete)"</string>
+ <string name="permdesc_accessCoarseLocation">"Consente l\'accesso a fonti di localizzazione geografica non puntuale (come il database della rete cellulare) per determinare una posizione approssimativa del telefono, quando possibile. Le applicazioni dannose possono sfruttare questa possibilità per determinare approssimativamente dove ti trovi."</string>
+ <string name="permlab_accessSurfaceFlinger">"accesso a SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Consente l\'utilizzo dell\'applicazione di funzioni di basso livello SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"lettura buffer di frame"</string>
+ <string name="permdesc_readFrameBuffer">"Consente la lettura da parte dell\'applicazione dei contenuti del buffer di frame."</string>
+ <string name="permlab_modifyAudioSettings">"modifica impostazioni audio"</string>
+ <string name="permdesc_modifyAudioSettings">"Consente all\'applicazione di modificare impostazioni audio globali come volume e routing."</string>
+ <string name="permlab_recordAudio">"registrazione audio"</string>
+ <string name="permdesc_recordAudio">"Consente l\'accesso dell\'applicazione al percorso di registrazione dell\'audio."</string>
+ <string name="permlab_camera">"acquisizione foto"</string>
+ <string name="permdesc_camera">"Consente di scattare foto nell\'applicazione con la fotocamera. L\'applicazione può acquisire in qualsiasi momento le immagini rilevate dalla fotocamera."</string>
+ <string name="permlab_brick">"disattivazione telefono"</string>
+ <string name="permdesc_brick">"Consente all\'applicazione di disattivare l\'intero telefono in modo definitivo. Questa autorizzazione è molto pericolosa."</string>
+ <string name="permlab_reboot">"riavvio forzato del telefono"</string>
+ <string name="permdesc_reboot">"Consente all\'applicazione di imporre il riavvio del telefono."</string>
+ <string name="permlab_mount_unmount_filesystems">"installazione/disinstallazione filesystem"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Consente montaggio e smontaggio da parte dell\'applicazione dei filesystem degli archivi rimovibili."</string>
+ <string name="permlab_mount_format_filesystems">"formattazione archivio esterno"</string>
+ <string name="permdesc_mount_format_filesystems">"Consente all\'applicazione di formattare l\'archivio rimovibile."</string>
+ <string name="permlab_vibrate">"controllo vibrazione"</string>
+ <string name="permdesc_vibrate">"Consente all\'applicazione di controllare la vibrazione."</string>
+ <string name="permlab_flashlight">"controllo flash"</string>
+ <string name="permdesc_flashlight">"Consente all\'applicazione di controllare il flash."</string>
+ <string name="permlab_hardware_test">"esecuzione test hardware"</string>
+ <string name="permdesc_hardware_test">"Consente all\'applicazione di controllare varie periferiche per il test dell\'hardware."</string>
+ <string name="permlab_callPhone">"chiamata diretta n. telefono"</string>
+ <string name="permdesc_callPhone">"Consente all\'applicazione di chiamare numeri automaticamente. Le applicazioni dannose potrebbero far risultare chiamate impreviste sulla bolletta telefonica. Questa autorizzazione non consente all\'applicazione di chiamare numeri di emergenza."</string>
+ <string name="permlab_callPrivileged">"chiamata diretta di tutti i n. telefono"</string>
+ <string name="permdesc_callPrivileged">"Consente all\'applicazione di chiamare qualsiasi numero, compresi quelli di emergenza, automaticamente. Le applicazioni dannose potrebbero effettuare chiamate non necessarie e illegali a servizi di emergenza."</string>
+ <string name="permlab_locationUpdates">"controllo notifiche aggiornamento posizione"</string>
+ <string name="permdesc_locationUpdates">"Consente l\'attivazione/disattivazione delle notifiche di aggiornamento della posizione dal segnale cellulare. Da non usare per normali applicazioni."</string>
+ <string name="permlab_checkinProperties">"accesso a proprietà di archiviazione"</string>
+ <string name="permdesc_checkinProperties">"Consente l\'accesso di lettura/scrittura alle proprietà caricate dal servizio di archiviazione. Da non usare per normali applicazioni."</string>
+ <string name="permlab_bindGadget">"scegliere widget"</string>
+ <string name="permdesc_bindGadget">"Consente all\'applicazione di indicare al sistema quali widget possono essere utilizzati e da quale applicazione. Con questa autorizzazione, le applicazioni possono consentire ad altre applicazioni di accedere a dati personali. Da non usare per normali applicazioni."</string>
+ <string name="permlab_modifyPhoneState">"modifica stato del telefono"</string>
+ <string name="permdesc_modifyPhoneState">"Consente all\'applicazione di controllare le funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può cambiare rete, attivare e disattivare il segnale cellulare e così via, senza alcuna notifica."</string>
+ <string name="permlab_readPhoneState">"lettura stato del telefono"</string>
+ <string name="permdesc_readPhoneState">"Consente l\'accesso dell\'applicazione alle funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può determinare il numero del telefono in uso, se una chiamata è attiva o meno, il numero a cui è collegata la chiamata e simili."</string>
+ <string name="permlab_wakeLock">"disattivazione stand-by del telefono"</string>
+ <string name="permdesc_wakeLock">"Consente a un\'applicazione di impedire lo stand-by del telefono."</string>
+ <string name="permlab_devicePower">"accensione o spegnimento del telefono"</string>
+ <string name="permdesc_devicePower">"Consente all\'applicazione di accendere o spegnere il telefono."</string>
+ <string name="permlab_factoryTest">"esecuzione in modalità test di fabbrica"</string>
+ <string name="permdesc_factoryTest">"In esecuzione come test del produttore di basso livello, consentendo l\'accesso completo all\'hardware del telefono. Disponibile soltanto quando il telefono è in esecuzione in modalità test del produttore."</string>
+ <string name="permlab_setWallpaper">"impostazione sfondo"</string>
+ <string name="permdesc_setWallpaper">"Consente all\'applicazione di impostare lo sfondo del sistema."</string>
+ <string name="permlab_setWallpaperHints">"impostaz. suggerimenti dimensioni sfondo"</string>
+ <string name="permdesc_setWallpaperHints">"Consente all\'applicazione di impostare i suggerimenti per le dimensioni dello sfondo del sistema."</string>
+ <string name="permlab_masterClear">"ripristino impostazioni predef. di fabbrica"</string>
+ <string name="permdesc_masterClear">"Consente a un\'applicazione di ripristinare le impostazioni di fabbrica del sistema, eliminando tutti i dati, le configurazioni e le applicazioni installate."</string>
+ <string name="permlab_setTimeZone">"impostazione fuso orario"</string>
+ <string name="permdesc_setTimeZone">"Consente a un\'applicazione di modificare il fuso orario del telefono."</string>
+ <string name="permlab_getAccounts">"rilevamento account noti"</string>
+ <string name="permdesc_getAccounts">"Consente a un\'applicazione di recuperare l\'elenco di account memorizzati sul telefono."</string>
+ <string name="permlab_accessNetworkState">"visualizzazione stato della rete"</string>
+ <string name="permdesc_accessNetworkState">"Consente a un\'applicazione di visualizzare lo stato di tutte le reti."</string>
+ <string name="permlab_createNetworkSockets">"accesso completo a Internet"</string>
+ <string name="permdesc_createNetworkSockets">"Consente a un\'applicazione di creare socket di rete."</string>
+ <string name="permlab_writeApnSettings">"scrittura impostazioni APN"</string>
+ <string name="permdesc_writeApnSettings">"Consente a un\'applicazione di modificare le impostazioni APN, come proxy e porta di qualsiasi APN."</string>
+ <string name="permlab_changeNetworkState">"modifica connettività di rete"</string>
+ <string name="permdesc_changeNetworkState">"Consente a un\'applicazione di modificare lo stato di connettività di rete."</string>
+ <string name="permlab_changeBackgroundDataSetting">"cambiare l\'impostazione di utilizzo dei dati in background"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Consente a un\'applicazione di cambiare l\'impostazione di utilizzo dei dati in background."</string>
+ <string name="permlab_accessWifiState">"visualizzazione stato Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Consente a un\'applicazione di visualizzare le informazioni relative allo stato della connessione Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"modifica stato Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Consente a un\'applicazione di connettersi/disconnettersi da punti di accesso Wi-Fi e di apportare modifiche alle reti Wi-Fi configurate."</string>
+ <string name="permlab_changeWifiMulticastState">"consenti ricezione multicast Wi-Fi"</string>
+ <string name="permdesc_changeWifiMulticastState">"Consente a un\'applicazione di ricevere pacchetti non direttamente indirizzati al tuo dispositivo. Può essere utile durante la ricerca di servizi offerti nelle vicinanze. Consuma di più rispetto alla modalità non multicast."</string>
+ <string name="permlab_bluetoothAdmin">"gestione Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Consente a un\'applicazione di configurare il telefono Bluetooth locale e di rilevare e abbinare dispositivi remoti."</string>
+ <string name="permlab_bluetooth">"creazione connessioni Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Consente a un\'applicazione di visualizzare la configurazione del telefono Bluetooth locale e di stabilire e accettare connessioni con dispositivi associati."</string>
+ <string name="permlab_disableKeyguard">"disattivazione blocco tastiera"</string>
+ <string name="permdesc_disableKeyguard">"Consente la disattivazione da parte di un\'applicazione del blocco tastiera e di eventuali protezioni tramite password associate. Un valido esempio è la disattivazione da parte del telefono del blocco tastiera quando riceve una telefonata in entrata, e la successiva riattivazione del blocco al termine della chiamata."</string>
+ <string name="permlab_readSyncSettings">"lettura impostazioni di sincronizz."</string>
+ <string name="permdesc_readSyncSettings">"Consente a un\'applicazione di leggere le impostazioni di sincronizzazione, come l\'attivazione o meno della sincronizzazione per Contatti."</string>
+ <string name="permlab_writeSyncSettings">"scrittura impostazioni di sincronizz."</string>
+ <string name="permdesc_writeSyncSettings">"Consente a un\'applicazione di modificare le impostazioni di sincronizzazione, come l\'attivazione o meno della sincronizzazione per Contatti."</string>
+ <string name="permlab_readSyncStats">"lettura statistiche di sincronizz."</string>
+ <string name="permdesc_readSyncStats">"Consente a un\'applicazione di leggere le statistiche di sincronizzazione, per esempio la cronologia delle sincronizzazioni effettuate."</string>
+ <string name="permlab_subscribedFeedsRead">"lettura feed sottoscritti"</string>
+ <string name="permdesc_subscribedFeedsRead">"Consente a un\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string>
+ <string name="permlab_subscribedFeedsWrite">"scrittura feed sottoscritti"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Consente la modifica da parte di un\'applicazione dei feed attualmente sincronizzati. Le applicazioni dannose potrebbero essere in grado di modificare i feed sincronizzati."</string>
+ <string name="permlab_readDictionary">"lettura dizionario definito dall\'utente"</string>
+ <string name="permdesc_readDictionary">"Consente a un\'applicazione di leggere parole, nomi e frasi private che l\'utente potrebbe aver memorizzato nel dizionario utente."</string>
+ <string name="permlab_writeDictionary">"scrittura nel dizionario definito dall\'utente"</string>
+ <string name="permdesc_writeDictionary">"Consente a un\'applicazione di scrivere nuove parole nel dizionario utente."</string>
+ <string name="permlab_sdcardWrite">"modificare/eliminare i contenuti della scheda SD"</string>
+ <string name="permdesc_sdcardWrite">"Consente a un\'applicazione di scrivere sulla scheda SD."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Casa"</item>
- <item msgid="869923650527136615">"Cellulare"</item>
- <item msgid="7897544654242874543">"Ufficio"</item>
- <item msgid="1103601433382158155">"Fax ufficio"</item>
- <item msgid="1735177144948329370">"Fax casa"</item>
- <item msgid="603878674477207394">"Cercapersone"</item>
- <item msgid="1650824275177931637">"Altro"</item>
- <item msgid="9192514806975898961">"Personalizzato"</item>
+ <item>"Casa"</item>
+ <item>"Cellulare"</item>
+ <item>"Ufficio"</item>
+ <item>"Fax ufficio"</item>
+ <item>"Fax casa"</item>
+ <item>"Cercapersone"</item>
+ <item>"Altro"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Casa"</item>
- <item msgid="7084237356602625604">"Ufficio"</item>
- <item msgid="1112044410659011023">"Altro"</item>
- <item msgid="2374913952870110618">"Personalizzato"</item>
+ <item>"Casa"</item>
+ <item>"Ufficio"</item>
+ <item>"Altro"</item>
+ <item>"Personalizzato"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Cellulare"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Casa"</item>
- <item msgid="5629153956045109251">"Ufficio"</item>
- <item msgid="4966604264500343469">"Altro"</item>
- <item msgid="4932682847595299369">"Personalizzato"</item>
+ <item>"Casa"</item>
+ <item>"Ufficio"</item>
+ <item>"Altro"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Casa"</item>
- <item msgid="1359644565647383708">"Uffico"</item>
- <item msgid="7868549401053615677">"Altro"</item>
- <item msgid="3145118944639869809">"Personalizzato"</item>
+ <item>"Casa"</item>
+ <item>"Uffico"</item>
+ <item>"Altro"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Ufficio"</item>
- <item msgid="4378074129049520373">"Altro"</item>
- <item msgid="3455047468583965104">"Personalizzato"</item>
+ <item>"Ufficio"</item>
+ <item>"Altro"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Inserisci il PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Codice PIN errato."</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Per sbloccare, premi Menu, poi 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numero di emergenza"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Nessun servizio)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Schermo bloccato."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Premi Menu per sbloccare o effettuare chiamate di emergenza."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Premi Menu per sbloccare."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Traccia la sequenza di sblocco"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Chiamata di emergenza"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Corretta."</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Riprova"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"In carica (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Carico."</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Collegare il caricabatterie."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Nessuna SIM presente."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Nessuna SIM presente nel telefono."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Inserisci una SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rete bloccata"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La SIM è bloccata tramite PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Consulta il Manuale utente o contatta il servizio clienti."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La SIM è bloccata."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Sblocco SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. "\n\n"Riprova fra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono tramite i dati di accesso di Google."\n\n"Riprova fra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Riprova fra <xliff:g id="NUMBER">%d</xliff:g> secondi."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Hai dimenticato la sequenza?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Troppi tentativi di inserimento della sequenza."</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Per sbloccare, accedi tramite il tuo account Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nome utente (email)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Password"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Accedi"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Password o nome utente non valido."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Cancella"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nessuna notifica"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"In corso"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifiche"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"In carica..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Collegare il caricabatterie"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteria quasi scarica:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"energia residua inferiore a <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Perché?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Test di fabbrica non riuscito"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"L\'azione FACTORY_TEST è supportata soltanto per i pacchetti installati in /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Nessun pacchetto trovato che fornisca l\'azione FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Riavvia"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"La pagina all\'indirizzo <xliff:g id="TITLE">%s</xliff:g> indica:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Uscire da questa pagina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Seleziona OK per continuare o Annulla per rimanere nella pagina corrente."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Conferma"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lettura cronologia e segnalibri del browser"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Consente all\'applicazione di leggere tutti gli URL visitati e tutti i segnalibri del browser."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"creazione cronologia e segnalibri del browser"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Consente a un\'applicazione di modificare la cronologia o i segnalibri del browser memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati del browser."</string>
- <string name="save_password_message" msgid="767344687139195790">"Memorizzare la password nel browser?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Non ora"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Memorizza"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Mai"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"L\'utente non è autorizzato ad aprire questa pagina."</string>
- <string name="text_copied" msgid="4985729524670131385">"Testo copiato negli appunti."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Altro"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"spazio"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Invio"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"Canc"</string>
- <string name="search_go" msgid="8298016669822141719">"Cerca"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mese fa"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Oltre 1 mese fa"</string>
+ <string name="keyguard_password_enter_pin_code">"Inserisci il PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Codice PIN errato."</string>
+ <string name="keyguard_label_text">"Per sbloccare, premi Menu, poi 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Numero di emergenza"</string>
+ <string name="lockscreen_carrier_default">"(Nessun servizio)"</string>
+ <string name="lockscreen_screen_locked">"Schermo bloccato."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Premi Menu per sbloccare o effettuare chiamate di emergenza."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Premi Menu per sbloccare."</string>
+ <string name="lockscreen_pattern_instructions">"Traccia la sequenza di sblocco"</string>
+ <string name="lockscreen_emergency_call">"Chiamata di emergenza"</string>
+ <string name="lockscreen_pattern_correct">"Corretta."</string>
+ <string name="lockscreen_pattern_wrong">"Riprova"</string>
+ <string name="lockscreen_plugged_in">"In carica (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Collegare il caricabatterie."</string>
+ <string name="lockscreen_missing_sim_message_short">"Nessuna SIM presente."</string>
+ <string name="lockscreen_missing_sim_message">"Nessuna SIM presente nel telefono."</string>
+ <string name="lockscreen_missing_sim_instructions">"Inserisci una SIM."</string>
+ <string name="lockscreen_network_locked_message">"Rete bloccata"</string>
+ <string name="lockscreen_sim_puk_locked_message">"La SIM è bloccata tramite PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Consulta il Manuale utente o contatta il servizio clienti."</string>
+ <string name="lockscreen_sim_locked_message">"La SIM è bloccata."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Sblocco SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. "\n\n"Riprova fra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono tramite i dati di accesso di Google."\n\n"Riprova fra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Riprova fra <xliff:g id="NUMBER">%d</xliff:g> secondi."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Hai dimenticato la sequenza?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Troppi tentativi di inserimento della sequenza."</string>
+ <string name="lockscreen_glogin_instructions">"Per sbloccare, accedi tramite il tuo account Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Nome utente (email)"</string>
+ <string name="lockscreen_glogin_password_hint">"Password"</string>
+ <string name="lockscreen_glogin_submit_button">"Accedi"</string>
+ <string name="lockscreen_glogin_invalid_input">"Password o nome utente non valido."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Nessuna notifica"</string>
+ <string name="status_bar_ongoing_events_title">"In corso"</string>
+ <string name="status_bar_latest_events_title">"Notifiche"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"In carica..."</string>
+ <string name="battery_low_title">"Collegare il caricabatterie"</string>
+ <string name="battery_low_subtitle">"Batteria quasi scarica:"</string>
+ <string name="battery_low_percent_format">"energia residua inferiore a <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="battery_low_why">"Perché?"</string>
+ <string name="factorytest_failed">"Test di fabbrica non riuscito"</string>
+ <string name="factorytest_not_system">"L\'azione FACTORY_TEST è supportata soltanto per i pacchetti installati in /system/app."</string>
+ <string name="factorytest_no_action">"Nessun pacchetto trovato che fornisca l\'azione FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Riavvia"</string>
+ <string name="js_dialog_title">"La pagina all\'indirizzo <xliff:g id="TITLE">%s</xliff:g> indica:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Uscire da questa pagina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Seleziona OK per continuare o Annulla per rimanere nella pagina corrente."</string>
+ <string name="save_password_label">"Conferma"</string>
+ <string name="permlab_readHistoryBookmarks">"lettura cronologia e segnalibri del browser"</string>
+ <string name="permdesc_readHistoryBookmarks">"Consente all\'applicazione di leggere tutti gli URL visitati e tutti i segnalibri del browser."</string>
+ <string name="permlab_writeHistoryBookmarks">"creazione cronologia e segnalibri del browser"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Consente a un\'applicazione di modificare la cronologia o i segnalibri del browser memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati del browser."</string>
+ <string name="save_password_message">"Memorizzare la password nel browser?"</string>
+ <string name="save_password_notnow">"Non ora"</string>
+ <string name="save_password_remember">"Memorizza"</string>
+ <string name="save_password_never">"Mai"</string>
+ <string name="open_permission_deny">"L\'utente non è autorizzato ad aprire questa pagina."</string>
+ <string name="text_copied">"Testo copiato negli appunti."</string>
+ <string name="more_item_label">"Altro"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"spazio"</string>
+ <string name="menu_enter_shortcut_label">"Invio"</string>
+ <string name="menu_delete_shortcut_label">"Canc"</string>
+ <string name="search_go">"Cerca"</string>
+ <string name="oneMonthDurationPast">"1 mese fa"</string>
+ <string name="beforeOneMonthDurationPast">"Oltre 1 mese fa"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 secondo fa"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> secondi fa"</item>
+ <item quantity="one">"1 secondo fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> secondi fa"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuto fa"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuti fa"</item>
+ <item quantity="one">"1 minuto fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minuti fa"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 ora fa"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
+ <item quantity="one">"1 ora fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ieri"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
+ <item quantity="one">"ieri"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"tra 1 secondo"</item>
- <item quantity="other" msgid="1241926116443974687">"tra <xliff:g id="COUNT">%d</xliff:g> secondi"</item>
+ <item quantity="one">"tra 1 secondo"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> secondi"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"tra 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"tra <xliff:g id="COUNT">%d</xliff:g> minuti"</item>
+ <item quantity="one">"tra 1 minuto"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> minuti"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"tra 1 ora"</item>
- <item quantity="other" msgid="547290677353727389">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
+ <item quantity="one">"tra 1 ora"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"domani"</item>
- <item quantity="other" msgid="5109449375100953247">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
+ <item quantity="one">"domani"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 sec fa"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sec fa"</item>
+ <item quantity="one">"1 sec fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sec fa"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 min fa"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min fa"</item>
+ <item quantity="one">"1 min fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> min fa"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 ora fa"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
+ <item quantity="one">"1 ora fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ieri"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
+ <item quantity="one">"ieri"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"tra 1 sec"</item>
- <item quantity="other" msgid="5495880108825805108">"tra <xliff:g id="COUNT">%d</xliff:g> sec"</item>
+ <item quantity="one">"tra 1 sec"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> sec"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"tra 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"tra <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ <item quantity="one">"tra 1 min"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> min"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"tra 1 ora"</item>
- <item quantity="other" msgid="3705373766798013406">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
+ <item quantity="one">"tra 1 ora"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"domani"</item>
- <item quantity="other" msgid="2973062968038355991">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
+ <item quantity="one">"domani"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"il %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"alle %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"nel %s"</string>
- <string name="day" msgid="8144195776058119424">"giorno"</string>
- <string name="days" msgid="4774547661021344602">"giorni"</string>
- <string name="hour" msgid="2126771916426189481">"ora"</string>
- <string name="hours" msgid="894424005266852993">"ore"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"min"</string>
- <string name="second" msgid="3184235808021478">"sec"</string>
- <string name="seconds" msgid="3161515347216589235">"sec"</string>
- <string name="week" msgid="5617961537173061583">"settimana"</string>
- <string name="weeks" msgid="6509623834583944518">"settimane"</string>
- <string name="year" msgid="4001118221013892076">"anno"</string>
- <string name="years" msgid="6881577717993213522">"anni"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Ogni giorno feriale (lun-ven)"</string>
- <string name="daily" msgid="5738949095624133403">"Quotidianamente"</string>
- <string name="weekly" msgid="983428358394268344">"Ogni settimana il <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Mensilmente"</string>
- <string name="yearly" msgid="1519577999407493836">"Annualmente"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Impossibile riprodurre il video"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Spiacenti, questo video non è valido per lo streaming su questo dispositivo."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Spiacenti. Impossibile riprodurre il video."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"mezzogiorno"</string>
- <string name="Noon" msgid="3342127745230013127">"Mezzogiorno"</string>
- <string name="midnight" msgid="7166259508850457595">"mezzanotte"</string>
- <string name="Midnight" msgid="5630806906897892201">"Mezzanotte"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Seleziona tutto"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleziona testo"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Termina selezione testo"</string>
- <string name="cut" msgid="3092569408438626261">"Taglia"</string>
- <string name="cutAll" msgid="2436383270024931639">"Taglia tutto"</string>
- <string name="copy" msgid="2681946229533511987">"Copia"</string>
- <string name="copyAll" msgid="2590829068100113057">"Copia tutto"</string>
- <string name="paste" msgid="5629880836805036433">"Incolla"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copia URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Metodo inserimento"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Aggiungi \"%s\" al dizionario"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Modifica testo"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Spazio in esaurimento"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Spazio di archiviazione del telefono in esaurimento."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Annulla"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Annulla"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Attenzione"</string>
- <string name="capital_on" msgid="1544682755514494298">"ON"</string>
- <string name="capital_off" msgid="6815870386972805832">"OFF"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Completa l\'azione con"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Usa come predefinita per questa azione."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Cancella predefinita in Home &gt; Impostazioni &gt; Applicazioni &gt; Gestisci applicazioni."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Seleziona un\'azione"</string>
- <string name="noApplications" msgid="1691104391758345586">"Nessuna applicazione è in grado di svolgere questa azione."</string>
- <string name="aerr_title" msgid="653922989522758100">"Spiacenti."</string>
- <string name="aerr_application" msgid="4683614104336409186">"Interruzione imprevista dell\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo<xliff:g id="PROCESS">%2$s</xliff:g>). Riprova."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Interruzione imprevista del processo <xliff:g id="PROCESS">%1$s</xliff:g>. Riprova."</string>
- <string name="anr_title" msgid="3100070910664756057">"Spiacenti."</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> (nell\'applicazione <xliff:g id="APPLICATION">%2$s</xliff:g>) non risponde."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> (nel processo <xliff:g id="PROCESS">%2$s</xliff:g>) non risponde."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (nel processo <xliff:g id="PROCESS">%2$s</xliff:g>) non risponde."</string>
- <string name="anr_process" msgid="1246866008169975783">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> non risponde."</string>
- <string name="force_close" msgid="3653416315450806396">"Termina"</string>
- <string name="report" msgid="4060218260984795706">"Segnala"</string>
- <string name="wait" msgid="7147118217226317732">"Attendi"</string>
- <string name="debug" msgid="9103374629678531849">"Debug"</string>
- <string name="sendText" msgid="5132506121645618310">"Selezione un\'opzione di invio"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volume suoneria"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volume app. multimediali"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Riproduzione tramite Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volume chiamate"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume chiamate Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volume allarme"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volume notifiche"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Suoneria predefinita"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Suoneria predefinita (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silenzioso"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Suonerie"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Suoneria sconosciuta"</string>
+ <string name="preposition_for_date">"il %s"</string>
+ <string name="preposition_for_time">"alle %s"</string>
+ <string name="preposition_for_year">"nel %s"</string>
+ <string name="day">"giorno"</string>
+ <string name="days">"giorni"</string>
+ <string name="hour">"ora"</string>
+ <string name="hours">"ore"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"min"</string>
+ <string name="second">"sec"</string>
+ <string name="seconds">"sec"</string>
+ <string name="week">"settimana"</string>
+ <string name="weeks">"settimane"</string>
+ <string name="year">"anno"</string>
+ <string name="years">"anni"</string>
+ <string name="every_weekday">"Ogni giorno feriale (lun-ven)"</string>
+ <string name="daily">"Quotidianamente"</string>
+ <string name="weekly">"Ogni settimana il <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Mensilmente"</string>
+ <string name="yearly">"Annualmente"</string>
+ <string name="VideoView_error_title">"Impossibile riprodurre il video"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Spiacenti, questo video non è valido per lo streaming su questo dispositivo."</string>
+ <string name="VideoView_error_text_unknown">"Spiacenti. Impossibile riprodurre il video."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"mezzogiorno"</string>
+ <string name="Noon">"Mezzogiorno"</string>
+ <string name="midnight">"mezzanotte"</string>
+ <string name="Midnight">"Mezzanotte"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Seleziona tutto"</string>
+ <string name="selectText">"Seleziona testo"</string>
+ <string name="stopSelectingText">"Termina selezione testo"</string>
+ <string name="cut">"Taglia"</string>
+ <string name="cutAll">"Taglia tutto"</string>
+ <string name="copy">"Copia"</string>
+ <string name="copyAll">"Copia tutto"</string>
+ <string name="paste">"Incolla"</string>
+ <string name="copyUrl">"Copia URL"</string>
+ <string name="inputMethod">"Metodo inserimento"</string>
+ <string name="addToDictionary">"Aggiungi \"%s\" al dizionario"</string>
+ <string name="editTextMenuTitle">"Modifica testo"</string>
+ <string name="low_internal_storage_view_title">"Spazio in esaurimento"</string>
+ <string name="low_internal_storage_view_text">"Spazio di archiviazione del telefono in esaurimento."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Annulla"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Annulla"</string>
+ <string name="dialog_alert_title">"Attenzione"</string>
+ <string name="capital_on">"ON"</string>
+ <string name="capital_off">"OFF"</string>
+ <string name="whichApplication">"Completa l\'azione con"</string>
+ <string name="alwaysUse">"Usa come predefinita per questa azione."</string>
+ <string name="clearDefaultHintMsg">"Cancella predefinita in Home &gt; Impostazioni &gt; Applicazioni &gt; Gestisci applicazioni."</string>
+ <string name="chooseActivity">"Seleziona un\'azione"</string>
+ <string name="noApplications">"Nessuna applicazione è in grado di svolgere questa azione."</string>
+ <string name="aerr_title">"Spiacenti."</string>
+ <string name="aerr_application">"Interruzione imprevista dell\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo<xliff:g id="PROCESS">%2$s</xliff:g>). Riprova."</string>
+ <string name="aerr_process">"Interruzione imprevista del processo <xliff:g id="PROCESS">%1$s</xliff:g>. Riprova."</string>
+ <string name="anr_title">"Spiacenti."</string>
+ <string name="anr_activity_application">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> (nell\'applicazione <xliff:g id="APPLICATION">%2$s</xliff:g>) non risponde."</string>
+ <string name="anr_activity_process">"L\'attività <xliff:g id="ACTIVITY">%1$s</xliff:g> (nel processo <xliff:g id="PROCESS">%2$s</xliff:g>) non risponde."</string>
+ <string name="anr_application_process">"L\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (nel processo <xliff:g id="PROCESS">%2$s</xliff:g>) non risponde."</string>
+ <string name="anr_process">"Il processo <xliff:g id="PROCESS">%1$s</xliff:g> non risponde."</string>
+ <string name="force_close">"Termina"</string>
+ <string name="report">"Segnala"</string>
+ <string name="wait">"Attendi"</string>
+ <string name="debug">"Debug"</string>
+ <string name="sendText">"Selezione un\'opzione di invio"</string>
+ <string name="volume_ringtone">"Volume suoneria"</string>
+ <string name="volume_music">"Volume app. multimediali"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Riproduzione tramite Bluetooth"</string>
+ <string name="volume_call">"Volume chiamate"</string>
+ <string name="volume_bluetooth_call">"Volume chiamate Bluetooth"</string>
+ <string name="volume_alarm">"Volume allarme"</string>
+ <string name="volume_notification">"Volume notifiche"</string>
+ <string name="volume_unknown">"Volume"</string>
+ <string name="ringtone_default">"Suoneria predefinita"</string>
+ <string name="ringtone_default_with_actual">"Suoneria predefinita (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silenzioso"</string>
+ <string name="ringtone_picker_title">"Suonerie"</string>
+ <string name="ringtone_unknown">"Suoneria sconosciuta"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Rete Wi-Fi disponibile"</item>
- <item quantity="other" msgid="4192424489168397386">"Reti Wi-Fi disponibili"</item>
+ <item quantity="one">"Rete Wi-Fi disponibile"</item>
+ <item quantity="other">"Reti Wi-Fi disponibili"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Rete Wi-Fi aperta disponibile"</item>
- <item quantity="other" msgid="7915895323644292768">"Reti Wi-Fi aperte disponibili"</item>
+ <item quantity="one">"Rete Wi-Fi aperta disponibile"</item>
+ <item quantity="other">"Reti Wi-Fi aperte disponibili"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Inserisci carattere"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Applicazione sconosciuta"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Invio SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"È in corso l\'invio di numerosi SMS. Seleziona \"OK\" per continuare, oppure \"Annulla\" per interrompere l\'invio."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annulla"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Imposta"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Predefinito"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Nessuna autorizzazione richiesta"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Nascondi"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Mostra tutto"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Caricamento..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB collegata"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Il telefono è stato collegato al computer tramite USB. Seleziona \"Collega\" se desideri copiare file tra il computer e la scheda SD del telefono."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Collega"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Non collegare"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Problema di utilizzo della scheda SD per l\'archiviazione USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB collegata"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Seleziona per copiare file sul/dal tuo computer."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Disattiva archivio USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Seleziona per disattivare archivio USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Disattiva archivio USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Prima di disattivare l\'archivio USB, verifica di aver smontato l\'host USB. A tale scopo, seleziona \"Disattiva\"."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Disattiva"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Annulla"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Abbiamo riscontrato un problema disattivando l\'archivio USB. Verifica di aver smontato l\'host USB e riprova."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatta scheda SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Formattare la scheda SD? Tutti i dati sulla scheda verranno persi."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatta"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Un computer è collegato al tuo cellulare."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Seleziona metodo di inserimento"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Preparazione scheda SD"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Ricerca errori."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Scheda SD vuota"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"Scheda SD vuota o con filesystem non supportato."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Scheda SD danneggiata"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"Scheda SD danneggiata. Potrebbe essere necessario riformattarla."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Rimozione imprevista della scheda SD"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Smonta scheda SD prima della rimozione per evitare la perdita di dati."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"È possibile rimuovere la scheda SD"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Puoi rimuovere la scheda SD in tutta sicurezza."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Scheda SD rimossa"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"Scheda SD rimossa. Inseriscine un\'altra."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Nessuna attività corrispondente trovata"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"aggiornare le statistiche di utilizzo dei componenti"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Consente la modifica delle statistiche di utilizzo dei componenti raccolte. Da non usare per normali applicazioni."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tocca due volte per il comando dello zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Errore durante l\'ampliamento del widget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Vai"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Cerca"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Invia"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Avanti"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Fine"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Esegui"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Componi numero"\n"utilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Crea contatto"\n"utilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"selezionato"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"non selezionato"</string>
+ <string name="select_character">"Inserisci carattere"</string>
+ <string name="sms_control_default_app_name">"Applicazione sconosciuta"</string>
+ <string name="sms_control_title">"Invio SMS"</string>
+ <string name="sms_control_message">"È in corso l\'invio di numerosi SMS. Seleziona \"OK\" per continuare, oppure \"Annulla\" per interrompere l\'invio."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Annulla"</string>
+ <string name="date_time_set">"Imposta"</string>
+ <string name="default_permission_group">"Predefinito"</string>
+ <string name="no_permissions">"Nessuna autorizzazione richiesta"</string>
+ <string name="perms_hide"><b>"Nascondi"</b></string>
+ <string name="perms_show_all"><b>"Mostra tutto"</b></string>
+ <string name="googlewebcontenthelper_loading">"Caricamento..."</string>
+ <string name="usb_storage_title">"USB collegata"</string>
+ <string name="usb_storage_message">"Il telefono è stato collegato al computer tramite USB. Seleziona \"Collega\" se desideri copiare file tra il computer e la scheda SD del telefono."</string>
+ <string name="usb_storage_button_mount">"Collega"</string>
+ <string name="usb_storage_button_unmount">"Non collegare"</string>
+ <string name="usb_storage_error_message">"Problema di utilizzo della scheda SD per l\'archiviazione USB."</string>
+ <string name="usb_storage_notification_title">"USB collegata"</string>
+ <string name="usb_storage_notification_message">"Seleziona per copiare file sul/dal tuo computer."</string>
+ <string name="usb_storage_stop_notification_title">"Disattiva archivio USB"</string>
+ <string name="usb_storage_stop_notification_message">"Seleziona per disattivare archivio USB."</string>
+ <string name="usb_storage_stop_title">"Disattiva archivio USB"</string>
+ <string name="usb_storage_stop_message">"Prima di disattivare l\'archivio USB, verifica di aver smontato l\'host USB. A tale scopo, seleziona \"Disattiva\"."</string>
+ <string name="usb_storage_stop_button_mount">"Disattiva"</string>
+ <string name="usb_storage_stop_button_unmount">"Annulla"</string>
+ <string name="usb_storage_stop_error_message">"Abbiamo riscontrato un problema disattivando l\'archivio USB. Verifica di aver smontato l\'host USB e riprova."</string>
+ <string name="extmedia_format_title">"Formatta scheda SD"</string>
+ <string name="extmedia_format_message">"Formattare la scheda SD? Tutti i dati sulla scheda verranno persi."</string>
+ <string name="extmedia_format_button_format">"Formatta"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Seleziona metodo di inserimento"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidati"</u></string>
+ <string name="ext_media_checking_notification_title">"Preparazione scheda SD"</string>
+ <string name="ext_media_checking_notification_message">"Ricerca errori."</string>
+ <string name="ext_media_nofs_notification_title">"Scheda SD vuota"</string>
+ <string name="ext_media_nofs_notification_message">"Scheda SD vuota o con filesystem non supportato."</string>
+ <string name="ext_media_unmountable_notification_title">"Scheda SD danneggiata"</string>
+ <string name="ext_media_unmountable_notification_message">"Scheda SD danneggiata. Potrebbe essere necessario riformattarla."</string>
+ <string name="ext_media_badremoval_notification_title">"Rimozione imprevista della scheda SD"</string>
+ <string name="ext_media_badremoval_notification_message">"Smonta scheda SD prima della rimozione per evitare la perdita di dati."</string>
+ <string name="ext_media_safe_unmount_notification_title">"È possibile rimuovere la scheda SD"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Puoi rimuovere la scheda SD in tutta sicurezza."</string>
+ <string name="ext_media_nomedia_notification_title">"Scheda SD rimossa"</string>
+ <string name="ext_media_nomedia_notification_message">"Scheda SD rimossa. Inseriscine un\'altra."</string>
+ <string name="activity_list_empty">"Nessuna attività corrispondente trovata"</string>
+ <string name="permlab_pkgUsageStats">"aggiornare le statistiche di utilizzo dei componenti"</string>
+ <string name="permdesc_pkgUsageStats">"Consente la modifica delle statistiche di utilizzo dei componenti raccolte. Da non usare per normali applicazioni."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Tocca due volte per il comando dello zoom"</string>
+ <string name="gadget_host_error_inflating">"Errore durante l\'ampliamento del widget"</string>
+ <string name="ime_action_go">"Vai"</string>
+ <string name="ime_action_search">"Cerca"</string>
+ <string name="ime_action_send">"Invia"</string>
+ <string name="ime_action_next">"Avanti"</string>
+ <string name="ime_action_done">"Fine"</string>
+ <string name="ime_action_default">"Esegui"</string>
+ <string name="dial_number_using">"Componi numero"\n"utilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Crea contatto"\n"utilizzando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="accessibility_compound_button_selected">"selezionato"</string>
+ <string name="accessibility_compound_button_unselected">"non selezionato"</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f6a546f..4ad87d7 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -15,695 +15,748 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"&lt;æ–°è¦&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"..."</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(電話番å·ãªã—)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(åå‰ï¼‰"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ボイスメール"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"接続ã«å•é¡ŒãŒã‚ã‚‹ã‹ã€MMIコードãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"サービスãŒæœ‰åŠ¹ã«ãªã‚Šã¾ã—ãŸã€‚"</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"次ã®ã‚µãƒ¼ãƒ“スãŒæœ‰åŠ¹ã«ãªã‚Šã¾ã—ãŸ:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"サービスãŒç„¡åŠ¹ã«ãªã‚Šã¾ã—ãŸã€‚"</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"登録ã•ã‚Œã¾ã—ãŸã€‚"</string>
- <string name="serviceErased" msgid="1288584695297200972">"消去ã•ã‚Œã¾ã—ãŸã€‚"</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"パスワードãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMIãŒå®Œäº†ã—ã¾ã—ãŸã€‚"</string>
- <string name="badPin" msgid="5085454289896032547">"入力ã—ãŸå¤ã„PINã¯æ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="badPuk" msgid="5702522162746042460">"入力ã—ãŸPUKã¯æ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="mismatchPin" msgid="3695902225843339274">"入力ã—ãŸPINãŒä¸€è‡´ã—ã¾ã›ã‚“。"</string>
- <string name="invalidPin" msgid="3850018445187475377">"4~8æ¡ã®æ•°å­—ã®PINを入力ã—ã¦ãã ã•ã„。"</string>
- <string name="needPuk" msgid="919668385956251611">"SIMカードã¯PUKã§ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™ã€‚ロックを解除ã™ã‚‹ã«ã¯PUKコードを入力ã—ã¦ãã ã•ã„。"</string>
- <string name="needPuk2" msgid="4526033371987193070">"SIMカードã®ãƒ­ãƒƒã‚¯è§£é™¤ã®ãŸã‚PUK2を入力ã—ã¾ã™ã€‚"</string>
- <string name="ClipMmi" msgid="6952821216480289285">"ç€ä¿¡æ™‚ã®ç™ºä¿¡è€…番å·"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"発信者番å·"</string>
- <string name="CfMmi" msgid="5123218989141573515">"ç€ä¿¡è»¢é€"</string>
- <string name="CwMmi" msgid="9129678056795016867">"通話中ç€ä¿¡"</string>
- <string name="BaMmi" msgid="455193067926770581">"発信制é™"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"パスワードã®å¤‰æ›´"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PINã®å¤‰æ›´"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"発呼者番å·ã‚’æ示"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"発呼者番å·ã‚’制é™"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"三者間通話"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"迷惑ãªç€ä¿¡ã‚’æ‹’å¦"</string>
- <string name="CndMmi" msgid="3116446237081575808">"発呼者番å·ã‚’é…ä¿¡"</string>
- <string name="DndMmi" msgid="1265478932418334331">"ç€ä¿¡æ‹’å¦"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"既定: 発信者番å·éžé€šçŸ¥ã€æ¬¡ã®ç™ºä¿¡: éžé€šçŸ¥"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"既定: 発信者番å·éžé€šçŸ¥ã€æ¬¡ã®ç™ºä¿¡: 通知"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"既定: 発信者番å·é€šçŸ¥ã€æ¬¡ã®ç™ºä¿¡: éžé€šçŸ¥"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"既定: 発信者番å·é€šçŸ¥ã€æ¬¡ã®ç™ºä¿¡: 通知"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"æä¾›å¯èƒ½ãªã‚µãƒ¼ãƒ“スãŒã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"発信者番å·ã®è¨­å®šã¯å¤‰æ›´ã§ãã¾ã›ã‚“。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"アクセス制é™ãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"データサービスãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"緊急サービスãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"音声/SMSサービスãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"ã™ã¹ã¦ã®éŸ³å£°/SMSサービスãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"音声"</string>
- <string name="serviceClassData" msgid="872456782077937893">"データ"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"éžåŒæœŸ"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"åŒæœŸ"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"パケット"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"ローミングインジケーターON"</string>
- <string name="roamingText1" msgid="5314861519752538922">"ローミングインジケーターOFF"</string>
- <string name="roamingText2" msgid="8969929049081268115">"ローミングインジケーター点滅中"</string>
- <string name="roamingText3" msgid="5148255027043943317">"周辺外"</string>
- <string name="roamingText4" msgid="8808456682550796530">"屋外"</string>
- <string name="roamingText5" msgid="7604063252850354350">"ローミング: 優先ã™ã‚‹ã‚·ã‚¹ãƒ†ãƒ "</string>
- <string name="roamingText6" msgid="2059440825782871513">"ローミング: 利用ã§ãるシステム"</string>
- <string name="roamingText7" msgid="7112078724097233605">"ローミング: ææºãƒ‘ートナー"</string>
- <string name="roamingText8" msgid="5989569778604089291">"ローミング: プレミアムパートナー"</string>
- <string name="roamingText9" msgid="7969296811355152491">"ローミング: サービスã®å…¨æ©Ÿèƒ½ã‚’利用å¯"</string>
- <string name="roamingText10" msgid="3992906999815316417">"ローミング: サービスã®ä¸€éƒ¨æ©Ÿèƒ½ã®ã¿åˆ©ç”¨å¯"</string>
- <string name="roamingText11" msgid="4154476854426920970">"ローミングãƒãƒŠãƒ¼ON"</string>
- <string name="roamingText12" msgid="1189071119992726320">"ローミングãƒãƒŠãƒ¼OFF"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"サービスを検索中"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転é€ã§ãã¾ã›ã‚“"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g> (<xliff:g id="TIME_DELAY">{2}</xliff:g>秒後)"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転é€ã§ãã¾ã›ã‚“"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転é€ã§ãã¾ã›ã‚“"</string>
- <string name="fcComplete" msgid="3118848230966886575">"機能コードãŒå®Œäº†ã—ã¾ã—ãŸã€‚"</string>
- <string name="fcError" msgid="3327560126588500777">"接続エラーã¾ãŸã¯ç„¡åŠ¹ãªæ©Ÿèƒ½ã‚³ãƒ¼ãƒ‰ã§ã™ã€‚"</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"ウェブページã«ã‚¨ãƒ©ãƒ¼ãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"URLãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"ã“ã®ã‚µã‚¤ãƒˆã®èªè¨¼æ–¹å¼ã«ã¯å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“。"</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"èªè¨¼ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"プロキシサーãƒãƒ¼ã‚’使用ã—ãŸèªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"サーãƒãƒ¼ã«æŽ¥ç¶šã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"サーãƒãƒ¼ã¨é€šä¿¡ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã—ã°ã‚‰ãã—ã¦ã‹ã‚‰ã‚‚ã†ä¸€åº¦è©¦ã—ã¦ãã ã•ã„。"</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"サーãƒãƒ¼ã¸ã®æŽ¥ç¶šãŒã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã«ãªã‚Šã¾ã—ãŸã€‚"</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"ã“ã®ãƒšãƒ¼ã‚¸ã¯ã‚µãƒ¼ãƒãƒ¼ã®ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆãŒå¤šã™ãŽã¾ã™ã€‚"</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"ã“ã®ãƒ—ロトコルã«ã¯å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“。"</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"安全ãªæŽ¥ç¶šã‚’確立ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"URLãŒç„¡åŠ¹ãªã®ã§ãƒšãƒ¼ã‚¸ã‚’表示ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"ファイルã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"è¦æ±‚ã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"処ç†ä¸­ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒå¤šã™ãŽã¾ã™ã€‚ã—ã°ã‚‰ãã—ã¦ã‹ã‚‰ã‚‚ã†ä¸€åº¦è©¦ã—ã¦ãã ã•ã„。"</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"åŒæœŸ"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"åŒæœŸ"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>ã§ã®å‰Šé™¤ãŒå¤šã™ãŽã¾ã™ã€‚"</string>
- <string name="low_memory" msgid="6632412458436461203">"電話ã®ãƒ¡ãƒ¢ãƒªãŒã„ã£ã±ã„ã§ã™ã€‚ファイルを削除ã—ã¦ãƒ¡ãƒ¢ãƒªã‚’解放ã—ã¦ãã ã•ã„。"</string>
- <string name="me" msgid="6545696007631404292">"自分"</string>
- <string name="power_dialog" msgid="1319919075463988638">"æºå¸¯é›»è©±ã‚ªãƒ—ション"</string>
- <string name="silent_mode" msgid="7167703389802618663">"マナーモード"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"ワイヤレス接続をONã«ã™ã‚‹"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"ワイヤレス接続をOFFã«ã™ã‚‹"</string>
- <string name="screen_lock" msgid="799094655496098153">"ç”»é¢ã‚’ロック"</string>
- <string name="power_off" msgid="4266614107412865048">"é›»æºã‚’切る"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"シャットダウン中..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"æºå¸¯é›»è©±ã®é›»æºã‚’切りã¾ã™ã€‚"</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"最近使ã£ãŸã‚¢ãƒ—リケーションã¯ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="global_actions" msgid="2406416831541615258">"æºå¸¯é›»è©±ã‚ªãƒ—ション"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"ç”»é¢ãƒ­ãƒƒã‚¯"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"é›»æºã‚’切る"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"マナーモード"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"サウンドOFF"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"サウンドON"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"機内モード"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"機内モードON"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"機内モードOFF"</string>
- <string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"料金ã®ç™ºç”Ÿã™ã‚‹ã‚µãƒ¼ãƒ“ス"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"料金ã®ç™ºç”Ÿã™ã‚‹æ“作をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"é€å—ä¿¡ã—ãŸãƒ¡ãƒƒã‚»ãƒ¼ã‚¸"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"SMSã€ãƒ¡ãƒ¼ãƒ«ãªã©ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®èª­ã¿æ›¸ã"</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"個人情報"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"端末ã®é€£çµ¡å…ˆã¨ã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ã«ç›´æŽ¥ã‚¢ã‚¯ã‚»ã‚¹"</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"ç¾åœ¨åœ°"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"ç¾åœ¨åœ°ã‚’追跡"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯é€šä¿¡"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®ã•ã¾ã–ã¾ãªæ©Ÿèƒ½ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Googleアカウント"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"利用å¯èƒ½ãªGoogleアカウントã¸ã®ã‚¢ã‚¯ã‚»ã‚¹"</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã®åˆ¶å¾¡"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"æºå¸¯é›»è©±ã®ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã«ç›´æŽ¥ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ã€‚"</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"電話/通話"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"通話ã®ç›£è¦–ã€è¨˜éŒ²ã€å‡¦ç†"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"システムツール"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"システムã®ä½Žãƒ¬ãƒ™ãƒ«ã®ã‚¢ã‚¯ã‚»ã‚¹ã¨åˆ¶å¾¡"</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"開発ツール"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"アプリケーションã®ãƒ‡ãƒ™ãƒ­ãƒƒãƒ‘ーã«ã®ã¿å¿…è¦ãªæ©Ÿèƒ½ã§ã™ã€‚"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"ストレージ"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"SDカードã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ã€‚"</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"ステータスãƒãƒ¼ã®ç„¡åŠ¹åŒ–や変更"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"ステータスãƒãƒ¼ã®ç„¡åŠ¹åŒ–やシステムアイコンã®è¿½åŠ ã‚„削除をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"ステータスãƒãƒ¼ã®æ‹¡å¤§/縮å°"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"ステータスãƒãƒ¼ã®æ‹¡å¤§ã‚„縮å°ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"発信ã®å‚å—"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"通話発信ã¨ãƒ€ã‚¤ãƒ¤ãƒ«ã™ã‚‹ç•ªå·ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒç™ºä¿¡ã‚’監視ã€è»¢é€ã€é˜»æ­¢ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"SMSã®å—ä¿¡"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"SMSメッセージã®å—ä¿¡ã¨å‡¦ç†ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’監視ã—ãŸã‚Šã€è¡¨ç¤ºã›ãšã«å‰Šé™¤ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"MMSã®å—ä¿¡"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"MMSメッセージã®å—ä¿¡ã¨å‡¦ç†ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’監視ã—ãŸã‚Šã€è¡¨ç¤ºã›ãšã«å‰Šé™¤ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"SMSメッセージã®é€ä¿¡"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"SMSメッセージã®é€ä¿¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒç¢ºèªãªã—ã§ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’é€ä¿¡ã—ã€æ–™é‡‘ãŒç™ºç”Ÿã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"SMSã®èª­ã¿å–ã‚Š"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"æºå¸¯é›»è©±ã‚„SIMカードã«ä¿å­˜ã—ãŸSMSメッセージã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒæ©Ÿå¯†ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’読ã¿å–ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"SMSã®ç·¨é›†"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"æºå¸¯é›»è©±ã‚„SIMカードã«ä¿å­˜ã—ãŸSMSメッセージã¸ã®æ›¸ãè¾¼ã¿ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’削除ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAPã®å—ä¿¡"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"WAPメッセージã®å—ä¿¡ã¨å‡¦ç†ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’監視ã—ãŸã‚Šã€è¡¨ç¤ºã›ãšã«å‰Šé™¤ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"実行中ã®ã‚¢ãƒ—リケーションã®å–å¾—"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"ç¾åœ¨å®Ÿè¡Œä¸­ã¾ãŸã¯æœ€è¿‘実行ã—ãŸã‚¿ã‚¹ã‚¯ã«é–¢ã™ã‚‹æƒ…å ±ã®å–得をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒä»–ã®ã‚¢ãƒ—リケーションã®éžå…¬é–‹æƒ…報をå–å¾—ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"実行中ã®ã‚¢ãƒ—リケーションã®é †åºã®å¤‰æ›´"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"タスクをフォアグラウンドやãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã«ç§»å‹•ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒå„ªå…ˆã•ã‚Œã¦ã€ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã§ããªããªã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"アプリケーションã®ãƒ‡ãƒãƒƒã‚°ã‚’有効ã«ã™ã‚‹"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"別ã®ã‚¢ãƒ—リケーションをデãƒãƒƒã‚°ãƒ¢ãƒ¼ãƒ‰ã«ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒåˆ¥ã®ã‚¢ãƒ—リケーションを終了ã•ã›ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI設定ã®å¤‰æ›´"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"地域/言語やフォントã®ã‚µã‚¤ã‚ºãªã©ã€ç¾åœ¨ã®è¨­å®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"ä»–ã®ã‚¢ãƒ—リケーションã®å†èµ·å‹•"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"ä»–ã®ã‚¢ãƒ—リケーションã®å¼·åˆ¶çš„ãªå†èµ·å‹•ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"アプリケーションã®å¼·åˆ¶çµ‚了"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"フォアグラウンドã§å®Ÿè¡Œã•ã‚Œã¦ã„ã‚‹æ“作を強制終了ã—ã¦æˆ»ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="permlab_dump" msgid="1681799862438954752">"システムã®å†…部状態ã®å–å¾—"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"システムã®å†…部状態ã®å–得をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã€é€šå¸¸ã¯å¿…è¦ã¨ã—ãªã„広範囲ã«ã‚ãŸã‚‹éžå…¬é–‹ã®æ©Ÿå¯†æƒ…報をå–å¾—ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"部分的ã«ã‚·ãƒ£ãƒƒãƒˆãƒ€ã‚¦ãƒ³ã™ã‚‹"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"アクティビティマãƒãƒ¼ã‚¸ãƒ£ã‚’シャットダウン状態ã«ã—ã¾ã™ã€‚完全ãªã‚·ãƒ£ãƒƒãƒˆãƒ€ã‚¦ãƒ³ã¯å®Ÿè¡Œã—ã¾ã›ã‚“。"</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"アプリケーションã®åˆ‡ã‚Šæ›¿ãˆã‚’ç¦æ­¢ã™ã‚‹"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"ユーザーãŒåˆ¥ã®ã‚¢ãƒ—リケーションã«åˆ‡ã‚Šæ›¿ãˆã‚‰ã‚Œãªã„よã†ã«ã—ã¾ã™ã€‚"</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"起動中ã®ã™ã¹ã¦ã®ã‚¢ãƒ—リケーションã®ç›£è¦–ã¨åˆ¶å¾¡"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"システムãŒèµ·å‹•ã™ã‚‹æ“作ã®ç›£è¦–ã¨åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã‚·ã‚¹ãƒ†ãƒ ã‚’完全ã«ç ´å£Šã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚ã“ã®è¨±å¯ã¯é–‹ç™ºã«ã®ã¿å¿…è¦ã§ã€æºå¸¯é›»è©±ã®é€šå¸¸ã®ä½¿ç”¨ã«ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"パッケージ削除ブロードキャストã®é€ä¿¡"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"アプリケーションパッケージã®å‰Šé™¤ã®é€šçŸ¥ã‚’é…ä¿¡ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒä»–ã®å®Ÿè¡Œä¸­ã®ã‚¢ãƒ—リケーションを強制終了ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"SMSå—信ブロードキャストã®é€ä¿¡"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"SMSメッセージã®å—信通知ã®é…信をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒå—ä¿¡SMSメッセージをå½é€ ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSHå—信ブロードキャストã®é€ä¿¡"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"WAP PUSHメッセージã®å—ä¿¡ã®é€šçŸ¥ã‚’é…ä¿¡ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒMMSå—信メッセージをå½é€ ã—ãŸã‚Šã€ã‚¦ã‚§ãƒ–ページã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„を密ã‹ã«æ”¹ã–ã‚“ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"実行中ã®ãƒ—ロセスã®æ•°ã‚’制é™"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"実行ã™ã‚‹ãƒ—ロセス数ã®ä¸Šé™ã®åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã«ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã‚¢ãƒ—リケーションをã™ã¹ã¦çµ‚了ã™ã‚‹"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã«ãªã‚Šæ¬¡ç¬¬å¿…ãšæ“作を終了ã•ã›ã‚‹ã‹ã©ã†ã‹ã®åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"電池統計情報ã®å¤‰å›½"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"åŽé›†ã—ãŸé›»æ± çµ±è¨ˆæƒ…å ±ã®å¤‰æ›´ã‚’許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
- <string name="permlab_backup" msgid="470013022865453920">"システムã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã¨å¾©å…ƒã‚’制御ã™ã‚‹"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"システムã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ãŠã‚ˆã³å¾©å…ƒãƒ¡ã‚«ãƒ‹ã‚ºãƒ ã®åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"未許å¯ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã®è¡¨ç¤º"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"内部システムã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã§ä½¿ç”¨ã™ã‚‹ãŸã‚ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ä½œæˆã‚’許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"システムレベルã®è­¦å‘Šã®è¡¨ç¤º"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"システムã®è­¦å‘Šã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã®è¡¨ç¤ºã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒæºå¸¯é›»è©±ã®ç”»é¢å…¨ä½“ã‚’å½è£…ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"アニメーションã®ãƒ—リセット速度ã®å¤‰æ›´"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"ã„ã¤ã§ã‚‚アニメーション全般ã®é€Ÿåº¦ã‚’変更ã™ã‚‹ (アニメーションを速ãã¾ãŸã¯é…ãã™ã‚‹) ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"アプリケーショントークンã®ç®¡ç†"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"通常ã®Z-orderingを回é¿ã—ã¦ã€ç‹¬è‡ªã®ãƒˆãƒ¼ã‚¯ãƒ³ã‚’作æˆã€ç®¡ç†ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"キーを押ã—ã¦ãƒœã‚¿ãƒ³ã‚’コントロール"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"入力イベント (キーを押ã™ãªã©) を別ã®ã‚¢ãƒ—リケーションã«ä¼ãˆã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæ‚ªæ„ã®ã‚るアプリケーションãŒã€æºå¸¯é›»è©±ã‚’ä¹—ã£å–ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"入力やæ“作ã®è¨˜éŒ²"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"別ã®ã‚¢ãƒ—リケーションã¸ã®å…¥åŠ›ï¼ˆãƒ‘スワードãªã©ï¼‰ã§ã‚‚キー入力を監視ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"入力方法ã«é–¢é€£ä»˜ã‘ã‚‹"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"入力方法ã®ãƒˆãƒƒãƒ—レベルインターフェースã«é–¢é€£ä»˜ã‘ã‚‹ã“ã¨ã‚’所有者ã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã«ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"ç”»é¢ã®å‘ãã®å¤‰æ›´"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"ã„ã¤ã§ã‚‚ç”»é¢ã®å›žè»¢ã‚’変更ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã«ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linuxã®ã‚·ã‚°ãƒŠãƒ«ã‚’アプリケーションã«é€ä¿¡"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"å—ä¿¡ã—ãŸé›»æ³¢ã‚’継続プロセスã«é€ä¿¡ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"アプリケーションを常ã«å®Ÿè¡Œã™ã‚‹"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"自身を部分的ã«æ°¸ç¶šã•ã›ã¦ã€ä»–ã®ã‚¢ãƒ—リケーション用ã«ã¯ãã®é ˜åŸŸã‚’システムã«ä½¿ã‚ã›ãªã„よã†ã«ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"アプリケーションã®å‰Šé™¤"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Androidパッケージã®å‰Šé™¤ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã€é‡è¦ãªã‚¢ãƒ—リケーションを削除ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"ä»–ã®ã‚¢ãƒ—リケーションã®ãƒ‡ãƒ¼ã‚¿ã‚’削除"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"ユーザーデータã®æ¶ˆåŽ»ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"ä»–ã®ã‚¢ãƒ—リケーションã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’削除"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"キャッシュファイルã®å‰Šé™¤ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"アプリケーションã®ãƒ¡ãƒ¢ãƒªå®¹é‡ã®è¨ˆæ¸¬"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"アプリケーションã®ã‚³ãƒ¼ãƒ‰ã€ãƒ‡ãƒ¼ã‚¿ã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã®ã‚µã‚¤ã‚ºã‚’å–å¾—ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"アプリケーションを直接インストール"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Androidパッケージã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«/更新をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã€å‹æ‰‹ã«å¼·åŠ›ãªæ¨©é™ã‚’æŒã¤æ–°ã—ã„アプリケーションを追加ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"アプリケーションキャッシュデータã®å‰Šé™¤"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"アプリケーションã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‹ã‚‰ãƒ•ã‚¡ã‚¤ãƒ«ã‚’削除ã—ã¦æºå¸¯é›»è©±ã®ãƒ¡ãƒ¢ãƒªã‚’解放ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã€ã‚¢ã‚¯ã‚»ã‚¹ã¯ã‚·ã‚¹ãƒ†ãƒ ãƒ—ロセスã®ã¿ã«åˆ¶é™ã•ã‚Œã¾ã™ã€‚"</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"システムログファイルã®èª­ã¿å–ã‚Š"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"システムã®ã•ã¾ã–ã¾ãªãƒ­ã‚°ãƒ•ã‚¡ã‚¤ãƒ«ã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæºå¸¯é›»è©±ã®ä½¿ç”¨çŠ¶æ³ã«é–¢ã™ã‚‹å…¨èˆ¬æƒ…å ±ãŒå–å¾—ã•ã‚Œã¾ã™ãŒã€å€‹äººæƒ…報やéžå…¬é–‹æƒ…å ±ãŒå«ã¾ã‚Œã‚‹ã“ã¨ã¯ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"diagãŒæ‰€æœ‰ã™ã‚‹ãƒªã‚½ãƒ¼ã‚¹ã®èª­ã¿æ›¸ã"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"diagグループãŒæ‰€æœ‰ã™ã‚‹ãƒªã‚½ãƒ¼ã‚¹ï¼ˆä¾‹:/dev内ã®ãƒ•ã‚¡ã‚¤ãƒ«ï¼‰ã¸ã®èª­ã¿æ›¸ãをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚システムã®å®‰å®šæ€§ã¨ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã«å½±éŸ¿ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚メーカー/オペレーターã«ã‚ˆã‚‹ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢å›ºæœ‰ã®è¨ºæ–­ä»¥å¤–ã«ã¯ä½¿ç”¨ã—ãªã„ã§ãã ã•ã„。"</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"アプリケーションã®ã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆã‚’有効/無効ã«ã™ã‚‹"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"別アプリケーションã®ã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆã®æœ‰åŠ¹/無効を変更ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæ‚ªæ„ã®ã‚るアプリケーションãŒã€æºå¸¯é›»è©±ã®é‡è¦ãªæ©Ÿèƒ½ã‚’無効ã«ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚アプリケーションコンãƒãƒ¼ãƒãƒ³ãƒˆãŒåˆ©ç”¨ã§ããªã„ã€æ•´åˆæ€§ãŒå–ã‚Œãªã„ã€ã¾ãŸã¯ä¸å®‰å®šãªçŠ¶æ…‹ã«ãªã‚‹æã‚ŒãŒã‚ã‚‹ã®ã§ã€è¨±å¯ã«ã¯æ³¨æ„ãŒå¿…è¦ã§ã™ã€‚"</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"優先アプリケーションã®è¨­å®š"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"優先アプリケーションを変更ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒå®Ÿè¡Œä¸­ã®ã‚¢ãƒ—リケーションを密ã‹ã«å¤‰æ›´ã—ã€æ—¢å­˜ã®ã‚¢ãƒ—リケーションã«ãªã‚Šã™ã¾ã—ã¦éžå…¬é–‹ãƒ‡ãƒ¼ã‚¿ã‚’åŽé›†ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"システムã®å…¨èˆ¬è¨­å®šã®å¤‰æ›´"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"システム設定データã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã‚·ã‚¹ãƒ†ãƒ è¨­å®šã‚’破壊ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"システムã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨­å®šã®å¤‰æ›´"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"システムã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨­å®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Googleサービスã®åœ°å›³ã®å¤‰æ›´"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Googleサービスマップã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"起動時ã«è‡ªå‹•çš„ã«é–‹å§‹"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"システムã®èµ·å‹•å¾Œã«è‡ªå‹•çš„ã«èµ·å‹•ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚æºå¸¯é›»è©±ã®èµ·å‹•ã«æ™‚é–“ãŒã‹ã‹ã‚‹ã‚ˆã†ã«ãªã‚Šã€ã‚¢ãƒ—リケーションãŒå¸¸ã«å®Ÿè¡Œã•ã‚Œã‚‹ãŸã‚ã«æºå¸¯é›»è©±ã®å…¨ä½“çš„ãªå‹•ä½œãŒé…ããªã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"stickyブロードキャストã®é…ä¿¡"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"é…ä¿¡ãŒçµ‚了ã—ã¦ã‚‚メモリã«æ®‹ã‚‹ã‚ˆã†ãªstickyブロードキャストをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ¡ãƒ¢ãƒªã‚’使ã„ã™ãŽã¦ã€æºå¸¯é›»è©±ã®å‹•ä½œãŒé…ããªã£ãŸã‚Šã€ä¸å®‰å®šã«ãªã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"連絡先データã®èª­ã¿å–ã‚Š"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"端末ã«ä¿å­˜ã—ãŸé€£çµ¡å…ˆï¼ˆã‚¢ãƒ‰ãƒ¬ã‚¹ï¼‰ãƒ‡ãƒ¼ã‚¿ã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ‡ãƒ¼ã‚¿ã‚’他人ã«é€ä¿¡ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"連絡先データã®æ›¸ãè¾¼ã¿"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"端末ã«ä¿å­˜ã—ãŸé€£çµ¡å…ˆï¼ˆã‚¢ãƒ‰ãƒ¬ã‚¹ï¼‰ãƒ‡ãƒ¼ã‚¿ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒé€£çµ¡å…ˆãƒ‡ãƒ¼ã‚¿ã‚’消去/変更ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"所有者データã®æ›¸ãè¾¼ã¿"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"端末ã«ä¿å­˜ã—ãŸæ‰€æœ‰è€…ã®ãƒ‡ãƒ¼ã‚¿ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒæ‰€æœ‰è€…ã®ãƒ‡ãƒ¼ã‚¿ã‚’消去/変更ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"所有者データã®èª­ã¿å–ã‚Š"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"æºå¸¯é›»è©±ã«ä¿å­˜ã—ãŸæ‰€æœ‰è€…データã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒæ‰€æœ‰è€…データを読ã¿å–ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"カレンダーデータã®èª­ã¿å–ã‚Š"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"端末ã«ä¿å­˜ã—ãŸã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ã®äºˆå®šã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ã®äºˆå®šã‚’他人ã«é€ä¿¡ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"カレンダーデータã®æ›¸ãè¾¼ã¿"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"端末ã«ä¿å­˜ã—ãŸã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ã®äºˆå®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã€ã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ãƒ‡ãƒ¼ã‚¿ã‚’消去/変更ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"ä»®ã®ä½ç½®æƒ…å ±ã§ãƒ†ã‚¹ãƒˆ"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"テスト用ã«ä»®ã®ä½ç½®æƒ…å ±æºã‚’作æˆã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæ‚ªæ„ã®ã‚るアプリケーションãŒã€GPSã€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ—ロãƒã‚¤ãƒ€ãªã©ã‹ã‚‰è¿”ã•ã‚Œã‚‹æœ¬å½“ã®ä½ç½®æƒ…報や状æ³ã‚’改ã–ã‚“ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ä½ç½®æƒ…å ±æ供者ã®è¿½åŠ ã‚³ãƒžãƒ³ãƒ‰ã‚¢ã‚¯ã‚»ã‚¹"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"ä½ç½®æƒ…å ±æ供元ã®è¿½åŠ ã‚³ãƒžãƒ³ãƒ‰ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒGPSãªã©ã®ä½ç½®æä¾›ã®å‹•ä½œã‚’妨害ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"ä½ç½®æƒ…å ±æ供元ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã‚’許å¯ã™ã‚‹"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"テスト用ã«ä»®ã®ä½ç½®æƒ…報を作æˆã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæ‚ªæ„ã®ã‚るアプリケーションãŒã€GPSã‚„ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ—ロãƒã‚¤ãƒ€ãªã©ã‹ã‚‰è¿”ã•ã‚Œã‚‹æœ¬å½“ã®ä½ç½®æƒ…報や状æ³ã‚’改ã–ã‚“ã—ãŸã‚Šã€ç«¯æœ«ã®ç¾åœ¨åœ°ã‚’監視ã—ã¦å¤–部ã«å ±å‘Šã—ãŸã‚Šã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"精細ãªä½ç½®æƒ…報(GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"GPSãªã©æºå¸¯é›»è©±ã®ä½ç½®æƒ…å ±ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ï¼ˆå¯èƒ½ãªå ´åˆï¼‰ã€‚今ã„る場所ãŒæ‚ªæ„ã®ã‚るアプリケーションã«æ¤œå‡ºã•ã‚ŒãŸã‚Šã€ãƒãƒƒãƒ†ãƒªãƒ¼ã®æ¶ˆè²»ãŒå¢—ãˆã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ãŠãŠã‚ˆãã®ä½ç½®æƒ…報(ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯åŸºåœ°å±€ï¼‰"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"セルラーãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãªã©ã€æºå¸¯é›»è©±ã®ãŠãŠã‚ˆãã®ä½ç½®ã‚’特定ã™ã‚‹æƒ…å ±æºãŒåˆ©ç”¨å¯èƒ½ãªå ´åˆã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæ‚ªæ„ã®ã‚るアプリケーションãŒã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãŠãŠã‚ˆãã®ä½ç½®ã‚’特定ã§ãã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"SurfaceFlingerã¸ã®ã‚¢ã‚¯ã‚»ã‚¹"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"SurfaceFlingerã®ä½Žãƒ¬ãƒ™ãƒ«ã®æ©Ÿèƒ½ã®ä½¿ç”¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"フレームãƒãƒƒãƒ•ã‚¡ã®èª­ã¿å–ã‚Š"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"フレームãƒãƒƒãƒ•ã‚¡ã®å†…容ã®èª­ã¿å–ã‚Šã¨ä½¿ç”¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"音声設定ã®å¤‰æ›´"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"音é‡ã‚„転é€ãªã©ã®éŸ³å£°å…¨èˆ¬ã®è¨­å®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"録音"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"オーディオ録音パスã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_camera" msgid="8059288807274039014">"写真ã®æ’®å½±"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"カメラã§ã®å†™çœŸæ’®å½±ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚アプリケーションã¯ã‚«ãƒ¡ãƒ©ã‹ã‚‰ç”»åƒã‚’ã„ã¤ã§ã‚‚åŽé›†ã§ãã¾ã™ã€‚"</string>
- <string name="permlab_brick" msgid="8337817093326370537">"端末を永続的ã«ç„¡åŠ¹ã«ã™ã‚‹"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"æºå¸¯é›»è©±å…¨ä½“を永続的ã«ç„¡åŠ¹ã«ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã®è¨±å¯ã¯éžå¸¸ã«å±é™ºã§ã™ã€‚"</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"端末ã®å†èµ·å‹•"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"端末ã®å¼·åˆ¶çš„ãªå†èµ·å‹•ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"ファイルシステムã®ãƒžã‚¦ãƒ³ãƒˆã¨ãƒžã‚¦ãƒ³ãƒˆè§£é™¤"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"リムーãƒãƒ–ルメモリã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚·ã‚¹ãƒ†ãƒ ã®ãƒžã‚¦ãƒ³ãƒˆã¨ãƒžã‚¦ãƒ³ãƒˆè§£é™¤ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"外部ストレージã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆ"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"アプリケーションãŒãƒªãƒ ãƒ¼ãƒãƒ–ルストレージをフォーマットã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"ãƒã‚¤ãƒ–レーション制御"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"ãƒã‚¤ãƒ–レーションã®åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ライトã®ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"ライトã®åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã®ãƒ†ã‚¹ãƒˆ"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã®ãƒ†ã‚¹ãƒˆã®ãŸã‚ã«ã•ã¾ã–ã¾ãªå‘¨è¾ºæ©Ÿå™¨ã‚’制御ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"電話番å·ç™ºä¿¡"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"電話番å·ã®è‡ªå‹•ç™ºä¿¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒæ„図ã—ãªã„電話をã‹ã‘ã¦æ–™é‡‘ãŒç™ºç”Ÿã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚緊急通報ã¸ã®ç™ºä¿¡ã¯è¨±å¯ã—ã¾ã›ã‚“。"</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"電話番å·ç™ºä¿¡"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"緊急通報をå«ã‚ã‚らゆる電話番å·ã«è‡ªå‹•ç™ºä¿¡ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒç·Šæ€¥ã‚µãƒ¼ãƒ“スã«ä¸æ­£ãªé€šå ±ã‚’ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"ä½ç½®æƒ…å ±ã®æ›´æ–°é€šçŸ¥"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"無線通信ã‹ã‚‰ã®ä½ç½®æ›´æ–°é€šçŸ¥ã‚’有効/無効ã«ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"ãƒã‚§ãƒƒã‚¯ã‚¤ãƒ³ãƒ—ロパティã¸ã®ã‚¢ã‚¯ã‚»ã‚¹"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"ãƒã‚§ãƒƒã‚¯ã‚¤ãƒ³ã‚µãƒ¼ãƒ“スãŒã‚¢ãƒƒãƒ—ロードã—ãŸãƒ—ロパティã¸ã®èª­ã¿æ›¸ãを許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"ウィジェットã®é¸æŠž"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"ã©ã®ã‚¢ãƒ—リケーションãŒã©ã®ã‚¦ã‚£ã‚¸ã‚§ãƒƒãƒˆã‚’使用ã§ãã‚‹ã‹ã‚·ã‚¹ãƒ†ãƒ ã«æŒ‡å®šã™ã‚‹ã“ã¨ã‚’ã“ã®ã‚¢ãƒ—リケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šã€ã‚¢ãƒ—リケーション間ã§å€‹äººãƒ‡ãƒ¼ã‚¿ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"端末ステータスã®å¤‰æ›´"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"端末ã®é›»è©±æ©Ÿèƒ½ã®ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚アプリケーションã¯ã€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®åˆ‡ã‚Šæ›¿ãˆã€æºå¸¯é›»è©±ã®ç„¡ç·šé€šä¿¡ã®ã‚ªãƒ³/オフãªã©ã‚’通知ã›ãšã«è¡Œã†ã“ã¨ãŒã§ãã¾ã™ã€‚"</string>
- <string name="permlab_readPhoneState" msgid="2326172951448691631">"æºå¸¯ã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã¨IDã®èª­ã¿å–ã‚Š"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"端末ã®é›»è©±æ©Ÿèƒ½ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã®æ¨©é™ãŒè¨±å¯ã•ã‚ŒãŸã‚¢ãƒ—リケーションã§ã¯ã€ã“ã®æºå¸¯ã®é›»è©±ç•ªå·ã‚„シリアル番å·ã€é€šè©±ä¸­ã‹ã©ã†ã‹ã€é€šè©±ç›¸æ‰‹ã®é›»è©±ç•ªå·ãªã©ã‚’特定ã§ãã¾ã™ã€‚"</string>
- <string name="permlab_wakeLock" msgid="573480187941496130">"端末ã®ã‚¹ãƒªãƒ¼ãƒ—を無効ã«ã™ã‚‹"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"端末ã®ã‚¹ãƒªãƒ¼ãƒ—を無効ã«ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"é›»æºã®ON/OFF"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"æºå¸¯é›»è©±ã®é›»æºã®ã‚ªãƒ³/オフをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"出è·æ™‚試験モードã§ã®å®Ÿè¡Œ"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"æºå¸¯é›»è©±ã®ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’完全ã«è¨±å¯ã—ã¦ã€ä½Žãƒ¬ãƒ™ãƒ«ã®ãƒ¡ãƒ¼ã‚«ãƒ¼ãƒ†ã‚¹ãƒˆã¨ã—ã¦å®Ÿè¡Œã—ã¾ã™ã€‚メーカーã®ãƒ†ã‚¹ãƒˆãƒ¢ãƒ¼ãƒ‰ã§æºå¸¯é›»è©±ã‚’使用ã™ã‚‹ã¨ãã®ã¿åˆ©ç”¨ã§ãã¾ã™ã€‚"</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"å£ç´™ã®è¨­å®š"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"システムã®å£ç´™ã®è¨­å®šã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"å£ç´™ã‚µã‚¤ã‚ºã®ãƒ’ントã®è¨­å®š"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"システムã®å£ç´™ã‚µã‚¤ã‚ºã®ãƒ’ントã®è¨­å®šã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"システムを出è·æ™‚設定ã«ãƒªã‚»ãƒƒãƒˆ"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"データã€è¨­å®šã€ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ãŸã‚¢ãƒ—リケーションをã™ã¹ã¦æ¶ˆåŽ»ã—ã¦ã€å®Œå…¨ã«å‡ºè·æ™‚ã®è¨­å®šã«ã‚·ã‚¹ãƒ†ãƒ ã‚’リセットã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"タイムゾーンã®è¨­å®š"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"端末ã®ã‚¿ã‚¤ãƒ ã‚¾ãƒ¼ãƒ³ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"既知ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®å–å¾—"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"端末内ã«ã‚るアカウントã®ãƒªã‚¹ãƒˆã®å–得をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯çŠ¶æ…‹ã®è¡¨ç¤º"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"ã™ã¹ã¦ã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯çŠ¶æ…‹ã®è¡¨ç¤ºã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"完全ãªã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆã‚¢ã‚¯ã‚»ã‚¹"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚½ã‚±ãƒƒãƒˆã®ä½œæˆã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"アクセスãƒã‚¤ãƒ³ãƒˆå設定ã®æ›¸ãè¾¼ã¿"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"APNã®ãƒ—ロキシやãƒãƒ¼ãƒˆãªã©ã®APN設定ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯æŽ¥ç¶šã®å¤‰æ›´"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®æŽ¥ç¶šçŠ¶æ…‹ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ãƒ‡ãƒ¼ã‚¿ä½¿ç”¨è¨­å®šã®å¤‰æ›´"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ãƒ‡ãƒ¼ã‚¿ä½¿ç”¨ã®è¨­å®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Wi-Fi状態ã®è¡¨ç¤º"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Wi-Fi状態ã«é–¢ã™ã‚‹æƒ…å ±ã®è¡¨ç¤ºã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Wi-Fi状態ã®å¤‰æ›´"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Wi-Fiアクセスãƒã‚¤ãƒ³ãƒˆã¸ã®æŽ¥ç¶šã‚„接続ã®åˆ‡æ–­ã€è¨­å®šã•ã‚ŒãŸWi-Fiãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fiマルãƒã‚­ãƒ£ã‚¹ãƒˆã®å—信を許å¯ã™ã‚‹"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"端末を直接ã®å®›å…ˆã¨ã¯ã—ã¦ã„ãªã„パケットã®å—信をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚近隣ã§æ供中ã®ã‚µãƒ¼ãƒ“スを検出ã—ãŸã„å ´åˆã«ä¾¿åˆ©ã§ã™ã€‚マルãƒã‚­ãƒ£ã‚¹ãƒˆä»¥å¤–ã®ãƒ¢ãƒ¼ãƒ‰ã‚ˆã‚Šã‚‚電力を消費ã—ã¾ã™ã€‚"</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetoothã®ç®¡ç†"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"ã“ã®Bluetooth端末ã®è¨­å®šã€ãŠã‚ˆã³ãƒªãƒ¢ãƒ¼ãƒˆç«¯æœ«ã‚’検出ã—ã¦ãƒšã‚¢ã«è¨­å®šã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth接続ã®ä½œæˆ"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"ã“ã®Bluetooth端末ã®è¨­å®šè¡¨ç¤ºã€ãŠã‚ˆã³åˆ¥ã®ç«¯æœ«ã‚’ペアã¨ã—ã¦è¨­å®šã—接続を承èªã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"キーロックを無効ã«ã™ã‚‹"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"キーロックや関連ã™ã‚‹ãƒ‘スワードセキュリティを無効ã«ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚正当ãªåˆ©ç”¨ã®ä¾‹ã§ã¯ã€ã‹ã‹ã£ã¦ããŸé›»è©±ã‚’å—ä¿¡ã™ã‚‹éš›ã«ã‚­ãƒ¼ãƒ­ãƒƒã‚¯ã‚’無効ã«ã—ã€é€šè©±ã®çµ‚了時ã«ã‚­ãƒ¼ãƒ­ãƒƒã‚¯ã‚’有効ã«ã—ç›´ã—ã¾ã™ã€‚"</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"åŒæœŸè¨­å®šã®èª­ã¿å–ã‚Š"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"連絡先ã®åŒæœŸã®æœ‰åŠ¹/無効ãªã©ã€åŒæœŸè¨­å®šã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"åŒæœŸè¨­å®šã®æ›¸ãè¾¼ã¿"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"連絡先ã®åŒæœŸã®æœ‰åŠ¹/無効ãªã©ã€åŒæœŸè¨­å®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"åŒæœŸçµ±è¨ˆã®èª­ã¿å–ã‚Š"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"åŒæœŸçŠ¶æ…‹ï¼ˆåŒæœŸå±¥æ­´ãªã©ï¼‰ã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"登録ã—ãŸãƒ•ã‚£ãƒ¼ãƒ‰ã®èª­ã¿å–ã‚Š"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"ç¾åœ¨åŒæœŸã—ã¦ã„るフィードã®è©³ç´°ã®å–得をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"登録ã—ãŸãƒ•ã‚£ãƒ¼ãƒ‰ã®æ›¸ãè¾¼ã¿"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"ç¾åœ¨åŒæœŸã—ã¦ã„るフィードã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒåŒæœŸãƒ•ã‚£ãƒ¼ãƒ‰ã‚’変更ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"ユーザー定義辞書ã®èª­ã¿è¾¼ã¿"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"アプリケーションãŒãƒ¦ãƒ¼ã‚¶ãƒ¼è¾žæ›¸ã«ç™»éŒ²ã•ã‚Œã¦ã„る個人的ãªèªžå¥ã‚„åå‰ã‚’読ã¿è¾¼ã‚€ã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"ユーザー定義辞書ã¸ã®æ›¸ãè¾¼ã¿"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"アプリケーションãŒãƒ¦ãƒ¼ã‚¶ãƒ¼è¾žæ›¸ã«æ–°ã—ã„語å¥ã‚’書ã込むã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"SDカードã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„を修正/削除ã™ã‚‹"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"SDカードã¸ã®æ›¸ãè¾¼ã¿ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <!-- no translation found for fileSizeSuffix (7670819340156489359) -->
+ <skip />
+ <string name="untitled">"&lt;æ–°è¦&gt;"</string>
+ <string name="ellipsis">"..."</string>
+ <string name="emptyPhoneNumber">"(電話番å·ãªã—)"</string>
+ <string name="unknownName">"(åå‰ï¼‰"</string>
+ <string name="defaultVoiceMailAlphaTag">"ボイスメール"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"接続ã«å•é¡ŒãŒã‚ã‚‹ã‹ã€MMIコードãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="serviceEnabled">"サービスãŒæœ‰åŠ¹ã«ãªã‚Šã¾ã—ãŸã€‚"</string>
+ <string name="serviceEnabledFor">"次ã®ã‚µãƒ¼ãƒ“スãŒæœ‰åŠ¹ã«ãªã‚Šã¾ã—ãŸ:"</string>
+ <string name="serviceDisabled">"サービスãŒç„¡åŠ¹ã«ãªã‚Šã¾ã—ãŸã€‚"</string>
+ <string name="serviceRegistered">"登録ã•ã‚Œã¾ã—ãŸã€‚"</string>
+ <string name="serviceErased">"消去ã•ã‚Œã¾ã—ãŸã€‚"</string>
+ <string name="passwordIncorrect">"パスワードãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="mmiComplete">"MMIãŒå®Œäº†ã—ã¾ã—ãŸã€‚"</string>
+ <string name="badPin">"入力ã—ãŸå¤ã„PINã¯æ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="badPuk">"入力ã—ãŸPUKã¯æ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="mismatchPin">"入力ã—ãŸPINãŒä¸€è‡´ã—ã¾ã›ã‚“。"</string>
+ <string name="invalidPin">"4~8æ¡ã®æ•°å­—ã®PINを入力ã—ã¦ãã ã•ã„。"</string>
+ <string name="needPuk">"SIMカードã¯PUKã§ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™ã€‚ロックを解除ã™ã‚‹ã«ã¯PUKコードを入力ã—ã¦ãã ã•ã„。"</string>
+ <string name="needPuk2">"SIMカードã®ãƒ­ãƒƒã‚¯è§£é™¤ã®ãŸã‚PUK2を入力ã—ã¾ã™ã€‚"</string>
+ <string name="ClipMmi">"ç€ä¿¡æ™‚ã®ç™ºä¿¡è€…番å·"</string>
+ <string name="ClirMmi">"発信者番å·"</string>
+ <string name="CfMmi">"ç€ä¿¡è»¢é€"</string>
+ <string name="CwMmi">"通話中ç€ä¿¡"</string>
+ <string name="BaMmi">"発信制é™"</string>
+ <string name="PwdMmi">"パスワードã®å¤‰æ›´"</string>
+ <string name="PinMmi">"PINã®å¤‰æ›´"</string>
+ <!-- no translation found for CnipMmi (3110534680557857162) -->
+ <skip />
+ <!-- no translation found for CnirMmi (3062102121430548731) -->
+ <skip />
+ <!-- no translation found for ThreeWCMmi (9051047170321190368) -->
+ <skip />
+ <!-- no translation found for RuacMmi (7827887459138308886) -->
+ <skip />
+ <!-- no translation found for CndMmi (3116446237081575808) -->
+ <skip />
+ <!-- no translation found for DndMmi (1265478932418334331) -->
+ <skip />
+ <string name="CLIRDefaultOnNextCallOn">"既定: 発信者番å·éžé€šçŸ¥ã€æ¬¡ã®ç™ºä¿¡: éžé€šçŸ¥"</string>
+ <string name="CLIRDefaultOnNextCallOff">"既定: 発信者番å·éžé€šçŸ¥ã€æ¬¡ã®ç™ºä¿¡: 通知"</string>
+ <string name="CLIRDefaultOffNextCallOn">"既定: 発信者番å·é€šçŸ¥ã€æ¬¡ã®ç™ºä¿¡: éžé€šçŸ¥"</string>
+ <string name="CLIRDefaultOffNextCallOff">"既定: 発信者番å·é€šçŸ¥ã€æ¬¡ã®ç™ºä¿¡: 通知"</string>
+ <string name="serviceNotProvisioned">"æä¾›å¯èƒ½ãªã‚µãƒ¼ãƒ“スãŒã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="CLIRPermanent">"発信者番å·ã®è¨­å®šã¯å¤‰æ›´ã§ãã¾ã›ã‚“。"</string>
+ <string name="RestrictedChangedTitle">"アクセス制é™ãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ"</string>
+ <string name="RestrictedOnData">"データサービスãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
+ <string name="RestrictedOnEmergency">"緊急サービスãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
+ <string name="RestrictedOnNormal">"音声/SMSサービスãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
+ <string name="RestrictedOnAll">"ã™ã¹ã¦ã®éŸ³å£°/SMSサービスãŒãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
+ <string name="serviceClassVoice">"音声"</string>
+ <string name="serviceClassData">"データ"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"éžåŒæœŸ"</string>
+ <string name="serviceClassDataSync">"åŒæœŸ"</string>
+ <string name="serviceClassPacket">"パケット"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <!-- no translation found for roamingText0 (7170335472198694945) -->
+ <skip />
+ <!-- no translation found for roamingText1 (5314861519752538922) -->
+ <skip />
+ <!-- no translation found for roamingText2 (8969929049081268115) -->
+ <skip />
+ <!-- no translation found for roamingText3 (5148255027043943317) -->
+ <skip />
+ <!-- no translation found for roamingText4 (8808456682550796530) -->
+ <skip />
+ <!-- no translation found for roamingText5 (7604063252850354350) -->
+ <skip />
+ <!-- no translation found for roamingText6 (2059440825782871513) -->
+ <skip />
+ <!-- no translation found for roamingText7 (7112078724097233605) -->
+ <skip />
+ <!-- no translation found for roamingText8 (5989569778604089291) -->
+ <skip />
+ <!-- no translation found for roamingText9 (7969296811355152491) -->
+ <skip />
+ <!-- no translation found for roamingText10 (3992906999815316417) -->
+ <skip />
+ <!-- no translation found for roamingText11 (4154476854426920970) -->
+ <skip />
+ <!-- no translation found for roamingText12 (1189071119992726320) -->
+ <skip />
+ <!-- no translation found for roamingTextSearching (8360141885972279963) -->
+ <skip />
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転é€ã§ãã¾ã›ã‚“"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g> (<xliff:g id="TIME_DELAY">{2}</xliff:g>秒後)"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転é€ã§ãã¾ã›ã‚“"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転é€ã§ãã¾ã›ã‚“"</string>
+ <!-- no translation found for fcComplete (3118848230966886575) -->
+ <skip />
+ <!-- no translation found for fcError (3327560126588500777) -->
+ <skip />
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"ウェブページã«ã‚¨ãƒ©ãƒ¼ãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="httpErrorLookup">"URLãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"</string>
+ <string name="httpErrorUnsupportedAuthScheme">"ã“ã®ã‚µã‚¤ãƒˆã®èªè¨¼æ–¹å¼ã«ã¯å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“。"</string>
+ <string name="httpErrorAuth">"èªè¨¼ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
+ <string name="httpErrorProxyAuth">"プロキシサーãƒãƒ¼ã‚’使用ã—ãŸèªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"</string>
+ <string name="httpErrorConnect">"サーãƒãƒ¼ã«æŽ¥ç¶šã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
+ <string name="httpErrorIO">"サーãƒãƒ¼ã¨é€šä¿¡ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã—ã°ã‚‰ãã—ã¦ã‹ã‚‰ã‚‚ã†ä¸€åº¦è©¦ã—ã¦ãã ã•ã„。"</string>
+ <string name="httpErrorTimeout">"サーãƒãƒ¼ã¸ã®æŽ¥ç¶šãŒã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã«ãªã‚Šã¾ã—ãŸã€‚"</string>
+ <string name="httpErrorRedirectLoop">"ã“ã®ãƒšãƒ¼ã‚¸ã¯ã‚µãƒ¼ãƒãƒ¼ã®ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆãŒå¤šã™ãŽã¾ã™ã€‚"</string>
+ <string name="httpErrorUnsupportedScheme">"ã“ã®ãƒ—ロトコルã«ã¯å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“。"</string>
+ <string name="httpErrorFailedSslHandshake">"安全ãªæŽ¥ç¶šã‚’確立ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
+ <string name="httpErrorBadUrl">"URLãŒç„¡åŠ¹ãªã®ã§ãƒšãƒ¼ã‚¸ã‚’表示ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
+ <string name="httpErrorFile">"ファイルã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
+ <string name="httpErrorFileNotFound">"è¦æ±‚ã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
+ <string name="httpErrorTooManyRequests">"処ç†ä¸­ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒå¤šã™ãŽã¾ã™ã€‚ã—ã°ã‚‰ãã—ã¦ã‹ã‚‰ã‚‚ã†ä¸€åº¦è©¦ã—ã¦ãã ã•ã„。"</string>
+ <string name="contentServiceSync">"åŒæœŸ"</string>
+ <string name="contentServiceSyncNotificationTitle">"åŒæœŸ"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>ã§ã®å‰Šé™¤ãŒå¤šã™ãŽã¾ã™ã€‚"</string>
+ <string name="low_memory">"電話ã®ãƒ¡ãƒ¢ãƒªãŒã„ã£ã±ã„ã§ã™ã€‚ファイルを削除ã—ã¦ãƒ¡ãƒ¢ãƒªã‚’解放ã—ã¦ãã ã•ã„。"</string>
+ <string name="me">"自分"</string>
+ <string name="power_dialog">"æºå¸¯é›»è©±ã‚ªãƒ—ション"</string>
+ <string name="silent_mode">"マナーモード"</string>
+ <string name="turn_on_radio">"ワイヤレス接続をONã«ã™ã‚‹"</string>
+ <string name="turn_off_radio">"ワイヤレス接続をOFFã«ã™ã‚‹"</string>
+ <string name="screen_lock">"ç”»é¢ã‚’ロック"</string>
+ <string name="power_off">"é›»æºã‚’切る"</string>
+ <string name="shutdown_progress">"シャットダウン中..."</string>
+ <string name="shutdown_confirm">"æºå¸¯é›»è©±ã®é›»æºã‚’切りã¾ã™ã€‚"</string>
+ <string name="no_recent_tasks">"最近使ã£ãŸã‚¢ãƒ—リケーションã¯ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="global_actions">"æºå¸¯é›»è©±ã‚ªãƒ—ション"</string>
+ <string name="global_action_lock">"ç”»é¢ãƒ­ãƒƒã‚¯"</string>
+ <string name="global_action_power_off">"é›»æºã‚’切る"</string>
+ <string name="global_action_toggle_silent_mode">"マナーモード"</string>
+ <string name="global_action_silent_mode_on_status">"サウンドOFF"</string>
+ <string name="global_action_silent_mode_off_status">"サウンドON"</string>
+ <string name="global_actions_toggle_airplane_mode">"機内モード"</string>
+ <string name="global_actions_airplane_mode_on_status">"機内モードON"</string>
+ <string name="global_actions_airplane_mode_off_status">"機内モードOFF"</string>
+ <string name="safeMode">"セーフモード"</string>
+ <string name="android_system_label">"Androidシステム"</string>
+ <string name="permgrouplab_costMoney">"料金ã®ç™ºç”Ÿã™ã‚‹ã‚µãƒ¼ãƒ“ス"</string>
+ <string name="permgroupdesc_costMoney">"料金ã®ç™ºç”Ÿã™ã‚‹æ“作をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permgrouplab_messages">"é€å—ä¿¡ã—ãŸãƒ¡ãƒƒã‚»ãƒ¼ã‚¸"</string>
+ <string name="permgroupdesc_messages">"SMSã€ãƒ¡ãƒ¼ãƒ«ãªã©ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®èª­ã¿æ›¸ã"</string>
+ <string name="permgrouplab_personalInfo">"個人情報"</string>
+ <string name="permgroupdesc_personalInfo">"端末ã®é€£çµ¡å…ˆã¨ã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ã«ç›´æŽ¥ã‚¢ã‚¯ã‚»ã‚¹"</string>
+ <string name="permgrouplab_location">"ç¾åœ¨åœ°"</string>
+ <string name="permgroupdesc_location">"ç¾åœ¨åœ°ã‚’追跡"</string>
+ <string name="permgrouplab_network">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯é€šä¿¡"</string>
+ <string name="permgroupdesc_network">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®ã•ã¾ã–ã¾ãªæ©Ÿèƒ½ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permgrouplab_accounts">"Googleアカウント"</string>
+ <string name="permgroupdesc_accounts">"利用å¯èƒ½ãªGoogleアカウントã¸ã®ã‚¢ã‚¯ã‚»ã‚¹"</string>
+ <string name="permgrouplab_hardwareControls">"ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã®åˆ¶å¾¡"</string>
+ <string name="permgroupdesc_hardwareControls">"æºå¸¯é›»è©±ã®ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã«ç›´æŽ¥ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ã€‚"</string>
+ <string name="permgrouplab_phoneCalls">"電話/通話"</string>
+ <string name="permgroupdesc_phoneCalls">"通話ã®ç›£è¦–ã€è¨˜éŒ²ã€å‡¦ç†"</string>
+ <string name="permgrouplab_systemTools">"システムツール"</string>
+ <string name="permgroupdesc_systemTools">"システムã®ä½Žãƒ¬ãƒ™ãƒ«ã®ã‚¢ã‚¯ã‚»ã‚¹ã¨åˆ¶å¾¡"</string>
+ <string name="permgrouplab_developmentTools">"開発ツール"</string>
+ <string name="permgroupdesc_developmentTools">"アプリケーションã®ãƒ‡ãƒ™ãƒ­ãƒƒãƒ‘ーã«ã®ã¿å¿…è¦ãªæ©Ÿèƒ½ã§ã™ã€‚"</string>
+ <!-- no translation found for permgrouplab_storage (1971118770546336966) -->
+ <skip />
+ <!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
+ <skip />
+ <string name="permlab_statusBar">"ステータスãƒãƒ¼ã®ç„¡åŠ¹åŒ–や変更"</string>
+ <string name="permdesc_statusBar">"ステータスãƒãƒ¼ã®ç„¡åŠ¹åŒ–やシステムアイコンã®è¿½åŠ ã‚„削除をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_expandStatusBar">"ステータスãƒãƒ¼ã®æ‹¡å¤§/縮å°"</string>
+ <string name="permdesc_expandStatusBar">"ステータスãƒãƒ¼ã®æ‹¡å¤§ã‚„縮å°ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_processOutgoingCalls">"発信ã®å‚å—"</string>
+ <string name="permdesc_processOutgoingCalls">"通話発信ã¨ãƒ€ã‚¤ãƒ¤ãƒ«ã™ã‚‹ç•ªå·ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒç™ºä¿¡ã‚’監視ã€è»¢é€ã€é˜»æ­¢ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_receiveSms">"SMSã®å—ä¿¡"</string>
+ <string name="permdesc_receiveSms">"SMSメッセージã®å—ä¿¡ã¨å‡¦ç†ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’監視ã—ãŸã‚Šã€è¡¨ç¤ºã›ãšã«å‰Šé™¤ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_receiveMms">"MMSã®å—ä¿¡"</string>
+ <string name="permdesc_receiveMms">"MMSメッセージã®å—ä¿¡ã¨å‡¦ç†ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’監視ã—ãŸã‚Šã€è¡¨ç¤ºã›ãšã«å‰Šé™¤ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_sendSms">"SMSメッセージã®é€ä¿¡"</string>
+ <string name="permdesc_sendSms">"SMSメッセージã®é€ä¿¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒç¢ºèªãªã—ã§ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’é€ä¿¡ã—ã€æ–™é‡‘ãŒç™ºç”Ÿã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_readSms">"SMSã®èª­ã¿å–ã‚Š"</string>
+ <string name="permdesc_readSms">"æºå¸¯é›»è©±ã‚„SIMカードã«ä¿å­˜ã—ãŸSMSメッセージã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒæ©Ÿå¯†ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’読ã¿å–ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_writeSms">"SMSã®ç·¨é›†"</string>
+ <string name="permdesc_writeSms">"æºå¸¯é›»è©±ã‚„SIMカードã«ä¿å­˜ã—ãŸSMSメッセージã¸ã®æ›¸ãè¾¼ã¿ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’削除ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_receiveWapPush">"WAPã®å—ä¿¡"</string>
+ <string name="permdesc_receiveWapPush">"WAPメッセージã®å—ä¿¡ã¨å‡¦ç†ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’監視ã—ãŸã‚Šã€è¡¨ç¤ºã›ãšã«å‰Šé™¤ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_getTasks">"実行中ã®ã‚¢ãƒ—リケーションã®å–å¾—"</string>
+ <string name="permdesc_getTasks">"ç¾åœ¨å®Ÿè¡Œä¸­ã¾ãŸã¯æœ€è¿‘実行ã—ãŸã‚¿ã‚¹ã‚¯ã«é–¢ã™ã‚‹æƒ…å ±ã®å–得をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒä»–ã®ã‚¢ãƒ—リケーションã®éžå…¬é–‹æƒ…報をå–å¾—ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_reorderTasks">"実行中ã®ã‚¢ãƒ—リケーションã®é †åºã®å¤‰æ›´"</string>
+ <string name="permdesc_reorderTasks">"タスクをフォアグラウンドやãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã«ç§»å‹•ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒå„ªå…ˆã•ã‚Œã¦ã€ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã§ããªããªã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_setDebugApp">"アプリケーションã®ãƒ‡ãƒãƒƒã‚°ã‚’有効ã«ã™ã‚‹"</string>
+ <string name="permdesc_setDebugApp">"別ã®ã‚¢ãƒ—リケーションをデãƒãƒƒã‚°ãƒ¢ãƒ¼ãƒ‰ã«ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒåˆ¥ã®ã‚¢ãƒ—リケーションを終了ã•ã›ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_changeConfiguration">"UI設定ã®å¤‰æ›´"</string>
+ <string name="permdesc_changeConfiguration">"地域/言語やフォントã®ã‚µã‚¤ã‚ºãªã©ã€ç¾åœ¨ã®è¨­å®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_restartPackages">"ä»–ã®ã‚¢ãƒ—リケーションã®å†èµ·å‹•"</string>
+ <string name="permdesc_restartPackages">"ä»–ã®ã‚¢ãƒ—リケーションã®å¼·åˆ¶çš„ãªå†èµ·å‹•ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_forceBack">"アプリケーションã®å¼·åˆ¶çµ‚了"</string>
+ <string name="permdesc_forceBack">"フォアグラウンドã§å®Ÿè¡Œã•ã‚Œã¦ã„ã‚‹æ“作を強制終了ã—ã¦æˆ»ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="permlab_dump">"システムã®å†…部状態ã®å–å¾—"</string>
+ <string name="permdesc_dump">"システムã®å†…部状態ã®å–得をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã€é€šå¸¸ã¯å¿…è¦ã¨ã—ãªã„広範囲ã«ã‚ãŸã‚‹éžå…¬é–‹ã®æ©Ÿå¯†æƒ…報をå–å¾—ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <!-- no translation found for permlab_shutdown (7185747824038909016) -->
+ <skip />
+ <!-- no translation found for permdesc_shutdown (7046500838746291775) -->
+ <skip />
+ <!-- no translation found for permlab_stopAppSwitches (4138608610717425573) -->
+ <skip />
+ <!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
+ <skip />
+ <string name="permlab_runSetActivityWatcher">"起動中ã®ã™ã¹ã¦ã®ã‚¢ãƒ—リケーションã®ç›£è¦–ã¨åˆ¶å¾¡"</string>
+ <string name="permdesc_runSetActivityWatcher">"システムãŒèµ·å‹•ã™ã‚‹æ“作ã®ç›£è¦–ã¨åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã‚·ã‚¹ãƒ†ãƒ ã‚’完全ã«ç ´å£Šã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚ã“ã®è¨±å¯ã¯é–‹ç™ºã«ã®ã¿å¿…è¦ã§ã€æºå¸¯é›»è©±ã®é€šå¸¸ã®ä½¿ç”¨ã«ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="permlab_broadcastPackageRemoved">"パッケージ削除ブロードキャストã®é€ä¿¡"</string>
+ <string name="permdesc_broadcastPackageRemoved">"アプリケーションパッケージã®å‰Šé™¤ã®é€šçŸ¥ã‚’é…ä¿¡ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒä»–ã®å®Ÿè¡Œä¸­ã®ã‚¢ãƒ—リケーションを強制終了ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_broadcastSmsReceived">"SMSå—信ブロードキャストã®é€ä¿¡"</string>
+ <string name="permdesc_broadcastSmsReceived">"SMSメッセージã®å—信通知ã®é…信をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒå—ä¿¡SMSメッセージをå½é€ ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_broadcastWapPush">"WAP-PUSHå—信ブロードキャストã®é€ä¿¡"</string>
+ <string name="permdesc_broadcastWapPush">"WAP PUSHメッセージã®å—ä¿¡ã®é€šçŸ¥ã‚’é…ä¿¡ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒMMSå—信メッセージをå½é€ ã—ãŸã‚Šã€ã‚¦ã‚§ãƒ–ページã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„を密ã‹ã«æ”¹ã–ã‚“ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_setProcessLimit">"実行中ã®ãƒ—ロセスã®æ•°ã‚’制é™"</string>
+ <string name="permdesc_setProcessLimit">"実行ã™ã‚‹ãƒ—ロセス数ã®ä¸Šé™ã®åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã«ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="permlab_setAlwaysFinish">"ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã‚¢ãƒ—リケーションをã™ã¹ã¦çµ‚了ã™ã‚‹"</string>
+ <string name="permdesc_setAlwaysFinish">"ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã«ãªã‚Šæ¬¡ç¬¬å¿…ãšæ“作を終了ã•ã›ã‚‹ã‹ã©ã†ã‹ã®åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="permlab_batteryStats">"電池統計情報ã®å¤‰å›½"</string>
+ <string name="permdesc_batteryStats">"åŽé›†ã—ãŸé›»æ± çµ±è¨ˆæƒ…å ±ã®å¤‰æ›´ã‚’許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
+ <!-- no translation found for permlab_backup (470013022865453920) -->
+ <skip />
+ <!-- no translation found for permdesc_backup (2305432853944929371) -->
+ <skip />
+ <string name="permlab_internalSystemWindow">"未許å¯ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã®è¡¨ç¤º"</string>
+ <string name="permdesc_internalSystemWindow">"内部システムã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã§ä½¿ç”¨ã™ã‚‹ãŸã‚ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ä½œæˆã‚’許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
+ <string name="permlab_systemAlertWindow">"システムレベルã®è­¦å‘Šã®è¡¨ç¤º"</string>
+ <string name="permdesc_systemAlertWindow">"システムã®è­¦å‘Šã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã®è¡¨ç¤ºã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒæºå¸¯é›»è©±ã®ç”»é¢å…¨ä½“ã‚’å½è£…ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_setAnimationScale">"アニメーションã®ãƒ—リセット速度ã®å¤‰æ›´"</string>
+ <string name="permdesc_setAnimationScale">"ã„ã¤ã§ã‚‚アニメーション全般ã®é€Ÿåº¦ã‚’変更ã™ã‚‹ (アニメーションを速ãã¾ãŸã¯é…ãã™ã‚‹) ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_manageAppTokens">"アプリケーショントークンã®ç®¡ç†"</string>
+ <string name="permdesc_manageAppTokens">"通常ã®Z-orderingを回é¿ã—ã¦ã€ç‹¬è‡ªã®ãƒˆãƒ¼ã‚¯ãƒ³ã‚’作æˆã€ç®¡ç†ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="permlab_injectEvents">"キーを押ã—ã¦ãƒœã‚¿ãƒ³ã‚’コントロール"</string>
+ <string name="permdesc_injectEvents">"入力イベント (キーを押ã™ãªã©) を別ã®ã‚¢ãƒ—リケーションã«ä¼ãˆã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæ‚ªæ„ã®ã‚るアプリケーションãŒã€æºå¸¯é›»è©±ã‚’ä¹—ã£å–ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_readInputState">"入力やæ“作ã®è¨˜éŒ²"</string>
+ <string name="permdesc_readInputState">"別ã®ã‚¢ãƒ—リケーションã¸ã®å…¥åŠ›ï¼ˆãƒ‘スワードãªã©ï¼‰ã§ã‚‚キー入力を監視ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="permlab_bindInputMethod">"入力方法ã«é–¢é€£ä»˜ã‘ã‚‹"</string>
+ <string name="permdesc_bindInputMethod">"入力方法ã®ãƒˆãƒƒãƒ—レベルインターフェースã«é–¢é€£ä»˜ã‘ã‚‹ã“ã¨ã‚’所有者ã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã«ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="permlab_setOrientation">"ç”»é¢ã®å‘ãã®å¤‰æ›´"</string>
+ <string name="permdesc_setOrientation">"ã„ã¤ã§ã‚‚ç”»é¢ã®å›žè»¢ã‚’変更ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã«ã¯ã¾ã£ãŸãå¿…è¦ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="permlab_signalPersistentProcesses">"Linuxã®ã‚·ã‚°ãƒŠãƒ«ã‚’アプリケーションã«é€ä¿¡"</string>
+ <string name="permdesc_signalPersistentProcesses">"å—ä¿¡ã—ãŸé›»æ³¢ã‚’継続プロセスã«é€ä¿¡ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_persistentActivity">"アプリケーションを常ã«å®Ÿè¡Œã™ã‚‹"</string>
+ <string name="permdesc_persistentActivity">"自身を部分的ã«æ°¸ç¶šã•ã›ã¦ã€ä»–ã®ã‚¢ãƒ—リケーション用ã«ã¯ãã®é ˜åŸŸã‚’システムã«ä½¿ã‚ã›ãªã„よã†ã«ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_deletePackages">"アプリケーションã®å‰Šé™¤"</string>
+ <string name="permdesc_deletePackages">"Androidパッケージã®å‰Šé™¤ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã€é‡è¦ãªã‚¢ãƒ—リケーションを削除ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_clearAppUserData">"ä»–ã®ã‚¢ãƒ—リケーションã®ãƒ‡ãƒ¼ã‚¿ã‚’削除"</string>
+ <string name="permdesc_clearAppUserData">"ユーザーデータã®æ¶ˆåŽ»ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_deleteCacheFiles">"ä»–ã®ã‚¢ãƒ—リケーションã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’削除"</string>
+ <string name="permdesc_deleteCacheFiles">"キャッシュファイルã®å‰Šé™¤ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_getPackageSize">"アプリケーションã®ãƒ¡ãƒ¢ãƒªå®¹é‡ã®è¨ˆæ¸¬"</string>
+ <string name="permdesc_getPackageSize">"アプリケーションã®ã‚³ãƒ¼ãƒ‰ã€ãƒ‡ãƒ¼ã‚¿ã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã®ã‚µã‚¤ã‚ºã‚’å–å¾—ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_installPackages">"アプリケーションを直接インストール"</string>
+ <string name="permdesc_installPackages">"Androidパッケージã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«/更新をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã€å‹æ‰‹ã«å¼·åŠ›ãªæ¨©é™ã‚’æŒã¤æ–°ã—ã„アプリケーションを追加ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_clearAppCache">"アプリケーションキャッシュデータã®å‰Šé™¤"</string>
+ <string name="permdesc_clearAppCache">"アプリケーションã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‹ã‚‰ãƒ•ã‚¡ã‚¤ãƒ«ã‚’削除ã—ã¦æºå¸¯é›»è©±ã®ãƒ¡ãƒ¢ãƒªã‚’解放ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã€ã‚¢ã‚¯ã‚»ã‚¹ã¯ã‚·ã‚¹ãƒ†ãƒ ãƒ—ロセスã®ã¿ã«åˆ¶é™ã•ã‚Œã¾ã™ã€‚"</string>
+ <string name="permlab_readLogs">"システムログファイルã®èª­ã¿å–ã‚Š"</string>
+ <string name="permdesc_readLogs">"システムã®ã•ã¾ã–ã¾ãªãƒ­ã‚°ãƒ•ã‚¡ã‚¤ãƒ«ã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæºå¸¯é›»è©±ã®ä½¿ç”¨çŠ¶æ³ã«é–¢ã™ã‚‹å…¨èˆ¬æƒ…å ±ãŒå–å¾—ã•ã‚Œã¾ã™ãŒã€å€‹äººæƒ…報やéžå…¬é–‹æƒ…å ±ãŒå«ã¾ã‚Œã‚‹ã“ã¨ã¯ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="permlab_diagnostic">"diagãŒæ‰€æœ‰ã™ã‚‹ãƒªã‚½ãƒ¼ã‚¹ã®èª­ã¿æ›¸ã"</string>
+ <string name="permdesc_diagnostic">"diagグループãŒæ‰€æœ‰ã™ã‚‹ãƒªã‚½ãƒ¼ã‚¹ï¼ˆä¾‹:/dev内ã®ãƒ•ã‚¡ã‚¤ãƒ«ï¼‰ã¸ã®èª­ã¿æ›¸ãをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚システムã®å®‰å®šæ€§ã¨ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã«å½±éŸ¿ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚メーカー/オペレーターã«ã‚ˆã‚‹ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢å›ºæœ‰ã®è¨ºæ–­ä»¥å¤–ã«ã¯ä½¿ç”¨ã—ãªã„ã§ãã ã•ã„。"</string>
+ <string name="permlab_changeComponentState">"アプリケーションã®ã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆã‚’有効/無効ã«ã™ã‚‹"</string>
+ <string name="permdesc_changeComponentState">"別アプリケーションã®ã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆã®æœ‰åŠ¹/無効を変更ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæ‚ªæ„ã®ã‚るアプリケーションãŒã€æºå¸¯é›»è©±ã®é‡è¦ãªæ©Ÿèƒ½ã‚’無効ã«ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚アプリケーションコンãƒãƒ¼ãƒãƒ³ãƒˆãŒåˆ©ç”¨ã§ããªã„ã€æ•´åˆæ€§ãŒå–ã‚Œãªã„ã€ã¾ãŸã¯ä¸å®‰å®šãªçŠ¶æ…‹ã«ãªã‚‹æã‚ŒãŒã‚ã‚‹ã®ã§ã€è¨±å¯ã«ã¯æ³¨æ„ãŒå¿…è¦ã§ã™ã€‚"</string>
+ <string name="permlab_setPreferredApplications">"優先アプリケーションã®è¨­å®š"</string>
+ <string name="permdesc_setPreferredApplications">"優先アプリケーションを変更ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒå®Ÿè¡Œä¸­ã®ã‚¢ãƒ—リケーションを密ã‹ã«å¤‰æ›´ã—ã€æ—¢å­˜ã®ã‚¢ãƒ—リケーションã«ãªã‚Šã™ã¾ã—ã¦éžå…¬é–‹ãƒ‡ãƒ¼ã‚¿ã‚’åŽé›†ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_writeSettings">"システムã®å…¨èˆ¬è¨­å®šã®å¤‰æ›´"</string>
+ <string name="permdesc_writeSettings">"システム設定データã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã‚·ã‚¹ãƒ†ãƒ è¨­å®šã‚’破壊ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_writeSecureSettings">"システムã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨­å®šã®å¤‰æ›´"</string>
+ <string name="permdesc_writeSecureSettings">"システムã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨­å®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
+ <string name="permlab_writeGservices">"Googleサービスã®åœ°å›³ã®å¤‰æ›´"</string>
+ <string name="permdesc_writeGservices">"Googleサービスマップã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
+ <string name="permlab_receiveBootCompleted">"起動時ã«è‡ªå‹•çš„ã«é–‹å§‹"</string>
+ <string name="permdesc_receiveBootCompleted">"システムã®èµ·å‹•å¾Œã«è‡ªå‹•çš„ã«èµ·å‹•ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚æºå¸¯é›»è©±ã®èµ·å‹•ã«æ™‚é–“ãŒã‹ã‹ã‚‹ã‚ˆã†ã«ãªã‚Šã€ã‚¢ãƒ—リケーションãŒå¸¸ã«å®Ÿè¡Œã•ã‚Œã‚‹ãŸã‚ã«æºå¸¯é›»è©±ã®å…¨ä½“çš„ãªå‹•ä½œãŒé…ããªã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_broadcastSticky">"stickyブロードキャストã®é…ä¿¡"</string>
+ <string name="permdesc_broadcastSticky">"é…ä¿¡ãŒçµ‚了ã—ã¦ã‚‚メモリã«æ®‹ã‚‹ã‚ˆã†ãªstickyブロードキャストをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ¡ãƒ¢ãƒªã‚’使ã„ã™ãŽã¦ã€æºå¸¯é›»è©±ã®å‹•ä½œãŒé…ããªã£ãŸã‚Šã€ä¸å®‰å®šã«ãªã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_readContacts">"連絡先データã®èª­ã¿å–ã‚Š"</string>
+ <string name="permdesc_readContacts">"端末ã«ä¿å­˜ã—ãŸé€£çµ¡å…ˆï¼ˆã‚¢ãƒ‰ãƒ¬ã‚¹ï¼‰ãƒ‡ãƒ¼ã‚¿ã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒãƒ‡ãƒ¼ã‚¿ã‚’他人ã«é€ä¿¡ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_writeContacts">"連絡先データã®æ›¸ãè¾¼ã¿"</string>
+ <string name="permdesc_writeContacts">"端末ã«ä¿å­˜ã—ãŸé€£çµ¡å…ˆï¼ˆã‚¢ãƒ‰ãƒ¬ã‚¹ï¼‰ãƒ‡ãƒ¼ã‚¿ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒé€£çµ¡å…ˆãƒ‡ãƒ¼ã‚¿ã‚’消去/変更ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_writeOwnerData">"所有者データã®æ›¸ãè¾¼ã¿"</string>
+ <string name="permdesc_writeOwnerData">"端末ã«ä¿å­˜ã—ãŸæ‰€æœ‰è€…ã®ãƒ‡ãƒ¼ã‚¿ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒæ‰€æœ‰è€…ã®ãƒ‡ãƒ¼ã‚¿ã‚’消去/変更ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_readOwnerData">"所有者データã®èª­ã¿å–ã‚Š"</string>
+ <string name="permdesc_readOwnerData">"æºå¸¯é›»è©±ã«ä¿å­˜ã—ãŸæ‰€æœ‰è€…データã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒæ‰€æœ‰è€…データを読ã¿å–ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_readCalendar">"カレンダーデータã®èª­ã¿å–ã‚Š"</string>
+ <string name="permdesc_readCalendar">"端末ã«ä¿å­˜ã—ãŸã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ã®äºˆå®šã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ã®äºˆå®šã‚’他人ã«é€ä¿¡ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_writeCalendar">"カレンダーデータã®æ›¸ãè¾¼ã¿"</string>
+ <string name="permdesc_writeCalendar">"端末ã«ä¿å­˜ã—ãŸã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ã®äºˆå®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒã€ã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼ãƒ‡ãƒ¼ã‚¿ã‚’消去/変更ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_accessMockLocation">"ä»®ã®ä½ç½®æƒ…å ±ã§ãƒ†ã‚¹ãƒˆ"</string>
+ <string name="permdesc_accessMockLocation">"テスト用ã«ä»®ã®ä½ç½®æƒ…å ±æºã‚’作æˆã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæ‚ªæ„ã®ã‚るアプリケーションãŒã€GPSã€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ—ロãƒã‚¤ãƒ€ãªã©ã‹ã‚‰è¿”ã•ã‚Œã‚‹æœ¬å½“ã®ä½ç½®æƒ…報や状æ³ã‚’改ã–ã‚“ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_accessLocationExtraCommands">"ä½ç½®æƒ…å ±æ供者ã®è¿½åŠ ã‚³ãƒžãƒ³ãƒ‰ã‚¢ã‚¯ã‚»ã‚¹"</string>
+ <string name="permdesc_accessLocationExtraCommands">"ä½ç½®æƒ…å ±æ供元ã®è¿½åŠ ã‚³ãƒžãƒ³ãƒ‰ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒGPSãªã©ã®ä½ç½®æä¾›ã®å‹•ä½œã‚’妨害ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
+ <skip />
+ <!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
+ <skip />
+ <string name="permlab_accessFineLocation">"精細ãªä½ç½®æƒ…報(GPS)"</string>
+ <string name="permdesc_accessFineLocation">"GPSãªã©æºå¸¯é›»è©±ã®ä½ç½®æƒ…å ±ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ï¼ˆå¯èƒ½ãªå ´åˆï¼‰ã€‚今ã„る場所ãŒæ‚ªæ„ã®ã‚るアプリケーションã«æ¤œå‡ºã•ã‚ŒãŸã‚Šã€ãƒãƒƒãƒ†ãƒªãƒ¼ã®æ¶ˆè²»ãŒå¢—ãˆã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_accessCoarseLocation">"ãŠãŠã‚ˆãã®ä½ç½®æƒ…報(ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯åŸºåœ°å±€ï¼‰"</string>
+ <string name="permdesc_accessCoarseLocation">"セルラーãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãªã©ã€æºå¸¯é›»è©±ã®ãŠãŠã‚ˆãã®ä½ç½®ã‚’特定ã™ã‚‹æƒ…å ±æºãŒåˆ©ç”¨å¯èƒ½ãªå ´åˆã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæ‚ªæ„ã®ã‚るアプリケーションãŒã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãŠãŠã‚ˆãã®ä½ç½®ã‚’特定ã§ãã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_accessSurfaceFlinger">"SurfaceFlingerã¸ã®ã‚¢ã‚¯ã‚»ã‚¹"</string>
+ <string name="permdesc_accessSurfaceFlinger">"SurfaceFlingerã®ä½Žãƒ¬ãƒ™ãƒ«ã®æ©Ÿèƒ½ã®ä½¿ç”¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_readFrameBuffer">"フレームãƒãƒƒãƒ•ã‚¡ã®èª­ã¿å–ã‚Š"</string>
+ <string name="permdesc_readFrameBuffer">"フレームãƒãƒƒãƒ•ã‚¡ã®å†…容ã®èª­ã¿å–ã‚Šã¨ä½¿ç”¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_modifyAudioSettings">"音声設定ã®å¤‰æ›´"</string>
+ <string name="permdesc_modifyAudioSettings">"音é‡ã‚„転é€ãªã©ã®éŸ³å£°å…¨èˆ¬ã®è¨­å®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_recordAudio">"録音"</string>
+ <string name="permdesc_recordAudio">"オーディオ録音パスã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_camera">"写真ã®æ’®å½±"</string>
+ <string name="permdesc_camera">"カメラã§ã®å†™çœŸæ’®å½±ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚アプリケーションã¯ã‚«ãƒ¡ãƒ©ã‹ã‚‰ç”»åƒã‚’ã„ã¤ã§ã‚‚åŽé›†ã§ãã¾ã™ã€‚"</string>
+ <string name="permlab_brick">"端末を永続的ã«ç„¡åŠ¹ã«ã™ã‚‹"</string>
+ <string name="permdesc_brick">"æºå¸¯é›»è©±å…¨ä½“を永続的ã«ç„¡åŠ¹ã«ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã®è¨±å¯ã¯éžå¸¸ã«å±é™ºã§ã™ã€‚"</string>
+ <string name="permlab_reboot">"端末ã®å†èµ·å‹•"</string>
+ <string name="permdesc_reboot">"端末ã®å¼·åˆ¶çš„ãªå†èµ·å‹•ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_mount_unmount_filesystems">"ファイルシステムã®ãƒžã‚¦ãƒ³ãƒˆã¨ãƒžã‚¦ãƒ³ãƒˆè§£é™¤"</string>
+ <string name="permdesc_mount_unmount_filesystems">"リムーãƒãƒ–ルメモリã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚·ã‚¹ãƒ†ãƒ ã®ãƒžã‚¦ãƒ³ãƒˆã¨ãƒžã‚¦ãƒ³ãƒˆè§£é™¤ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_mount_format_filesystems">"外部ストレージã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆ"</string>
+ <string name="permdesc_mount_format_filesystems">"アプリケーションãŒãƒªãƒ ãƒ¼ãƒãƒ–ルストレージをフォーマットã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_vibrate">"ãƒã‚¤ãƒ–レーション制御"</string>
+ <string name="permdesc_vibrate">"ãƒã‚¤ãƒ–レーションã®åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_flashlight">"ライトã®ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«"</string>
+ <string name="permdesc_flashlight">"ライトã®åˆ¶å¾¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_hardware_test">"ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã®ãƒ†ã‚¹ãƒˆ"</string>
+ <string name="permdesc_hardware_test">"ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã®ãƒ†ã‚¹ãƒˆã®ãŸã‚ã«ã•ã¾ã–ã¾ãªå‘¨è¾ºæ©Ÿå™¨ã‚’制御ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_callPhone">"電話番å·ç™ºä¿¡"</string>
+ <string name="permdesc_callPhone">"電話番å·ã®è‡ªå‹•ç™ºä¿¡ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒæ„図ã—ãªã„電話をã‹ã‘ã¦æ–™é‡‘ãŒç™ºç”Ÿã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚緊急通報ã¸ã®ç™ºä¿¡ã¯è¨±å¯ã—ã¾ã›ã‚“。"</string>
+ <string name="permlab_callPrivileged">"電話番å·ç™ºä¿¡"</string>
+ <string name="permdesc_callPrivileged">"緊急通報をå«ã‚ã‚らゆる電話番å·ã«è‡ªå‹•ç™ºä¿¡ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒç·Šæ€¥ã‚µãƒ¼ãƒ“スã«ä¸æ­£ãªé€šå ±ã‚’ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_locationUpdates">"ä½ç½®æƒ…å ±ã®æ›´æ–°é€šçŸ¥"</string>
+ <string name="permdesc_locationUpdates">"無線通信ã‹ã‚‰ã®ä½ç½®æ›´æ–°é€šçŸ¥ã‚’有効/無効ã«ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
+ <string name="permlab_checkinProperties">"ãƒã‚§ãƒƒã‚¯ã‚¤ãƒ³ãƒ—ロパティã¸ã®ã‚¢ã‚¯ã‚»ã‚¹"</string>
+ <string name="permdesc_checkinProperties">"ãƒã‚§ãƒƒã‚¯ã‚¤ãƒ³ã‚µãƒ¼ãƒ“スãŒã‚¢ãƒƒãƒ—ロードã—ãŸãƒ—ロパティã¸ã®èª­ã¿æ›¸ãを許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
+ <string name="permlab_bindGadget">"ウィジェットã®é¸æŠž"</string>
+ <string name="permdesc_bindGadget">"ã©ã®ã‚¢ãƒ—リケーションãŒã©ã®ã‚¦ã‚£ã‚¸ã‚§ãƒƒãƒˆã‚’使用ã§ãã‚‹ã‹ã‚·ã‚¹ãƒ†ãƒ ã«æŒ‡å®šã™ã‚‹ã“ã¨ã‚’ã“ã®ã‚¢ãƒ—リケーションã«è¨±å¯ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šã€ã‚¢ãƒ—リケーション間ã§å€‹äººãƒ‡ãƒ¼ã‚¿ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
+ <string name="permlab_modifyPhoneState">"端末ステータスã®å¤‰æ›´"</string>
+ <string name="permdesc_modifyPhoneState">"端末ã®é›»è©±æ©Ÿèƒ½ã®ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚アプリケーションã¯ã€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®åˆ‡ã‚Šæ›¿ãˆã€æºå¸¯é›»è©±ã®ç„¡ç·šé€šä¿¡ã®ã‚ªãƒ³/オフãªã©ã‚’通知ã›ãšã«è¡Œã†ã“ã¨ãŒã§ãã¾ã™ã€‚"</string>
+ <string name="permlab_readPhoneState">"端末ステータスã®èª­ã¿å–ã‚Š"</string>
+ <string name="permdesc_readPhoneState">"端末ã®é›»è©±æ©Ÿèƒ½ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚アプリケーションã¯ã€ã“ã®æºå¸¯é›»è©±ã®é›»è©±ç•ªå·ã€é€šè©±ä¸­ã‹ã©ã†ã‹ã€é€šè©±ç›¸æ‰‹ã®é›»è©±ç•ªå·ãªã©ã‚’特定ã§ãã¾ã™ã€‚"</string>
+ <string name="permlab_wakeLock">"端末ã®ã‚¹ãƒªãƒ¼ãƒ—を無効ã«ã™ã‚‹"</string>
+ <string name="permdesc_wakeLock">"端末ã®ã‚¹ãƒªãƒ¼ãƒ—を無効ã«ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_devicePower">"é›»æºã®ON/OFF"</string>
+ <string name="permdesc_devicePower">"æºå¸¯é›»è©±ã®é›»æºã®ã‚ªãƒ³/オフをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_factoryTest">"出è·æ™‚試験モードã§ã®å®Ÿè¡Œ"</string>
+ <string name="permdesc_factoryTest">"æºå¸¯é›»è©±ã®ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’完全ã«è¨±å¯ã—ã¦ã€ä½Žãƒ¬ãƒ™ãƒ«ã®ãƒ¡ãƒ¼ã‚«ãƒ¼ãƒ†ã‚¹ãƒˆã¨ã—ã¦å®Ÿè¡Œã—ã¾ã™ã€‚メーカーã®ãƒ†ã‚¹ãƒˆãƒ¢ãƒ¼ãƒ‰ã§æºå¸¯é›»è©±ã‚’使用ã™ã‚‹ã¨ãã®ã¿åˆ©ç”¨ã§ãã¾ã™ã€‚"</string>
+ <string name="permlab_setWallpaper">"å£ç´™ã®è¨­å®š"</string>
+ <string name="permdesc_setWallpaper">"システムã®å£ç´™ã®è¨­å®šã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_setWallpaperHints">"å£ç´™ã‚µã‚¤ã‚ºã®ãƒ’ントã®è¨­å®š"</string>
+ <string name="permdesc_setWallpaperHints">"システムã®å£ç´™ã‚µã‚¤ã‚ºã®ãƒ’ントã®è¨­å®šã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_masterClear">"システムを出è·æ™‚設定ã«ãƒªã‚»ãƒƒãƒˆ"</string>
+ <string name="permdesc_masterClear">"データã€è¨­å®šã€ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ãŸã‚¢ãƒ—リケーションをã™ã¹ã¦æ¶ˆåŽ»ã—ã¦ã€å®Œå…¨ã«å‡ºè·æ™‚ã®è¨­å®šã«ã‚·ã‚¹ãƒ†ãƒ ã‚’リセットã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_setTimeZone">"タイムゾーンã®è¨­å®š"</string>
+ <string name="permdesc_setTimeZone">"端末ã®ã‚¿ã‚¤ãƒ ã‚¾ãƒ¼ãƒ³ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_getAccounts">"既知ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®å–å¾—"</string>
+ <string name="permdesc_getAccounts">"端末内ã«ã‚るアカウントã®ãƒªã‚¹ãƒˆã®å–得をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_accessNetworkState">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯çŠ¶æ…‹ã®è¡¨ç¤º"</string>
+ <string name="permdesc_accessNetworkState">"ã™ã¹ã¦ã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯çŠ¶æ…‹ã®è¡¨ç¤ºã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_createNetworkSockets">"完全ãªã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆã‚¢ã‚¯ã‚»ã‚¹"</string>
+ <string name="permdesc_createNetworkSockets">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚½ã‚±ãƒƒãƒˆã®ä½œæˆã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_writeApnSettings">"アクセスãƒã‚¤ãƒ³ãƒˆå設定ã®æ›¸ãè¾¼ã¿"</string>
+ <string name="permdesc_writeApnSettings">"APNã®ãƒ—ロキシやãƒãƒ¼ãƒˆãªã©ã®APN設定ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_changeNetworkState">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯æŽ¥ç¶šã®å¤‰æ›´"</string>
+ <string name="permdesc_changeNetworkState">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®æŽ¥ç¶šçŠ¶æ…‹ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_changeBackgroundDataSetting">"ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ãƒ‡ãƒ¼ã‚¿ä½¿ç”¨è¨­å®šã®å¤‰æ›´"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ãƒ‡ãƒ¼ã‚¿ä½¿ç”¨ã®è¨­å®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_accessWifiState">"Wi-Fi状態ã®è¡¨ç¤º"</string>
+ <string name="permdesc_accessWifiState">"Wi-Fi状態ã«é–¢ã™ã‚‹æƒ…å ±ã®è¡¨ç¤ºã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_changeWifiState">"Wi-Fi状態ã®å¤‰æ›´"</string>
+ <string name="permdesc_changeWifiState">"Wi-Fiアクセスãƒã‚¤ãƒ³ãƒˆã¸ã®æŽ¥ç¶šã‚„接続ã®åˆ‡æ–­ã€è¨­å®šã•ã‚ŒãŸWi-Fiãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
+ <skip />
+ <!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
+ <skip />
+ <string name="permlab_bluetoothAdmin">"Bluetoothã®ç®¡ç†"</string>
+ <string name="permdesc_bluetoothAdmin">"ã“ã®Bluetooth端末ã®è¨­å®šã€ãŠã‚ˆã³ãƒªãƒ¢ãƒ¼ãƒˆç«¯æœ«ã‚’検出ã—ã¦ãƒšã‚¢ã«è¨­å®šã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_bluetooth">"Bluetooth接続ã®ä½œæˆ"</string>
+ <string name="permdesc_bluetooth">"ã“ã®Bluetooth端末ã®è¨­å®šè¡¨ç¤ºã€ãŠã‚ˆã³åˆ¥ã®ç«¯æœ«ã‚’ペアã¨ã—ã¦è¨­å®šã—接続を承èªã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_disableKeyguard">"キーロックを無効ã«ã™ã‚‹"</string>
+ <string name="permdesc_disableKeyguard">"キーロックや関連ã™ã‚‹ãƒ‘スワードセキュリティを無効ã«ã™ã‚‹ã“ã¨ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚正当ãªåˆ©ç”¨ã®ä¾‹ã§ã¯ã€ã‹ã‹ã£ã¦ããŸé›»è©±ã‚’å—ä¿¡ã™ã‚‹éš›ã«ã‚­ãƒ¼ãƒ­ãƒƒã‚¯ã‚’無効ã«ã—ã€é€šè©±ã®çµ‚了時ã«ã‚­ãƒ¼ãƒ­ãƒƒã‚¯ã‚’有効ã«ã—ç›´ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_readSyncSettings">"åŒæœŸè¨­å®šã®èª­ã¿å–ã‚Š"</string>
+ <string name="permdesc_readSyncSettings">"連絡先ã®åŒæœŸã®æœ‰åŠ¹/無効ãªã©ã€åŒæœŸè¨­å®šã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_writeSyncSettings">"åŒæœŸè¨­å®šã®æ›¸ãè¾¼ã¿"</string>
+ <string name="permdesc_writeSyncSettings">"連絡先ã®åŒæœŸã®æœ‰åŠ¹/無効ãªã©ã€åŒæœŸè¨­å®šã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_readSyncStats">"åŒæœŸçµ±è¨ˆã®èª­ã¿å–ã‚Š"</string>
+ <string name="permdesc_readSyncStats">"åŒæœŸçŠ¶æ…‹ï¼ˆåŒæœŸå±¥æ­´ãªã©ï¼‰ã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_subscribedFeedsRead">"登録ã—ãŸãƒ•ã‚£ãƒ¼ãƒ‰ã®èª­ã¿å–ã‚Š"</string>
+ <string name="permdesc_subscribedFeedsRead">"ç¾åœ¨åŒæœŸã—ã¦ã„るフィードã®è©³ç´°ã®å–得をアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_subscribedFeedsWrite">"登録ã—ãŸãƒ•ã‚£ãƒ¼ãƒ‰ã®æ›¸ãè¾¼ã¿"</string>
+ <string name="permdesc_subscribedFeedsWrite">"ç¾åœ¨åŒæœŸã—ã¦ã„るフィードã®å¤‰æ›´ã‚’アプリケーションã«è¨±å¯ã—ã¾ã™ã€‚悪æ„ã®ã‚るアプリケーションãŒåŒæœŸãƒ•ã‚£ãƒ¼ãƒ‰ã‚’変更ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
+ <string name="permlab_readDictionary">"ユーザー定義辞書ã®èª­ã¿è¾¼ã¿"</string>
+ <string name="permdesc_readDictionary">"アプリケーションãŒãƒ¦ãƒ¼ã‚¶ãƒ¼è¾žæ›¸ã«ç™»éŒ²ã•ã‚Œã¦ã„る個人的ãªèªžå¥ã‚„åå‰ã‚’読ã¿è¾¼ã‚€ã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚"</string>
+ <string name="permlab_writeDictionary">"ユーザー定義辞書ã¸ã®æ›¸ãè¾¼ã¿"</string>
+ <string name="permdesc_writeDictionary">"アプリケーションãŒãƒ¦ãƒ¼ã‚¶ãƒ¼è¾žæ›¸ã«æ–°ã—ã„語å¥ã‚’書ã込むã“ã¨ã‚’許å¯ã—ã¾ã™ã€‚"</string>
+ <!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
+ <skip />
+ <!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
+ <skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"自宅"</item>
- <item msgid="869923650527136615">"æºå¸¯"</item>
- <item msgid="7897544654242874543">"仕事"</item>
- <item msgid="1103601433382158155">"FAX(仕事)"</item>
- <item msgid="1735177144948329370">"FAX(自宅)"</item>
- <item msgid="603878674477207394">"ãƒã‚±ãƒ™ãƒ«"</item>
- <item msgid="1650824275177931637">"ãã®ä»–"</item>
- <item msgid="9192514806975898961">"カスタム"</item>
+ <item>"自宅"</item>
+ <item>"æºå¸¯"</item>
+ <item>"仕事"</item>
+ <item>"FAX(仕事)"</item>
+ <item>"FAX(自宅)"</item>
+ <item>"ãƒã‚±ãƒ™ãƒ«"</item>
+ <item>"ãã®ä»–"</item>
+ <item>"カスタム"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"自宅"</item>
- <item msgid="7084237356602625604">"仕事"</item>
- <item msgid="1112044410659011023">"ãã®ä»–"</item>
- <item msgid="2374913952870110618">"カスタム"</item>
+ <item>"自宅"</item>
+ <item>"仕事"</item>
+ <item>"ãã®ä»–"</item>
+ <item>"カスタム"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"æºå¸¯"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"自宅"</item>
- <item msgid="5629153956045109251">"仕事"</item>
- <item msgid="4966604264500343469">"ãã®ä»–"</item>
- <item msgid="4932682847595299369">"カスタム"</item>
+ <item>"自宅"</item>
+ <item>"仕事"</item>
+ <item>"ãã®ä»–"</item>
+ <item>"カスタム"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"自宅"</item>
- <item msgid="1359644565647383708">"仕事"</item>
- <item msgid="7868549401053615677">"ãã®ä»–"</item>
- <item msgid="3145118944639869809">"カスタム"</item>
+ <item>"自宅"</item>
+ <item>"仕事"</item>
+ <item>"ãã®ä»–"</item>
+ <item>"カスタム"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"仕事"</item>
- <item msgid="4378074129049520373">"ãã®ä»–"</item>
- <item msgid="3455047468583965104">"カスタム"</item>
+ <item>"仕事"</item>
+ <item>"ãã®ä»–"</item>
+ <item>"カスタム"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Googleトーク"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Googleトーク"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PINコードを入力"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"PINコードãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"MENUã€0キーã§ãƒ­ãƒƒã‚¯è§£é™¤"</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"緊急通報番å·"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(通信サービスãªã—)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"ç”»é¢ãƒ­ãƒƒã‚¯ä¸­"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"MENUキーã§ãƒ­ãƒƒã‚¯è§£é™¤(ã¾ãŸã¯ç·Šæ€¥é€šå ±)"</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"MENUキーã§ãƒ­ãƒƒã‚¯è§£é™¤"</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"ロックを解除ã™ã‚‹ãƒ‘ターンを入力"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"緊急通報"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"一致ã—ã¾ã—ãŸ"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"充電中(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"充電完了。"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"å……é›»ã—ã¦ãã ã•ã„。"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"SIMカードãŒæŒ¿å…¥ã•ã‚Œã¦ã„ã¾ã›ã‚“"</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"SIMカードãŒæŒ¿å…¥ã•ã‚Œã¦ã„ã¾ã›ã‚“"</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"SIMカードを挿入ã—ã¦ãã ã•ã„。"</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãŒãƒ­ãƒƒã‚¯ã•ã‚Œã¾ã—ãŸ"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIMカードã¯PUKã§ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"ユーザーガイドをå‚ç…§ã™ã‚‹ã‹ã€ãŠå®¢æ§˜ã‚µãƒãƒ¼ãƒˆã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。"</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIMカードã¯ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIMカードã®ãƒ­ãƒƒã‚¯è§£é™¤ä¸­..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"ロック解除ã®ãƒ‘ターンã¯<xliff:g id="NUMBER_0">%d</xliff:g>回ã¨ã‚‚æ­£ã—ã指定ã•ã‚Œã¦ã„ã¾ã›ã‚“。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後ã«ã‚‚ã†ä¸€åº¦æŒ‡å®šã—ã¦ãã ã•ã„。"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"指定ã—ãŸãƒ‘ターンã¯<xliff:g id="NUMBER_0">%d</xliff:g>回ã¨ã‚‚æ­£ã—ãã‚ã‚Šã¾ã›ã‚“。ã‚ã¨<xliff:g id="NUMBER_1">%d</xliff:g>回指定ã«å¤±æ•—ã™ã‚‹ã¨ã€æºå¸¯é›»è©±ã®ãƒ­ãƒƒã‚¯ã®è§£é™¤ã«Googleã¸ã®ãƒ­ã‚°ã‚¤ãƒ³ãŒå¿…è¦ã«ãªã‚Šã¾ã™ã€‚"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒後ã«ã‚‚ã†ä¸€åº¦æŒ‡å®šã—ã¦ãã ã•ã„。"</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g>秒後ã«ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"パターンを忘れãŸå ´åˆ"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"パターンã®ã‚¨ãƒ©ãƒ¼ãŒå¤šã™ãŽã¾ã™"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Googleアカウントã§ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãƒ­ãƒƒã‚¯è§£é™¤"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"ユーザーå (メール)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"パスワード"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ログイン"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ユーザーåã¾ãŸã¯ãƒ‘スワードãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"通知を消去"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"通知ãªã—"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"実行中"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"充電中..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"å……é›»ã—ã¦ãã ã•ã„"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"電池ãŒæ®‹ã‚Šå°‘ãªããªã£ã¦ã„ã¾ã™:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"残é‡<xliff:g id="NUMBER">%d%%</xliff:g>以下"</string>
- <string name="battery_low_why" msgid="7655196144309694753">"ç†ç”±"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"出è·æ™‚試験ãŒå¤±æ•—"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"FACTORY_TESTæ“作ã¯ã€/system/appã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚ŒãŸãƒ‘ッケージã®ã¿ãŒå¯¾è±¡ã§ã™ã€‚"</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"FACTORY_TESTæ“作を行ã†ãƒ‘ッケージã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"å†èµ·å‹•"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"ページ「<xliff:g id="TITLE">%s</xliff:g>ã€ã®è¨˜è¿°:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"ã“ã®ãƒšãƒ¼ã‚¸ã‹ã‚‰ç§»å‹•ã—ã¾ã™ã‹ï¼Ÿ"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"移動ã™ã‚‹å ´åˆã¯[OK]ã€ä»Šã®ãƒšãƒ¼ã‚¸ã«æ®‹ã‚‹å ´åˆã¯[キャンセル]ã‚’é¸æŠžã—ã¦ãã ã•ã„。"</string>
- <string name="save_password_label" msgid="6860261758665825069">"確èª"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"ブラウザã®å±¥æ­´ã¨ãƒ–ックマークを読ã¿å–ã‚‹"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"ブラウザã§ã‚¢ã‚¯ã‚»ã‚¹ã—ãŸã™ã¹ã¦ã®URLãŠã‚ˆã³ãƒ–ラウザã®ã™ã¹ã¦ã®ãƒ–ックマークã®èª­ã¿å–りをアプリケーションã«è¨±å¯ã—ã¾ã™ã€‚"</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"ブラウザã®å±¥æ­´ã¨ãƒ–ックマークを書ã込む"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"æºå¸¯é›»è©±ã«ä¿å­˜ã•ã‚Œã¦ã„るブラウザã®å±¥æ­´ã‚„ブックマークã®ä¿®æ­£ã‚’アプリケーショã«è¨±å¯ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šæ‚ªæ„ã®ã‚るアプリケーションãŒã€ãƒ–ラウザã®ãƒ‡ãƒ¼ã‚¿ã‚’消去ã¾ãŸã¯å¤‰æ›´ã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="save_password_message" msgid="767344687139195790">"ã“ã®ãƒ‘スワードをブラウザã§ä¿å­˜ã—ã¾ã™ã‹ï¼Ÿ"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"今ã¯ä¿å­˜ã—ãªã„"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"ä¿å­˜"</string>
- <string name="save_password_never" msgid="8274330296785855105">"ä¿å­˜ã—ãªã„"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"ã“ã®ãƒšãƒ¼ã‚¸ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“。"</string>
- <string name="text_copied" msgid="4985729524670131385">"テキストをクリップボードã«ã‚³ãƒ”ーã—ã¾ã—ãŸã€‚"</string>
- <string name="more_item_label" msgid="4650918923083320495">"ãã®ä»–"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"MENU+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"Space"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"Del"</string>
- <string name="search_go" msgid="8298016669822141719">"検索"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1ã‹æœˆå‰"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1ã‹æœˆå‰"</string>
+ <string name="keyguard_password_enter_pin_code">"PINコードを入力"</string>
+ <string name="keyguard_password_wrong_pin_code">"PINコードãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="keyguard_label_text">"MENUã€0キーã§ãƒ­ãƒƒã‚¯è§£é™¤"</string>
+ <string name="emergency_call_dialog_number_for_display">"緊急通報番å·"</string>
+ <string name="lockscreen_carrier_default">"(通信サービスãªã—)"</string>
+ <string name="lockscreen_screen_locked">"ç”»é¢ãƒ­ãƒƒã‚¯ä¸­"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"MENUキーã§ãƒ­ãƒƒã‚¯è§£é™¤(ã¾ãŸã¯ç·Šæ€¥é€šå ±)"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"MENUキーã§ãƒ­ãƒƒã‚¯è§£é™¤"</string>
+ <string name="lockscreen_pattern_instructions">"ロックを解除ã™ã‚‹ãƒ‘ターンを入力"</string>
+ <string name="lockscreen_emergency_call">"緊急通報"</string>
+ <string name="lockscreen_pattern_correct">"一致ã—ã¾ã—ãŸ"</string>
+ <string name="lockscreen_pattern_wrong">"ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„"</string>
+ <string name="lockscreen_plugged_in">"充電中(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"å……é›»ã—ã¦ãã ã•ã„。"</string>
+ <string name="lockscreen_missing_sim_message_short">"SIMカードãŒæŒ¿å…¥ã•ã‚Œã¦ã„ã¾ã›ã‚“"</string>
+ <string name="lockscreen_missing_sim_message">"SIMカードãŒæŒ¿å…¥ã•ã‚Œã¦ã„ã¾ã›ã‚“"</string>
+ <string name="lockscreen_missing_sim_instructions">"SIMカードを挿入ã—ã¦ãã ã•ã„。"</string>
+ <string name="lockscreen_network_locked_message">"ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãŒãƒ­ãƒƒã‚¯ã•ã‚Œã¾ã—ãŸ"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIMカードã¯PUKã§ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"ユーザーガイドをå‚ç…§ã™ã‚‹ã‹ã€ãŠå®¢æ§˜ã‚µãƒãƒ¼ãƒˆã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。"</string>
+ <string name="lockscreen_sim_locked_message">"SIMカードã¯ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™ã€‚"</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIMカードã®ãƒ­ãƒƒã‚¯è§£é™¤ä¸­..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"ロック解除ã®ãƒ‘ターンã¯<xliff:g id="NUMBER_0">%d</xliff:g>回ã¨ã‚‚æ­£ã—ã指定ã•ã‚Œã¦ã„ã¾ã›ã‚“。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後ã«ã‚‚ã†ä¸€åº¦æŒ‡å®šã—ã¦ãã ã•ã„。"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"指定ã—ãŸãƒ‘ターンã¯<xliff:g id="NUMBER_0">%d</xliff:g>回ã¨ã‚‚æ­£ã—ãã‚ã‚Šã¾ã›ã‚“。ã‚ã¨<xliff:g id="NUMBER_1">%d</xliff:g>回指定ã«å¤±æ•—ã™ã‚‹ã¨ã€æºå¸¯é›»è©±ã®ãƒ­ãƒƒã‚¯ã®è§£é™¤ã«Googleã¸ã®ãƒ­ã‚°ã‚¤ãƒ³ãŒå¿…è¦ã«ãªã‚Šã¾ã™ã€‚"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒後ã«ã‚‚ã†ä¸€åº¦æŒ‡å®šã—ã¦ãã ã•ã„。"</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g>秒後ã«ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"</string>
+ <string name="lockscreen_forgot_pattern_button_text">"パターンを忘れãŸå ´åˆ"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"パターンã®ã‚¨ãƒ©ãƒ¼ãŒå¤šã™ãŽã¾ã™"</string>
+ <string name="lockscreen_glogin_instructions">"Googleアカウントã§ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãƒ­ãƒƒã‚¯è§£é™¤"</string>
+ <string name="lockscreen_glogin_username_hint">"ユーザーå (メール)"</string>
+ <string name="lockscreen_glogin_password_hint">"パスワード"</string>
+ <string name="lockscreen_glogin_submit_button">"ログイン"</string>
+ <string name="lockscreen_glogin_invalid_input">"ユーザーåã¾ãŸã¯ãƒ‘スワードãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"通知ãªã—"</string>
+ <string name="status_bar_ongoing_events_title">"実行中"</string>
+ <string name="status_bar_latest_events_title">"通知"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"充電中..."</string>
+ <string name="battery_low_title">"å……é›»ã—ã¦ãã ã•ã„"</string>
+ <string name="battery_low_subtitle">"電池ãŒæ®‹ã‚Šå°‘ãªããªã£ã¦ã„ã¾ã™:"</string>
+ <string name="battery_low_percent_format">"残é‡<xliff:g id="NUMBER">%d%%</xliff:g>以下"</string>
+ <!-- no translation found for battery_low_why (7655196144309694753) -->
+ <skip />
+ <string name="factorytest_failed">"出è·æ™‚試験ãŒå¤±æ•—"</string>
+ <string name="factorytest_not_system">"FACTORY_TESTæ“作ã¯ã€/system/appã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚ŒãŸãƒ‘ッケージã®ã¿ãŒå¯¾è±¡ã§ã™ã€‚"</string>
+ <string name="factorytest_no_action">"FACTORY_TESTæ“作を行ã†ãƒ‘ッケージã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"</string>
+ <string name="factorytest_reboot">"å†èµ·å‹•"</string>
+ <string name="js_dialog_title">"ページ「<xliff:g id="TITLE">%s</xliff:g>ã€ã®è¨˜è¿°:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"ã“ã®ãƒšãƒ¼ã‚¸ã‹ã‚‰ç§»å‹•ã—ã¾ã™ã‹ï¼Ÿ"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"移動ã™ã‚‹å ´åˆã¯[OK]ã€ä»Šã®ãƒšãƒ¼ã‚¸ã«æ®‹ã‚‹å ´åˆã¯[キャンセル]ã‚’é¸æŠžã—ã¦ãã ã•ã„。"</string>
+ <string name="save_password_label">"確èª"</string>
+ <!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
+ <skip />
+ <!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
+ <skip />
+ <!-- no translation found for permlab_writeHistoryBookmarks (9009434109836280374) -->
+ <skip />
+ <!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
+ <skip />
+ <string name="save_password_message">"ã“ã®ãƒ‘スワードをブラウザã§ä¿å­˜ã—ã¾ã™ã‹ï¼Ÿ"</string>
+ <string name="save_password_notnow">"今ã¯ä¿å­˜ã—ãªã„"</string>
+ <string name="save_password_remember">"ä¿å­˜"</string>
+ <string name="save_password_never">"ä¿å­˜ã—ãªã„"</string>
+ <string name="open_permission_deny">"ã“ã®ãƒšãƒ¼ã‚¸ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“。"</string>
+ <string name="text_copied">"テキストをクリップボードã«ã‚³ãƒ”ーã—ã¾ã—ãŸã€‚"</string>
+ <string name="more_item_label">"ãã®ä»–"</string>
+ <string name="prepend_shortcut_label">"MENU+"</string>
+ <string name="menu_space_shortcut_label">"Space"</string>
+ <string name="menu_enter_shortcut_label">"Enter"</string>
+ <string name="menu_delete_shortcut_label">"Del"</string>
+ <string name="search_go">"検索"</string>
+ <string name="oneMonthDurationPast">"1ã‹æœˆå‰"</string>
+ <string name="beforeOneMonthDurationPast">"1ã‹æœˆå‰"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1秒å‰"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>秒å‰"</item>
+ <item quantity="one">"1秒å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒å‰"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1分å‰"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>分å‰"</item>
+ <item quantity="one">"1分å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分å‰"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1時間å‰"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>時間å‰"</item>
+ <item quantity="one">"1時間å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間å‰"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"昨日"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>æ—¥å‰"</item>
+ <item quantity="one">"昨日"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>æ—¥å‰"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1秒後"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
+ <item quantity="one">"1秒後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1分後"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
+ <item quantity="one">"1分後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1時間後"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
+ <item quantity="one">"1時間後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"明日"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
+ <item quantity="one">"明日"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1秒å‰"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>秒å‰"</item>
+ <item quantity="one">"1秒å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒å‰"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1分å‰"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>分å‰"</item>
+ <item quantity="one">"1分å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分å‰"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1時間å‰"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>時間å‰"</item>
+ <item quantity="one">"1時間å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間å‰"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"昨日"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>æ—¥å‰"</item>
+ <item quantity="one">"昨日"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>æ—¥å‰"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1秒後"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
+ <item quantity="one">"1秒後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1分後"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
+ <item quantity="one">"1分後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1時間後"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
+ <item quantity="one">"1時間後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"明日"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
+ <item quantity="one">"明日"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%så¹´"</string>
- <string name="day" msgid="8144195776058119424">"æ—¥"</string>
- <string name="days" msgid="4774547661021344602">"æ—¥"</string>
- <string name="hour" msgid="2126771916426189481">"時間"</string>
- <string name="hours" msgid="894424005266852993">"時間"</string>
- <string name="minute" msgid="9148878657703769868">"分"</string>
- <string name="minutes" msgid="5646001005827034509">"分"</string>
- <string name="second" msgid="3184235808021478">"秒"</string>
- <string name="seconds" msgid="3161515347216589235">"秒"</string>
- <string name="week" msgid="5617961537173061583">"週間"</string>
- <string name="weeks" msgid="6509623834583944518">"週間"</string>
- <string name="year" msgid="4001118221013892076">"å¹´"</string>
- <string name="years" msgid="6881577717993213522">"å¹´"</string>
- <string name="every_weekday" msgid="8777593878457748503">"平日(月~金)"</string>
- <string name="daily" msgid="5738949095624133403">"毎日"</string>
- <string name="weekly" msgid="983428358394268344">"毎週<xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"毎月"</string>
- <string name="yearly" msgid="1519577999407493836">"毎年"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"動画をå†ç”Ÿã§ãã¾ã›ã‚“"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"ã“ã®å‹•ç”»ã¯ã”使用ã®ç«¯æœ«ã§ã‚¹ãƒˆãƒªãƒ¼ãƒŸãƒ³ã‚°ã§ãã¾ã›ã‚“。"</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"ã“ã®å‹•ç”»ã¯å†ç”Ÿã§ãã¾ã›ã‚“。"</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"æ­£åˆ"</string>
- <string name="Noon" msgid="3342127745230013127">"æ­£åˆ"</string>
- <string name="midnight" msgid="7166259508850457595">"åˆå‰0時"</string>
- <string name="Midnight" msgid="5630806906897892201">"åˆå‰0時"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"ã™ã¹ã¦é¸æŠž"</string>
- <string name="selectText" msgid="3889149123626888637">"テキストをé¸æŠž"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"テキストã®é¸æŠžã‚’終了"</string>
- <string name="cut" msgid="3092569408438626261">"切りå–ã‚Š"</string>
- <string name="cutAll" msgid="2436383270024931639">"ã™ã¹ã¦åˆ‡ã‚Šå–ã‚Š"</string>
- <string name="copy" msgid="2681946229533511987">"コピー"</string>
- <string name="copyAll" msgid="2590829068100113057">"ã™ã¹ã¦ã‚³ãƒ”ー"</string>
- <string name="paste" msgid="5629880836805036433">"貼り付ã‘"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URLをコピー"</string>
- <string name="inputMethod" msgid="7673923508389094672">"入力方法"</string>
- <string name="addToDictionary" msgid="726256909274177272">"辞書ã«ã€Œ%sã€ã‚’追加"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"テキストを編集"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"空ã容é‡ä½Žä¸‹"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"æºå¸¯é›»è©±ã®ç©ºã容é‡ãŒå°‘ãªããªã£ã¦ã„ã¾ã™ã€‚"</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"キャンセル"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"キャンセル"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"注æ„"</string>
- <string name="capital_on" msgid="1544682755514494298">"ON"</string>
- <string name="capital_off" msgid="6815870386972805832">"OFF"</string>
- <string name="whichApplication" msgid="4533185947064773386">"アプリケーションをé¸æŠž"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"常ã«ã“ã®æ“作ã§ä½¿ç”¨ã™ã‚‹"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"ホームã®[設定]&gt;[アプリケーション]&gt;[アプリケーションã®ç®¡ç†]ã§ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆè¨­å®šã‚’クリアã—ã¾ã™ã€‚"</string>
- <string name="chooseActivity" msgid="1009246475582238425">"æ“作ã®é¸æŠž"</string>
- <string name="noApplications" msgid="1691104391758345586">"ã“ã®æ“作を実行ã§ãるアプリケーションã¯ã‚ã‚Šã¾ã›ã‚“。"</string>
- <string name="aerr_title" msgid="653922989522758100">"エラー"</string>
- <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)ãŒäºˆæœŸã›ãšåœæ­¢ã—ã¾ã—ãŸã€‚ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"</string>
- <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g>ãŒäºˆæœŸã›ãšåœæ­¢ã—ã¾ã—ãŸã€‚ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"</string>
- <string name="anr_title" msgid="3100070910664756057">"エラー"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="ACTIVITY">%1$s</xliff:g>(<xliff:g id="APPLICATION">%2$s</xliff:g>)ã¯å¿œç­”ã—ã¦ã„ã¾ã›ã‚“。"</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g>(プロセス: <xliff:g id="PROCESS">%2$s</xliff:g>)ã¯å¿œç­”ã—ã¦ã„ã¾ã›ã‚“。"</string>
- <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)ã¯å¿œç­”ã—ã¦ã„ã¾ã›ã‚“。"</string>
- <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g>ã¯å¿œç­”ã—ã¦ã„ã¾ã›ã‚“。"</string>
- <string name="force_close" msgid="3653416315450806396">"強制終了"</string>
- <string name="report" msgid="4060218260984795706">"レãƒãƒ¼ãƒˆ"</string>
- <string name="wait" msgid="7147118217226317732">"å¾…æ©Ÿ"</string>
- <string name="debug" msgid="9103374629678531849">"デãƒãƒƒã‚°"</string>
- <string name="sendText" msgid="5132506121645618310">"アプリケーションをé¸æŠž"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"ç€ä¿¡éŸ³é‡"</string>
- <string name="volume_music" msgid="5421651157138628171">"メディアã®éŸ³é‡"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Bluetooth経由ã§å†ç”Ÿä¸­ã§ã™"</string>
- <string name="volume_call" msgid="3941680041282788711">"通話音é‡"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetoothç€ä¿¡éŸ³é‡"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"アラームã®éŸ³é‡"</string>
- <string name="volume_notification" msgid="2422265656744276715">"通知音é‡"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"音é‡"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"プリセットç€ä¿¡éŸ³"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"端末ã®åŸºæœ¬ç€ä¿¡éŸ³ï¼ˆ<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"サイレント"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"ç€ä¿¡éŸ³"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"ä¸æ˜Žãªç€ä¿¡éŸ³"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"%så¹´"</string>
+ <string name="day">"æ—¥"</string>
+ <string name="days">"æ—¥"</string>
+ <string name="hour">"時間"</string>
+ <string name="hours">"時間"</string>
+ <string name="minute">"分"</string>
+ <string name="minutes">"分"</string>
+ <string name="second">"秒"</string>
+ <string name="seconds">"秒"</string>
+ <string name="week">"週間"</string>
+ <string name="weeks">"週間"</string>
+ <string name="year">"å¹´"</string>
+ <string name="years">"å¹´"</string>
+ <string name="every_weekday">"平日(月~金)"</string>
+ <string name="daily">"毎日"</string>
+ <string name="weekly">"毎週<xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"毎月"</string>
+ <string name="yearly">"毎年"</string>
+ <string name="VideoView_error_title">"動画をå†ç”Ÿã§ãã¾ã›ã‚“"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"ã“ã®å‹•ç”»ã¯ã”使用ã®ç«¯æœ«ã§ã‚¹ãƒˆãƒªãƒ¼ãƒŸãƒ³ã‚°ã§ãã¾ã›ã‚“。"</string>
+ <string name="VideoView_error_text_unknown">"ã“ã®å‹•ç”»ã¯å†ç”Ÿã§ãã¾ã›ã‚“。"</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"æ­£åˆ"</string>
+ <string name="Noon">"æ­£åˆ"</string>
+ <string name="midnight">"åˆå‰0時"</string>
+ <string name="Midnight">"åˆå‰0時"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"ã™ã¹ã¦é¸æŠž"</string>
+ <string name="selectText">"テキストをé¸æŠž"</string>
+ <string name="stopSelectingText">"テキストã®é¸æŠžã‚’終了"</string>
+ <string name="cut">"切りå–ã‚Š"</string>
+ <string name="cutAll">"ã™ã¹ã¦åˆ‡ã‚Šå–ã‚Š"</string>
+ <string name="copy">"コピー"</string>
+ <string name="copyAll">"ã™ã¹ã¦ã‚³ãƒ”ー"</string>
+ <string name="paste">"貼り付ã‘"</string>
+ <string name="copyUrl">"URLをコピー"</string>
+ <string name="inputMethod">"入力方法"</string>
+ <string name="addToDictionary">"辞書ã«ã€Œ%sã€ã‚’追加"</string>
+ <string name="editTextMenuTitle">"テキストを編集"</string>
+ <string name="low_internal_storage_view_title">"空ã容é‡ä½Žä¸‹"</string>
+ <string name="low_internal_storage_view_text">"æºå¸¯é›»è©±ã®ç©ºã容é‡ãŒå°‘ãªããªã£ã¦ã„ã¾ã™ã€‚"</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"キャンセル"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"キャンセル"</string>
+ <string name="dialog_alert_title">"注æ„"</string>
+ <string name="capital_on">"ON"</string>
+ <string name="capital_off">"OFF"</string>
+ <string name="whichApplication">"アプリケーションをé¸æŠž"</string>
+ <string name="alwaysUse">"常ã«ã“ã®æ“作ã§ä½¿ç”¨ã™ã‚‹"</string>
+ <string name="clearDefaultHintMsg">"ホームã®[設定]&gt;[アプリケーション]&gt;[アプリケーションã®ç®¡ç†]ã§ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆè¨­å®šã‚’クリアã—ã¾ã™ã€‚"</string>
+ <string name="chooseActivity">"æ“作ã®é¸æŠž"</string>
+ <string name="noApplications">"ã“ã®æ“作を実行ã§ãるアプリケーションã¯ã‚ã‚Šã¾ã›ã‚“。"</string>
+ <string name="aerr_title">"エラー"</string>
+ <string name="aerr_application">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)ãŒäºˆæœŸã›ãšåœæ­¢ã—ã¾ã—ãŸã€‚ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"</string>
+ <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>ãŒäºˆæœŸã›ãšåœæ­¢ã—ã¾ã—ãŸã€‚ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"</string>
+ <string name="anr_title">"エラー"</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g>(<xliff:g id="APPLICATION">%2$s</xliff:g>)ã¯å¿œç­”ã—ã¦ã„ã¾ã›ã‚“。"</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g>(プロセス: <xliff:g id="PROCESS">%2$s</xliff:g>)ã¯å¿œç­”ã—ã¦ã„ã¾ã›ã‚“。"</string>
+ <string name="anr_application_process">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)ã¯å¿œç­”ã—ã¦ã„ã¾ã›ã‚“。"</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>ã¯å¿œç­”ã—ã¦ã„ã¾ã›ã‚“。"</string>
+ <string name="force_close">"強制終了"</string>
+ <!-- no translation found for report (4060218260984795706) -->
+ <skip />
+ <string name="wait">"å¾…æ©Ÿ"</string>
+ <string name="debug">"デãƒãƒƒã‚°"</string>
+ <string name="sendText">"アプリケーションをé¸æŠž"</string>
+ <string name="volume_ringtone">"ç€ä¿¡éŸ³é‡"</string>
+ <string name="volume_music">"メディアã®éŸ³é‡"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Bluetooth経由ã§å†ç”Ÿä¸­ã§ã™"</string>
+ <string name="volume_call">"通話音é‡"</string>
+ <string name="volume_bluetooth_call">"Bluetoothç€ä¿¡éŸ³é‡"</string>
+ <string name="volume_alarm">"アラームã®éŸ³é‡"</string>
+ <string name="volume_notification">"通知音é‡"</string>
+ <string name="volume_unknown">"音é‡"</string>
+ <string name="ringtone_default">"プリセットç€ä¿¡éŸ³"</string>
+ <string name="ringtone_default_with_actual">"端末ã®åŸºæœ¬ç€ä¿¡éŸ³ï¼ˆ<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"サイレント"</string>
+ <string name="ringtone_picker_title">"ç€ä¿¡éŸ³"</string>
+ <string name="ringtone_unknown">"ä¸æ˜Žãªç€ä¿¡éŸ³"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fiを利用ã§ãã¾ã™"</item>
- <item quantity="other" msgid="4192424489168397386">"Wi-Fiを利用ã§ãã¾ã™"</item>
+ <item quantity="one">"Wi-Fiを利用ã§ãã¾ã™"</item>
+ <item quantity="other">"Wi-Fiを利用ã§ãã¾ã™"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Wi-Fiオープンãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãŒåˆ©ç”¨ã§ãã¾ã™"</item>
- <item quantity="other" msgid="7915895323644292768">"Wi-Fiオープンãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãŒåˆ©ç”¨ã§ãã¾ã™"</item>
+ <item quantity="one">"Wi-Fiオープンãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãŒåˆ©ç”¨ã§ãã¾ã™"</item>
+ <item quantity="other">"Wi-Fiオープンãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãŒåˆ©ç”¨ã§ãã¾ã™"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"文字を挿入"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"ä¸æ˜Žãªã‚¢ãƒ—リケーション"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"SMSメッセージã®é€ä¿¡ä¸­"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"大é‡ã®SMSメッセージをé€ä¿¡ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚[OK]ã§é€ä¿¡ã€[キャンセル]ã§ä¸­æ­¢ã—ã¾ã™ã€‚"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"キャンセル"</string>
- <string name="date_time_set" msgid="5777075614321087758">"設定"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"端末既定"</string>
- <string name="no_permissions" msgid="7283357728219338112">"権é™ä»˜ä¸Žã®å¿…è¦ã¯ã‚ã‚Šã¾ã›ã‚“"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"éš ã™"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"ã™ã¹ã¦è¡¨ç¤º"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"読ã¿è¾¼ã¿ä¸­..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB接続"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"USB経由ã§æºå¸¯é›»è©±ã‚’コンピュータã«æŽ¥ç¶šã—ã¾ã—ãŸã€‚コンピュータã¨æºå¸¯é›»è©±ã®SDカード間ã§ãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピーã™ã‚‹ã«ã¯ã€[マウント]ã‚’é¸æŠžã—ã¾ã™ã€‚"</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"マウント"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"マウントã—ãªã„"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"USBメモリã«SDカードを使用ã™ã‚‹éš›ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB接続"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"パソコンã¨ã®é–“ã§ãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピーã—ã¾ã™ã€‚"</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USBストレージをOFFã«ã™ã‚‹"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"USBストレージをOFFã«ã™ã‚‹å ´åˆã«é¸æŠžã—ã¾ã™ã€‚"</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"USBストレージをOFFã«ã™ã‚‹"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"USBストレージをOFFã«ã™ã‚‹å‰ã«USBホストã®ãƒžã‚¦ãƒ³ãƒˆã‚’解除ã—ãŸã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。USBストレージをOFFã«ã™ã‚‹ã«ã¯[OFF]ã‚’é¸æŠžã—ã¾ã™ã€‚"</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"OFF"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"キャンセル"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"USBストレージをOFFã«ã™ã‚‹éš›ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚USBホストã®ãƒžã‚¦ãƒ³ãƒˆãŒè§£é™¤ã•ã‚Œã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¦ã‹ã‚‰ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。"</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"SDカードをフォーマット"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"SDカードをフォーマットã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿã‚«ãƒ¼ãƒ‰å†…ã®ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãŒå¤±ã‚ã‚Œã¾ã™ã€‚"</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"フォーマット"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USBデãƒãƒƒã‚°ãŒæŽ¥ç¶šã•ã‚Œã¾ã—ãŸ"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"コンピュータãŒæºå¸¯ã«æŽ¥ç¶šã•ã‚Œã¾ã—ãŸã€‚"</string>
- <string name="select_input_method" msgid="2086499663193509436">"入力方法ã®é¸æŠž"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SDカードã®æº–備中"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"エラーを確èªã—ã¦ã„ã¾ã™ã€‚"</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"空ã®SDカード"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"SDカードãŒç©ºã‹ã€ã‚µãƒãƒ¼ãƒˆå¯¾è±¡å¤–ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚·ã‚¹ãƒ†ãƒ ã‚’使用ã—ã¦ã„ã¾ã™ã€‚"</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"ç ´æã—ãŸSDカード"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"SDカードãŒç ´æã—ã¦ã„ã¾ã™ã€‚カードã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆãŒå¿…è¦ãªå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚"</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SDカードãŒäºˆæœŸã›ãšå–り外ã•ã‚Œã¾ã—ãŸ"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"データã®å–ªå¤±ã‚’防ããŸã‚SDカードをå–り外ã™å‰ã«ãƒžã‚¦ãƒ³ãƒˆã‚’解除ã—ã¦ãã ã•ã„。"</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SDカードを安全ã«å–り外ã—ã¾ã—ãŸ"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"SDカードã¯å®‰å…¨ã«å–り外ã›ã¾ã™ã€‚"</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SDカードãŒå–り外ã•ã‚Œã¦ã„ã¾ã™"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"SDカードãŒå–り外ã•ã‚Œã¾ã—ãŸã€‚æ–°ã—ã„カードを挿入ã—ã¦ãã ã•ã„。"</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"一致ã™ã‚‹ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"コンãƒãƒ¼ãƒãƒ³ãƒˆä½¿ç”¨çŠ¶æ³ã«é–¢ã™ã‚‹çµ±è¨ˆæƒ…å ±ã®æ›´æ–°"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"åŽé›†ã•ã‚ŒãŸã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆä½¿ç”¨çŠ¶æ³ã«é–¢ã™ã‚‹çµ±è¨ˆæƒ…å ±ã®å¤‰æ›´ã‚’許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ダブルタップã§ã‚ºãƒ¼ãƒ ã—ã¾ã™"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"ウィジェットã®å±•é–‹ã‚¨ãƒ©ãƒ¼"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"移動"</string>
- <string name="ime_action_search" msgid="658110271822807811">"検索"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"é€ä¿¡"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"次ã¸"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"完了"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"実行"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g>を使ã£ã¦"\n"発信"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>を使ã£ã¦"\n"連絡先を新è¦ç™»éŒ²"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"オン"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"オフ"</string>
+ <string name="select_character">"文字を挿入"</string>
+ <string name="sms_control_default_app_name">"ä¸æ˜Žãªã‚¢ãƒ—リケーション"</string>
+ <string name="sms_control_title">"SMSメッセージã®é€ä¿¡ä¸­"</string>
+ <string name="sms_control_message">"大é‡ã®SMSメッセージをé€ä¿¡ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚[OK]ã§é€ä¿¡ã€[キャンセル]ã§ä¸­æ­¢ã—ã¾ã™ã€‚"</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"キャンセル"</string>
+ <string name="date_time_set">"設定"</string>
+ <string name="default_permission_group">"端末既定"</string>
+ <string name="no_permissions">"権é™ä»˜ä¸Žã®å¿…è¦ã¯ã‚ã‚Šã¾ã›ã‚“"</string>
+ <string name="perms_hide"><b>"éš ã™"</b></string>
+ <string name="perms_show_all"><b>"ã™ã¹ã¦è¡¨ç¤º"</b></string>
+ <string name="googlewebcontenthelper_loading">"読ã¿è¾¼ã¿ä¸­..."</string>
+ <string name="usb_storage_title">"USB接続"</string>
+ <string name="usb_storage_message">"USB経由ã§æºå¸¯é›»è©±ã‚’コンピュータã«æŽ¥ç¶šã—ã¾ã—ãŸã€‚コンピュータã¨æºå¸¯é›»è©±ã®SDカード間ã§ãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピーã™ã‚‹ã«ã¯ã€[マウント]ã‚’é¸æŠžã—ã¾ã™ã€‚"</string>
+ <string name="usb_storage_button_mount">"マウント"</string>
+ <string name="usb_storage_button_unmount">"マウントã—ãªã„"</string>
+ <string name="usb_storage_error_message">"USBメモリã«SDカードを使用ã™ã‚‹éš›ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"</string>
+ <string name="usb_storage_notification_title">"USB接続"</string>
+ <string name="usb_storage_notification_message">"パソコンã¨ã®é–“ã§ãƒ•ã‚¡ã‚¤ãƒ«ã‚’コピーã—ã¾ã™ã€‚"</string>
+ <string name="usb_storage_stop_notification_title">"USBストレージをOFFã«ã™ã‚‹"</string>
+ <string name="usb_storage_stop_notification_message">"USBストレージをOFFã«ã™ã‚‹å ´åˆã«é¸æŠžã—ã¾ã™ã€‚"</string>
+ <string name="usb_storage_stop_title">"USBストレージをOFFã«ã™ã‚‹"</string>
+ <string name="usb_storage_stop_message">"USBストレージをOFFã«ã™ã‚‹å‰ã«USBホストã®ãƒžã‚¦ãƒ³ãƒˆã‚’解除ã—ãŸã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。USBストレージをOFFã«ã™ã‚‹ã«ã¯[OFF]ã‚’é¸æŠžã—ã¾ã™ã€‚"</string>
+ <string name="usb_storage_stop_button_mount">"OFF"</string>
+ <string name="usb_storage_stop_button_unmount">"キャンセル"</string>
+ <string name="usb_storage_stop_error_message">"USBストレージをOFFã«ã™ã‚‹éš›ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚USBホストã®ãƒžã‚¦ãƒ³ãƒˆãŒè§£é™¤ã•ã‚Œã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¦ã‹ã‚‰ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。"</string>
+ <string name="extmedia_format_title">"SDカードをフォーマット"</string>
+ <string name="extmedia_format_message">"SDカードをフォーマットã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿã‚«ãƒ¼ãƒ‰å†…ã®ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãŒå¤±ã‚ã‚Œã¾ã™ã€‚"</string>
+ <string name="extmedia_format_button_format">"フォーマット"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"入力方法ã®é¸æŠž"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"候補"</u></string>
+ <string name="ext_media_checking_notification_title">"SDカードã®æº–備中"</string>
+ <!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
+ <skip />
+ <string name="ext_media_nofs_notification_title">"空ã®SDカード"</string>
+ <!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
+ <skip />
+ <string name="ext_media_unmountable_notification_title">"ç ´æã—ãŸSDカード"</string>
+ <!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
+ <skip />
+ <string name="ext_media_badremoval_notification_title">"SDカードãŒäºˆæœŸã›ãšå–り外ã•ã‚Œã¾ã—ãŸ"</string>
+ <string name="ext_media_badremoval_notification_message">"データã®å–ªå¤±ã‚’防ããŸã‚SDカードをå–り外ã™å‰ã«ãƒžã‚¦ãƒ³ãƒˆã‚’解除ã—ã¦ãã ã•ã„。"</string>
+ <string name="ext_media_safe_unmount_notification_title">"SDカードを安全ã«å–り外ã—ã¾ã—ãŸ"</string>
+ <!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
+ <skip />
+ <string name="ext_media_nomedia_notification_title">"SDカードãŒå–り外ã•ã‚Œã¦ã„ã¾ã™"</string>
+ <!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
+ <skip />
+ <string name="activity_list_empty">"一致ã™ã‚‹ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"</string>
+ <string name="permlab_pkgUsageStats">"コンãƒãƒ¼ãƒãƒ³ãƒˆä½¿ç”¨çŠ¶æ³ã«é–¢ã™ã‚‹çµ±è¨ˆæƒ…å ±ã®æ›´æ–°"</string>
+ <string name="permdesc_pkgUsageStats">"åŽé›†ã•ã‚ŒãŸã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆä½¿ç”¨çŠ¶æ³ã«é–¢ã™ã‚‹çµ±è¨ˆæƒ…å ±ã®å¤‰æ›´ã‚’許å¯ã—ã¾ã™ã€‚通常ã®ã‚¢ãƒ—リケーションã§ã¯ä½¿ç”¨ã—ã¾ã›ã‚“。"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"ダブルタップã§ã‚ºãƒ¼ãƒ ã—ã¾ã™"</string>
+ <string name="gadget_host_error_inflating">"ウィジェットã®å±•é–‹ã‚¨ãƒ©ãƒ¼"</string>
+ <string name="ime_action_go">"移動"</string>
+ <string name="ime_action_search">"検索"</string>
+ <string name="ime_action_send">"é€ä¿¡"</string>
+ <string name="ime_action_next">"次ã¸"</string>
+ <string name="ime_action_done">"完了"</string>
+ <string name="ime_action_default">"実行"</string>
+ <string name="dial_number_using">"<xliff:g id="NUMBER">%s</xliff:g>を使ã£ã¦"\n"発信"</string>
+ <string name="create_contact_using">"<xliff:g id="NUMBER">%s</xliff:g>を使ã£ã¦"\n"連絡先を新è¦ç™»éŒ²"</string>
+ <!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
+ <skip />
+ <!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 2e85a10..c3a9c70 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"&lt;제목없ìŒ&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(전화번호 ì—†ìŒ)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(ì•Œ 수 ì—†ìŒ)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ìŒì„±ë©”ì¼"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"ì—°ê²°ì— ë¬¸ì œê°€ 있거나 MMI 코드가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"서비스를 사용하ë„ë¡ ì„¤ì •í–ˆìŠµë‹ˆë‹¤."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"사용 ì„¤ì •ëœ ì„œë¹„ìŠ¤ 목ë¡:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"서비스가 사용 중지ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"등ë¡ì´ 완료ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="serviceErased" msgid="1288584695297200972">"삭제했습니다."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"비밀번호가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI 완료"</string>
- <string name="badPin" msgid="5085454289896032547">"ì´ì „ PINì´ ì˜¬ë°”ë¥´ì§€ 않습니다."</string>
- <string name="badPuk" msgid="5702522162746042460">"입력한 PUK가 올바르지 않습니다."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"입력한 PINì´ ì¼ì¹˜í•˜ì§€ 않습니다."</string>
- <string name="invalidPin" msgid="3850018445187475377">"4~ 8ìžë¦¬ 숫ìžë¡œ ëœ PINì„ ìž…ë ¥í•˜ì„¸ìš”."</string>
- <string name="needPuk" msgid="919668385956251611">"SIM ì¹´ë“œì˜ PUKê°€ 잠겨 있습니다. 잠금해제하려면 PUK 코드를 입력하세요."</string>
- <string name="needPuk2" msgid="4526033371987193070">"SIM ì¹´ë“œ ìž ê¸ˆì„ í•´ì œí•˜ë ¤ë©´ PUK2를 입력하세요."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"수신 ë°œì‹ ìž ë²ˆí˜¸"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"발신 ë°œì‹ ìž ë²ˆí˜¸"</string>
- <string name="CfMmi" msgid="5123218989141573515">"착신전환"</string>
- <string name="CwMmi" msgid="9129678056795016867">"통화중 대기"</string>
- <string name="BaMmi" msgid="455193067926770581">"착발신 제한"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"비밀번호 변경"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN 변경"</string>
+ <string name="untitled">"&lt;제목없ìŒ&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(전화번호 ì—†ìŒ)"</string>
+ <string name="unknownName">"(ì•Œ 수 ì—†ìŒ)"</string>
+ <string name="defaultVoiceMailAlphaTag">"ìŒì„±ë©”ì¼"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"ì—°ê²°ì— ë¬¸ì œê°€ 있거나 MMI 코드가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="serviceEnabled">"서비스를 사용하ë„ë¡ ì„¤ì •í–ˆìŠµë‹ˆë‹¤."</string>
+ <string name="serviceEnabledFor">"사용 ì„¤ì •ëœ ì„œë¹„ìŠ¤ 목ë¡:"</string>
+ <string name="serviceDisabled">"서비스가 사용 중지ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="serviceRegistered">"등ë¡ì´ 완료ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="serviceErased">"삭제했습니다."</string>
+ <string name="passwordIncorrect">"비밀번호가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="mmiComplete">"MMI 완료"</string>
+ <string name="badPin">"ì´ì „ PINì´ ì˜¬ë°”ë¥´ì§€ 않습니다."</string>
+ <string name="badPuk">"입력한 PUK가 올바르지 않습니다."</string>
+ <string name="mismatchPin">"입력한 PINì´ ì¼ì¹˜í•˜ì§€ 않습니다."</string>
+ <string name="invalidPin">"4~ 8ìžë¦¬ 숫ìžë¡œ ëœ PINì„ ìž…ë ¥í•˜ì„¸ìš”."</string>
+ <string name="needPuk">"SIM ì¹´ë“œì˜ PUKê°€ 잠겨 있습니다. 잠금해제하려면 PUK 코드를 입력하세요."</string>
+ <string name="needPuk2">"SIM ì¹´ë“œ ìž ê¸ˆì„ í•´ì œí•˜ë ¤ë©´ PUK2를 입력하세요."</string>
+ <string name="ClipMmi">"수신 ë°œì‹ ìž ë²ˆí˜¸"</string>
+ <string name="ClirMmi">"발신 ë°œì‹ ìž ë²ˆí˜¸"</string>
+ <string name="CfMmi">"착신전환"</string>
+ <string name="CwMmi">"통화중 대기"</string>
+ <string name="BaMmi">"착발신 제한"</string>
+ <string name="PwdMmi">"비밀번호 변경"</string>
+ <string name="PinMmi">"PIN 변경"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ë°œì‹ ìž ë²ˆí˜¸ê°€ 기본ì ìœ¼ë¡œ 제한ë¨ìœ¼ë¡œ 설정ë©ë‹ˆë‹¤. ë‹¤ìŒ í†µí™”: 제한ë¨"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ë°œì‹ ìž ë²ˆí˜¸ê°€ 기본ì ìœ¼ë¡œ 제한ë¨ìœ¼ë¡œ 설정ë©ë‹ˆë‹¤. ë‹¤ìŒ í†µí™”: 제한ë˜ì§€ ì•ŠìŒ"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ë°œì‹ ìž ë²ˆí˜¸ê°€ 기본ì ìœ¼ë¡œ 제한ë˜ì§€ ì•ŠìŒìœ¼ë¡œ 설정ë©ë‹ˆë‹¤. ë‹¤ìŒ í†µí™”: 제한ë¨"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ë°œì‹ ìž ë²ˆí˜¸ê°€ 기본ì ìœ¼ë¡œ 제한ë˜ì§€ ì•ŠìŒìœ¼ë¡œ 설정ë©ë‹ˆë‹¤. ë‹¤ìŒ í†µí™”: 제한ë˜ì§€ ì•ŠìŒ"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"서비스가 준비ë˜ì§€ 않았습니다."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"ë°œì‹ ìž ë²ˆí˜¸ ì„¤ì •ì„ ë³€ê²½í•  수 없습니다."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"ì œí•œëœ ì•¡ì„¸ìŠ¤ê°€ 변경ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"ë°ì´í„° 서비스가 차단ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"긴급 서비스가 차단ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"ìŒì„±/SMS 서비스가 차단ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"모든 ìŒì„±/SMS 서비스가 차단ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"ìŒì„±"</string>
- <string name="serviceClassData" msgid="872456782077937893">"ë°ì´í„°"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"팩스"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"비ë™ê¸°"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"ë™ê¸°í™”"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"패킷"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"ë°œì‹ ìž ë²ˆí˜¸ê°€ 기본ì ìœ¼ë¡œ 제한ë¨ìœ¼ë¡œ 설정ë©ë‹ˆë‹¤. ë‹¤ìŒ í†µí™”: 제한ë¨"</string>
+ <string name="CLIRDefaultOnNextCallOff">"ë°œì‹ ìž ë²ˆí˜¸ê°€ 기본ì ìœ¼ë¡œ 제한ë¨ìœ¼ë¡œ 설정ë©ë‹ˆë‹¤. ë‹¤ìŒ í†µí™”: 제한ë˜ì§€ ì•ŠìŒ"</string>
+ <string name="CLIRDefaultOffNextCallOn">"ë°œì‹ ìž ë²ˆí˜¸ê°€ 기본ì ìœ¼ë¡œ 제한ë˜ì§€ ì•ŠìŒìœ¼ë¡œ 설정ë©ë‹ˆë‹¤. ë‹¤ìŒ í†µí™”: 제한ë¨"</string>
+ <string name="CLIRDefaultOffNextCallOff">"ë°œì‹ ìž ë²ˆí˜¸ê°€ 기본ì ìœ¼ë¡œ 제한ë˜ì§€ ì•ŠìŒìœ¼ë¡œ 설정ë©ë‹ˆë‹¤. ë‹¤ìŒ í†µí™”: 제한ë˜ì§€ ì•ŠìŒ"</string>
+ <string name="serviceNotProvisioned">"서비스가 준비ë˜ì§€ 않았습니다."</string>
+ <string name="CLIRPermanent">"ë°œì‹ ìž ë²ˆí˜¸ ì„¤ì •ì„ ë³€ê²½í•  수 없습니다."</string>
+ <string name="RestrictedChangedTitle">"ì œí•œëœ ì•¡ì„¸ìŠ¤ê°€ 변경ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="RestrictedOnData">"ë°ì´í„° 서비스가 차단ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="RestrictedOnEmergency">"긴급 서비스가 차단ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="RestrictedOnNormal">"ìŒì„±/SMS 서비스가 차단ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="RestrictedOnAll">"모든 ìŒì„±/SMS 서비스가 차단ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="serviceClassVoice">"ìŒì„±"</string>
+ <string name="serviceClassData">"ë°ì´í„°"</string>
+ <string name="serviceClassFAX">"팩스"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"비ë™ê¸°"</string>
+ <string name="serviceClassDataSync">"ë™ê¸°í™”"</string>
+ <string name="serviceClassPacket">"패킷"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안ë¨"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g><xliff:g id="TIME_DELAY">{2}</xliff:g>초 후"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안ë¨"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안ë¨"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안ë¨"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g><xliff:g id="TIME_DELAY">{2}</xliff:g>초 후"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안ë¨"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안ë¨"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"확ì¸"</string>
- <string name="httpError" msgid="2567300624552921790">"웹페ì´ì§€ì— 오류가 있습니다."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"URLì„ ì°¾ì„ ìˆ˜ 없습니다."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"사ì´íŠ¸ ì¸ì¦ 스키마가 지ì›ë˜ì§€ 않습니다."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"ì¸ì¦ì— 실패했습니다."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"프ë¡ì‹œ 서버를 통한 ì¸ì¦ì— 실패했습니다."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"ì„œë²„ì— ì—°ê²°í•˜ì§€ 못했습니다."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"서버와 통신할 수 없습니다. ìž ì‹œ í›„ì— ë‹¤ì‹œ ì‹œë„í•´ 주세요."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"서버 ì—°ê²° ì œí•œì‹œê°„ì´ ì´ˆê³¼ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"페ì´ì§€ì— 서버 ë¦¬ë””ë ‰ì…˜ì´ ë„ˆë¬´ ë§Žì´ í¬í•¨ë˜ì–´ 있습니다."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"지ì›ë˜ì§€ 않는 프로토콜입니다."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"보안 ì—°ê²°ì„ ì„¤ì •í•˜ì§€ 못했습니다."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"URLì´ ì˜¬ë°”ë¥´ì§€ ì•Šì•„ 페ì´ì§€ë¥¼ ì—´ 수 없습니다."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"파ì¼ì— 액세스할 수 없습니다."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"요청한 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"처리 ì¤‘ì¸ ìš”ì²­ì´ ë„ˆë¬´ 많습니다. ìž ì‹œ í›„ì— ë‹¤ì‹œ ì‹œë„í•´ 주세요."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"ë™ê¸°í™”"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ë™ê¸°í™”"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> 삭제가 너무 많습니다."</string>
- <string name="low_memory" msgid="6632412458436461203">"휴대전화 ì €ìž¥ê³µê°„ì´ ê½‰ 찼습니다. ì¼ë¶€ 파ì¼ì„ 삭제하여 저장 여유 ê³µê°„ì„ ëŠ˜ë¦¬ì„¸ìš”."</string>
- <string name="me" msgid="6545696007631404292">"나"</string>
- <string name="power_dialog" msgid="1319919075463988638">"휴대전화 옵션"</string>
- <string name="silent_mode" msgid="7167703389802618663">"ë¬´ìŒ ëª¨ë“œ"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"무선 사용"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"무선 ë„기"</string>
- <string name="screen_lock" msgid="799094655496098153">"화면 잠금"</string>
- <string name="power_off" msgid="4266614107412865048">"ë„기"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"종료 중..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"휴대전화가 종료ë©ë‹ˆë‹¤."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"최신 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì•„ë‹™ë‹ˆë‹¤."</string>
- <string name="global_actions" msgid="2406416831541615258">"휴대전화 옵션"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"화면 잠금"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"ë„기"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"ë¬´ìŒ ëª¨ë“œ"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"소리 꺼ì§"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"소리 켜ì§"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"비행 모드"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"비행 모드 사용"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"비행 모드 사용 안함"</string>
- <string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"ìš”ê¸ˆì´ ë¶€ê³¼ë˜ëŠ” 서비스"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìš”ê¸ˆì´ ë¶€ê³¼ë  ìˆ˜ 있는 ìž‘ì—…ì„ í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"메시지"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"SMS, ì´ë©”ì¼ ë° ê¸°íƒ€ 메시지를 ì½ê³  ì”니다."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"ê°œì¸ì •ë³´"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ì£¼ì†Œë¡ ë° ìº˜ë¦°ë”ì— ì§ì ‘ 액세스합니다."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"위치"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"실제 위치 모니터ë§"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"ë„¤íŠ¸ì›Œí¬ í†µì‹ "</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ì–‘í•œ ë„¤íŠ¸ì›Œí¬ ê¸°ëŠ¥ì— ì•¡ì„¸ìŠ¤í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Google 계정"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"사용 가능한 Google ê³„ì •ì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"하드웨어 제어"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"íœ´ëŒ€ì „í™”ì˜ í•˜ë“œì›¨ì–´ì— ì§ì ‘ 액세스합니다."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"전화 통화"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"ì „í™” 통화를 모니터ë§, ê¸°ë¡ ë° ì²˜ë¦¬í•©ë‹ˆë‹¤."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"시스템 ë„구"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"ì‹œìŠ¤í…œì„ í•˜ìœ„ 수준ì—ì„œ 액세스하고 제어합니다."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"개발 ë„구"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"ì‘용프로그램 개발ìžì—게만 필요한 기능입니다."</string>
+ <string name="httpErrorOk">"확ì¸"</string>
+ <string name="httpError">"웹페ì´ì§€ì— 오류가 있습니다."</string>
+ <string name="httpErrorLookup">"URLì„ ì°¾ì„ ìˆ˜ 없습니다."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"사ì´íŠ¸ ì¸ì¦ 스키마가 지ì›ë˜ì§€ 않습니다."</string>
+ <string name="httpErrorAuth">"ì¸ì¦ì— 실패했습니다."</string>
+ <string name="httpErrorProxyAuth">"프ë¡ì‹œ 서버를 통한 ì¸ì¦ì— 실패했습니다."</string>
+ <string name="httpErrorConnect">"ì„œë²„ì— ì—°ê²°í•˜ì§€ 못했습니다."</string>
+ <string name="httpErrorIO">"서버와 통신할 수 없습니다. ìž ì‹œ í›„ì— ë‹¤ì‹œ ì‹œë„í•´ 주세요."</string>
+ <string name="httpErrorTimeout">"서버 ì—°ê²° ì œí•œì‹œê°„ì´ ì´ˆê³¼ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="httpErrorRedirectLoop">"페ì´ì§€ì— 서버 ë¦¬ë””ë ‰ì…˜ì´ ë„ˆë¬´ ë§Žì´ í¬í•¨ë˜ì–´ 있습니다."</string>
+ <string name="httpErrorUnsupportedScheme">"지ì›ë˜ì§€ 않는 프로토콜입니다."</string>
+ <string name="httpErrorFailedSslHandshake">"보안 ì—°ê²°ì„ ì„¤ì •í•˜ì§€ 못했습니다."</string>
+ <string name="httpErrorBadUrl">"URLì´ ì˜¬ë°”ë¥´ì§€ ì•Šì•„ 페ì´ì§€ë¥¼ ì—´ 수 없습니다."</string>
+ <string name="httpErrorFile">"파ì¼ì— 액세스할 수 없습니다."</string>
+ <string name="httpErrorFileNotFound">"요청한 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다."</string>
+ <string name="httpErrorTooManyRequests">"처리 ì¤‘ì¸ ìš”ì²­ì´ ë„ˆë¬´ 많습니다. ìž ì‹œ í›„ì— ë‹¤ì‹œ ì‹œë„í•´ 주세요."</string>
+ <string name="contentServiceSync">"ë™ê¸°í™”"</string>
+ <string name="contentServiceSyncNotificationTitle">"ë™ê¸°í™”"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> 삭제가 너무 많습니다."</string>
+ <string name="low_memory">"휴대전화 ì €ìž¥ê³µê°„ì´ ê½‰ 찼습니다. ì¼ë¶€ 파ì¼ì„ 삭제하여 저장 여유 ê³µê°„ì„ ëŠ˜ë¦¬ì„¸ìš”."</string>
+ <string name="me">"나"</string>
+ <string name="power_dialog">"휴대전화 옵션"</string>
+ <string name="silent_mode">"ë¬´ìŒ ëª¨ë“œ"</string>
+ <string name="turn_on_radio">"무선 사용"</string>
+ <string name="turn_off_radio">"무선 ë„기"</string>
+ <string name="screen_lock">"화면 잠금"</string>
+ <string name="power_off">"ë„기"</string>
+ <string name="shutdown_progress">"종료 중..."</string>
+ <string name="shutdown_confirm">"휴대전화가 종료ë©ë‹ˆë‹¤."</string>
+ <string name="no_recent_tasks">"최신 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì•„ë‹™ë‹ˆë‹¤."</string>
+ <string name="global_actions">"휴대전화 옵션"</string>
+ <string name="global_action_lock">"화면 잠금"</string>
+ <string name="global_action_power_off">"ë„기"</string>
+ <string name="global_action_toggle_silent_mode">"ë¬´ìŒ ëª¨ë“œ"</string>
+ <string name="global_action_silent_mode_on_status">"소리 꺼ì§"</string>
+ <string name="global_action_silent_mode_off_status">"소리 켜ì§"</string>
+ <string name="global_actions_toggle_airplane_mode">"비행 모드"</string>
+ <string name="global_actions_airplane_mode_on_status">"비행 모드 사용"</string>
+ <string name="global_actions_airplane_mode_off_status">"비행 모드 사용 안함"</string>
+ <string name="safeMode">"안전 모드"</string>
+ <string name="android_system_label">"Android 시스템"</string>
+ <string name="permgrouplab_costMoney">"ìš”ê¸ˆì´ ë¶€ê³¼ë˜ëŠ” 서비스"</string>
+ <string name="permgroupdesc_costMoney">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìš”ê¸ˆì´ ë¶€ê³¼ë  ìˆ˜ 있는 ìž‘ì—…ì„ í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permgrouplab_messages">"메시지"</string>
+ <string name="permgroupdesc_messages">"SMS, ì´ë©”ì¼ ë° ê¸°íƒ€ 메시지를 ì½ê³  ì”니다."</string>
+ <string name="permgrouplab_personalInfo">"ê°œì¸ì •ë³´"</string>
+ <string name="permgroupdesc_personalInfo">"íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ì£¼ì†Œë¡ ë° ìº˜ë¦°ë”ì— ì§ì ‘ 액세스합니다."</string>
+ <string name="permgrouplab_location">"위치"</string>
+ <string name="permgroupdesc_location">"실제 위치 모니터ë§"</string>
+ <string name="permgrouplab_network">"ë„¤íŠ¸ì›Œí¬ í†µì‹ "</string>
+ <string name="permgroupdesc_network">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ì–‘í•œ ë„¤íŠ¸ì›Œí¬ ê¸°ëŠ¥ì— ì•¡ì„¸ìŠ¤í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permgrouplab_accounts">"Google 계정"</string>
+ <string name="permgroupdesc_accounts">"사용 가능한 Google ê³„ì •ì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤."</string>
+ <string name="permgrouplab_hardwareControls">"하드웨어 제어"</string>
+ <string name="permgroupdesc_hardwareControls">"íœ´ëŒ€ì „í™”ì˜ í•˜ë“œì›¨ì–´ì— ì§ì ‘ 액세스합니다."</string>
+ <string name="permgrouplab_phoneCalls">"전화 통화"</string>
+ <string name="permgroupdesc_phoneCalls">"ì „í™” 통화를 모니터ë§, ê¸°ë¡ ë° ì²˜ë¦¬í•©ë‹ˆë‹¤."</string>
+ <string name="permgrouplab_systemTools">"시스템 ë„구"</string>
+ <string name="permgroupdesc_systemTools">"ì‹œìŠ¤í…œì„ í•˜ìœ„ 수준ì—ì„œ 액세스하고 제어합니다."</string>
+ <string name="permgrouplab_developmentTools">"개발 ë„구"</string>
+ <string name="permgroupdesc_developmentTools">"ì‘용프로그램 개발ìžì—게만 필요한 기능입니다."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"ìƒíƒœ 표시줄 사용 중지 ë˜ëŠ” 수정"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìƒíƒœ í‘œì‹œì¤„ì„ ì‚¬ìš© 중지하거나 시스템 ì•„ì´ì½˜ì„ 추가 ë° ì œê±°í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"ìƒíƒœ 표시줄 확장/축소"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìƒíƒœ í‘œì‹œì¤„ì„ í™•ìž¥í•˜ê±°ë‚˜ 축소할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"발신전화 가로채기"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë°œì‹ ì „í™”ë¥¼ 처리하고 전화를 걸 번호를 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë°œì‹ ì „í™”ë¥¼ 모니터ë§í•˜ê±°ë‚˜, 다른 방향으로 ëŒë¦¬ê±°ë‚˜, 중단시킬 수 있습니다."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"SMS 수신"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ SMS 메시지를 받고 처리할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë©”ì‹œì§€ë¥¼ 모니터ë§í•˜ê±°ë‚˜ 사용ìžê°€ 보기 ì „ì— ì‚­ì œí•  수 있습니다."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"MMS 수신"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ MMS 메시지를 받고 처리할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë©”ì‹œì§€ë¥¼ 모니터ë§í•˜ê±°ë‚˜ 사용ìžê°€ 보기 ì „ì— ì‚­ì œí•  수 있습니다."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"SMS 메시지 보내기"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ SMS 메시지를 보낼 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ í™•ì¸ ì—†ì´ ë©”ì‹œì§€ë¥¼ 전송하여 ìš”ê¸ˆì„ ë¶€ê³¼í•  수 있습니다."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"SMS ë˜ëŠ” MMS ì½ê¸°"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™” ë˜ëŠ” SIM ì¹´ë“œì— ì €ìž¥ëœ SMS 메시지를 ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ê¸°ë°€ 메시지를 ì½ì„ 수 있습니다."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"SMS ë˜ëŠ” MMS 편집"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™” ë˜ëŠ” SIM ì¹´ë“œì— ì €ìž¥ëœ SMS ë©”ì‹œì§€ì— ì“¸ 수 있ë„ë¡ í•©ë‹ˆë‹¤. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ 메시지를 삭제할 수 있습니다."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP 수신"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ WAP 메시지를 받고 처리할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë©”ì‹œì§€ë¥¼ 모니터ë§í•˜ê±°ë‚˜ 사용ìžê°€ 보기 ì „ì— ì‚­ì œí•  수 있습니다."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"실행 ì¤‘ì¸ ì‘용프로그램 검색"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í˜„ìž¬ 실행 중ì´ê±°ë‚˜ ìµœê·¼ì— ì‹¤í–‰ëœ ìž‘ì—…ì— ëŒ€í•œ 정보를 검색할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì— ëŒ€í•œ ê°œì¸ ì •ë³´ë¥¼ 검색할 수 있습니다."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"실행 ì¤‘ì¸ ì‘용프로그램 순서 재지정"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìž‘ì—…ì„ í¬ê·¸ë¼ìš´ë“œë‚˜ 백그ë¼ìš´ë“œë¡œ ì´ë™í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ ì¡°ìž‘ ì—†ì´ ì•žìœ¼ë¡œ ì´ë™í•  수 있습니다."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"ì‘용프로그램 디버깅 사용"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì— ëŒ€í•´ ë””ë²„ê¹…ì„ ì‚¬ìš©í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ì¤‘ì§€ì‹œí‚¬ 수 있습니다."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI 설정 변경"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë¡œì¼€ì¼ ë˜ëŠ” ì „ì²´ 글꼴 í¬ê¸°ì™€ ê°™ì€ í˜„ìž¬ êµ¬ì„±ì„ ë³€ê²½í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"다른 ì‘용프로그램 다시 시작"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ê°•ì œë¡œ 다시 시작할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"강제로 ì‘용프로그램 닫기"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í¬ê·¸ë¼ìš´ë“œì— 있는 활ë™ì„ 강제로 ë‹«ê³  ë˜ëŒì•„ê°ˆ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"시스템 내부 ìƒíƒœ 검색"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œì˜ ë‚´ë¶€ ìƒíƒœë¥¼ 검색할 수 있ë„ë¡ í•©ë‹ˆë‹¤. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ ì¼ë°˜ì ìœ¼ë¡œ 필요하지 ì•Šì€ ë‹¤ì–‘í•œ ê°œì¸ì •ë³´ì™€ 보안정보를 검색할 수 있습니다."</string>
+ <string name="permlab_statusBar">"ìƒíƒœ 표시줄 사용 중지 ë˜ëŠ” 수정"</string>
+ <string name="permdesc_statusBar">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìƒíƒœ í‘œì‹œì¤„ì„ ì‚¬ìš© 중지하거나 시스템 ì•„ì´ì½˜ì„ 추가 ë° ì œê±°í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_expandStatusBar">"ìƒíƒœ 표시줄 확장/축소"</string>
+ <string name="permdesc_expandStatusBar">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìƒíƒœ í‘œì‹œì¤„ì„ í™•ìž¥í•˜ê±°ë‚˜ 축소할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_processOutgoingCalls">"발신전화 가로채기"</string>
+ <string name="permdesc_processOutgoingCalls">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë°œì‹ ì „í™”ë¥¼ 처리하고 전화를 걸 번호를 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë°œì‹ ì „í™”ë¥¼ 모니터ë§í•˜ê±°ë‚˜, 다른 방향으로 ëŒë¦¬ê±°ë‚˜, 중단시킬 수 있습니다."</string>
+ <string name="permlab_receiveSms">"SMS 수신"</string>
+ <string name="permdesc_receiveSms">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ SMS 메시지를 받고 처리할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë©”ì‹œì§€ë¥¼ 모니터ë§í•˜ê±°ë‚˜ 사용ìžê°€ 보기 ì „ì— ì‚­ì œí•  수 있습니다."</string>
+ <string name="permlab_receiveMms">"MMS 수신"</string>
+ <string name="permdesc_receiveMms">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ MMS 메시지를 받고 처리할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë©”ì‹œì§€ë¥¼ 모니터ë§í•˜ê±°ë‚˜ 사용ìžê°€ 보기 ì „ì— ì‚­ì œí•  수 있습니다."</string>
+ <string name="permlab_sendSms">"SMS 메시지 보내기"</string>
+ <string name="permdesc_sendSms">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ SMS 메시지를 보낼 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ í™•ì¸ ì—†ì´ ë©”ì‹œì§€ë¥¼ 전송하여 ìš”ê¸ˆì„ ë¶€ê³¼í•  수 있습니다."</string>
+ <string name="permlab_readSms">"SMS ë˜ëŠ” MMS ì½ê¸°"</string>
+ <string name="permdesc_readSms">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™” ë˜ëŠ” SIM ì¹´ë“œì— ì €ìž¥ëœ SMS 메시지를 ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ê¸°ë°€ 메시지를 ì½ì„ 수 있습니다."</string>
+ <string name="permlab_writeSms">"SMS ë˜ëŠ” MMS 편집"</string>
+ <string name="permdesc_writeSms">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™” ë˜ëŠ” SIM ì¹´ë“œì— ì €ìž¥ëœ SMS ë©”ì‹œì§€ì— ì“¸ 수 있ë„ë¡ í•©ë‹ˆë‹¤. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ 메시지를 삭제할 수 있습니다."</string>
+ <string name="permlab_receiveWapPush">"WAP 수신"</string>
+ <string name="permdesc_receiveWapPush">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ WAP 메시지를 받고 처리할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë©”ì‹œì§€ë¥¼ 모니터ë§í•˜ê±°ë‚˜ 사용ìžê°€ 보기 ì „ì— ì‚­ì œí•  수 있습니다."</string>
+ <string name="permlab_getTasks">"실행 ì¤‘ì¸ ì‘용프로그램 검색"</string>
+ <string name="permdesc_getTasks">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í˜„ìž¬ 실행 중ì´ê±°ë‚˜ ìµœê·¼ì— ì‹¤í–‰ëœ ìž‘ì—…ì— ëŒ€í•œ 정보를 검색할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì— ëŒ€í•œ ê°œì¸ ì •ë³´ë¥¼ 검색할 수 있습니다."</string>
+ <string name="permlab_reorderTasks">"실행 ì¤‘ì¸ ì‘용프로그램 순서 재지정"</string>
+ <string name="permdesc_reorderTasks">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìž‘ì—…ì„ í¬ê·¸ë¼ìš´ë“œë‚˜ 백그ë¼ìš´ë“œë¡œ ì´ë™í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ ì¡°ìž‘ ì—†ì´ ì•žìœ¼ë¡œ ì´ë™í•  수 있습니다."</string>
+ <string name="permlab_setDebugApp">"ì‘용프로그램 디버깅 사용"</string>
+ <string name="permdesc_setDebugApp">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì— ëŒ€í•´ ë””ë²„ê¹…ì„ ì‚¬ìš©í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ì¤‘ì§€ì‹œí‚¬ 수 있습니다."</string>
+ <string name="permlab_changeConfiguration">"UI 설정 변경"</string>
+ <string name="permdesc_changeConfiguration">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë¡œì¼€ì¼ ë˜ëŠ” ì „ì²´ 글꼴 í¬ê¸°ì™€ ê°™ì€ í˜„ìž¬ êµ¬ì„±ì„ ë³€ê²½í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_restartPackages">"다른 ì‘용프로그램 다시 시작"</string>
+ <string name="permdesc_restartPackages">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ê°•ì œë¡œ 다시 시작할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_forceBack">"강제로 ì‘용프로그램 닫기"</string>
+ <string name="permdesc_forceBack">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í¬ê·¸ë¼ìš´ë“œì— 있는 활ë™ì„ 강제로 ë‹«ê³  ë˜ëŒì•„ê°ˆ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
+ <string name="permlab_dump">"시스템 내부 ìƒíƒœ 검색"</string>
+ <string name="permdesc_dump">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œì˜ ë‚´ë¶€ ìƒíƒœë¥¼ 검색할 수 있ë„ë¡ í•©ë‹ˆë‹¤. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ ì¼ë°˜ì ìœ¼ë¡œ 필요하지 ì•Šì€ ë‹¤ì–‘í•œ ê°œì¸ì •ë³´ì™€ 보안정보를 검색할 수 있습니다."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"실행 ì¤‘ì¸ ëª¨ë“  ì‘용프로그램 ëª¨ë‹ˆí„°ë§ ë° ì œì–´"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œì—ì„œ 활ë™ì´ 시작ë˜ëŠ” ë°©ì‹ì„ 모니터ë§í•˜ê³  제어할 수 있ë„ë¡ í•©ë‹ˆë‹¤. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ ì‹œìŠ¤í…œì„ ì™„ì „ížˆ ì†ìƒì‹œí‚¬ 수 있습니다. ì´ ê¶Œí•œì€ ê°œë°œ 과정ì—만 필요하며 ì¼ë°˜ 휴대전화 사용 ì‹œì—는 필요하지 않습니다."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"패키지 제거 브로드ìºìŠ¤íŠ¸ 보내기"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‘용프로그램 패키지가 ì‚­ì œë˜ì—ˆë‹¤ëŠ” ì•Œë¦¼ì„ ë¸Œë¡œë“œìºìŠ¤íŠ¸í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹¤í–‰ ì¤‘ì¸ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ì¤‘ì§€ì‹œí‚¬ 수 있습니다."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"SMS 수신 브로드ìºìŠ¤íŠ¸ 보내기"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ SMS 메시지를 받았다는 ì•Œë¦¼ì„ ë¸Œë¡œë“œìºìŠ¤íŠ¸í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë“¤ì–´ì˜¤ëŠ” SMS 메시지처럼 위장할 수 있습니다."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-수신 브로드ìºìŠ¤íŠ¸ 보내기"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ WAP PUSH 메시지를 받았다는 ì•Œë¦¼ì„ ë¸Œë¡œë“œìºìŠ¤íŠ¸í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ MMS 메시지를 ë°›ì€ ê²ƒì²˜ëŸ¼ 위장하거나 웹페ì´ì§€ì˜ 콘í…츠를 악성 변종으로 몰래 바꿀 수 있습니다."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"실행 ì¤‘ì¸ í”„ë¡œì„¸ìŠ¤ 수 제한"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹¤í–‰í•  최대 프로세스 수를 제어할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"모든 백그ë¼ìš´ë“œ ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹«ížˆë„ë¡ í•˜ê¸°"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë°±ê·¸ë¼ìš´ë“œë¡œ ì´ë™í•œ 활ë™ì„ í•­ìƒ ë°”ë¡œ 종료할지 여부를 제어할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"배터리 통계 수정"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"ìˆ˜ì§‘ëœ ë°°í„°ë¦¬ 통계를 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—서는 사용할 수 없습니다."</string>
+ <string name="permlab_runSetActivityWatcher">"실행 ì¤‘ì¸ ëª¨ë“  ì‘용프로그램 ëª¨ë‹ˆí„°ë§ ë° ì œì–´"</string>
+ <string name="permdesc_runSetActivityWatcher">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œì—ì„œ 활ë™ì´ 시작ë˜ëŠ” ë°©ì‹ì„ 모니터ë§í•˜ê³  제어할 수 있ë„ë¡ í•©ë‹ˆë‹¤. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ ì‹œìŠ¤í…œì„ ì™„ì „ížˆ ì†ìƒì‹œí‚¬ 수 있습니다. ì´ ê¶Œí•œì€ ê°œë°œ 과정ì—만 필요하며 ì¼ë°˜ 휴대전화 사용 ì‹œì—는 필요하지 않습니다."</string>
+ <string name="permlab_broadcastPackageRemoved">"패키지 제거 브로드ìºìŠ¤íŠ¸ 보내기"</string>
+ <string name="permdesc_broadcastPackageRemoved">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‘용프로그램 패키지가 ì‚­ì œë˜ì—ˆë‹¤ëŠ” ì•Œë¦¼ì„ ë¸Œë¡œë“œìºìŠ¤íŠ¸í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹¤í–‰ ì¤‘ì¸ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ì¤‘ì§€ì‹œí‚¬ 수 있습니다."</string>
+ <string name="permlab_broadcastSmsReceived">"SMS 수신 브로드ìºìŠ¤íŠ¸ 보내기"</string>
+ <string name="permdesc_broadcastSmsReceived">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ SMS 메시지를 받았다는 ì•Œë¦¼ì„ ë¸Œë¡œë“œìºìŠ¤íŠ¸í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë“¤ì–´ì˜¤ëŠ” SMS 메시지처럼 위장할 수 있습니다."</string>
+ <string name="permlab_broadcastWapPush">"WAP-PUSH-수신 브로드ìºìŠ¤íŠ¸ 보내기"</string>
+ <string name="permdesc_broadcastWapPush">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ WAP PUSH 메시지를 받았다는 ì•Œë¦¼ì„ ë¸Œë¡œë“œìºìŠ¤íŠ¸í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ MMS 메시지를 ë°›ì€ ê²ƒì²˜ëŸ¼ 위장하거나 웹페ì´ì§€ì˜ 콘í…츠를 악성 변종으로 몰래 바꿀 수 있습니다."</string>
+ <string name="permlab_setProcessLimit">"실행 ì¤‘ì¸ í”„ë¡œì„¸ìŠ¤ 수 제한"</string>
+ <string name="permdesc_setProcessLimit">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹¤í–‰í•  최대 프로세스 수를 제어할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
+ <string name="permlab_setAlwaysFinish">"모든 백그ë¼ìš´ë“œ ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹«ížˆë„ë¡ í•˜ê¸°"</string>
+ <string name="permdesc_setAlwaysFinish">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë°±ê·¸ë¼ìš´ë“œë¡œ ì´ë™í•œ 활ë™ì„ í•­ìƒ ë°”ë¡œ 종료할지 여부를 제어할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
+ <string name="permlab_batteryStats">"배터리 통계 수정"</string>
+ <string name="permdesc_batteryStats">"ìˆ˜ì§‘ëœ ë°°í„°ë¦¬ 통계를 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—서는 사용할 수 없습니다."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"ì¸ì¦ë˜ì§€ ì•Šì€ ì°½ 표시"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"내부 시스템 ì‚¬ìš©ìž ì¸í„°íŽ˜ì´ìŠ¤ì—ì„œ 사용하는 ì°½ì„ ë§Œë“¤ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—서는 사용하지 않습니다."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"시스템 수준 경고 표시"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ 경고 ì°½ì„ í‘œì‹œí•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™” 화면 전체를 차지할 수 있습니다."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"ì „ì²´ 애니메ì´ì…˜ ì†ë„ 수정"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì–¸ì œë“ ì§€ ì „ì²´ 애니메ì´ì…˜ ì†ë„를 빠르게 ë˜ëŠ” ëŠë¦¬ê²Œ 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"ì‘용프로그램 í† í° ê´€ë¦¬"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì¼ë°˜ì ì¸ Z-순서를 무시하여 ìžì²´ 토í°ì„ 만들고 관리할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"키 ë° ì»¨íŠ¸ë¡¤ 버튼 누르기"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìž…ë ¥ ì´ë²¤íŠ¸(예: 키 누름)를 다른 ì‘ìš©í”„ë¡œê·¸ëž¨ì— ì „ë‹¬í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ë¥¼ 완전히 제어할 수 있습니다."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"사용ìžê°€ 입력한 ë‚´ìš© ë° ìˆ˜í–‰í•œ ìž‘ì—… 기ë¡"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘용프로그램과 ìƒí˜¸ìž‘ìš©í•  ë•Œì—ë„ ì‚¬ìš©ìžê°€ 누르는 키(예: 비밀번호 ìž…ë ¥)를 ë³¼ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"입력 방법 고정"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"보유ìžê°€ ìž…ë ¥ ë°©ë²•ì˜ ìµœìƒìœ„ ì¸í„°íŽ˜ì´ìŠ¤ë§Œ 사용하ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì–¸ì œë“ ì§€ 화면 íšŒì „ì„ ë³€ê²½í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"ì‘ìš©í”„ë¡œê·¸ëž¨ì— Linux 신호 보내기"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì œê³µëœ ì‹ í˜¸ë¥¼ 모든 ì˜êµ¬ 프로세스로 ë³´ë‚´ë„ë¡ ìš”ì²­í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í•­ìƒ ì‹¤í–‰ë˜ë„ë¡ ì„¤ì •"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì—°ê²°ëœ ì¼ë¶€ 구성 요소를 지ì†í•˜ì—¬ 다른 ì‘ìš©í”„ë¡œê·¸ëž¨ì— ì‚¬ìš©í•  수 ì—†ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"ì‘용프로그램 ì‚­ì œ"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ Android 패키지를 삭제할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì¤‘ìš”í•œ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ì‚­ì œí•  수 있습니다."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"다른 ì‘ìš©í”„ë¡œê·¸ëž¨ì˜ ë°ì´í„° ì‚­ì œ"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìž ë°ì´í„°ë¥¼ 지울 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"다른 ì‘ìš©í”„ë¡œê·¸ëž¨ì˜ ìºì‹œ ì‚­ì œ"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìºì‹œ 파ì¼ì„ 삭제할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"ì‘용프로그램 저장공간 계산"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í•´ë‹¹ 코드, ë°ì´í„° ë° ìºì‹œ í¬ê¸°ë¥¼ 검색할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"ì‘용프로그램 ì§ì ‘ 설치"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìƒˆë¡œìš´ ë˜ëŠ” ì—…ë°ì´íŠ¸ëœ Android 패키지를 설치할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìž„ì˜ì˜ 강력한 권한으로 새 ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ì¶”ê°€í•  수 있습니다."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"모든 ì‘용프로그램 ìºì‹œ ë°ì´í„° ì‚­ì œ"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‘용프로그램 ìºì‹œ ë””ë ‰í† ë¦¬ì— ìžˆëŠ” 파ì¼ì„ 삭제하여 íœ´ëŒ€ì „í™”ì˜ ì €ìž¥ê³µê°„ì„ ëŠ˜ë¦´ 수 있ë„ë¡ í•©ë‹ˆë‹¤. 액세스는 ì¼ë°˜ì ìœ¼ë¡œ 시스템 프로세스로 제한ë©ë‹ˆë‹¤."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"시스템 로그 íŒŒì¼ ì½ê¸°"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œì˜ ë‹¤ì–‘í•œ 로그 파ì¼ì„ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° ì‘ìš©í”„ë¡œê·¸ëž¨ì€ ì‚¬ìš©ìžê°€ 휴대전화로 수행하는 ìž‘ì—…ì— ëŒ€í•œ ì¼ë°˜ì ì¸ 정보를 검색할 수 있지만 ì—¬ê¸°ì— ê°œì¸ì •ë³´ëŠ” í¬í•¨ë˜ì–´ì„œëŠ” 안 ë©ë‹ˆë‹¤."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 ì†Œìœ ì˜ ë¦¬ì†ŒìŠ¤ ì½ê¸°/작성"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì§„ë‹¨ 그룹 ì†Œìœ ì˜ ë¦¬ì†ŒìŠ¤(예: /devì— ìžˆëŠ” 파ì¼)를 ì½ê³  쓸 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê¸°ëŠ¥ì€ ì‹œìŠ¤í…œ 안정성 ë° ë³´ì•ˆì— ì˜í–¥ì„ 미칠 수 있으므로 제조업체 ë˜ëŠ” 사업ìžê°€ 하드웨어 관련 ì§„ë‹¨ì„ ìˆ˜í–‰í•˜ëŠ” 경우ì—만 사용해야 합니다."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"ì‘용프로그램 구성 요소 사용 ë˜ëŠ” 사용 안함"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘용프로그램 구성 요소 사용 여부를 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì¤‘ìš”í•œ 휴대전화 ê¸°ëŠ¥ì„ ì‚¬ìš©í•˜ì§€ ì•Šë„ë¡ ì„¤ì •í•  수 있습니다. ì´ ê¶Œí•œì„ ì„¤ì •í•  경우 ì‘용프로그램 구성 요소가 사용 불가능하게 ë˜ê±°ë‚˜ ì¼ê´€ì„±ì´ 맞지 않거나 불안정해질 수 있으므로 주ì˜í•´ì•¼ 합니다."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"기본 ì‘용프로그램 설정"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ê¸°ë³¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ìˆ˜ì •í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ ê°œì¸ ì •ë³´ë¥¼ 수집하기 위해 기존 ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ìŠ¤í‘¸í•‘í•˜ì—¬ 실행ë˜ëŠ” ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ëª°ëž˜ 변경할 수 있습니다."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"전체 시스템 설정 수정"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œì˜ ì„¤ì • ë°ì´í„°ë¥¼ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ êµ¬ì„±ì„ ì†ìƒì‹œí‚¬ 수 있습니다."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"보안 시스템 설정 수정"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ 보안 설정값 ë°ì´í„°ë¥¼ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—서는 사용하지 않습니다."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Google 서비스 ì§€ë„ ìˆ˜ì •"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ Google 서비스 지ë„를 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—서는 사용하지 않습니다."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"부팅할 ë•Œ ìžë™ 시작"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ ë¶€íŒ…ì´ ëë‚œ 후 바로 시작할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 휴대전화가 시작하는 ë° ì‹œê°„ì´ ì˜¤ëž˜ 걸리고 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í•­ìƒ ì‹¤í–‰ë˜ì–´ ì „ì²´ 휴대전화 ì†ë„ê°€ ëŠë ¤ì§ˆ 수 있습니다."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"ë‚¨ì€ ë¸Œë¡œë“œìºìŠ¤íŠ¸ 보내기"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë¸Œë¡œë“œìºìŠ¤íŠ¸ê°€ ëë‚œ í›„ì— ë‚¨ì€ ë¸Œë¡œë“œìºìŠ¤íŠ¸ë¥¼ 보낼 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ê°€ 메모리를 너무 ë§Žì´ ì‚¬ìš©í•˜ë„ë¡ í•˜ì—¬ ì†ë„를 저하시키거나 불안정하게 만들 수 있습니다."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"ì—°ë½ì²˜ ë°ì´í„° ì½ê¸°"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ëª¨ë“  ì—°ë½ì²˜(주소) ë°ì´í„°ë¥¼ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë°ì´í„°ë¥¼ 다른 사람ì—게 보낼 수 있습니다."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"ì—°ë½ì²˜ ë°ì´í„° 작성"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ì—°ë½ì²˜(주소) ë°ì´í„°ë¥¼ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì—°ë½ì²˜ ë°ì´í„°ë¥¼ 지우거나 수정할 수 있습니다."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"ì†Œìœ ìž ë°ì´í„° 작성"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ì†Œìœ ìž ë°ì´í„°ë¥¼ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ ì†Œìœ ìž ë°ì´í„°ë¥¼ 지우거나 수정할 수 있습니다."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"ì†Œìœ ìž ë°ì´í„° ì½ê¸°"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ íœ´ëŒ€ì „í™” ì†Œìœ ìž ë°ì´í„°ë¥¼ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™” ì†Œìœ ìž ë°ì´í„°ë¥¼ ì½ì„ 수 있습니다."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"ìº˜ë¦°ë” ë°ì´í„° ì½ê¸°"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ëª¨ë“  ìº˜ë¦°ë” ì¼ì •ì„ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìº˜ë¦°ë” ì¼ì •ì„ 다른 사람ì—게 보낼 수 있습니다."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"ìº˜ë¦°ë” ë°ì´í„° 작성"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ìº˜ë¦°ë” ì¼ì •ì„ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìº˜ë¦°ë” ë°ì´í„°ë¥¼ 지우거나 수정할 수 있습니다."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"테스트를 위해 위치 소스로 가장"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"테스트용 가짜 위치 소스를 만듭니다. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ GPS, ë„¤íŠ¸ì›Œí¬ ì œê³µì—…ì²´ ê°™ì€ ì‹¤ì œ 위치 소스ì—ì„œ 반환한 위치 ë°/ë˜ëŠ” ìƒíƒœë¥¼ ë®ì–´ì“¸ 수 있습니다."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"추가 위치 제공업체 명령 액세스"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"추가 위치 제공업체 ëª…ë ¹ì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ GPS ë˜ëŠ” 기타 위치 ì†ŒìŠ¤ì˜ ìž‘ë™ì„ ë°©í•´í•  수 있습니다."</string>
+ <string name="permlab_internalSystemWindow">"ì¸ì¦ë˜ì§€ ì•Šì€ ì°½ 표시"</string>
+ <string name="permdesc_internalSystemWindow">"내부 시스템 ì‚¬ìš©ìž ì¸í„°íŽ˜ì´ìŠ¤ì—ì„œ 사용하는 ì°½ì„ ë§Œë“¤ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—서는 사용하지 않습니다."</string>
+ <string name="permlab_systemAlertWindow">"시스템 수준 경고 표시"</string>
+ <string name="permdesc_systemAlertWindow">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ 경고 ì°½ì„ í‘œì‹œí•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™” 화면 전체를 차지할 수 있습니다."</string>
+ <string name="permlab_setAnimationScale">"ì „ì²´ 애니메ì´ì…˜ ì†ë„ 수정"</string>
+ <string name="permdesc_setAnimationScale">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì–¸ì œë“ ì§€ ì „ì²´ 애니메ì´ì…˜ ì†ë„를 빠르게 ë˜ëŠ” ëŠë¦¬ê²Œ 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_manageAppTokens">"ì‘용프로그램 í† í° ê´€ë¦¬"</string>
+ <string name="permdesc_manageAppTokens">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì¼ë°˜ì ì¸ Z-순서를 무시하여 ìžì²´ 토í°ì„ 만들고 관리할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
+ <string name="permlab_injectEvents">"키 ë° ì»¨íŠ¸ë¡¤ 버튼 누르기"</string>
+ <string name="permdesc_injectEvents">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìž…ë ¥ ì´ë²¤íŠ¸(예: 키 누름)를 다른 ì‘ìš©í”„ë¡œê·¸ëž¨ì— ì „ë‹¬í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ë¥¼ 완전히 제어할 수 있습니다."</string>
+ <string name="permlab_readInputState">"사용ìžê°€ 입력한 ë‚´ìš© ë° ìˆ˜í–‰í•œ ìž‘ì—… 기ë¡"</string>
+ <string name="permdesc_readInputState">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘용프로그램과 ìƒí˜¸ìž‘ìš©í•  ë•Œì—ë„ ì‚¬ìš©ìžê°€ 누르는 키(예: 비밀번호 ìž…ë ¥)를 ë³¼ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
+ <string name="permlab_bindInputMethod">"입력 방법 고정"</string>
+ <string name="permdesc_bindInputMethod">"보유ìžê°€ ìž…ë ¥ ë°©ë²•ì˜ ìµœìƒìœ„ ì¸í„°íŽ˜ì´ìŠ¤ë§Œ 사용하ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
+ <string name="permlab_setOrientation">"화면 방향 변경"</string>
+ <string name="permdesc_setOrientation">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì–¸ì œë“ ì§€ 화면 íšŒì „ì„ ë³€ê²½í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—는 필요하지 않습니다."</string>
+ <string name="permlab_signalPersistentProcesses">"ì‘ìš©í”„ë¡œê·¸ëž¨ì— Linux 신호 보내기"</string>
+ <string name="permdesc_signalPersistentProcesses">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì œê³µëœ ì‹ í˜¸ë¥¼ 모든 ì˜êµ¬ 프로세스로 ë³´ë‚´ë„ë¡ ìš”ì²­í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_persistentActivity">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í•­ìƒ ì‹¤í–‰ë˜ë„ë¡ ì„¤ì •"</string>
+ <string name="permdesc_persistentActivity">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì—°ê²°ëœ ì¼ë¶€ 구성 요소를 지ì†í•˜ì—¬ 다른 ì‘ìš©í”„ë¡œê·¸ëž¨ì— ì‚¬ìš©í•  수 ì—†ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_deletePackages">"ì‘용프로그램 ì‚­ì œ"</string>
+ <string name="permdesc_deletePackages">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ Android 패키지를 삭제할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì¤‘ìš”í•œ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ì‚­ì œí•  수 있습니다."</string>
+ <string name="permlab_clearAppUserData">"다른 ì‘ìš©í”„ë¡œê·¸ëž¨ì˜ ë°ì´í„° ì‚­ì œ"</string>
+ <string name="permdesc_clearAppUserData">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìž ë°ì´í„°ë¥¼ 지울 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_deleteCacheFiles">"다른 ì‘ìš©í”„ë¡œê·¸ëž¨ì˜ ìºì‹œ ì‚­ì œ"</string>
+ <string name="permdesc_deleteCacheFiles">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìºì‹œ 파ì¼ì„ 삭제할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_getPackageSize">"ì‘용프로그램 저장공간 계산"</string>
+ <string name="permdesc_getPackageSize">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í•´ë‹¹ 코드, ë°ì´í„° ë° ìºì‹œ í¬ê¸°ë¥¼ 검색할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_installPackages">"ì‘용프로그램 ì§ì ‘ 설치"</string>
+ <string name="permdesc_installPackages">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìƒˆë¡œìš´ ë˜ëŠ” ì—…ë°ì´íŠ¸ëœ Android 패키지를 설치할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìž„ì˜ì˜ 강력한 권한으로 새 ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ì¶”ê°€í•  수 있습니다."</string>
+ <string name="permlab_clearAppCache">"모든 ì‘용프로그램 ìºì‹œ ë°ì´í„° ì‚­ì œ"</string>
+ <string name="permdesc_clearAppCache">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‘용프로그램 ìºì‹œ ë””ë ‰í† ë¦¬ì— ìžˆëŠ” 파ì¼ì„ 삭제하여 íœ´ëŒ€ì „í™”ì˜ ì €ìž¥ê³µê°„ì„ ëŠ˜ë¦´ 수 있ë„ë¡ í•©ë‹ˆë‹¤. 액세스는 ì¼ë°˜ì ìœ¼ë¡œ 시스템 프로세스로 제한ë©ë‹ˆë‹¤."</string>
+ <string name="permlab_readLogs">"시스템 로그 íŒŒì¼ ì½ê¸°"</string>
+ <string name="permdesc_readLogs">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œì˜ ë‹¤ì–‘í•œ 로그 파ì¼ì„ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° ì‘ìš©í”„ë¡œê·¸ëž¨ì€ ì‚¬ìš©ìžê°€ 휴대전화로 수행하는 ìž‘ì—…ì— ëŒ€í•œ ì¼ë°˜ì ì¸ 정보를 검색할 수 있지만 ì—¬ê¸°ì— ê°œì¸ì •ë³´ëŠ” í¬í•¨ë˜ì–´ì„œëŠ” 안 ë©ë‹ˆë‹¤."</string>
+ <string name="permlab_diagnostic">"진단 그룹 ì†Œìœ ì˜ ë¦¬ì†ŒìŠ¤ ì½ê¸°/작성"</string>
+ <string name="permdesc_diagnostic">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì§„ë‹¨ 그룹 ì†Œìœ ì˜ ë¦¬ì†ŒìŠ¤(예: /devì— ìžˆëŠ” 파ì¼)를 ì½ê³  쓸 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê¸°ëŠ¥ì€ ì‹œìŠ¤í…œ 안정성 ë° ë³´ì•ˆì— ì˜í–¥ì„ 미칠 수 있으므로 제조업체 ë˜ëŠ” 사업ìžê°€ 하드웨어 관련 ì§„ë‹¨ì„ ìˆ˜í–‰í•˜ëŠ” 경우ì—만 사용해야 합니다."</string>
+ <string name="permlab_changeComponentState">"ì‘용프로그램 구성 요소 사용 ë˜ëŠ” 사용 안함"</string>
+ <string name="permdesc_changeComponentState">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë‹¤ë¥¸ ì‘용프로그램 구성 요소 사용 여부를 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì¤‘ìš”í•œ 휴대전화 ê¸°ëŠ¥ì„ ì‚¬ìš©í•˜ì§€ ì•Šë„ë¡ ì„¤ì •í•  수 있습니다. ì´ ê¶Œí•œì„ ì„¤ì •í•  경우 ì‘용프로그램 구성 요소가 사용 불가능하게 ë˜ê±°ë‚˜ ì¼ê´€ì„±ì´ 맞지 않거나 불안정해질 수 있으므로 주ì˜í•´ì•¼ 합니다."</string>
+ <string name="permlab_setPreferredApplications">"기본 ì‘용프로그램 설정"</string>
+ <string name="permdesc_setPreferredApplications">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ê¸°ë³¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ìˆ˜ì •í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ ê°œì¸ ì •ë³´ë¥¼ 수집하기 위해 기존 ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ìŠ¤í‘¸í•‘í•˜ì—¬ 실행ë˜ëŠ” ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ëª°ëž˜ 변경할 수 있습니다."</string>
+ <string name="permlab_writeSettings">"전체 시스템 설정 수정"</string>
+ <string name="permdesc_writeSettings">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œì˜ ì„¤ì • ë°ì´í„°ë¥¼ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ êµ¬ì„±ì„ ì†ìƒì‹œí‚¬ 수 있습니다."</string>
+ <string name="permlab_writeSecureSettings">"보안 시스템 설정 수정"</string>
+ <string name="permdesc_writeSecureSettings">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ 보안 설정값 ë°ì´í„°ë¥¼ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—서는 사용하지 않습니다."</string>
+ <string name="permlab_writeGservices">"Google 서비스 ì§€ë„ ìˆ˜ì •"</string>
+ <string name="permdesc_writeGservices">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ Google 서비스 지ë„를 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—서는 사용하지 않습니다."</string>
+ <string name="permlab_receiveBootCompleted">"부팅할 ë•Œ ìžë™ 시작"</string>
+ <string name="permdesc_receiveBootCompleted">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ ë¶€íŒ…ì´ ëë‚œ 후 바로 시작할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 휴대전화가 시작하는 ë° ì‹œê°„ì´ ì˜¤ëž˜ 걸리고 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í•­ìƒ ì‹¤í–‰ë˜ì–´ ì „ì²´ 휴대전화 ì†ë„ê°€ ëŠë ¤ì§ˆ 수 있습니다."</string>
+ <string name="permlab_broadcastSticky">"ë‚¨ì€ ë¸Œë¡œë“œìºìŠ¤íŠ¸ 보내기"</string>
+ <string name="permdesc_broadcastSticky">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë¸Œë¡œë“œìºìŠ¤íŠ¸ê°€ ëë‚œ í›„ì— ë‚¨ì€ ë¸Œë¡œë“œìºìŠ¤íŠ¸ë¥¼ 보낼 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ê°€ 메모리를 너무 ë§Žì´ ì‚¬ìš©í•˜ë„ë¡ í•˜ì—¬ ì†ë„를 저하시키거나 불안정하게 만들 수 있습니다."</string>
+ <string name="permlab_readContacts">"ì—°ë½ì²˜ ë°ì´í„° ì½ê¸°"</string>
+ <string name="permdesc_readContacts">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ëª¨ë“  ì—°ë½ì²˜(주소) ë°ì´í„°ë¥¼ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë°ì´í„°ë¥¼ 다른 사람ì—게 보낼 수 있습니다."</string>
+ <string name="permlab_writeContacts">"ì—°ë½ì²˜ ë°ì´í„° 작성"</string>
+ <string name="permdesc_writeContacts">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ì—°ë½ì²˜(주소) ë°ì´í„°ë¥¼ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì—°ë½ì²˜ ë°ì´í„°ë¥¼ 지우거나 수정할 수 있습니다."</string>
+ <string name="permlab_writeOwnerData">"ì†Œìœ ìž ë°ì´í„° 작성"</string>
+ <string name="permdesc_writeOwnerData">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ì†Œìœ ìž ë°ì´í„°ë¥¼ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ ì†Œìœ ìž ë°ì´í„°ë¥¼ 지우거나 수정할 수 있습니다."</string>
+ <string name="permlab_readOwnerData">"ì†Œìœ ìž ë°ì´í„° ì½ê¸°"</string>
+ <string name="permdesc_readOwnerData">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ íœ´ëŒ€ì „í™” ì†Œìœ ìž ë°ì´í„°ë¥¼ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™” ì†Œìœ ìž ë°ì´í„°ë¥¼ ì½ì„ 수 있습니다."</string>
+ <string name="permlab_readCalendar">"ìº˜ë¦°ë” ë°ì´í„° ì½ê¸°"</string>
+ <string name="permdesc_readCalendar">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ëª¨ë“  ìº˜ë¦°ë” ì¼ì •ì„ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìº˜ë¦°ë” ì¼ì •ì„ 다른 사람ì—게 보낼 수 있습니다."</string>
+ <string name="permlab_writeCalendar">"ìº˜ë¦°ë” ë°ì´í„° 작성"</string>
+ <string name="permdesc_writeCalendar">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì €ìž¥ëœ ìº˜ë¦°ë” ì¼ì •ì„ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìº˜ë¦°ë” ë°ì´í„°ë¥¼ 지우거나 수정할 수 있습니다."</string>
+ <string name="permlab_accessMockLocation">"테스트를 위해 위치 소스로 가장"</string>
+ <string name="permdesc_accessMockLocation">"테스트용 가짜 위치 소스를 만듭니다. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ GPS, ë„¤íŠ¸ì›Œí¬ ì œê³µì—…ì²´ ê°™ì€ ì‹¤ì œ 위치 소스ì—ì„œ 반환한 위치 ë°/ë˜ëŠ” ìƒíƒœë¥¼ ë®ì–´ì“¸ 수 있습니다."</string>
+ <string name="permlab_accessLocationExtraCommands">"추가 위치 제공업체 명령 액세스"</string>
+ <string name="permdesc_accessLocationExtraCommands">"추가 위치 제공업체 ëª…ë ¹ì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤. 단, 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ ê¸°ëŠ¥ì„ ì´ìš©í•˜ì—¬ GPS ë˜ëŠ” 기타 위치 ì†ŒìŠ¤ì˜ ìž‘ë™ì„ ë°©í•´í•  수 있습니다."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"ìžì„¸í•œ (GPS) 위치"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"가능한 경우 휴대전화ì—ì„œ GPS(범지구 위치 측정 시스템) ë“±ì˜ ìžì„¸í•œ 위치 ì†ŒìŠ¤ì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ 위치를 확ì¸í•˜ê³  추가 배터리 ì „ì›ì„ 소비할 수 있습니다."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"광범위한 ë„¤íŠ¸ì›Œí¬ ê¸°ë°˜ 위치"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"íœ´ëŒ€ì „í™”ì˜ ëŒ€ëžµì ì¸ 위치를 측정하기 위해 셀룰러 ë„¤íŠ¸ì›Œí¬ ë°ì´í„°ë² ì´ìŠ¤ì™€ ê°™ì€ ê´‘ë²”ìœ„í•œ 위치 ì†ŒìŠ¤ì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ 위치를 대략ì ìœ¼ë¡œ 측정할 수 있습니다."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"SurfaceFlinger 액세스"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ SurfaceFlingerì˜ í•˜ìœ„ 수준 ê¸°ëŠ¥ì„ ì‚¬ìš©í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"프레임 ë²„í¼ ì½ê¸°"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í”„ë ˆìž„ 버í¼ì˜ 콘í…츠를 ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"오디오 설정 변경"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë³¼ë¥¨ ë° ê²½ë¡œ 지정 ê°™ì€ ì „ì²´ 오디오 ì„¤ì •ì„ ìˆ˜ì •í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"오디오 ë…¹ìŒ"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì˜¤ë””ì˜¤ 레코드 ê²½ë¡œì— ì•¡ì„¸ìŠ¤í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"사진 ì´¬ì˜"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì¹´ë©”ë¼ë¡œ ì‚¬ì§„ì„ ì°ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì¹´ë©”ë¼ì— 표시ë˜ëŠ” ì´ë¯¸ì§€ë¥¼ 언제든지 수집할 수 있습니다."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"휴대전화를 ì˜êµ¬ì ìœ¼ë¡œ 사용 중지"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ë¥¼ ì˜êµ¬ì ìœ¼ë¡œ 사용 중지할 수 있게 합니다. ì´ ê¸°ëŠ¥ì€ ë§¤ìš° 위험합니다."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"휴대전화 강제로 다시 부팅"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ë¥¼ 강제로 다시 부팅할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"파ì¼ì‹œìŠ¤í…œ 마운트 ë° ë§ˆìš´íŠ¸ í•´ì œ"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ë™ì‹ ì €ìž¥ì†Œì˜ íŒŒì¼ ì‹œìŠ¤í…œì„ ë§ˆìš´íŠ¸í•˜ê³  마운트 해제할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"외부 저장소 í¬ë§·"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì œê±° 가능한 저장소를 í¬ë§·í•˜ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"ì§„ë™ ì œì–´"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì§„ë™ì„ 제어할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ì†ì „등 제어"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì†ì „ë“±ì„ ì œì–´í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"하드웨어 테스트"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í•˜ë“œì›¨ì–´ë¥¼ 테스트할 목ì ìœ¼ë¡œ 다양한 주변장치를 제어할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"전화번호로 ì§ì ‘ 전화걸기"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ ì¡°ìž‘ ì—†ì´ ì „í™”ë²ˆí˜¸ë¡œ 전화를 걸 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘용프로그램으로 ì¸í•´ 예ìƒì¹˜ 못한 통화 ìš”ê¸ˆì´ ë¶€ê³¼ë  ìˆ˜ 있습니다. ì´ ê¶Œí•œìœ¼ë¡œ ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë¹„ìƒ ì „í™”ë¥¼ 걸게 í•  수는 없습니다."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"전화번호로 ì§ì ‘ 전화걸기"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ ì¡°ìž‘ ì—†ì´ ë¹„ìƒ ë²ˆí˜¸ë¥¼ í¬í•¨í•œ 전화번호로 전화를 걸 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‘급 서비스를 불필요하거나 불법ì ìœ¼ë¡œ 호출할 수 있습니다."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"위치 ì—…ë°ì´íŠ¸ 알림 제어"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"ë¬´ì„ ì˜ ìœ„ì¹˜ ì—…ë°ì´íŠ¸ ì•Œë¦¼ì„ ì‚¬ìš©í•˜ê±°ë‚˜ 사용 중지할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—서는 사용하지 않습니다."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"ì²´í¬ì¸ ì†ì„± 액세스"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"ì²´í¬ì¸ 서비스ì—ì„œ 업로드한 ì†ì„±ì— 대한 ì½ê¸°/쓰기 액세스를 허용합니다. ì¼ë°˜ ì‘용프로그램ì—서는 사용할 수 없습니다."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"위젯 ì„ íƒ"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‘용프로그램ì—ì„œ 사용할 수 있는 ìœ„ì ¯ì„ ì‹œìŠ¤í…œì— ì•Œë¦´ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê¶Œí•œì„ ê°–ëŠ” ì‘ìš©í”„ë¡œê·¸ëž¨ì€ ê°œì¸ ì •ë³´ì— ëŒ€í•œ 액세스 ê¶Œí•œì„ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì— ë¶€ì—¬í•  수 있습니다. ì¼ë°˜ ì‘용프로그램ì—서는 사용하지 않습니다."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"휴대전화 ìƒíƒœ 수정"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìž¥ì¹˜ì˜ íœ´ëŒ€ì „í™” ê¸°ëŠ¥ì„ ì œì–´í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê¶Œí•œì„ ê°–ëŠ” ì‘ìš©í”„ë¡œê·¸ëž¨ì€ ì‚¬ìš©ìžì—게 알리지 ì•Šê³  네트워í¬ë¥¼ 전환하거나 휴대전화 무선 ê¸°ëŠ¥ì„ ì¼œê³  ë„는 ë“±ì˜ ìž‘ì—…ì„ ìˆ˜í–‰í•  수 있습니다."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"휴대전화가 절전 모드로 전환ë˜ì§€ ì•Šë„ë¡ ì„¤ì •"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ê°€ 절전 모드로 전환ë˜ì§€ ì•Šë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"휴대전화 ì „ì› ì¼œê³  ë„기"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ë¥¼ 켜거나 ëŒ ìˆ˜ 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"출고 테스트 모드로 실행"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"휴대전화 í•˜ë“œì›¨ì–´ì— ëŒ€í•œ 완전한 액세스를 허용하는 하위 ìˆ˜ì¤€ì˜ ì œì¡°ì—…ì²´ 테스트로 실행ë©ë‹ˆë‹¤. 휴대전화가 제조업체 테스트 모드로 실행 ì¤‘ì¼ ë•Œë§Œ 사용할 수 있습니다."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"배경화면 설정"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ ë°°ê²½í™”ë©´ì„ ì„¤ì •í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"배경화면 í¬ê¸° 힌트 설정"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ 배경화면 í¬ê¸° 힌트를 설정할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"ì‹œìŠ¤í…œì„ ê¸°ë³¸ê°’ìœ¼ë¡œ 재설정"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ëª¨ë“  ë°ì´í„°, 구성 ë° ì„¤ì¹˜ëœ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ì§€ì›Œì„œ ì‹œìŠ¤í…œì„ ì™„ì „ížˆ 초기화할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"표준시간대 설정"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì˜ í‘œì¤€ì‹œê°„ëŒ€ë¥¼ 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"알려진 계정 검색"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì•Œë ¤ì§„ 계정 목ë¡ì„ 가져올 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ë„¤íŠ¸ì›Œí¬ ìƒíƒœ 보기"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ëª¨ë“  네트워í¬ì˜ ìƒíƒœë¥¼ ë³¼ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"ì¸í„°ë„·ì— 완전히 액세스"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë„¤íŠ¸ì›Œí¬ ì†Œì¼“ì„ ë§Œë“¤ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"액세스í¬ì¸íŠ¸ ì´ë¦„ 설정 쓰기"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ APNì˜ í”„ë¡ì‹œ ë° í¬íŠ¸ ê°™ì€ APN ì„¤ì •ì„ ìˆ˜ì •í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"ë„¤íŠ¸ì›Œí¬ ì—°ê²° 변경"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë„¤íŠ¸ì›Œí¬ ì—°ê²° ìƒíƒœë¥¼ 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"백그ë¼ìš´ë“œ ë°ì´í„° 사용 설정 변경"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë°±ê·¸ë¼ìš´ë“œ ë°ì´í„° 사용 ì„¤ì •ì„ ë³€ê²½í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Wi-Fi ìƒíƒœ 보기"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ Wi-Fiì˜ ìƒíƒœì— 대한 정보를 ë³¼ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Wi-Fi ìƒíƒœ 변경"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ Wi-Fi 액세스í¬ì¸íŠ¸ì— 연결하거나 ì—°ê²°ì„ ëŠê³ , êµ¬ì„±ëœ Wi-Fi 네트워í¬ë¥¼ 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_accessFineLocation">"ìžì„¸í•œ (GPS) 위치"</string>
+ <string name="permdesc_accessFineLocation">"가능한 경우 휴대전화ì—ì„œ GPS(범지구 위치 측정 시스템) ë“±ì˜ ìžì„¸í•œ 위치 ì†ŒìŠ¤ì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ 위치를 확ì¸í•˜ê³  추가 배터리 ì „ì›ì„ 소비할 수 있습니다."</string>
+ <string name="permlab_accessCoarseLocation">"광범위한 ë„¤íŠ¸ì›Œí¬ ê¸°ë°˜ 위치"</string>
+ <string name="permdesc_accessCoarseLocation">"íœ´ëŒ€ì „í™”ì˜ ëŒ€ëžµì ì¸ 위치를 측정하기 위해 셀룰러 ë„¤íŠ¸ì›Œí¬ ë°ì´í„°ë² ì´ìŠ¤ì™€ ê°™ì€ ê´‘ë²”ìœ„í•œ 위치 ì†ŒìŠ¤ì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ 위치를 대략ì ìœ¼ë¡œ 측정할 수 있습니다."</string>
+ <string name="permlab_accessSurfaceFlinger">"SurfaceFlinger 액세스"</string>
+ <string name="permdesc_accessSurfaceFlinger">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ SurfaceFlingerì˜ í•˜ìœ„ 수준 ê¸°ëŠ¥ì„ ì‚¬ìš©í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_readFrameBuffer">"프레임 ë²„í¼ ì½ê¸°"</string>
+ <string name="permdesc_readFrameBuffer">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í”„ë ˆìž„ 버í¼ì˜ 콘í…츠를 ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_modifyAudioSettings">"오디오 설정 변경"</string>
+ <string name="permdesc_modifyAudioSettings">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë³¼ë¥¨ ë° ê²½ë¡œ 지정 ê°™ì€ ì „ì²´ 오디오 ì„¤ì •ì„ ìˆ˜ì •í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_recordAudio">"오디오 ë…¹ìŒ"</string>
+ <string name="permdesc_recordAudio">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì˜¤ë””ì˜¤ 레코드 ê²½ë¡œì— ì•¡ì„¸ìŠ¤í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_camera">"사진 ì´¬ì˜"</string>
+ <string name="permdesc_camera">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì¹´ë©”ë¼ë¡œ ì‚¬ì§„ì„ ì°ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì¹´ë©”ë¼ì— 표시ë˜ëŠ” ì´ë¯¸ì§€ë¥¼ 언제든지 수집할 수 있습니다."</string>
+ <string name="permlab_brick">"휴대전화를 ì˜êµ¬ì ìœ¼ë¡œ 사용 중지"</string>
+ <string name="permdesc_brick">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ë¥¼ ì˜êµ¬ì ìœ¼ë¡œ 사용 중지할 수 있게 합니다. ì´ ê¸°ëŠ¥ì€ ë§¤ìš° 위험합니다."</string>
+ <string name="permlab_reboot">"휴대전화 강제로 다시 부팅"</string>
+ <string name="permdesc_reboot">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ë¥¼ 강제로 다시 부팅할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_mount_unmount_filesystems">"파ì¼ì‹œìŠ¤í…œ 마운트 ë° ë§ˆìš´íŠ¸ í•´ì œ"</string>
+ <string name="permdesc_mount_unmount_filesystems">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì´ë™ì‹ ì €ìž¥ì†Œì˜ íŒŒì¼ ì‹œìŠ¤í…œì„ ë§ˆìš´íŠ¸í•˜ê³  마운트 해제할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_mount_format_filesystems">"외부 저장소 í¬ë§·"</string>
+ <string name="permdesc_mount_format_filesystems">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì œê±° 가능한 저장소를 í¬ë§·í•˜ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_vibrate">"ì§„ë™ ì œì–´"</string>
+ <string name="permdesc_vibrate">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì§„ë™ì„ 제어할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_flashlight">"ì†ì „등 제어"</string>
+ <string name="permdesc_flashlight">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì†ì „ë“±ì„ ì œì–´í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_hardware_test">"하드웨어 테스트"</string>
+ <string name="permdesc_hardware_test">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í•˜ë“œì›¨ì–´ë¥¼ 테스트할 목ì ìœ¼ë¡œ 다양한 주변장치를 제어할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_callPhone">"전화번호로 ì§ì ‘ 전화걸기"</string>
+ <string name="permdesc_callPhone">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ ì¡°ìž‘ ì—†ì´ ì „í™”ë²ˆí˜¸ë¡œ 전화를 걸 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘용프로그램으로 ì¸í•´ 예ìƒì¹˜ 못한 통화 ìš”ê¸ˆì´ ë¶€ê³¼ë  ìˆ˜ 있습니다. ì´ ê¶Œí•œìœ¼ë¡œ ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë¹„ìƒ ì „í™”ë¥¼ 걸게 í•  수는 없습니다."</string>
+ <string name="permlab_callPrivileged">"전화번호로 ì§ì ‘ 전화걸기"</string>
+ <string name="permdesc_callPrivileged">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìžì˜ ì¡°ìž‘ ì—†ì´ ë¹„ìƒ ë²ˆí˜¸ë¥¼ í¬í•¨í•œ 전화번호로 전화를 걸 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‘급 서비스를 불필요하거나 불법ì ìœ¼ë¡œ 호출할 수 있습니다."</string>
+ <string name="permlab_locationUpdates">"위치 ì—…ë°ì´íŠ¸ 알림 제어"</string>
+ <string name="permdesc_locationUpdates">"ë¬´ì„ ì˜ ìœ„ì¹˜ ì—…ë°ì´íŠ¸ ì•Œë¦¼ì„ ì‚¬ìš©í•˜ê±°ë‚˜ 사용 중지할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘용프로그램ì—서는 사용하지 않습니다."</string>
+ <string name="permlab_checkinProperties">"ì²´í¬ì¸ ì†ì„± 액세스"</string>
+ <string name="permdesc_checkinProperties">"ì²´í¬ì¸ 서비스ì—ì„œ 업로드한 ì†ì„±ì— 대한 ì½ê¸°/쓰기 액세스를 허용합니다. ì¼ë°˜ ì‘용프로그램ì—서는 사용할 수 없습니다."</string>
+ <string name="permlab_bindGadget">"위젯 ì„ íƒ"</string>
+ <string name="permdesc_bindGadget">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‘용프로그램ì—ì„œ 사용할 수 있는 ìœ„ì ¯ì„ ì‹œìŠ¤í…œì— ì•Œë¦´ 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê¶Œí•œì„ ê°–ëŠ” ì‘ìš©í”„ë¡œê·¸ëž¨ì€ ê°œì¸ ì •ë³´ì— ëŒ€í•œ 액세스 ê¶Œí•œì„ ë‹¤ë¥¸ ì‘ìš©í”„ë¡œê·¸ëž¨ì— ë¶€ì—¬í•  수 있습니다. ì¼ë°˜ ì‘용프로그램ì—서는 사용하지 않습니다."</string>
+ <string name="permlab_modifyPhoneState">"휴대전화 ìƒíƒœ 수정"</string>
+ <string name="permdesc_modifyPhoneState">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìž¥ì¹˜ì˜ íœ´ëŒ€ì „í™” ê¸°ëŠ¥ì„ ì œì–´í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê¶Œí•œì„ ê°–ëŠ” ì‘ìš©í”„ë¡œê·¸ëž¨ì€ ì‚¬ìš©ìžì—게 알리지 ì•Šê³  네트워í¬ë¥¼ 전환하거나 휴대전화 무선 ê¸°ëŠ¥ì„ ì¼œê³  ë„는 ë“±ì˜ ìž‘ì—…ì„ ìˆ˜í–‰í•  수 있습니다."</string>
+ <string name="permlab_readPhoneState">"휴대전화 ìƒíƒœ ì½ê¸°"</string>
+ <string name="permdesc_readPhoneState">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ìž¥ì¹˜ì˜ íœ´ëŒ€ì „í™” ê¸°ëŠ¥ì— ì•¡ì„¸ìŠ¤í•  수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê¶Œí•œì„ ê°–ëŠ” ì‘ìš©í”„ë¡œê·¸ëž¨ì€ íœ´ëŒ€ì „í™”ì˜ ì „í™”ë²ˆí˜¸, 통화가 활성ì¸ì§€ 여부, 해당 통화가 ì—°ê²°ëœ ë²ˆí˜¸ ë“±ì„ í™•ì¸í•  수 있습니다."</string>
+ <string name="permlab_wakeLock">"휴대전화가 절전 모드로 전환ë˜ì§€ ì•Šë„ë¡ ì„¤ì •"</string>
+ <string name="permdesc_wakeLock">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ê°€ 절전 모드로 전환ë˜ì§€ ì•Šë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_devicePower">"휴대전화 ì „ì› ì¼œê³  ë„기"</string>
+ <string name="permdesc_devicePower">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ë¥¼ 켜거나 ëŒ ìˆ˜ 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_factoryTest">"출고 테스트 모드로 실행"</string>
+ <string name="permdesc_factoryTest">"휴대전화 í•˜ë“œì›¨ì–´ì— ëŒ€í•œ 완전한 액세스를 허용하는 하위 ìˆ˜ì¤€ì˜ ì œì¡°ì—…ì²´ 테스트로 실행ë©ë‹ˆë‹¤. 휴대전화가 제조업체 테스트 모드로 실행 ì¤‘ì¼ ë•Œë§Œ 사용할 수 있습니다."</string>
+ <string name="permlab_setWallpaper">"배경화면 설정"</string>
+ <string name="permdesc_setWallpaper">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ ë°°ê²½í™”ë©´ì„ ì„¤ì •í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_setWallpaperHints">"배경화면 í¬ê¸° 힌트 설정"</string>
+ <string name="permdesc_setWallpaperHints">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‹œìŠ¤í…œ 배경화면 í¬ê¸° 힌트를 설정할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_masterClear">"ì‹œìŠ¤í…œì„ ê¸°ë³¸ê°’ìœ¼ë¡œ 재설정"</string>
+ <string name="permdesc_masterClear">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ëª¨ë“  ë°ì´í„°, 구성 ë° ì„¤ì¹˜ëœ ì‘ìš©í”„ë¡œê·¸ëž¨ì„ ì§€ì›Œì„œ ì‹œìŠ¤í…œì„ ì™„ì „ížˆ 초기화할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_setTimeZone">"표준시간대 설정"</string>
+ <string name="permdesc_setTimeZone">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì˜ í‘œì¤€ì‹œê°„ëŒ€ë¥¼ 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_getAccounts">"알려진 계정 검색"</string>
+ <string name="permdesc_getAccounts">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ íœ´ëŒ€ì „í™”ì— ì•Œë ¤ì§„ 계정 목ë¡ì„ 가져올 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_accessNetworkState">"ë„¤íŠ¸ì›Œí¬ ìƒíƒœ 보기"</string>
+ <string name="permdesc_accessNetworkState">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ëª¨ë“  네트워í¬ì˜ ìƒíƒœë¥¼ ë³¼ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_createNetworkSockets">"ì¸í„°ë„·ì— 완전히 액세스"</string>
+ <string name="permdesc_createNetworkSockets">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë„¤íŠ¸ì›Œí¬ ì†Œì¼“ì„ ë§Œë“¤ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_writeApnSettings">"액세스í¬ì¸íŠ¸ ì´ë¦„ 설정 쓰기"</string>
+ <string name="permdesc_writeApnSettings">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ APNì˜ í”„ë¡ì‹œ ë° í¬íŠ¸ ê°™ì€ APN ì„¤ì •ì„ ìˆ˜ì •í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_changeNetworkState">"ë„¤íŠ¸ì›Œí¬ ì—°ê²° 변경"</string>
+ <string name="permdesc_changeNetworkState">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë„¤íŠ¸ì›Œí¬ ì—°ê²° ìƒíƒœë¥¼ 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_changeBackgroundDataSetting">"백그ë¼ìš´ë“œ ë°ì´í„° 사용 설정 변경"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë°±ê·¸ë¼ìš´ë“œ ë°ì´í„° 사용 ì„¤ì •ì„ ë³€ê²½í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_accessWifiState">"Wi-Fi ìƒíƒœ 보기"</string>
+ <string name="permdesc_accessWifiState">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ Wi-Fiì˜ ìƒíƒœì— 대한 정보를 ë³¼ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_changeWifiState">"Wi-Fi ìƒíƒœ 변경"</string>
+ <string name="permdesc_changeWifiState">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ Wi-Fi 액세스í¬ì¸íŠ¸ì— 연결하거나 ì—°ê²°ì„ ëŠê³ , êµ¬ì„±ëœ Wi-Fi 네트워í¬ë¥¼ 변경할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth 관리"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë¡œì»¬ Bluetooth 휴대전화를 구성한 ë‹¤ìŒ ì›ê²© 장치를 검색하여 페어ë§í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth 연결 만들기"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë¡œì»¬ Bluetooth ì „í™”ì˜ êµ¬ì„±ì„ ë³´ê³  페어ë§ëœ ìž¥ì¹˜ì— ì—°ê²°í•˜ë©° ì—°ê²°ì„ ìˆ˜ë½í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"키 잠금 사용 중지"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í‚¤ 잠금 ë° ê´€ë ¨ 비밀번호 ë³´ì•ˆì„ ì‚¬ìš© 중지할 수 있ë„ë¡ í•©ë‹ˆë‹¤. 예를 들어, 휴대전화가 수신전화를 ë°›ì„ ë•Œ 키 ìž ê¸ˆì„ ì‚¬ìš© 중지했다가 통화가 ë나면 키 ìž ê¸ˆì„ ë‹¤ì‹œ 사용할 수 있습니다."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ë™ê¸°í™” 설정 ì½ê¸°"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì£¼ì†Œë¡ì— ë™ê¸°í™”를 사용할지 여부와 ê°™ì€ ë™ê¸°í™” ì„¤ì •ì„ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"ë™ê¸°í™” 설정 쓰기"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì£¼ì†Œë¡ì— 대해 ë™ê¸°í™”를 사용할지 여부 ë“±ì˜ ë™ê¸°í™” ì„¤ì •ì„ ìˆ˜ì •í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"ë™ê¸°í™” 통계 ì½ê¸°"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë™ê¸°í™” 통계(예: ì‹¤í–‰ëœ ë™ê¸°í™” 기ë¡)ì„ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ê°€ìž…ëœ í”¼ë“œ ì½ê¸°"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í˜„ìž¬ ë™ê¸°í™”ëœ í”¼ë“œì— ëŒ€í•œ 세부정보를 가져올 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"가입 피드 작성"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í˜„ìž¬ ë™ê¸°í™”ëœ í”¼ë“œë¥¼ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë™ê¸°í™”ëœ í”¼ë“œë¥¼ 변경할 수 있습니다."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"ì‚¬ìš©ìž ì •ì˜ ì‚¬ì „ ì½ê¸°"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìž ì‚¬ì „ì— ë³´ê´€ë˜ì–´ 있는 비공개 단어, ì´ë¦„ ë° êµ¬ë¬¸ì„ ì½ë„ë¡ í•©ë‹ˆë‹¤."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"ìƒìš©ìž ì •ì˜ ì‚¬ì „ì— ìž‘ì„±"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìž ì‚¬ì „ì— ìƒˆ 단어를 입력할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_bluetoothAdmin">"Bluetooth 관리"</string>
+ <string name="permdesc_bluetoothAdmin">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë¡œì»¬ Bluetooth 휴대전화를 구성한 ë‹¤ìŒ ì›ê²© 장치를 검색하여 페어ë§í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_bluetooth">"Bluetooth 연결 만들기"</string>
+ <string name="permdesc_bluetooth">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë¡œì»¬ Bluetooth ì „í™”ì˜ êµ¬ì„±ì„ ë³´ê³  페어ë§ëœ ìž¥ì¹˜ì— ì—°ê²°í•˜ë©° ì—°ê²°ì„ ìˆ˜ë½í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_disableKeyguard">"키 잠금 사용 중지"</string>
+ <string name="permdesc_disableKeyguard">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í‚¤ 잠금 ë° ê´€ë ¨ 비밀번호 ë³´ì•ˆì„ ì‚¬ìš© 중지할 수 있ë„ë¡ í•©ë‹ˆë‹¤. 예를 들어, 휴대전화가 수신전화를 ë°›ì„ ë•Œ 키 ìž ê¸ˆì„ ì‚¬ìš© 중지했다가 통화가 ë나면 키 ìž ê¸ˆì„ ë‹¤ì‹œ 사용할 수 있습니다."</string>
+ <string name="permlab_readSyncSettings">"ë™ê¸°í™” 설정 ì½ê¸°"</string>
+ <string name="permdesc_readSyncSettings">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì£¼ì†Œë¡ì— ë™ê¸°í™”를 사용할지 여부와 ê°™ì€ ë™ê¸°í™” ì„¤ì •ì„ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_writeSyncSettings">"ë™ê¸°í™” 설정 쓰기"</string>
+ <string name="permdesc_writeSyncSettings">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì£¼ì†Œë¡ì— 대해 ë™ê¸°í™”를 사용할지 여부 ë“±ì˜ ë™ê¸°í™” ì„¤ì •ì„ ìˆ˜ì •í•  수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_readSyncStats">"ë™ê¸°í™” 통계 ì½ê¸°"</string>
+ <string name="permdesc_readSyncStats">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë™ê¸°í™” 통계(예: ì‹¤í–‰ëœ ë™ê¸°í™” 기ë¡)ì„ ì½ì„ 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_subscribedFeedsRead">"ê°€ìž…ëœ í”¼ë“œ ì½ê¸°"</string>
+ <string name="permdesc_subscribedFeedsRead">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í˜„ìž¬ ë™ê¸°í™”ëœ í”¼ë“œì— ëŒ€í•œ 세부정보를 가져올 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_subscribedFeedsWrite">"가입 피드 작성"</string>
+ <string name="permdesc_subscribedFeedsWrite">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ í˜„ìž¬ ë™ê¸°í™”ëœ í”¼ë“œë¥¼ 수정할 수 있ë„ë¡ í•©ë‹ˆë‹¤. ì´ ê²½ìš° 악성 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ë™ê¸°í™”ëœ í”¼ë“œë¥¼ 변경할 수 있습니다."</string>
+ <string name="permlab_readDictionary">"ì‚¬ìš©ìž ì •ì˜ ì‚¬ì „ ì½ê¸°"</string>
+ <string name="permdesc_readDictionary">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìž ì‚¬ì „ì— ë³´ê´€ë˜ì–´ 있는 비공개 단어, ì´ë¦„ ë° êµ¬ë¬¸ì„ ì½ë„ë¡ í•©ë‹ˆë‹¤."</string>
+ <string name="permlab_writeDictionary">"ìƒìš©ìž ì •ì˜ ì‚¬ì „ì— ìž‘ì„±"</string>
+ <string name="permdesc_writeDictionary">"ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì‚¬ìš©ìž ì‚¬ì „ì— ìƒˆ 단어를 입력할 수 있ë„ë¡ í•©ë‹ˆë‹¤."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"집"</item>
- <item msgid="869923650527136615">"모바ì¼"</item>
- <item msgid="7897544654242874543">"회사"</item>
- <item msgid="1103601433382158155">"회사 팩스"</item>
- <item msgid="1735177144948329370">"집(팩스)"</item>
- <item msgid="603878674477207394">"호출기"</item>
- <item msgid="1650824275177931637">"기타"</item>
- <item msgid="9192514806975898961">"맞춤설정"</item>
+ <item>"집"</item>
+ <item>"모바ì¼"</item>
+ <item>"회사"</item>
+ <item>"회사 팩스"</item>
+ <item>"집(팩스)"</item>
+ <item>"호출기"</item>
+ <item>"기타"</item>
+ <item>"맞춤설정"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"집"</item>
- <item msgid="7084237356602625604">"회사"</item>
- <item msgid="1112044410659011023">"기타"</item>
- <item msgid="2374913952870110618">"맞춤설정"</item>
+ <item>"집"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"맞춤설정"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"모바ì¼"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"집"</item>
- <item msgid="5629153956045109251">"회사"</item>
- <item msgid="4966604264500343469">"기타"</item>
- <item msgid="4932682847595299369">"맞춤설정"</item>
+ <item>"집"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"맞춤설정"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"집"</item>
- <item msgid="1359644565647383708">"회사"</item>
- <item msgid="7868549401053615677">"기타"</item>
- <item msgid="3145118944639869809">"맞춤설정"</item>
+ <item>"집"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"맞춤설정"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"회사"</item>
- <item msgid="4378074129049520373">"기타"</item>
- <item msgid="3455047468583965104">"맞춤설정"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"맞춤설정"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google 토í¬"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google 토í¬"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN 코드 입력"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"PIN 코드가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"잠금해제하려면 메뉴를 누른 ë‹¤ìŒ 0ì„ ëˆ„ë¦…ë‹ˆë‹¤."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ë¹„ìƒ ì „í™”ë²ˆí˜¸"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(서비스 안ë¨)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"화면 잠김"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ë¹„ìƒ ì „í™”ë¥¼ 걸거나 잠금해제하려면 메뉴를 누르세요."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"잠금해제하려면 메뉴를 누르세요."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"잠금해제를 위해 패턴 그리기"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"ë¹„ìƒ ì „í™”"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"맞습니다."</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"죄송합니다. 다시 ì‹œë„하세요."</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"충전 중(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"PIN 코드 입력"</string>
+ <string name="keyguard_password_wrong_pin_code">"PIN 코드가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="keyguard_label_text">"잠금해제하려면 메뉴를 누른 ë‹¤ìŒ 0ì„ ëˆ„ë¦…ë‹ˆë‹¤."</string>
+ <string name="emergency_call_dialog_number_for_display">"ë¹„ìƒ ì „í™”ë²ˆí˜¸"</string>
+ <string name="lockscreen_carrier_default">"(서비스 안ë¨)"</string>
+ <string name="lockscreen_screen_locked">"화면 잠김"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"ë¹„ìƒ ì „í™”ë¥¼ 걸거나 잠금해제하려면 메뉴를 누르세요."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"잠금해제하려면 메뉴를 누르세요."</string>
+ <string name="lockscreen_pattern_instructions">"잠금해제를 위해 패턴 그리기"</string>
+ <string name="lockscreen_emergency_call">"ë¹„ìƒ ì „í™”"</string>
+ <string name="lockscreen_pattern_correct">"맞습니다."</string>
+ <string name="lockscreen_pattern_wrong">"죄송합니다. 다시 ì‹œë„하세요."</string>
+ <string name="lockscreen_plugged_in">"충전 중(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"충전기를 연결하세요."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"SIM 카드가 없습니다."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"íœ´ëŒ€ì „í™”ì— SIM 카드가 없습니다."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"SIM 카드를 삽입하세요."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"ë„¤íŠ¸ì›Œí¬ ìž ê¹€"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM ì¹´ë“œì˜ PUKê°€ 잠겨 있습니다."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"ì‚¬ìš©ìž ê°€ì´ë“œë¥¼ 참조하거나 ê³ ê°ì§€ì›íŒ€ì— 문ì˜í•˜ì„¸ìš”."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM 카드가 잠겨 있습니다."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM 카드 잠금해제 중..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"잠금해제 íŒ¨í„´ì„ <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„하세요."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"잠금해제 íŒ¨í„´ì„ <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 ë” ì‹¤íŒ¨í•˜ë©´ Google 로그ì¸ì„ 통해 휴대전화를 잠금해제하ë„ë¡ ìš”ì²­ë©ë‹ˆë‹¤. "\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„하세요."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g>ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„하세요."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"íŒ¨í„´ì„ ìžŠìœ¼ì…¨ë‚˜ìš”?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"íŒ¨í„´ì„ ë„ˆë¬´ ë§Žì´ ì‹œë„했습니다."</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"잠금해제하려면 Google 계정으로 로그ì¸í•˜ì„¸ìš”."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"ì‚¬ìš©ìž ì´ë¦„(ì´ë©”ì¼)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"비밀번호"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"로그ì¸"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ì‚¬ìš©ìž ì´ë¦„ ë˜ëŠ” 비밀번호가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"충전기를 연결하세요."</string>
+ <string name="lockscreen_missing_sim_message_short">"SIM 카드가 없습니다."</string>
+ <string name="lockscreen_missing_sim_message">"íœ´ëŒ€ì „í™”ì— SIM 카드가 없습니다."</string>
+ <string name="lockscreen_missing_sim_instructions">"SIM 카드를 삽입하세요."</string>
+ <string name="lockscreen_network_locked_message">"ë„¤íŠ¸ì›Œí¬ ìž ê¹€"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM ì¹´ë“œì˜ PUKê°€ 잠겨 있습니다."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"ì‚¬ìš©ìž ê°€ì´ë“œë¥¼ 참조하거나 ê³ ê°ì§€ì›íŒ€ì— 문ì˜í•˜ì„¸ìš”."</string>
+ <string name="lockscreen_sim_locked_message">"SIM 카드가 잠겨 있습니다."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM 카드 잠금해제 중..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"잠금해제 íŒ¨í„´ì„ <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„하세요."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"잠금해제 íŒ¨í„´ì„ <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 ë” ì‹¤íŒ¨í•˜ë©´ Google 로그ì¸ì„ 통해 휴대전화를 잠금해제하ë„ë¡ ìš”ì²­ë©ë‹ˆë‹¤. "\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„하세요."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g>ì´ˆ í›„ì— ë‹¤ì‹œ ì‹œë„하세요."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"íŒ¨í„´ì„ ìžŠìœ¼ì…¨ë‚˜ìš”?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"íŒ¨í„´ì„ ë„ˆë¬´ ë§Žì´ ì‹œë„했습니다."</string>
+ <string name="lockscreen_glogin_instructions">"잠금해제하려면 Google 계정으로 로그ì¸í•˜ì„¸ìš”."</string>
+ <string name="lockscreen_glogin_username_hint">"ì‚¬ìš©ìž ì´ë¦„(ì´ë©”ì¼)"</string>
+ <string name="lockscreen_glogin_password_hint">"비밀번호"</string>
+ <string name="lockscreen_glogin_submit_button">"로그ì¸"</string>
+ <string name="lockscreen_glogin_invalid_input">"ì‚¬ìš©ìž ì´ë¦„ ë˜ëŠ” 비밀번호가 잘못ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"알림 ì—†ìŒ"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"진행 중"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"충전 중..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"충전기를 연결하세요."</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"배터리 ì „ì›ì´ 부족합니다."</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"<xliff:g id="NUMBER">%d%%</xliff:g> 미만 남ìŒ"</string>
+ <string name="status_bar_no_notifications_title">"알림 ì—†ìŒ"</string>
+ <string name="status_bar_ongoing_events_title">"진행 중"</string>
+ <string name="status_bar_latest_events_title">"알림"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"충전 중..."</string>
+ <string name="battery_low_title">"충전기를 연결하세요."</string>
+ <string name="battery_low_subtitle">"배터리 ì „ì›ì´ 부족합니다."</string>
+ <string name="battery_low_percent_format">"<xliff:g id="NUMBER">%d%%</xliff:g> 미만 남ìŒ"</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"출고 테스트 불합격"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"FACTORY_TEST ìž‘ì—…ì€ /system/app ë””ë ‰í† ë¦¬ì— ì„¤ì¹˜ëœ íŒ¨í‚¤ì§€ì— ëŒ€í•´ì„œë§Œ 지ì›ë©ë‹ˆë‹¤."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"FACTORY_TEST ìž‘ì—…ì„ ì œê³µí•˜ëŠ” 패키지가 없습니다."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"다시 부팅"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"\'<xliff:g id="TITLE">%s</xliff:g>\' 페ì´ì§€ ë‚´ìš©:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"ìžë°”스í¬ë¦½íŠ¸"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"다른 페ì´ì§€ë¥¼ íƒìƒ‰í•˜ì‹œê² ìŠµë‹ˆê¹Œ?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"계ì†í•˜ë ¤ë©´ \'확ì¸\'ì„ ì„ íƒí•˜ê³  현재 페ì´ì§€ì— 그대로 있으려면 \'취소\'를 ì„ íƒí•˜ì„¸ìš”."</string>
- <string name="save_password_label" msgid="6860261758665825069">"확ì¸"</string>
+ <string name="factorytest_failed">"출고 테스트 불합격"</string>
+ <string name="factorytest_not_system">"FACTORY_TEST ìž‘ì—…ì€ /system/app ë””ë ‰í† ë¦¬ì— ì„¤ì¹˜ëœ íŒ¨í‚¤ì§€ì— ëŒ€í•´ì„œë§Œ 지ì›ë©ë‹ˆë‹¤."</string>
+ <string name="factorytest_no_action">"FACTORY_TEST ìž‘ì—…ì„ ì œê³µí•˜ëŠ” 패키지가 없습니다."</string>
+ <string name="factorytest_reboot">"다시 부팅"</string>
+ <string name="js_dialog_title">"\'<xliff:g id="TITLE">%s</xliff:g>\' 페ì´ì§€ ë‚´ìš©:"</string>
+ <string name="js_dialog_title_default">"ìžë°”스í¬ë¦½íŠ¸"</string>
+ <string name="js_dialog_before_unload">"다른 페ì´ì§€ë¥¼ íƒìƒ‰í•˜ì‹œê² ìŠµë‹ˆê¹Œ?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"계ì†í•˜ë ¤ë©´ \'확ì¸\'ì„ ì„ íƒí•˜ê³  현재 페ì´ì§€ì— 그대로 있으려면 \'취소\'를 ì„ íƒí•˜ì„¸ìš”."</string>
+ <string name="save_password_label">"확ì¸"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"브ë¼ìš°ì €ì— ì´ ë¹„ë°€ë²ˆí˜¸ë¥¼ 저장하시겠습니까?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"나중ì—"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"저장"</string>
- <string name="save_password_never" msgid="8274330296785855105">"안함"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"페ì´ì§€ë¥¼ ì—´ 수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."</string>
- <string name="text_copied" msgid="4985729524670131385">"í…스트가 í´ë¦½ë³´ë“œì— 복사ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="more_item_label" msgid="4650918923083320495">"ë”보기"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"스페ì´ìŠ¤ë°”"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"ìž…ë ¥"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"삭제"</string>
- <string name="search_go" msgid="8298016669822141719">"검색"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"한 달 전"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"한 달 전"</string>
+ <string name="save_password_message">"브ë¼ìš°ì €ì— ì´ ë¹„ë°€ë²ˆí˜¸ë¥¼ 저장하시겠습니까?"</string>
+ <string name="save_password_notnow">"나중ì—"</string>
+ <string name="save_password_remember">"저장"</string>
+ <string name="save_password_never">"안함"</string>
+ <string name="open_permission_deny">"페ì´ì§€ë¥¼ ì—´ 수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."</string>
+ <string name="text_copied">"í…스트가 í´ë¦½ë³´ë“œì— 복사ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="more_item_label">"ë”보기"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"스페ì´ìŠ¤ë°”"</string>
+ <string name="menu_enter_shortcut_label">"ìž…ë ¥"</string>
+ <string name="menu_delete_shortcut_label">"삭제"</string>
+ <string name="search_go">"검색"</string>
+ <string name="oneMonthDurationPast">"한 달 전"</string>
+ <string name="beforeOneMonthDurationPast">"한 달 전"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1ì´ˆ ì „"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>ì´ˆ ì „"</item>
+ <item quantity="one">"1ì´ˆ ì „"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>ì´ˆ ì „"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1분 전"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
+ <item quantity="one">"1분 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1시간 전"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
+ <item quantity="one">"1시간 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"어제"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>ì¼ ì „"</item>
+ <item quantity="one">"어제"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>ì¼ ì „"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1ì´ˆ ë‚´"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
+ <item quantity="one">"1ì´ˆ ë‚´"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1분 후"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
+ <item quantity="one">"1분 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1시간 후"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
+ <item quantity="one">"1시간 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"ë‚´ì¼"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g>ì¼ í›„"</item>
+ <item quantity="one">"ë‚´ì¼"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>ì¼ í›„"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1ì´ˆ ì „"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>ì´ˆ ì „"</item>
+ <item quantity="one">"1ì´ˆ ì „"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>ì´ˆ ì „"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1분 전"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
+ <item quantity="one">"1분 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1시간 전"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
+ <item quantity="one">"1시간 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"어제"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>ì¼ ì „"</item>
+ <item quantity="one">"어제"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>ì¼ ì „"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1초 후"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
+ <item quantity="one">"1초 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1분 후"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
+ <item quantity="one">"1분 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1시간 후"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
+ <item quantity="one">"1시간 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"ë‚´ì¼"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g>ì¼ í›„"</item>
+ <item quantity="one">"ë‚´ì¼"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>ì¼ í›„"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%së…„"</string>
- <string name="day" msgid="8144195776058119424">"ì¼"</string>
- <string name="days" msgid="4774547661021344602">"ì¼"</string>
- <string name="hour" msgid="2126771916426189481">"시간"</string>
- <string name="hours" msgid="894424005266852993">"시간"</string>
- <string name="minute" msgid="9148878657703769868">"분"</string>
- <string name="minutes" msgid="5646001005827034509">"분"</string>
- <string name="second" msgid="3184235808021478">"ì´ˆ"</string>
- <string name="seconds" msgid="3161515347216589235">"ì´ˆ"</string>
- <string name="week" msgid="5617961537173061583">"주"</string>
- <string name="weeks" msgid="6509623834583944518">"주"</string>
- <string name="year" msgid="4001118221013892076">"ë…„"</string>
- <string name="years" msgid="6881577717993213522">"ë…„"</string>
- <string name="every_weekday" msgid="8777593878457748503">"주중 매ì¼(ì›”-금)"</string>
- <string name="daily" msgid="5738949095624133403">"매ì¼"</string>
- <string name="weekly" msgid="983428358394268344">"매주 <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"매월"</string>
- <string name="yearly" msgid="1519577999407493836">"매년"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"ë™ì˜ìƒ ìž¬ìƒ ì•ˆë¨"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"죄송합니다. ì´ ê¸°ê¸°ë¡œì˜ ìŠ¤íŠ¸ë¦¬ë°ì— ì í•©í•˜ì§€ ì•Šì€ ë™ì˜ìƒìž…니다."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"죄송합니다. ë™ì˜ìƒì„ 재ìƒí•  수 없습니다."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"확ì¸"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"정오"</string>
- <string name="Noon" msgid="3342127745230013127">"정오"</string>
- <string name="midnight" msgid="7166259508850457595">"ìžì •"</string>
- <string name="Midnight" msgid="5630806906897892201">"ìžì •"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"ëª¨ë‘ ì„ íƒ"</string>
- <string name="selectText" msgid="3889149123626888637">"í…스트 ì„ íƒ"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"í…스트 ì„ íƒ ì¤‘ì§€"</string>
- <string name="cut" msgid="3092569408438626261">"잘ë¼ë‚´ê¸°"</string>
- <string name="cutAll" msgid="2436383270024931639">"ëª¨ë‘ ìž˜ë¼ë‚´ê¸°"</string>
- <string name="copy" msgid="2681946229533511987">"복사"</string>
- <string name="copyAll" msgid="2590829068100113057">"ëª¨ë‘ ë³µì‚¬"</string>
- <string name="paste" msgid="5629880836805036433">"붙여넣기"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URL 복사"</string>
- <string name="inputMethod" msgid="7673923508389094672">"입력 방법"</string>
- <string name="addToDictionary" msgid="726256909274177272">"ì‚¬ì „ì— \'%s\' 추가"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"í…스트 수정"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"저장공간 부족"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"휴대전화 ì €ìž¥ê³µê°„ì´ ë¶€ì¡±í•©ë‹ˆë‹¤."</string>
- <string name="ok" msgid="5970060430562524910">"확ì¸"</string>
- <string name="cancel" msgid="6442560571259935130">"취소"</string>
- <string name="yes" msgid="5362982303337969312">"확ì¸"</string>
- <string name="no" msgid="5141531044935541497">"취소"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"주ì˜"</string>
- <string name="capital_on" msgid="1544682755514494298">"사용"</string>
- <string name="capital_off" msgid="6815870386972805832">"사용 안함"</string>
- <string name="whichApplication" msgid="4533185947064773386">"ìž‘ì—…ì„ ìˆ˜í–‰í•  ë•Œ 사용하는 ì‘용프로그램"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"ì´ ìž‘ì—…ì— ëŒ€í•´ 기본값으로 사용"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"홈 설정 &gt; ì‘용프로그램 &gt; ì‘용프로그램 관리ì—ì„œ ê¸°ë³¸ê°’ì„ ì§€ì›ë‹ˆë‹¤."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"ìž‘ì—… ì„ íƒ"</string>
- <string name="noApplications" msgid="1691104391758345586">"ìž‘ì—…ì„ ìˆ˜í–‰í•  수 있는 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì—†ìŠµë‹ˆë‹¤."</string>
- <string name="aerr_title" msgid="653922989522758100">"죄송합니다."</string>
- <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> ì‘용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)ì´ ì˜ˆìƒì¹˜ 않게 중지ë˜ì—ˆìŠµë‹ˆë‹¤. 다시 ì‹œë„í•´ 주세요."</string>
- <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 예ìƒì¹˜ 않게 중지ë˜ì—ˆìŠµë‹ˆë‹¤. 다시 ì‹œë„í•´ 주세요."</string>
- <string name="anr_title" msgid="3100070910664756057">"죄송합니다."</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="APPLICATION">%2$s</xliff:g> 활ë™(<xliff:g id="ACTIVITY">%1$s</xliff:g> ì‘용프로그램)ì´ ì‘답하지 않습니다."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 활ë™(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)ì´ ì‘답하지 않습니다."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g> ì‘용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)ì´ ì‘답하지 않습니다."</string>
- <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 ì‘답하지 않습니다."</string>
- <string name="force_close" msgid="3653416315450806396">"닫기"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"%së…„"</string>
+ <string name="day">"ì¼"</string>
+ <string name="days">"ì¼"</string>
+ <string name="hour">"시간"</string>
+ <string name="hours">"시간"</string>
+ <string name="minute">"분"</string>
+ <string name="minutes">"분"</string>
+ <string name="second">"ì´ˆ"</string>
+ <string name="seconds">"ì´ˆ"</string>
+ <string name="week">"주"</string>
+ <string name="weeks">"주"</string>
+ <string name="year">"ë…„"</string>
+ <string name="years">"ë…„"</string>
+ <string name="every_weekday">"주중 매ì¼(ì›”-금)"</string>
+ <string name="daily">"매ì¼"</string>
+ <string name="weekly">"매주 <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"매월"</string>
+ <string name="yearly">"매년"</string>
+ <string name="VideoView_error_title">"ë™ì˜ìƒ ìž¬ìƒ ì•ˆë¨"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"죄송합니다. ì´ ê¸°ê¸°ë¡œì˜ ìŠ¤íŠ¸ë¦¬ë°ì— ì í•©í•˜ì§€ ì•Šì€ ë™ì˜ìƒìž…니다."</string>
+ <string name="VideoView_error_text_unknown">"죄송합니다. ë™ì˜ìƒì„ 재ìƒí•  수 없습니다."</string>
+ <string name="VideoView_error_button">"확ì¸"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"정오"</string>
+ <string name="Noon">"정오"</string>
+ <string name="midnight">"ìžì •"</string>
+ <string name="Midnight">"ìžì •"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"ëª¨ë‘ ì„ íƒ"</string>
+ <string name="selectText">"í…스트 ì„ íƒ"</string>
+ <string name="stopSelectingText">"í…스트 ì„ íƒ ì¤‘ì§€"</string>
+ <string name="cut">"잘ë¼ë‚´ê¸°"</string>
+ <string name="cutAll">"ëª¨ë‘ ìž˜ë¼ë‚´ê¸°"</string>
+ <string name="copy">"복사"</string>
+ <string name="copyAll">"ëª¨ë‘ ë³µì‚¬"</string>
+ <string name="paste">"붙여넣기"</string>
+ <string name="copyUrl">"URL 복사"</string>
+ <string name="inputMethod">"입력 방법"</string>
+ <string name="addToDictionary">"ì‚¬ì „ì— \'%s\' 추가"</string>
+ <string name="editTextMenuTitle">"í…스트 수정"</string>
+ <string name="low_internal_storage_view_title">"저장공간 부족"</string>
+ <string name="low_internal_storage_view_text">"휴대전화 ì €ìž¥ê³µê°„ì´ ë¶€ì¡±í•©ë‹ˆë‹¤."</string>
+ <string name="ok">"확ì¸"</string>
+ <string name="cancel">"취소"</string>
+ <string name="yes">"확ì¸"</string>
+ <string name="no">"취소"</string>
+ <string name="dialog_alert_title">"주ì˜"</string>
+ <string name="capital_on">"사용"</string>
+ <string name="capital_off">"사용 안함"</string>
+ <string name="whichApplication">"ìž‘ì—…ì„ ìˆ˜í–‰í•  ë•Œ 사용하는 ì‘용프로그램"</string>
+ <string name="alwaysUse">"ì´ ìž‘ì—…ì— ëŒ€í•´ 기본값으로 사용"</string>
+ <string name="clearDefaultHintMsg">"홈 설정 &gt; ì‘용프로그램 &gt; ì‘용프로그램 관리ì—ì„œ ê¸°ë³¸ê°’ì„ ì§€ì›ë‹ˆë‹¤."</string>
+ <string name="chooseActivity">"ìž‘ì—… ì„ íƒ"</string>
+ <string name="noApplications">"ìž‘ì—…ì„ ìˆ˜í–‰í•  수 있는 ì‘ìš©í”„ë¡œê·¸ëž¨ì´ ì—†ìŠµë‹ˆë‹¤."</string>
+ <string name="aerr_title">"죄송합니다."</string>
+ <string name="aerr_application">"<xliff:g id="APPLICATION">%1$s</xliff:g> ì‘용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)ì´ ì˜ˆìƒì¹˜ 않게 중지ë˜ì—ˆìŠµë‹ˆë‹¤. 다시 ì‹œë„í•´ 주세요."</string>
+ <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 예ìƒì¹˜ 않게 중지ë˜ì—ˆìŠµë‹ˆë‹¤. 다시 ì‹œë„í•´ 주세요."</string>
+ <string name="anr_title">"죄송합니다."</string>
+ <string name="anr_activity_application">"<xliff:g id="APPLICATION">%2$s</xliff:g> 활ë™(<xliff:g id="ACTIVITY">%1$s</xliff:g> ì‘용프로그램)ì´ ì‘답하지 않습니다."</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 활ë™(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)ì´ ì‘답하지 않습니다."</string>
+ <string name="anr_application_process">"<xliff:g id="APPLICATION">%1$s</xliff:g> ì‘용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)ì´ ì‘답하지 않습니다."</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 ì‘답하지 않습니다."</string>
+ <string name="force_close">"닫기"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"대기"</string>
- <string name="debug" msgid="9103374629678531849">"디버그"</string>
- <string name="sendText" msgid="5132506121645618310">"í…ìŠ¤íŠ¸ì— ëŒ€í•œ ìž‘ì—… ì„ íƒ"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"벨소리 볼륨"</string>
- <string name="volume_music" msgid="5421651157138628171">"미디어 볼륨"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Bluetooth를 통해 재ìƒ"</string>
- <string name="volume_call" msgid="3941680041282788711">"통화 볼륨"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth 통화 볼륨"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"알람 볼륨"</string>
- <string name="volume_notification" msgid="2422265656744276715">"알림 볼륨"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"볼륨"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"기본 벨소리"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"기본 벨소리(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"무ìŒ"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"벨소리"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"알 수 없는 벨소리"</string>
+ <string name="wait">"대기"</string>
+ <string name="debug">"디버그"</string>
+ <string name="sendText">"í…ìŠ¤íŠ¸ì— ëŒ€í•œ ìž‘ì—… ì„ íƒ"</string>
+ <string name="volume_ringtone">"벨소리 볼륨"</string>
+ <string name="volume_music">"미디어 볼륨"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Bluetooth를 통해 재ìƒ"</string>
+ <string name="volume_call">"통화 볼륨"</string>
+ <string name="volume_bluetooth_call">"Bluetooth 통화 볼륨"</string>
+ <string name="volume_alarm">"알람 볼륨"</string>
+ <string name="volume_notification">"알림 볼륨"</string>
+ <string name="volume_unknown">"볼륨"</string>
+ <string name="ringtone_default">"기본 벨소리"</string>
+ <string name="ringtone_default_with_actual">"기본 벨소리(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"무ìŒ"</string>
+ <string name="ringtone_picker_title">"벨소리"</string>
+ <string name="ringtone_unknown">"알 수 없는 벨소리"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fi ë„¤íŠ¸ì›Œí¬ ì‚¬ìš© 가능"</item>
- <item quantity="other" msgid="4192424489168397386">"Wi-Fi ë„¤íŠ¸ì›Œí¬ ì‚¬ìš© 가능"</item>
+ <item quantity="one">"Wi-Fi ë„¤íŠ¸ì›Œí¬ ì‚¬ìš© 가능"</item>
+ <item quantity="other">"Wi-Fi ë„¤íŠ¸ì›Œí¬ ì‚¬ìš© 가능"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"개방형 Wi-Fi ë„¤íŠ¸ì›Œí¬ ì‚¬ìš© 가능"</item>
- <item quantity="other" msgid="7915895323644292768">"개방형 Wi-Fi ë„¤íŠ¸ì›Œí¬ ì‚¬ìš© 가능"</item>
+ <item quantity="one">"개방형 Wi-Fi ë„¤íŠ¸ì›Œí¬ ì‚¬ìš© 가능"</item>
+ <item quantity="other">"개방형 Wi-Fi ë„¤íŠ¸ì›Œí¬ ì‚¬ìš© 가능"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"ë¬¸ìž ì‚½ìž…"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"ì•Œ 수 없는 ì‘용프로그램"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"SMS 메시지를 보내는 중"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"여러 ê°œì˜ SMS 메시지를 보내는 중입니다. 계ì†í•˜ë ¤ë©´ \'확ì¸\'ì„ ì„ íƒí•˜ê³  ì „ì†¡ì„ ì¤‘ì§€í•˜ë ¤ë©´ \'취소\'를 ì„ íƒí•˜ì„¸ìš”."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"확ì¸"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"취소"</string>
- <string name="date_time_set" msgid="5777075614321087758">"설정"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"기본값"</string>
- <string name="no_permissions" msgid="7283357728219338112">"권한 í•„ìš” ì—†ìŒ"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"숨기기"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"ëª¨ë‘ í‘œì‹œ"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"로드 중..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB ì—°ê²°ë¨"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"USB를 통해 휴대전화를 ì»´í“¨í„°ì— ì—°ê²°í–ˆìŠµë‹ˆë‹¤. 컴퓨터와 휴대전화 SD ì¹´ë“œ ê°„ì— íŒŒì¼ì„ 복사하려면 \'마운트\'를 ì„ íƒí•˜ì„¸ìš”."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"마운트"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"마운트 안함"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"USB 저장소로 SD 카드를 사용하는 ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB ì—°ê²°ë¨"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"ì»´í“¨í„°ì— íŒŒì¼ì„ 복사하거나 ì»´í“¨í„°ì˜ íŒŒì¼ì„ 복사하려면 ì„ íƒí•©ë‹ˆë‹¤."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB 저장소 ë„기"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"USB 저장소 ë„기를 ì„ íƒí•˜ì„¸ìš”."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"USB 저장소 ë„기"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"USB 저장소를 ë„기 ì „ì— ë°˜ë“œì‹œ USB 호스트ì—ì„œ 마운트 해제하세요. USB 저장소를 ë„려면 \'ë„기\'를 ì„ íƒí•˜ì„¸ìš”."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"USB 저장소 ë„기"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"취소"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"USB 저장소를 ë„는 ë™ì•ˆ Weveì— ë¬¸ì œê°€ 발행했습니다. USB 호스트를 마운트 해제했는지 확ì¸í•œ 후 다시 ì‹œë„하세요."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"SD ì¹´ë“œ í¬ë§·"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"SD 카드를 í¬ë§·í•˜ì‹œê² ìŠµë‹ˆê¹Œ? í¬ë§·í•˜ë©´ ì¹´ë“œì˜ ëª¨ë“  ë°ì´í„°ë¥¼ 잃게 ë©ë‹ˆë‹¤."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"í¬ë§·"</string>
+ <string name="select_character">"ë¬¸ìž ì‚½ìž…"</string>
+ <string name="sms_control_default_app_name">"ì•Œ 수 없는 ì‘용프로그램"</string>
+ <string name="sms_control_title">"SMS 메시지를 보내는 중"</string>
+ <string name="sms_control_message">"여러 ê°œì˜ SMS 메시지를 보내는 중입니다. 계ì†í•˜ë ¤ë©´ \'확ì¸\'ì„ ì„ íƒí•˜ê³  ì „ì†¡ì„ ì¤‘ì§€í•˜ë ¤ë©´ \'취소\'를 ì„ íƒí•˜ì„¸ìš”."</string>
+ <string name="sms_control_yes">"확ì¸"</string>
+ <string name="sms_control_no">"취소"</string>
+ <string name="date_time_set">"설정"</string>
+ <string name="default_permission_group">"기본값"</string>
+ <string name="no_permissions">"권한 í•„ìš” ì—†ìŒ"</string>
+ <string name="perms_hide"><b>"숨기기"</b></string>
+ <string name="perms_show_all"><b>"ëª¨ë‘ í‘œì‹œ"</b></string>
+ <string name="googlewebcontenthelper_loading">"로드 중..."</string>
+ <string name="usb_storage_title">"USB ì—°ê²°ë¨"</string>
+ <string name="usb_storage_message">"USB를 통해 휴대전화를 ì»´í“¨í„°ì— ì—°ê²°í–ˆìŠµë‹ˆë‹¤. 컴퓨터와 휴대전화 SD ì¹´ë“œ ê°„ì— íŒŒì¼ì„ 복사하려면 \'마운트\'를 ì„ íƒí•˜ì„¸ìš”."</string>
+ <string name="usb_storage_button_mount">"마운트"</string>
+ <string name="usb_storage_button_unmount">"마운트 안함"</string>
+ <string name="usb_storage_error_message">"USB 저장소로 SD 카드를 사용하는 ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."</string>
+ <string name="usb_storage_notification_title">"USB ì—°ê²°ë¨"</string>
+ <string name="usb_storage_notification_message">"ì»´í“¨í„°ì— íŒŒì¼ì„ 복사하거나 ì»´í“¨í„°ì˜ íŒŒì¼ì„ 복사하려면 ì„ íƒí•©ë‹ˆë‹¤."</string>
+ <string name="usb_storage_stop_notification_title">"USB 저장소 ë„기"</string>
+ <string name="usb_storage_stop_notification_message">"USB 저장소 ë„기를 ì„ íƒí•˜ì„¸ìš”."</string>
+ <string name="usb_storage_stop_title">"USB 저장소 ë„기"</string>
+ <string name="usb_storage_stop_message">"USB 저장소를 ë„기 ì „ì— ë°˜ë“œì‹œ USB 호스트ì—ì„œ 마운트 해제하세요. USB 저장소를 ë„려면 \'ë„기\'를 ì„ íƒí•˜ì„¸ìš”."</string>
+ <string name="usb_storage_stop_button_mount">"USB 저장소 ë„기"</string>
+ <string name="usb_storage_stop_button_unmount">"취소"</string>
+ <string name="usb_storage_stop_error_message">"USB 저장소를 ë„는 ë™ì•ˆ Weveì— ë¬¸ì œê°€ 발행했습니다. USB 호스트를 마운트 해제했는지 확ì¸í•œ 후 다시 ì‹œë„하세요."</string>
+ <string name="extmedia_format_title">"SD ì¹´ë“œ í¬ë§·"</string>
+ <string name="extmedia_format_message">"SD 카드를 í¬ë§·í•˜ì‹œê² ìŠµë‹ˆê¹Œ? í¬ë§·í•˜ë©´ ì¹´ë“œì˜ ëª¨ë“  ë°ì´í„°ë¥¼ 잃게 ë©ë‹ˆë‹¤."</string>
+ <string name="extmedia_format_button_format">"í¬ë§·"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"ìž…ë ¥ 방법 ì„ íƒ"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 ì›ì¸"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SD 카드 준비 중"</string>
+ <string name="select_input_method">"ìž…ë ¥ 방법 ì„ íƒ"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"가능한 ì›ì¸"</u></string>
+ <string name="ext_media_checking_notification_title">"SD 카드 준비 중"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"빈 SD 카드"</string>
+ <string name="ext_media_nofs_notification_title">"빈 SD 카드"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"ì†ìƒëœ SD ì¹´ë“œ"</string>
+ <string name="ext_media_unmountable_notification_title">"ì†ìƒëœ SD ì¹´ë“œ"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD 카드가 예ìƒì¹˜ 않게 제거ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"ë°ì´í„° ì†ì‹¤ì„ 피하려면 SD 카드를 제거하기 ì „ì— ë§ˆìš´íŠ¸ 해제합니다."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SD 카드를 안전하게 제거할 수 있습니다."</string>
+ <string name="ext_media_badremoval_notification_title">"SD 카드가 예ìƒì¹˜ 않게 제거ë˜ì—ˆìŠµë‹ˆë‹¤."</string>
+ <string name="ext_media_badremoval_notification_message">"ë°ì´í„° ì†ì‹¤ì„ 피하려면 SD 카드를 제거하기 ì „ì— ë§ˆìš´íŠ¸ 해제합니다."</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD 카드를 안전하게 제거할 수 있습니다."</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SD 카드를 제거했습니다."</string>
+ <string name="ext_media_nomedia_notification_title">"SD 카드를 제거했습니다."</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"ì¼ì¹˜í•˜ëŠ” 활ë™ì´ 없습니다."</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"구성 요소 사용 통계 ì—…ë°ì´íŠ¸"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"ìˆ˜ì§‘ëœ êµ¬ì„±ìš”ì†Œ 사용 통계를 수정할 수 있는 ê¶Œí•œì„ ë¶€ì—¬í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘ìš©í”„ë¡œê·¸ëž¨ì€ ì´ ê¶Œí•œì„ ì‚¬ìš©í•  수 없습니다."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"확대/축소하려면 ë‘ ë²ˆ 탭하세요."</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"ìœ„ì ¯ì„ í™•ìž¥í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."</string>
- <string name="ime_action_go" msgid="8320845651737369027">"ì´ë™"</string>
- <string name="ime_action_search" msgid="658110271822807811">"검색"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"전송"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"다ìŒ"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"완료"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"실행"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"전화하기 "\n"<xliff:g id="NUMBER">%s</xliff:g>ì— ì—°ê²°"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"전화번호부ì—"\n"<xliff:g id="NUMBER">%s</xliff:g> 추가"</string>
+ <string name="activity_list_empty">"ì¼ì¹˜í•˜ëŠ” 활ë™ì´ 없습니다."</string>
+ <string name="permlab_pkgUsageStats">"구성 요소 사용 통계 ì—…ë°ì´íŠ¸"</string>
+ <string name="permdesc_pkgUsageStats">"ìˆ˜ì§‘ëœ êµ¬ì„±ìš”ì†Œ 사용 통계를 수정할 수 있는 ê¶Œí•œì„ ë¶€ì—¬í•©ë‹ˆë‹¤. ì¼ë°˜ ì‘ìš©í”„ë¡œê·¸ëž¨ì€ ì´ ê¶Œí•œì„ ì‚¬ìš©í•  수 없습니다."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"확대/축소하려면 ë‘ ë²ˆ 탭하세요."</string>
+ <string name="gadget_host_error_inflating">"ìœ„ì ¯ì„ í™•ìž¥í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."</string>
+ <string name="ime_action_go">"ì´ë™"</string>
+ <string name="ime_action_search">"검색"</string>
+ <string name="ime_action_send">"전송"</string>
+ <string name="ime_action_next">"다ìŒ"</string>
+ <string name="ime_action_done">"완료"</string>
+ <string name="ime_action_default">"실행"</string>
+ <string name="dial_number_using">"전화하기 "\n"<xliff:g id="NUMBER">%s</xliff:g>ì— ì—°ê²°"</string>
+ <string name="create_contact_using">"전화번호부ì—"\n"<xliff:g id="NUMBER">%s</xliff:g> 추가"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-mcc204-cs/strings.xml b/core/res/res/values-mcc204-cs/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-cs/strings.xml
+++ b/core/res/res/values-mcc204-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-da/strings.xml b/core/res/res/values-mcc204-da/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-da/strings.xml
+++ b/core/res/res/values-mcc204-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-de/strings.xml b/core/res/res/values-mcc204-de/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-de/strings.xml
+++ b/core/res/res/values-mcc204-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-el/strings.xml b/core/res/res/values-mcc204-el/strings.xml
index f7ca3d2..97bfe65 100644
--- a/core/res/res/values-mcc204-el/strings.xml
+++ b/core/res/res/values-mcc204-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc204-es-rUS/strings.xml b/core/res/res/values-mcc204-es-rUS/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-es-rUS/strings.xml
+++ b/core/res/res/values-mcc204-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-es/strings.xml b/core/res/res/values-mcc204-es/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-es/strings.xml
+++ b/core/res/res/values-mcc204-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-fr/strings.xml b/core/res/res/values-mcc204-fr/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-fr/strings.xml
+++ b/core/res/res/values-mcc204-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-it/strings.xml b/core/res/res/values-mcc204-it/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-it/strings.xml
+++ b/core/res/res/values-mcc204-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-ja/strings.xml b/core/res/res/values-mcc204-ja/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-ja/strings.xml
+++ b/core/res/res/values-mcc204-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-ko/strings.xml b/core/res/res/values-mcc204-ko/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-ko/strings.xml
+++ b/core/res/res/values-mcc204-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-nl/strings.xml b/core/res/res/values-mcc204-nl/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-nl/strings.xml
+++ b/core/res/res/values-mcc204-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-pl/strings.xml b/core/res/res/values-mcc204-pl/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-pl/strings.xml
+++ b/core/res/res/values-mcc204-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-pt-rPT/strings.xml b/core/res/res/values-mcc204-pt-rPT/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc204-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-pt/strings.xml b/core/res/res/values-mcc204-pt/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-pt/strings.xml
+++ b/core/res/res/values-mcc204-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-ru/strings.xml b/core/res/res/values-mcc204-ru/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-ru/strings.xml
+++ b/core/res/res/values-mcc204-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-sv/strings.xml b/core/res/res/values-mcc204-sv/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-sv/strings.xml
+++ b/core/res/res/values-mcc204-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-tr/strings.xml b/core/res/res/values-mcc204-tr/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-tr/strings.xml
+++ b/core/res/res/values-mcc204-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-zh-rCN/strings.xml b/core/res/res/values-mcc204-zh-rCN/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc204-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc204-zh-rTW/strings.xml b/core/res/res/values-mcc204-zh-rTW/strings.xml
index 94786f1..7d96230 100644
--- a/core/res/res/values-mcc204-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc204-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="2972154133076909542">"nl_nl"</string>
+ <string name="locale_replacement">"nl_nl"</string>
</resources>
diff --git a/core/res/res/values-mcc230-cs/strings.xml b/core/res/res/values-mcc230-cs/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-cs/strings.xml
+++ b/core/res/res/values-mcc230-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-da/strings.xml b/core/res/res/values-mcc230-da/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-da/strings.xml
+++ b/core/res/res/values-mcc230-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-de/strings.xml b/core/res/res/values-mcc230-de/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-de/strings.xml
+++ b/core/res/res/values-mcc230-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-el/strings.xml b/core/res/res/values-mcc230-el/strings.xml
index 49ea9f3..97bfe65 100644
--- a/core/res/res/values-mcc230-el/strings.xml
+++ b/core/res/res/values-mcc230-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc230-es-rUS/strings.xml b/core/res/res/values-mcc230-es-rUS/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-es-rUS/strings.xml
+++ b/core/res/res/values-mcc230-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-es/strings.xml b/core/res/res/values-mcc230-es/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-es/strings.xml
+++ b/core/res/res/values-mcc230-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-fr/strings.xml b/core/res/res/values-mcc230-fr/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-fr/strings.xml
+++ b/core/res/res/values-mcc230-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-it/strings.xml b/core/res/res/values-mcc230-it/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-it/strings.xml
+++ b/core/res/res/values-mcc230-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-ja/strings.xml b/core/res/res/values-mcc230-ja/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-ja/strings.xml
+++ b/core/res/res/values-mcc230-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-ko/strings.xml b/core/res/res/values-mcc230-ko/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-ko/strings.xml
+++ b/core/res/res/values-mcc230-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-nl/strings.xml b/core/res/res/values-mcc230-nl/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-nl/strings.xml
+++ b/core/res/res/values-mcc230-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-pl/strings.xml b/core/res/res/values-mcc230-pl/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-pl/strings.xml
+++ b/core/res/res/values-mcc230-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-pt-rPT/strings.xml b/core/res/res/values-mcc230-pt-rPT/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc230-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-pt/strings.xml b/core/res/res/values-mcc230-pt/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-pt/strings.xml
+++ b/core/res/res/values-mcc230-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-ru/strings.xml b/core/res/res/values-mcc230-ru/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-ru/strings.xml
+++ b/core/res/res/values-mcc230-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-sv/strings.xml b/core/res/res/values-mcc230-sv/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-sv/strings.xml
+++ b/core/res/res/values-mcc230-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-tr/strings.xml b/core/res/res/values-mcc230-tr/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-tr/strings.xml
+++ b/core/res/res/values-mcc230-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-zh-rCN/strings.xml b/core/res/res/values-mcc230-zh-rCN/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc230-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc230-zh-rTW/strings.xml b/core/res/res/values-mcc230-zh-rTW/strings.xml
index 63ade62..d3ecdbb 100644
--- a/core/res/res/values-mcc230-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc230-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="9011721823833053909">"cs_cz"</string>
+ <string name="locale_replacement">"cs_cz"</string>
</resources>
diff --git a/core/res/res/values-mcc232-cs/strings.xml b/core/res/res/values-mcc232-cs/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-cs/strings.xml
+++ b/core/res/res/values-mcc232-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-da/strings.xml b/core/res/res/values-mcc232-da/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-da/strings.xml
+++ b/core/res/res/values-mcc232-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-de/strings.xml b/core/res/res/values-mcc232-de/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-de/strings.xml
+++ b/core/res/res/values-mcc232-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-el/strings.xml b/core/res/res/values-mcc232-el/strings.xml
index 3698d2c..97bfe65 100644
--- a/core/res/res/values-mcc232-el/strings.xml
+++ b/core/res/res/values-mcc232-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc232-es-rUS/strings.xml b/core/res/res/values-mcc232-es-rUS/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-es-rUS/strings.xml
+++ b/core/res/res/values-mcc232-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-es/strings.xml b/core/res/res/values-mcc232-es/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-es/strings.xml
+++ b/core/res/res/values-mcc232-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-fr/strings.xml b/core/res/res/values-mcc232-fr/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-fr/strings.xml
+++ b/core/res/res/values-mcc232-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-it/strings.xml b/core/res/res/values-mcc232-it/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-it/strings.xml
+++ b/core/res/res/values-mcc232-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-ja/strings.xml b/core/res/res/values-mcc232-ja/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-ja/strings.xml
+++ b/core/res/res/values-mcc232-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-ko/strings.xml b/core/res/res/values-mcc232-ko/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-ko/strings.xml
+++ b/core/res/res/values-mcc232-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-nl/strings.xml b/core/res/res/values-mcc232-nl/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-nl/strings.xml
+++ b/core/res/res/values-mcc232-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-pl/strings.xml b/core/res/res/values-mcc232-pl/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-pl/strings.xml
+++ b/core/res/res/values-mcc232-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-pt-rPT/strings.xml b/core/res/res/values-mcc232-pt-rPT/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc232-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-pt/strings.xml b/core/res/res/values-mcc232-pt/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-pt/strings.xml
+++ b/core/res/res/values-mcc232-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-ru/strings.xml b/core/res/res/values-mcc232-ru/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-ru/strings.xml
+++ b/core/res/res/values-mcc232-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-sv/strings.xml b/core/res/res/values-mcc232-sv/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-sv/strings.xml
+++ b/core/res/res/values-mcc232-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-tr/strings.xml b/core/res/res/values-mcc232-tr/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-tr/strings.xml
+++ b/core/res/res/values-mcc232-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-zh-rCN/strings.xml b/core/res/res/values-mcc232-zh-rCN/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc232-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc232-zh-rTW/strings.xml b/core/res/res/values-mcc232-zh-rTW/strings.xml
index b028927..4773838 100644
--- a/core/res/res/values-mcc232-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc232-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="166900303893651370">"de_at"</string>
+ <string name="locale_replacement">"de_at"</string>
</resources>
diff --git a/core/res/res/values-mcc234-cs/strings.xml b/core/res/res/values-mcc234-cs/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-cs/strings.xml
+++ b/core/res/res/values-mcc234-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-da/strings.xml b/core/res/res/values-mcc234-da/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-da/strings.xml
+++ b/core/res/res/values-mcc234-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-de/strings.xml b/core/res/res/values-mcc234-de/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-de/strings.xml
+++ b/core/res/res/values-mcc234-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-el/strings.xml b/core/res/res/values-mcc234-el/strings.xml
index e04aa93..97bfe65 100644
--- a/core/res/res/values-mcc234-el/strings.xml
+++ b/core/res/res/values-mcc234-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc234-es-rUS/strings.xml b/core/res/res/values-mcc234-es-rUS/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-es-rUS/strings.xml
+++ b/core/res/res/values-mcc234-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-es/strings.xml b/core/res/res/values-mcc234-es/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-es/strings.xml
+++ b/core/res/res/values-mcc234-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-fr/strings.xml b/core/res/res/values-mcc234-fr/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-fr/strings.xml
+++ b/core/res/res/values-mcc234-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-it/strings.xml b/core/res/res/values-mcc234-it/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-it/strings.xml
+++ b/core/res/res/values-mcc234-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-ja/strings.xml b/core/res/res/values-mcc234-ja/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-ja/strings.xml
+++ b/core/res/res/values-mcc234-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-ko/strings.xml b/core/res/res/values-mcc234-ko/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-ko/strings.xml
+++ b/core/res/res/values-mcc234-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-nl/strings.xml b/core/res/res/values-mcc234-nl/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-nl/strings.xml
+++ b/core/res/res/values-mcc234-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-pl/strings.xml b/core/res/res/values-mcc234-pl/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-pl/strings.xml
+++ b/core/res/res/values-mcc234-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-pt-rPT/strings.xml b/core/res/res/values-mcc234-pt-rPT/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc234-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-pt/strings.xml b/core/res/res/values-mcc234-pt/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-pt/strings.xml
+++ b/core/res/res/values-mcc234-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-ru/strings.xml b/core/res/res/values-mcc234-ru/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-ru/strings.xml
+++ b/core/res/res/values-mcc234-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-sv/strings.xml b/core/res/res/values-mcc234-sv/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-sv/strings.xml
+++ b/core/res/res/values-mcc234-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-tr/strings.xml b/core/res/res/values-mcc234-tr/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-tr/strings.xml
+++ b/core/res/res/values-mcc234-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-zh-rCN/strings.xml b/core/res/res/values-mcc234-zh-rCN/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc234-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc234-zh-rTW/strings.xml b/core/res/res/values-mcc234-zh-rTW/strings.xml
index bd391e1..2538b73 100644
--- a/core/res/res/values-mcc234-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc234-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="233769627858930762">"en_gb"</string>
+ <string name="locale_replacement">"en_gb"</string>
</resources>
diff --git a/core/res/res/values-mcc260-cs/strings.xml b/core/res/res/values-mcc260-cs/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-cs/strings.xml
+++ b/core/res/res/values-mcc260-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-da/strings.xml b/core/res/res/values-mcc260-da/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-da/strings.xml
+++ b/core/res/res/values-mcc260-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-de/strings.xml b/core/res/res/values-mcc260-de/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-de/strings.xml
+++ b/core/res/res/values-mcc260-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-el/strings.xml b/core/res/res/values-mcc260-el/strings.xml
index ea6f87b..97bfe65 100644
--- a/core/res/res/values-mcc260-el/strings.xml
+++ b/core/res/res/values-mcc260-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc260-es-rUS/strings.xml b/core/res/res/values-mcc260-es-rUS/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-es-rUS/strings.xml
+++ b/core/res/res/values-mcc260-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-es/strings.xml b/core/res/res/values-mcc260-es/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-es/strings.xml
+++ b/core/res/res/values-mcc260-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-fr/strings.xml b/core/res/res/values-mcc260-fr/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-fr/strings.xml
+++ b/core/res/res/values-mcc260-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-it/strings.xml b/core/res/res/values-mcc260-it/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-it/strings.xml
+++ b/core/res/res/values-mcc260-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-ja/strings.xml b/core/res/res/values-mcc260-ja/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-ja/strings.xml
+++ b/core/res/res/values-mcc260-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-ko/strings.xml b/core/res/res/values-mcc260-ko/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-ko/strings.xml
+++ b/core/res/res/values-mcc260-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-nl/strings.xml b/core/res/res/values-mcc260-nl/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-nl/strings.xml
+++ b/core/res/res/values-mcc260-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-pl/strings.xml b/core/res/res/values-mcc260-pl/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-pl/strings.xml
+++ b/core/res/res/values-mcc260-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-pt-rPT/strings.xml b/core/res/res/values-mcc260-pt-rPT/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc260-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-pt/strings.xml b/core/res/res/values-mcc260-pt/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-pt/strings.xml
+++ b/core/res/res/values-mcc260-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-ru/strings.xml b/core/res/res/values-mcc260-ru/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-ru/strings.xml
+++ b/core/res/res/values-mcc260-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-sv/strings.xml b/core/res/res/values-mcc260-sv/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-sv/strings.xml
+++ b/core/res/res/values-mcc260-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-tr/strings.xml b/core/res/res/values-mcc260-tr/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-tr/strings.xml
+++ b/core/res/res/values-mcc260-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-zh-rCN/strings.xml b/core/res/res/values-mcc260-zh-rCN/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc260-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc260-zh-rTW/strings.xml b/core/res/res/values-mcc260-zh-rTW/strings.xml
index 13ea1b2..1161f9a 100644
--- a/core/res/res/values-mcc260-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc260-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="6306793451973344945">"pl_pl"</string>
+ <string name="locale_replacement">"pl_pl"</string>
</resources>
diff --git a/core/res/res/values-mcc262-cs/strings.xml b/core/res/res/values-mcc262-cs/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-cs/strings.xml
+++ b/core/res/res/values-mcc262-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-da/strings.xml b/core/res/res/values-mcc262-da/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-da/strings.xml
+++ b/core/res/res/values-mcc262-da/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-de/strings.xml b/core/res/res/values-mcc262-de/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-de/strings.xml
+++ b/core/res/res/values-mcc262-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-el/strings.xml b/core/res/res/values-mcc262-el/strings.xml
index 38827c5..97bfe65 100644
--- a/core/res/res/values-mcc262-el/strings.xml
+++ b/core/res/res/values-mcc262-el/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"el_GR"</string>
+ <string name="locale_replacement">"el_GR"</string>
</resources>
diff --git a/core/res/res/values-mcc262-es-rUS/strings.xml b/core/res/res/values-mcc262-es-rUS/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-es-rUS/strings.xml
+++ b/core/res/res/values-mcc262-es-rUS/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-es/strings.xml b/core/res/res/values-mcc262-es/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-es/strings.xml
+++ b/core/res/res/values-mcc262-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-fr/strings.xml b/core/res/res/values-mcc262-fr/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-fr/strings.xml
+++ b/core/res/res/values-mcc262-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-it/strings.xml b/core/res/res/values-mcc262-it/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-it/strings.xml
+++ b/core/res/res/values-mcc262-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-ja/strings.xml b/core/res/res/values-mcc262-ja/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-ja/strings.xml
+++ b/core/res/res/values-mcc262-ja/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-ko/strings.xml b/core/res/res/values-mcc262-ko/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-ko/strings.xml
+++ b/core/res/res/values-mcc262-ko/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-nl/strings.xml b/core/res/res/values-mcc262-nl/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-nl/strings.xml
+++ b/core/res/res/values-mcc262-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-pl/strings.xml b/core/res/res/values-mcc262-pl/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-pl/strings.xml
+++ b/core/res/res/values-mcc262-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-pt-rPT/strings.xml b/core/res/res/values-mcc262-pt-rPT/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc262-pt-rPT/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-pt/strings.xml b/core/res/res/values-mcc262-pt/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-pt/strings.xml
+++ b/core/res/res/values-mcc262-pt/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-ru/strings.xml b/core/res/res/values-mcc262-ru/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-ru/strings.xml
+++ b/core/res/res/values-mcc262-ru/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-sv/strings.xml b/core/res/res/values-mcc262-sv/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-sv/strings.xml
+++ b/core/res/res/values-mcc262-sv/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-tr/strings.xml b/core/res/res/values-mcc262-tr/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-tr/strings.xml
+++ b/core/res/res/values-mcc262-tr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-zh-rCN/strings.xml b/core/res/res/values-mcc262-zh-rCN/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc262-zh-rCN/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-mcc262-zh-rTW/strings.xml b/core/res/res/values-mcc262-zh-rTW/strings.xml
index a90e7cf..9505cf4 100644
--- a/core/res/res/values-mcc262-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc262-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="locale_replacement" msgid="273407696421660814">"de_de"</string>
+ <string name="locale_replacement">"de_de"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c19d057..dff943c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -15,697 +15,752 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"kB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"&lt;uten navn&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Mangler telefonnummer)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Ukjent)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Telefonsvarer"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Tilkoblingsproblem eller ugyldig MMI-kode."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Tjenesten ble aktivert."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Tjenesten ble aktivert for:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Tjenesten ble deaktivert."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registreringen er vellykket."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Registreringen ble fjernet."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Ugyldig passord."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI utført."</string>
- <string name="badPin" msgid="5085454289896032547">"Den gamle PIN-koden du skrev inn er feil."</string>
- <string name="badPuk" msgid="5702522162746042460">"PUK-koden du skrev inn er feil."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"PIN-kodene stemmer ikke overens."</string>
- <string name="invalidPin" msgid="3850018445187475377">"PIN-koden må være mellom fire og åtte siffer."</string>
- <string name="needPuk" msgid="919668385956251611">"SIM-kortet ditt er PUK-låst. Skriv inn PUK-koden for å låse det opp."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Skriv inn PUK2 for å låse opp SIM-kortet."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Inngående nummervisning"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Utgående nummervisning"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Viderekobling"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Samtale venter"</string>
- <string name="BaMmi" msgid="455193067926770581">"Samtaleblokkering"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Passordendring"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN-kode-bytte"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Nummervisning tilgjengelig"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Nummervisning begrenset"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Telefonkonferanse"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Avvisning av uønskede samtaler"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Levering av nummervisning"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Ikke forstyrr"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Nummervisning er begrenset som standard. Neste anrop: Begrenset"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Nummervisning er begrenset som standard. Neste anrop: Ikke begrenset"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Nummervisning er ikke begrenset som standard. Neste anrop: Begrenset"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nummervisning er ikke begrenset som standard. Neste anrop: Ikke begrenset"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"SIM-kortet er ikke tilrettelagt for tjenesten."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Kunne ikke endre innstilling for nummervisning."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Tilgangsbegrensning endret"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Datatjenesten er blokkert."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Nødtjenesten er blokkert."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Tale-/SMS-tjenester er blokkert."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Alle tale-/SMS-tjenester er blokkert."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Tale"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Data"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"Fax"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynkron"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synkron"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pakkedata"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Roaming-indikator av"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Roaming-indikator på"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Roaming-indikator blinker"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Ute av nabolaget"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Ute av bygningen"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming - foretrukket system"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming - tilgjengelig system"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming - alliansepartner"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming - gullpartner"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming - full tjenestefunksjoanlitet"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming - delvis tjenestefunksjonalitet"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Roaming-banner på"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Roaming-banner av"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Leter etter tjeneste"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> etter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Funksjonskode utført."</string>
- <string name="fcError" msgid="3327560126588500777">"Tilkoblingsproblem eller ugyldig funksjonskode."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Nettsiden inneholder en feil."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Kunne ikke finne adressen."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Støtter ikke sidens autentiseringsmetode."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Autentiseringen feilet."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Autentisering via mellomtjeneren feilet."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Kunne ikke koble til tjeneren."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Klarte ikke å kommunisere med tjeneren. Prøv igjen senere."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Det oppsto et tidsavbrudd under tilkobling til tjeneren."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Siden inneholder for mange videresendinger."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokollen er ikke støttet."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Kunne ikke opprette en sikker tilkobling."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Kunne ikke åpne siden, siden adressen er ugyldig."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Kunne ikke åpne filen."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Fant ikke den forespurte filen."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"For mange forespørsler blir behandlet. Prøv igjen senere."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synkronisering"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronisering"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange slettinger av <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefonens lagringsminne er fullt! Slett noen filer for å frigjøre plass."</string>
- <string name="me" msgid="6545696007631404292">"Meg"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefoninnstillinger"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Stillemodus"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Slå på trådløst nett"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Slå av trådløst nett"</string>
- <string name="screen_lock" msgid="799094655496098153">"LÃ¥s skjermen"</string>
- <string name="power_off" msgid="4266614107412865048">"Slå av"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Avslutter…"</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Telefonen vil bli slått av."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Ingen nylig brukte applikasjoner."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefoninnstillinger"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"LÃ¥s skjermen"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Slå av"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stillemodus"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er av"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er på"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flymodus"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flymodus er på"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flymodus er av"</string>
- <string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Betaltjenester"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Lar applikasjoner utføre operasjoner som kan koste deg penger."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Meldinger"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Lese og skrive SMS, e-post og andre meldinger på telefonen."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Personlig informasjon"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Direkte tilgang til kontakter og kalendre lagret på telefonen."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Plassering"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Overvåking av telefonens fysiske plassering"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Nettverkstilgang"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Gir applikasjoner tilgang til diverse nettverksfunksjoner."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Google-kontoer"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Tilgang til tilgjengelige Google-kontoer."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Maskinvarekontroll"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Direkte tilgang til maskinvaren på telefonen."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefonsamtaler"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Overvåk, ta opp, og behandle telefonsamtaler."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Systemverktøy"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Lavnivå tilgang og kontroll over systemet."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Utviklingsverktøy"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funksjonalitet kun utviklere trenger."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Lagring"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Tilgang til minnekortet."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"deaktivere eller endre statusfeltet"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Lar applikasjonen deaktivere statusfeltet, samt legge til og fjerne systemikoner."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"utvide/slå sammen statusfeltet"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Lar applikasjonen utvide eller slå sammen statusfeltet."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"avskjære utgående anrop"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Lar applikasjonen behandle utgående anrop og endre nummeret som ringes. Ondsinnede applikasjoner kan overvåke, videresende, eller hindre utgående anrop."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"motta SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Lar applikasjonen motta og behandle SMS-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"motta MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Lar applikasjonen motta og behandle MMS-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"sende SMS-meldinger"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Lar applikasjonen sende SMS-meldinger. Ondsinnede applikasjoner kan koste deg penger ved å sende meldinger uten bekreftelse."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"lese SMS- og MMS-meldinger"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Lar applikasjonen lese SMS-meldinger lagret i telefonen eller på SIM-kortet. Ondsinnede applikasjoner kan lese private meldinger."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"redigere SMS- og MMS-meldinger"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Lar applikasjonen skrive til SMS-meldinger lagret i telefonen eller på SIM-kortet. Ondsinnede applikasjoner kan slette meldinger."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"motta WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Lar applikasjonen motta og behandle WAP-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"se kjørende applikasjoner"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Tillater applikasjonen å hente informasjon om aktive og nylig kjørte programmer. Kan tillate ondsinnede applikasjoner å oppdage privat informasjon om andre applikasjoner."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"omordne kjørende applikasjoner"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillater applikasjonen å flytte programmer til forgrunnen eller bakgrunnen. Ondsinnede applikasjoner kan tvinge seg selv til fronten."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"aktiver applikasjonsdebugging"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Lar applikasjonen skru på debugging for en annen applikasjon. Ondsinnede applikasjoner kan bruke dette til å drepe andre applikasjoner."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"endre innstillingene for brukergrensesnitt"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Tillater applikasjonen å endre gjeldende innstillinger, slik som språk eller skriftstørrelse."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"omstarte andre applikasjoner"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Lar applikasjonen tvinge andre applikasjoner til å starte på nytt."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"tvinge applikasjoner til å lukkes"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Lar applikasjonen tvinge enhver aktivitet som er i forgrunnen til å lukkes og gå tilbake. Vanlige applikasjoner bør aldri trenge dette."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"hente intern systemtilstand"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Lar applikasjonen hente intern tilstand fra systemet. Ondsinnede applikasjoner kan hente et bredt spekter av privat og sikker informasjon som de vanligvis aldri burde ha behov for."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"delvis avslutning"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Lar applikasjonen sette aktivitetshåndtereren i avslutningstilstand. Slår ikke systemet helt av."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"forhindre applikasjonsbytte"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Lar applikasjonen forhindre brukeren fra å bytte til en annen applikasjon."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"overvåke og kontrollere all applikasjonsoppstart"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Lar applikasjonen overvåke og kontrollere hvordan systemet starter applikasjoner. Ondsinnede applikasjoner kan ta over systemet helt. Denne rettigheten behøves bare for utvikling, aldri for vanlig bruk av telefonen."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"kringkaste melding om fjernet pakke"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Lar applikasjonen kringkaste en melding om at en applikasjonspakke er blitt fjernet. Ondsinnede applikasjoner kan bruke dette til å drepe vilkårlige andre kjørende applikasjoner."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"kringkaste melding om mottatt SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Lar applikasjonen kringkaste en melding om at en SMS-melding er mottatt. Ondsinnede applikasjoner kan bruke dette til å forfalske innkommende SMS-meldinger."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"kringkaste melding om mottatt WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Lar applikasjonen kringkaste en melding om at en WAP-PUSH-melding er blitt mottatt. Ondsinnede applikasjoner kan bruke dette til å forfalske MMS-kvitteringer eller i det stille erstatte innholdet av vilkårlige nettsider med ondsinnede varianter."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"begrense antallet kjørende prosesser"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Lar applikasjonen kontrollere maksimalt antall kjørende prosesser. Behøves aldri for vanlige applikasjoner."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"få alle bakgrunnsapplikasjoner til å lukkes"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Lar applikasjonen kontrollere om aktiviteter alltid avsluttes når de sendes til bakgrunnen. Behøves aldri for vanlige applikasjoner."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"endre batteristatistikk"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Lar applikasjonen endre på innsamlet batteristatistikk. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_backup" msgid="470013022865453920">"kontrollere backup og gjenoppretting"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Lar applikasjonen kontrollere systemets backup- og gjenopprettingsmekanisme. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"vis uautoriserte vinduer"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Tillater at det opprettes vinduer ment for bruk av systemets interne brukergrensesnitt. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"vise advarsler på systemnivå"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Lar applikasjonen vise systemadvarselvinduer. Ondsinnede applikasjoner kan ta over hele skjermen."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"endre global animasjonshastighet"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Lar applikasjonen endre den globale animasjonshastigheten (raskere eller tregere animasjoner) når som helst."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"styre applikasjonssymboler"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Lar applikasjoner lage og vedlikeholde sine egne symboler, noe som lar dem overstyre den vanlige Z-ordningen. Vanlige applikasjoner bør aldri trenge dette."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"trykke taster og kontrolknapper"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Lar applikasjonen levere sine egne inndatahendelser (tastetrykk osv.) til andre applikasjoner. Ondsinnede applikasjoner kan bruke dette til å ta over telefonen."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"ta opp hva som skrives og gjøres"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Lar applikasjonen overvåke tastetrykk selv når interaksjonen er med et annet program (som å skrive inn et passord). Vanlige applikasjoner bør aldri trenge dette."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"binde til en inndatametode"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Lar applikasjonen binde til toppnivågrensesnittet for en inndatametode. Vanlige applikasjoner bør aldri trenge dette."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"snu skjermen"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Lar applikasjonen rotere skjermen når som helst. Vanlige applikasjoner bør aldri trenge dette."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"sende Linux-signaler til applikasjoner"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Lar applikasjonen spørre om at et gitt signal blir sendt til alle varige prosesser."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"forbli kjørende"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Lar applikasjonen gjøre deler av seg selv varig, så systemet ikke kan bruke det til andre applikasjoner."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"slette applikasjoner"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Lar applikasjonen slette Android-pakker. Ondsinnede applikasjoner kan bruke dette til å slette viktige applikasjoner."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"slette andre applikasjoners data"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Lar applikasjonen fjerne brukerdata."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"slette andre applikasjoners hurtigbuffer"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Lar applikasjonen to slette hurtigbufferfiler."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"måle lagringsplass for applikasjon"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Lar applikasjonen hente kode-, data- og hurtigbufferstørrelser"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"installere applikasjoner direkte"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Lar applikasjonen installere nye eller oppdaterte Android-pakker. Ondsinnede applikasjoner kan bruke dette til å legge til nye applikasjoner med vilkårlig kraftige rettigheter."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"slette hurtigbufferdata for alle applikasjoner"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Lar applikasjonen frigjøre lagringsplass ved å slette filer i applikasjoners hurtigbufferkatalog. Tilgangen er vanligvis sterkt begrenset, til systemprosesser."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"lese systemets loggfiler"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Lar applikasjonen to lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med telefonen, men skal ikke inneholde personlig eller privat informasjon."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Lar applikasjonen to lese og skrive enhver ressurs eid av gruppen diag; for eksempel, filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør KUN brukes for maskinvarespesifikke diagnoseverktøy laget av operatøren eller produsenten."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"aktivere eller deaktigere applikasjonskomponenter"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Lar applikasjonen endre om en komponent i en annen applikasjon er aktivert eller ikke. Ondsinnede applikasjoner kan bruke dette til å deaktivere viktige telefonfunksjoner. Denne rettigheten må brukes med forsiktighet, ettersom det er mulig å få applikasjonskomponenter inn i en ubrukelig, inkonsistent eller ustabil tilstand."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"velge foretrukne applikasjoner"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Lar applikasjonen endre valgene for foretrukne applikasjoner. Dette kan gi ondsinnede applikasjoner tilgang til i det stille å endre hvilke applikasjoner som kjøres, og slik gi seg ut til å være en eksisterende applikasjon og samle private data."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"endre globale systeminnstillinger"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Lar applikasjonen endre systemets innstillingsdata. Ondsinnede applikasjoner kan skade systemets innstillinger."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"endre sikre systeminnstillinger"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Lar applikasjonen endre systemets sikre innstillingsdata. Ikke ment for bruk av vanlige applikasjoner."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"redigere Google-tjenestekartet"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Lar applikasjonen redigere Google-tjenestekartet. Ikke ment for bruk av vanlige applikasjoner."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"starte automatisk sammen med systemet"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Lar applikasjonen sette opp at den selv skal starte så fort systemet er ferdig med å slå seg på. Dette kan gjøre at det tar lengre tid å starte telefonen, og at den kan bli tregere fordi applikasjonen alltid kjører."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"sende varige kringkastinger"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Lar applikasjonen sende varige kringkastinger, som forblir på systemet etter at kringkastingen er avsluttet. Ondsinnede applikasjoner kan gjøre telefonen treg eller ustabil ved å få den til å bruke for mye minne."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"lese kontaktinformasjon"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Lar applikasjonen lese all kontakt- og adresseinformasjon lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å sende personlige data til andre."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"skrive kontaktinformasjon"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Lar applikasjonen endre kontakt- og adresseinformasjon lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å redigere eller endre kontaktinformasjonen."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"skrive eierinformasjon"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Lar applikasjonen endre dataene om telefoneieren. Ondsinnede applikasjoner kan bruke dette til å slette eller redigere telefonens eierdata."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"lese eierinformasjon"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Lar applikasjonen lese dataene om telefoneieren. Ondsinnede applikasjoner kan bruke dette til å lese telefonens eierdata."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"lese kalenderinformasjon"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Lar applikasjonen lese alle kalenderhendelser lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å sende kalenderhendelser til andre."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"skrive kalenderinformasjon"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Lar applikasjonen endre kalenderhendelser lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å slette eller endre kalenderinformasjon."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"lage manuelle plasseringskilder for testing"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Lage manuelle plassingskilder for testing. Ondsinnede applikasjoner kan bruke dette til å overstyre plasseringen og/eller statusen rapportert av ekte plasseringskilder slik som GPS eller nettverksoperatører."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"få tilgang til ekstra plasseringskommandoer"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Få tilgang til ekstra kommandoer for plasseringskilder. Ondsinnede applikasjoner kan bruke dette til å forstyrre GPS eller andre plasseringskilder."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"installere plasseringskilder"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Lar applikasjonen lage manuelle plasseringskilder for testing. Ondsinnede applikasjoner kan bruke dette til å overstyre plasseringen og/eller statusen rapportert av ekte plasseringskilder slik som GPS eller nettverksoperatører, eller overvåke og rapportere plasseringen din til en tredjepart."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"nøyaktig (GPS-) plassering"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Få tilgang til nøyaktige plasseringskilder som Global Positioning System (GPS) på telefonen, når det er tilgjengelig. Ondsinnede applikasjoner kan bruke dette til å finne ut hvor du er, og kan bruke mer batteri."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"grov (nettverksbasert) plassering"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Få tilgang til grove plasseringskilder som databasen over basestasjoner til å finne ut omtrent hvor telefonen er, når det er tilgjengelig. Ondsinnede applikasjoner kan bruke dette til å finne ut omtrent hvor du er."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"få tilgang til SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Lar applikasjonen bruke lavnivåfunksjonalitet i SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lese skjermbufferet"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Lar applikasjonen lese innholdet i skjermbufferet."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"endre lydinnstillinger"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Lar applikasjonen endre globale lydinnstillinger som volum og ruting."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"ta opp lyd"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Gir applikasjonen tilgang til opptaksstien for lyd."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"ta bilder"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Lar applikasjonen ta bilder med kameraet. Dette gir applikasjonen til når som helst å se og lagre det kameraet ser."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"deaktivere telefonen permanent"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Lar applikasjonen deaktivere hele telefonen permanent. Dette er svært farlig."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"tvinge omstart av telefon"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Lar applikasjonen tvinge telefonen til å starte på nytt."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montere og avmontere filsystemer"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Lar applikasjonen montere og avmontere filsystemer for uttagbar lagring."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatere ekstern lagringsplass"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Lar applikasjonen formatere ekstern lagringsplass."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"kontrollere vibratoren"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Lar applikasjonen kontrollere vibratoren."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollere lommelykten"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Lar applikasjonen kontrollere lommelykten."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"teste maskinvare"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Lar applikasjonen styre diverse enheter med det formål å teste maskinvaren."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"ringe telefonnummer direkte"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Lar applikasjonen ringe telefonnummer uten inngripen fra brukeren. Ondsinnede applikasjoner kan forårsake uventede oppringinger på telefonregningen. Merk at dette ikke gir applikasjonen lov til å ringe nødnummer."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"ringe vilkårlige telefonnummer direkte"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Lar applikasjonen ringe hvilket som helst telefonnummer, inkludert nødnummer, uten inngripen fra brukeren. Ondsinnede applikasjoner kan forårsake unødvendige og ulovlige samtaler til nødtjenester."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontrollere varsling for plasseringsendring"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Lar applikasjonen slå av/på varsling om plasseringsendringer fra radioen. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"få tilgang til egenskaper for innsjekking"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Gir lese- og skrivetilgang til egenskaper lastet opp av innsjekkingstjenesten. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"velg gadgeter"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Lar applikasjonen fortelle systemet hvilke gadgeter som kan brukes av hvilke applikasjoner. Med denne rettigheten kan applikasjoner andre applikasjoner tilgang til personlig data. Ikke ment for vanlige applikasjoner."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"endre telefontilstand"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Lar applikasjonen kontrollere telefonfunksjonaliteten i enheten. En applikasjon med denne rettigheten kan endre nettverk, slå telefonens radio av eller på og lignende uten noensinne å varsle brukeren."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"forhindre telefonen fra å sove"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Lar applikasjonen forhindre telefonen fra å gå i hvilemodus."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"slå telefonen av eller på"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Lar applikasjonen skru telefonen av eller på."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"kjøre i fabrikktestmodus"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Kjøre som en lavnivås produsenttest, med full tilgang til telefonens maskinvare. Kun tilgjengelig når telefonen kjører i produsenttestmodus."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"endre bakgrunnsbilde"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Lar applikasjonen sette systemets bakgrunnsbilde."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"sette størrelseshint for bakgrunn"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Lar applikasjonen sette størrelseshint for systemets bakgrunnsbilde."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"nullstille systemet til fabrikkinnstillinger"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Lar applikasjonen nullstille systemet til fabrikkinnstillinger, noe som vil fjerne alle data, alt oppsett, og alle installerte applikasjoner."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"endre tidssone"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Lar applikasjonen endre telefonens tidssone."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"oppdage kjente kontoer"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Lar applikasjonen hente listen over kontoer telefonen kjenner til."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"se nettverkstilstand"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Lar applikasjonen se tilstanden til alle nettverk."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"full internett-tilgang"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Lar applikasjonen opprette vilkårlige nettverkstilkoblinger."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"skrive APN-innstillinger"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Lar applikasjonen to endre APN-innstillinger slik som mellomtjener eller port for hvilket som helst aksesspunkt."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"endre nettverkskonnektivitet"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Lar applikasjonen endre tilstanden til nettverkskonnektivitet."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"endre innstilling for bakgrunnsdata"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Lar applikasjonen endre innstillingen for bakgrunnsdata."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"se tilstand for trådløse nettverk"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Lar applikasjonen få se informasjon om tilstanden til de trådløse nettene."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"endre tilstand for trådløse nettverk"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Lar applikasjonen koble til og fra trådløse aksesspunkt, og å gjøre endringer i konfigurerte trådløse nettverk."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"tillat multicast for trådløse nettverk"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Lar applikasjonen motta pakker som ikke er adressert til enheten selv. Dette kan være nyttig ved leting etter nærliggende tjenester, men bruker mer strøm enn ikke-multicast-modus."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth-administrasjon"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Lar applikasjonen konfigurere den lokale Bluetooth-telefonen, og å oppdage og pare med andre enheter."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"opprette Bluetooth-tilkoblinger"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Lar applikasjonen se konfigurasjonen til den lokale Bluetooth-telefonen, og å opprette og godta tilkoblinger med parede enheter."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"slå av tastaturlås"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Lar applikasjonen slå av tastaturlåsen og enhver tilknyttet passordsikkerhet. Et legitimt eksempel på dette er at telefonen slår av tastaturlåsen når den mottar et innkommende anrop, og så slår den på igjen når samtalen er over."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lese synkroniseringsinnstillinger"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Lar applikasjonen lese synkroniseringsinnstillingene, som for eksempel om kontakter blir synkronisert."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"skrive synkroniseringsinnstillinger"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Lar applikasjonen to endre på synkroniseringsinnstillingene, som for eksempel om kontakter blir synkronisert."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"lese synkroniseringsstatistikk"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Lar applikasjonen lese synkroniseringsstatistikk, som for eksempel historien over alle synkroniseringer utført."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lese abonnement på nyhetskilder"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Lar applikasjonen hente detaljer om hvilke nyhetskilder som synkroniseres."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"endre abonnement på nyhetskilder"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Lar applikasjonen redigere hvilke nyhetskilder som synkroniseres. Dette kan gi en ondsinnet applikasjon tilgang til å endre hvilke nyhetskilder som synkroniseres."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"lese brukerdefinert ordliste"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Lar applikasjonen lese private ord, navn og uttrykk som brukeren har lagret i den brukerdefinerte ordlisten."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"skrive til brukerdefinert ordliste"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Lar applikasjonen skrive nye ord til den brukerdefinerte ordlisten."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"redigere/slette innhold på minnekort"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Lar applikasjonen skrive til minnekortet."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"kB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <!-- no translation found for fileSizeSuffix (7670819340156489359) -->
+ <skip />
+ <string name="untitled">"&lt;uten navn&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Mangler telefonnummer)"</string>
+ <string name="unknownName">"(Ukjent)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Telefonsvarer"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Tilkoblingsproblem eller ugyldig MMI-kode."</string>
+ <string name="serviceEnabled">"Tjenesten ble aktivert."</string>
+ <string name="serviceEnabledFor">"Tjenesten ble aktivert for:"</string>
+ <string name="serviceDisabled">"Tjenesten ble deaktivert."</string>
+ <string name="serviceRegistered">"Registreringen er vellykket."</string>
+ <string name="serviceErased">"Registreringen ble fjernet."</string>
+ <string name="passwordIncorrect">"Ugyldig passord."</string>
+ <string name="mmiComplete">"MMI utført."</string>
+ <string name="badPin">"Den gamle PIN-koden du skrev inn er feil."</string>
+ <string name="badPuk">"PUK-koden du skrev inn er feil."</string>
+ <string name="mismatchPin">"PIN-kodene stemmer ikke overens."</string>
+ <string name="invalidPin">"PIN-koden må være mellom fire og åtte siffer."</string>
+ <string name="needPuk">"SIM-kortet ditt er PUK-låst. Skriv inn PUK-koden for å låse det opp."</string>
+ <string name="needPuk2">"Skriv inn PUK2 for å låse opp SIM-kortet."</string>
+ <string name="ClipMmi">"Inngående nummervisning"</string>
+ <string name="ClirMmi">"Utgående nummervisning"</string>
+ <string name="CfMmi">"Viderekobling"</string>
+ <string name="CwMmi">"Samtale venter"</string>
+ <string name="BaMmi">"Samtaleblokkering"</string>
+ <string name="PwdMmi">"Passordbytte"</string>
+ <string name="PinMmi">"PIN-kode-bytte"</string>
+ <!-- no translation found for CnipMmi (3110534680557857162) -->
+ <skip />
+ <!-- no translation found for CnirMmi (3062102121430548731) -->
+ <skip />
+ <!-- no translation found for ThreeWCMmi (9051047170321190368) -->
+ <skip />
+ <!-- no translation found for RuacMmi (7827887459138308886) -->
+ <skip />
+ <!-- no translation found for CndMmi (3116446237081575808) -->
+ <skip />
+ <!-- no translation found for DndMmi (1265478932418334331) -->
+ <skip />
+ <string name="CLIRDefaultOnNextCallOn">"Nummervisning er begrenset som standard. Neste anrop: Begrenset"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Nummervisning er begrenset som standard. Neste anrop: Ikke begrenset"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Nummervisning er ikke begrenset som standard. Neste anrop: Begrenset"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Nummervisning er ikke begrenset som standard. Neste anrop: Ikke begrenset"</string>
+ <string name="serviceNotProvisioned">"SIM-kortet er ikke tilrettelagt for tjenesten."</string>
+ <string name="CLIRPermanent">"Kunne ikke endre innstilling for nummervisning."</string>
+ <string name="RestrictedChangedTitle">"Endring i begrenset tilgang"</string>
+ <string name="RestrictedOnData">"Datatjenesten er blokkert."</string>
+ <string name="RestrictedOnEmergency">"Nødtjenesten er blokkert."</string>
+ <string name="RestrictedOnNormal">"Tale- og SMS-tjenesten er blokkert."</string>
+ <string name="RestrictedOnAll">"Alle tale- og SMS-tjenester er blokkert."</string>
+ <string name="serviceClassVoice">"Tale"</string>
+ <string name="serviceClassData">"Data"</string>
+ <string name="serviceClassFAX">"Fax"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynkron"</string>
+ <string name="serviceClassDataSync">"Synkron"</string>
+ <string name="serviceClassPacket">"Pakkedata"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <!-- no translation found for roamingText0 (7170335472198694945) -->
+ <skip />
+ <!-- no translation found for roamingText1 (5314861519752538922) -->
+ <skip />
+ <!-- no translation found for roamingText2 (8969929049081268115) -->
+ <skip />
+ <!-- no translation found for roamingText3 (5148255027043943317) -->
+ <skip />
+ <!-- no translation found for roamingText4 (8808456682550796530) -->
+ <skip />
+ <!-- no translation found for roamingText5 (7604063252850354350) -->
+ <skip />
+ <!-- no translation found for roamingText6 (2059440825782871513) -->
+ <skip />
+ <!-- no translation found for roamingText7 (7112078724097233605) -->
+ <skip />
+ <!-- no translation found for roamingText8 (5989569778604089291) -->
+ <skip />
+ <!-- no translation found for roamingText9 (7969296811355152491) -->
+ <skip />
+ <!-- no translation found for roamingText10 (3992906999815316417) -->
+ <skip />
+ <!-- no translation found for roamingText11 (4154476854426920970) -->
+ <skip />
+ <!-- no translation found for roamingText12 (1189071119992726320) -->
+ <skip />
+ <!-- no translation found for roamingTextSearching (8360141885972279963) -->
+ <skip />
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> etter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
+ <!-- no translation found for fcComplete (3118848230966886575) -->
+ <skip />
+ <!-- no translation found for fcError (3327560126588500777) -->
+ <skip />
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Nettsiden inneholder en feil."</string>
+ <string name="httpErrorLookup">"Kunne ikke finne adressen."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Støtter ikke sidens autentiseringsmetode."</string>
+ <string name="httpErrorAuth">"Autentiseringen feilet."</string>
+ <string name="httpErrorProxyAuth">"Autentisering via mellomtjeneren feilet."</string>
+ <string name="httpErrorConnect">"Kunne ikke koble til tjeneren."</string>
+ <string name="httpErrorIO">"Klarte ikke å kommunisere med tjeneren. Prøv igjen senere."</string>
+ <string name="httpErrorTimeout">"Det oppsto et tidsavbrudd under tilkobling til tjeneren."</string>
+ <string name="httpErrorRedirectLoop">"Siden inneholder for mange videresendinger."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokollen er ikke støttet."</string>
+ <string name="httpErrorFailedSslHandshake">"Kunne ikke opprette en sikker tilkobling."</string>
+ <string name="httpErrorBadUrl">"Kunne ikke åpne siden, siden adressen er ugyldig."</string>
+ <string name="httpErrorFile">"Kunne ikke åpne filen."</string>
+ <string name="httpErrorFileNotFound">"Fant ikke den forespurte filen."</string>
+ <string name="httpErrorTooManyRequests">"For mange forespørsler blir behandlet. Prøv igjen senere."</string>
+ <string name="contentServiceSync">"Synkronisering"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synkronisering"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"For mange slettinger av <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Telefonens lagringsminne er fullt! Slett noen filer for å frigjøre plass."</string>
+ <string name="me">"Meg"</string>
+ <string name="power_dialog">"Telefoninnstillinger"</string>
+ <string name="silent_mode">"Stillemodus"</string>
+ <string name="turn_on_radio">"Slå på trådløst nett"</string>
+ <string name="turn_off_radio">"Slå av trådløst nett"</string>
+ <string name="screen_lock">"LÃ¥s skjermen"</string>
+ <string name="power_off">"Slå av"</string>
+ <string name="shutdown_progress">"Avslutter…"</string>
+ <string name="shutdown_confirm">"Telefonen vil bli slått av."</string>
+ <string name="no_recent_tasks">"Ingen nylig brukte applikasjoner."</string>
+ <string name="global_actions">"Telefoninnstillinger"</string>
+ <string name="global_action_lock">"LÃ¥s skjermen"</string>
+ <string name="global_action_power_off">"Slå av"</string>
+ <string name="global_action_toggle_silent_mode">"Stillemodus"</string>
+ <string name="global_action_silent_mode_on_status">"Lyden er av"</string>
+ <string name="global_action_silent_mode_off_status">"Lyden er på"</string>
+ <string name="global_actions_toggle_airplane_mode">"Flymodus"</string>
+ <string name="global_actions_airplane_mode_on_status">"Flymodus er på"</string>
+ <string name="global_actions_airplane_mode_off_status">"Flymodus er av"</string>
+ <string name="safeMode">"Sikkermodus"</string>
+ <string name="android_system_label">"Android-system"</string>
+ <string name="permgrouplab_costMoney">"Betaltjenester"</string>
+ <string name="permgroupdesc_costMoney">"Lar applikasjoner utføre operasjoner som kan koste deg penger."</string>
+ <string name="permgrouplab_messages">"Meldinger"</string>
+ <string name="permgroupdesc_messages">"Lese og skrive SMS, e-post og andre meldinger på telefonen."</string>
+ <string name="permgrouplab_personalInfo">"Personlig informasjon"</string>
+ <string name="permgroupdesc_personalInfo">"Direkte tilgang til kontakter og kalendre lagret på telefonen."</string>
+ <string name="permgrouplab_location">"Plassering"</string>
+ <string name="permgroupdesc_location">"Overvåking av telefonens fysiske plassering"</string>
+ <string name="permgrouplab_network">"Nettverkstilgang"</string>
+ <string name="permgroupdesc_network">"Gir applikasjoner tilgang til diverse nettverksfunksjoner."</string>
+ <string name="permgrouplab_accounts">"Google-kontoer"</string>
+ <string name="permgroupdesc_accounts">"Tilgang til tilgjengelige Google-kontoer."</string>
+ <string name="permgrouplab_hardwareControls">"Maskinvarekontroll"</string>
+ <string name="permgroupdesc_hardwareControls">"Direkte tilgang til maskinvaren på telefonen."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonsamtaler"</string>
+ <string name="permgroupdesc_phoneCalls">"Overvåk, ta opp, og behandle telefonsamtaler."</string>
+ <string name="permgrouplab_systemTools">"Systemverktøy"</string>
+ <string name="permgroupdesc_systemTools">"Lavnivå tilgang og kontroll over systemet."</string>
+ <string name="permgrouplab_developmentTools">"Utviklingsverktøy"</string>
+ <string name="permgroupdesc_developmentTools">"Funksjonalitet kun utviklere trenger."</string>
+ <!-- no translation found for permgrouplab_storage (1971118770546336966) -->
+ <skip />
+ <!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
+ <skip />
+ <string name="permlab_statusBar">"deaktivere eller endre statusfeltet"</string>
+ <string name="permdesc_statusBar">"Lar applikasjonen deaktivere statusfeltet, samt legge til og fjerne systemikoner."</string>
+ <string name="permlab_expandStatusBar">"utvide/slå sammen statusfeltet"</string>
+ <string name="permdesc_expandStatusBar">"Lar applikasjonen utvide eller slå sammen statusfeltet."</string>
+ <string name="permlab_processOutgoingCalls">"avskjære utgående anrop"</string>
+ <string name="permdesc_processOutgoingCalls">"Lar applikasjonen behandle utgående anrop og endre nummeret som ringes. Ondsinnede applikasjoner kan overvåke, videresende, eller hindre utgående anrop."</string>
+ <string name="permlab_receiveSms">"motta SMS"</string>
+ <string name="permdesc_receiveSms">"Lar applikasjonen motta og behandle SMS-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
+ <string name="permlab_receiveMms">"motta MMS"</string>
+ <string name="permdesc_receiveMms">"Lar applikasjonen motta og behandle MMS-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
+ <string name="permlab_sendSms">"sende SMS-meldinger"</string>
+ <string name="permdesc_sendSms">"Lar applikasjonen sende SMS-meldinger. Ondsinnede applikasjoner kan koste deg penger ved å sende meldinger uten bekreftelse."</string>
+ <string name="permlab_readSms">"lese SMS- og MMS-meldinger"</string>
+ <string name="permdesc_readSms">"Lar applikasjonen lese SMS-meldinger lagret i telefonen eller på SIM-kortet. Ondsinnede applikasjoner kan lese private meldinger."</string>
+ <string name="permlab_writeSms">"redigere SMS- og MMS-meldinger"</string>
+ <string name="permdesc_writeSms">"Lar applikasjonen skrive til SMS-meldinger lagret i telefonen eller på SIM-kortet. Ondsinnede applikasjoner kan slette meldinger."</string>
+ <string name="permlab_receiveWapPush">"motta WAP"</string>
+ <string name="permdesc_receiveWapPush">"Lar applikasjonen motta og behandle WAP-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
+ <string name="permlab_getTasks">"se kjørende applikasjoner"</string>
+ <string name="permdesc_getTasks">"Tillater applikasjonen å hente informasjon om aktive og nylig kjørte programmer. Kan tillate ondsinnede applikasjoner å oppdage privat informasjon om andre applikasjoner."</string>
+ <string name="permlab_reorderTasks">"omordne kjørende applikasjoner"</string>
+ <string name="permdesc_reorderTasks">"Tillater applikasjonen å flytte programmer til forgrunnen eller bakgrunnen. Ondsinnede applikasjoner kan tvinge seg selv til fronten."</string>
+ <string name="permlab_setDebugApp">"aktiver applikasjonsdebugging"</string>
+ <string name="permdesc_setDebugApp">"Lar applikasjonen skru på debugging for en annen applikasjon. Ondsinnede applikasjoner kan bruke dette til å drepe andre applikasjoner."</string>
+ <string name="permlab_changeConfiguration">"endre innstillingene for brukergrensesnitt"</string>
+ <string name="permdesc_changeConfiguration">"Tillater applikasjonen å endre gjeldende innstillinger, slik som språk eller skriftstørrelse."</string>
+ <string name="permlab_restartPackages">"omstarte andre applikasjoner"</string>
+ <string name="permdesc_restartPackages">"Lar applikasjonen tvinge andre applikasjoner til å starte på nytt."</string>
+ <string name="permlab_forceBack">"tvinge applikasjoner til å lukkes"</string>
+ <string name="permdesc_forceBack">"Lar applikasjonen tvinge enhver aktivitet som er i forgrunnen til å lukkes og gå tilbake. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_dump">"hente intern systemtilstand"</string>
+ <string name="permdesc_dump">"Lar applikasjonen hente intern tilstand fra systemet. Onsdinnede applikasjoner kan hente et bredt spekter av privat og sikker informasjon som de vanligvis aldri burde ha behov for."</string>
+ <!-- no translation found for permlab_shutdown (7185747824038909016) -->
+ <skip />
+ <!-- no translation found for permdesc_shutdown (7046500838746291775) -->
+ <skip />
+ <!-- no translation found for permlab_stopAppSwitches (4138608610717425573) -->
+ <skip />
+ <!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
+ <skip />
+ <string name="permlab_runSetActivityWatcher">"overvåke og kontrollere all applikasjonsoppstart"</string>
+ <string name="permdesc_runSetActivityWatcher">"Lar applikasjonen overvåke og kontrollere hvordan systemet starter applikasjoner. Ondsinnede applikasjoner kan ta over systemet helt. Denne rettigheten behøves bare for utvikling, aldri for vanlig bruk av telefonen."</string>
+ <string name="permlab_broadcastPackageRemoved">"kringkaste melding om fjernet pakke"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Lar applikasjonen kringkaste en melding om at en applikasjonspakke er blitt fjernet. Ondsinnede applikasjoner kan bruke dette til å drepe vilkårlige andre kjørende applikasjoner."</string>
+ <string name="permlab_broadcastSmsReceived">"kringkaste melding om mottatt SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Lar applikasjonen kringkaste en melding om at en SMS-melding er mottatt. Ondsinnede applikasjoner kan bruke dette til å forfalske innkommende SMS-meldinger."</string>
+ <string name="permlab_broadcastWapPush">"kringkaste melding om mottatt WAP-PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Lar applikasjonen kringkaste en melding om at en WAP-PUSH-melding er blitt mottatt. Ondsinnede applikasjoner kan bruke dette for å forfalske MMS-kvitteringer eller i det stille erstatte innholdet av vilkårlige nettsider med ondsinnede varianter."</string>
+ <string name="permlab_setProcessLimit">"begrense antallet kjørende prosesser"</string>
+ <string name="permdesc_setProcessLimit">"Lar applikasjonen kontrollere maksimalt antall kjørende prosesser. Behøves aldri for vanlige applikasjoner."</string>
+ <string name="permlab_setAlwaysFinish">"få alle bakgrunnsapplikasjoner til å lukkes"</string>
+ <string name="permdesc_setAlwaysFinish">"Lar applikasjonen kontrollere om aktiviteter alltid avsluttes når de sendes til bakgrunnen. Behøves aldri for vanlige applikasjoner."</string>
+ <string name="permlab_batteryStats">"endre batteristatistikk"</string>
+ <string name="permdesc_batteryStats">"Lar applikasjonen endre på innsamlet batteristatistikk. Ikke ment for vanlige applikasjoner."</string>
+ <!-- no translation found for permlab_backup (470013022865453920) -->
+ <skip />
+ <!-- no translation found for permdesc_backup (2305432853944929371) -->
+ <skip />
+ <string name="permlab_internalSystemWindow">"vis uautoriserte vinduer"</string>
+ <string name="permdesc_internalSystemWindow">"Tillater at det opprettes vinduer ment for bruk av systemets interne brukergrensesnitt. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_systemAlertWindow">"vise advarsler på systemnivå"</string>
+ <string name="permdesc_systemAlertWindow">"Lar applikasjonen vise systemadvarselvinduer. Ondsinnede applikasjoner kan ta over hele skjermen."</string>
+ <string name="permlab_setAnimationScale">"endre global animasjonshastighet"</string>
+ <string name="permdesc_setAnimationScale">"Lar applikasjonen endre den globale animasjonshastigheten (raskere eller tregere animasjoner) når som helst."</string>
+ <string name="permlab_manageAppTokens">"styre applikasjonssymboler"</string>
+ <string name="permdesc_manageAppTokens">"Lar applikasjoner lage og vedlikeholde sine egne symboler, noe som lar dem overstyre den vanlige Z-ordningen. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_injectEvents">"trykke taster og kontrolknapper"</string>
+ <string name="permdesc_injectEvents">"Lar applikasjonen levere sine egne inndatahendelser (tastetrykk osv.) til andre applikasjoner. Ondsinnede applikasjoner kan bruke dette for å ta over telefonen."</string>
+ <string name="permlab_readInputState">"ta opp hva som skrives og gjøres"</string>
+ <string name="permdesc_readInputState">"Lar applikasjonen overvåke tastetrykk selv når interaksjonen er med et annet program (som å skrive inn et passord). Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_bindInputMethod">"binde til en inndatametode"</string>
+ <string name="permdesc_bindInputMethod">"Lar applikasjonen binde til toppnivågrensesnittet for en inndatametode. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_setOrientation">"snu skjermen"</string>
+ <string name="permdesc_setOrientation">"Lar applikasjonen rotere skjermen når som helst. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_signalPersistentProcesses">"sende Linux-signaler til applikasjoner"</string>
+ <string name="permdesc_signalPersistentProcesses">"Lar applikasjonen spørre om at et gitt signal blir sendt til alle varige prosesser."</string>
+ <string name="permlab_persistentActivity">"forbli kjørende"</string>
+ <string name="permdesc_persistentActivity">"Lar applikasjonen gjøre deler av seg selv varig, så systemet ikke kan bruke det til andre applikasjoner."</string>
+ <string name="permlab_deletePackages">"slette applikasjoner"</string>
+ <string name="permdesc_deletePackages">"Lar applikasjonen slette Android-pakker. Ondsinnede applikasjoner kan bruke dette for å slette viktige applikasjoner."</string>
+ <string name="permlab_clearAppUserData">"slette andre applikasjoners data"</string>
+ <string name="permdesc_clearAppUserData">"Lar applikasjonen fjerne brukerdata."</string>
+ <string name="permlab_deleteCacheFiles">"slette andre applikasjoners hurtigbuffer"</string>
+ <string name="permdesc_deleteCacheFiles">"Lar applikasjonen to slette hurtigbufferfiler."</string>
+ <string name="permlab_getPackageSize">"måle lagringsplass for applikasjon"</string>
+ <string name="permdesc_getPackageSize">"Lar applikasjonen hente kode-, data- og hurtigbufferstørrelser"</string>
+ <string name="permlab_installPackages">"installere applikasjoner direkte"</string>
+ <string name="permdesc_installPackages">"Lar applikasjonen installere nye eller oppdaterte Android-pakker. Ondsinnede applikasjoner kan bruke dette for å legge til nye applikasjoner med vilkårlig kraftige rettigheter."</string>
+ <string name="permlab_clearAppCache">"slette hurtigbufferdata for alle applikasjoner"</string>
+ <string name="permdesc_clearAppCache">"Lar applikasjonen frigjøre lagringsplass ved å slette filer i applikasjoners hurtigbufferkatalog. Tilgangen er vanligvis sterkt begrenset, til systemprosesser."</string>
+ <string name="permlab_readLogs">"lese systemets loggfiler"</string>
+ <string name="permdesc_readLogs">"Lar applikasjonen to lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med telefonen, men skal ikke inneholde personlig eller privat informasjon."</string>
+ <string name="permlab_diagnostic">"lese/skrive ressurser eid av diag"</string>
+ <string name="permdesc_diagnostic">"Lar applikasjonen to lese og skrive enhver ressurs eid av gruppen diag; for eksempel, filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør KUN brukes for maskinvarespesifikke diagnoseverktøy laget av operatøren eller produsenten."</string>
+ <string name="permlab_changeComponentState">"aktivere eller deaktigere applikasjonskomponenter"</string>
+ <string name="permdesc_changeComponentState">"Lar applikasjonen endre om en komponent i en annen applikasjon er aktivert eller ikke. Ondsinnede applikasjoner kan bruke dette for å deaktivere viktige telefonfunksjoner. Denne rettigheten må brukes med forsiktighet, ettersom det er mulig å få applikasjonskomponenter inn i en ubrukelig, inkonsistent eller ustabil tilstand."</string>
+ <string name="permlab_setPreferredApplications">"velge foretrukne applikasjoner"</string>
+ <string name="permdesc_setPreferredApplications">"Lar applikasjonen endre valgene for foretrukne applikasjoner. Dette kan gi ondsinnede applikasjoner tilgang til i det stille å endre hvilke applikasjoner som kjøres, og slik gi seg ut for å være en eksisterende applikasjon og samle private data."</string>
+ <string name="permlab_writeSettings">"endre globale systeminnstillinger"</string>
+ <string name="permdesc_writeSettings">"Lar applikasjonen endre systemets innstillingsdata. Ondsinnede applikasjoner kan skade systemets innstillinger."</string>
+ <string name="permlab_writeSecureSettings">"endre sikre systeminnstillinger"</string>
+ <string name="permdesc_writeSecureSettings">"Lar applikasjonen endre systemets sikre innstillingsdata. Ikke ment for bruk av vanlige applikasjoner."</string>
+ <string name="permlab_writeGservices">"redigere Google-tjenestekartet"</string>
+ <string name="permdesc_writeGservices">"Lar applikasjonen redigere Google-tjenestekartet. Ikke ment for bruk av vanlige applikasjoner."</string>
+ <string name="permlab_receiveBootCompleted">"starte automatisk sammen med systemet"</string>
+ <string name="permdesc_receiveBootCompleted">"Lar applikasjonen sette opp at den selv skal starte så fort systemet er ferdig med å slå seg på. Dette kan gjøre at det tar lengre tid å starte telefonen, og at den kan bli tregere fordi applikasjonen alltid kjører."</string>
+ <string name="permlab_broadcastSticky">"sende varige kringkastinger"</string>
+ <string name="permdesc_broadcastSticky">"Lar applikasjonen sende varige kringkastinger, som forblir på systemet etter at kringkastingen er avsluttet. Ondsinnede applikasjoner kan gjøre telefonen treg eller ustabil ved å få den til å bruke for mye minne."</string>
+ <string name="permlab_readContacts">"lese kontaktinformasjon"</string>
+ <string name="permdesc_readContacts">"Lar applikasjonen lese all kontakt- og adresseinformasjon lagret på telefonen. Ondsinnede applikasjoner kan bruke dette for å sende personlige data til andre."</string>
+ <string name="permlab_writeContacts">"skrive kontaktinformasjon"</string>
+ <string name="permdesc_writeContacts">"Lar applikasjonen endre kontakt- og adresseinformasjon lagret på telefonen. Ondsinnede applikasjoner kan bruke dette for å redigere eller endre kontaktinformasjonen."</string>
+ <string name="permlab_writeOwnerData">"skrive eierinformasjon"</string>
+ <string name="permdesc_writeOwnerData">"Lar applikasjonen endre dataene om telefoneieren. Ondsinnede applikasjoner kan bruke dette til å slette eller redigere telefonens eierdata."</string>
+ <string name="permlab_readOwnerData">"lese eierinformasjon"</string>
+ <string name="permdesc_readOwnerData">"Lar applikasjonen lese dataene om telefoneieren. Ondsinnede applikasjoner kan bruke dette til å lese telefonens eierdata."</string>
+ <string name="permlab_readCalendar">"lese kalenderinformasjon"</string>
+ <string name="permdesc_readCalendar">"Lar applikasjonen lese alle kalenderhendelser lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å sende kalenderhendelser til andre."</string>
+ <string name="permlab_writeCalendar">"skrive kalenderinformasjon"</string>
+ <string name="permdesc_writeCalendar">"Lar applikasjonen endre kalenderhendelser lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å slette eller endre kalenderinformasjon."</string>
+ <string name="permlab_accessMockLocation">"lage falske plasseringskilder for testing"</string>
+ <string name="permdesc_accessMockLocation">"Lage falske plassingskilder for testing. Ondsinnede applikasjoner kan bruke dette for å overstyre plasseringen og/eller statusen rapportert av ekte plasseringskilder slik som GPS eller nettverksoperatører."</string>
+ <string name="permlab_accessLocationExtraCommands">"få tilgang til ekstra plasseringskommandoer"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Få tilgang til ekstra kommandoer for plasseringskilder. Ondsinnede applikasjoner kan bruke dette til å forstyrre GPS eller andre plasseringskilder."</string>
+ <!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
+ <skip />
+ <!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
+ <skip />
+ <string name="permlab_accessFineLocation">"nøyaktig (GPS-) plassering"</string>
+ <string name="permdesc_accessFineLocation">"Få tilgang til nøyaktige plasseringskilder som Global Positioning System (GPS) på telefonen, når det er tilgjengelig. Ondsinnede applikasjoner kan bruke dette for å finne ut hvor du er, og kan bruke mer batteri."</string>
+ <string name="permlab_accessCoarseLocation">"grov (nettverksbasert) plassering"</string>
+ <string name="permdesc_accessCoarseLocation">"Få tilgang til grove plasseringskilder som databasen over basestasjoner for å finne ut omtrent hvor telefonen er, når det er tilgjengelig. Ondsinnede applikasjoner kan bruke dette for å finne ut omtrent hvor du er."</string>
+ <string name="permlab_accessSurfaceFlinger">"få tilgang til SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Lar applikasjonen bruke lavnivåfunksjonalitet i SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"lese skjermbufferet"</string>
+ <string name="permdesc_readFrameBuffer">"Lar applikasjonen lese innholdet i skjermbufferet."</string>
+ <string name="permlab_modifyAudioSettings">"endre lydinnstillinger"</string>
+ <string name="permdesc_modifyAudioSettings">"Lar applikasjonen endre globale lydinnstillinger som volum og ruting."</string>
+ <string name="permlab_recordAudio">"ta opp lyd"</string>
+ <string name="permdesc_recordAudio">"Gir applikasjonen tilgang til opptaksstien for lyd."</string>
+ <string name="permlab_camera">"ta bilder"</string>
+ <string name="permdesc_camera">"Lar applikasjonen ta bilder med kameraet. Dette gir applikasjonen til når som helst å se og lagre det kameraet ser."</string>
+ <string name="permlab_brick">"deaktivere telefonen permanent"</string>
+ <string name="permdesc_brick">"Lar applikasjonen deaktivere hele telefonen permanent. Dette er svært farlig."</string>
+ <string name="permlab_reboot">"tvinge omstart av telefon"</string>
+ <string name="permdesc_reboot">"Lar applikasjonen tvinge telefonen til å starte på nytt."</string>
+ <string name="permlab_mount_unmount_filesystems">"montere og avmontere filsystemer"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Lar applikasjonen montere og avmontere filsystemer for uttagbar lagring."</string>
+ <string name="permlab_mount_format_filesystems">"formatere ekstern lagringsplass"</string>
+ <string name="permdesc_mount_format_filesystems">"Lar applikasjonen formatere ekstern lagringsplass."</string>
+ <string name="permlab_vibrate">"kontrollere vibratoren"</string>
+ <string name="permdesc_vibrate">"Lar applikasjonen kontrollere vibratoren."</string>
+ <string name="permlab_flashlight">"kontrollere lommelykten"</string>
+ <string name="permdesc_flashlight">"Lar applikasjonen kontrollere lommelykten."</string>
+ <string name="permlab_hardware_test">"teste maskinvare"</string>
+ <string name="permdesc_hardware_test">"Lar applikasjonen styre diverse enheter med det formål å teste maskinvaren."</string>
+ <string name="permlab_callPhone">"ringe telefonnummer direkte"</string>
+ <string name="permdesc_callPhone">"Lar applikasjonen ringe telefonnummer uten inngripen fra brukeren. Ondsinnede applikasjoner kan forårsake uventede oppringinger på telefonregningen. Merk at dette ikke gir applikasjonen lov til å ringe nødnummer."</string>
+ <string name="permlab_callPrivileged">"ringe vilkårlige telefonnummer direkte"</string>
+ <string name="permdesc_callPrivileged">"Lar applikasjonen ringe hvilket som helst telefonnummer, inkludert nødnummer, uten inngripen fra brukeren. Ondsinnede applikasjoner kan forårsake unødvendige og ulovlige samtaler til nødtjenester."</string>
+ <string name="permlab_locationUpdates">"kontrollere varsling for plasseringsendring"</string>
+ <string name="permdesc_locationUpdates">"Lar applikasjonen slå av/på varsling om plasseringsendringer fra radioen. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_checkinProperties">"få tilgang til egenskaper for innsjekking"</string>
+ <string name="permdesc_checkinProperties">"Gir lese- og skrivetilgang til egenskaper lastet opp av innsjekkingstjenesten. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_bindGadget">"velg gadgeter"</string>
+ <string name="permdesc_bindGadget">"Lar applikasjonen fortelle systemet hvilke gadgeter som kan brukes av hvilke applikasjoner. Med denne rettigheten kan applikasjoner andre applikasjoner tilgang til personlig data. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_modifyPhoneState">"endre telefontilstand"</string>
+ <string name="permdesc_modifyPhoneState">"Lar applikasjonen kontrollere telefonfunksjonaliteten i enheten. En applikasjon med denne rettigheten kan endre nettverk, slå telefonens radio av eller på og lignende uten noensinne å varsle brukeren."</string>
+ <string name="permlab_readPhoneState">"lese telefontilstand"</string>
+ <string name="permdesc_readPhoneState">"Lar applikasjonen få tilgang til telefonfunksjonaliteten i enheten. En applikasjon med denne rettigheten kan få vite enhetens telefonnummer, om en samtale pågår, nummeret samtalen er koblet til og lignende."</string>
+ <string name="permlab_wakeLock">"forhindre telefonen fra å sove"</string>
+ <string name="permdesc_wakeLock">"Lar applikasjonen forhindre telefonen fra å gå i hvilemodus."</string>
+ <string name="permlab_devicePower">"slå telefonen av eller på"</string>
+ <string name="permdesc_devicePower">"Lar applikasjonen skru telefonen av eller på."</string>
+ <string name="permlab_factoryTest">"kjøre i fabrikktestmodus"</string>
+ <string name="permdesc_factoryTest">"Kjøre som en lavnivås produsenttest, med full tilgang til telefonens maskinvare. Kun tilgjengelig når telefonen kjører i produsenttestmodus."</string>
+ <string name="permlab_setWallpaper">"endre bakgrunnsbilde"</string>
+ <string name="permdesc_setWallpaper">"Lar applikasjonen sette systemets bakgrunnsbilde."</string>
+ <string name="permlab_setWallpaperHints">"sette størrelseshint for bakgrunn"</string>
+ <string name="permdesc_setWallpaperHints">"Lar applikasjonen sette størrelseshint for systemets bakgrunnsbilde."</string>
+ <string name="permlab_masterClear">"nullstille systemet til fabrikkinnstillinger"</string>
+ <string name="permdesc_masterClear">"Lar applikasjonen nullstille systemet til fabrikkinnstillinger, noe som vil fjerne alle data, alt oppsett, og alle installerte applikasjoner."</string>
+ <string name="permlab_setTimeZone">"endre tidssone"</string>
+ <string name="permdesc_setTimeZone">"Lar applikasjonen endre telefonens tidssone."</string>
+ <string name="permlab_getAccounts">"oppdage kjente kontoer"</string>
+ <string name="permdesc_getAccounts">"Lar applikasjonen hente listen over kontoer telefonen kjenner til."</string>
+ <string name="permlab_accessNetworkState">"se nettverkstilstand"</string>
+ <string name="permdesc_accessNetworkState">"Lar applikasjonen se tilstanden til alle nettverk."</string>
+ <string name="permlab_createNetworkSockets">"full internett-tilgang"</string>
+ <string name="permdesc_createNetworkSockets">"Lar applikasjonen opprette vilkårlige nettverkstilkoblinger."</string>
+ <string name="permlab_writeApnSettings">"skrive APN-innstillinger"</string>
+ <string name="permdesc_writeApnSettings">"Lar applikasjonen to endre APN-innstillinger slik som mellomtjener eller port for hvilket som helst aksesspunkt."</string>
+ <string name="permlab_changeNetworkState">"endre nettverkskonnektivitet"</string>
+ <string name="permdesc_changeNetworkState">"Lar applikasjonen endre tilstanden til nettverkskonnektivitet."</string>
+ <string name="permlab_changeBackgroundDataSetting">"endre innstilling for bakgrunnsdata"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Lar applikasjonen endre innstillingen for bakgrunnsdata."</string>
+ <string name="permlab_accessWifiState">"se tilstand for trådløse nettverk"</string>
+ <string name="permdesc_accessWifiState">"Lar applikasjonen få se informasjon om tilstanden til de trådløse nettene."</string>
+ <string name="permlab_changeWifiState">"endre tilstand for trådløse nettverk"</string>
+ <string name="permdesc_changeWifiState">"Lar applikasjonen koble til og fra trådløse aksesspunkt, og å gjøre endringer i konfigurerte trådløse nettverk."</string>
+ <!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
+ <skip />
+ <!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
+ <skip />
+ <string name="permlab_bluetoothAdmin">"Bluetooth-administrasjon"</string>
+ <string name="permdesc_bluetoothAdmin">"Lar applikasjonen konfigurere den lokale Bluetooth-telefonen, og å oppdage og pare med andre enheter."</string>
+ <string name="permlab_bluetooth">"opprette Bluetooth-tilkoblinger"</string>
+ <string name="permdesc_bluetooth">"Lar applikasjonen se konfigurasjonen til den lokale Bluetooth-telefonen, og å opprette og godta tilkoblinger med parede enheter."</string>
+ <string name="permlab_disableKeyguard">"slå av tastaturlås"</string>
+ <string name="permdesc_disableKeyguard">"Lar applikasjonen slå av tastaturlåsen og enhver tilknyttet passordsikkerhet. Et legitimt eksempel på dette er at telefonen slår av tastaturlåsen når den mottar et innkommende anrop, og så slår den på igjen når samtalen er over."</string>
+ <string name="permlab_readSyncSettings">"lese synkroniseringsinnstillinger"</string>
+ <string name="permdesc_readSyncSettings">"Lar applikasjonen lese synkroniseringsinnstillingene, som for eksempel om kontakter blir synkronisert."</string>
+ <string name="permlab_writeSyncSettings">"skrive synkroniseringsinnstillinger"</string>
+ <string name="permdesc_writeSyncSettings">"Lar applikasjonen to endre på synkroniseringsinnstillingene, som for eksempel om kontakter blir synkronisert."</string>
+ <string name="permlab_readSyncStats">"lese synkroniseringsstatistikk"</string>
+ <string name="permdesc_readSyncStats">"Lar applikasjonen lese synkroniseringsstatistikk, som for eksempel historien over alle synkroniseringer utført."</string>
+ <string name="permlab_subscribedFeedsRead">"lese abonnement på nyhetskilder"</string>
+ <string name="permdesc_subscribedFeedsRead">"Lar applikasjonen hente detaljer om hvilke nyhetskilder som synkroniseres."</string>
+ <string name="permlab_subscribedFeedsWrite">"endre abonnement på nyhetskilder"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Lar applikasjonen redigere hvilke nyhetskilder som synkroniseres. Dette kan gi en ondsinnet applikasjon tilgang til å endre hvilke nyhetskilder som synkroniseres."</string>
+ <string name="permlab_readDictionary">"lese brukerdefinert ordliste"</string>
+ <string name="permdesc_readDictionary">"Lar applikasjonen lese private ord, navn og uttrykk som brukeren har lagret i den brukerdefinerte ordlisten."</string>
+ <string name="permlab_writeDictionary">"skrive til brukerdefinert ordliste"</string>
+ <string name="permdesc_writeDictionary">"Lar applikasjonen skrive nye ord til den brukerdefinerte ordlisten."</string>
+ <!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
+ <skip />
+ <!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
+ <skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Hjemmenummer"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Arbeid"</item>
- <item msgid="1103601433382158155">"Faks arbeid"</item>
- <item msgid="1735177144948329370">"Faks hjemme"</item>
- <item msgid="603878674477207394">"Personsøker"</item>
- <item msgid="1650824275177931637">"Annen"</item>
- <item msgid="9192514806975898961">"Egendefinert…"</item>
+ <item>"Hjemme"</item>
+ <item>"Mobil"</item>
+ <item>"Arbeid"</item>
+ <item>"Faks arbeid"</item>
+ <item>"Faks hjemme"</item>
+ <item>"Personsøker"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Hjemme"</item>
- <item msgid="7084237356602625604">"Arbeid"</item>
- <item msgid="1112044410659011023">"Annen"</item>
- <item msgid="2374913952870110618">"Egendefinert…"</item>
+ <item>"Hjemme"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobil"</string>
+ <!-- no translation found for mobileEmailTypeName (2858957283716687707) -->
+ <skip />
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Hjemme"</item>
- <item msgid="5629153956045109251">"Arbeid"</item>
- <item msgid="4966604264500343469">"Annen"</item>
- <item msgid="4932682847595299369">"Egendefinert…"</item>
+ <item>"Hjemme"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Hjemme"</item>
- <item msgid="1359644565647383708">"Arbeid"</item>
- <item msgid="7868549401053615677">"Annen"</item>
- <item msgid="3145118944639869809">"Egendefinert…"</item>
+ <item>"Hjemme"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Arbeid"</item>
- <item msgid="4378074129049520373">"Annen"</item>
- <item msgid="3455047468583965104">"Egendefinert…"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Skriv inn PIN-kode:"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Gal PIN-kode!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"For å låse opp, trykk på Meny og deretter 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nødnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Ingen operatør)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skjermen er låst"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Trykk på menyknappen for å låse opp eller ringe et nødnummer."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Trykk på menyknappen for å låse opp."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Tegn mønster for å låse opp"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Nødanrop"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Riktig!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Beklager, prøv igjen:"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Lader (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Fullt ladet"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Koble til en batterilader."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Mangler SIM-kort."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Ikke noe SIM-kort i telefonen."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Sett inn et SIM-kort."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Nettverk ikke tillatt"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-kortet er PUK-låst."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Se manualen eller kontakt kundeservice."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kortet er låst."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Låser opp SIM-kort…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Prøv igjen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Glemt mønsteret?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"For mange mønsterforsøk!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"For å låse opp, logg på med Google-kontoen din"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Brukernavn (e-post)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Passord"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Logg inn"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ugyldig brukernavn eller passord."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Fjern"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen varslinger"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktiviteter"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varslinger"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Lader…"</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Koble til en lader"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet er nesten tomt:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"mindre enn <xliff:g id="NUMBER">%d%%</xliff:g> igjen."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Hvorfor?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Factory test failed"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"The FACTORY_TEST action is only supported for packages installed in /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"No package was found that provides the FACTORY_TEST action."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reboot"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Siden \'<xliff:g id="TITLE">%s</xliff:g> sier:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Naviger bort fra denne siden?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Velg OK for å fortsette, eller Avbryt for å forbli på denne siden."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Bekreft"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lese nettleserens historie og bokmerker"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Lar applikasjonen lese alle adresser nettleseren har besøkt, og alle nettleserens bokmerker."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"skrive til nettleserens historie og bokmerker"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Lar applikasjonen endre nettleserens historie og bokmerker lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å fjerne eller redigere nettleserens data."</string>
- <string name="save_password_message" msgid="767344687139195790">"Ønsker du at nettleseren skal huske dette passordet?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nå"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Aldri"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Du har ikke de nødvendige rettighetene til å åpne denne siden."</string>
- <string name="text_copied" msgid="4985729524670131385">"Kopierte tekst til utklippstavlen."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Mer"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"menyknapp+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"mellomrom"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"slett"</string>
- <string name="search_go" msgid="8298016669822141719">"Søk"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"For én måned siden"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"For over en måned siden"</string>
+ <string name="keyguard_password_enter_pin_code">"Skriv inn PIN-kode:"</string>
+ <string name="keyguard_password_wrong_pin_code">"Gal PIN-kode!"</string>
+ <string name="keyguard_label_text">"For å låse opp, trykk menuknappen fulgt av 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Nødnummer"</string>
+ <string name="lockscreen_carrier_default">"(Ingen operatør)"</string>
+ <string name="lockscreen_screen_locked">"Skjermen er låst"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Trykk på menyknappen for å låse opp eller ringe et nødnummer."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Trykk på menyknappen for å låse opp."</string>
+ <string name="lockscreen_pattern_instructions">"Tegn mønster for å låse opp"</string>
+ <string name="lockscreen_emergency_call">"Nødanrop"</string>
+ <string name="lockscreen_pattern_correct">"Riktig!"</string>
+ <string name="lockscreen_pattern_wrong">"Beklager, prøv igjen:"</string>
+ <string name="lockscreen_plugged_in">"Lader (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Koble til en batterilader."</string>
+ <string name="lockscreen_missing_sim_message_short">"Mangler SIM-kort."</string>
+ <string name="lockscreen_missing_sim_message">"Ikke noe SIM-kort i telefonen."</string>
+ <string name="lockscreen_missing_sim_instructions">"Sett inn et SIM-kort."</string>
+ <string name="lockscreen_network_locked_message">"Nettverk ikke tillatt"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-kortet er PUK-låst."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Se manualen eller kontakt kundeservice."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-kortet er låst."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Låser opp SIM-kort…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Prøv igjen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Glemt mønsteret?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"For mange mønsterforsøk!"</string>
+ <string name="lockscreen_glogin_instructions">"For å låse opp, logg inn med Google-kontoen din"</string>
+ <string name="lockscreen_glogin_username_hint">"Brukernavn (e-post)"</string>
+ <string name="lockscreen_glogin_password_hint">"Passord"</string>
+ <string name="lockscreen_glogin_submit_button">"Logg inn"</string>
+ <string name="lockscreen_glogin_invalid_input">"Ugyldig brukernavn eller passord."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Ingen varslinger"</string>
+ <string name="status_bar_ongoing_events_title">"Aktiviteter"</string>
+ <string name="status_bar_latest_events_title">"Varslinger"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Lader…"</string>
+ <string name="battery_low_title">"Koble til en lader"</string>
+ <string name="battery_low_subtitle">"Batteriet er nesten tomt:"</string>
+ <string name="battery_low_percent_format">"mindre enn <xliff:g id="NUMBER">%d%%</xliff:g> igjen."</string>
+ <!-- no translation found for battery_low_why (7655196144309694753) -->
+ <skip />
+ <string name="factorytest_failed">"Factory test failed"</string>
+ <string name="factorytest_not_system">"The FACTORY_TEST action is only supported for packages installed in /system/app."</string>
+ <string name="factorytest_no_action">"No package was found that provides the FACTORY_TEST action."</string>
+ <string name="factorytest_reboot">"Reboot"</string>
+ <string name="js_dialog_title">"Siden \'<xliff:g id="TITLE">%s</xliff:g> sier:\""</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Naviger bort fra denne siden?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Velg OK for å fortsette, eller Avbryt for å forbli på denne siden."</string>
+ <string name="save_password_label">"Bekreft"</string>
+ <!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
+ <skip />
+ <!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
+ <skip />
+ <!-- no translation found for permlab_writeHistoryBookmarks (9009434109836280374) -->
+ <skip />
+ <!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
+ <skip />
+ <string name="save_password_message">"Ønsker du at nettleseren skal huske dette passordet?"</string>
+ <string name="save_password_notnow">"Ikke nå"</string>
+ <string name="save_password_remember">"Husk"</string>
+ <string name="save_password_never">"Aldri"</string>
+ <string name="open_permission_deny">"Du har ikke de nødvendige rettighetene til å åpne denne siden."</string>
+ <string name="text_copied">"Kopierte tekst til utklippstavlen."</string>
+ <string name="more_item_label">"Mer"</string>
+ <string name="prepend_shortcut_label">"menyknapp+"</string>
+ <string name="menu_space_shortcut_label">"mellomrom"</string>
+ <string name="menu_enter_shortcut_label">"enter"</string>
+ <string name="menu_delete_shortcut_label">"slett"</string>
+ <string name="search_go">"Søk"</string>
+ <string name="oneMonthDurationPast">"For en måned siden"</string>
+ <string name="beforeOneMonthDurationPast">"For over en måned siden"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"for et sekund siden"</item>
- <item quantity="other" msgid="3903706804349556379">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
+ <item quantity="one">"for et sekund siden"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"for et minutt siden"</item>
- <item quantity="other" msgid="2176942008915455116">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
+ <item quantity="one">"for et minutt siden"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"for en time siden"</item>
- <item quantity="other" msgid="2467273239587587569">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
+ <item quantity="one">"for en time siden"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"i går"</item>
- <item quantity="other" msgid="2479586466153314633">"for <xliff:g id="COUNT">%d</xliff:g> dager siden"</item>
+ <item quantity="one">"i går"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> dager siden"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"om et sekund"</item>
- <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ <item quantity="one">"om et sekund"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"om et minutt"</item>
- <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
+ <item quantity="one">"om et minutt"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"om et minutt"</item>
- <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
+ <item quantity="one">"om et minutt"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"i morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dager"</item>
+ <item quantity="one">"i morgen"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dager"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 sek siden"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek siden"</item>
+ <item quantity="one">"1 sek siden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sek siden"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 min siden"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min siden"</item>
+ <item quantity="one">"1 min siden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> min siden"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 t siden"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> t siden"</item>
+ <item quantity="one">"1 t siden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> t siden"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"i går"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> d siden"</item>
+ <item quantity="one">"i går"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> d siden"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"om 1 sek"</item>
- <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
+ <item quantity="one">"om 1 sek"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"om 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ <item quantity="one">"om 1 min"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> min"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"om 1 t"</item>
- <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> t"</item>
+ <item quantity="one">"om 1 t"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> t"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"i morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> d"</item>
+ <item quantity="one">"i morgen"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> d"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s"</string>
- <string name="day" msgid="8144195776058119424">"dag"</string>
- <string name="days" msgid="4774547661021344602">"dager"</string>
- <string name="hour" msgid="2126771916426189481">"time"</string>
- <string name="hours" msgid="894424005266852993">"timer"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"min"</string>
- <string name="second" msgid="3184235808021478">"s"</string>
- <string name="seconds" msgid="3161515347216589235">"s"</string>
- <string name="week" msgid="5617961537173061583">"uke"</string>
- <string name="weeks" msgid="6509623834583944518">"uker"</string>
- <string name="year" msgid="4001118221013892076">"Ã¥r"</string>
- <string name="years" msgid="6881577717993213522">"Ã¥r"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Hverdager (man–fre)"</string>
- <string name="daily" msgid="5738949095624133403">"Hver dag"</string>
- <string name="weekly" msgid="983428358394268344">"Hver <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"En gang i måneden"</string>
- <string name="yearly" msgid="1519577999407493836">"En gang i året"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Kan ikke spille video"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Beklager, denne videoen er ikke gyldig for streaming til denne enheten."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Beklager, kan ikke spille denne videoen."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"middag"</string>
- <string name="Noon" msgid="3342127745230013127">"Middag"</string>
- <string name="midnight" msgid="7166259508850457595">"midnatt"</string>
- <string name="Midnight" msgid="5630806906897892201">"Midnatt"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Merk alt"</string>
- <string name="selectText" msgid="3889149123626888637">"Merk tekst"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Slutt å merke tekst"</string>
- <string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
- <string name="cutAll" msgid="2436383270024931639">"Klipp ut alt"</string>
- <string name="copy" msgid="2681946229533511987">"Kopier"</string>
- <string name="copyAll" msgid="2590829068100113057">"Kopier alt"</string>
- <string name="paste" msgid="5629880836805036433">"Lim inn"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Kopier URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Inndatametode"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Legg «%s» til ordlisten"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Rediger tekst"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Lite plass"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Det begynner å bli lite lagringsplass på telefonen."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Avbryt"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Merk"</string>
- <string name="capital_on" msgid="1544682755514494298">"PÃ¥"</string>
- <string name="capital_off" msgid="6815870386972805832">"Av"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Complete action using"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Use by default for this action."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Clear default in Home Settings &gt; Applications &gt; Manage applications."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Select an action"</string>
- <string name="noApplications" msgid="1691104391758345586">"No applications can perform this action."</string>
- <string name="aerr_title" msgid="653922989522758100">"Sorry!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has stopped unexpectedly. Please try again."</string>
- <string name="aerr_process" msgid="1551785535966089511">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has stopped unexpectedly. Please try again."</string>
- <string name="anr_title" msgid="3100070910664756057">"Sorry!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in application <xliff:g id="APPLICATION">%2$s</xliff:g>) is not responding."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Application <xliff:g id="APPLICATION">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
- <string name="anr_process" msgid="1246866008169975783">"Process <xliff:g id="PROCESS">%1$s</xliff:g> is not responding."</string>
- <string name="force_close" msgid="3653416315450806396">"Force close"</string>
- <string name="report" msgid="4060218260984795706">"Rapportér"</string>
- <string name="wait" msgid="7147118217226317732">"Wait"</string>
- <string name="debug" msgid="9103374629678531849">"Debug"</string>
- <string name="sendText" msgid="5132506121645618310">"Select an action for text"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Ringetonevolum"</string>
- <string name="volume_music" msgid="5421651157138628171">"Medievolum"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Spiller over Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Samtalevolum"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth-samtalevolum"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Alarmvolum"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Varslingsvolum"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volum"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Standard ringetone"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standard ringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Stille"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Ukjent ringetone"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"%s"</string>
+ <string name="day">"dag"</string>
+ <string name="days">"dager"</string>
+ <string name="hour">"time"</string>
+ <string name="hours">"timer"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"min"</string>
+ <string name="second">"s"</string>
+ <string name="seconds">"s"</string>
+ <string name="week">"uke"</string>
+ <string name="weeks">"uker"</string>
+ <string name="year">"Ã¥r"</string>
+ <string name="years">"Ã¥r"</string>
+ <string name="every_weekday">"Hverdager (man–fre)"</string>
+ <string name="daily">"Hver dag"</string>
+ <string name="weekly">"Hver <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"En gang i måneden"</string>
+ <string name="yearly">"En gang i året"</string>
+ <string name="VideoView_error_title">"Kan ikke spille video"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Beklager, denne videoen er ikke gyldig for streaming til denne enheten."</string>
+ <string name="VideoView_error_text_unknown">"Beklager, kan ikke spille denne videoen."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"middag"</string>
+ <string name="Noon">"Middag"</string>
+ <string name="midnight">"midnatt"</string>
+ <string name="Midnight">"Midnatt"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Merk alt"</string>
+ <string name="selectText">"Merk tekst"</string>
+ <string name="stopSelectingText">"Slutt å merke tekst"</string>
+ <string name="cut">"Klipp ut"</string>
+ <string name="cutAll">"Klipp ut alt"</string>
+ <string name="copy">"Kopier"</string>
+ <string name="copyAll">"Kopier alt"</string>
+ <string name="paste">"Lim inn"</string>
+ <string name="copyUrl">"Kopier URL"</string>
+ <string name="inputMethod">"Inndatametode"</string>
+ <string name="addToDictionary">"Legg \\\"%s\\\" til ordlisten"</string>
+ <string name="editTextMenuTitle">"Rediger tekst"</string>
+ <string name="low_internal_storage_view_title">"Lite plass"</string>
+ <string name="low_internal_storage_view_text">"Det begynner å bli lite lagringsplass på telefonen."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Avbryt"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Avbryt"</string>
+ <string name="dialog_alert_title">"Merk"</string>
+ <string name="capital_on">"PÃ¥"</string>
+ <string name="capital_off">"Av"</string>
+ <string name="whichApplication">"Complete action using"</string>
+ <string name="alwaysUse">"Use by default for this action."</string>
+ <string name="clearDefaultHintMsg">"Clear default in Home Settings &gt; Applications &gt; Manage applications."</string>
+ <string name="chooseActivity">"Select an action"</string>
+ <string name="noApplications">"No applications can perform this action."</string>
+ <string name="aerr_title">"Sorry!"</string>
+ <string name="aerr_application">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has stopped unexpectedly. Please try again."</string>
+ <string name="aerr_process">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has stopped unexpectedly. Please try again."</string>
+ <string name="anr_title">"Sorry!"</string>
+ <string name="anr_activity_application">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in application <xliff:g id="APPLICATION">%2$s</xliff:g>) is not responding."</string>
+ <string name="anr_activity_process">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
+ <string name="anr_application_process">"Application <xliff:g id="APPLICATION">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
+ <string name="anr_process">"Process <xliff:g id="PROCESS">%1$s</xliff:g> is not responding."</string>
+ <string name="force_close">"Force close"</string>
+ <!-- no translation found for report (4060218260984795706) -->
+ <skip />
+ <string name="wait">"Wait"</string>
+ <string name="debug">"Debug"</string>
+ <string name="sendText">"Select an action for text"</string>
+ <string name="volume_ringtone">"Ringetonevolum"</string>
+ <string name="volume_music">"Medievolum"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Spiller over Bluetooth"</string>
+ <string name="volume_call">"Samtalevolum"</string>
+ <string name="volume_bluetooth_call">"Bluetooth-samtalevolum"</string>
+ <string name="volume_alarm">"Alarmvolum"</string>
+ <string name="volume_notification">"Varslingsvolum"</string>
+ <string name="volume_unknown">"Volum"</string>
+ <string name="ringtone_default">"Standard ringetone"</string>
+ <string name="ringtone_default_with_actual">"Standard ringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Stille"</string>
+ <string name="ringtone_picker_title">"Ringetoner"</string>
+ <string name="ringtone_unknown">"Ukjent ringetone"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Trådløsnett i nærheten"</item>
- <item quantity="other" msgid="4192424489168397386">"Trådløsnett i nærheten"</item>
+ <item quantity="one">"Trådløsnett i nærheten"</item>
+ <item quantity="other">"Trådløsnett i nærheten"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Åpent trådløsnett i nærheten"</item>
- <item quantity="other" msgid="7915895323644292768">"Åpne trådløsnett i nærheten"</item>
+ <item quantity="one">"Åpent trådløsnett i nærheten"</item>
+ <item quantity="other">"Åpne trådløsnett i nærheten"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Sett inn tegn"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Ukjent applikasjon"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Sender SMS-meldinger"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Et stort antall SMS-meldinger blir sendt. Velg «OK» for å fortsette, eller «Avbryt» for å avbryte sendingen."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Avbryt"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Lagre"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Trenger ingen rettigheter"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Skjul"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Vis alle"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Laster inn…"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB koblet til"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Du har koblet telefonen til en datamaskin via USB. Velg «Montér» dersom du ønsker å kopiere filer mellom datmaskinen og minnekortet i telefonen."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Montér"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Ikke montér"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Det oppsto et problem med å bruke minnekortet ditt for USB-lagring."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB tilkoblet"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Velg om du ønsker å kopiere filer til/fra en datamaskin."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Slå av USB-lagring"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Velg for å slå av USB-lagring."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Slå av USB-lagring"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Før du slår av USB-lagring, sjekk at du har avmontert enheten i USB-verten. Velg «slå av» for å slå av USB-lagring."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Slå av"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Avbryt"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Det oppsto et problem under avslutningen av USB-lagring. Sjekk at USB-verten har avmontert og prøv igjen."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatere minnekort"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Er du sikker på at du ønsker å formatere minnekortet? Alle data på kortet vil gå tapt."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-debugging tilkoblet"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"En datamaskin er koblet til telefonen."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Velg inndatametode"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
- <string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Forbereder minnekort"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Sjekker for feil."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Tomt minnekort"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"Minnekortet er tomt eller har et ikke-støttet filsystem."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Skadet minnekort"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"Minnekortet er skadet. Du må kanskje formatere det."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Minnekortet ble tatt ut uventet"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Avmonter minnekortet før det tas ut, for å unngå datatap."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Trygt å ta ut minnekort"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Det er trygt å ta ut minnekortet."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Minnekortet ble tatt ut"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"Minnekortet ble fjernet. Sett inn et nytt."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Fant ingen tilsvarende aktiviteter"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"oppdater statistikk over komponentbruk"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Tillater endring av innsamlet data om bruk av komponenter. Ikke ment for vanlige applikasjoner."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Trykk to ganger for zoomkontroll"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Feil under oppakking av gadget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"GÃ¥"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Søk"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Send"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Neste"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Utført"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Utfør"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Ring nummeret"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Lag kontakt"\n"med nummeret <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"valgt"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"ikke valgt"</string>
+ <string name="select_character">"Sett inn tegn"</string>
+ <string name="sms_control_default_app_name">"Ukjent applikasjon"</string>
+ <string name="sms_control_title">"Sending SMS messages"</string>
+ <string name="sms_control_message">"A large number of SMS messages are being sent. Select \"OK\" to continue, or \"Cancel\" to stop sending."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Avbryt"</string>
+ <string name="date_time_set">"Lagre"</string>
+ <string name="default_permission_group">"Standard"</string>
+ <string name="no_permissions">"Trenger ingen rettigheter"</string>
+ <string name="perms_hide"><b>"Skjul"</b></string>
+ <string name="perms_show_all"><b>"Vis alle"</b></string>
+ <string name="googlewebcontenthelper_loading">"Laster inn…"</string>
+ <string name="usb_storage_title">"USB koblet til"</string>
+ <string name="usb_storage_message">"Du har koblet telefonen til en datamaskin via USB. Velg \"Monter\" dersom du ønsker å kopiere filer mellom datmaskinen og minnekortet i telefonen."</string>
+ <string name="usb_storage_button_mount">"Monter"</string>
+ <string name="usb_storage_button_unmount">"Ikke monter"</string>
+ <string name="usb_storage_error_message">"Det oppsto et problem med å bruke minnekortet ditt for USB-lagring."</string>
+ <string name="usb_storage_notification_title">"USB tilkoblet"</string>
+ <string name="usb_storage_notification_message">"Velg om du ønsker å kopiere filer til/fra en datamaskin."</string>
+ <string name="usb_storage_stop_notification_title">"Slå av USB-lagring"</string>
+ <string name="usb_storage_stop_notification_message">"Velg for å slå av USB-lagring."</string>
+ <string name="usb_storage_stop_title">"Slå av USB-lagring"</string>
+ <string name="usb_storage_stop_message">"Før du slår av USB-lagring, sjekk at du har avmontert enheten i USB-verten. Velg «slå av» for å slå av USB-lagring."</string>
+ <string name="usb_storage_stop_button_mount">"Slå av"</string>
+ <string name="usb_storage_stop_button_unmount">"Avbryt"</string>
+ <string name="usb_storage_stop_error_message">"Det oppsto et problem under avslutningen av USB-lagring. Sjekk at USB-verten har avmontert og prøv igjen."</string>
+ <string name="extmedia_format_title">"Formatere minnekort"</string>
+ <string name="extmedia_format_message">"Er du sikker på at du ønsker å formatere minnekortet? Alle data på kortet vil gå tapt."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Velg inndatametode"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
+ <string name="candidates_style">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
+ <string name="ext_media_checking_notification_title">"Forbereder minnekort"</string>
+ <!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
+ <skip />
+ <string name="ext_media_nofs_notification_title">"Tomt minnekort"</string>
+ <!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
+ <skip />
+ <string name="ext_media_unmountable_notification_title">"Skadet minnekort"</string>
+ <!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
+ <skip />
+ <string name="ext_media_badremoval_notification_title">"Minnekortet ble tatt ut uventet"</string>
+ <string name="ext_media_badremoval_notification_message">"Avmonter minnekortet før det tas ut, for å unngå datatap."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Trygt å ta ut minnekort"</string>
+ <!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
+ <skip />
+ <string name="ext_media_nomedia_notification_title">"Minnekortet ble tatt ut"</string>
+ <!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
+ <skip />
+ <string name="activity_list_empty">"Fant ingen tilsvarende aktiviteter"</string>
+ <string name="permlab_pkgUsageStats">"oppdater statistikk over komponentbruk"</string>
+ <string name="permdesc_pkgUsageStats">"Tillater endring av innsamlet data om bruk av komponenter. Ikke ment for vanlige applikasjoner."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Trykk to ganger for zoomkontroll"</string>
+ <string name="gadget_host_error_inflating">"Feil under oppakking av gadget"</string>
+ <string name="ime_action_go">"GÃ¥"</string>
+ <string name="ime_action_search">"Søk"</string>
+ <string name="ime_action_send">"Send"</string>
+ <string name="ime_action_next">"Neste"</string>
+ <string name="ime_action_done">"Utført"</string>
+ <string name="ime_action_default">"Utfør"</string>
+ <!-- no translation found for dial_number_using (5789176425167573586) -->
+ <skip />
+ <!-- no translation found for create_contact_using (4947405226788104538) -->
+ <skip />
+ <!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
+ <skip />
+ <!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 709e7cc..2bbd02d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -15,695 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"kB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"&lt;zonder titel&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Geen telefoonnummer)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Onbekend)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Voicemail"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Verbindingsprobleem of ongeldige MMI-code."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Service is ingeschakeld."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Service is ingeschakeld voor:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Service is uitgeschakeld."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"De registratie is voltooid."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Wissen uitgevoerd."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Onjuist wachtwoord."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI voltooid."</string>
- <string name="badPin" msgid="5085454289896032547">"De oude PIN-code die u heeft ingevoerd, is onjuist."</string>
- <string name="badPuk" msgid="5702522162746042460">"De PUK-code die u heeft ingevoerd, is onjuist."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"De PIN-codes die u heeft ingevoerd, komen niet overeen."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Voer een PIN-code van 4 tot 8 cijfers in."</string>
- <string name="needPuk" msgid="919668385956251611">"Uw SIM-kaart is vergrendeld met de PUK-code. Typ de PUK-code om te ontgrendelen."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Voer de PUK2-code in om de SIM-kaart te ontgrendelen."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Inkomende beller-id"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Uitgaande beller-id"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Oproep doorschakelen"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Wisselgesprek"</string>
- <string name="BaMmi" msgid="455193067926770581">"Oproep blokkeren"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Wachtwoordwijziging"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN-wijziging"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Nummer van beller beschikbaar"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Nummer van beller beperkt"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Driewegs bellen"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Ongewenste, vervelende oproepen weigeren"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Weergave van nummer van beller"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Niet storen"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Beller-id standaard ingesteld op \'beperkt\'. Volgende oproep: beperkt."</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Beller-id standaard ingesteld op \'beperkt\'. Volgende oproep: onbeperkt."</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: beperkt."</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: onbeperkt."</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Service niet voorzien."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"De instelling voor beller-id kan niet worden gewijzigd."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Beperkte toegang gewijzigd"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Gegevensservice is geblokkeerd."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Alarmservice is geblokkeerd."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Spraak-/SMS-service is geblokkeerd."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Alle spraak-/SMS-services zijn geblokkeerd."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Spraak"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Gegevens"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynchroon"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synchroniseren"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pakket"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Roamingaanduiding aan"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Roamingaanduiding uit"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Roamingaanduiding knippert"</string>
- <string name="roamingText3" msgid="5148255027043943317">"Uit de buurt"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Buiten het gebouw"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming - Voorkeurssysteem"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming - Beschikbaar systeem"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming - Alliance-partner"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming - Premium-partner"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming - Volledige servicefunctionaliteit"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming - Gedeeltelijke servicefunctionaliteit"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Roamingbanner aan"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Roamingbanner uit"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Service zoeken"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> na <xliff:g id="TIME_DELAY">{2}</xliff:g> seconden"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Functiecode voltooid."</string>
- <string name="fcError" msgid="3327560126588500777">"Verbindingsprobleem of ongeldige functiecode."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"De webpagina bevat een fout."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"De URL kan niet worden gevonden."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Het schema voor de siteverificatie wordt niet ondersteund."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Verificatie mislukt."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Verificatie via de proxyserver is mislukt."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Er kan geen verbinding met de server worden gemaakt."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"De server kan niet communiceren. Probeer het later opnieuw."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Er is een time-out voor de serververbinding opgetreden."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"De pagina bevat te veel serveromleidingen."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Het protocol wordt niet ondersteund."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Er kan geen beveiligde verbinding tot stand worden gebracht."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"De pagina kan niet worden geopend, omdat de URL ongeldig is."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Het bestand kan niet worden geopend."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Het opgevraagde bestand is niet gevonden."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Er worden te veel aanvragen verwerkt. Probeer het later opnieuw."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synchroniseren"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchroniseren"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel verwijderen voor <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefoongeheugen is vol! Verwijder enkele bestanden om ruimte vrij te maken."</string>
- <string name="me" msgid="6545696007631404292">"Ik"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefoonopties"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Stille modus"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Draadloos inschakelen"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Draadloos uitschakelen"</string>
- <string name="screen_lock" msgid="799094655496098153">"Schermvergrendeling"</string>
- <string name="power_off" msgid="4266614107412865048">"Uitschakelen"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Uitschakelen..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Uw telefoon wordt uitgeschakeld."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Geen recente toepassingen."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefoonopties"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Schermvergrendeling"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Uitschakelen"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stille modus"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Geluid is UIT"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Geluid is AAN"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegmodus"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegmodus is AAN"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegmodus is UIT"</string>
- <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services waarvoor u moet betalen"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Toepassingen toestaan activiteiten uit te voeren waarvoor mogelijk kosten in rekening worden gebracht."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Uw berichten"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"SMS, e-mail en andere berichten lezen en schrijven."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Uw persoonlijke informatie"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Rechtstreekse toegang tot de op uw telefoon opgeslagen contacten en agenda."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Uw locatie"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Uw fysieke locatie bijhouden"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Netwerkcommunicatie"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Toepassingen toestaan verschillende netwerkfuncties te openen."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Uw Google-accounts"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Toegang tot de beschikbare Google-accounts."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Bedieningselementen hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Rechtstreekse toegang tot hardware op de handset."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefoonoproepen"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Oproepen bijhouden, registreren en verwerken."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Systeemhulpprogramma\'s"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Toegang tot en beheer van het systeem op lager niveau."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Ontwikkelingshulpprogramma\'s"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Functies die alleen door toepassingsontwikkelaars worden gebruikt."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Opslagruimte"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Toegang tot de SD-kaart."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"statusbalk uitschakelen of wijzigen"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Hiermee kan een toepassing de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"statusbalk uitvouwen/samenvouwen"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Hiermee kan de toepassing de statusbalk uitvouwen of samenvouwen."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"uitgaande oproepen onderscheppen"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Hiermee kan een toepassing uitgaande oproepen verwerken en het nummer wijzigen dat wordt gebeld. Schadelijke toepassingen kunnen uitgaande oproepen bijhouden, omleiden of tegenhouden."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"SMS ontvangen"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Hiermee kan een toepassing SMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"MMS ontvangen"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Hiermee kan een toepassing MMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"SMS-berichten verzenden"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Hiermee kan de toepassing SMS-berichten verzenden. Schadelijke toepassingen kunnen u geld kosten door berichten te verzenden zonder uw toestemming."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"SMS of MMS lezen"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Hiermee kan een toepassing de op uw telefoon of SIM-kaart opgeslagen SMS-berichten lezen. Schadelijke toepassingen kunnen uw vertrouwelijke berichten mogelijk lezen."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"SMS of MMS bewerken"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Hiermee kan een toepassing naar de op uw telefoon of SIM-kaart opgeslagen SMS-berichten schrijven. Schadelijke toepassingen kunnen uw berichten mogelijk verwijderen."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP ontvangen"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Hiermee kan een toepassing WAP-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"actieve toepassingen ophalen"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Hiermee kan een toepassing informatie over huidige en recent uitgevoerde taken ophalen. Schadelijke toepassingen kunnen op deze manier mogelijk privé-informatie over andere toepassingen achterhalen."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"actieve toepassingen opnieuw indelen"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Hiermee kan een toepassing taken naar de voor- en achtergrond verplaatsen. Schadelijke toepassingen kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"foutopsporing in toepassingen inschakelen"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Hiermee kan een toepassing de foutopsporing voor een andere toepassing inschakelen. Schadelijke toepassingen kunnen dit gebruiken om andere toepassingen af te sluiten."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"uw UI-instellingen wijzigen"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Hiermee kan een toepassing de huidige configuratie, zoals de landinstelling of de algemene lettergrootte, wijzigen."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"andere toepassingen opnieuw starten"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Hiermee kan een toepassing andere toepassingen opnieuw starten."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"toepassing nu sluiten"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Hiermee kan een toepassing elke willekeurige activiteit die op de voorgrond wordt uitgevoerd, sluiten en naar de achtergrond verplaatsen. Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"interne systeemstatus ophalen"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Hiermee kan een toepassing de interne status van het systeem ophalen. Schadelijke toepassingen kunnen privé- of veiligheidsgegevens ophalen die ze normaal niet nodig hebben."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"gedeeltelijke uitschakeling"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Hiermee wordt activiteitenbeheer uitgeschakeld. Er wordt geen volledige uitschakeling uitgevoerd."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"schakelen tussen toepassingen voorkomen"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hiermee wordt voorkomen dat de gebruiker overschakelt naar een andere toepassing."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"alle startende toepassingen bijhouden en beheren"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Hiermee kan een toepassing de manier waarop het systeem activiteiten start, bijhouden en beheren. Schadelijke toepassingen kunnen het systeem volledig in gevaar brengen. Deze machtiging is alleen voor ontwikkeling vereist, nooit voor normaal telefoongebruik."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"melding verzenden dat pakket is verwijderd"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Hiermee kan een toepassing een melding verzenden dat een toepassingspakket is verwijderd. Schadelijke toepassingen kunnen hiervan gebruik maken om alle andere actieve toepassingen af te sluiten."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"melding over ontvangen SMS-bericht verzenden"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Hiermee kan een toepassing een melding verzenden dat een SMS-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om inkomende SMS-berichten te vervalsen."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"melding over ontvangen WAP-PUSH-bericht verzenden"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Hiermee kan een toepassing een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om een valse MMS-ontvangst te melden of de inhoud van willekeurige webpagina\'s door schadelijke varianten te vervangen."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"aantal actieve processen beperken"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Hiermee kan een toepassing het maximum aantal processen bepalen dat wordt uitgevoerd. Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"alle achtergrondtoepassingen sluiten"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Hiermee kan een toepassing bepalen of activiteiten altijd worden afgesloten zodra deze naar de achtergrond gaan. Nooit nodig voor normale toepassingen."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"accustatistieken aanpassen"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Hiermee kunnen verzamelde accustatistieken worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_backup" msgid="470013022865453920">"systeemback-up en -herstel beheren"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Hiermee kan de toepassing het mechanisme voor systeemback-up en -herstel beheren. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"niet-geautoriseerde vensters weergeven"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Hiermee kunnen vensters worden gemaakt die door de interne systeemgebruikersinterface worden gebruikt. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"waarschuwingen op systeemniveau weergeven"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Hiermee kan een toepassing systeemwaarschuwingen weergeven. Schadelijke toepassingen kunnen op deze manier het hele scherm van de telefoon overnemen."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"algemene animatiesnelheid wijzigen"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Hiermee kan een toepassing op elk gewenst moment de algemene animatiesnelheid wijzigen (snellere of tragere animaties)."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"toepassingstokens beheren"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Hiermee kunnen toepassingen hun eigen tokens maken en beheren, waarbij de normale Z-volgorde wordt overgeslagen. Nooit nodig voor normale toepassingen."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"drukken op toetsen en bedieningselementen"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Hiermee kan een toepassing zijn eigen invoergebeurtenissen (toetsaanslagen, enzovoort) aan andere toepassingen doorgeven. Schadelijke toepassingen kunnen dit gebruiken om de telefoon over te nemen."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"uw invoer en acties vastleggen"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Hiermee kan een toepassing uw toetsaanslagen registreren, zelfs tijdens de interactie met een andere toepassing (zoals de invoer van een wachtwoord). Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"verbinden aan een invoermethode"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Hiermee staat u de houder toe zich te verbinden met de hoofdinterface van een invoermethode. Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Hiermee kan een toepassing op elk gewenst moment de oriëntatie van het scherm wijzigen. Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-signalen verzenden naar toepassingen"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Hiermee kan de toepassing ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"toepassing altijd laten uitvoeren"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Hiermee kan een toepassing delen van zichzelf persistent maken, zodat het systeem dat deel niet voor andere toepassingen kan gebruiken."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"toepassingen verwijderen"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Hiermee kan een toepassing Android-pakketten verwijderen. Schadelijke toepassingen kunnen dit gebruiken om belangrijke toepassingen te verwijderen."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"gegevens van andere toepassingen verwijderen"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Hiermee kan een toepassing gebruikersgegevens wissen."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"caches van andere toepassingen verwijderen"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Hiermee kan een toepassing cachebestanden verwijderen."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"opslagruimte van toepassing bepalen"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Hiermee kan een toepassing de bijbehorende code, gegevens en cachegrootten ophalen."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"toepassingen rechtstreeks installeren"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Hiermee kan een toepassing nieuwe of bijgewerkte Android-pakketten installeren. Schadelijke toepassingen kunnen hiervan gebruik maken om nieuwe toepassingen met willekeurig krachtige machtigingen toe te voegen."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"alle cachegegevens van toepassing verwijderen"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Hiermee kan een toepassing opslagruimte op de telefoon vrij maken door bestanden te verwijderen uit de cachemap van de toepassing. De toegang is doorgaans beperkt tot het systeemproces."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"systeemlogbestanden lezen"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw telefoongebruik. Hierin is geen persoonlijke of privé-informatie opgenomen."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Hiermee kan een toepassing lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of operator."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"toepassingscomponenten in- of uitschakelen"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Hiermee kan een toepassing bepalen of een component van een andere toepassing is ingeschakeld. Schadelijke toepassingen kunnen hiervan gebruik maken om belangrijke telefoonfuncties uit te schakelen. Een machtiging moet zorgvuldig worden overwogen, aangezien toepassingscomponenten onbruikbaar, inconsistent of instabiel kunnen worden."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"voorkeurstoepassingen instellen"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Hiermee kan een toepassing uw voorkeurstoepassingen wijzigen. Schadelijke toepassingen kunnen op deze manier de actieve toepassingen zonder uw medeweten wijzigen en uw bestaande toepassingen doorzoeken om privégegevens van u te verzamelen."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"algemene systeeminstellingen wijzigen"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Hiermee kan een toepassing de systeeminstellingen wijzigen. Schadelijke toepassingen kunnen hiermee uw systeemconfiguratie beschadigen."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"beveiligde systeeminstellingen wijzigen"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Hiermee kan een toepassing beveiligde systeeminstellingen wijzigen. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"de Google-serviceskaart wijzigen"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Hiermee kan een toepassing de Google-serviceskaart wijzigen. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"automatisch starten bij opstarten"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Hiermee kan een toepassing zichzelf starten zodra het systeem klaar is met opstarten. Hierdoor kan het langer duren voordat de telefoon is opgestart en kan de toepassing de telefoonprocessen vertragen door altijd actief te zijn."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"sticky broadcast verzenden"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Hiermee kan een toepassing sticky broadcasts verzenden die achterblijven als de broadcast eindigt. Schadelijke toepassingen kunnen hiermee de telefoon traag of instabiel maken door ervoor te zorgen dat er te veel geheugenruimte wordt gebruikt."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"contactgegevens lezen"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Hiermee kan een toepassing alle contactgegevens (adresgegevens) zien die op uw telefoon zijn opgeslagen. Schadelijke toepassingen kunnen hiervan gebruik maken om uw gegevens te verzenden naar andere personen."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"contactgegevens schrijven"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Hiermee kan een toepassing de op uw telefoon opgeslagen contactgegevens (adresgegevens) wijzigen. Schadelijke toepassingen kunnen hiermee uw contactgegevens verwijderen of wijzigen."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"gegevens eigenaar schrijven"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Hiermee kan een toepassing de op uw telefoon opgeslagen gegevens van de eigenaar wijzigen. Schadelijke toepassingen kunnen hiermee gegevens van de eigenaar verwijderen of wijzigen."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"gegevens eigenaar lezen"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Hiermee kan een toepassing de op uw telefoon opgeslagen gegevens van de eigenaar lezen. Schadelijke toepassingen kunnen hiermee gegevens van de eigenaar lezen."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"agendagegevens lezen"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Hiermee kan een toepassing alle agendagebeurtenissen lezen die zijn opgeslagen op uw telefoon. Schadelijke toepassingen kunnen hiervan gebruik maken om uw agendagebeurtenissen te verzenden naar andere personen."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"agendagegevens schrijven"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Hiermee kan een toepassing de op uw telefoon opgeslagen agendagebeurtenissen wijzigen. Schadelijke toepassingen kunnen hiermee uw agendagegevens verwijderen of wijzigen."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"neplocatiebronnen voor test"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Neplocatiebronnen voor testdoeleinden maken. Schadelijke toepassingen kunnen dit gebruiken om de locatie en/of status te overschrijven die door de echte locatiebronnen wordt aangegeven, zoals GPS of netwerkaanbieders."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"toegang opdrachten aanbieder extra locaties"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Toegang tot opdrachten aanbieder extra locaties. Schadelijke toepassingen kunnen hiervan gebruik maken om de werking van GPS of andere locatiebronnen te verstoren."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"toestemming om een locatieprovider te installeren"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Neplocatiebronnen voor testdoeleinden maken. Schadelijke toepassingen kunnen dit gebruiken om de locatie en/of status te overschrijven die door de echte locatiebronnen, zoals GPS of netwerkaanbieders, wordt aangegeven of om uw locatie bij te houden en te rapporteren aan externe bronnen."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"nauwkeurige (GPS) locatie"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Toegang tot exacte locatiebronnen, zoals het Global Positioning System op de telefoon, indien beschikbaar. Schadelijke toepassingen kunnen dit gebruiken om te bepalen waar u zich bevindt en mogelijk extra acculading verbruiken."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"globale (netwerkgebaseerde) locatie"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Toegang tot globale locatiebronnen, zoals de mobiele netwerkdatabase om een globale telefoonlocatie te bepalen, indien beschikbaar. Schadelijke toepassingen kunnen hiervan gebruik maken om bij benadering te bepalen waar u zich bevindt."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"toegang tot SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Hiermee kan een toepassing SurfaceFlinger-functies op laag niveau gebruiken."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"framebuffer lezen"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Hiermee kan een toepassing de inhoud van de framebuffer lezen."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"uw audio-instellingen wijzigen"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Hiermee kan een toepassing de algemene audio-instellingen, zoals volume en omleiding, wijzigen."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"audio opnemen"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Hiermee krijgt de toepassing toegang tot het audio-opnamepad."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"foto\'s maken"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Hiermee kan een toepassing foto\'s maken met de camera. De toepassing kan op deze manier op elk gewenste moment foto\'s verzamelen van wat de camera ziet."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"telefoon permanent uitschakelen"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Hiermee kan de toepassing de telefoon permanent uitschakelen. Dit is erg gevaarlijk."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"telefoon nu opnieuw opstarten"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Hiermee kan de toepassing de telefoon nu opnieuw opstarten."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"bestandssystemen koppelen en ontkoppelen"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Hiermee kan de toepassing bestandssystemen koppelen en ontkoppelen voor verwisselbare opslagruimte."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"externe opslag formatteren"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Hiermee kan de toepassing de externe opslag formatteren."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"trilstand beheren"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Hiermee kan de toepassing de trilstand beheren."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"zaklamp bedienen"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Hiermee kan de toepassing de zaklamp bedienen."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"hardware testen"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Hiermee kan de toepassing verschillende randapparaten beheren om de hardware te testen."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"telefoonnummers rechtstreeks bellen"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Hiermee kan de toepassing telefoonnummers bellen zonder uw tussenkomst. Door schadelijke toepassingen kunnen onverwachte oproepen op uw telefoonrekening verschijnen. De toepassing kan hiermee geen alarmnummers bellen."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"alle telefoonnummers rechtstreeks bellen"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Hiermee kan een toepassing elk telefoonnummer, inclusief alarmnummers, bellen zonder uw tussenkomst. Schadelijke toepassingen kunnen onnodige en illegale oproepen uitvoeren naar alarmdiensten."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"meldingen over locatie-updates beheren"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Hiermee kunnen updatemeldingen voor locaties van de radio worden ingeschakeld/uitgeschakeld. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"toegang tot checkin-eigenschappen"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Hiermee wordt lees-/schrijftoegang gegeven tot eigenschappen die door de checkin-service zijn geüpload. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"widgets kiezen"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Hiermee kan een toepassing het systeem melden welke widgets door welke toepassing kunnen worden gebruikt. Met deze toestemming kunnen toepassingen andere toepassingen toegang geven tot persoonlijke gegevens. Niet voor gebruik door normale toepassingen."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"telefoonstatus wijzigen"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Hiermee kan de toepassing de telefoonfuncties van het apparaat beheren. Een toepassing met deze machtiging kan schakelen tussen netwerken, de radio van de telefoon in- of uitschakelen en dergelijke zonder dat u hiervan op de hoogte wordt gesteld."</string>
- <string name="permlab_readPhoneState" msgid="2326172951448691631">"telefoonstatus en -identiteit lezen"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"Hiermee krijgt de toepassing toegang tot de telefoonfuncties van het apparaat. Een toepassing met de betreffende machtiging kan het telefoonnummer en serienummer van deze telefoon achterhalen, bepalen of een oproep actief is, het gekozen nummer achterhalen en dergelijke."</string>
- <string name="permlab_wakeLock" msgid="573480187941496130">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Hiermee kan een toepassing voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"telefoon in- of uitschakelen"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Hiermee kan de toepassing de telefoon in- of uitschakelen."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"uitvoeren in fabriekstestmodus"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Uitvoeren als fabrikanttest op laag niveau, waardoor toegang wordt gegeven tot de hardware van de telefoon. Alleen beschikbaar als een telefoon zich in de fabrikanttestmodus bevindt."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"achtergrond instellen"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Hiermee kan de toepassing de systeemachtergrond instellen."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"grootte achtergrond instellen"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Hiermee kan de toepassing de grootte van de achtergrond instellen."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"systeem terugzetten op fabrieksinstellingen"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Hiermee kan een toepassing het systeem terugzetten op de fabrieksinstellingen, waarbij alle gegevens, configuraties en geïnstalleerde toepassingen worden verwijderd."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"tijdzone instellen"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Hiermee kan een toepassing de tijdzone van de telefoon wijzigen."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"bekende accounts zoeken"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Hiermee kan een toepassing de lijst met accounts van een telefoon ophalen."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"netwerkstatus bekijken"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Hiermee kan een toepassing de status van alle netwerken bekijken."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"volledige internettoegang"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Hiermee kan een toepassing netwerksockets maken."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"instellingen voor toegangspuntnaam schrijven"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Hiermee kan een toepassing de APN-instellingen, zoals proxy en poort, van elke APN wijzigen."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"netwerkverbinding wijzigen"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Hiermee kan een toepassing de verbindingsstatus van het netwerk wijzigen."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"instelling voor gebruik van achtergrondgegevens van gegevens wijzigen"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Hiermee kan een toepassing de instelling voor gebruik van achtergrondgegevens wijzigen."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Wi-Fi-status bekijken"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Hiermee kan een toepassing informatie over de Wi-Fi-status bekijken."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Wi-Fi-status wijzigen"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Hiermee kan een toepassing zich koppelen aan en loskoppelen van Wi-Fi toegangspunten en wijzigingen aanbrengen in geconfigureerde Wi-Fi-netwerken."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fi Multicast-ontvangst toestaan"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Hiermee kan een toepassing pakketten ontvangen die niet rechtstreeks zijn geadresseerd aan uw apparaat. Dit kan handig zijn wanneer services in de buurt worden ontdekt. Dit verbruikt meer energie dan de niet-multicastmodus."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth-beheer"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Hiermee kan een toepassing de lokale Bluetooth-telefoon configureren en externe apparaten zoeken en aansluiten."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth-verbindingen maken"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Hiermee kan een toepassing de configuratie van een lokale Bluetooth-telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"toetsvergrendeling uitschakelen"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Hiermee kan een toepassing de toetsvergrendeling en bijbehorende wachtwoordbeveiliging uitschakelen. Een voorbeeld: de telefoon schakelt de toetsvergrendeling uit als er een oproep binnenkomt en schakelt de toetsvergrendeling weer in als de oproep is beëindigd."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"synchronisatie-instellingen lezen"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Hiermee kan een toepassing de synchronisatie-instellingen lezen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"synchronisatie-instellingen schrijven"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Hiermee kan een toepassing uw synchronisatie-instellingen wijzigen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"synchronisatiestatistieken lezen"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Hiermee kan een toepassing de synchronisatiestatistieken lezen, zoals de geschiedenis van uitgevoerde synchronisaties."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"geabonneerde feeds lezen"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Hiermee kan een toepassing details over de huidige gesynchroniseerde feeds achterhalen."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"geabonneerde feeds schrijven"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Hiermee kan een toepassing uw huidige gesynchroniseerde feeds wijzigen. Een schadelijke toepassing kan op deze manier uw gesynchroniseerde feeds wijzigen."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"door gebruiker gedefinieerd woordenboek lezen"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Hiermee kan een toepassing privéwoorden, namen en woordcombinaties lezen die de gebruiker heeft opgeslagen in het gebruikerswoordenboek."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"schrijven naar door gebruiker gedefinieerd woordenboek"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Hiermee kan een toepassing nieuwe woorden schrijven naar het gebruikerswoordenboek."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"inhoud op de SD-kaart aanpassen/verwijderen"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Hiermee kan een toepassing schrijven naar de SD-kaart."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"kB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"&lt;zonder titel&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Geen telefoonnummer)"</string>
+ <string name="unknownName">"(Onbekend)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Voicemail"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Verbindingsprobleem of ongeldige MMI-code."</string>
+ <string name="serviceEnabled">"Service is ingeschakeld."</string>
+ <string name="serviceEnabledFor">"Service is ingeschakeld voor:"</string>
+ <string name="serviceDisabled">"Service is uitgeschakeld."</string>
+ <string name="serviceRegistered">"De registratie is voltooid."</string>
+ <string name="serviceErased">"Wissen uitgevoerd."</string>
+ <string name="passwordIncorrect">"Onjuist wachtwoord."</string>
+ <string name="mmiComplete">"MMI voltooid."</string>
+ <string name="badPin">"De oude PIN-code die u heeft ingevoerd, is onjuist."</string>
+ <string name="badPuk">"De PUK-code die u heeft ingevoerd, is onjuist."</string>
+ <string name="mismatchPin">"De PIN-codes die u heeft ingevoerd, komen niet overeen."</string>
+ <string name="invalidPin">"Voer een PIN-code van 4 tot 8 cijfers in."</string>
+ <string name="needPuk">"Uw SIM-kaart is vergrendeld met de PUK-code. Typ de PUK-code om te ontgrendelen."</string>
+ <string name="needPuk2">"Voer de PUK2-code in om de SIM-kaart te ontgrendelen."</string>
+ <string name="ClipMmi">"Inkomende beller-id"</string>
+ <string name="ClirMmi">"Uitgaande beller-id"</string>
+ <string name="CfMmi">"Oproep doorschakelen"</string>
+ <string name="CwMmi">"Wisselgesprek"</string>
+ <string name="BaMmi">"Oproep blokkeren"</string>
+ <string name="PwdMmi">"Wachtwoordwijziging"</string>
+ <string name="PinMmi">"PIN-wijziging"</string>
+ <string name="CnipMmi">"Nummer van beller beschikbaar"</string>
+ <string name="CnirMmi">"Nummer van beller beperkt"</string>
+ <string name="ThreeWCMmi">"Driewegs bellen"</string>
+ <string name="RuacMmi">"Ongewenste, vervelende oproepen weigeren"</string>
+ <string name="CndMmi">"Weergave van nummer van beller"</string>
+ <string name="DndMmi">"Niet storen"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Beller-id standaard ingesteld op \'beperkt\'. Volgende oproep: beperkt."</string>
+ <string name="CLIRDefaultOnNextCallOff">"Beller-id standaard ingesteld op \'beperkt\'. Volgende oproep: onbeperkt."</string>
+ <string name="CLIRDefaultOffNextCallOn">"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: beperkt."</string>
+ <string name="CLIRDefaultOffNextCallOff">"Beller-id standaard ingesteld op \'onbeperkt\'. Volgende oproep: onbeperkt."</string>
+ <string name="serviceNotProvisioned">"Service niet voorzien."</string>
+ <string name="CLIRPermanent">"De instelling voor beller-id kan niet worden gewijzigd."</string>
+ <string name="RestrictedChangedTitle">"Beperkte toegang gewijzigd"</string>
+ <string name="RestrictedOnData">"Gegevensservice is geblokkeerd."</string>
+ <string name="RestrictedOnEmergency">"Alarmservice is geblokkeerd."</string>
+ <string name="RestrictedOnNormal">"Spraak-/SMS-service is geblokkeerd."</string>
+ <string name="RestrictedOnAll">"Alle spraak-/SMS-services zijn geblokkeerd."</string>
+ <string name="serviceClassVoice">"Spraak"</string>
+ <string name="serviceClassData">"Gegevens"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynchroon"</string>
+ <string name="serviceClassDataSync">"Synchroniseren"</string>
+ <string name="serviceClassPacket">"Pakket"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Roamingaanduiding aan"</string>
+ <string name="roamingText1">"Roamingaanduiding uit"</string>
+ <string name="roamingText2">"Roamingaanduiding knippert"</string>
+ <string name="roamingText3">"Uit de buurt"</string>
+ <string name="roamingText4">"Buiten het gebouw"</string>
+ <string name="roamingText5">"Roaming - Voorkeurssysteem"</string>
+ <string name="roamingText6">"Roaming - Beschikbaar systeem"</string>
+ <string name="roamingText7">"Roaming - Alliance-partner"</string>
+ <string name="roamingText8">"Roaming - Premium-partner"</string>
+ <string name="roamingText9">"Roaming - Volledige servicefunctionaliteit"</string>
+ <string name="roamingText10">"Roaming - Gedeeltelijke servicefunctionaliteit"</string>
+ <string name="roamingText11">"Roamingbanner aan"</string>
+ <string name="roamingText12">"Roamingbanner uit"</string>
+ <string name="roamingTextSearching">"Service zoeken"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> na <xliff:g id="TIME_DELAY">{2}</xliff:g> seconden"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
+ <string name="fcComplete">"Functiecode voltooid."</string>
+ <string name="fcError">"Verbindingsprobleem of ongeldige functiecode."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"De webpagina bevat een fout."</string>
+ <string name="httpErrorLookup">"De URL kan niet worden gevonden."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Het schema voor de siteverificatie wordt niet ondersteund."</string>
+ <string name="httpErrorAuth">"Verificatie mislukt."</string>
+ <string name="httpErrorProxyAuth">"Verificatie via de proxyserver is mislukt."</string>
+ <string name="httpErrorConnect">"Er kan geen verbinding met de server worden gemaakt."</string>
+ <string name="httpErrorIO">"De server kan niet communiceren. Probeer het later opnieuw."</string>
+ <string name="httpErrorTimeout">"Er is een time-out voor de serververbinding opgetreden."</string>
+ <string name="httpErrorRedirectLoop">"De pagina bevat te veel serveromleidingen."</string>
+ <string name="httpErrorUnsupportedScheme">"Het protocol wordt niet ondersteund."</string>
+ <string name="httpErrorFailedSslHandshake">"Er kan geen beveiligde verbinding tot stand worden gebracht."</string>
+ <string name="httpErrorBadUrl">"De pagina kan niet worden geopend, omdat de URL ongeldig is."</string>
+ <string name="httpErrorFile">"Het bestand kan niet worden geopend."</string>
+ <string name="httpErrorFileNotFound">"Het opgevraagde bestand is niet gevonden."</string>
+ <string name="httpErrorTooManyRequests">"Er worden te veel aanvragen verwerkt. Probeer het later opnieuw."</string>
+ <string name="contentServiceSync">"Synchroniseren"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchroniseren"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Te veel verwijderen voor <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Telefoongeheugen is vol! Verwijder enkele bestanden om ruimte vrij te maken."</string>
+ <string name="me">"Ik"</string>
+ <string name="power_dialog">"Telefoonopties"</string>
+ <string name="silent_mode">"Stille modus"</string>
+ <string name="turn_on_radio">"Draadloos inschakelen"</string>
+ <string name="turn_off_radio">"Draadloos uitschakelen"</string>
+ <string name="screen_lock">"Schermvergrendeling"</string>
+ <string name="power_off">"Uitschakelen"</string>
+ <string name="shutdown_progress">"Uitschakelen..."</string>
+ <string name="shutdown_confirm">"Uw telefoon wordt uitgeschakeld."</string>
+ <string name="no_recent_tasks">"Geen recente toepassingen."</string>
+ <string name="global_actions">"Telefoonopties"</string>
+ <string name="global_action_lock">"Schermvergrendeling"</string>
+ <string name="global_action_power_off">"Uitschakelen"</string>
+ <string name="global_action_toggle_silent_mode">"Stille modus"</string>
+ <string name="global_action_silent_mode_on_status">"Geluid is UIT"</string>
+ <string name="global_action_silent_mode_off_status">"Geluid is AAN"</string>
+ <string name="global_actions_toggle_airplane_mode">"Vliegmodus"</string>
+ <string name="global_actions_airplane_mode_on_status">"Vliegmodus is AAN"</string>
+ <string name="global_actions_airplane_mode_off_status">"Vliegmodus is UIT"</string>
+ <string name="safeMode">"Veilige modus"</string>
+ <string name="android_system_label">"Android-systeem"</string>
+ <string name="permgrouplab_costMoney">"Services waarvoor u moet betalen"</string>
+ <string name="permgroupdesc_costMoney">"Toepassingen toestaan activiteiten uit te voeren waarvoor mogelijk kosten in rekening worden gebracht."</string>
+ <string name="permgrouplab_messages">"Uw berichten"</string>
+ <string name="permgroupdesc_messages">"SMS, e-mail en andere berichten lezen en schrijven."</string>
+ <string name="permgrouplab_personalInfo">"Uw persoonlijke informatie"</string>
+ <string name="permgroupdesc_personalInfo">"Rechtstreekse toegang tot de op uw telefoon opgeslagen contacten en agenda."</string>
+ <string name="permgrouplab_location">"Uw locatie"</string>
+ <string name="permgroupdesc_location">"Uw fysieke locatie bijhouden"</string>
+ <string name="permgrouplab_network">"Netwerkcommunicatie"</string>
+ <string name="permgroupdesc_network">"Toepassingen toestaan verschillende netwerkfuncties te openen."</string>
+ <string name="permgrouplab_accounts">"Uw Google-accounts"</string>
+ <string name="permgroupdesc_accounts">"Toegang tot de beschikbare Google-accounts."</string>
+ <string name="permgrouplab_hardwareControls">"Bedieningselementen hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Rechtstreekse toegang tot hardware op de handset."</string>
+ <string name="permgrouplab_phoneCalls">"Telefoonoproepen"</string>
+ <string name="permgroupdesc_phoneCalls">"Oproepen bijhouden, registreren en verwerken."</string>
+ <string name="permgrouplab_systemTools">"Systeemhulpprogramma\'s"</string>
+ <string name="permgroupdesc_systemTools">"Toegang tot en beheer van het systeem op lager niveau."</string>
+ <string name="permgrouplab_developmentTools">"Ontwikkelingshulpprogramma\'s"</string>
+ <string name="permgroupdesc_developmentTools">"Functies die alleen door toepassingsontwikkelaars worden gebruikt."</string>
+ <string name="permgrouplab_storage">"Opslagruimte"</string>
+ <string name="permgroupdesc_storage">"Toegang tot de SD-kaart."</string>
+ <string name="permlab_statusBar">"statusbalk uitschakelen of wijzigen"</string>
+ <string name="permdesc_statusBar">"Hiermee kan een toepassing de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
+ <string name="permlab_expandStatusBar">"statusbalk uitvouwen/samenvouwen"</string>
+ <string name="permdesc_expandStatusBar">"Hiermee kan de toepassing de statusbalk uitvouwen of samenvouwen."</string>
+ <string name="permlab_processOutgoingCalls">"uitgaande oproepen onderscheppen"</string>
+ <string name="permdesc_processOutgoingCalls">"Hiermee kan een toepassing uitgaande oproepen verwerken en het nummer wijzigen dat wordt gebeld. Schadelijke toepassingen kunnen uitgaande oproepen bijhouden, omleiden of tegenhouden."</string>
+ <string name="permlab_receiveSms">"SMS ontvangen"</string>
+ <string name="permdesc_receiveSms">"Hiermee kan een toepassing SMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permlab_receiveMms">"MMS ontvangen"</string>
+ <string name="permdesc_receiveMms">"Hiermee kan een toepassing MMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permlab_sendSms">"SMS-berichten verzenden"</string>
+ <string name="permdesc_sendSms">"Hiermee kan de toepassing SMS-berichten verzenden. Schadelijke toepassingen kunnen u geld kosten door berichten te verzenden zonder uw toestemming."</string>
+ <string name="permlab_readSms">"SMS of MMS lezen"</string>
+ <string name="permdesc_readSms">"Hiermee kan een toepassing de op uw telefoon of SIM-kaart opgeslagen SMS-berichten lezen. Schadelijke toepassingen kunnen uw vertrouwelijke berichten mogelijk lezen."</string>
+ <string name="permlab_writeSms">"SMS of MMS bewerken"</string>
+ <string name="permdesc_writeSms">"Hiermee kan een toepassing naar de op uw telefoon of SIM-kaart opgeslagen SMS-berichten schrijven. Schadelijke toepassingen kunnen uw berichten mogelijk verwijderen."</string>
+ <string name="permlab_receiveWapPush">"WAP ontvangen"</string>
+ <string name="permdesc_receiveWapPush">"Hiermee kan een toepassing WAP-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permlab_getTasks">"actieve toepassingen ophalen"</string>
+ <string name="permdesc_getTasks">"Hiermee kan een toepassing informatie over huidige en recent uitgevoerde taken ophalen. Schadelijke toepassingen kunnen op deze manier mogelijk privé-informatie over andere toepassingen achterhalen."</string>
+ <string name="permlab_reorderTasks">"actieve toepassingen opnieuw indelen"</string>
+ <string name="permdesc_reorderTasks">"Hiermee kan een toepassing taken naar de voor- en achtergrond verplaatsen. Schadelijke toepassingen kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
+ <string name="permlab_setDebugApp">"foutopsporing in toepassingen inschakelen"</string>
+ <string name="permdesc_setDebugApp">"Hiermee kan een toepassing de foutopsporing voor een andere toepassing inschakelen. Schadelijke toepassingen kunnen dit gebruiken om andere toepassingen af te sluiten."</string>
+ <string name="permlab_changeConfiguration">"uw UI-instellingen wijzigen"</string>
+ <string name="permdesc_changeConfiguration">"Hiermee kan een toepassing de huidige configuratie, zoals de landinstelling of de algemene lettergrootte, wijzigen."</string>
+ <string name="permlab_restartPackages">"andere toepassingen opnieuw starten"</string>
+ <string name="permdesc_restartPackages">"Hiermee kan een toepassing andere toepassingen opnieuw starten."</string>
+ <string name="permlab_forceBack">"toepassing nu sluiten"</string>
+ <string name="permdesc_forceBack">"Hiermee kan een toepassing elke willekeurige activiteit die op de voorgrond wordt uitgevoerd, sluiten en naar de achtergrond verplaatsen. Nooit vereist voor normale toepassingen."</string>
+ <string name="permlab_dump">"interne systeemstatus ophalen"</string>
+ <string name="permdesc_dump">"Hiermee kan een toepassing de interne status van het systeem ophalen. Schadelijke toepassingen kunnen privé- of veiligheidsgegevens ophalen die ze normaal niet nodig hebben."</string>
+ <string name="permlab_shutdown">"gedeeltelijke uitschakeling"</string>
+ <string name="permdesc_shutdown">"Hiermee wordt activiteitenbeheer uitgeschakeld. Er wordt geen volledige uitschakeling uitgevoerd."</string>
+ <string name="permlab_stopAppSwitches">"schakelen tussen toepassingen voorkomen"</string>
+ <string name="permdesc_stopAppSwitches">"Hiermee wordt voorkomen dat de gebruiker overschakelt naar een andere toepassing."</string>
+ <string name="permlab_runSetActivityWatcher">"alle startende toepassingen bijhouden en beheren"</string>
+ <string name="permdesc_runSetActivityWatcher">"Hiermee kan een toepassing de manier waarop het systeem activiteiten start, bijhouden en beheren. Schadelijke toepassingen kunnen het systeem volledig in gevaar brengen. Deze machtiging is alleen voor ontwikkeling vereist, nooit voor normaal telefoongebruik."</string>
+ <string name="permlab_broadcastPackageRemoved">"melding verzenden dat pakket is verwijderd"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Hiermee kan een toepassing een melding verzenden dat een toepassingspakket is verwijderd. Schadelijke toepassingen kunnen hiervan gebruik maken om alle andere actieve toepassingen af te sluiten."</string>
+ <string name="permlab_broadcastSmsReceived">"melding over ontvangen SMS-bericht verzenden"</string>
+ <string name="permdesc_broadcastSmsReceived">"Hiermee kan een toepassing een melding verzenden dat een SMS-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om inkomende SMS-berichten te vervalsen."</string>
+ <string name="permlab_broadcastWapPush">"melding over ontvangen WAP-PUSH-bericht verzenden"</string>
+ <string name="permdesc_broadcastWapPush">"Hiermee kan een toepassing een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om een valse MMS-ontvangst te melden of de inhoud van willekeurige webpagina\'s door schadelijke varianten te vervangen."</string>
+ <string name="permlab_setProcessLimit">"aantal actieve processen beperken"</string>
+ <string name="permdesc_setProcessLimit">"Hiermee kan een toepassing het maximum aantal processen bepalen dat wordt uitgevoerd. Nooit vereist voor normale toepassingen."</string>
+ <string name="permlab_setAlwaysFinish">"alle achtergrondtoepassingen sluiten"</string>
+ <string name="permdesc_setAlwaysFinish">"Hiermee kan een toepassing bepalen of activiteiten altijd worden afgesloten zodra deze naar de achtergrond gaan. Nooit nodig voor normale toepassingen."</string>
+ <string name="permlab_batteryStats">"accustatistieken aanpassen"</string>
+ <string name="permdesc_batteryStats">"Hiermee kunnen verzamelde accustatistieken worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_backup">"systeemback-up en -herstel beheren"</string>
+ <string name="permdesc_backup">"Hiermee kan de toepassing het mechanisme voor systeemback-up en -herstel beheren. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_internalSystemWindow">"niet-geautoriseerde vensters weergeven"</string>
+ <string name="permdesc_internalSystemWindow">"Hiermee kunnen vensters worden gemaakt die door de interne systeemgebruikersinterface worden gebruikt. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_systemAlertWindow">"waarschuwingen op systeemniveau weergeven"</string>
+ <string name="permdesc_systemAlertWindow">"Hiermee kan een toepassing systeemwaarschuwingen weergeven. Schadelijke toepassingen kunnen op deze manier het hele scherm van de telefoon overnemen."</string>
+ <string name="permlab_setAnimationScale">"algemene animatiesnelheid wijzigen"</string>
+ <string name="permdesc_setAnimationScale">"Hiermee kan een toepassing op elk gewenst moment de algemene animatiesnelheid wijzigen (snellere of tragere animaties)."</string>
+ <string name="permlab_manageAppTokens">"toepassingstokens beheren"</string>
+ <string name="permdesc_manageAppTokens">"Hiermee kunnen toepassingen hun eigen tokens maken en beheren, waarbij de normale Z-volgorde wordt overgeslagen. Nooit nodig voor normale toepassingen."</string>
+ <string name="permlab_injectEvents">"drukken op toetsen en bedieningselementen"</string>
+ <string name="permdesc_injectEvents">"Hiermee kan een toepassing zijn eigen invoergebeurtenissen (toetsaanslagen, enzovoort) aan andere toepassingen doorgeven. Schadelijke toepassingen kunnen dit gebruiken om de telefoon over te nemen."</string>
+ <string name="permlab_readInputState">"uw invoer en acties vastleggen"</string>
+ <string name="permdesc_readInputState">"Hiermee kan een toepassing uw toetsaanslagen registreren, zelfs tijdens de interactie met een andere toepassing (zoals de invoer van een wachtwoord). Nooit vereist voor normale toepassingen."</string>
+ <string name="permlab_bindInputMethod">"verbinden aan een invoermethode"</string>
+ <string name="permdesc_bindInputMethod">"Hiermee staat u de houder toe zich te verbinden met de hoofdinterface van een invoermethode. Nooit vereist voor normale toepassingen."</string>
+ <string name="permlab_setOrientation">"schermstand wijzigen"</string>
+ <string name="permdesc_setOrientation">"Hiermee kan een toepassing op elk gewenst moment de oriëntatie van het scherm wijzigen. Nooit vereist voor normale toepassingen."</string>
+ <string name="permlab_signalPersistentProcesses">"Linux-signalen verzenden naar toepassingen"</string>
+ <string name="permdesc_signalPersistentProcesses">"Hiermee kan de toepassing ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
+ <string name="permlab_persistentActivity">"toepassing altijd laten uitvoeren"</string>
+ <string name="permdesc_persistentActivity">"Hiermee kan een toepassing delen van zichzelf persistent maken, zodat het systeem dat deel niet voor andere toepassingen kan gebruiken."</string>
+ <string name="permlab_deletePackages">"toepassingen verwijderen"</string>
+ <string name="permdesc_deletePackages">"Hiermee kan een toepassing Android-pakketten verwijderen. Schadelijke toepassingen kunnen dit gebruiken om belangrijke toepassingen te verwijderen."</string>
+ <string name="permlab_clearAppUserData">"gegevens van andere toepassingen verwijderen"</string>
+ <string name="permdesc_clearAppUserData">"Hiermee kan een toepassing gebruikersgegevens wissen."</string>
+ <string name="permlab_deleteCacheFiles">"caches van andere toepassingen verwijderen"</string>
+ <string name="permdesc_deleteCacheFiles">"Hiermee kan een toepassing cachebestanden verwijderen."</string>
+ <string name="permlab_getPackageSize">"opslagruimte van toepassing bepalen"</string>
+ <string name="permdesc_getPackageSize">"Hiermee kan een toepassing de bijbehorende code, gegevens en cachegrootten ophalen."</string>
+ <string name="permlab_installPackages">"toepassingen rechtstreeks installeren"</string>
+ <string name="permdesc_installPackages">"Hiermee kan een toepassing nieuwe of bijgewerkte Android-pakketten installeren. Schadelijke toepassingen kunnen hiervan gebruik maken om nieuwe toepassingen met willekeurig krachtige machtigingen toe te voegen."</string>
+ <string name="permlab_clearAppCache">"alle cachegegevens van toepassing verwijderen"</string>
+ <string name="permdesc_clearAppCache">"Hiermee kan een toepassing opslagruimte op de telefoon vrij maken door bestanden te verwijderen uit de cachemap van de toepassing. De toegang is doorgaans beperkt tot het systeemproces."</string>
+ <string name="permlab_readLogs">"systeemlogbestanden lezen"</string>
+ <string name="permdesc_readLogs">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw telefoongebruik. Hierin is geen persoonlijke of privé-informatie opgenomen."</string>
+ <string name="permlab_diagnostic">"lezen/schrijven naar bronnen van diag"</string>
+ <string name="permdesc_diagnostic">"Hiermee kan een toepassing lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of operator."</string>
+ <string name="permlab_changeComponentState">"toepassingscomponenten in- of uitschakelen"</string>
+ <string name="permdesc_changeComponentState">"Hiermee kan een toepassing bepalen of een component van een andere toepassing is ingeschakeld. Schadelijke toepassingen kunnen hiervan gebruik maken om belangrijke telefoonfuncties uit te schakelen. Een machtiging moet zorgvuldig worden overwogen, aangezien toepassingscomponenten onbruikbaar, inconsistent of instabiel kunnen worden."</string>
+ <string name="permlab_setPreferredApplications">"voorkeurstoepassingen instellen"</string>
+ <string name="permdesc_setPreferredApplications">"Hiermee kan een toepassing uw voorkeurstoepassingen wijzigen. Schadelijke toepassingen kunnen op deze manier de actieve toepassingen zonder uw medeweten wijzigen en uw bestaande toepassingen doorzoeken om privégegevens van u te verzamelen."</string>
+ <string name="permlab_writeSettings">"algemene systeeminstellingen wijzigen"</string>
+ <string name="permdesc_writeSettings">"Hiermee kan een toepassing de systeeminstellingen wijzigen. Schadelijke toepassingen kunnen hiermee uw systeemconfiguratie beschadigen."</string>
+ <string name="permlab_writeSecureSettings">"beveiligde systeeminstellingen wijzigen"</string>
+ <string name="permdesc_writeSecureSettings">"Hiermee kan een toepassing beveiligde systeeminstellingen wijzigen. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_writeGservices">"de Google-serviceskaart wijzigen"</string>
+ <string name="permdesc_writeGservices">"Hiermee kan een toepassing de Google-serviceskaart wijzigen. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_receiveBootCompleted">"automatisch starten bij opstarten"</string>
+ <string name="permdesc_receiveBootCompleted">"Hiermee kan een toepassing zichzelf starten zodra het systeem klaar is met opstarten. Hierdoor kan het langer duren voordat de telefoon is opgestart en kan de toepassing de telefoonprocessen vertragen door altijd actief te zijn."</string>
+ <string name="permlab_broadcastSticky">"sticky broadcast verzenden"</string>
+ <string name="permdesc_broadcastSticky">"Hiermee kan een toepassing sticky broadcasts verzenden die achterblijven als de broadcast eindigt. Schadelijke toepassingen kunnen hiermee de telefoon traag of instabiel maken door ervoor te zorgen dat er te veel geheugenruimte wordt gebruikt."</string>
+ <string name="permlab_readContacts">"contactgegevens lezen"</string>
+ <string name="permdesc_readContacts">"Hiermee kan een toepassing alle contactgegevens (adresgegevens) zien die op uw telefoon zijn opgeslagen. Schadelijke toepassingen kunnen hiervan gebruik maken om uw gegevens te verzenden naar andere personen."</string>
+ <string name="permlab_writeContacts">"contactgegevens schrijven"</string>
+ <string name="permdesc_writeContacts">"Hiermee kan een toepassing de op uw telefoon opgeslagen contactgegevens (adresgegevens) wijzigen. Schadelijke toepassingen kunnen hiermee uw contactgegevens verwijderen of wijzigen."</string>
+ <string name="permlab_writeOwnerData">"gegevens eigenaar schrijven"</string>
+ <string name="permdesc_writeOwnerData">"Hiermee kan een toepassing de op uw telefoon opgeslagen gegevens van de eigenaar wijzigen. Schadelijke toepassingen kunnen hiermee gegevens van de eigenaar verwijderen of wijzigen."</string>
+ <string name="permlab_readOwnerData">"gegevens eigenaar lezen"</string>
+ <string name="permdesc_readOwnerData">"Hiermee kan een toepassing de op uw telefoon opgeslagen gegevens van de eigenaar lezen. Schadelijke toepassingen kunnen hiermee gegevens van de eigenaar lezen."</string>
+ <string name="permlab_readCalendar">"agendagegevens lezen"</string>
+ <string name="permdesc_readCalendar">"Hiermee kan een toepassing alle agendagebeurtenissen lezen die zijn opgeslagen op uw telefoon. Schadelijke toepassingen kunnen hiervan gebruik maken om uw agendagebeurtenissen te verzenden naar andere personen."</string>
+ <string name="permlab_writeCalendar">"agendagegevens schrijven"</string>
+ <string name="permdesc_writeCalendar">"Hiermee kan een toepassing de op uw telefoon opgeslagen agendagebeurtenissen wijzigen. Schadelijke toepassingen kunnen hiermee uw agendagegevens verwijderen of wijzigen."</string>
+ <string name="permlab_accessMockLocation">"neplocatiebronnen voor test"</string>
+ <string name="permdesc_accessMockLocation">"Neplocatiebronnen voor testdoeleinden maken. Schadelijke toepassingen kunnen dit gebruiken om de locatie en/of status te overschrijven die door de echte locatiebronnen wordt aangegeven, zoals GPS of netwerkaanbieders."</string>
+ <string name="permlab_accessLocationExtraCommands">"toegang opdrachten aanbieder extra locaties"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Toegang tot opdrachten aanbieder extra locaties. Schadelijke toepassingen kunnen hiervan gebruik maken om de werking van GPS of andere locatiebronnen te verstoren."</string>
+ <string name="permlab_installLocationProvider">"toestemming om een locatieprovider te installeren"</string>
+ <string name="permdesc_installLocationProvider">"Neplocatiebronnen voor testdoeleinden maken. Schadelijke toepassingen kunnen dit gebruiken om de locatie en/of status te overschrijven die door de echte locatiebronnen, zoals GPS of netwerkaanbieders, wordt aangegeven of om uw locatie bij te houden en te rapporteren aan externe bronnen."</string>
+ <string name="permlab_accessFineLocation">"nauwkeurige (GPS) locatie"</string>
+ <string name="permdesc_accessFineLocation">"Toegang tot exacte locatiebronnen, zoals het Global Positioning System op de telefoon, indien beschikbaar. Schadelijke toepassingen kunnen dit gebruiken om te bepalen waar u zich bevindt en mogelijk extra acculading verbruiken."</string>
+ <string name="permlab_accessCoarseLocation">"globale (netwerkgebaseerde) locatie"</string>
+ <string name="permdesc_accessCoarseLocation">"Toegang tot globale locatiebronnen, zoals de mobiele netwerkdatabase om een globale telefoonlocatie te bepalen, indien beschikbaar. Schadelijke toepassingen kunnen hiervan gebruik maken om bij benadering te bepalen waar u zich bevindt."</string>
+ <string name="permlab_accessSurfaceFlinger">"toegang tot SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Hiermee kan een toepassing SurfaceFlinger-functies op laag niveau gebruiken."</string>
+ <string name="permlab_readFrameBuffer">"framebuffer lezen"</string>
+ <string name="permdesc_readFrameBuffer">"Hiermee kan een toepassing de inhoud van de framebuffer lezen."</string>
+ <string name="permlab_modifyAudioSettings">"uw audio-instellingen wijzigen"</string>
+ <string name="permdesc_modifyAudioSettings">"Hiermee kan een toepassing de algemene audio-instellingen, zoals volume en omleiding, wijzigen."</string>
+ <string name="permlab_recordAudio">"audio opnemen"</string>
+ <string name="permdesc_recordAudio">"Hiermee krijgt de toepassing toegang tot het audio-opnamepad."</string>
+ <string name="permlab_camera">"foto\'s maken"</string>
+ <string name="permdesc_camera">"Hiermee kan een toepassing foto\'s maken met de camera. De toepassing kan op deze manier op elk gewenste moment foto\'s verzamelen van wat de camera ziet."</string>
+ <string name="permlab_brick">"telefoon permanent uitschakelen"</string>
+ <string name="permdesc_brick">"Hiermee kan de toepassing de telefoon permanent uitschakelen. Dit is erg gevaarlijk."</string>
+ <string name="permlab_reboot">"telefoon nu opnieuw opstarten"</string>
+ <string name="permdesc_reboot">"Hiermee kan de toepassing de telefoon nu opnieuw opstarten."</string>
+ <string name="permlab_mount_unmount_filesystems">"bestandssystemen koppelen en ontkoppelen"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Hiermee kan de toepassing bestandssystemen koppelen en ontkoppelen voor verwisselbare opslagruimte."</string>
+ <string name="permlab_mount_format_filesystems">"externe opslag formatteren"</string>
+ <string name="permdesc_mount_format_filesystems">"Hiermee kan de toepassing de externe opslag formatteren."</string>
+ <string name="permlab_vibrate">"trilstand beheren"</string>
+ <string name="permdesc_vibrate">"Hiermee kan de toepassing de trilstand beheren."</string>
+ <string name="permlab_flashlight">"zaklamp bedienen"</string>
+ <string name="permdesc_flashlight">"Hiermee kan de toepassing de zaklamp bedienen."</string>
+ <string name="permlab_hardware_test">"hardware testen"</string>
+ <string name="permdesc_hardware_test">"Hiermee kan de toepassing verschillende randapparaten beheren om de hardware te testen."</string>
+ <string name="permlab_callPhone">"telefoonnummers rechtstreeks bellen"</string>
+ <string name="permdesc_callPhone">"Hiermee kan de toepassing telefoonnummers bellen zonder uw tussenkomst. Door schadelijke toepassingen kunnen onverwachte oproepen op uw telefoonrekening verschijnen. De toepassing kan hiermee geen alarmnummers bellen."</string>
+ <string name="permlab_callPrivileged">"alle telefoonnummers rechtstreeks bellen"</string>
+ <string name="permdesc_callPrivileged">"Hiermee kan een toepassing elk telefoonnummer, inclusief alarmnummers, bellen zonder uw tussenkomst. Schadelijke toepassingen kunnen onnodige en illegale oproepen uitvoeren naar alarmdiensten."</string>
+ <string name="permlab_locationUpdates">"meldingen over locatie-updates beheren"</string>
+ <string name="permdesc_locationUpdates">"Hiermee kunnen updatemeldingen voor locaties van de radio worden ingeschakeld/uitgeschakeld. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_checkinProperties">"toegang tot checkin-eigenschappen"</string>
+ <string name="permdesc_checkinProperties">"Hiermee wordt lees-/schrijftoegang gegeven tot eigenschappen die door de checkin-service zijn geüpload. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_bindGadget">"widgets kiezen"</string>
+ <string name="permdesc_bindGadget">"Hiermee kan een toepassing het systeem melden welke widgets door welke toepassing kunnen worden gebruikt. Met deze toestemming kunnen toepassingen andere toepassingen toegang geven tot persoonlijke gegevens. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_modifyPhoneState">"telefoonstatus wijzigen"</string>
+ <string name="permdesc_modifyPhoneState">"Hiermee kan de toepassing de telefoonfuncties van het apparaat beheren. Een toepassing met deze machtiging kan schakelen tussen netwerken, de radio van de telefoon in- of uitschakelen en dergelijke zonder dat u hiervan op de hoogte wordt gesteld."</string>
+ <string name="permlab_readPhoneState">"telefoonstatus lezen"</string>
+ <string name="permdesc_readPhoneState">"Hiermee krijgt de toepassing toegang tot de telefoonfuncties van het apparaat. Een toepassing met de betreffende machtiging kan het telefoonnummer van deze telefoon achterhalen, bepalen of een oproep actief is, het gekozen nummer achterhalen en dergelijke."</string>
+ <string name="permlab_wakeLock">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
+ <string name="permdesc_wakeLock">"Hiermee kan een toepassing voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
+ <string name="permlab_devicePower">"telefoon in- of uitschakelen"</string>
+ <string name="permdesc_devicePower">"Hiermee kan de toepassing de telefoon in- of uitschakelen."</string>
+ <string name="permlab_factoryTest">"uitvoeren in fabriekstestmodus"</string>
+ <string name="permdesc_factoryTest">"Uitvoeren als fabrikanttest op laag niveau, waardoor toegang wordt gegeven tot de hardware van de telefoon. Alleen beschikbaar als een telefoon zich in de fabrikanttestmodus bevindt."</string>
+ <string name="permlab_setWallpaper">"achtergrond instellen"</string>
+ <string name="permdesc_setWallpaper">"Hiermee kan de toepassing de systeemachtergrond instellen."</string>
+ <string name="permlab_setWallpaperHints">"grootte achtergrond instellen"</string>
+ <string name="permdesc_setWallpaperHints">"Hiermee kan de toepassing de grootte van de achtergrond instellen."</string>
+ <string name="permlab_masterClear">"systeem terugzetten op fabrieksinstellingen"</string>
+ <string name="permdesc_masterClear">"Hiermee kan een toepassing het systeem terugzetten op de fabrieksinstellingen, waarbij alle gegevens, configuraties en geïnstalleerde toepassingen worden verwijderd."</string>
+ <string name="permlab_setTimeZone">"tijdzone instellen"</string>
+ <string name="permdesc_setTimeZone">"Hiermee kan een toepassing de tijdzone van de telefoon wijzigen."</string>
+ <string name="permlab_getAccounts">"bekende accounts zoeken"</string>
+ <string name="permdesc_getAccounts">"Hiermee kan een toepassing de lijst met accounts van een telefoon ophalen."</string>
+ <string name="permlab_accessNetworkState">"netwerkstatus bekijken"</string>
+ <string name="permdesc_accessNetworkState">"Hiermee kan een toepassing de status van alle netwerken bekijken."</string>
+ <string name="permlab_createNetworkSockets">"volledige internettoegang"</string>
+ <string name="permdesc_createNetworkSockets">"Hiermee kan een toepassing netwerksockets maken."</string>
+ <string name="permlab_writeApnSettings">"instellingen voor toegangspuntnaam schrijven"</string>
+ <string name="permdesc_writeApnSettings">"Hiermee kan een toepassing de APN-instellingen, zoals proxy en poort, van elke APN wijzigen."</string>
+ <string name="permlab_changeNetworkState">"netwerkverbinding wijzigen"</string>
+ <string name="permdesc_changeNetworkState">"Hiermee kan een toepassing de verbindingsstatus van het netwerk wijzigen."</string>
+ <string name="permlab_changeBackgroundDataSetting">"instelling voor gebruik van achtergrondgegevens van gegevens wijzigen"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Hiermee kan een toepassing de instelling voor gebruik van achtergrondgegevens wijzigen."</string>
+ <string name="permlab_accessWifiState">"Wi-Fi-status bekijken"</string>
+ <string name="permdesc_accessWifiState">"Hiermee kan een toepassing informatie over de Wi-Fi-status bekijken."</string>
+ <string name="permlab_changeWifiState">"Wi-Fi-status wijzigen"</string>
+ <string name="permdesc_changeWifiState">"Hiermee kan een toepassing zich koppelen aan en loskoppelen van Wi-Fi toegangspunten en wijzigingen aanbrengen in geconfigureerde Wi-Fi-netwerken."</string>
+ <string name="permlab_changeWifiMulticastState">"Wi-Fi Multicast-ontvangst toestaan"</string>
+ <string name="permdesc_changeWifiMulticastState">"Hiermee kan een toepassing pakketten ontvangen die niet rechtstreeks zijn geadresseerd aan uw apparaat. Dit kan handig zijn wanneer services in de buurt worden ontdekt. Dit verbruikt meer energie dan de niet-multicastmodus."</string>
+ <string name="permlab_bluetoothAdmin">"bluetooth-beheer"</string>
+ <string name="permdesc_bluetoothAdmin">"Hiermee kan een toepassing de lokale Bluetooth-telefoon configureren en externe apparaten zoeken en aansluiten."</string>
+ <string name="permlab_bluetooth">"Bluetooth-verbindingen maken"</string>
+ <string name="permdesc_bluetooth">"Hiermee kan een toepassing de configuratie van een lokale Bluetooth-telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
+ <string name="permlab_disableKeyguard">"toetsvergrendeling uitschakelen"</string>
+ <string name="permdesc_disableKeyguard">"Hiermee kan een toepassing de toetsvergrendeling en bijbehorende wachtwoordbeveiliging uitschakelen. Een voorbeeld: de telefoon schakelt de toetsvergrendeling uit als er een oproep binnenkomt en schakelt de toetsvergrendeling weer in als de oproep is beëindigd."</string>
+ <string name="permlab_readSyncSettings">"synchronisatie-instellingen lezen"</string>
+ <string name="permdesc_readSyncSettings">"Hiermee kan een toepassing de synchronisatie-instellingen lezen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
+ <string name="permlab_writeSyncSettings">"synchronisatie-instellingen schrijven"</string>
+ <string name="permdesc_writeSyncSettings">"Hiermee kan een toepassing uw synchronisatie-instellingen wijzigen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
+ <string name="permlab_readSyncStats">"synchronisatiestatistieken lezen"</string>
+ <string name="permdesc_readSyncStats">"Hiermee kan een toepassing de synchronisatiestatistieken lezen, zoals de geschiedenis van uitgevoerde synchronisaties."</string>
+ <string name="permlab_subscribedFeedsRead">"geabonneerde feeds lezen"</string>
+ <string name="permdesc_subscribedFeedsRead">"Hiermee kan een toepassing details over de huidige gesynchroniseerde feeds achterhalen."</string>
+ <string name="permlab_subscribedFeedsWrite">"geabonneerde feeds schrijven"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Hiermee kan een toepassing uw huidige gesynchroniseerde feeds wijzigen. Een schadelijke toepassing kan op deze manier uw gesynchroniseerde feeds wijzigen."</string>
+ <string name="permlab_readDictionary">"door gebruiker gedefinieerd woordenboek lezen"</string>
+ <string name="permdesc_readDictionary">"Hiermee kan een toepassing privéwoorden, namen en woordcombinaties lezen die de gebruiker heeft opgeslagen in het gebruikerswoordenboek."</string>
+ <string name="permlab_writeDictionary">"schrijven naar door gebruiker gedefinieerd woordenboek"</string>
+ <string name="permdesc_writeDictionary">"Hiermee kan een toepassing nieuwe woorden schrijven naar het gebruikerswoordenboek."</string>
+ <string name="permlab_sdcardWrite">"inhoud op de SD-kaart aanpassen/verwijderen"</string>
+ <string name="permdesc_sdcardWrite">"Hiermee kan een toepassing schrijven naar de SD-kaart."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Thuis"</item>
- <item msgid="869923650527136615">"Mobiel"</item>
- <item msgid="7897544654242874543">"Werk"</item>
- <item msgid="1103601433382158155">"Fax werk"</item>
- <item msgid="1735177144948329370">"Fax thuis"</item>
- <item msgid="603878674477207394">"Semafoon"</item>
- <item msgid="1650824275177931637">"Overig"</item>
- <item msgid="9192514806975898961">"Aangepast"</item>
+ <item>"Thuis"</item>
+ <item>"Mobiel"</item>
+ <item>"Werk"</item>
+ <item>"Fax werk"</item>
+ <item>"Fax thuis"</item>
+ <item>"Semafoon"</item>
+ <item>"Overig"</item>
+ <item>"Aangepast"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Thuis"</item>
- <item msgid="7084237356602625604">"Werk"</item>
- <item msgid="1112044410659011023">"Overig"</item>
- <item msgid="2374913952870110618">"Aangepast"</item>
+ <item>"Thuis"</item>
+ <item>"Werk"</item>
+ <item>"Overig"</item>
+ <item>"Aangepast"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobiel"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Thuis"</item>
- <item msgid="5629153956045109251">"Werk"</item>
- <item msgid="4966604264500343469">"Overig"</item>
- <item msgid="4932682847595299369">"Aangepast"</item>
+ <item>"Thuis"</item>
+ <item>"Werk"</item>
+ <item>"Overig"</item>
+ <item>"Aangepast"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Thuis"</item>
- <item msgid="1359644565647383708">"Werk"</item>
- <item msgid="7868549401053615677">"Overig"</item>
- <item msgid="3145118944639869809">"Aangepast"</item>
+ <item>"Thuis"</item>
+ <item>"Werk"</item>
+ <item>"Overig"</item>
+ <item>"Aangepast"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Werk"</item>
- <item msgid="4378074129049520373">"Overig"</item>
- <item msgid="3455047468583965104">"Aangepast"</item>
+ <item>"Werk"</item>
+ <item>"Overig"</item>
+ <item>"Aangepast"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN-code invoeren"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Onjuiste PIN-code!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Druk op \'Menu\' en vervolgens op 0 om te ontgrendelen."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Alarmnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Geen service)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Scherm vergrendeld."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Druk op \'Menu\' om te ontgrendelen of noodoproep te plaatsen."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Druk op \'Menu\' om te ontgrendelen."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Patroon tekenen om te ontgrendelen"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Noodoproep"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Juist!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Probeer het opnieuw"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Opladen (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Opgeladen."</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Sluit de oplader aan."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Geen SIM-kaart."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Geen SIM-kaart in telefoon."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Plaats een SIM-kaart."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netwerk vergrendeld"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-kaart is vergrendeld met PUK-code."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Raadpleeg de gebruikershandleiding of neem contact op met de klantenservice."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kaart is vergrendeld."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-kaart ontgrendelen..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen, wordt u gevraagd om uw telefoon te ontgrendelen met uw Google aanmelding."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Probeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Patroon vergeten?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Te veel patroonpogingen!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Om te ontgrendelen, moet U zich eerst bij uw Google-account aanmelden"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Gebruikersnaam (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Wachtwoord"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Aanmelden"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Gebruikersnaam of wachtwoord ongeldig."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wissen"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Geen meldingen"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actief"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Opladen..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Sluit de oplader aan"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"De accu raakt op:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"minder dan <xliff:g id="NUMBER">%d%%</xliff:g> resterend."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Waarom?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Fabriekstest mislukt"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"De actie FACTORY_TEST wordt alleen ondersteund voor pakketten die zijn geïnstalleerd in /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Er is geen pakket gevonden dat de actie FACTORY_TEST levert."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Opnieuw opstarten"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"De pagina op \'<xliff:g id="TITLE">%s</xliff:g>\' zegt:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Wilt u deze pagina verlaten?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Kies OK om door te gaan of Annuleren om op de huidige pagina te blijven."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Bevestigen"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"browsergeschiedenis en bladwijzers lezen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Hiermee kan een toepassing de URL\'s lezen die u via de browser heeft bezocht, evenals alle bladwijzers van de browser."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"browsergeschiedenis en bladwijzers schrijven"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Hiermee kan een toepassing de op uw telefoon opgeslagen browsergeschiedenis of bladwijzers wijzigen. Schadelijke toepassingen kunnen hiermee uw browsergegevens verwijderen of wijzigen."</string>
- <string name="save_password_message" msgid="767344687139195790">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nooit"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"U heeft geen toestemming om deze pagina te openen."</string>
- <string name="text_copied" msgid="4985729524670131385">"Tekst naar klembord gekopieerd."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Meer"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"ruimte"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"invoeren"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"verwijderen"</string>
- <string name="search_go" msgid="8298016669822141719">"Zoeken"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand geleden"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Meer dan 1 maand geleden"</string>
+ <string name="keyguard_password_enter_pin_code">"PIN-code invoeren"</string>
+ <string name="keyguard_password_wrong_pin_code">"Onjuiste PIN-code!"</string>
+ <string name="keyguard_label_text">"Druk op \'Menu\' en vervolgens op 0 om te ontgrendelen."</string>
+ <string name="emergency_call_dialog_number_for_display">"Alarmnummer"</string>
+ <string name="lockscreen_carrier_default">"(Geen service)"</string>
+ <string name="lockscreen_screen_locked">"Scherm vergrendeld."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Druk op \'Menu\' om te ontgrendelen of noodoproep te plaatsen."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Druk op \'Menu\' om te ontgrendelen."</string>
+ <string name="lockscreen_pattern_instructions">"Patroon tekenen om te ontgrendelen"</string>
+ <string name="lockscreen_emergency_call">"Noodoproep"</string>
+ <string name="lockscreen_pattern_correct">"Juist!"</string>
+ <string name="lockscreen_pattern_wrong">"Probeer het opnieuw"</string>
+ <string name="lockscreen_plugged_in">"Opladen (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Sluit de oplader aan."</string>
+ <string name="lockscreen_missing_sim_message_short">"Geen SIM-kaart."</string>
+ <string name="lockscreen_missing_sim_message">"Geen SIM-kaart in telefoon."</string>
+ <string name="lockscreen_missing_sim_instructions">"Plaats een SIM-kaart."</string>
+ <string name="lockscreen_network_locked_message">"Netwerk vergrendeld"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-kaart is vergrendeld met PUK-code."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Raadpleeg de gebruikershandleiding of neem contact op met de klantenservice."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-kaart is vergrendeld."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM-kaart ontgrendelen..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen, wordt u gevraagd om uw telefoon te ontgrendelen met uw Google aanmelding."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Probeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Patroon vergeten?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Te veel patroonpogingen!"</string>
+ <string name="lockscreen_glogin_instructions">"Om te ontgrendelen, moet U zich eerst bij uw Google-account aanmelden"</string>
+ <string name="lockscreen_glogin_username_hint">"Gebruikersnaam (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Wachtwoord"</string>
+ <string name="lockscreen_glogin_submit_button">"Aanmelden"</string>
+ <string name="lockscreen_glogin_invalid_input">"Gebruikersnaam of wachtwoord ongeldig."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Geen meldingen"</string>
+ <string name="status_bar_ongoing_events_title">"Actief"</string>
+ <string name="status_bar_latest_events_title">"Meldingen"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Opladen..."</string>
+ <string name="battery_low_title">"Sluit de oplader aan"</string>
+ <string name="battery_low_subtitle">"De accu raakt op:"</string>
+ <string name="battery_low_percent_format">"minder dan <xliff:g id="NUMBER">%d%%</xliff:g> resterend."</string>
+ <string name="battery_low_why">"Waarom?"</string>
+ <string name="factorytest_failed">"Fabriekstest mislukt"</string>
+ <string name="factorytest_not_system">"De actie FACTORY_TEST wordt alleen ondersteund voor pakketten die zijn geïnstalleerd in /system/app."</string>
+ <string name="factorytest_no_action">"Er is geen pakket gevonden dat de actie FACTORY_TEST levert."</string>
+ <string name="factorytest_reboot">"Opnieuw opstarten"</string>
+ <string name="js_dialog_title">"De pagina op \'<xliff:g id="TITLE">%s</xliff:g>\' zegt:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Wilt u deze pagina verlaten?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Kies OK om door te gaan of Annuleren om op de huidige pagina te blijven."</string>
+ <string name="save_password_label">"Bevestigen"</string>
+ <string name="permlab_readHistoryBookmarks">"browsergeschiedenis en bladwijzers lezen"</string>
+ <string name="permdesc_readHistoryBookmarks">"Hiermee kan een toepassing de URL\'s lezen die u via de browser heeft bezocht, evenals alle bladwijzers van de browser."</string>
+ <string name="permlab_writeHistoryBookmarks">"browsergeschiedenis en bladwijzers schrijven"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Hiermee kan een toepassing de op uw telefoon opgeslagen browsergeschiedenis of bladwijzers wijzigen. Schadelijke toepassingen kunnen hiermee uw browsergegevens verwijderen of wijzigen."</string>
+ <string name="save_password_message">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
+ <string name="save_password_notnow">"Niet nu"</string>
+ <string name="save_password_remember">"Onthouden"</string>
+ <string name="save_password_never">"Nooit"</string>
+ <string name="open_permission_deny">"U heeft geen toestemming om deze pagina te openen."</string>
+ <string name="text_copied">"Tekst naar klembord gekopieerd."</string>
+ <string name="more_item_label">"Meer"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"ruimte"</string>
+ <string name="menu_enter_shortcut_label">"invoeren"</string>
+ <string name="menu_delete_shortcut_label">"verwijderen"</string>
+ <string name="search_go">"Zoeken"</string>
+ <string name="oneMonthDurationPast">"1 maand geleden"</string>
+ <string name="beforeOneMonthDurationPast">"Meer dan 1 maand geleden"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 seconde geleden"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
+ <item quantity="one">"1 seconde geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuut geleden"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
+ <item quantity="one">"1 minuut geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 uur geleden"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
+ <item quantity="one">"1 uur geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"gisteren"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
+ <item quantity="one">"gisteren"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"over 1 seconde"</item>
- <item quantity="other" msgid="1241926116443974687">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
+ <item quantity="one">"over 1 seconde"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"over 1 minuut"</item>
- <item quantity="other" msgid="3330713936399448749">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
+ <item quantity="one">"over 1 minuut"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"over 1 uur"</item>
- <item quantity="other" msgid="547290677353727389">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
+ <item quantity="one">"over 1 uur"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"morgen"</item>
- <item quantity="other" msgid="5109449375100953247">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
+ <item quantity="one">"morgen"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 seconde geleden"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
+ <item quantity="one">"1 seconde geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 minuut geleden"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
+ <item quantity="one">"1 minuut geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 uur geleden"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
+ <item quantity="one">"1 uur geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"gisteren"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
+ <item quantity="one">"gisteren"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"over 1 seconde"</item>
- <item quantity="other" msgid="5495880108825805108">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
+ <item quantity="one">"over 1 seconde"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"over 1 minuut"</item>
- <item quantity="other" msgid="4216113292706568726">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
+ <item quantity="one">"over 1 minuut"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"over 1 uur"</item>
- <item quantity="other" msgid="3705373766798013406">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
+ <item quantity="one">"over 1 uur"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"morgen"</item>
- <item quantity="other" msgid="2973062968038355991">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
+ <item quantity="one">"morgen"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"op %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"om %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"in %s"</string>
- <string name="day" msgid="8144195776058119424">"dag"</string>
- <string name="days" msgid="4774547661021344602">"dagen"</string>
- <string name="hour" msgid="2126771916426189481">"uur"</string>
- <string name="hours" msgid="894424005266852993">"uren"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"minuten"</string>
- <string name="second" msgid="3184235808021478">"sec"</string>
- <string name="seconds" msgid="3161515347216589235">"seconden"</string>
- <string name="week" msgid="5617961537173061583">"week"</string>
- <string name="weeks" msgid="6509623834583944518">"weken"</string>
- <string name="year" msgid="4001118221013892076">"jaar"</string>
- <string name="years" msgid="6881577717993213522">"jaren"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Elke weekdag (ma-vr)"</string>
- <string name="daily" msgid="5738949095624133403">"Dagelijks"</string>
- <string name="weekly" msgid="983428358394268344">"Wekelijks op <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Maandelijks"</string>
- <string name="yearly" msgid="1519577999407493836">"Jaarlijks"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Video kan niet worden afgespeeld"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Deze video kan helaas niet worden gestreamd naar dit apparaat."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Deze video kan niet worden afgespeeld."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"twaalf uur \'s middags"</string>
- <string name="Noon" msgid="3342127745230013127">"Twaalf uur \'s middags"</string>
- <string name="midnight" msgid="7166259508850457595">"middernacht"</string>
- <string name="Midnight" msgid="5630806906897892201">"Middernacht"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Alles selecteren"</string>
- <string name="selectText" msgid="3889149123626888637">"Tekst selecteren"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Stoppen met tekst selecteren"</string>
- <string name="cut" msgid="3092569408438626261">"Knippen"</string>
- <string name="cutAll" msgid="2436383270024931639">"Alles knippen"</string>
- <string name="copy" msgid="2681946229533511987">"Kopiëren"</string>
- <string name="copyAll" msgid="2590829068100113057">"Alles kopiëren"</string>
- <string name="paste" msgid="5629880836805036433">"Plakken"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URL kopiëren"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Invoermethode"</string>
- <string name="addToDictionary" msgid="726256909274177272">"%s\' toevoegen aan woordenboek"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Tekst bewerken"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Weinig ruimte"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Opslagruimte van telefoon raakt op."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Annuleren"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Annuleren"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Let op"</string>
- <string name="capital_on" msgid="1544682755514494298">"AAN"</string>
- <string name="capital_off" msgid="6815870386972805832">"UIT"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Actie voltooien met"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Standaard gebruiken voor deze actie."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Wis standaardinstelling via startscherm: \'Instellingen\' &gt; \'Toepassingen\' &gt; \'Toepassingen beheren\'."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Een actie selecteren"</string>
- <string name="noApplications" msgid="1691104391758345586">"Geen enkele toepassing kan deze actie uitvoeren."</string>
- <string name="aerr_title" msgid="653922989522758100">"Helaas!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"De toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) is onverwachts gestopt. Probeer het opnieuw."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> is onverwachts gestopt. Probeer het opnieuw."</string>
- <string name="anr_title" msgid="3100070910664756057">"Helaas!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in toepassing <xliff:g id="APPLICATION">%2$s</xliff:g>) reageert niet."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
- <string name="anr_process" msgid="1246866008169975783">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> reageert niet."</string>
- <string name="force_close" msgid="3653416315450806396">"Nu sluiten"</string>
- <string name="report" msgid="4060218260984795706">"Rapport"</string>
- <string name="wait" msgid="7147118217226317732">"Wachten"</string>
- <string name="debug" msgid="9103374629678531849">"Foutopsporing"</string>
- <string name="sendText" msgid="5132506121645618310">"Selecteer een actie voor tekst"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Belvolume"</string>
- <string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Afspelen via Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volume inkomende oproep"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume tijdens gesprek in Bluetooth-modus"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Alarmvolume"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Meldingsvolume"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Standaardbeltoon"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standaardbeltoon (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Stil"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Beltonen"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Onbekende beltoon"</string>
+ <string name="preposition_for_date">"op %s"</string>
+ <string name="preposition_for_time">"om %s"</string>
+ <string name="preposition_for_year">"in %s"</string>
+ <string name="day">"dag"</string>
+ <string name="days">"dagen"</string>
+ <string name="hour">"uur"</string>
+ <string name="hours">"uren"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"minuten"</string>
+ <string name="second">"sec"</string>
+ <string name="seconds">"seconden"</string>
+ <string name="week">"week"</string>
+ <string name="weeks">"weken"</string>
+ <string name="year">"jaar"</string>
+ <string name="years">"jaren"</string>
+ <string name="every_weekday">"Elke weekdag (ma-vr)"</string>
+ <string name="daily">"Dagelijks"</string>
+ <string name="weekly">"Wekelijks op <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Maandelijks"</string>
+ <string name="yearly">"Jaarlijks"</string>
+ <string name="VideoView_error_title">"Video kan niet worden afgespeeld"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Deze video kan helaas niet worden gestreamd naar dit apparaat."</string>
+ <string name="VideoView_error_text_unknown">"Deze video kan niet worden afgespeeld."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"twaalf uur \'s middags"</string>
+ <string name="Noon">"Twaalf uur \'s middags"</string>
+ <string name="midnight">"middernacht"</string>
+ <string name="Midnight">"Middernacht"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Alles selecteren"</string>
+ <string name="selectText">"Tekst selecteren"</string>
+ <string name="stopSelectingText">"Stoppen met tekst selecteren"</string>
+ <string name="cut">"Knippen"</string>
+ <string name="cutAll">"Alles knippen"</string>
+ <string name="copy">"Kopiëren"</string>
+ <string name="copyAll">"Alles kopiëren"</string>
+ <string name="paste">"Plakken"</string>
+ <string name="copyUrl">"URL kopiëren"</string>
+ <string name="inputMethod">"Invoermethode"</string>
+ <string name="addToDictionary">"%s\' toevoegen aan woordenboek"</string>
+ <string name="editTextMenuTitle">"Tekst bewerken"</string>
+ <string name="low_internal_storage_view_title">"Weinig ruimte"</string>
+ <string name="low_internal_storage_view_text">"Opslagruimte van telefoon raakt op."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Annuleren"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Annuleren"</string>
+ <string name="dialog_alert_title">"Let op"</string>
+ <string name="capital_on">"AAN"</string>
+ <string name="capital_off">"UIT"</string>
+ <string name="whichApplication">"Actie voltooien met"</string>
+ <string name="alwaysUse">"Standaard gebruiken voor deze actie."</string>
+ <string name="clearDefaultHintMsg">"Wis standaardinstelling via startscherm: \'Instellingen\' &gt; \'Toepassingen\' &gt; \'Toepassingen beheren\'."</string>
+ <string name="chooseActivity">"Een actie selecteren"</string>
+ <string name="noApplications">"Geen enkele toepassing kan deze actie uitvoeren."</string>
+ <string name="aerr_title">"Helaas!"</string>
+ <string name="aerr_application">"De toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) is onverwachts gestopt. Probeer het opnieuw."</string>
+ <string name="aerr_process">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> is onverwachts gestopt. Probeer het opnieuw."</string>
+ <string name="anr_title">"Helaas!"</string>
+ <string name="anr_activity_application">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in toepassing <xliff:g id="APPLICATION">%2$s</xliff:g>) reageert niet."</string>
+ <string name="anr_activity_process">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
+ <string name="anr_application_process">"Toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
+ <string name="anr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> reageert niet."</string>
+ <string name="force_close">"Nu sluiten"</string>
+ <string name="report">"Rapport"</string>
+ <string name="wait">"Wachten"</string>
+ <string name="debug">"Foutopsporing"</string>
+ <string name="sendText">"Selecteer een actie voor tekst"</string>
+ <string name="volume_ringtone">"Belvolume"</string>
+ <string name="volume_music">"Mediavolume"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Afspelen via Bluetooth"</string>
+ <string name="volume_call">"Volume inkomende oproep"</string>
+ <string name="volume_bluetooth_call">"Volume tijdens gesprek in Bluetooth-modus"</string>
+ <string name="volume_alarm">"Alarmvolume"</string>
+ <string name="volume_notification">"Meldingsvolume"</string>
+ <string name="volume_unknown">"Volume"</string>
+ <string name="ringtone_default">"Standaardbeltoon"</string>
+ <string name="ringtone_default_with_actual">"Standaardbeltoon (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Stil"</string>
+ <string name="ringtone_picker_title">"Beltonen"</string>
+ <string name="ringtone_unknown">"Onbekende beltoon"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fi-netwerk beschikbaar"</item>
- <item quantity="other" msgid="4192424489168397386">"Wi-Fi-netwerken beschikbaar"</item>
+ <item quantity="one">"Wi-Fi-netwerk beschikbaar"</item>
+ <item quantity="other">"Wi-Fi-netwerken beschikbaar"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Open Wi-Fi-netwerk beschikbaar"</item>
- <item quantity="other" msgid="7915895323644292768">"Open Wi-Fi-netwerken beschikbaar"</item>
+ <item quantity="one">"Open Wi-Fi-netwerk beschikbaar"</item>
+ <item quantity="other">"Open Wi-Fi-netwerken beschikbaar"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Onbekende toepassing"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Er wordt een groot aantal SMS-berichten verzonden. Selecteer \'OK\' om door te gaan of \'Annuleren\' om de verzending te stoppen."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annuleren"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Instellen"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Standaard"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Geen machtigingen vereist"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Verbergen"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Alles weergeven"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Laden..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB-verbinding"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"U heeft uw telefoon via USB op uw computer aangesloten. Selecteer \'Koppelen\' als u bestanden tussen uw computer en de SD-kaart van uw telefoon wilt kopiëren."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Koppelen"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Niet koppelen"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Er is een probleem bij het gebruik van uw SD-kaart voor USB-opslag."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-verbinding"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Selecteer dit om bestanden naar/van uw computer te kopiëren."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB-opslag uitschakelen"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Selecteer dit om USB-opslag uit te schakelen."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"USB-opslag uitschakelen"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Voordat u de USB-opslag uitschakelt, moet u de koppeling met de USB-host verbreken. Selecteer \'Uitschakelen\' om USB-opslag uit te schakelen."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Uitschakelen"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Annuleren"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Er is een probleem opgetreden tijdens het uitschakelen van USB-opslag. Controleer of u de USB-host heeft losgekoppeld en probeer het opnieuw."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"SD-kaart formatteren"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Weet u zeker dat u de SD-kaart wilt formatteren? Alle gegevens op uw kaart gaan dan verloren."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatteren"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-foutopsporing verbonden"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Uw telefoon heeft verbinding met een computer."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Invoermethode selecteren"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SD-kaart voorbereiden"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Controleren op fouten."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Lege SD-kaart"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"SD-kaart is leeg of heeft een niet-ondersteund bestandssysteem."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Beschadigde SD-kaart"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"SD-kaart beschadigd. U moet de kaart mogelijk opnieuw formatteren."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD-kaart onverwachts verwijderd"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Ontkoppel de SD-kaart voordat u deze verwijdert om gegevensverlies te voorkomen."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"De SD-kaart kan veilig worden verwijderd"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"U kunt de SD-kaart veilig verwijderen."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SD-kaart is verwijderd"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"SD-kaart verwijderd. Plaats een nieuwe."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Geen overeenkomende activiteiten gevonden"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"gebruiksstatistieken van component bijwerken"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Hiermee kunnen verzamelde gebruiksstatistieken van een component worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tik twee keer voor zoomregeling"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Fout bij uitbreiden van widget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Ga"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Zoeken"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Verzenden"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Volgende"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Gereed"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Uitvoeren"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Nummer bellen"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Contact maken"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"aangevinkt"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"niet aangevinkt"</string>
+ <string name="select_character">"Teken invoegen"</string>
+ <string name="sms_control_default_app_name">"Onbekende toepassing"</string>
+ <string name="sms_control_title">"SMS-berichten verzenden"</string>
+ <string name="sms_control_message">"Er wordt een groot aantal SMS-berichten verzonden. Selecteer \'OK\' om door te gaan of \'Annuleren\' om de verzending te stoppen."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Annuleren"</string>
+ <string name="date_time_set">"Instellen"</string>
+ <string name="default_permission_group">"Standaard"</string>
+ <string name="no_permissions">"Geen machtigingen vereist"</string>
+ <string name="perms_hide"><b>"Verbergen"</b></string>
+ <string name="perms_show_all"><b>"Alles weergeven"</b></string>
+ <string name="googlewebcontenthelper_loading">"Laden..."</string>
+ <string name="usb_storage_title">"USB-verbinding"</string>
+ <string name="usb_storage_message">"U heeft uw telefoon via USB op uw computer aangesloten. Selecteer \'Koppelen\' als u bestanden tussen uw computer en de SD-kaart van uw telefoon wilt kopiëren."</string>
+ <string name="usb_storage_button_mount">"Koppelen"</string>
+ <string name="usb_storage_button_unmount">"Niet koppelen"</string>
+ <string name="usb_storage_error_message">"Er is een probleem bij het gebruik van uw SD-kaart voor USB-opslag."</string>
+ <string name="usb_storage_notification_title">"USB-verbinding"</string>
+ <string name="usb_storage_notification_message">"Selecteer dit om bestanden naar/van uw computer te kopiëren."</string>
+ <string name="usb_storage_stop_notification_title">"USB-opslag uitschakelen"</string>
+ <string name="usb_storage_stop_notification_message">"Selecteer dit om USB-opslag uit te schakelen."</string>
+ <string name="usb_storage_stop_title">"USB-opslag uitschakelen"</string>
+ <string name="usb_storage_stop_message">"Voordat u de USB-opslag uitschakelt, moet u de koppeling met de USB-host verbreken. Selecteer \'Uitschakelen\' om USB-opslag uit te schakelen."</string>
+ <string name="usb_storage_stop_button_mount">"Uitschakelen"</string>
+ <string name="usb_storage_stop_button_unmount">"Annuleren"</string>
+ <string name="usb_storage_stop_error_message">"Er is een probleem opgetreden tijdens het uitschakelen van USB-opslag. Controleer of u de USB-host heeft losgekoppeld en probeer het opnieuw."</string>
+ <string name="extmedia_format_title">"SD-kaart formatteren"</string>
+ <string name="extmedia_format_message">"Weet u zeker dat u de SD-kaart wilt formatteren? Alle gegevens op uw kaart gaan dan verloren."</string>
+ <string name="extmedia_format_button_format">"Formatteren"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Invoermethode selecteren"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"kandidaten"</u></string>
+ <string name="ext_media_checking_notification_title">"SD-kaart voorbereiden"</string>
+ <string name="ext_media_checking_notification_message">"Controleren op fouten."</string>
+ <string name="ext_media_nofs_notification_title">"Lege SD-kaart"</string>
+ <string name="ext_media_nofs_notification_message">"SD-kaart is leeg of heeft een niet-ondersteund bestandssysteem."</string>
+ <string name="ext_media_unmountable_notification_title">"Beschadigde SD-kaart"</string>
+ <string name="ext_media_unmountable_notification_message">"SD-kaart beschadigd. U moet de kaart mogelijk opnieuw formatteren."</string>
+ <string name="ext_media_badremoval_notification_title">"SD-kaart onverwachts verwijderd"</string>
+ <string name="ext_media_badremoval_notification_message">"Ontkoppel de SD-kaart voordat u deze verwijdert om gegevensverlies te voorkomen."</string>
+ <string name="ext_media_safe_unmount_notification_title">"De SD-kaart kan veilig worden verwijderd"</string>
+ <string name="ext_media_safe_unmount_notification_message">"U kunt de SD-kaart veilig verwijderen."</string>
+ <string name="ext_media_nomedia_notification_title">"SD-kaart is verwijderd"</string>
+ <string name="ext_media_nomedia_notification_message">"SD-kaart verwijderd. Plaats een nieuwe."</string>
+ <string name="activity_list_empty">"Geen overeenkomende activiteiten gevonden"</string>
+ <string name="permlab_pkgUsageStats">"gebruiksstatistieken van component bijwerken"</string>
+ <string name="permdesc_pkgUsageStats">"Hiermee kunnen verzamelde gebruiksstatistieken van een component worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Tik twee keer voor zoomregeling"</string>
+ <string name="gadget_host_error_inflating">"Fout bij uitbreiden van widget"</string>
+ <string name="ime_action_go">"Ga"</string>
+ <string name="ime_action_search">"Zoeken"</string>
+ <string name="ime_action_send">"Verzenden"</string>
+ <string name="ime_action_next">"Volgende"</string>
+ <string name="ime_action_done">"Gereed"</string>
+ <string name="ime_action_default">"Uitvoeren"</string>
+ <string name="dial_number_using">"Nummer bellen"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Contact maken"\n"met <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="accessibility_compound_button_selected">"aangevinkt"</string>
+ <string name="accessibility_compound_button_unselected">"niet aangevinkt"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a33e94e..3f7921d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -15,695 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"&lt;bez nazwy&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Brak numeru telefonu)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Nieznany)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Poczta głosowa"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problem z połączeniem lub błędny kod MMI."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Usługa była włączona."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Usługa została włączona dla:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Usługa została wyłączona."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Rejestracja powiodła się."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Wymazywanie zakończone pomyślnie."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Błędne hasło."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI zakończone."</string>
- <string name="badPin" msgid="5085454289896032547">"Wprowadzony stary kod PIN jest nieprawidłowy."</string>
- <string name="badPuk" msgid="5702522162746042460">"Wprowadzony kod PUK jest nieprawidłowy."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Wprowadzone kody PIN nie sÄ… identyczne."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Wpisz kod PIN o długości od 4 do 8 cyfr."</string>
- <string name="needPuk" msgid="919668385956251611">"Karta SIM jest zablokowana kodem PUK. Wprowadź kod PUK, aby odblokować kartę."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Wprowadź kod PUK2, aby odblokować kartę SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Identyfikator rozmówcy przy połączeniach przychodzących"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Identyfikator rozmówcy przy połączeniach wychodzących"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Przekierowania połączeń"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Połączenia oczekujące"</string>
- <string name="BaMmi" msgid="455193067926770581">"Blokada dzwonienia"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Zmiana hasła"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Zmiana kodu PIN"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"Numer telefonu, z którego wykonywane jest połączenie, widoczny"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"Numer telefonujący zastrzeżony"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"Połączenie dla trzech abonentów"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"Odrzucanie niepożądanych, irytujących połączeń"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Dostarczanie numeru telefonujÄ…cego"</string>
- <string name="DndMmi" msgid="1265478932418334331">"Nie przeszkadzać"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Identyfikator rozmówcy ustawiony jest domyÅ›lnie na „zastrzeżonyâ€. NastÄ™pne poÅ‚Ä…czenie: zastrzeżony"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Identyfikator rozmówcy ustawiony jest domyÅ›lnie na „zastrzeżonyâ€. NastÄ™pne poÅ‚Ä…czenie: nie zastrzeżony"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Identyfikator rozmówcy ustawiony jest domyÅ›lnie na „nie zastrzeżonyâ€. NastÄ™pne poÅ‚Ä…czenie: zastrzeżony"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Identyfikator rozmówcy ustawiony jest domyÅ›lnie na „nie zastrzeżonyâ€. NastÄ™pne poÅ‚Ä…czenie: nie zastrzeżony"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Usługa nie jest świadczona."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Nie można zmienić ustawienia identyfikatora rozmówcy."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Zmieniono ograniczenie dostępu"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Usługa transmisji danych jest zablokowana."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Usługa połączeń alarmowych jest zablokowana."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Usługa głosowa/SMS jest zablokowana."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Wszystkie usługi głosowe/SMS są zablokowane."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"GÅ‚os"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Dane"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAKS"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Dane asynchroniczne"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synchronizacja"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pakiet"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Wskaźnik roamingu włączony"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Wskaźnik roamingu wyłączony"</string>
- <string name="roamingText2" msgid="8969929049081268115">"Migający wskaźnik roamingu"</string>
- <string name="roamingText3" msgid="5148255027043943317">"W innej okolicy"</string>
- <string name="roamingText4" msgid="8808456682550796530">"Poza biurem"</string>
- <string name="roamingText5" msgid="7604063252850354350">"Roaming – preferowany system"</string>
- <string name="roamingText6" msgid="2059440825782871513">"Roaming – dostępny system"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming – partner stowarzyszony"</string>
- <string name="roamingText8" msgid="5989569778604089291">"Roaming – partner Premium"</string>
- <string name="roamingText9" msgid="7969296811355152491">"Roaming – pełna funkcjonalność usługi"</string>
- <string name="roamingText10" msgid="3992906999815316417">"Roaming – częściowa funkcjonalność usługi"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Baner roamingu włączony"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Baner roamingu wyłączony"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"Wyszukiwanie usługi"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundach"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
- <string name="fcComplete" msgid="3118848230966886575">"Wykonano kod funkcji."</string>
- <string name="fcError" msgid="3327560126588500777">"Problem z połączeniem lub nieprawidłowy kod funkcji."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Strona sieci Web zawiera błąd."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Nie można odszukać adresu URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Schemat uwierzytelniania strony nie jest obsługiwany."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Nieudane uwierzytelnianie."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Autoryzacja przez serwer proxy zakończyła się niepowodzeniem."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Nieudane połączenie z serwerem."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Nie udało się połączyć z serwerem. Spróbuj ponownie później."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Zbyt długi czas oczekiwania na połączenie z serwerem."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Strona zawiera zbyt wiele przekierowań do serwerów."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokół nie jest obsługiwany"</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Nie można ustanowić bezpiecznego połączenia."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Nie można otworzyć strony, ponieważ adres URL jest nieprawidłowy."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Nie można uzyskać dostępu do pliku."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Nie znaleziono żądanego pliku."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Zbyt wiele żądań jest przetwarzanych. Spróbuj ponownie później."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synchronizacja"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizuj"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zbyt wiele usuwanych <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"Pamięć telefonu jest pełna! Usuń niektóre pliki, aby zwolnić miejsce."</string>
- <string name="me" msgid="6545696007631404292">"Ja"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opcje telefonu"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Tryb cichy"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Włącz połączenia bezprzewodowe"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Wyłącz połączenia bezprzewodowe"</string>
- <string name="screen_lock" msgid="799094655496098153">"Blokada ekranu"</string>
- <string name="power_off" msgid="4266614107412865048">"Wyłącz"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Wyłączanie..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Telefon zostanie wyłączony"</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Brak ostatnio używanych aplikacji."</string>
- <string name="global_actions" msgid="2406416831541615258">"Opcje telefonu"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Blokada ekranu"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Wyłącz"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tryb cichy"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Dźwięk jest wyłączony"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Dźwięk jest włączony"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Tryb samolotowy"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Tryb samolotowy jest włączony"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Tryb samolotowy jest wyłączony"</string>
- <string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
- <string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Usługi płatne"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Pozwól aplikacjom na wykonywanie płatnych operacji."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Twoje wiadomości"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Czytanie i zapisywanie wiadomości SMS, e-mail i innych"</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Informacje osobiste"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Bezpośredni dostęp do kontaktów i kalendarza zapisanych w telefonie."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Twoja lokalizacja"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Monitorowanie fizycznej lokalizacji"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Połączenia sieciowe"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Pozwól aplikacjom na dostęp do różnych funkcji sieci."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Twoje konta Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Uzyskaj dostęp do dostępnych kont Google."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Sterowanie sprzętowe"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Bezpośredni dostęp do elementów sprzętowych telefonu."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Połączenia telefoniczne"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitorowanie, nagrywanie i przetwarzanie połączeń telefonicznych."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Narzędzia systemowe"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Dostęp i kontrola systemu niższego poziomu."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Narzędzia programistyczne"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funkcje potrzebne jedynie programistom"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Pamięć"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"Dostęp do karty SD."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"wyłączanie lub zmienianie paska stanu"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Pozwala aplikacjom na wyłączenie paska stanu lub dodawanie i usuwanie ikon systemowych."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"rozwijanie/zwijanie paska stanu"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Pozwala aplikacji na rozwijanie lub zwijanie paska stanu."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"przechwytywanie połączeń wychodzących"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Pozwala aplikacji na przetwarzanie połączeń wychodzących i zmianę wybieranego numeru. Szkodliwe aplikacje mogą monitorować, przekierowywać lub blokować połączenia wychodzące."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"odbieranie wiadomości SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Pozwala aplikacjom na odbieranie i przetwarzanie wiadomości SMS. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez wyświetlania ich użytkownikowi."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"odbieranie wiadomości MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Pozwala aplikacji na odbieranie i przetwarzanie wiadomości MMS. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez pokazywania ich użytkownikowi."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"wysyłanie wiadomości SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Pozwól aplikacjom na wysyłanie wiadomości SMS. Szkodliwe aplikacje mogą generować koszty, wysyłając wiadomości bez wiedzy użytkownika."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"czytanie wiadomości SMS lub MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Pozwala aplikacji na czytanie wiadomości SMS zapisanych w telefonie lub na karcie SIM. Szkodliwe aplikacje mogą czytać poufne wiadomości."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"edytowanie wiadomości SMS lub MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Pozwala aplikacji na zapisywanie wiadomości SMS przechowywanych w telefonie lub na karcie SIM. Szkodliwe aplikacje mogą usunąć wiadomości."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"odbieranie WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Pozwala aplikacjom na odbieranie i przetwarzanie wiadomości WAP. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez wyświetlania ich użytkownikowi."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"pobieranie uruchomionych aplikacji"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Umożliwia aplikacji pobieranie informacji na temat obecnie i ostatnio uruchomionych zadań. Może pozwolić szkodliwym aplikacjom na uzyskanie prywatnych informacji na temat innych aplikacji."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"zmienianie porzÄ…dku uruchomionych aplikacji"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Pozwala aplikacji na przenoszenie zadań z tła na pierwszy plan. Szkodliwe aplikacje mogą wymusić działanie pierwszoplanowe bez kontroli użytkownika."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"włączenie debugowania aplikacji"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Szkodliwe aplikacje mogą to wykorzystać do wyłączenia innych programów."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmienianie ustawień interfejsu użytkownika"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Pozwala aplikacji zmieniać bieżącą konfigurację, na przykład lokalny lub globalny rozmiar czcionki."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"resetowanie innych aplikacji"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Pozwala aplikacji na wymuszenie ponownego uruchomienia innych aplikacji."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"wymuszanie zamknięcia aplikacji"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Pozwala aplikacji na wymuszenie zamknięcia i cofnięcia dowolnej operacji działającej na pierwszym planie. Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"pobieranie informacji o wewnętrznym stanie systemu"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Pozwala aplikacjom na pobieranie informacji o wewnętrznym stanie systemu. Szkodliwe aplikacje mogą pobrać szeroką gamę osobistych i zabezpieczonych informacji, które normalnie nie powinny im być nigdy potrzebne."</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"częściowe wyłączenie"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"Przełącza menedżera aktywności w stan wyłączenia. Nie wykonuje pełnego wyłączenia."</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zapobieganie przełączaniu aplikacji"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Zapobiega przełączaniu aplikacji na inną przez użytkownika."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"monitorowanie i kontrolowanie wszystkich uruchamianych aplikacji"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Pozwala aplikacji na monitorowanie i kontrolowanie sposobu, w jaki w systemie uruchamiane są różne działania. Szkodliwe aplikacje mogą całkowicie przejąć system. Te uprawnienia potrzebne są tylko programistom, nigdy w przypadku normalnego wykorzystywania telefonu."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"wysyłanie transmisji informującej o usuniętym pakiecie"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Pozwala aplikacji na wysyłanie powiadomienia, że pakiet aplikacji został usunięty. Szkodliwe aplikacje mogą z niego skorzystać w celu wyłączania innych działających aplikacji."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"wysyłanie transmisji otrzymanych w wiadomości SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Pozwala aplikacji na wysyłanie powiadomienia, że została odebrana wiadomość SMS. Szkodliwe aplikacje mogą to wykorzystać do fałszowania przychodzących wiadomości SMS."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"wysyłanie transmisji informującej o otrzymaniu wiadomości WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Pozwala aplikacji na nadanie powiadomienia o otrzymaniu wiadomości WAP PUSH. Szkodliwe aplikacje mogą to wykorzystać do fałszowania potwierdzenia odbioru wiadomości MMS lub do niezauważalnego podmieniania zawartości dowolnej strony internetowej jej szkodliwymi wariantami."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ograniczanie liczby uruchomionych procesów"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Pozwala aplikacji na kontrolowanie maksymalnej liczby uruchamianych procesów. Nigdy nie wykorzystywane przez normalne aplikacje."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"zamykanie wszystkich aplikacji działających w tle"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Pozwala aplikacji na kontrolowanie, czy czynności są zawsze kończone, kiedy zaczynają działać w tle. Nigdy nie jest potrzebne normalnym aplikacjom."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"zmienianie statystyk dotyczÄ…cych baterii"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Pozwala na zmianÄ™ zebranych statystyk dotyczÄ…cych baterii. Nie do wykorzystania przez normalne aplikacje."</string>
- <string name="permlab_backup" msgid="470013022865453920">"kontrolowanie tworzenia i przywracania kopii zapasowych systemu"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"Umożliwia aplikacji kontrolowanie mechanizmu tworzenia i przywracania kopii zapasowych systemu. Nie jest przeznaczone do użytku dla zwykłych aplikacji."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"wyświetlanie nieuwierzytelnionych okien"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Pozwala na tworzenie okien, które przeznaczone są do wykorzystania przez wewnętrzny interfejs użytkownika systemu. Nie do wykorzystania przez normalne aplikacje."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"wyświetlanie ostrzeżeń systemowych"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Pozwala aplikacji na pokazywanie okien alarmów systemowych. Szkodliwe aplikacje mogą przejąć kontrolę nad całym ekranem telefonu."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"zmienianie ogólnej prędkości animacji"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Pozwala aplikacji na zmianę ogólnej prędkości animacji (szybsze lub wolniejsze animacje) w dowolnym momencie."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"zarzÄ…dzanie tokenami aplikacji"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Pozwala aplikacjom na tworzenie własnych tokenów i zarządzanie nimi z pominięciem zwykłego porządku warstw. Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"naciskanie klawiszy oraz przycisków sterujących"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Pozwala aplikacjom na dostarczanie własnych zdarzeń wprowadzania danych (naciśnięcie klawisza itp.) do innych aplikacji. Szkodliwe aplikacje mogą to wykorzystać do przejęcia kontroli nad telefonem."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"zapamiętywanie wpisywanych znaków oraz wykonywanych czynności"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Pozwala aplikacjom na śledzenie naciskanych klawiszy, nawet podczas pracy z innym programem (na przykład podczas wpisywania hasła). Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"tworzenie powiązania z metodą wejściową"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu metody wejściowej. To uprawnienie nie powinno być nigdy wymagane przez zwykłe aplikacje."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"zmienianie orientacji ekranu"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Pozwala aplikacji na zmianę orientacji ekranu w dowolnym momencie. Nigdy nie powinno być potrzeby stosowania w normalnych aplikacjach."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"wysyłanie sygnałów systemu Linux do aplikacji"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Pozwala aplikacjom żądać, aby dostarczany sygnał był wysyłany do wszystkich trwających procesów."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"sprawianie, że aplikacja jest cały czas uruchomiona"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Dzięki temu uprawnieniu część elementów aplikacji może być trwała, przez co system nie może ich wykorzystać do innych aplikacji."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"usuwanie aplikacji"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Pozwala aplikacjom na usuwanie pakietów systemu Android. Szkodliwe aplikacje mogą wykorzystać to do usuwania ważnych aplikacji."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"usuwanie danych innych aplikacji"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Pozwala aplikacji na czyszczenie danych użytkowników."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"usuwanie pamięci podręcznej innych aplikacji"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Pozwala aplikacji na usuwanie plików z pamięci podręcznej."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"mierzenie rozmiaru pamięci aplikacji"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Pozwala aplikacji na pobieranie własnego kodu, danych oraz rozmiarów pamięci podręcznej"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"bezpośrednie instalowanie aplikacji"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Pozwala aplikacji na instalowanie nowych lub zaktualizowanych pakietów systemu Android. Szkodliwe aplikacje mogą to wykorzystać, aby dodać nowe aplikacje z arbitralnie nadanymi rozległymi uprawnieniami."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"usuwanie wszystkich danych aplikacji z pamięci podręcznej"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Pozwala aplikacji na zwalnianie pamięci telefonu przez usuwanie plików z katalogu pamięci podręcznej aplikacji. Dostęp jest bardzo ograniczony, z reguły do procesów systemu."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"czytanie plików dziennika systemu"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Umożliwia aplikacji czytanie różnych plików dziennika systemowego. Pozwala to na uzyskanie ogólnych informacji o czynnościach wykonywanych w telefonie, ale bez ujawniania danych osobowych lub osobistych informacji."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Pozwala aplikacji na czytanie i zapisywanie we wszystkich zasobach posiadanych przez diagnozowaną grupę, jak na przykład pliki w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane TYLKO w celach diagnozowania sprzętu przez producenta lub operatora."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"włączanie lub wyłączanie składników aplikacji"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Pozwala aplikacji na włączenie lub wyłączenie składnika innej aplikacji. Szkodliwe aplikacje mogą wykorzystać to uprawnienie do wyłączenia ważnych funkcji telefonu. Przy włączaniu uprawnienia należy zachować ostrożność, ponieważ istnieje możliwość wprowadzenia składników aplikacji w stan nieużywalności, niespójności lub niestabilności."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"ustawianie preferowanych aplikacji"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Umożliwia aplikacji zmianę preferowanych programów użytkownika. Może to pozwolić szkodliwym aplikacjom na niezauważalną podmianę uruchamianych programów, aby zbierać prywatne dane użytkownika."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modyfikowanie ogólnych ustawień systemu"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Pozwala aplikacji na zmianę danych ustawień systemowych. Szkodliwe aplikacje mogą uszkodzić konfigurację systemu."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modyfikowanie ustawień systemu dotyczących zabezpieczeń"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Pozwala aplikacji na modyfikowanie danych ustawień zabezpieczeń systemu. To uprawnienie nie jest wykorzystywane przez normalne aplikacje."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"zmienianie mapy usług Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Pozwala aplikacji na modyfikowanie mapy usług Google. Nie wykorzystywane przez normalne aplikacje."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"automatyczne uruchamianie podczas uruchamiania urzÄ…dzenia"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Pozwala aplikacji na samoczynne uruchamianie zaraz po zakończeniu uruchamiania systemu. Może to spowodować, że telefon będzie się dłużej uruchamiał oraz może ogólnie spowolnić działanie urządzenia, ponieważ aplikacja będzie cały czas uruchomiona."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"wysyłanie transmisji trwałej"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Pozwala aplikacji na wysyłanie transmisji trwałych, które pozostają aktywne po zakończeniu połączenia. Szkodliwe aplikacje mogą spowolnić lub zdestabilizować telefon, przez wymuszenie zbyt dużego zużycia pamięci."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"czytanie danych kontaktów"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Pozwala aplikacji na czytanie wszystkich danych kontaktowych (adresowych) zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby wysyłać dane użytkownika do innych ludzi."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"zapisywanie danych kontaktowych"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Pozwala aplikacji na zmianę danych kontaktowych (adresowych) zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby usunąć lub zmienić dane kontaktowe."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"zapisywanie danych właściciela"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Pozwala aplikacji na zmianę danych właściciela zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby wymazać lub zmienić dane właściciela."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"czytanie danych właściciela"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Pozwala aplikacji na czytanie danych właściciela zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać do odczytania danych właściciela."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"czytanie danych kalendarza"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Pozwala aplikacji na odczytywanie wszystkich wydarzeń z kalendarza, zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać do rozsyłania wydarzeń z kalendarza do innych ludzi."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"zapisywanie danych kalendarza"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Pozwala aplikacji na zmianę wydarzeń z kalendarza zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby usunąć lub zmienić dane w kalendarzu."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"udawanie źródeł położenia dla testów"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Tworzenie pozorowanych źródeł ustalania położenia dla testów. Szkodliwe aplikacje mogą to wykorzystać, aby zastąpić prawdziwe położenie i/lub stan zwracany przez prawdziwe źródła, takie jak GPS lub dostawcy usługi sieciowej."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"dostęp do dodatkowych poleceń dostawcy informacji o lokalizacji"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Dostęp do dodatkowych poleceń dostawcy informacji o lokalizacji. Szkodliwe aplikacje mogą go wykorzystać, aby wpływać na działanie urządzenia GPS lub innych źródeł ustalania lokalizacji."</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"uprawnienia do instalowania dostawcy danych o lokalizacji"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Utwórz sztuczne źródła danych o lokalizacji na potrzeby testowania. Złośliwe aplikacje mogą korzystać z tej opcji w celu zastępowania danych o lokalizacji i/lub stanie zwracanych przez prawdziwe źródła danych o lokalizacji, takie jak odbiornik GPS lub dostawcy sieciowi, bądź monitorowania i zgłaszania lokalizacji do źródeł zewnętrznych."</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"dokładna lokalizacja (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Uzyskiwanie dostępu do dokładnych źródeł ustalania położenia w telefonie, takich jak system GPS, tam, gdzie są one dostępne. Szkodliwe aplikacje mogą to wykorzystać do określenia położenia użytkownika oraz mogą zużywać więcej energii baterii."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"przybliżone ustalanie lokalizacji (oparte o sieć)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Dostęp do źródeł, takich jak bazy danych sieci komórkowych, jeśli są dostępne, które pozwalają określić przybliżoną lokalizację telefonu. Szkodliwe aplikacje mogą go wykorzystać do określenia, gdzie w przybliżeniu znajduje się użytkownik."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"dostęp do usługi SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Pozwala aplikacji na wykorzystanie funkcji niskiego poziomu usługi SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"czytanie bufora ramki"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Pozwala aplikacji na wykorzystanie odczytanej zawartości bufora ramki."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"zmienianie ustawień audio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Pozwala aplikacjom na zmianę globalnych ustawień audio, takich jak głośność i routing."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"nagrywanie dźwięku"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Pozwala aplikacji na dostęp do ścieżki nagrywania dźwięku."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"robienie zdjęć"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Pozwala aplikacji na wykonywanie zdjęć za pomocą aparatu. Dzięki temu może ona pobierać zdjęcia z aparatu w dowolnym momencie."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"wyłączenie telefonu na stałe"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Pozwala aplikacji na wyłączenie całego telefonu na stałe. Jest to bardzo niebezpieczne."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"wymuszanie ponownego uruchomienia telefonu"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Pozwala aplikacji na wymuszenie ponownego uruchomienia telefonu."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"podłączanie i odłączanie systemów plików"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Pozwala aplikacjom na podłączanie i odłączanie systemów plików w pamięciach przenośnych."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatowanie pamięci zewnętrznej"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Zezwala aplikacji na formatowanie wymiennych nośników."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"kontrolowanie wibracji"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Pozwala aplikacjom na kontrolowanie wibracji."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolowanie latarki"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Pozwala aplikacji kontrolować latarkę."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"testowanie sprzętu"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Pozwala aplikacji na kontrolowanie różnych urządzeń peryferyjnych w celu testowania sprzętu."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"bezpośrednie wybieranie numerów telefonów"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Pozwala aplikacjom na dzwonienie pod numery telefonów bez interwencji użytkownika. Szkodliwe aplikacje mogą powodować występowanie niespodziewanych połączeń na rachunku telefonicznym. Należy zauważyć, że aplikacje nie mogą dzwonić na numery alarmowe."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"bezpośrednie wybieranie dowolnych numerów telefonu"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Pozwala aplikacji dzwonić na dowolny numer telefonu, włącznie z numerami alarmowymi, bez interwencji użytkownika. Szkodliwe aplikacje mogą wykonywać niepotrzebne i nielegalne połączenia z usługami alarmowymi."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontrolowanie powiadomień o aktualizacjach lokalizacji"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Pozwala włączyć/wyłączyć powiadomienia o aktualizacjach lokalizacji przez sieć bezprzewodową. Nie wykorzystywane przez normalne aplikacje."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"dostęp do właściwości usługi rezerwacji"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Pozwala na dostęp z uprawnieniami do odczytu/zapisu do właściwości przesłanych przez usługę rezerwacji. Nie wykorzystywane przez normalne aplikacje."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"wybieranie widżetów"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Zezwala aplikacjom na wskazywanie systemowi, które widżety mogą być używane przez inne aplikacje. Z użyciem tego pozwolenia aplikacje mogą udzielać dostępu do danych osobistych innym aplikacjom. Nie jest ono przeznaczone dla zwykłych aplikacji."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"zmiana stanu telefonu"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Pozwala aplikacji na kontrolowanie funkcji telefonu w urządzeniu. Aplikacja z tymi uprawnieniami może zmieniać, włączać i wyłączać sieci bezprzewodowe itp. bez informowania użytkownika."</string>
- <string name="permlab_readPhoneState" msgid="2326172951448691631">"odczytywanie stanu i informacji o telefonie"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"Umożliwia aplikacji dostęp do funkcji telefonu w tym urządzeniu. Aplikacja z takim pozwoleniem może określić numer telefonu i numer seryjny tego telefonu, czy aktywne jest połączenie, numer, z którym nawiązane jest połączenie itp."</string>
- <string name="permlab_wakeLock" msgid="573480187941496130">"zapobieganie przejściu telefonu w stan uśpienia"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Pozwala aplikacji na zapobieganie przejściu telefonu w stan uśpienia."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"włączanie lub wyłączanie telefonu"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Pozwala aplikacji włączać i wyłączać telefon."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"uruchamianie w trybie testu fabrycznego"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Uruchom jako niskopoziomowy test producenta, pozwalając na całkowity dostęp do elementów sprzętowych telefonu. Dostępne tylko jeśli telefon działa w trybie testu producenta."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"ustawianie tapety"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Pozwala aplikacji na ustawianie tapety systemu."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"ustawianie wskazówek dotyczących rozmiaru tapety"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Pozwala aplikacji na ustawianie wskazówek dotyczących rozmiaru tapety."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"resetowanie systemu do ustawień fabrycznych"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Pozwala aplikacji na całkowite zresetowanie systemu do ustawień fabrycznych, z wymazaniem wszystkich danych, konfiguracji oraz zainstalowanych aplikacji."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"ustawianie strefy czasowej"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Pozwala aplikacji na zmianÄ™ strefy czasowej w telefonie."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"wykrywanie znanych kont"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Pozwala aplikacji na pobranie listy kont zapisanych w telefonie."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"wyświetlanie stanu sieci"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Pozwala aplikacji na wyświetlanie stanu wszystkich sieci."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"pełen dostęp do internetu"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Pozwala aplikacji na tworzenie gniazd sieciowych."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"zapisywanie ustawień nazwy punktu dostępowego (APN, Access Point Name)"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Pozwala aplikacji na zmianę ustawień APN, takich jak serwer proxy oraz port dowolnego APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"zmienianie połączeń sieci"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Pozwala aplikacji na zmianę stanu połączeń sieciowych."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"zmienianie ustawienia używania danych w tle"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Zezwala aplikacji na zmianę ustawień użycia danych w tle."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"wyświetlanie stanu Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Pozwala aplikacji na wyświetlanie informacji o stanie Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"zmiana stanu Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Pozwala aplikacji na łączenie i rozłączanie z punktami dostępowymi Wi-Fi oraz na dokonywanie zmian skonfigurowanych sieci Wi-Fi."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"zezwolenie na odbiór grupowych połączeń Wi-Fi"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Umożliwia aplikacji odbieranie pakietów nieskierowanych bezpośrednio do Twojego urządzenia. Może to być przydatne przy wykrywaniu usług oferowanych w okolicy. Powoduje większe zapotrzebowanie na energię niż w trybie innym niż grupowy."</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administrowanie Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Pozwala aplikacji na konfigurowanie lokalnego telefonu Bluetooth, wyszukiwanie urządzeń zdalnych i łączenie się z nimi."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"tworzenie połączeń Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Pozwala aplikacji na wyświetlanie konfiguracji lokalnego telefonu Bluetooth oraz na tworzenie i akceptowanie połączeń ze sparowanymi urządzeniami."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"wyłączanie blokady klawiatury"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Pozwala aplikacji na wyłączenie blokady klawiatury i wszystkich związanych z tym haseł zabezpieczających. Typowym przykładem takiego działania jest wyłączanie blokady klawiatury, gdy pojawia się połączenie przychodzące, a następnie ponowne jej włączanie po zakończeniu połączenia."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"czytanie ustawień synchronizowania"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Pozwala aplikacji na czytanie ustawień synchronizacji, takich jak informacje, czy synchronizacja kontaktów jest włączona."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"zapisywanie ustawień synchronizowania"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Pozwala aplikacji na zmianę ustawień synchronizowania, takich jak ustalenie, czy synchronizacja dla kontaktów ma być włączona."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"czytanie statystyk dotyczÄ…cych synchronizowania"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Pozwala aplikacji na czytanie statystyk synchronizowania, np. historii przeprowadzonych synchronizacji."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"czytanie subskrybowanych źródeł"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Pozwala aplikacjom na pobieranie informacji szczegółowych na temat obecnie zsynchronizowanych źródeł."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"zapisywanie subskrybowanych źródeł"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Umożliwia aplikacji zmianę obecnie zsynchronizowanych źródeł. Może to pozwolić szkodliwej aplikacji na zmianę zsynchronizowanych źródeł."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"odczytywanie słownika zdefiniowanego przez użytkownika"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Zezwala aplikacji na odczytywanie wszelkich prywatnych słów, nazw i wyrażeń zapisanych przez użytkownika w swoim słowniku."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"zapisywanie w słowniku zdefiniowanym przez użytkownika"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Zezwala aplikacjom na zapisywanie nowych słów w słowniku użytkownika."</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"modyfikowanie/usuwanie zawartości karty SD"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"Umożliwia aplikacji zapis na karcie SD."</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"&lt;bez nazwy&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Brak numeru telefonu)"</string>
+ <string name="unknownName">"(Nieznany)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Poczta głosowa"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problem z połączeniem lub błędny kod MMI."</string>
+ <string name="serviceEnabled">"Usługa była włączona."</string>
+ <string name="serviceEnabledFor">"Usługa została włączona dla:"</string>
+ <string name="serviceDisabled">"Usługa została wyłączona."</string>
+ <string name="serviceRegistered">"Rejestracja powiodła się."</string>
+ <string name="serviceErased">"Wymazywanie zakończone pomyślnie."</string>
+ <string name="passwordIncorrect">"Błędne hasło."</string>
+ <string name="mmiComplete">"MMI zakończone."</string>
+ <string name="badPin">"Wprowadzony stary kod PIN jest nieprawidłowy."</string>
+ <string name="badPuk">"Wprowadzony kod PUK jest nieprawidłowy."</string>
+ <string name="mismatchPin">"Wprowadzone kody PIN nie sÄ… identyczne."</string>
+ <string name="invalidPin">"Wpisz kod PIN o długości od 4 do 8 cyfr."</string>
+ <string name="needPuk">"Karta SIM jest zablokowana kodem PUK. Wprowadź kod PUK, aby odblokować kartę."</string>
+ <string name="needPuk2">"Wprowadź kod PUK2, aby odblokować kartę SIM."</string>
+ <string name="ClipMmi">"Identyfikator rozmówcy przy połączeniach przychodzących"</string>
+ <string name="ClirMmi">"Identyfikator rozmówcy przy połączeniach wychodzących"</string>
+ <string name="CfMmi">"Przekierowania połączeń"</string>
+ <string name="CwMmi">"Połączenia oczekujące"</string>
+ <string name="BaMmi">"Blokada dzwonienia"</string>
+ <string name="PwdMmi">"Zmiana hasła"</string>
+ <string name="PinMmi">"Zmiana kodu PIN"</string>
+ <string name="CnipMmi">"Numer telefonu, z którego wykonywane jest połączenie, widoczny"</string>
+ <string name="CnirMmi">"Numer telefonujący zastrzeżony"</string>
+ <string name="ThreeWCMmi">"Połączenie dla trzech abonentów"</string>
+ <string name="RuacMmi">"Odrzucanie niepożądanych, irytujących połączeń"</string>
+ <string name="CndMmi">"Dostarczanie numeru telefonujÄ…cego"</string>
+ <string name="DndMmi">"Nie przeszkadzać"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Identyfikator rozmówcy ustawiony jest domyÅ›lnie na „zastrzeżonyâ€. NastÄ™pne poÅ‚Ä…czenie: zastrzeżony"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Identyfikator rozmówcy ustawiony jest domyÅ›lnie na „zastrzeżonyâ€. NastÄ™pne poÅ‚Ä…czenie: nie zastrzeżony"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Identyfikator rozmówcy ustawiony jest domyÅ›lnie na „nie zastrzeżonyâ€. NastÄ™pne poÅ‚Ä…czenie: zastrzeżony"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Identyfikator rozmówcy ustawiony jest domyÅ›lnie na „nie zastrzeżonyâ€. NastÄ™pne poÅ‚Ä…czenie: nie zastrzeżony"</string>
+ <string name="serviceNotProvisioned">"Usługa nie jest świadczona."</string>
+ <string name="CLIRPermanent">"Nie można zmienić ustawienia identyfikatora rozmówcy."</string>
+ <string name="RestrictedChangedTitle">"Zmieniono ograniczenie dostępu"</string>
+ <string name="RestrictedOnData">"Usługa transmisji danych jest zablokowana."</string>
+ <string name="RestrictedOnEmergency">"Usługa połączeń alarmowych jest zablokowana."</string>
+ <string name="RestrictedOnNormal">"Usługa głosowa/SMS jest zablokowana."</string>
+ <string name="RestrictedOnAll">"Wszystkie usługi głosowe/SMS są zablokowane."</string>
+ <string name="serviceClassVoice">"GÅ‚os"</string>
+ <string name="serviceClassData">"Dane"</string>
+ <string name="serviceClassFAX">"FAKS"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Dane asynchroniczne"</string>
+ <string name="serviceClassDataSync">"Synchronizacja"</string>
+ <string name="serviceClassPacket">"Pakiet"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="roamingText0">"Wskaźnik roamingu włączony"</string>
+ <string name="roamingText1">"Wskaźnik roamingu wyłączony"</string>
+ <string name="roamingText2">"Migający wskaźnik roamingu"</string>
+ <string name="roamingText3">"W innej okolicy"</string>
+ <string name="roamingText4">"Poza biurem"</string>
+ <string name="roamingText5">"Roaming – preferowany system"</string>
+ <string name="roamingText6">"Roaming – dostępny system"</string>
+ <string name="roamingText7">"Roaming – partner stowarzyszony"</string>
+ <string name="roamingText8">"Roaming – partner Premium"</string>
+ <string name="roamingText9">"Roaming – pełna funkcjonalność usługi"</string>
+ <string name="roamingText10">"Roaming – częściowa funkcjonalność usługi"</string>
+ <string name="roamingText11">"Baner roamingu włączony"</string>
+ <string name="roamingText12">"Baner roamingu wyłączony"</string>
+ <string name="roamingTextSearching">"Wyszukiwanie usługi"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundach"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
+ <string name="fcComplete">"Wykonano kod funkcji."</string>
+ <string name="fcError">"Problem z połączeniem lub nieprawidłowy kod funkcji."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Strona sieci Web zawiera błąd."</string>
+ <string name="httpErrorLookup">"Nie można odszukać adresu URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Schemat uwierzytelniania strony nie jest obsługiwany."</string>
+ <string name="httpErrorAuth">"Nieudane uwierzytelnianie."</string>
+ <string name="httpErrorProxyAuth">"Autoryzacja przez serwer proxy zakończyła się niepowodzeniem."</string>
+ <string name="httpErrorConnect">"Nieudane połączenie z serwerem."</string>
+ <string name="httpErrorIO">"Nie udało się połączyć z serwerem. Spróbuj ponownie później."</string>
+ <string name="httpErrorTimeout">"Zbyt długi czas oczekiwania na połączenie z serwerem."</string>
+ <string name="httpErrorRedirectLoop">"Strona zawiera zbyt wiele przekierowań do serwerów."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokół nie jest obsługiwany"</string>
+ <string name="httpErrorFailedSslHandshake">"Nie można ustanowić bezpiecznego połączenia."</string>
+ <string name="httpErrorBadUrl">"Nie można otworzyć strony, ponieważ adres URL jest nieprawidłowy."</string>
+ <string name="httpErrorFile">"Nie można uzyskać dostępu do pliku."</string>
+ <string name="httpErrorFileNotFound">"Nie znaleziono żądanego pliku."</string>
+ <string name="httpErrorTooManyRequests">"Zbyt wiele żądań jest przetwarzanych. Spróbuj ponownie później."</string>
+ <string name="contentServiceSync">"Synchronizacja"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchronizuj"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Zbyt wiele usuwanych <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Pamięć telefonu jest pełna! Usuń niektóre pliki, aby zwolnić miejsce."</string>
+ <string name="me">"Ja"</string>
+ <string name="power_dialog">"Opcje telefonu"</string>
+ <string name="silent_mode">"Tryb cichy"</string>
+ <string name="turn_on_radio">"Włącz połączenia bezprzewodowe"</string>
+ <string name="turn_off_radio">"Wyłącz połączenia bezprzewodowe"</string>
+ <string name="screen_lock">"Blokada ekranu"</string>
+ <string name="power_off">"Wyłącz"</string>
+ <string name="shutdown_progress">"Wyłączanie..."</string>
+ <string name="shutdown_confirm">"Telefon zostanie wyłączony"</string>
+ <string name="no_recent_tasks">"Brak ostatnio używanych aplikacji."</string>
+ <string name="global_actions">"Opcje telefonu"</string>
+ <string name="global_action_lock">"Blokada ekranu"</string>
+ <string name="global_action_power_off">"Wyłącz"</string>
+ <string name="global_action_toggle_silent_mode">"Tryb cichy"</string>
+ <string name="global_action_silent_mode_on_status">"Dźwięk jest wyłączony"</string>
+ <string name="global_action_silent_mode_off_status">"Dźwięk jest włączony"</string>
+ <string name="global_actions_toggle_airplane_mode">"Tryb samolotowy"</string>
+ <string name="global_actions_airplane_mode_on_status">"Tryb samolotowy jest włączony"</string>
+ <string name="global_actions_airplane_mode_off_status">"Tryb samolotowy jest wyłączony"</string>
+ <string name="safeMode">"Tryb awaryjny"</string>
+ <string name="android_system_label">"System Android"</string>
+ <string name="permgrouplab_costMoney">"Usługi płatne"</string>
+ <string name="permgroupdesc_costMoney">"Pozwól aplikacjom na wykonywanie płatnych operacji."</string>
+ <string name="permgrouplab_messages">"Twoje wiadomości"</string>
+ <string name="permgroupdesc_messages">"Czytanie i zapisywanie wiadomości SMS, e-mail i innych"</string>
+ <string name="permgrouplab_personalInfo">"Informacje osobiste"</string>
+ <string name="permgroupdesc_personalInfo">"Bezpośredni dostęp do kontaktów i kalendarza zapisanych w telefonie."</string>
+ <string name="permgrouplab_location">"Twoja lokalizacja"</string>
+ <string name="permgroupdesc_location">"Monitorowanie fizycznej lokalizacji"</string>
+ <string name="permgrouplab_network">"Połączenia sieciowe"</string>
+ <string name="permgroupdesc_network">"Pozwól aplikacjom na dostęp do różnych funkcji sieci."</string>
+ <string name="permgrouplab_accounts">"Twoje konta Google"</string>
+ <string name="permgroupdesc_accounts">"Uzyskaj dostęp do dostępnych kont Google."</string>
+ <string name="permgrouplab_hardwareControls">"Sterowanie sprzętowe"</string>
+ <string name="permgroupdesc_hardwareControls">"Bezpośredni dostęp do elementów sprzętowych telefonu."</string>
+ <string name="permgrouplab_phoneCalls">"Połączenia telefoniczne"</string>
+ <string name="permgroupdesc_phoneCalls">"Monitorowanie, nagrywanie i przetwarzanie połączeń telefonicznych."</string>
+ <string name="permgrouplab_systemTools">"Narzędzia systemowe"</string>
+ <string name="permgroupdesc_systemTools">"Dostęp i kontrola systemu niższego poziomu."</string>
+ <string name="permgrouplab_developmentTools">"Narzędzia programistyczne"</string>
+ <string name="permgroupdesc_developmentTools">"Funkcje potrzebne jedynie programistom"</string>
+ <string name="permgrouplab_storage">"Pamięć"</string>
+ <string name="permgroupdesc_storage">"Dostęp do karty SD."</string>
+ <string name="permlab_statusBar">"wyłączanie lub zmienianie paska stanu"</string>
+ <string name="permdesc_statusBar">"Pozwala aplikacjom na wyłączenie paska stanu lub dodawanie i usuwanie ikon systemowych."</string>
+ <string name="permlab_expandStatusBar">"rozwijanie/zwijanie paska stanu"</string>
+ <string name="permdesc_expandStatusBar">"Pozwala aplikacji na rozwijanie lub zwijanie paska stanu."</string>
+ <string name="permlab_processOutgoingCalls">"przechwytywanie połączeń wychodzących"</string>
+ <string name="permdesc_processOutgoingCalls">"Pozwala aplikacji na przetwarzanie połączeń wychodzących i zmianę wybieranego numeru. Szkodliwe aplikacje mogą monitorować, przekierowywać lub blokować połączenia wychodzące."</string>
+ <string name="permlab_receiveSms">"odbieranie wiadomości SMS"</string>
+ <string name="permdesc_receiveSms">"Pozwala aplikacjom na odbieranie i przetwarzanie wiadomości SMS. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez wyświetlania ich użytkownikowi."</string>
+ <string name="permlab_receiveMms">"odbieranie wiadomości MMS"</string>
+ <string name="permdesc_receiveMms">"Pozwala aplikacji na odbieranie i przetwarzanie wiadomości MMS. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez pokazywania ich użytkownikowi."</string>
+ <string name="permlab_sendSms">"wysyłanie wiadomości SMS"</string>
+ <string name="permdesc_sendSms">"Pozwól aplikacjom na wysyłanie wiadomości SMS. Szkodliwe aplikacje mogą generować koszty, wysyłając wiadomości bez wiedzy użytkownika."</string>
+ <string name="permlab_readSms">"czytanie wiadomości SMS lub MMS"</string>
+ <string name="permdesc_readSms">"Pozwala aplikacji na czytanie wiadomości SMS zapisanych w telefonie lub na karcie SIM. Szkodliwe aplikacje mogą czytać poufne wiadomości."</string>
+ <string name="permlab_writeSms">"edytowanie wiadomości SMS lub MMS"</string>
+ <string name="permdesc_writeSms">"Pozwala aplikacji na zapisywanie wiadomości SMS przechowywanych w telefonie lub na karcie SIM. Szkodliwe aplikacje mogą usunąć wiadomości."</string>
+ <string name="permlab_receiveWapPush">"odbieranie WAP"</string>
+ <string name="permdesc_receiveWapPush">"Pozwala aplikacjom na odbieranie i przetwarzanie wiadomości WAP. Szkodliwe aplikacje mogą monitorować wiadomości lub usuwać je bez wyświetlania ich użytkownikowi."</string>
+ <string name="permlab_getTasks">"pobieranie uruchomionych aplikacji"</string>
+ <string name="permdesc_getTasks">"Umożliwia aplikacji pobieranie informacji na temat obecnie i ostatnio uruchomionych zadań. Może pozwolić szkodliwym aplikacjom na uzyskanie prywatnych informacji na temat innych aplikacji."</string>
+ <string name="permlab_reorderTasks">"zmienianie porzÄ…dku uruchomionych aplikacji"</string>
+ <string name="permdesc_reorderTasks">"Pozwala aplikacji na przenoszenie zadań z tła na pierwszy plan. Szkodliwe aplikacje mogą wymusić działanie pierwszoplanowe bez kontroli użytkownika."</string>
+ <string name="permlab_setDebugApp">"włączenie debugowania aplikacji"</string>
+ <string name="permdesc_setDebugApp">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Szkodliwe aplikacje mogą to wykorzystać do wyłączenia innych programów."</string>
+ <string name="permlab_changeConfiguration">"zmienianie ustawień interfejsu użytkownika"</string>
+ <string name="permdesc_changeConfiguration">"Pozwala aplikacji zmieniać bieżącą konfigurację, na przykład lokalny lub globalny rozmiar czcionki."</string>
+ <string name="permlab_restartPackages">"resetowanie innych aplikacji"</string>
+ <string name="permdesc_restartPackages">"Pozwala aplikacji na wymuszenie ponownego uruchomienia innych aplikacji."</string>
+ <string name="permlab_forceBack">"wymuszanie zamknięcia aplikacji"</string>
+ <string name="permdesc_forceBack">"Pozwala aplikacji na wymuszenie zamknięcia i cofnięcia dowolnej operacji działającej na pierwszym planie. Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
+ <string name="permlab_dump">"pobieranie informacji o wewnętrznym stanie systemu"</string>
+ <string name="permdesc_dump">"Pozwala aplikacjom na pobieranie informacji o wewnętrznym stanie systemu. Szkodliwe aplikacje mogą pobrać szeroką gamę osobistych i zabezpieczonych informacji, które normalnie nie powinny im być nigdy potrzebne."</string>
+ <string name="permlab_shutdown">"częściowe wyłączenie"</string>
+ <string name="permdesc_shutdown">"Przełącza menedżera aktywności w stan wyłączenia. Nie wykonuje pełnego wyłączenia."</string>
+ <string name="permlab_stopAppSwitches">"zapobieganie przełączaniu aplikacji"</string>
+ <string name="permdesc_stopAppSwitches">"Zapobiega przełączaniu aplikacji na inną przez użytkownika."</string>
+ <string name="permlab_runSetActivityWatcher">"monitorowanie i kontrolowanie wszystkich uruchamianych aplikacji"</string>
+ <string name="permdesc_runSetActivityWatcher">"Pozwala aplikacji na monitorowanie i kontrolowanie sposobu, w jaki w systemie uruchamiane są różne działania. Szkodliwe aplikacje mogą całkowicie przejąć system. Te uprawnienia potrzebne są tylko programistom, nigdy w przypadku normalnego wykorzystywania telefonu."</string>
+ <string name="permlab_broadcastPackageRemoved">"wysyłanie transmisji informującej o usuniętym pakiecie"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Pozwala aplikacji na wysyłanie powiadomienia, że pakiet aplikacji został usunięty. Szkodliwe aplikacje mogą z niego skorzystać w celu wyłączania innych działających aplikacji."</string>
+ <string name="permlab_broadcastSmsReceived">"wysyłanie transmisji otrzymanych w wiadomości SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Pozwala aplikacji na wysyłanie powiadomienia, że została odebrana wiadomość SMS. Szkodliwe aplikacje mogą to wykorzystać do fałszowania przychodzących wiadomości SMS."</string>
+ <string name="permlab_broadcastWapPush">"wysyłanie transmisji informującej o otrzymaniu wiadomości WAP-PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Pozwala aplikacji na nadanie powiadomienia o otrzymaniu wiadomości WAP PUSH. Szkodliwe aplikacje mogą to wykorzystać do fałszowania potwierdzenia odbioru wiadomości MMS lub do niezauważalnego podmieniania zawartości dowolnej strony internetowej jej szkodliwymi wariantami."</string>
+ <string name="permlab_setProcessLimit">"ograniczanie liczby uruchomionych procesów"</string>
+ <string name="permdesc_setProcessLimit">"Pozwala aplikacji na kontrolowanie maksymalnej liczby uruchamianych procesów. Nigdy nie wykorzystywane przez normalne aplikacje."</string>
+ <string name="permlab_setAlwaysFinish">"zamykanie wszystkich aplikacji działających w tle"</string>
+ <string name="permdesc_setAlwaysFinish">"Pozwala aplikacji na kontrolowanie, czy czynności są zawsze kończone, kiedy zaczynają działać w tle. Nigdy nie jest potrzebne normalnym aplikacjom."</string>
+ <string name="permlab_batteryStats">"zmienianie statystyk dotyczÄ…cych baterii"</string>
+ <string name="permdesc_batteryStats">"Pozwala na zmianÄ™ zebranych statystyk dotyczÄ…cych baterii. Nie do wykorzystania przez normalne aplikacje."</string>
+ <string name="permlab_backup">"kontrolowanie tworzenia i przywracania kopii zapasowych systemu"</string>
+ <string name="permdesc_backup">"Umożliwia aplikacji kontrolowanie mechanizmu tworzenia i przywracania kopii zapasowych systemu. Nie jest przeznaczone do użytku dla zwykłych aplikacji."</string>
+ <string name="permlab_internalSystemWindow">"wyświetlanie nieuwierzytelnionych okien"</string>
+ <string name="permdesc_internalSystemWindow">"Pozwala na tworzenie okien, które przeznaczone są do wykorzystania przez wewnętrzny interfejs użytkownika systemu. Nie do wykorzystania przez normalne aplikacje."</string>
+ <string name="permlab_systemAlertWindow">"wyświetlanie ostrzeżeń systemowych"</string>
+ <string name="permdesc_systemAlertWindow">"Pozwala aplikacji na pokazywanie okien alarmów systemowych. Szkodliwe aplikacje mogą przejąć kontrolę nad całym ekranem telefonu."</string>
+ <string name="permlab_setAnimationScale">"zmienianie ogólnej prędkości animacji"</string>
+ <string name="permdesc_setAnimationScale">"Pozwala aplikacji na zmianę ogólnej prędkości animacji (szybsze lub wolniejsze animacje) w dowolnym momencie."</string>
+ <string name="permlab_manageAppTokens">"zarzÄ…dzanie tokenami aplikacji"</string>
+ <string name="permdesc_manageAppTokens">"Pozwala aplikacjom na tworzenie własnych tokenów i zarządzanie nimi z pominięciem zwykłego porządku warstw. Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
+ <string name="permlab_injectEvents">"naciskanie klawiszy oraz przycisków sterujących"</string>
+ <string name="permdesc_injectEvents">"Pozwala aplikacjom na dostarczanie własnych zdarzeń wprowadzania danych (naciśnięcie klawisza itp.) do innych aplikacji. Szkodliwe aplikacje mogą to wykorzystać do przejęcia kontroli nad telefonem."</string>
+ <string name="permlab_readInputState">"zapamiętywanie wpisywanych znaków oraz wykonywanych czynności"</string>
+ <string name="permdesc_readInputState">"Pozwala aplikacjom na śledzenie naciskanych klawiszy, nawet podczas pracy z innym programem (na przykład podczas wpisywania hasła). Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
+ <string name="permlab_bindInputMethod">"tworzenie powiązania z metodą wejściową"</string>
+ <string name="permdesc_bindInputMethod">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu metody wejściowej. To uprawnienie nie powinno być nigdy wymagane przez zwykłe aplikacje."</string>
+ <string name="permlab_setOrientation">"zmienianie orientacji ekranu"</string>
+ <string name="permdesc_setOrientation">"Pozwala aplikacji na zmianę orientacji ekranu w dowolnym momencie. Nigdy nie powinno być potrzeby stosowania w normalnych aplikacjach."</string>
+ <string name="permlab_signalPersistentProcesses">"wysyłanie sygnałów systemu Linux do aplikacji"</string>
+ <string name="permdesc_signalPersistentProcesses">"Pozwala aplikacjom żądać, aby dostarczany sygnał był wysyłany do wszystkich trwających procesów."</string>
+ <string name="permlab_persistentActivity">"sprawianie, że aplikacja jest cały czas uruchomiona"</string>
+ <string name="permdesc_persistentActivity">"Dzięki temu uprawnieniu część elementów aplikacji może być trwała, przez co system nie może ich wykorzystać do innych aplikacji."</string>
+ <string name="permlab_deletePackages">"usuwanie aplikacji"</string>
+ <string name="permdesc_deletePackages">"Pozwala aplikacjom na usuwanie pakietów systemu Android. Szkodliwe aplikacje mogą wykorzystać to do usuwania ważnych aplikacji."</string>
+ <string name="permlab_clearAppUserData">"usuwanie danych innych aplikacji"</string>
+ <string name="permdesc_clearAppUserData">"Pozwala aplikacji na czyszczenie danych użytkowników."</string>
+ <string name="permlab_deleteCacheFiles">"usuwanie pamięci podręcznej innych aplikacji"</string>
+ <string name="permdesc_deleteCacheFiles">"Pozwala aplikacji na usuwanie plików z pamięci podręcznej."</string>
+ <string name="permlab_getPackageSize">"mierzenie rozmiaru pamięci aplikacji"</string>
+ <string name="permdesc_getPackageSize">"Pozwala aplikacji na pobieranie własnego kodu, danych oraz rozmiarów pamięci podręcznej"</string>
+ <string name="permlab_installPackages">"bezpośrednie instalowanie aplikacji"</string>
+ <string name="permdesc_installPackages">"Pozwala aplikacji na instalowanie nowych lub zaktualizowanych pakietów systemu Android. Szkodliwe aplikacje mogą to wykorzystać, aby dodać nowe aplikacje z arbitralnie nadanymi rozległymi uprawnieniami."</string>
+ <string name="permlab_clearAppCache">"usuwanie wszystkich danych aplikacji z pamięci podręcznej"</string>
+ <string name="permdesc_clearAppCache">"Pozwala aplikacji na zwalnianie pamięci telefonu przez usuwanie plików z katalogu pamięci podręcznej aplikacji. Dostęp jest bardzo ograniczony, z reguły do procesów systemu."</string>
+ <string name="permlab_readLogs">"czytanie plików dziennika systemu"</string>
+ <string name="permdesc_readLogs">"Umożliwia aplikacji czytanie różnych plików dziennika systemowego. Pozwala to na uzyskanie ogólnych informacji o czynnościach wykonywanych w telefonie, ale bez ujawniania danych osobowych lub osobistych informacji."</string>
+ <string name="permlab_diagnostic">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
+ <string name="permdesc_diagnostic">"Pozwala aplikacji na czytanie i zapisywanie we wszystkich zasobach posiadanych przez diagnozowaną grupę, jak na przykład pliki w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane TYLKO w celach diagnozowania sprzętu przez producenta lub operatora."</string>
+ <string name="permlab_changeComponentState">"włączanie lub wyłączanie składników aplikacji"</string>
+ <string name="permdesc_changeComponentState">"Pozwala aplikacji na włączenie lub wyłączenie składnika innej aplikacji. Szkodliwe aplikacje mogą wykorzystać to uprawnienie do wyłączenia ważnych funkcji telefonu. Przy włączaniu uprawnienia należy zachować ostrożność, ponieważ istnieje możliwość wprowadzenia składników aplikacji w stan nieużywalności, niespójności lub niestabilności."</string>
+ <string name="permlab_setPreferredApplications">"ustawianie preferowanych aplikacji"</string>
+ <string name="permdesc_setPreferredApplications">"Umożliwia aplikacji zmianę preferowanych programów użytkownika. Może to pozwolić szkodliwym aplikacjom na niezauważalną podmianę uruchamianych programów, aby zbierać prywatne dane użytkownika."</string>
+ <string name="permlab_writeSettings">"modyfikowanie ogólnych ustawień systemu"</string>
+ <string name="permdesc_writeSettings">"Pozwala aplikacji na zmianę danych ustawień systemowych. Szkodliwe aplikacje mogą uszkodzić konfigurację systemu."</string>
+ <string name="permlab_writeSecureSettings">"modyfikowanie ustawień systemu dotyczących zabezpieczeń"</string>
+ <string name="permdesc_writeSecureSettings">"Pozwala aplikacji na modyfikowanie danych ustawień zabezpieczeń systemu. To uprawnienie nie jest wykorzystywane przez normalne aplikacje."</string>
+ <string name="permlab_writeGservices">"zmienianie mapy usług Google"</string>
+ <string name="permdesc_writeGservices">"Pozwala aplikacji na modyfikowanie mapy usług Google. Nie wykorzystywane przez normalne aplikacje."</string>
+ <string name="permlab_receiveBootCompleted">"automatyczne uruchamianie podczas uruchamiania urzÄ…dzenia"</string>
+ <string name="permdesc_receiveBootCompleted">"Pozwala aplikacji na samoczynne uruchamianie zaraz po zakończeniu uruchamiania systemu. Może to spowodować, że telefon będzie się dłużej uruchamiał oraz może ogólnie spowolnić działanie urządzenia, ponieważ aplikacja będzie cały czas uruchomiona."</string>
+ <string name="permlab_broadcastSticky">"wysyłanie transmisji trwałej"</string>
+ <string name="permdesc_broadcastSticky">"Pozwala aplikacji na wysyłanie transmisji trwałych, które pozostają aktywne po zakończeniu połączenia. Szkodliwe aplikacje mogą spowolnić lub zdestabilizować telefon, przez wymuszenie zbyt dużego zużycia pamięci."</string>
+ <string name="permlab_readContacts">"czytanie danych kontaktów"</string>
+ <string name="permdesc_readContacts">"Pozwala aplikacji na czytanie wszystkich danych kontaktowych (adresowych) zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby wysyłać dane użytkownika do innych ludzi."</string>
+ <string name="permlab_writeContacts">"zapisywanie danych kontaktowych"</string>
+ <string name="permdesc_writeContacts">"Pozwala aplikacji na zmianę danych kontaktowych (adresowych) zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby usunąć lub zmienić dane kontaktowe."</string>
+ <string name="permlab_writeOwnerData">"zapisywanie danych właściciela"</string>
+ <string name="permdesc_writeOwnerData">"Pozwala aplikacji na zmianę danych właściciela zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby wymazać lub zmienić dane właściciela."</string>
+ <string name="permlab_readOwnerData">"czytanie danych właściciela"</string>
+ <string name="permdesc_readOwnerData">"Pozwala aplikacji na czytanie danych właściciela zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać do odczytania danych właściciela."</string>
+ <string name="permlab_readCalendar">"czytanie danych kalendarza"</string>
+ <string name="permdesc_readCalendar">"Pozwala aplikacji na odczytywanie wszystkich wydarzeń z kalendarza, zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać do rozsyłania wydarzeń z kalendarza do innych ludzi."</string>
+ <string name="permlab_writeCalendar">"zapisywanie danych kalendarza"</string>
+ <string name="permdesc_writeCalendar">"Pozwala aplikacji na zmianę wydarzeń z kalendarza zapisanych w telefonie. Szkodliwe aplikacje mogą to wykorzystać, aby usunąć lub zmienić dane w kalendarzu."</string>
+ <string name="permlab_accessMockLocation">"udawanie źródeł położenia dla testów"</string>
+ <string name="permdesc_accessMockLocation">"Tworzenie pozorowanych źródeł ustalania położenia dla testów. Szkodliwe aplikacje mogą to wykorzystać, aby zastąpić prawdziwe położenie i/lub stan zwracany przez prawdziwe źródła, takie jak GPS lub dostawcy usługi sieciowej."</string>
+ <string name="permlab_accessLocationExtraCommands">"dostęp do dodatkowych poleceń dostawcy informacji o lokalizacji"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Dostęp do dodatkowych poleceń dostawcy informacji o lokalizacji. Szkodliwe aplikacje mogą go wykorzystać, aby wpływać na działanie urządzenia GPS lub innych źródeł ustalania lokalizacji."</string>
+ <string name="permlab_installLocationProvider">"uprawnienia do instalowania dostawcy danych o lokalizacji"</string>
+ <string name="permdesc_installLocationProvider">"Utwórz sztuczne źródła danych o lokalizacji na potrzeby testowania. Złośliwe aplikacje mogą korzystać z tej opcji w celu zastępowania danych o lokalizacji i/lub stanie zwracanych przez prawdziwe źródła danych o lokalizacji, takie jak odbiornik GPS lub dostawcy sieciowi, bądź monitorowania i zgłaszania lokalizacji do źródeł zewnętrznych."</string>
+ <string name="permlab_accessFineLocation">"dokładna lokalizacja (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Uzyskiwanie dostępu do dokładnych źródeł ustalania położenia w telefonie, takich jak system GPS, tam, gdzie są one dostępne. Szkodliwe aplikacje mogą to wykorzystać do określenia położenia użytkownika oraz mogą zużywać więcej energii baterii."</string>
+ <string name="permlab_accessCoarseLocation">"przybliżone ustalanie lokalizacji (oparte o sieć)"</string>
+ <string name="permdesc_accessCoarseLocation">"Dostęp do źródeł, takich jak bazy danych sieci komórkowych, jeśli są dostępne, które pozwalają określić przybliżoną lokalizację telefonu. Szkodliwe aplikacje mogą go wykorzystać do określenia, gdzie w przybliżeniu znajduje się użytkownik."</string>
+ <string name="permlab_accessSurfaceFlinger">"dostęp do usługi SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Pozwala aplikacji na wykorzystanie funkcji niskiego poziomu usługi SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"czytanie bufora ramki"</string>
+ <string name="permdesc_readFrameBuffer">"Pozwala aplikacji na wykorzystanie odczytanej zawartości bufora ramki."</string>
+ <string name="permlab_modifyAudioSettings">"zmienianie ustawień audio"</string>
+ <string name="permdesc_modifyAudioSettings">"Pozwala aplikacjom na zmianę globalnych ustawień audio, takich jak głośność i routing."</string>
+ <string name="permlab_recordAudio">"nagrywanie dźwięku"</string>
+ <string name="permdesc_recordAudio">"Pozwala aplikacji na dostęp do ścieżki nagrywania dźwięku."</string>
+ <string name="permlab_camera">"robienie zdjęć"</string>
+ <string name="permdesc_camera">"Pozwala aplikacji na wykonywanie zdjęć za pomocą aparatu. Dzięki temu może ona pobierać zdjęcia z aparatu w dowolnym momencie."</string>
+ <string name="permlab_brick">"wyłączenie telefonu na stałe"</string>
+ <string name="permdesc_brick">"Pozwala aplikacji na wyłączenie całego telefonu na stałe. Jest to bardzo niebezpieczne."</string>
+ <string name="permlab_reboot">"wymuszanie ponownego uruchomienia telefonu"</string>
+ <string name="permdesc_reboot">"Pozwala aplikacji na wymuszenie ponownego uruchomienia telefonu."</string>
+ <string name="permlab_mount_unmount_filesystems">"podłączanie i odłączanie systemów plików"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Pozwala aplikacjom na podłączanie i odłączanie systemów plików w pamięciach przenośnych."</string>
+ <string name="permlab_mount_format_filesystems">"formatowanie pamięci zewnętrznej"</string>
+ <string name="permdesc_mount_format_filesystems">"Zezwala aplikacji na formatowanie wymiennych nośników."</string>
+ <string name="permlab_vibrate">"kontrolowanie wibracji"</string>
+ <string name="permdesc_vibrate">"Pozwala aplikacjom na kontrolowanie wibracji."</string>
+ <string name="permlab_flashlight">"kontrolowanie latarki"</string>
+ <string name="permdesc_flashlight">"Pozwala aplikacji kontrolować latarkę."</string>
+ <string name="permlab_hardware_test">"testowanie sprzętu"</string>
+ <string name="permdesc_hardware_test">"Pozwala aplikacji na kontrolowanie różnych urządzeń peryferyjnych w celu testowania sprzętu."</string>
+ <string name="permlab_callPhone">"bezpośrednie wybieranie numerów telefonów"</string>
+ <string name="permdesc_callPhone">"Pozwala aplikacjom na dzwonienie pod numery telefonów bez interwencji użytkownika. Szkodliwe aplikacje mogą powodować występowanie niespodziewanych połączeń na rachunku telefonicznym. Należy zauważyć, że aplikacje nie mogą dzwonić na numery alarmowe."</string>
+ <string name="permlab_callPrivileged">"bezpośrednie wybieranie dowolnych numerów telefonu"</string>
+ <string name="permdesc_callPrivileged">"Pozwala aplikacji dzwonić na dowolny numer telefonu, włącznie z numerami alarmowymi, bez interwencji użytkownika. Szkodliwe aplikacje mogą wykonywać niepotrzebne i nielegalne połączenia z usługami alarmowymi."</string>
+ <string name="permlab_locationUpdates">"kontrolowanie powiadomień o aktualizacjach lokalizacji"</string>
+ <string name="permdesc_locationUpdates">"Pozwala włączyć/wyłączyć powiadomienia o aktualizacjach lokalizacji przez sieć bezprzewodową. Nie wykorzystywane przez normalne aplikacje."</string>
+ <string name="permlab_checkinProperties">"dostęp do właściwości usługi rezerwacji"</string>
+ <string name="permdesc_checkinProperties">"Pozwala na dostęp z uprawnieniami do odczytu/zapisu do właściwości przesłanych przez usługę rezerwacji. Nie wykorzystywane przez normalne aplikacje."</string>
+ <string name="permlab_bindGadget">"wybieranie widżetów"</string>
+ <string name="permdesc_bindGadget">"Zezwala aplikacjom na wskazywanie systemowi, które widżety mogą być używane przez inne aplikacje. Z użyciem tego pozwolenia aplikacje mogą udzielać dostępu do danych osobistych innym aplikacjom. Nie jest ono przeznaczone dla zwykłych aplikacji."</string>
+ <string name="permlab_modifyPhoneState">"zmiana stanu telefonu"</string>
+ <string name="permdesc_modifyPhoneState">"Pozwala aplikacji na kontrolowanie funkcji telefonu w urządzeniu. Aplikacja z tymi uprawnieniami może zmieniać, włączać i wyłączać sieci bezprzewodowe itp. bez informowania użytkownika."</string>
+ <string name="permlab_readPhoneState">"czytanie stanu telefonu"</string>
+ <string name="permdesc_readPhoneState">"Pozwala aplikacji na dostęp do funkcji telefonu w urządzeniu. Aplikacja z takim uprawnieniem może określić numer tego telefonu, czy jest nawiązane połączenie, numer, z którym jest ono nawiązane, itp."</string>
+ <string name="permlab_wakeLock">"zapobieganie przejściu telefonu w stan uśpienia"</string>
+ <string name="permdesc_wakeLock">"Pozwala aplikacji na zapobieganie przejściu telefonu w stan uśpienia."</string>
+ <string name="permlab_devicePower">"włączanie lub wyłączanie telefonu"</string>
+ <string name="permdesc_devicePower">"Pozwala aplikacji włączać i wyłączać telefon."</string>
+ <string name="permlab_factoryTest">"uruchamianie w trybie testu fabrycznego"</string>
+ <string name="permdesc_factoryTest">"Uruchom jako niskopoziomowy test producenta, pozwalając na całkowity dostęp do elementów sprzętowych telefonu. Dostępne tylko jeśli telefon działa w trybie testu producenta."</string>
+ <string name="permlab_setWallpaper">"ustawianie tapety"</string>
+ <string name="permdesc_setWallpaper">"Pozwala aplikacji na ustawianie tapety systemu."</string>
+ <string name="permlab_setWallpaperHints">"ustawianie wskazówek dotyczących rozmiaru tapety"</string>
+ <string name="permdesc_setWallpaperHints">"Pozwala aplikacji na ustawianie wskazówek dotyczących rozmiaru tapety."</string>
+ <string name="permlab_masterClear">"resetowanie systemu do ustawień fabrycznych"</string>
+ <string name="permdesc_masterClear">"Pozwala aplikacji na całkowite zresetowanie systemu do ustawień fabrycznych, z wymazaniem wszystkich danych, konfiguracji oraz zainstalowanych aplikacji."</string>
+ <string name="permlab_setTimeZone">"ustawianie strefy czasowej"</string>
+ <string name="permdesc_setTimeZone">"Pozwala aplikacji na zmianÄ™ strefy czasowej w telefonie."</string>
+ <string name="permlab_getAccounts">"wykrywanie znanych kont"</string>
+ <string name="permdesc_getAccounts">"Pozwala aplikacji na pobranie listy kont zapisanych w telefonie."</string>
+ <string name="permlab_accessNetworkState">"wyświetlanie stanu sieci"</string>
+ <string name="permdesc_accessNetworkState">"Pozwala aplikacji na wyświetlanie stanu wszystkich sieci."</string>
+ <string name="permlab_createNetworkSockets">"pełen dostęp do internetu"</string>
+ <string name="permdesc_createNetworkSockets">"Pozwala aplikacji na tworzenie gniazd sieciowych."</string>
+ <string name="permlab_writeApnSettings">"zapisywanie ustawień nazwy punktu dostępowego (APN, Access Point Name)"</string>
+ <string name="permdesc_writeApnSettings">"Pozwala aplikacji na zmianę ustawień APN, takich jak serwer proxy oraz port dowolnego APN."</string>
+ <string name="permlab_changeNetworkState">"zmienianie połączeń sieci"</string>
+ <string name="permdesc_changeNetworkState">"Pozwala aplikacji na zmianę stanu połączeń sieciowych."</string>
+ <string name="permlab_changeBackgroundDataSetting">"zmienianie ustawienia używania danych w tle"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Zezwala aplikacji na zmianę ustawień użycia danych w tle."</string>
+ <string name="permlab_accessWifiState">"wyświetlanie stanu Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Pozwala aplikacji na wyświetlanie informacji o stanie Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"zmiana stanu Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Pozwala aplikacji na łączenie i rozłączanie z punktami dostępowymi Wi-Fi oraz na dokonywanie zmian skonfigurowanych sieci Wi-Fi."</string>
+ <string name="permlab_changeWifiMulticastState">"zezwolenie na odbiór grupowych połączeń Wi-Fi"</string>
+ <string name="permdesc_changeWifiMulticastState">"Umożliwia aplikacji odbieranie pakietów nieskierowanych bezpośrednio do Twojego urządzenia. Może to być przydatne przy wykrywaniu usług oferowanych w okolicy. Powoduje większe zapotrzebowanie na energię niż w trybie innym niż grupowy."</string>
+ <string name="permlab_bluetoothAdmin">"administrowanie Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Pozwala aplikacji na konfigurowanie lokalnego telefonu Bluetooth, wyszukiwanie urządzeń zdalnych i łączenie się z nimi."</string>
+ <string name="permlab_bluetooth">"tworzenie połączeń Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Pozwala aplikacji na wyświetlanie konfiguracji lokalnego telefonu Bluetooth oraz na tworzenie i akceptowanie połączeń ze sparowanymi urządzeniami."</string>
+ <string name="permlab_disableKeyguard">"wyłączanie blokady klawiatury"</string>
+ <string name="permdesc_disableKeyguard">"Pozwala aplikacji na wyłączenie blokady klawiatury i wszystkich związanych z tym haseł zabezpieczających. Typowym przykładem takiego działania jest wyłączanie blokady klawiatury, gdy pojawia się połączenie przychodzące, a następnie ponowne jej włączanie po zakończeniu połączenia."</string>
+ <string name="permlab_readSyncSettings">"czytanie ustawień synchronizowania"</string>
+ <string name="permdesc_readSyncSettings">"Pozwala aplikacji na czytanie ustawień synchronizacji, takich jak informacje, czy synchronizacja kontaktów jest włączona."</string>
+ <string name="permlab_writeSyncSettings">"zapisywanie ustawień synchronizowania"</string>
+ <string name="permdesc_writeSyncSettings">"Pozwala aplikacji na zmianę ustawień synchronizowania, takich jak ustalenie, czy synchronizacja dla kontaktów ma być włączona."</string>
+ <string name="permlab_readSyncStats">"czytanie statystyk dotyczÄ…cych synchronizowania"</string>
+ <string name="permdesc_readSyncStats">"Pozwala aplikacji na czytanie statystyk synchronizowania, np. historii przeprowadzonych synchronizacji."</string>
+ <string name="permlab_subscribedFeedsRead">"czytanie subskrybowanych źródeł"</string>
+ <string name="permdesc_subscribedFeedsRead">"Pozwala aplikacjom na pobieranie informacji szczegółowych na temat obecnie zsynchronizowanych źródeł."</string>
+ <string name="permlab_subscribedFeedsWrite">"zapisywanie subskrybowanych źródeł"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Umożliwia aplikacji zmianę obecnie zsynchronizowanych źródeł. Może to pozwolić szkodliwej aplikacji na zmianę zsynchronizowanych źródeł."</string>
+ <string name="permlab_readDictionary">"odczytywanie słownika zdefiniowanego przez użytkownika"</string>
+ <string name="permdesc_readDictionary">"Zezwala aplikacji na odczytywanie wszelkich prywatnych słów, nazw i wyrażeń zapisanych przez użytkownika w swoim słowniku."</string>
+ <string name="permlab_writeDictionary">"zapisywanie w słowniku zdefiniowanym przez użytkownika"</string>
+ <string name="permdesc_writeDictionary">"Zezwala aplikacjom na zapisywanie nowych słów w słowniku użytkownika."</string>
+ <string name="permlab_sdcardWrite">"modyfikowanie/usuwanie zawartości karty SD"</string>
+ <string name="permdesc_sdcardWrite">"Umożliwia aplikacji zapis na karcie SD."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Dom"</item>
- <item msgid="869923650527136615">"Komórka"</item>
- <item msgid="7897544654242874543">"Praca"</item>
- <item msgid="1103601433382158155">"Faks w pracy"</item>
- <item msgid="1735177144948329370">"Faks domowy"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Inny"</item>
- <item msgid="9192514806975898961">"Niestandardowy"</item>
+ <item>"Dom"</item>
+ <item>"Komórka"</item>
+ <item>"Praca"</item>
+ <item>"Faks w pracy"</item>
+ <item>"Faks domowy"</item>
+ <item>"Pager"</item>
+ <item>"Inny"</item>
+ <item>"Niestandardowy"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Dom"</item>
- <item msgid="7084237356602625604">"Praca"</item>
- <item msgid="1112044410659011023">"Inne"</item>
- <item msgid="2374913952870110618">"Niestandardowy"</item>
+ <item>"Dom"</item>
+ <item>"Praca"</item>
+ <item>"Inne"</item>
+ <item>"Niestandardowy"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Komórka"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Dom"</item>
- <item msgid="5629153956045109251">"Praca"</item>
- <item msgid="4966604264500343469">"Inny"</item>
- <item msgid="4932682847595299369">"Niestandardowy"</item>
+ <item>"Dom"</item>
+ <item>"Praca"</item>
+ <item>"Inny"</item>
+ <item>"Niestandardowy"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Dom"</item>
- <item msgid="1359644565647383708">"Praca"</item>
- <item msgid="7868549401053615677">"Inne"</item>
- <item msgid="3145118944639869809">"Niestandardowy"</item>
+ <item>"Dom"</item>
+ <item>"Praca"</item>
+ <item>"Inne"</item>
+ <item>"Niestandardowy"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Praca"</item>
- <item msgid="4378074129049520373">"Inne"</item>
- <item msgid="3455047468583965104">"Niestandardowy"</item>
+ <item>"Praca"</item>
+ <item>"Inne"</item>
+ <item>"Niestandardowy"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Wprowadź kod PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Błędny kod PIN!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Aby odblokować, naciśnij Menu, a następnie 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numer alarmowy"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Brak usługi)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran zablokowany."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Naciśnij Menu, aby odblokować lub wykonać połączenie alarmowe."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Naciśnij Menu, aby odblokować."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Narysuj wzór, aby odblokować"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Połączenie alarmowe"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Poprawnie!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Niestety, spróbuj ponownie"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Åadowanie (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Naładowany."</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Podłącz ładowarkę."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Brak karty SIM."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Brak karty SIM w telefonie."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Włóż kartę SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Sieć zablokowana"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Karta SIM jest zablokowana kodem PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Zapoznaj się z instrukcją obsługi lub skontaktuj się z działem obsługi klienta."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Karta SIM jest zablokowana."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Odblokowywanie karty SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Wzór odblokowania został nieprawidłowo narysowany <xliff:g id="NUMBER_0">%d</xliff:g> razy. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> sekund."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Wzór odblokowania został narysowany nieprawidłowo <xliff:g id="NUMBER_0">%d</xliff:g> razy. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon trzeba będzie odblokować przez zalogowanie na koncie Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> sekund."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Spróbuj ponownie za <xliff:g id="NUMBER">%d</xliff:g> sekund."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zapomniałeś wzoru?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Zbyt wiele prób narysowania wzoru!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Aby odblokować, zaloguj się za pomocą konta Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nazwa użytkownika (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Hasło"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Zaloguj"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Błędna nazwa użytkownika lub hasło."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wyczyść"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Brak powiadomień"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Bieżące"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Powiadomienia"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Åadowanie..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Podłącz ładowarkę"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Bateria się rozładowuje:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"pozostało mniej niż <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
- <string name="battery_low_why" msgid="7655196144309694753">"Dlaczego?"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"Nieudany test fabryczny"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Czynność FACTORY_TEST jest obsługiwana tylko dla pakietów zainstalowanych w katalogu /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Nie znaleziono żadnego pakietu, który zapewnia działanie FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Uruchom ponownie"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Komunikat ze strony pod adresem „<xliff:g id="TITLE">%s</xliff:g>â€:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Czy opuścić tę stronę?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wybierz opcję OK, aby kontynuować, lub opcję Anuluj, aby pozostać na tej stronie."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Potwierdź"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"odczyt historii i zakładek przeglądarki"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Umożliwia aplikacji odczyt wszystkich adresów URL odwiedzonych przez przeglądarkę, a także wszystkich zakładek przeglądarki."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"zapis historii i zakładek przeglądarki"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Umożliwia aplikacji modyfikowanie historii lub zakładek przeglądarki zapisanych w telefonie. Złośliwe aplikacje mogą używać tej opcji do usuwania lub modyfikowania danych przeglądarki."</string>
- <string name="save_password_message" msgid="767344687139195790">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Nie teraz"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Zapamiętaj"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nigdy"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Brak uprawnień do otwierania tej strony."</string>
- <string name="text_copied" msgid="4985729524670131385">"Tekst został skopiowany do schowka."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Więcej"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"spacja"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"usuń"</string>
- <string name="search_go" msgid="8298016669822141719">"Szukaj"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 miesiÄ…c temu"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ponad 1 miesiÄ…c temu"</string>
+ <string name="keyguard_password_enter_pin_code">"Wprowadź kod PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Błędny kod PIN!"</string>
+ <string name="keyguard_label_text">"Aby odblokować, naciśnij Menu, a następnie 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Numer alarmowy"</string>
+ <string name="lockscreen_carrier_default">"(Brak usługi)"</string>
+ <string name="lockscreen_screen_locked">"Ekran zablokowany."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Naciśnij Menu, aby odblokować lub wykonać połączenie alarmowe."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Naciśnij Menu, aby odblokować."</string>
+ <string name="lockscreen_pattern_instructions">"Narysuj wzór, aby odblokować"</string>
+ <string name="lockscreen_emergency_call">"Połączenie alarmowe"</string>
+ <string name="lockscreen_pattern_correct">"Poprawnie!"</string>
+ <string name="lockscreen_pattern_wrong">"Niestety, spróbuj ponownie"</string>
+ <string name="lockscreen_plugged_in">"Åadowanie (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Podłącz ładowarkę."</string>
+ <string name="lockscreen_missing_sim_message_short">"Brak karty SIM."</string>
+ <string name="lockscreen_missing_sim_message">"Brak karty SIM w telefonie."</string>
+ <string name="lockscreen_missing_sim_instructions">"Włóż kartę SIM."</string>
+ <string name="lockscreen_network_locked_message">"Sieć zablokowana"</string>
+ <string name="lockscreen_sim_puk_locked_message">"Karta SIM jest zablokowana kodem PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Zapoznaj się z instrukcją obsługi lub skontaktuj się z działem obsługi klienta."</string>
+ <string name="lockscreen_sim_locked_message">"Karta SIM jest zablokowana."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Odblokowywanie karty SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Wzór odblokowania został nieprawidłowo narysowany <xliff:g id="NUMBER_0">%d</xliff:g> razy. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> sekund."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Wzór odblokowania został narysowany nieprawidłowo <xliff:g id="NUMBER_0">%d</xliff:g> razy. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon trzeba będzie odblokować przez zalogowanie na koncie Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> sekund."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Spróbuj ponownie za <xliff:g id="NUMBER">%d</xliff:g> sekund."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Zapomniałeś wzoru?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Zbyt wiele prób narysowania wzoru!"</string>
+ <string name="lockscreen_glogin_instructions">"Aby odblokować, zaloguj się za pomocą konta Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Nazwa użytkownika (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Hasło"</string>
+ <string name="lockscreen_glogin_submit_button">"Zaloguj"</string>
+ <string name="lockscreen_glogin_invalid_input">"Błędna nazwa użytkownika lub hasło."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"Brak powiadomień"</string>
+ <string name="status_bar_ongoing_events_title">"Bieżące"</string>
+ <string name="status_bar_latest_events_title">"Powiadomienia"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Åadowanie..."</string>
+ <string name="battery_low_title">"Podłącz ładowarkę"</string>
+ <string name="battery_low_subtitle">"Bateria się rozładowuje:"</string>
+ <string name="battery_low_percent_format">"pozostało mniej niż <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="battery_low_why">"Dlaczego?"</string>
+ <string name="factorytest_failed">"Nieudany test fabryczny"</string>
+ <string name="factorytest_not_system">"Czynność FACTORY_TEST jest obsługiwana tylko dla pakietów zainstalowanych w katalogu /system/app."</string>
+ <string name="factorytest_no_action">"Nie znaleziono żadnego pakietu, który zapewnia działanie FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Uruchom ponownie"</string>
+ <string name="js_dialog_title">"Komunikat ze strony pod adresem „<xliff:g id="TITLE">%s</xliff:g>â€:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Czy opuścić tę stronę?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wybierz opcję OK, aby kontynuować, lub opcję Anuluj, aby pozostać na tej stronie."</string>
+ <string name="save_password_label">"Potwierdź"</string>
+ <string name="permlab_readHistoryBookmarks">"odczyt historii i zakładek przeglądarki"</string>
+ <string name="permdesc_readHistoryBookmarks">"Umożliwia aplikacji odczyt wszystkich adresów URL odwiedzonych przez przeglądarkę, a także wszystkich zakładek przeglądarki."</string>
+ <string name="permlab_writeHistoryBookmarks">"zapis historii i zakładek przeglądarki"</string>
+ <string name="permdesc_writeHistoryBookmarks">"Umożliwia aplikacji modyfikowanie historii lub zakładek przeglądarki zapisanych w telefonie. Złośliwe aplikacje mogą używać tej opcji do usuwania lub modyfikowania danych przeglądarki."</string>
+ <string name="save_password_message">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string>
+ <string name="save_password_notnow">"Nie teraz"</string>
+ <string name="save_password_remember">"Zapamiętaj"</string>
+ <string name="save_password_never">"Nigdy"</string>
+ <string name="open_permission_deny">"Brak uprawnień do otwierania tej strony."</string>
+ <string name="text_copied">"Tekst został skopiowany do schowka."</string>
+ <string name="more_item_label">"Więcej"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"spacja"</string>
+ <string name="menu_enter_shortcut_label">"enter"</string>
+ <string name="menu_delete_shortcut_label">"usuń"</string>
+ <string name="search_go">"Szukaj"</string>
+ <string name="oneMonthDurationPast">"1 miesiÄ…c temu"</string>
+ <string name="beforeOneMonthDurationPast">"Ponad 1 miesiÄ…c temu"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"sekundÄ™ temu"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekund temu"</item>
+ <item quantity="one">"sekundÄ™ temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sekund temu"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minutÄ™ temu"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minut temu"</item>
+ <item quantity="one">"1 minutÄ™ temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minut temu"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"godzinÄ™ temu"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> godzin temu"</item>
+ <item quantity="one">"godzinÄ™ temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> godzin temu"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"wczoraj"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
+ <item quantity="one">"wczoraj"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"za sekundÄ™"</item>
- <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> sekund"</item>
+ <item quantity="one">"za sekundÄ™"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> sekund"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"za minutÄ™"</item>
- <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> minut"</item>
+ <item quantity="one">"za minutÄ™"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> minut"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"za godzinÄ™"</item>
- <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> godzin"</item>
+ <item quantity="one">"za godzinÄ™"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> godzin"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"jutro"</item>
- <item quantity="other" msgid="5109449375100953247">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
+ <item quantity="one">"jutro"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"sekundÄ™ temu"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek. temu"</item>
+ <item quantity="one">"sekundÄ™ temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sek. temu"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"minutÄ™ temu"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
+ <item quantity="one">"minutÄ™ temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"godzinÄ™ temu"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
+ <item quantity="one">"godzinÄ™ temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"wczoraj"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
+ <item quantity="one">"wczoraj"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"za sekundÄ™"</item>
- <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> sek."</item>
+ <item quantity="one">"za sekundÄ™"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> sek."</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"za minutÄ™"</item>
- <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ <item quantity="one">"za minutÄ™"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"za godzinÄ™"</item>
- <item quantity="other" msgid="3705373766798013406">"za <xliff:g id="COUNT">%d</xliff:g> godz."</item>
+ <item quantity="one">"za godzinÄ™"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> godz."</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"jutro"</item>
- <item quantity="other" msgid="2973062968038355991">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
+ <item quantity="one">"jutro"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"dnia %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"o %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"w %s"</string>
- <string name="day" msgid="8144195776058119424">"dzień"</string>
- <string name="days" msgid="4774547661021344602">"dni"</string>
- <string name="hour" msgid="2126771916426189481">"godzina"</string>
- <string name="hours" msgid="894424005266852993">"godzin"</string>
- <string name="minute" msgid="9148878657703769868">"min"</string>
- <string name="minutes" msgid="5646001005827034509">"minut"</string>
- <string name="second" msgid="3184235808021478">"s"</string>
- <string name="seconds" msgid="3161515347216589235">"S"</string>
- <string name="week" msgid="5617961537173061583">"tydzień"</string>
- <string name="weeks" msgid="6509623834583944518">"tygodni"</string>
- <string name="year" msgid="4001118221013892076">"rok"</string>
- <string name="years" msgid="6881577717993213522">"lat"</string>
- <string name="every_weekday" msgid="8777593878457748503">"W każdy dzień roboczy (pon–pt)"</string>
- <string name="daily" msgid="5738949095624133403">"Codziennie"</string>
- <string name="weekly" msgid="983428358394268344">"Co tydzień w <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Miesięcznie"</string>
- <string name="yearly" msgid="1519577999407493836">"Co roku"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Nie można odtworzyć filmu wideo"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Przepraszamy, ten film wideo nie nadaje się do przesyłania strumieniowego do tego urządzenia."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Niestety, nie można odtworzyć tego filmu wideo."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"południe"</string>
- <string name="Noon" msgid="3342127745230013127">"Południe"</string>
- <string name="midnight" msgid="7166259508850457595">"północ"</string>
- <string name="Midnight" msgid="5630806906897892201">"Północ"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Zaznacz wszystko"</string>
- <string name="selectText" msgid="3889149123626888637">"Zaznacz tekst"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Zatrzymaj wybieranie tekstu"</string>
- <string name="cut" msgid="3092569408438626261">"Wytnij"</string>
- <string name="cutAll" msgid="2436383270024931639">"Wytnij wszystko"</string>
- <string name="copy" msgid="2681946229533511987">"Kopiuj"</string>
- <string name="copyAll" msgid="2590829068100113057">"Kopiuj wszystko"</string>
- <string name="paste" msgid="5629880836805036433">"Wklej"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Kopiuj adres URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Wprowadzanie tekstu"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Dodaj „%s†do słownika"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Edytuj tekst"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Mało miejsca"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Maleje ilość dostępnej pamięci telefonu."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Anuluj"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Anuluj"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Uwaga"</string>
- <string name="capital_on" msgid="1544682755514494298">"WÅ‚Ä…cz"</string>
- <string name="capital_off" msgid="6815870386972805832">"Wyłącz"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Zakończ czynność korzystając z"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Używaj domyślnie dla tej czynności."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Wyczyść domyślne w: Ustawienia strony głównej &gt; Aplikacje &gt; Zarządzaj aplikacjami."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Wybierz czynność"</string>
- <string name="noApplications" msgid="1691104391758345586">"Żadna z aplikacji nie może wykonać tej czynności."</string>
- <string name="aerr_title" msgid="653922989522758100">"Przepraszamy!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) została niespodziewanie zatrzymana. Spróbuj ponownie."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> został niespodziewanie zatrzymany. Spróbuj ponownie."</string>
- <string name="anr_title" msgid="3100070910664756057">"Przepraszamy!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> (w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>) nie odpowiada."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
- <string name="anr_process" msgid="1246866008169975783">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nie odpowiada."</string>
- <string name="force_close" msgid="3653416315450806396">"Wymuś zamknięcie"</string>
- <string name="report" msgid="4060218260984795706">"Zgłoś"</string>
- <string name="wait" msgid="7147118217226317732">"Czekaj"</string>
- <string name="debug" msgid="9103374629678531849">"Debuguj"</string>
- <string name="sendText" msgid="5132506121645618310">"Jak wysłać tekst?"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Głośność dzwonka"</string>
- <string name="volume_music" msgid="5421651157138628171">"Głośność multimediów"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Odtwarzanie przez Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Głośność podczas połączenia"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Głośność Bluetooth w czasie połączenia"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Głośność alarmu"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Głośność powiadomienia"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Głośność"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Dzwonek domyślny"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Dzwonek domyślny (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Cichy"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Dzwonki"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Nieznany dzwonek"</string>
+ <string name="preposition_for_date">"dnia %s"</string>
+ <string name="preposition_for_time">"o %s"</string>
+ <string name="preposition_for_year">"w %s"</string>
+ <string name="day">"dzień"</string>
+ <string name="days">"dni"</string>
+ <string name="hour">"godzina"</string>
+ <string name="hours">"godzin"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"minut"</string>
+ <string name="second">"s"</string>
+ <string name="seconds">"S"</string>
+ <string name="week">"tydzień"</string>
+ <string name="weeks">"tygodni"</string>
+ <string name="year">"rok"</string>
+ <string name="years">"lat"</string>
+ <string name="every_weekday">"W każdy dzień roboczy (pon–pt)"</string>
+ <string name="daily">"Codziennie"</string>
+ <string name="weekly">"Co tydzień w <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Miesięcznie"</string>
+ <string name="yearly">"Co roku"</string>
+ <string name="VideoView_error_title">"Nie można odtworzyć filmu wideo"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Przepraszamy, ten film wideo nie nadaje się do przesyłania strumieniowego do tego urządzenia."</string>
+ <string name="VideoView_error_text_unknown">"Niestety, nie można odtworzyć tego filmu wideo."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"południe"</string>
+ <string name="Noon">"Południe"</string>
+ <string name="midnight">"północ"</string>
+ <string name="Midnight">"Północ"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Zaznacz wszystko"</string>
+ <string name="selectText">"Zaznacz tekst"</string>
+ <string name="stopSelectingText">"Zatrzymaj wybieranie tekstu"</string>
+ <string name="cut">"Wytnij"</string>
+ <string name="cutAll">"Wytnij wszystko"</string>
+ <string name="copy">"Kopiuj"</string>
+ <string name="copyAll">"Kopiuj wszystko"</string>
+ <string name="paste">"Wklej"</string>
+ <string name="copyUrl">"Kopiuj adres URL"</string>
+ <string name="inputMethod">"Wprowadzanie tekstu"</string>
+ <string name="addToDictionary">"Dodaj „%s†do słownika"</string>
+ <string name="editTextMenuTitle">"Edytuj tekst"</string>
+ <string name="low_internal_storage_view_title">"Mało miejsca"</string>
+ <string name="low_internal_storage_view_text">"Maleje ilość dostępnej pamięci telefonu."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Anuluj"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Anuluj"</string>
+ <string name="dialog_alert_title">"Uwaga"</string>
+ <string name="capital_on">"WÅ‚Ä…cz"</string>
+ <string name="capital_off">"Wyłącz"</string>
+ <string name="whichApplication">"Zakończ czynność korzystając z"</string>
+ <string name="alwaysUse">"Używaj domyślnie dla tej czynności."</string>
+ <string name="clearDefaultHintMsg">"Wyczyść domyślne w: Ustawienia strony głównej &gt; Aplikacje &gt; Zarządzaj aplikacjami."</string>
+ <string name="chooseActivity">"Wybierz czynność"</string>
+ <string name="noApplications">"Żadna z aplikacji nie może wykonać tej czynności."</string>
+ <string name="aerr_title">"Przepraszamy!"</string>
+ <string name="aerr_application">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) została niespodziewanie zatrzymana. Spróbuj ponownie."</string>
+ <string name="aerr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> został niespodziewanie zatrzymany. Spróbuj ponownie."</string>
+ <string name="anr_title">"Przepraszamy!"</string>
+ <string name="anr_activity_application">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> (w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>) nie odpowiada."</string>
+ <string name="anr_activity_process">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
+ <string name="anr_application_process">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
+ <string name="anr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nie odpowiada."</string>
+ <string name="force_close">"Wymuś zamknięcie"</string>
+ <string name="report">"Zgłoś"</string>
+ <string name="wait">"Czekaj"</string>
+ <string name="debug">"Debuguj"</string>
+ <string name="sendText">"Jak wysłać tekst?"</string>
+ <string name="volume_ringtone">"Głośność dzwonka"</string>
+ <string name="volume_music">"Głośność multimediów"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Odtwarzanie przez Bluetooth"</string>
+ <string name="volume_call">"Głośność podczas połączenia"</string>
+ <string name="volume_bluetooth_call">"Głośność Bluetooth w czasie połączenia"</string>
+ <string name="volume_alarm">"Głośność alarmu"</string>
+ <string name="volume_notification">"Głośność powiadomienia"</string>
+ <string name="volume_unknown">"Głośność"</string>
+ <string name="ringtone_default">"Dzwonek domyślny"</string>
+ <string name="ringtone_default_with_actual">"Dzwonek domyślny (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Cichy"</string>
+ <string name="ringtone_picker_title">"Dzwonki"</string>
+ <string name="ringtone_unknown">"Nieznany dzwonek"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Sieć Wi-Fi jest dostępna"</item>
- <item quantity="other" msgid="4192424489168397386">"Dostępne sieci Wi-Fi"</item>
+ <item quantity="one">"Sieć Wi-Fi jest dostępna"</item>
+ <item quantity="other">"Dostępne sieci Wi-Fi"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Otwórz dostępne sieci Wi-Fi"</item>
- <item quantity="other" msgid="7915895323644292768">"Otwórz dostępne sieci Wi-Fi"</item>
+ <item quantity="one">"Otwórz dostępne sieci Wi-Fi"</item>
+ <item quantity="other">"Otwórz dostępne sieci Wi-Fi"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Wstaw znak"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Nieznana aplikacja"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Wysyłanie wiadomości SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"WysyÅ‚ana jest duża liczba wiadomoÅ›ci SMS. Wybierz „OKâ€, aby kontynuować, lub „Anulujâ€, aby zatrzymać wysyÅ‚anie."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Anuluj"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Ustaw"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Domyślne"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Nie są wymagane żadne uprawnienia"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ukryj"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Pokaż wszystko"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Åadowanie..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Połączenie przez USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Telefon zostaÅ‚ podÅ‚Ä…czony do komputera przez port USB. Wybierz polecenie „PodÅ‚Ä…czâ€, jeÅ›li chcesz skopiować pliki miÄ™dzy komputerem a kartÄ… SD w telefonie."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Podłącz"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Nie podłączaj"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Wystąpił problem z wykorzystaniem karty SD dla pamięci USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Połączenie przez USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Wybierz, aby skopiować pliki do/z komputera"</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Wyłącz nośnik USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Wybierz, aby wyłączyć nośnik USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Wyłącz nośnik USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Przed wyÅ‚Ä…czeniem noÅ›nika USB upewnij siÄ™, że odÅ‚Ä…czono go od hosta USB. Wybierz „WyÅ‚Ä…czâ€, aby wyÅ‚Ä…czyć noÅ›nik USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Wyłącz"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Anuluj"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Napotkano problem przy wyłączaniu nośnika USB. Sprawdź, czy host USB został odłączony i spróbuj ponownie."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatuj kartÄ™ SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Czy na pewno sformatować kartę SD? Wszystkie dane na karcie zostaną utracone."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatuj"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Podłączono moduł debugowania USB"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"Komputer jest połączony z telefonem."</string>
- <string name="select_input_method" msgid="2086499663193509436">"Sposób wprowadzania tekstu"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÄ„BCĆDEĘFGHIJKLÅMNŃOÓPQRSÅšTUVWXYZŹŻ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Przygotowywanie karty SD"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Sprawdzanie w poszukiwaniu błędów."</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Pusta karta SD"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"Karta SD jest pusta lub zawiera nieobsługiwany system plików."</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Uszkodzona karta SD"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"Karta SD jest uszkodzona. Konieczne może być ponowne sformatowanie."</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Karta SD została nieoczekiwanie wyjęta"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Odłącz kartę SD przed jej wyjęciem, aby uniknąć utraty danych."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Można bezpiecznie usunąć kartę SD"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"Możesz bezpiecznie wyjąć kartę SD."</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Usunięta karta SD"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"Karta SD została wyjęta. Włóż nową kartę."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Nie znaleziono pasujących działań"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"aktualizowanie statystyk użycia komponentu"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Zezwala na modyfikacje zebranych statystyk użycia komponentu. Nieprzeznaczone dla zwykłych aplikacji."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dotknij dwukrotnie, aby sterować powiększeniem"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Błąd podczas wyodrębniania widżetu"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Przejdź"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Szukaj"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Wyślij"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Dalej"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Gotowe"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Wykonaj"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Połącz"\n"z numerem <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Utwórz kontakt"\n"dla numeru <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"zaznaczone"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"niezaznaczone"</string>
+ <string name="select_character">"Wstaw znak"</string>
+ <string name="sms_control_default_app_name">"Nieznana aplikacja"</string>
+ <string name="sms_control_title">"Wysyłanie wiadomości SMS"</string>
+ <string name="sms_control_message">"WysyÅ‚ana jest duża liczba wiadomoÅ›ci SMS. Wybierz „OKâ€, aby kontynuować, lub „Anulujâ€, aby zatrzymać wysyÅ‚anie."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Anuluj"</string>
+ <string name="date_time_set">"Ustaw"</string>
+ <string name="default_permission_group">"Domyślne"</string>
+ <string name="no_permissions">"Nie są wymagane żadne uprawnienia"</string>
+ <string name="perms_hide"><b>"Ukryj"</b></string>
+ <string name="perms_show_all"><b>"Pokaż wszystko"</b></string>
+ <string name="googlewebcontenthelper_loading">"Åadowanie..."</string>
+ <string name="usb_storage_title">"Połączenie przez USB"</string>
+ <string name="usb_storage_message">"Telefon zostaÅ‚ podÅ‚Ä…czony do komputera przez port USB. Wybierz polecenie „PodÅ‚Ä…czâ€, jeÅ›li chcesz skopiować pliki miÄ™dzy komputerem a kartÄ… SD w telefonie."</string>
+ <string name="usb_storage_button_mount">"Podłącz"</string>
+ <string name="usb_storage_button_unmount">"Nie podłączaj"</string>
+ <string name="usb_storage_error_message">"Wystąpił problem z wykorzystaniem karty SD dla pamięci USB."</string>
+ <string name="usb_storage_notification_title">"Połączenie przez USB"</string>
+ <string name="usb_storage_notification_message">"Wybierz, aby skopiować pliki do/z komputera"</string>
+ <string name="usb_storage_stop_notification_title">"Wyłącz nośnik USB"</string>
+ <string name="usb_storage_stop_notification_message">"Wybierz, aby wyłączyć nośnik USB."</string>
+ <string name="usb_storage_stop_title">"Wyłącz nośnik USB"</string>
+ <string name="usb_storage_stop_message">"Przed wyÅ‚Ä…czeniem noÅ›nika USB upewnij siÄ™, że odÅ‚Ä…czono go od hosta USB. Wybierz „WyÅ‚Ä…czâ€, aby wyÅ‚Ä…czyć noÅ›nik USB."</string>
+ <string name="usb_storage_stop_button_mount">"Wyłącz"</string>
+ <string name="usb_storage_stop_button_unmount">"Anuluj"</string>
+ <string name="usb_storage_stop_error_message">"Napotkano problem przy wyłączaniu nośnika USB. Sprawdź, czy host USB został odłączony i spróbuj ponownie."</string>
+ <string name="extmedia_format_title">"Formatuj kartÄ™ SD"</string>
+ <string name="extmedia_format_message">"Czy na pewno sformatować kartę SD? Wszystkie dane na karcie zostaną utracone."</string>
+ <string name="extmedia_format_button_format">"Formatuj"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"Sposób wprowadzania tekstu"</string>
+ <string name="fast_scroll_alphabet">" AÄ„BCĆDEĘFGHIJKLÅMNŃOÓPQRSÅšTUVWXYZŹŻ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"kandydaci"</u></string>
+ <string name="ext_media_checking_notification_title">"Przygotowywanie karty SD"</string>
+ <string name="ext_media_checking_notification_message">"Sprawdzanie w poszukiwaniu błędów."</string>
+ <string name="ext_media_nofs_notification_title">"Pusta karta SD"</string>
+ <string name="ext_media_nofs_notification_message">"Karta SD jest pusta lub zawiera nieobsługiwany system plików."</string>
+ <string name="ext_media_unmountable_notification_title">"Uszkodzona karta SD"</string>
+ <string name="ext_media_unmountable_notification_message">"Karta SD jest uszkodzona. Konieczne może być ponowne sformatowanie."</string>
+ <string name="ext_media_badremoval_notification_title">"Karta SD została nieoczekiwanie wyjęta"</string>
+ <string name="ext_media_badremoval_notification_message">"Odłącz kartę SD przed jej wyjęciem, aby uniknąć utraty danych."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Można bezpiecznie usunąć kartę SD"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Możesz bezpiecznie wyjąć kartę SD."</string>
+ <string name="ext_media_nomedia_notification_title">"Usunięta karta SD"</string>
+ <string name="ext_media_nomedia_notification_message">"Karta SD została wyjęta. Włóż nową kartę."</string>
+ <string name="activity_list_empty">"Nie znaleziono pasujących działań"</string>
+ <string name="permlab_pkgUsageStats">"aktualizowanie statystyk użycia komponentu"</string>
+ <string name="permdesc_pkgUsageStats">"Zezwala na modyfikacje zebranych statystyk użycia komponentu. Nieprzeznaczone dla zwykłych aplikacji."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Dotknij dwukrotnie, aby sterować powiększeniem"</string>
+ <string name="gadget_host_error_inflating">"Błąd podczas wyodrębniania widżetu"</string>
+ <string name="ime_action_go">"Przejdź"</string>
+ <string name="ime_action_search">"Szukaj"</string>
+ <string name="ime_action_send">"Wyślij"</string>
+ <string name="ime_action_next">"Dalej"</string>
+ <string name="ime_action_done">"Gotowe"</string>
+ <string name="ime_action_default">"Wykonaj"</string>
+ <string name="dial_number_using">"Połącz"\n"z numerem <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Utwórz kontakt"\n"dla numeru <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="accessibility_compound_button_selected">"zaznaczone"</string>
+ <string name="accessibility_compound_button_unselected">"niezaznaczone"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index a6ab576..5b75aad 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"&lt;sem título&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nenhum número de telefone)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Desconhecido)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correio de voz"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problema de ligação ou código MMI inválido."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"O serviço foi activado."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"O serviço foi activado para:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"O serviço foi desactivado."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"O registo foi bem sucedido."</string>
- <string name="serviceErased" msgid="1288584695297200972">"A eliminação foi bem sucedida."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Palavra-passe incorrecta."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI concluído."</string>
- <string name="badPin" msgid="5085454289896032547">"O PIN antigo que introduziu não está correcto."</string>
- <string name="badPuk" msgid="5702522162746042460">"O PUK que introduziu não está correcto."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Os PINs que introduziu não coincidem."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Introduza um PIN entre 4 e 8 números."</string>
- <string name="needPuk" msgid="919668385956251611">"O seu cartão SIM está bloqueado com PUK. Introduza o código PUK para desbloqueá-lo."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Introduza o PUK2 para desbloquear o cartão SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"ID do Autor da Chamada"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"ID do autor da chamada efectuada"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Encaminhamento de chamadas"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Chamada em espera"</string>
- <string name="BaMmi" msgid="455193067926770581">"Barramento de chamadas"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Alteração de palavra-passe"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Alteração de PIN"</string>
+ <string name="untitled">"&lt;sem título&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Nenhum número de telefone)"</string>
+ <string name="unknownName">"(Desconhecido)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Correio de voz"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problema de ligação ou código MMI inválido."</string>
+ <string name="serviceEnabled">"O serviço foi activado."</string>
+ <string name="serviceEnabledFor">"O serviço foi activado para:"</string>
+ <string name="serviceDisabled">"O serviço foi desactivado."</string>
+ <string name="serviceRegistered">"O registo foi bem sucedido."</string>
+ <string name="serviceErased">"A eliminação foi bem sucedida."</string>
+ <string name="passwordIncorrect">"Palavra-passe incorrecta."</string>
+ <string name="mmiComplete">"MMI concluído."</string>
+ <string name="badPin">"O PIN antigo que introduziu não está correcto."</string>
+ <string name="badPuk">"O PUK que introduziu não está correcto."</string>
+ <string name="mismatchPin">"Os PINs que introduziu não coincidem."</string>
+ <string name="invalidPin">"Introduza um PIN entre 4 e 8 números."</string>
+ <string name="needPuk">"O seu cartão SIM está bloqueado com PUK. Introduza o código PUK para desbloqueá-lo."</string>
+ <string name="needPuk2">"Introduza o PUK2 para desbloquear o cartão SIM."</string>
+ <string name="ClipMmi">"ID do Autor da Chamada"</string>
+ <string name="ClirMmi">"ID do autor da chamada efectuada"</string>
+ <string name="CfMmi">"Encaminhamento de chamadas"</string>
+ <string name="CwMmi">"Chamada em espera"</string>
+ <string name="BaMmi">"Barramento de chamadas"</string>
+ <string name="PwdMmi">"Alteração de palavra-passe"</string>
+ <string name="PinMmi">"Alteração de PIN"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID do autor da chamada é predefinido como restrito. Chamada seguinte: Restrita"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ID do autor da chamada é predefinido como restrito. Chamada seguinte: Não restrita"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID do autor da chamada é predefinido como não restrito. Chamada seguinte: Restrita"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID do autor da chamada é predefinido com não restrito. Chamada seguinte: Não restrita"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Serviço não fornecido."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Não é possível mudar o ID do autor da chamada."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acesso restrito modificado"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"O serviço de dados está bloqueado."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"O serviço de emergência está bloqueado."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"O serviço de voz/SMS está bloqueado."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Todos os serviços de voz/SMS estão bloqueados."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voz"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Dados"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Assíncronos"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Sincronização"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pacote"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"ID do autor da chamada é predefinido como restrito. Chamada seguinte: Restrita"</string>
+ <string name="CLIRDefaultOnNextCallOff">"ID do autor da chamada é predefinido como restrito. Chamada seguinte: Não restrita"</string>
+ <string name="CLIRDefaultOffNextCallOn">"ID do autor da chamada é predefinido como não restrito. Chamada seguinte: Restrita"</string>
+ <string name="CLIRDefaultOffNextCallOff">"ID do autor da chamada é predefinido com não restrito. Chamada seguinte: Não restrita"</string>
+ <string name="serviceNotProvisioned">"Serviço não fornecido."</string>
+ <string name="CLIRPermanent">"Não é possível mudar o ID do autor da chamada."</string>
+ <string name="RestrictedChangedTitle">"Acesso restrito modificado"</string>
+ <string name="RestrictedOnData">"O serviço de dados está bloqueado."</string>
+ <string name="RestrictedOnEmergency">"O serviço de emergência está bloqueado."</string>
+ <string name="RestrictedOnNormal">"O serviço de voz/SMS está bloqueado."</string>
+ <string name="RestrictedOnAll">"Todos os serviços de voz/SMS estão bloqueados."</string>
+ <string name="serviceClassVoice">"Voz"</string>
+ <string name="serviceClassData">"Dados"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Assíncronos"</string>
+ <string name="serviceClassDataSync">"Sincronização"</string>
+ <string name="serviceClassPacket">"Pacote"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"A página Web contém um erro."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Não foi possível localizar o URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"O esquema de autenticação do site não é suportado."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"A autenticação falhou."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"A autenticação através do servidor proxy falhou."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Não foi possível estabelecer a ligação ao servidor."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"O servidor falhou ao comunicar. Tente novamente mais tarde."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Esgotou o tempo limite da ligação ao servidor."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"A página contém demasiados redireccionamentos do servidor."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"O protocolo não é suportado."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Não foi possível estabelecer uma ligação segura."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Não foi possível abrir a página porque o URL é inválido."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Não foi possível aceder ao ficheiro."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Não foi possível localizar o ficheiro pedido."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Existem demasiados pedidos em processamento. Tente novamente mais tarde."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Sincronização"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronização"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminações de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"O armazenamento do telefone está cheio! Elimine alguns ficheiros para libertar espaço."</string>
- <string name="me" msgid="6545696007631404292">"Eu"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opções do telefone"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Modo silencioso"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Activar sem fios"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Desactivar sem fios"</string>
- <string name="screen_lock" msgid="799094655496098153">"Bloqueio de ecrã"</string>
- <string name="power_off" msgid="4266614107412865048">"Desligar"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"A encerrar..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"O seu telefone irá encerrar."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Nenhuma aplicação recente."</string>
- <string name="global_actions" msgid="2406416831541615258">"Opções do telefone"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Bloqueio de ecrã"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som desactivado"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O som está activado"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"O modo de voo está activado"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"O modo de voo está desactivado"</string>
- <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que implicam pagamento"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Permite às aplicações efectuar acções que implicam pagamento."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"As suas mensagens"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Leia e escreva a sua SMS, o seu e-mail e outras mensagens."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Os seus dados pessoais"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Acesso directo aos seus contactos e calendário armazenados no telefone."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"A sua localização"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Monitorizar a sua localização física"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicação de rede"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Permite o acesso de aplicações a várias funcionalidades de rede."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"As suas Contas Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Aceda às Contas Google disponíveis."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controlos de hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Aceda directamente ao hardware no telefone."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Chamadas"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitorize, grave e processe chamadas telefónicas."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Ferramentas do sistema"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Acesso e controlo de nível inferior do sistema."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Ferramentas de desenvolvimento"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funcionalidades apenas necessárias para programadores de aplicações."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"A página Web contém um erro."</string>
+ <string name="httpErrorLookup">"Não foi possível localizar o URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"O esquema de autenticação do site não é suportado."</string>
+ <string name="httpErrorAuth">"A autenticação falhou."</string>
+ <string name="httpErrorProxyAuth">"A·autenticação·através·do·servidor·proxy·falhou."</string>
+ <string name="httpErrorConnect">"Não foi possível estabelecer a ligação ao servidor."</string>
+ <string name="httpErrorIO">"O servidor falhou ao comunicar. Tente novamente mais tarde."</string>
+ <string name="httpErrorTimeout">"Esgotou o tempo limite da ligação ao servidor."</string>
+ <string name="httpErrorRedirectLoop">"A página contém demasiados redireccionamentos do servidor."</string>
+ <string name="httpErrorUnsupportedScheme">"O protocolo não é suportado."</string>
+ <string name="httpErrorFailedSslHandshake">"Não foi possível estabelecer uma ligação segura."</string>
+ <string name="httpErrorBadUrl">"Não foi possível abrir a página porque o URL é inválido."</string>
+ <string name="httpErrorFile">"Não foi possível aceder ao ficheiro."</string>
+ <string name="httpErrorFileNotFound">"Não foi possível localizar o ficheiro pedido."</string>
+ <string name="httpErrorTooManyRequests">"Existem demasiados pedidos em processamento. Tente novamente mais tarde."</string>
+ <string name="contentServiceSync">"Sincronização"</string>
+ <string name="contentServiceSyncNotificationTitle">"Sincronização"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Demasiadas eliminações de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"O armazenamento do telefone está cheio! Elimine alguns ficheiros para libertar espaço."</string>
+ <string name="me">"Eu"</string>
+ <string name="power_dialog">"Opções do telefone"</string>
+ <string name="silent_mode">"Modo silencioso"</string>
+ <string name="turn_on_radio">"Activar sem fios"</string>
+ <string name="turn_off_radio">"Desactivar sem fios"</string>
+ <string name="screen_lock">"Bloqueio de ecrã"</string>
+ <string name="power_off">"Desligar"</string>
+ <string name="shutdown_progress">"A encerrar..."</string>
+ <string name="shutdown_confirm">"O seu telefone irá encerrar."</string>
+ <string name="no_recent_tasks">"Nenhuma aplicação recente."</string>
+ <string name="global_actions">"Opções do telefone"</string>
+ <string name="global_action_lock">"Bloqueio de ecrã"</string>
+ <string name="global_action_power_off">"Desligar"</string>
+ <string name="global_action_toggle_silent_mode">"Modo silencioso"</string>
+ <string name="global_action_silent_mode_on_status">"Som desactivado"</string>
+ <string name="global_action_silent_mode_off_status">"O som está activado"</string>
+ <string name="global_actions_toggle_airplane_mode">"Modo de avião"</string>
+ <string name="global_actions_airplane_mode_on_status">"O modo de voo está activado"</string>
+ <string name="global_actions_airplane_mode_off_status">"O modo de voo está desactivado"</string>
+ <string name="safeMode">"Modo seguro"</string>
+ <string name="android_system_label">"Sistema Android"</string>
+ <string name="permgrouplab_costMoney">"Serviços que implicam pagamento"</string>
+ <string name="permgroupdesc_costMoney">"Permite às aplicações efectuar acções que implicam pagamento."</string>
+ <string name="permgrouplab_messages">"As suas mensagens"</string>
+ <string name="permgroupdesc_messages">"Leia e escreva a sua SMS, o seu e-mail e outras mensagens."</string>
+ <string name="permgrouplab_personalInfo">"Os seus dados pessoais"</string>
+ <string name="permgroupdesc_personalInfo">"Acesso directo aos seus contactos e calendário armazenados no telefone."</string>
+ <string name="permgrouplab_location">"A sua localização"</string>
+ <string name="permgroupdesc_location">"Monitorizar a sua localização física"</string>
+ <string name="permgrouplab_network">"Comunicação de rede"</string>
+ <string name="permgroupdesc_network">"Permite o acesso de aplicações a várias funcionalidades de rede."</string>
+ <string name="permgrouplab_accounts">"As suas Contas Google"</string>
+ <string name="permgroupdesc_accounts">"Aceda às Contas Google disponíveis."</string>
+ <string name="permgrouplab_hardwareControls">"Controlos de hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Aceda directamente ao hardware no telefone."</string>
+ <string name="permgrouplab_phoneCalls">"Chamadas"</string>
+ <string name="permgroupdesc_phoneCalls">"Monitorize, grave e processe chamadas telefónicas."</string>
+ <string name="permgrouplab_systemTools">"Ferramentas do sistema"</string>
+ <string name="permgroupdesc_systemTools">"Acesso e controlo de nível inferior do sistema."</string>
+ <string name="permgrouplab_developmentTools">"Ferramentas de desenvolvimento"</string>
+ <string name="permgroupdesc_developmentTools">"Funcionalidades apenas necessárias para programadores de aplicações."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar ou modificar barra de estado"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Permite à aplicação desactivar a barra de estado ou adicionar e remover ícones do sistema."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expandir/fechar barra de estado"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Permite à aplicação expandir ou fechar a barra de estado."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"interceptar chamadas efectuadas"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Permite à aplicação processar chamadas efectuadas e mudar o número a marcar. Algumas aplicações maliciosas podem monitorizar, redireccionar ou impedir chamadas efectuadas."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"receber SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Permite à aplicação receber e processar mensagens SMS. Algumas aplicações maliciosas podem monitorizar as suas mensagens e eliminá-las sem mostrá-las a si."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"receber MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Permite à aplicação receber e processar mensagens MMS. Algumas aplicações maliciosas podem monitorizar as mensagens ou eliminá-las sem mostrá-las ao utilizador."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"enviar mensagens SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Permite à aplicação enviar mensagens SMS. Algumas aplicações maliciosas podem fazer com que incorra em custos, enviando mensagens sem a sua confirmação."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"ler SMS ou MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Permite à aplicação ler mensagens SMS armazenadas no seu telefone ou cartão SIM. Algumas aplicações maliciosas podem ler as suas mensagens confidenciais."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS ou MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Permite a aplicações escrever mensagens SMS armazenadas no seu telefone ou cartão SIM. Algumas aplicações maliciosas podem eliminar as suas mensagens."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"receber WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Permite à aplicação receber e processar mensagens WAP. Algumas aplicações maliciosas podem monitorizar ou eliminá-las sem mostrá-las ao utilizador."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"obter aplicações em execução"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Permite à aplicação obter informações sobre tarefas actualmente em execução e recentemente executadas. Pode permitir que aplicações maliciosas descubram informações privadas sobre outras aplicações."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"reordenar aplicações em execução"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite a uma aplicação mover tarefas do primeiro e do segundo planos. Algumas aplicações maliciosas podem impor-se no primeiro plano sem o controlo do utilizador."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"activar depuração da aplicação"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite a uma aplicação activar a depuração para outra aplicação. Algumas aplicações maliciosas podem utilizar este item para eliminar outras aplicações."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar definições da IU"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Permite a uma aplicação mudar a configuração actual como, por exemplo, a região ou o tamanho global do tipo de letra."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"reiniciar outras aplicações"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Permite a uma aplicação efectuar o reinício forçado de outras aplicações."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"forçar fecho da aplicação"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Permite a uma aplicação forçar qualquer actividade em primeiro plano a fechar e retroceder. Nunca deve ser necessário para aplicações normais."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"obter estado interno do sistema"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Permite à aplicação obter o estado interno do sistema. Algumas aplicações maliciosas podem obter uma ampla variedade de dados privados e seguros de que, normalmente, nunca devem necessitar."</string>
+ <string name="permlab_statusBar">"desactivar ou modificar barra de estado"</string>
+ <string name="permdesc_statusBar">"Permite à aplicação desactivar a barra de estado ou adicionar e remover ícones do sistema."</string>
+ <string name="permlab_expandStatusBar">"expandir/fechar barra de estado"</string>
+ <string name="permdesc_expandStatusBar">"Permite à aplicação expandir ou fechar a barra de estado."</string>
+ <string name="permlab_processOutgoingCalls">"interceptar chamadas efectuadas"</string>
+ <string name="permdesc_processOutgoingCalls">"Permite à aplicação processar chamadas efectuadas e mudar o número a marcar. Algumas aplicações maliciosas podem monitorizar, redireccionar ou impedir chamadas efectuadas."</string>
+ <string name="permlab_receiveSms">"receber SMS"</string>
+ <string name="permdesc_receiveSms">"Permite à aplicação receber e processar mensagens SMS. Algumas aplicações maliciosas podem monitorizar as suas mensagens e eliminá-las sem mostrá-las a si."</string>
+ <string name="permlab_receiveMms">"receber MMS"</string>
+ <string name="permdesc_receiveMms">"Permite à aplicação receber e processar mensagens MMS. Algumas aplicações maliciosas podem monitorizar as mensagens ou eliminá-las sem mostrá-las ao utilizador."</string>
+ <string name="permlab_sendSms">"enviar mensagens SMS"</string>
+ <string name="permdesc_sendSms">"Permite à aplicação enviar mensagens SMS. Algumas aplicações maliciosas podem fazer com que incorra em custos, enviando mensagens sem a sua confirmação."</string>
+ <string name="permlab_readSms">"ler SMS ou MMS"</string>
+ <string name="permdesc_readSms">"Permite à aplicação ler mensagens SMS armazenadas no seu telefone ou cartão SIM. Algumas aplicações maliciosas podem ler as suas mensagens confidenciais."</string>
+ <string name="permlab_writeSms">"editar SMS ou MMS"</string>
+ <string name="permdesc_writeSms">"Permite a aplicações escrever mensagens SMS armazenadas no seu telefone ou cartão SIM. Algumas aplicações maliciosas podem eliminar as suas mensagens."</string>
+ <string name="permlab_receiveWapPush">"receber WAP"</string>
+ <string name="permdesc_receiveWapPush">"Permite à aplicação receber e processar mensagens WAP. Algumas aplicações maliciosas podem monitorizar ou eliminá-las sem mostrá-las ao utilizador."</string>
+ <string name="permlab_getTasks">"obter aplicações em execução"</string>
+ <string name="permdesc_getTasks">"Permite à aplicação obter informações sobre tarefas actualmente em execução e recentemente executadas. Pode permitir que aplicações maliciosas descubram informações privadas sobre outras aplicações."</string>
+ <string name="permlab_reorderTasks">"reordenar aplicações em execução"</string>
+ <string name="permdesc_reorderTasks">"Permite a uma aplicação mover tarefas do primeiro e do segundo planos. Algumas aplicações maliciosas podem impor-se no primeiro plano sem o controlo do utilizador."</string>
+ <string name="permlab_setDebugApp">"activar depuração da aplicação"</string>
+ <string name="permdesc_setDebugApp">"Permite a uma aplicação activar a depuração para outra aplicação. Algumas aplicações maliciosas podem utilizar este item para eliminar outras aplicações."</string>
+ <string name="permlab_changeConfiguration">"mudar definições da IU"</string>
+ <string name="permdesc_changeConfiguration">"Permite a uma aplicação mudar a configuração actual como, por exemplo, a região ou o tamanho global do tipo de letra."</string>
+ <string name="permlab_restartPackages">"reiniciar outras aplicações"</string>
+ <string name="permdesc_restartPackages">"Permite a uma aplicação efectuar o reinício forçado de outras aplicações."</string>
+ <string name="permlab_forceBack">"forçar fecho da aplicação"</string>
+ <string name="permdesc_forceBack">"Permite a uma aplicação forçar qualquer actividade em primeiro plano a fechar e retroceder. Nunca deve ser necessário para aplicações normais."</string>
+ <string name="permlab_dump">"obter estado interno do sistema"</string>
+ <string name="permdesc_dump">"Permite à aplicação obter o estado interno do sistema. Algumas aplicações maliciosas podem obter uma ampla variedade de dados privados e seguros de que, normalmente, nunca devem necessitar."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"monitorizar a controlar a iniciação de todas as aplicações"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Permite a uma aplicação monitorizar e controlar a forma como o sistema inicia actividades. Algumas aplicações maliciosas podem comprometer totalmente o sistema. Esta autorização apenas é necessária para desenvolvimento, nunca para a utilização normal do telefone."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar difusão de pacote removido"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Permite a uma aplicação difundir uma notificação de que foi removido um pacote de aplicações. Algumas aplicações maliciosas podem utilizar este item para eliminar qualquer outra aplicação em execução."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"enviar difusão recebida por SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Permite a uma aplicação difundir uma notificação de que foi recebida uma mensagem SMS. Algumas aplicações maliciosas podem utilizar este item para falsificar mensagens SMS a receber."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar difusão recebida através de PUSH WAP"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Permite a uma aplicação difundir uma notificação de que foi recebida uma mensagens PUSH WAP. Algumas aplicações maliciosas podem utilizar este item para falsificar um recibo de mensagem MMS ou substituir, de forma silenciosa, o conteúdo de qualquer página Web por variantes maliciosas."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"número limite de processos em execução"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Permite a um aplicação controlar o número máximo de processos que será executado. Nunca é necessário para aplicações normais."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"fazer com que todas as aplicações de fundo fechem"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Permite a uma aplicação controlar se as actividades são sempre terminadas assim que passam para o fundo. Nunca é necessário para aplicações normais."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"modificar estatísticas da bateria"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Permite a modificação das estatísticas recolhidas sobre a bateria. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_runSetActivityWatcher">"monitorizar a controlar a iniciação de todas as aplicações"</string>
+ <string name="permdesc_runSetActivityWatcher">"Permite a uma aplicação monitorizar e controlar a forma como o sistema inicia actividades. Algumas aplicações maliciosas podem comprometer totalmente o sistema. Esta autorização apenas é necessária para desenvolvimento, nunca para a utilização normal do telefone."</string>
+ <string name="permlab_broadcastPackageRemoved">"enviar difusão de pacote removido"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Permite a uma aplicação difundir uma notificação de que foi removido um pacote de aplicações. Algumas aplicações maliciosas podem utilizar este item para eliminar qualquer outra aplicação em execução."</string>
+ <string name="permlab_broadcastSmsReceived">"enviar difusão recebida por SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Permite a uma aplicação difundir uma notificação de que foi recebida uma mensagem SMS. Algumas aplicações maliciosas podem utilizar este item para falsificar mensagens SMS a receber."</string>
+ <string name="permlab_broadcastWapPush">"enviar difusão recebida através de PUSH WAP"</string>
+ <string name="permdesc_broadcastWapPush">"Permite a uma aplicação difundir uma notificação de que foi recebida uma mensagens PUSH WAP. Algumas aplicações maliciosas podem utilizar este item para falsificar um recibo de mensagem MMS ou substituir, de forma silenciosa, o conteúdo de qualquer página Web por variantes maliciosas."</string>
+ <string name="permlab_setProcessLimit">"número limite de processos em execução"</string>
+ <string name="permdesc_setProcessLimit">"Permite a um aplicação controlar o número máximo de processos que será executado. Nunca é necessário para aplicações normais."</string>
+ <string name="permlab_setAlwaysFinish">"fazer com que todas as aplicações de fundo fechem"</string>
+ <string name="permdesc_setAlwaysFinish">"Permite a uma aplicação controlar se as actividades são sempre terminadas assim que passam para o fundo. Nunca é necessário para aplicações normais."</string>
+ <string name="permlab_batteryStats">"modificar estatísticas da bateria"</string>
+ <string name="permdesc_batteryStats">"Permite a modificação das estatísticas recolhidas sobre a bateria. Não se destina a utilização por aplicações normais."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"apresentar janelas não autorizadas"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite a criação de janelas destinadas a utilização pela interface de utilizador interna do sistema. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"apresentar alertas ao nível do sistema"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Permite a um aplicação mostrar janelas de alerta do sistema. Algumas aplicações maliciosas podem ocupar todo o ecrã do telefone."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar velocidade global da animação"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Permite a uma aplicação mudar a velocidade global da animação (animações mais rápidas ou mais lentas) em qualquer altura."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"gerir tokens de aplicações"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Permite a aplicações criar e gerir os seus próprios tokens, ignorando a ordenação normal dos mesmos pelo eixo dos Z. Nunca deve ser necessário para aplicações normais."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"premir teclas e botões de controlo"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Permite a uma aplicação fornecer os seus próprios eventos de entrada (toques em teclas, etc.) a outras aplicações. Algumas aplicações maliciosas podem utilizar este item para controlar o telefone."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"gravar o que utilizador escreve e as acções que efectua"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Permite às aplicações verificar as teclas que o utilizador prime, mesmo ao interagir com outras aplicações (como, por exemplo, ao introduzir uma palavra-passe). Nunca deve ser necessário para aplicações normais."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a um método de entrada"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permite ao titular vincular a interface de nível superior a um método de entrada de som. Nunca deve ser necessário para aplicações normais."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"mudar orientação do ecrã"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite a uma aplicação mudar a rotação do ecrã em qualquer momento. Nunca deve ser necessário para aplicações normais."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar sinais Linux para aplicações"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite à aplicação pedir que o sinal fornecido seja enviado a todos os processos persistentes."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"fazer com que a aplicação seja sempre executada"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Permite a uma aplicação tornar persistentes partes da mesma, para que o sistema não possa utilizá-la para outras aplicações."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"eliminar aplicações"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Permite a uma aplicação eliminar pacotes do Android. Algumas aplicações maliciosas podem utilizar este item para eliminar aplicações importantes."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"eliminar dados de outras aplicações"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Permite a uma aplicação limpar dados do proprietário."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"eliminar caches de outras aplicações"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Permite a uma aplicação eliminar ficheiros em cache."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"medir espaço de armazenamento da aplicação"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Permite a uma aplicação obter os respectivos código, dados e tamanhos de cache"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicações directamente"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Permite a uma aplicação instalar pacotes novos ou actualizados do Android. Algumas aplicações maliciosas podem utilizar este item para adicionar novas aplicações com autorizações arbitrariamente fortes."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos os dados da aplicações"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite a uma aplicação libertar espaço de armazenamento no telefone eliminando ficheiros no directório da cache da aplicação. Geralmente, o acesso é muito limitado para processamento do sistema."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"ler ficheiros de registo do sistema"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Permite a uma aplicação ler a partir dos diversos ficheiros de registo do sistema. Isto permite descobrir informações gerais sobre a forma como o utilizador usa o telefone, mas estas não devem conter quaisquer dados pessoais ou privados."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite a uma aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag. Por exemplo, ficheiros em /dev. Isto pode afectar potencialmente a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"activar ou desactivar componentes da aplicação"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Permite a uma aplicação mudar a opção de activar ou não um componente de outra aplicação. Algumas aplicações maliciosas podem utilizar este item para desactivar funcionalidades importantes do telefone. É necessário ter cuidado com a autorização, uma vez que é possível tornar alguns componentes de aplicações num estado inutilizável, inconsistente ou instável."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"definir aplicações preferidas"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Permite a uma aplicação modificar as suas aplicações preferidas. Isto pode permitir que algumas aplicações maliciosas mudem, de forma silenciosa, as aplicações executadas, falsificando as aplicações existentes para recolher os seus dados privados."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modificar definições globais do sistema"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Permite a uma aplicação modificar os dados das definições do sistema. Algumas aplicações maliciosas podem danificar as configurações do sistema."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificar definições seguras do sistema"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Permite a uma aplicação modificar os dados de definições seguras dos sistemas. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"modificar o mapa de serviços do Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Permite a uma aplicação modificar o mapa de serviços do Google. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"iniciar automaticamente no arranque"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Permite que uma aplicação se inicie automaticamente assim que tiver terminado o arranque do sistema. Isto pode demorar o início do telefone e permitir à aplicação abrandar todo o funcionamento do telefone, uma vez que está em constante execução."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar difusão fixa"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Permite a uma aplicação enviar difusões fixas, que permanecem após o fim da difusão. Algumas aplicações maliciosas podem tornar o telefone lento ou instável, fazendo com que utilize demasiada memória."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"ler dados de contacto"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Permite a uma aplicação ler todos os dados de contactos (endereços) armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para enviar os seus dados a outras pessoas."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"escrever dados de contacto"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Permite a uma aplicação modificar os dados de contacto (endereço) armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar estes dados para apagar ou modificar os dados dos seus contactos."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"escrever dados do proprietário"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Permite a uma aplicação modificar os dados do proprietário do telefone armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para apagar ou modificar dados do proprietário."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"ler dados do proprietário"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Permite a uma aplicação modificar os dados do proprietário do telefone armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para ler dados do proprietário do telefone."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"ler dados do calendário"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Permite a uma aplicação ler todos os eventos do calendário armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para enviar os eventos do seu calendário a outras pessoas."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"escrever dados do calendário"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Permite a uma aplicação modificar os eventos do calendário armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para apagar ou modificar os dados do seu calendário."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fontes de localização fictícias para teste"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Crie fontes de localização fictícias para fins de teste. Algumas aplicações maliciosas podem utilizar este item para substituir a localização e/ou o estado devolvido por fontes de localização reais, tais como fornecedores de GPS ou de Rede."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"aceder a comandos adicionais do fornecedor de localização"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Aceda a comandos adicionais do fornecedor de localização. Algumas aplicações maliciosas podem utilizar este item para interferir com o funcionamento do GPS ou de outras fontes de localização."</string>
+ <string name="permlab_internalSystemWindow">"apresentar janelas não autorizadas"</string>
+ <string name="permdesc_internalSystemWindow">"Permite a criação de janelas destinadas a utilização pela interface de utilizador interna do sistema. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_systemAlertWindow">"apresentar alertas ao nível do sistema"</string>
+ <string name="permdesc_systemAlertWindow">"Permite a um aplicação mostrar janelas de alerta do sistema. Algumas aplicações maliciosas podem ocupar todo o ecrã do telefone."</string>
+ <string name="permlab_setAnimationScale">"modificar velocidade global da animação"</string>
+ <string name="permdesc_setAnimationScale">"Permite a uma aplicação mudar a velocidade global da animação (animações mais rápidas ou mais lentas) em qualquer altura."</string>
+ <string name="permlab_manageAppTokens">"gerir tokens de aplicações"</string>
+ <string name="permdesc_manageAppTokens">"Permite a aplicações criar e gerir os seus próprios tokens, ignorando a ordenação normal dos mesmos pelo eixo dos Z. Nunca deve ser necessário para aplicações normais."</string>
+ <string name="permlab_injectEvents">"premir teclas e botões de controlo"</string>
+ <string name="permdesc_injectEvents">"Permite a uma aplicação fornecer os seus próprios eventos de entrada (toques em teclas, etc.) a outras aplicações. Algumas aplicações maliciosas podem utilizar este item para controlar o telefone."</string>
+ <string name="permlab_readInputState">"gravar o que utilizador escreve e as acções que efectua"</string>
+ <string name="permdesc_readInputState">"Permite às aplicações verificar as teclas que o utilizador prime, mesmo ao interagir com outras aplicações (como, por exemplo, ao introduzir uma palavra-passe). Nunca deve ser necessário para aplicações normais."</string>
+ <string name="permlab_bindInputMethod">"vincular a um método de entrada"</string>
+ <string name="permdesc_bindInputMethod">"Permite ao titular vincular a interface de nível superior a um método de entrada de som. Nunca deve ser necessário para aplicações normais."</string>
+ <string name="permlab_setOrientation">"mudar orientação do ecrã"</string>
+ <string name="permdesc_setOrientation">"Permite a uma aplicação mudar a rotação do ecrã em qualquer momento. Nunca deve ser necessário para aplicações normais."</string>
+ <string name="permlab_signalPersistentProcesses">"enviar sinais Linux para aplicações"</string>
+ <string name="permdesc_signalPersistentProcesses">"Permite à aplicação pedir que o sinal fornecido seja enviado a todos os processos persistentes."</string>
+ <string name="permlab_persistentActivity">"fazer com que a aplicação seja sempre executada"</string>
+ <string name="permdesc_persistentActivity">"Permite a uma aplicação tornar persistentes partes da mesma, para que o sistema não possa utilizá-la para outras aplicações."</string>
+ <string name="permlab_deletePackages">"eliminar aplicações"</string>
+ <string name="permdesc_deletePackages">"Permite a uma aplicação eliminar pacotes do Android. Algumas aplicações maliciosas podem utilizar este item para eliminar aplicações importantes."</string>
+ <string name="permlab_clearAppUserData">"eliminar dados de outras aplicações"</string>
+ <string name="permdesc_clearAppUserData">"Permite a uma aplicação limpar dados do proprietário."</string>
+ <string name="permlab_deleteCacheFiles">"eliminar caches de outras aplicações"</string>
+ <string name="permdesc_deleteCacheFiles">"Permite a uma aplicação eliminar ficheiros em cache."</string>
+ <string name="permlab_getPackageSize">"medir espaço de armazenamento da aplicação"</string>
+ <string name="permdesc_getPackageSize">"Permite a uma aplicação obter os respectivos código, dados e tamanhos de cache"</string>
+ <string name="permlab_installPackages">"instalar aplicações directamente"</string>
+ <string name="permdesc_installPackages">"Permite a uma aplicação instalar pacotes novos ou actualizados do Android. Algumas aplicações maliciosas podem utilizar este item para adicionar novas aplicações com autorizações arbitrariamente fortes."</string>
+ <string name="permlab_clearAppCache">"eliminar todos os dados da aplicações"</string>
+ <string name="permdesc_clearAppCache">"Permite a uma aplicação libertar espaço de armazenamento no telefone eliminando ficheiros no directório da cache da aplicação. Geralmente, o acesso é muito limitado para processamento do sistema."</string>
+ <string name="permlab_readLogs">"ler ficheiros de registo do sistema"</string>
+ <string name="permdesc_readLogs">"Permite a uma aplicação ler a partir dos diversos ficheiros de registo do sistema. Isto permite descobrir informações gerais sobre a forma como o utilizador usa o telefone, mas estas não devem conter quaisquer dados pessoais ou privados."</string>
+ <string name="permlab_diagnostic">"ler/escrever em recursos propriedade de diag"</string>
+ <string name="permdesc_diagnostic">"Permite a uma aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag. Por exemplo, ficheiros em /dev. Isto pode afectar potencialmente a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
+ <string name="permlab_changeComponentState">"activar ou desactivar componentes da aplicação"</string>
+ <string name="permdesc_changeComponentState">"Permite a uma aplicação mudar a opção de activar ou não um componente de outra aplicação. Algumas aplicações maliciosas podem utilizar este item para desactivar funcionalidades importantes do telefone. É necessário ter cuidado com a autorização, uma vez que é possível tornar alguns componentes de aplicações num estado inutilizável, inconsistente ou instável."</string>
+ <string name="permlab_setPreferredApplications">"definir aplicações preferidas"</string>
+ <string name="permdesc_setPreferredApplications">"Permite a uma aplicação modificar as suas aplicações preferidas. Isto pode permitir que algumas aplicações maliciosas mudem, de forma silenciosa, as aplicações executadas, falsificando as aplicações existentes para recolher os seus dados privados."</string>
+ <string name="permlab_writeSettings">"modificar definições globais do sistema"</string>
+ <string name="permdesc_writeSettings">"Permite a uma aplicação modificar os dados das definições do sistema. Algumas aplicações maliciosas podem danificar as configurações do sistema."</string>
+ <string name="permlab_writeSecureSettings">"modificar definições seguras do sistema"</string>
+ <string name="permdesc_writeSecureSettings">"Permite a uma aplicação modificar os dados de definições seguras dos sistemas. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_writeGservices">"modificar o mapa de serviços do Google"</string>
+ <string name="permdesc_writeGservices">"Permite a uma aplicação modificar o mapa de serviços do Google. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_receiveBootCompleted">"iniciar automaticamente no arranque"</string>
+ <string name="permdesc_receiveBootCompleted">"Permite que uma aplicação se inicie automaticamente assim que tiver terminado o arranque do sistema. Isto pode demorar o início do telefone e permitir à aplicação abrandar todo o funcionamento do telefone, uma vez que está em constante execução."</string>
+ <string name="permlab_broadcastSticky">"enviar difusão fixa"</string>
+ <string name="permdesc_broadcastSticky">"Permite a uma aplicação enviar difusões fixas, que permanecem após o fim da difusão. Algumas aplicações maliciosas podem tornar o telefone lento ou instável, fazendo com que utilize demasiada memória."</string>
+ <string name="permlab_readContacts">"ler dados de contacto"</string>
+ <string name="permdesc_readContacts">"Permite a uma aplicação ler todos os dados de contactos (endereços) armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para enviar os seus dados a outras pessoas."</string>
+ <string name="permlab_writeContacts">"escrever dados de contacto"</string>
+ <string name="permdesc_writeContacts">"Permite a uma aplicação modificar os dados de contacto (endereço) armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar estes dados para apagar ou modificar os dados dos seus contactos."</string>
+ <string name="permlab_writeOwnerData">"escrever dados do proprietário"</string>
+ <string name="permdesc_writeOwnerData">"Permite a uma aplicação modificar os dados do proprietário do telefone armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para apagar ou modificar dados do proprietário."</string>
+ <string name="permlab_readOwnerData">"ler dados do proprietário"</string>
+ <string name="permdesc_readOwnerData">"Permite a uma aplicação modificar os dados do proprietário do telefone armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para ler dados do proprietário do telefone."</string>
+ <string name="permlab_readCalendar">"ler dados do calendário"</string>
+ <string name="permdesc_readCalendar">"Permite a uma aplicação ler todos os eventos do calendário armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para enviar os eventos do seu calendário a outras pessoas."</string>
+ <string name="permlab_writeCalendar">"escrever dados do calendário"</string>
+ <string name="permdesc_writeCalendar">"Permite a uma aplicação modificar os eventos do calendário armazenados no seu telefone. Algumas aplicações maliciosas podem utilizar este item para apagar ou modificar os dados do seu calendário."</string>
+ <string name="permlab_accessMockLocation">"fontes de localização fictícias para teste"</string>
+ <string name="permdesc_accessMockLocation">"Crie fontes de localização fictícias para fins de teste. Algumas aplicações maliciosas podem utilizar este item para substituir a localização e/ou o estado devolvido por fontes de localização reais, tais como fornecedores de GPS ou de Rede."</string>
+ <string name="permlab_accessLocationExtraCommands">"aceder a comandos adicionais do fornecedor de localização"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Aceda a comandos adicionais do fornecedor de localização. Algumas aplicações maliciosas podem utilizar este item para interferir com o funcionamento do GPS ou de outras fontes de localização."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"localização exacta (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Aceder a fontes de localização específicas, tais como o Sistema de Posicionamento Global (GPS), no telefone, se disponível. Algumas aplicações maliciosas podem utilizar este item para determinar a localização do utilizador e podem consumir energia adicional da bateria."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"localização aproximada (baseada na rede)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Aceda a fontes de localização aproximadas, tais como a base de dados da rede celular, para determinar uma localização aproximada do telefone, se disponível. Algumas aplicações maliciosas podem utilizar este item para determinar aproximadamente onde o utilizador se encontra."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"aceder a SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permite às aplicações utilizar funcionalidades de SurfaceFlinger de nível inferior."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ler memória intermédia de fotogramas"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Permite à aplicação ler o conteúdo da memória intermédia de fotogramas."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"alterar as suas definições de áudio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Permite à aplicação modificar as definições de áudio globais, tais como o volume e o encaminhamento."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"gravar áudio"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Permite à aplicação aceder ao caminho de gravação de áudio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"tirar fotografias"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Permite à aplicação tirar fotografias com a câmara. Isto permite que a aplicação recolha imagens captadas pela câmara em qualquer momento."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"desactivar telefone de forma permanente"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Permite à aplicação desactivar permanentemente todo o telefone. Esta acção é muito perigosa."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"forçar reinício do telefone"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Permite à aplicação forçar o reinício do telefone."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar e desmontar sistemas de ficheiros"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permite à aplicação montar e desmontar sistemas de ficheiros para armazenamento removível."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatar armazenamento externo"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Permite a uma aplicação formatar o armazenamento removível."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"controlar vibrador"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Permite à aplicação controlar o vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Permite à aplicação controlar a lanterna."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"testar hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite à aplicação controlar vários periféricos para fins de teste de hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone directamente"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Permite à aplicação marcar números de telefone sem a intervenção do utilizador. Algumas aplicações maliciosas podem provocar o aparecimento de chamadas inesperadas na sua conta telefónica. Tenha em atenção que isto não permite à aplicação marcar números de emergência."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"marcar directamente quaisquer números de telefone"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Permite à aplicação marcar qualquer número de telefone, incluindo números de emergência, sem a intervenção do utilizador. Algumas aplicações maliciosas podem efectuar chamadas desnecessárias e ilegais para serviços de emergência."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar notificações de actualização de localização"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite a activação/desactivação de notificações de actualização de localização a partir do rádio. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"aceder a propriedades de verificação"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Permite acesso de leitura/escrita a propriedades carregadas pelo serviço de verificação. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"escolher miniaplicações"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Permite à aplicação informar o sistema acerca das miniaplicações que podem ser utilizadas com cada aplicação. Com esta autorização, algumas aplicações podem conceder acesso a dados pessoais a outras aplicações. Não se destina a utilização por aplicações normais."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar estado do telefone"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Permite à aplicação controlar as funcionalidades do telefone do dispositivo. Uma aplicação com esta autorização pode alternar entre redes, ligar e desligar o rádio do telefone, etc., sem nunca notificar o utilizador."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"impedir que o telefone entre em inactividade"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Permite a uma aplicação impedir o telefone de entrar em inactividade."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"ligar ou desligar o telefone"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Permite a uma aplicação ligar ou desligar o telefone."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"executar em modo de teste de fábrica"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Executar como um teste de nível inferior do fabricante, permitindo o acesso total ao hardware do telefone. Apenas disponível quando um telefone está em execução em modo de teste do fabricante."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"definir imagem de fundo"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permite à aplicação definir a imagem de fundo do sistema."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"definir sugestões de tamanho da imagem de fundo"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Permitir que a aplicação defina as sugestões de tamanho da imagem de fundo do sistema."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"repor definições de fábrica do sistemas"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Permite a uma aplicação repor totalmente as definições de fábrica do sistema, apagando todos os dados, configurações e aplicações instaladas."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"definir fuso horário"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Permite a uma aplicação mudar o fuso horário do telefone."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"descobrir contas reconhecidas"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Permite a uma aplicação obter a lista de contas reconhecidas pelo telefone."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ver estado da rede"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Permite a uma aplicação ver o estado de todas as redes."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"acesso total à Internet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Permite a uma aplicação criar sockets de rede."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"escrever definições de Nome do ponto de acesso"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Permite a uma aplicaçaõ modificar as definições de APN, tais como Proxy e Porta de qualquer APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"mudar conectividade de rede"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Permite a uma aplicação mudar o estado da conectividade de rede."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"mudar definição de utilização de dados de segundo plano"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Permite a uma aplicação mudar a definição de utilização de dados de segundo plano."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"ver estado de Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Permite a uma aplicação ver as informações acerca do estado do Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"alterar estado de Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite a uma aplicação ligar e desligar de pontos de acesso de Wi-Fi, bem como efectuar alterações a redes Wi-Fi configuradas."</string>
+ <string name="permlab_accessFineLocation">"localização exacta (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Aceder a fontes de localização específicas, tais como o Sistema de Posicionamento Global (GPS), no telefone, se disponível. Algumas aplicações maliciosas podem utilizar este item para determinar a localização do utilizador e podem consumir energia adicional da bateria."</string>
+ <string name="permlab_accessCoarseLocation">"localização aproximada (baseada na rede)"</string>
+ <string name="permdesc_accessCoarseLocation">"Aceda a fontes de localização aproximadas, tais como a base de dados da rede celular, para determinar uma localização aproximada do telefone, se disponível. Algumas aplicações maliciosas podem utilizar este item para determinar aproximadamente onde o utilizador se encontra."</string>
+ <string name="permlab_accessSurfaceFlinger">"aceder a SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Permite às aplicações utilizar funcionalidades de SurfaceFlinger de nível inferior."</string>
+ <string name="permlab_readFrameBuffer">"ler memória intermédia de fotogramas"</string>
+ <string name="permdesc_readFrameBuffer">"Permite·à·aplicação·ler·o·conteúdo·da·memória·intermédia·de·fotogramas."</string>
+ <string name="permlab_modifyAudioSettings">"mudar as suas definições de áudio"</string>
+ <string name="permdesc_modifyAudioSettings">"Permite à aplicação modificar as definições de áudio globais, tais como o volume e o encaminhamento."</string>
+ <string name="permlab_recordAudio">"gravar áudio"</string>
+ <string name="permdesc_recordAudio">"Permite à aplicação aceder ao caminho de gravação de áudio."</string>
+ <string name="permlab_camera">"tirar fotografias"</string>
+ <string name="permdesc_camera">"Permite à aplicação tirar fotografias com a câmara. Isto permite que a aplicação recolha imagens captadas pela câmara em qualquer momento."</string>
+ <string name="permlab_brick">"desactivar telefone de forma permanente"</string>
+ <string name="permdesc_brick">"Permite à aplicação desactivar permanentemente todo o telefone. Esta acção é muito perigosa."</string>
+ <string name="permlab_reboot">"forçar reinício do telefone"</string>
+ <string name="permdesc_reboot">"Permite à aplicação forçar o reinício do telefone."</string>
+ <string name="permlab_mount_unmount_filesystems">"montar e desmontar sistemas de ficheiros"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Permite à aplicação montar e desmontar sistemas de ficheiros para armazenamento removível."</string>
+ <string name="permlab_mount_format_filesystems">"formatar armazenamento externo"</string>
+ <string name="permdesc_mount_format_filesystems">"Permite a uma aplicação formatar o armazenamento removível."</string>
+ <string name="permlab_vibrate">"controlar vibrador"</string>
+ <string name="permdesc_vibrate">"Permite à aplicação controlar o vibrador."</string>
+ <string name="permlab_flashlight">"controlar lanterna"</string>
+ <string name="permdesc_flashlight">"Permite à aplicação controlar a lanterna."</string>
+ <string name="permlab_hardware_test">"testar hardware"</string>
+ <string name="permdesc_hardware_test">"Permite à aplicação controlar vários periféricos para fins de teste de hardware."</string>
+ <string name="permlab_callPhone">"marcar números de telefone directamente"</string>
+ <string name="permdesc_callPhone">"Permite à aplicação marcar números de telefone sem a intervenção do utilizador. Algumas aplicações maliciosas podem provocar o aparecimento de chamadas inesperadas na sua conta telefónica. Tenha em atenção que isto não permite à aplicação marcar números de emergência."</string>
+ <string name="permlab_callPrivileged">"marcar directamente quaisquer números de telefone"</string>
+ <string name="permdesc_callPrivileged">"Permite à aplicação marcar qualquer número de telefone, incluindo números de emergência, sem a intervenção do utilizador. Algumas aplicações maliciosas podem efectuar chamadas desnecessárias e ilegais para serviços de emergência."</string>
+ <string name="permlab_locationUpdates">"controlar notificações de actualização de localização"</string>
+ <string name="permdesc_locationUpdates">"Permite a activação/desactivação de notificações de actualização de localização a partir do rádio. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_checkinProperties">"aceder a propriedades de verificação"</string>
+ <string name="permdesc_checkinProperties">"Permite acesso de leitura/escrita a propriedades carregadas pelo serviço de verificação. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_bindGadget">"escolher miniaplicações"</string>
+ <string name="permdesc_bindGadget">"Permite à aplicação informar o sistema acerca das miniaplicações que podem ser utilizadas com cada aplicação. Com esta autorização, algumas aplicações podem conceder acesso a dados pessoais a outras aplicações. Não se destina a utilização por aplicações normais."</string>
+ <string name="permlab_modifyPhoneState">"modificar estado do telefone"</string>
+ <string name="permdesc_modifyPhoneState">"Permite à aplicação controlar as funcionalidades do telefone do dispositivo. Uma aplicação com esta autorização pode alternar entre redes, ligar e desligar o rádio do telefone, etc., sem nunca notificar o utilizador."</string>
+ <string name="permlab_readPhoneState">"ler estado do telefone"</string>
+ <string name="permdesc_readPhoneState">"Permite à aplicação aceder às funcionalidades do dispositivo. Uma aplicação com esta autorização pode determinar o número deste telefone, se existe uma chamada activa, o número a que a essa chamada está ligada, entre outras."</string>
+ <string name="permlab_wakeLock">"impedir que o telefone entre em inactividade"</string>
+ <string name="permdesc_wakeLock">"Permite a uma aplicação impedir o telefone de entrar em inactividade."</string>
+ <string name="permlab_devicePower">"ligar ou desligar o telefone"</string>
+ <string name="permdesc_devicePower">"Permite a uma aplicação ligar ou desligar o telefone."</string>
+ <string name="permlab_factoryTest">"executar em modo de teste de fábrica"</string>
+ <string name="permdesc_factoryTest">"Executar como um teste de nível inferior do fabricante, permitindo o acesso total ao hardware do telefone. Apenas disponível quando um telefone está em execução em modo de teste do fabricante."</string>
+ <string name="permlab_setWallpaper">"definir imagem de fundo"</string>
+ <string name="permdesc_setWallpaper">"Permite à aplicação definir a imagem de fundo do sistema."</string>
+ <string name="permlab_setWallpaperHints">"definir sugestões de tamanho da imagem de fundo"</string>
+ <string name="permdesc_setWallpaperHints">"Permitir que a aplicação defina as sugestões de tamanho da imagem de fundo do sistema."</string>
+ <string name="permlab_masterClear">"repor definições de fábrica do sistemas"</string>
+ <string name="permdesc_masterClear">"Permite a uma aplicação repor totalmente as definições de fábrica do sistema, apagando todos os dados, configurações e aplicações instaladas."</string>
+ <string name="permlab_setTimeZone">"definir fuso horário"</string>
+ <string name="permdesc_setTimeZone">"Permite a uma aplicação mudar o fuso horário do telefone."</string>
+ <string name="permlab_getAccounts">"descobrir contas reconhecidas"</string>
+ <string name="permdesc_getAccounts">"Permite a uma aplicação obter a lista de contas reconhecidas pelo telefone."</string>
+ <string name="permlab_accessNetworkState">"ver estado da rede"</string>
+ <string name="permdesc_accessNetworkState">"Permite a uma aplicação ver o estado de todas as redes."</string>
+ <string name="permlab_createNetworkSockets">"acesso total à Internet"</string>
+ <string name="permdesc_createNetworkSockets">"Permite a uma aplicação criar sockets de rede."</string>
+ <string name="permlab_writeApnSettings">"escrever definições de Nome do ponto de acesso"</string>
+ <string name="permdesc_writeApnSettings">"Permite a uma aplicaçaõ modificar as definições de APN, tais como Proxy e Porta de qualquer APN."</string>
+ <string name="permlab_changeNetworkState">"mudar conectividade de rede"</string>
+ <string name="permdesc_changeNetworkState">"Permite a uma aplicação mudar o estado da conectividade de rede."</string>
+ <string name="permlab_changeBackgroundDataSetting">"mudar definição de utilização de dados de segundo plano"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Permite a uma aplicação mudar a definição de utilização de dados de segundo plano."</string>
+ <string name="permlab_accessWifiState">"ver estado de Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Permite a uma aplicação ver as informações acerca do estado do Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"mudar estado de Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Permite a uma aplicação ligar e desligar de pontos de acesso de Wi-Fi, bem como efectuar alterações a redes Wi-Fi configuradas."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administração de Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permite a uma aplicação configurar o telefone Bluetooth local, bem como descobrir e emparelhar com dispositivos remotos."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"criar ligações Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Permite a uma aplicação ver a configuração do telefone Bluetooth local, bem como efectuar e aceitar ligações com dispositivos emparelhados."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"desactivar bloqueio de teclas"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permite a uma aplicação desactivar o bloqueio de teclas e qualquer segurança por palavra-passe associada. Um exemplo legítimo é a desactivação do bloqueio de teclas pelo telefone ao receber uma chamada, reactivando, em seguida, o bloqueio de teclas ao terminar a chamada."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler definições de sincronização"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Permite a uma aplicação ler as definições de sincronização como, por exemplo, se a sincronização está activada para Contactos."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"definições de sincronização de escrita"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Permite a uma aplicação modificar as definições de sincronização como, por exemplo, se a sincronização está activada para Contactos."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"ler estatísticas de sincronização"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Permite a uma aplicação ler as estatísticas de sincronização, por exemplo, o histórico de sincronizações ocorridas."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds subscritos"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Permite a uma aplicação obter detalhes acerca dos feeds actualmente sincronizados."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"escrever feeds subscritos"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Permite a uma aplicação modificar os seus feeds actualmente sincronizados. Isto pode permitir a uma aplicação maliciosa alterar os seus feeds sincronizados."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"ler dicionário definido pelo utilizador"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Permite a uma aplicação ler quaisquer palavras, nomes e expressões privadas que o utilizador possa ter armazenado no dicionário do utilizador."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"escrever no dicionário definido pelo utilizador"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Permite a uma aplicação escrever novas palavras no dicionário do utilizador."</string>
+ <string name="permlab_bluetoothAdmin">"administração de bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Permite a uma aplicação configurar o telefone Bluetooth local, bem como descobrir e emparelhar com dispositivos remotos."</string>
+ <string name="permlab_bluetooth">"criar ligações Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Permite a uma aplicação ver a configuração do telefone Bluetooth local, bem como efectuar e aceitar ligações com dispositivos emparelhados."</string>
+ <string name="permlab_disableKeyguard">"desactivar bloqueio de teclas"</string>
+ <string name="permdesc_disableKeyguard">"Permite a uma aplicação desactivar o bloqueio de teclas e qualquer segurança por palavra-passe associada. Um exemplo legítimo é a desactivação do bloqueio de teclas pelo telefone ao receber uma chamada, reactivando, em seguida, o bloqueio de teclas ao terminar a chamada."</string>
+ <string name="permlab_readSyncSettings">"ler definições de sincronização"</string>
+ <string name="permdesc_readSyncSettings">"Permite a uma aplicação ler as definições de sincronização como, por exemplo, se a sincronização está activada para Contactos."</string>
+ <string name="permlab_writeSyncSettings">"definições de sincronização de escrita"</string>
+ <string name="permdesc_writeSyncSettings">"Permite a uma aplicação modificar as definições de sincronização como, por exemplo, se a sincronização está activada para Contactos."</string>
+ <string name="permlab_readSyncStats">"ler estatísticas de sincronização"</string>
+ <string name="permdesc_readSyncStats">"Permite a uma aplicação ler as estatísticas de sincronização, por exemplo, o histórico de sincronizações ocorridas."</string>
+ <string name="permlab_subscribedFeedsRead">"ler feeds subscritos"</string>
+ <string name="permdesc_subscribedFeedsRead">"Permite a uma aplicação obter detalhes acerca dos feeds actualmente sincronizados."</string>
+ <string name="permlab_subscribedFeedsWrite">"escrever feeds subscritos"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Permite a uma aplicação modificar os seus feeds actualmente sincronizados. Isto pode permitir a uma aplicação maliciosa alterar os seus feeds sincronizados."</string>
+ <string name="permlab_readDictionary">"ler dicionário definido pelo utilizador"</string>
+ <string name="permdesc_readDictionary">"Permite a uma aplicação ler quaisquer palavras, nomes e expressões privadas que o utilizador possa ter armazenado no dicionário do utilizador."</string>
+ <string name="permlab_writeDictionary">"escrever no dicionário definido pelo utilizador"</string>
+ <string name="permdesc_writeDictionary">"Permite a uma aplicação escrever novas palavras no dicionário do utilizador."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Residência"</item>
- <item msgid="869923650527136615">"Móvel"</item>
- <item msgid="7897544654242874543">"Emprego"</item>
- <item msgid="1103601433382158155">"Fax do emprego"</item>
- <item msgid="1735177144948329370">"Fax da residência"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Outro"</item>
- <item msgid="9192514806975898961">"Personalizado"</item>
+ <item>"Residência"</item>
+ <item>"Móvel"</item>
+ <item>"Emprego"</item>
+ <item>"Fax do emprego"</item>
+ <item>"Fax da residência"</item>
+ <item>"Pager"</item>
+ <item>"Outro"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Residência"</item>
- <item msgid="7084237356602625604">"Emprego"</item>
- <item msgid="1112044410659011023">"Outro"</item>
- <item msgid="2374913952870110618">"Personalizado"</item>
+ <item>"Residência"</item>
+ <item>"Emprego"</item>
+ <item>"Outro"</item>
+ <item>"Personalizado"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Móvel"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Residência"</item>
- <item msgid="5629153956045109251">"Emprego"</item>
- <item msgid="4966604264500343469">"Outro"</item>
- <item msgid="4932682847595299369">"Personalizado"</item>
+ <item>"Residência"</item>
+ <item>"Emprego"</item>
+ <item>"Outro"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Residência"</item>
- <item msgid="1359644565647383708">"Emprego"</item>
- <item msgid="7868549401053615677">"Outro"</item>
- <item msgid="3145118944639869809">"Personalizado"</item>
+ <item>"Residência"</item>
+ <item>"Emprego"</item>
+ <item>"Outro"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Emprego"</item>
- <item msgid="4378074129049520373">"Outro"</item>
- <item msgid="3455047468583965104">"Personalizado"</item>
+ <item>"Emprego"</item>
+ <item>"Outro"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Introduzir código PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Código PIN incorrecto!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, prima Menu e, em seguida, 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergência"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Nenhum serviço)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ecrã bloqueado."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Prima Menu para desbloquear ou efectuar uma chamada de emergência."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Prima Menu para desbloquear."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenhar padrão para desbloquear"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Chamada de emergência"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correcto!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Lamentamos, tente novamente"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"A carregar (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Introduzir código PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Código PIN incorrecto!"</string>
+ <string name="keyguard_label_text">"Para desbloquear, prima Menu e, em seguida, 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Número de emergência"</string>
+ <string name="lockscreen_carrier_default">"(Nenhum serviço)"</string>
+ <string name="lockscreen_screen_locked">"Ecrã bloqueado."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Prima Menu para desbloquear ou efectuar uma chamada de emergência."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Prima Menu para desbloquear."</string>
+ <string name="lockscreen_pattern_instructions">"Desenhar padrão para desbloquear"</string>
+ <string name="lockscreen_emergency_call">"Chamada de emergência"</string>
+ <string name="lockscreen_pattern_correct">"Correcto!"</string>
+ <string name="lockscreen_pattern_wrong">"Lamentamos, tente novamente"</string>
+ <string name="lockscreen_plugged_in">"A carregar (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Ligue o carregador."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Nenhum cartão SIM."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Nenhum cartão SIM no telefone."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Introduza um cartão SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rede bloqueada"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"O cartão SIM está bloqueado por PUK"</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Consulte o Manual de utilizador ou contacte a Assistência a clientes."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O cartão SIM está bloqueado."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"A desbloquear cartão SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após outras <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telefone utilizando o seu início de sessão no Google."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Esqueceu-se do padrão?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Demasiadas tentativas de efectuar o padrão!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Para desbloquear, inicie sessão com a sua Conta Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nome de utilizador (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Palavra-passe"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Iniciar sessão"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nome de utilizador ou palavra-passe inválidos."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Ligue o carregador."</string>
+ <string name="lockscreen_missing_sim_message_short">"Nenhum cartão SIM."</string>
+ <string name="lockscreen_missing_sim_message">"Nenhum cartão SIM no telefone."</string>
+ <string name="lockscreen_missing_sim_instructions">"Introduza um cartão SIM."</string>
+ <string name="lockscreen_network_locked_message">"Rede bloqueada"</string>
+ <string name="lockscreen_sim_puk_locked_message">"O cartão SIM está bloqueado por PUK"</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Consulte o Manual de utilizador ou contacte a Assistência a clientes."</string>
+ <string name="lockscreen_sim_locked_message">"O cartão SIM está bloqueado."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"A desbloquear cartão SIM..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após outras <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telefone utilizando o seu início de sessão no Google."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Esqueceu-se do padrão?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Demasiadas tentativas de efectuar o padrão!"</string>
+ <string name="lockscreen_glogin_instructions">"Para desbloquear, inicie sessão com a sua Conta Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Nome de utilizador (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Palavra-passe"</string>
+ <string name="lockscreen_glogin_submit_button">"Iniciar sessão"</string>
+ <string name="lockscreen_glogin_invalid_input">"Nome de utilizador ou palavra-passe inválidos."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em curso"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"A carregar..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Ligue o carregador"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"A bateria está a ficar fraca:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"resta menos de <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
+ <string name="status_bar_no_notifications_title">"Sem notificações"</string>
+ <string name="status_bar_ongoing_events_title">"Em curso"</string>
+ <string name="status_bar_latest_events_title">"Notificações"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"A carregar..."</string>
+ <string name="battery_low_title">"Ligue o carregador"</string>
+ <string name="battery_low_subtitle">"A bateria está a ficar fraca:"</string>
+ <string name="battery_low_percent_format">"resta menos de <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"O teste de fábrica falhou"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"A acção FACTORY_TEST apenas é suportada para pacotes instalados em /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Não foi localizado qualquer pacote que forneça a acção FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" indica:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Navegar para outra página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Seleccione OK para continuar ou Cancelar para permanecer na página actual."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
+ <string name="factorytest_failed">"O teste de fábrica falhou"</string>
+ <string name="factorytest_not_system">"A acção FACTORY_TEST apenas é suportada para pacotes instalados em /system/app."</string>
+ <string name="factorytest_no_action">"Não foi localizado qualquer pacote que forneça a acção FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Reiniciar"</string>
+ <string name="js_dialog_title">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" indica:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Navegar para outra página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Seleccione OK para continuar ou Cancelar para permanecer na página actual."</string>
+ <string name="save_password_label">"Confirmar"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Quer que o browser memorize esta palavra-passe?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nunca"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Não tem autorização para abrir esta página."</string>
- <string name="text_copied" msgid="4985729524670131385">"Texto copiado para a área de transferência."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Mais"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"espaço"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"introduzir"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"eliminar"</string>
- <string name="search_go" msgid="8298016669822141719">"Pesquisar"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"Há 1 mês"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Há mais de 1 mês"</string>
+ <string name="save_password_message">"Quer que o browser memorize esta palavra-passe?"</string>
+ <string name="save_password_notnow">"Agora não"</string>
+ <string name="save_password_remember">"Lembrar"</string>
+ <string name="save_password_never">"Nunca"</string>
+ <string name="open_permission_deny">"Não tem autorização para abrir esta página."</string>
+ <string name="text_copied">"Texto copiado para a área de transferência."</string>
+ <string name="more_item_label">"Mais"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"espaço"</string>
+ <string name="menu_enter_shortcut_label">"introduzir"</string>
+ <string name="menu_delete_shortcut_label">"eliminar"</string>
+ <string name="search_go">"Pesquisar"</string>
+ <string name="oneMonthDurationPast">"Há 1 mês"</string>
+ <string name="beforeOneMonthDurationPast">"Há·mais·de·1·mês"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"Há 1 segundo"</item>
- <item quantity="other" msgid="3903706804349556379">"Há <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"Há 1 segundo"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"Há 1 minuto"</item>
- <item quantity="other" msgid="2176942008915455116">"Há <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"Há 1 minuto"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"Há 1 hora"</item>
- <item quantity="other" msgid="2467273239587587569">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"Há 1 hora"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ontem"</item>
- <item quantity="other" msgid="2479586466153314633">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"ontem"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"daqui a 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"daqui a <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"daqui a 1 segundo"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"daqui a 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"daqui a <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"daqui a 1 minuto"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"daqui a 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"daqui a <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"daqui a 1 hora"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"amanhã"</item>
- <item quantity="other" msgid="5109449375100953247">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"amanhã"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"Há 1 seg"</item>
- <item quantity="other" msgid="3699169366650930415">"Há <xliff:g id="COUNT">%d</xliff:g> seg"</item>
+ <item quantity="one">"Há 1 seg"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> seg"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"há 1 min"</item>
- <item quantity="other" msgid="851164968597150710">"Há <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ <item quantity="one">"há 1 min"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> min"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"Há 1 hora"</item>
- <item quantity="other" msgid="6889970745748538901">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"Há 1 hora"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ontem"</item>
- <item quantity="other" msgid="3453342639616481191">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"ontem"</item>
+ <item quantity="other">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"daqui a 1 seg"</item>
- <item quantity="other" msgid="5495880108825805108">"daqui a <xliff:g id="COUNT">%d</xliff:g> seg"</item>
+ <item quantity="one">"daqui a 1 seg"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> seg"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"daqui a 1 min"</item>
- <item quantity="other" msgid="4216113292706568726">"daqui a <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ <item quantity="one">"daqui a 1 min"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> min"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"daqui a 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"daqui a 1 hora"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"amanhã"</item>
- <item quantity="other" msgid="2973062968038355991">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"amanhã"</item>
+ <item quantity="other">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"a %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"às %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"em %s"</string>
- <string name="day" msgid="8144195776058119424">"dia"</string>
- <string name="days" msgid="4774547661021344602">"dias"</string>
- <string name="hour" msgid="2126771916426189481">"hora"</string>
- <string name="hours" msgid="894424005266852993">"horas"</string>
- <string name="minute" msgid="9148878657703769868">"minutos"</string>
- <string name="minutes" msgid="5646001005827034509">"min"</string>
- <string name="second" msgid="3184235808021478">"seg"</string>
- <string name="seconds" msgid="3161515347216589235">"seg"</string>
- <string name="week" msgid="5617961537173061583">"semana"</string>
- <string name="weeks" msgid="6509623834583944518">"semanas"</string>
- <string name="year" msgid="4001118221013892076">"ano"</string>
- <string name="years" msgid="6881577717993213522">"anos"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Todos os dias úteis (Seg-Sex)"</string>
- <string name="daily" msgid="5738949095624133403">"Diariamente"</string>
- <string name="weekly" msgid="983428358394268344">"Semanalmente à/ao <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Mensalmente"</string>
- <string name="yearly" msgid="1519577999407493836">"Anualmente"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Impossível reproduzir vídeo"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Lamentamos, este vídeo não é válido para transmissão em sequência neste dispositivo."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Lamentamos, não é possível reproduzir este vídeo."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"meio-dia"</string>
- <string name="Noon" msgid="3342127745230013127">"Meio-dia"</string>
- <string name="midnight" msgid="7166259508850457595">"meia-noite"</string>
- <string name="Midnight" msgid="5630806906897892201">"Meia-noite"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Seleccionar tudo"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Parar selecção de texto"</string>
- <string name="cut" msgid="3092569408438626261">"Cortar"</string>
- <string name="cutAll" msgid="2436383270024931639">"Cortar tudo"</string>
- <string name="copy" msgid="2681946229533511987">"Copiar"</string>
- <string name="copyAll" msgid="2590829068100113057">"Copiar tudo"</string>
- <string name="paste" msgid="5629880836805036433">"Colar"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Método de entrada"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Adicionar \"%s\" ao dicionário"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Editar texto"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Pouco espaço livre"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"O espaço de armazenamento do telefone está a ficar reduzido."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
- <string name="capital_on" msgid="1544682755514494298">"Activado"</string>
- <string name="capital_off" msgid="6815870386972805832">"Desactivar"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Concluir acção utilizando"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Utilizar por predefinição para esta acção."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Limpar predefinição em Definições iniciais &gt; Aplicações &gt; Gerir aplicações."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Seleccionar uma acção"</string>
- <string name="noApplications" msgid="1691104391758345586">"Nenhuma aplicação pode efectuar esta acção."</string>
- <string name="aerr_title" msgid="653922989522758100">"Lamentamos."</string>
- <string name="aerr_application" msgid="4683614104336409186">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou de forma inesperada. Tente novamente."</string>
- <string name="aerr_process" msgid="1551785535966089511">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> parou de forma inesperada. Tente novamente."</string>
- <string name="anr_title" msgid="3100070910664756057">"Lamentamos!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"A actividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (na aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>) não está a responder."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"A actividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está a responder."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está a responder."</string>
- <string name="anr_process" msgid="1246866008169975783">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está a responder."</string>
- <string name="force_close" msgid="3653416315450806396">"Forçar fecho"</string>
+ <string name="preposition_for_date">"a %s"</string>
+ <string name="preposition_for_time">"às %s"</string>
+ <string name="preposition_for_year">"em %s"</string>
+ <string name="day">"dia"</string>
+ <string name="days">"dias"</string>
+ <string name="hour">"hora"</string>
+ <string name="hours">"horas"</string>
+ <string name="minute">"minutos"</string>
+ <string name="minutes">"min"</string>
+ <string name="second">"seg"</string>
+ <string name="seconds">"seg"</string>
+ <string name="week">"semana"</string>
+ <string name="weeks">"semanas"</string>
+ <string name="year">"ano"</string>
+ <string name="years">"anos"</string>
+ <string name="every_weekday">"Todos os dias úteis (Seg-Sex)"</string>
+ <string name="daily">"Diariamente"</string>
+ <string name="weekly">"Semanalmente à/ao <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Mensalmente"</string>
+ <string name="yearly">"Anualmente"</string>
+ <string name="VideoView_error_title">"Impossível reproduzir vídeo"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Lamentamos, este vídeo não é válido para transmissão em sequência neste dispositivo."</string>
+ <string name="VideoView_error_text_unknown">"Lamentamos, não é possível reproduzir este vídeo."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"meio-dia"</string>
+ <string name="Noon">"Meio-dia"</string>
+ <string name="midnight">"meia-noite"</string>
+ <string name="Midnight">"Meia-noite"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Seleccionar tudo"</string>
+ <string name="selectText">"Seleccionar texto"</string>
+ <string name="stopSelectingText">"Parar selecção de texto"</string>
+ <string name="cut">"Cortar"</string>
+ <string name="cutAll">"Cortar tudo"</string>
+ <string name="copy">"Copiar"</string>
+ <string name="copyAll">"Copiar tudo"</string>
+ <string name="paste">"Colar"</string>
+ <string name="copyUrl">"Copiar URL"</string>
+ <string name="inputMethod">"Método de entrada"</string>
+ <string name="addToDictionary">"Adicionar \"%s\" ao dicionário"</string>
+ <string name="editTextMenuTitle">"Editar texto"</string>
+ <string name="low_internal_storage_view_title">"Pouco espaço livre"</string>
+ <string name="low_internal_storage_view_text">"O espaço de armazenamento do telefone está a ficar reduzido."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Cancelar"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Cancelar"</string>
+ <string name="dialog_alert_title">"Atenção"</string>
+ <string name="capital_on">"Activado"</string>
+ <string name="capital_off">"Desactivar"</string>
+ <string name="whichApplication">"Concluir acção utilizando"</string>
+ <string name="alwaysUse">"Utilizar por predefinição para esta acção."</string>
+ <string name="clearDefaultHintMsg">"Limpar predefinição em Definições iniciais &gt; Aplicações &gt; Gerir aplicações."</string>
+ <string name="chooseActivity">"Seleccionar uma acção"</string>
+ <string name="noApplications">"Nenhuma aplicação pode efectuar esta acção."</string>
+ <string name="aerr_title">"Lamentamos."</string>
+ <string name="aerr_application">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou de forma inesperada. Tente novamente."</string>
+ <string name="aerr_process">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> parou de forma inesperada. Tente novamente."</string>
+ <string name="anr_title">"Lamentamos!"</string>
+ <string name="anr_activity_application">"A actividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (na aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>) não está a responder."</string>
+ <string name="anr_activity_process">"A actividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está a responder."</string>
+ <string name="anr_application_process">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está a responder."</string>
+ <string name="anr_process">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está a responder."</string>
+ <string name="force_close">"Forçar fecho"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Esperar"</string>
- <string name="debug" msgid="9103374629678531849">"Depuração"</string>
- <string name="sendText" msgid="5132506121645618310">"Seleccionar uma acção para texto"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volume de multimédia"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"A reproduzir através de Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volume da chamada recebida"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume de chamada recebida em Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volume do alarme"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volume de notificações"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Toque predefinido"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Toque predefinido (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silencioso"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string>
+ <string name="wait">"Esperar"</string>
+ <string name="debug">"Depuração"</string>
+ <string name="sendText">"Seleccionar uma acção para texto"</string>
+ <string name="volume_ringtone">"Volume da campainha"</string>
+ <string name="volume_music">"Volume de multimédia"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"A reproduzir através de Bluetooth"</string>
+ <string name="volume_call">"Volume da chamada recebida"</string>
+ <string name="volume_bluetooth_call">"Volume de chamada recebida em Bluetooth"</string>
+ <string name="volume_alarm">"Volume do alarme"</string>
+ <string name="volume_notification">"Volume de notificações"</string>
+ <string name="volume_unknown">"Volume"</string>
+ <string name="ringtone_default">"Toque predefinido"</string>
+ <string name="ringtone_default_with_actual">"Toque predefinido (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silencioso"</string>
+ <string name="ringtone_picker_title">"Toques"</string>
+ <string name="ringtone_unknown">"Toque desconhecido"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Rede Wi-Fi disponível"</item>
- <item quantity="other" msgid="4192424489168397386">"Redes Wi-Fi disponíveis"</item>
+ <item quantity="one">"Rede Wi-Fi disponível"</item>
+ <item quantity="other">"Redes Wi-Fi disponíveis"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Rede Wi-Fi aberta disponível"</item>
- <item quantity="other" msgid="7915895323644292768">"Abrir redes Wi-Fi disponíveis"</item>
+ <item quantity="one">"Rede Wi-Fi aberta disponível"</item>
+ <item quantity="other">"Abrir redes Wi-Fi disponíveis"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Introduzir carácter"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Aplicação desconhecida"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"A enviar mensagens SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Está a ser enviado um grande número de mensagens SMS. Seleccione \"OK\" para continuar ou \"Cancelar\" para parar o envio."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Definir"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Predefinido"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Não são necessárias permissões"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ocultar"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar tudo"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"A carregar..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Ligado através de USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Ligou o telefone ao computador através de USB. Seleccione \"Montar\" se pretender copiar ficheiros entre o computador e o cartão SD do telefone."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Montar"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Não montar"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Existe um problema ao utilizar o cartão SD para armazenamento USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Ligado através de USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Seleccione para copiar ficheiro para/do seu computador."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desactivar armazenamento USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Opte por desactivar o armazenamento USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Desactivar armazenamento USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Antes de desactivar o armazenamento USB, certifique-se de que o desmontou no anfitrião USB. Seleccione \"Desactivar\" para desactivar o armazenamento USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Desactivar"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Cancelar"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Detectámos um problema ao desactivar o armazenamento USB. Verifique para se certificar de que desmontou o anfitrião USB e, em seguida, tente novamente."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatar cartão SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Tem a certeza de que pretende formatar o cartão SD? Perder-se-ão todos os dados no cartão."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatar"</string>
+ <string name="select_character">"Introduzir carácter"</string>
+ <string name="sms_control_default_app_name">"Aplicação desconhecida"</string>
+ <string name="sms_control_title">"A enviar mensagens SMS"</string>
+ <string name="sms_control_message">"Está a ser enviado um grande número de mensagens SMS. Seleccione \"OK\" para continuar ou \"Cancelar\" para parar o envio."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Cancelar"</string>
+ <string name="date_time_set">"Definir"</string>
+ <string name="default_permission_group">"Predefinido"</string>
+ <string name="no_permissions">"Não são necessárias permissões"</string>
+ <string name="perms_hide"><b>"Ocultar"</b></string>
+ <string name="perms_show_all"><b>"Mostrar tudo"</b></string>
+ <string name="googlewebcontenthelper_loading">"A carregar..."</string>
+ <string name="usb_storage_title">"Ligado através de USB"</string>
+ <string name="usb_storage_message">"Ligou o telefone ao computador através de USB. Seleccione \"Montar\" se pretender copiar ficheiros entre o computador e o cartão SD do telefone."</string>
+ <string name="usb_storage_button_mount">"Montar"</string>
+ <string name="usb_storage_button_unmount">"Não montar"</string>
+ <string name="usb_storage_error_message">"Existe um problema ao utilizar o cartão SD para armazenamento USB."</string>
+ <string name="usb_storage_notification_title">"Ligado através de USB"</string>
+ <string name="usb_storage_notification_message">"Seleccione para copiar ficheiro para/do seu computador."</string>
+ <string name="usb_storage_stop_notification_title">"Desactivar armazenamento USB"</string>
+ <string name="usb_storage_stop_notification_message">"Opte por desactivar o armazenamento USB."</string>
+ <string name="usb_storage_stop_title">"Desactivar armazenamento USB"</string>
+ <string name="usb_storage_stop_message">"Antes de desactivar o armazenamento USB, certifique-se de que o desmontou no anfitrião USB. Seleccione \"Desactivar\" para desactivar o armazenamento USB."</string>
+ <string name="usb_storage_stop_button_mount">"Desactivar"</string>
+ <string name="usb_storage_stop_button_unmount">"Cancelar"</string>
+ <string name="usb_storage_stop_error_message">"Detectámos um problema ao desactivar o armazenamento USB. Verifique para se certificar de que desmontou o anfitrião USB e, em seguida, tente novamente."</string>
+ <string name="extmedia_format_title">"Formatar cartão SD"</string>
+ <string name="extmedia_format_message">"Tem a certeza de que pretende formatar o cartão SD? Perder-se-ão todos os dados no cartão."</string>
+ <string name="extmedia_format_button_format">"Formatar"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Seleccionar método de entrada"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"A preparar cartão SD"</string>
+ <string name="select_input_method">"Seleccionar método de entrada"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidatos"</u></string>
+ <string name="ext_media_checking_notification_title">"A preparar cartão SD"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Cartão SD vazio"</string>
+ <string name="ext_media_nofs_notification_title">"Cartão SD vazio"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Cartão SD danificado"</string>
+ <string name="ext_media_unmountable_notification_title">"Cartão SD danificado"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Cartão SD removido de forma inesperada"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Desmonte o cartão SD antes de retirá-lo para evitar a perda de dados."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"É seguro retirar o cartão SD"</string>
+ <string name="ext_media_badremoval_notification_title">"Cartão SD removido de forma inesperada"</string>
+ <string name="ext_media_badremoval_notification_message">"Desmonte o cartão SD antes de retirá-lo para evitar a perda de dados."</string>
+ <string name="ext_media_safe_unmount_notification_title">"É seguro retirar o cartão SD"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Cartão SD removido"</string>
+ <string name="ext_media_nomedia_notification_title">"Cartão SD removido"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Nenhuma actividade correspondente encontrada"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualizar estatísticas de utilização de componentes"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permite a modificação de estatísticas de utilização de componentes recolhidas. Não se destina a utilização por aplicações normais."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tocar duas vezes para controlar o zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Erro ao inchar miniaplicação"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Pesquisar"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Enviar"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Seguinte"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Concluído"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Executar"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Marcar número"\n"utilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Criar contacto"\n"utilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Nenhuma actividade correspondente encontrada"</string>
+ <string name="permlab_pkgUsageStats">"actualizar estatísticas de utilização de componentes"</string>
+ <string name="permdesc_pkgUsageStats">"Permite a modificação de estatísticas de utilização de componentes recolhidas. Não se destina a utilização por aplicações normais."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Tocar duas vezes para controlar o zoom"</string>
+ <string name="gadget_host_error_inflating">"Erro ao inchar miniaplicação"</string>
+ <string name="ime_action_go">"Ir"</string>
+ <string name="ime_action_search">"Pesquisar"</string>
+ <string name="ime_action_send">"Enviar"</string>
+ <string name="ime_action_next">"Seguinte"</string>
+ <string name="ime_action_done">"Concluído"</string>
+ <string name="ime_action_default">"Executar"</string>
+ <string name="dial_number_using">"Marcar número"\n"utilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Criar contacto"\n"utilizando <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index a241e36..4f84872 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"Kb"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"Kb"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"&lt;sem título&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nenhum número de telefone)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Desconhecido)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correio de voz"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Problema de conexão ou código MMI inválido."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"O serviço foi ativado."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"O serviço foi ativado para:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"O serviço foi desativado."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registro bem-sucedido."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Exclusão bem-sucedida."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Senha incorreta."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI concluído."</string>
- <string name="badPin" msgid="5085454289896032547">"O PIN antigo digitado não está correto."</string>
- <string name="badPuk" msgid="5702522162746042460">"O PUK digitado não está correto."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Os PINs digitados não correspondem."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Digite um PIN com 4 a 8 números."</string>
- <string name="needPuk" msgid="919668385956251611">"O seu cartão SIM está bloqueado por um PUK. Digite o código PUK para desbloqueá-lo."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Digite o PUK2 para desbloquear o cartão SIM."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"ID do chamador de entrada"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"ID do chamador de saída"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Encaminhamento de chamada"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Chamada em espera"</string>
- <string name="BaMmi" msgid="455193067926770581">"Bloqueio de chamadas"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Alteração da senha"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Alteração do PIN"</string>
+ <string name="untitled">"&lt;sem título&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Nenhum número de telefone)"</string>
+ <string name="unknownName">"(Desconhecido)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Correio de voz"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Problema de conexão ou código MMI inválido."</string>
+ <string name="serviceEnabled">"O serviço foi ativado."</string>
+ <string name="serviceEnabledFor">"O serviço foi ativado para:"</string>
+ <string name="serviceDisabled">"O serviço foi desativado."</string>
+ <string name="serviceRegistered">"Registro bem-sucedido."</string>
+ <string name="serviceErased">"Exclusão bem-sucedida."</string>
+ <string name="passwordIncorrect">"Senha incorreta."</string>
+ <string name="mmiComplete">"MMI concluído."</string>
+ <string name="badPin">"O PIN antigo digitado não está correto."</string>
+ <string name="badPuk">"O PUK digitado não está correto."</string>
+ <string name="mismatchPin">"Os PINs digitados não correspondem."</string>
+ <string name="invalidPin">"Digite um PIN com 4 a 8 números."</string>
+ <string name="needPuk">"O seu cartão SIM está bloqueado por um PUK. Digite o código PUK para desbloqueá-lo."</string>
+ <string name="needPuk2">"Digite o PUK2 para desbloquear o cartão SIM."</string>
+ <string name="ClipMmi">"ID do chamador de entrada"</string>
+ <string name="ClirMmi">"ID do chamador de saída"</string>
+ <string name="CfMmi">"Encaminhamento de chamada"</string>
+ <string name="CwMmi">"Chamada em espera"</string>
+ <string name="BaMmi">"Bloqueio de chamadas"</string>
+ <string name="PwdMmi">"Alteração da senha"</string>
+ <string name="PinMmi">"Alteração do PIN"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"O ID do chamador assume o padrão de restrito. Próxima chamada: Restrita"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"O ID do chamador assume o padrão de restrito. Próxima chamada: Não restrita"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Restrita"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"O serviço não foi habilitado."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"A configuração do ID do chamador não pode ser alterada."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acesso restrito alterado"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"O serviço de dados está bloqueado."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"O serviço de emergência está bloqueado."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"O serviço de voz/SMS está bloqueado."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Todos os serviços de voz/SMS estão bloqueados."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Voz"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Dados"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Assíncrono"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Sincronizar"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Pacote"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"O ID do chamador assume o padrão de restrito. Próxima chamada: Restrita"</string>
+ <string name="CLIRDefaultOnNextCallOff">"O ID do chamador assume o padrão de restrito. Próxima chamada: Não restrita"</string>
+ <string name="CLIRDefaultOffNextCallOn">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Restrita"</string>
+ <string name="CLIRDefaultOffNextCallOff">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
+ <string name="serviceNotProvisioned">"O serviço não foi habilitado."</string>
+ <string name="CLIRPermanent">"A configuração do ID do chamador não pode ser alterada."</string>
+ <string name="RestrictedChangedTitle">"Acesso restrito alterado"</string>
+ <string name="RestrictedOnData">"O serviço de dados está bloqueado."</string>
+ <string name="RestrictedOnEmergency">"O serviço de emergência está bloqueado."</string>
+ <string name="RestrictedOnNormal">"O serviço de voz/SMS está bloqueado."</string>
+ <string name="RestrictedOnAll">"Todos os serviços de voz/SMS estão bloqueados."</string>
+ <string name="serviceClassVoice">"Voz"</string>
+ <string name="serviceClassData">"Dados"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Assíncrono"</string>
+ <string name="serviceClassDataSync">"Sincronizar"</string>
+ <string name="serviceClassPacket">"Pacote"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"A página da web contém um erro."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Não foi possível encontrar o URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"O esquema de autenticação do site não é suportado."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Falha na autenticação."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Falha na autenticação por meio do servidor proxy."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Falha na conexão com o servidor."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Falha de comunicação do servidor. Tente novamente mais tarde."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"O tempo limite de conexão com o servidor esgotou."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"A página contém muitos redirecionamentos do servidor."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"O protocolo não é suportado."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Não foi possível estabelecer uma conexão segura."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Não foi possível abrir a página porque o URL é inválido."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Não foi possível acessar o arquivo."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"O arquivo solicitado não foi encontrado."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Há muitas solicitações sendo processadas. Tente novamente mais tarde."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Sincronizar"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizar"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Muitas exclusões de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"O armazenamento do telefone está cheio! Exclua alguns arquivos para liberar espaço."</string>
- <string name="me" msgid="6545696007631404292">"Eu"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Opções do telefone"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Modo silencioso"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Ativar sem fio"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Desativar a rede sem fio"</string>
- <string name="screen_lock" msgid="799094655496098153">"Bloquear tela"</string>
- <string name="power_off" msgid="4266614107412865048">"Desligar"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Encerrando…"</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"O seu telefone será desligado."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Nenhum aplicativo recente."</string>
- <string name="global_actions" msgid="2406416831541615258">"Opções do telefone"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som DESATIVADO"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O som está ATIVADO"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo de avião ATIVADO"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo de avião DESATIVADO"</string>
- <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que geram gastos"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Permite que os aplicativos façam coisas que possam gerar gastos."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Suas mensagens"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Lê e grava o seu SMS, e-mail e outras mensagens."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Suas informações pessoais"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Acessa diretamente os seus contatos e agenda armazenados no telefone."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Seu local"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Monitora o seu local físico."</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicação da rede"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Permite que os aplicativos acessem diversos recursos de rede."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Suas Contas do Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Acessar as Contas do Google disponíveis."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controles de hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acessa o hardware diretamente no aparelho."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Chamadas telefônicas"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Monitora, registra e processa chamadas telefônicas."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Ferramentas do sistema"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Acesso de nível inferior e controle do sistema."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Ferramentas de desenvolvimento"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Recursos necessários apenas para desenvolvedores de aplicativo."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"A página da web contém um erro."</string>
+ <string name="httpErrorLookup">"Não foi possível encontrar o URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"O esquema de autenticação do site não é suportado."</string>
+ <string name="httpErrorAuth">"Falha na autenticação."</string>
+ <string name="httpErrorProxyAuth">"Falha na autenticação por meio do servidor proxy."</string>
+ <string name="httpErrorConnect">"Falha na conexão com o servidor."</string>
+ <string name="httpErrorIO">"Falha de comunicação do servidor. Tente novamente mais tarde."</string>
+ <string name="httpErrorTimeout">"O tempo limite de conexão com o servidor esgotou."</string>
+ <string name="httpErrorRedirectLoop">"A página contém muitos redirecionamentos do servidor."</string>
+ <string name="httpErrorUnsupportedScheme">"O protocolo não é suportado."</string>
+ <string name="httpErrorFailedSslHandshake">"Não foi possível estabelecer uma conexão segura."</string>
+ <string name="httpErrorBadUrl">"Não foi possível abrir a página porque o URL é inválido."</string>
+ <string name="httpErrorFile">"Não foi possível acessar o arquivo."</string>
+ <string name="httpErrorFileNotFound">"O arquivo solicitado não foi encontrado."</string>
+ <string name="httpErrorTooManyRequests">"Há muitas solicitações sendo processadas. Tente novamente mais tarde."</string>
+ <string name="contentServiceSync">"Sincronizar"</string>
+ <string name="contentServiceSyncNotificationTitle">"Sincronizar"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Muitas exclusões de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"O armazenamento do telefone está cheio! Exclua alguns arquivos para liberar espaço."</string>
+ <string name="me">"Eu"</string>
+ <string name="power_dialog">"Opções do telefone"</string>
+ <string name="silent_mode">"Modo silencioso"</string>
+ <string name="turn_on_radio">"Ativar sem fio"</string>
+ <string name="turn_off_radio">"Desativar a rede sem fio"</string>
+ <string name="screen_lock">"Bloquear tela"</string>
+ <string name="power_off">"Desligar"</string>
+ <string name="shutdown_progress">"Encerrando…"</string>
+ <string name="shutdown_confirm">"O seu telefone será desligado."</string>
+ <string name="no_recent_tasks">"Nenhum aplicativo recente."</string>
+ <string name="global_actions">"Opções do telefone"</string>
+ <string name="global_action_lock">"Bloquear tela"</string>
+ <string name="global_action_power_off">"Desligar"</string>
+ <string name="global_action_toggle_silent_mode">"Modo silencioso"</string>
+ <string name="global_action_silent_mode_on_status">"Som DESATIVADO"</string>
+ <string name="global_action_silent_mode_off_status">"O som está ATIVADO"</string>
+ <string name="global_actions_toggle_airplane_mode">"Modo de avião"</string>
+ <string name="global_actions_airplane_mode_on_status">"Modo de avião ATIVADO"</string>
+ <string name="global_actions_airplane_mode_off_status">"Modo de avião DESATIVADO"</string>
+ <string name="safeMode">"Modo de segurança"</string>
+ <string name="android_system_label">"Sistema Android"</string>
+ <string name="permgrouplab_costMoney">"Serviços que geram gastos"</string>
+ <string name="permgroupdesc_costMoney">"Permite que os aplicativos façam coisas que possam gerar gastos."</string>
+ <string name="permgrouplab_messages">"Suas mensagens"</string>
+ <string name="permgroupdesc_messages">"Lê e grava o seu SMS, e-mail e outras mensagens."</string>
+ <string name="permgrouplab_personalInfo">"Suas informações pessoais"</string>
+ <string name="permgroupdesc_personalInfo">"Acessa diretamente os seus contatos e agenda armazenados no telefone."</string>
+ <string name="permgrouplab_location">"Seu local"</string>
+ <string name="permgroupdesc_location">"Monitora o seu local físico."</string>
+ <string name="permgrouplab_network">"Comunicação da rede"</string>
+ <string name="permgroupdesc_network">"Permite que os aplicativos acessem diversos recursos de rede."</string>
+ <string name="permgrouplab_accounts">"Suas Contas do Google"</string>
+ <string name="permgroupdesc_accounts">"Acessar as Contas do Google disponíveis."</string>
+ <string name="permgrouplab_hardwareControls">"Controles de hardware"</string>
+ <string name="permgroupdesc_hardwareControls">"Acessa o hardware diretamente no aparelho."</string>
+ <string name="permgrouplab_phoneCalls">"Chamadas telefônicas"</string>
+ <string name="permgroupdesc_phoneCalls">"Monitora, registra e processa chamadas telefônicas."</string>
+ <string name="permgrouplab_systemTools">"Ferramentas do sistema"</string>
+ <string name="permgroupdesc_systemTools">"Acesso de nível inferior e controle do sistema."</string>
+ <string name="permgrouplab_developmentTools">"Ferramentas de desenvolvimento"</string>
+ <string name="permgroupdesc_developmentTools">"Recursos necessários apenas para desenvolvedores de aplicativo."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Permite que o aplicativo desative a barra de status ou adicione e remova ícones do sistema."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expandir/recolher barra de status"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Permite que o aplicativo expanda ou recolha a barra de status."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"interceptar chamadas enviadas"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Permite que o aplicativo processe chamadas enviadas e altere o número a ser discado. Aplicativos maliciosos podem monitorar, redirecionar ou impedir a realização de chamadas."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"receber SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Permite que o aplicativo receba e processe mensagens SMS. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"receber MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Permite que o aplicativo receba e processe mensagens MMS. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"enviar mensagens SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Permite que o aplicativo envie mensagens SMS. Aplicativos maliciosos podem gerar gastos enviando mensagens sem a sua confirmação."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"ler SMS ou MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Permite que o aplicativo leia mensagens SMS armazenadas no seu telefone ou cartão SIM. Aplicativos maliciosos podem ler as suas mensagens confidenciais."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS ou MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Permite que o aplicativo grave mensagens SMS armazenadas no seu telefone ou cartão SIM. Aplicativos maliciosos podem excluir suas mensagens."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"receber WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Permite que o aplicativo receba e processe mensagens WAP. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"recuperar aplicativos em execução"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Permite que o aplicativo recupere as informações sobre tarefas em execução no momento ou recentemente. Pode permitir que aplicativos maliciosos descubram informações particulares sobre outros aplicativos."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"reorganizar aplicativos em execução"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite que um aplicativo mova as tarefas para o primeiro e para o segundo planos. Aplicativos maliciosos podem se forçar à frente sem o seu controle."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"ativar depuração do aplicativo"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite que um aplicativo ative a depuração de outro aplicativo. Aplicativos maliciosos podem usar isso para encerrar outros aplicativos."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar as suas configurações de UI"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Permite que um aplicativo altere a configuração atual, como o local ou o tamanho geral da fonte."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"reiniciar outros aplicativos"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Permite que um aplicativo reinicie forçosamente outros aplicativos."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"forçar fechamento do aplicativo"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Permite que um aplicativo force o fechamento de qualquer atividade que esteja em primeiro plano. Aplicativos normais não devem precisar disso em momento algum."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"recuperar o estado interno do sistema"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Permite que um aplicativo recupere o estado interno do sistema. Aplicativos maliciosos podem recuperar uma grande variedade de informações privadas e de segurança que normalmente não precisariam."</string>
+ <string name="permlab_statusBar">"desativar ou modificar a barra de status"</string>
+ <string name="permdesc_statusBar">"Permite que o aplicativo desative a barra de status ou adicione e remova ícones do sistema."</string>
+ <string name="permlab_expandStatusBar">"expandir/recolher barra de status"</string>
+ <string name="permdesc_expandStatusBar">"Permite que o aplicativo expanda ou recolha a barra de status."</string>
+ <string name="permlab_processOutgoingCalls">"interceptar chamadas enviadas"</string>
+ <string name="permdesc_processOutgoingCalls">"Permite que o aplicativo processe chamadas enviadas e altere o número a ser discado. Aplicativos maliciosos podem monitorar, redirecionar ou impedir a realização de chamadas."</string>
+ <string name="permlab_receiveSms">"receber SMS"</string>
+ <string name="permdesc_receiveSms">"Permite que o aplicativo receba e processe mensagens SMS. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
+ <string name="permlab_receiveMms">"receber MMS"</string>
+ <string name="permdesc_receiveMms">"Permite que o aplicativo receba e processe mensagens MMS. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
+ <string name="permlab_sendSms">"enviar mensagens SMS"</string>
+ <string name="permdesc_sendSms">"Permite que o aplicativo envie mensagens SMS. Aplicativos maliciosos podem gerar gastos enviando mensagens sem a sua confirmação."</string>
+ <string name="permlab_readSms">"ler SMS ou MMS"</string>
+ <string name="permdesc_readSms">"Permite que o aplicativo leia mensagens SMS armazenadas no seu telefone ou cartão SIM. Aplicativos maliciosos podem ler as suas mensagens confidenciais."</string>
+ <string name="permlab_writeSms">"editar SMS ou MMS"</string>
+ <string name="permdesc_writeSms">"Permite que o aplicativo grave mensagens SMS armazenadas no seu telefone ou cartão SIM. Aplicativos maliciosos podem excluir suas mensagens."</string>
+ <string name="permlab_receiveWapPush">"receber WAP"</string>
+ <string name="permdesc_receiveWapPush">"Permite que o aplicativo receba e processe mensagens WAP. Aplicativos maliciosos podem monitorar as suas mensagens ou excluí-las sem mostrá-las a você."</string>
+ <string name="permlab_getTasks">"recuperar aplicativos em execução"</string>
+ <string name="permdesc_getTasks">"Permite que o aplicativo recupere as informações sobre tarefas em execução no momento ou recentemente. Pode permitir que aplicativos maliciosos descubram informações particulares sobre outros aplicativos."</string>
+ <string name="permlab_reorderTasks">"reorganizar aplicativos em execução"</string>
+ <string name="permdesc_reorderTasks">"Permite que um aplicativo mova as tarefas para o primeiro e para o segundo planos. Aplicativos maliciosos podem se forçar à frente sem o seu controle."</string>
+ <string name="permlab_setDebugApp">"ativar depuração do aplicativo"</string>
+ <string name="permdesc_setDebugApp">"Permite que um aplicativo ative a depuração de outro aplicativo. Aplicativos maliciosos podem usar isso para encerrar outros aplicativos."</string>
+ <string name="permlab_changeConfiguration">"alterar as suas configurações de UI"</string>
+ <string name="permdesc_changeConfiguration">"Permite que um aplicativo altere a configuração atual, como a localidade ou tamanho geral da fonte."</string>
+ <string name="permlab_restartPackages">"reiniciar outros aplicativos"</string>
+ <string name="permdesc_restartPackages">"Permite que um aplicativo reinicie forçosamente outros aplicativos."</string>
+ <string name="permlab_forceBack">"forçar fechamento do aplicativo"</string>
+ <string name="permdesc_forceBack">"Permite que um aplicativo force o fechamento de qualquer atividade que esteja em primeiro plano. Aplicativos normais não devem precisar disso em momento algum."</string>
+ <string name="permlab_dump">"recuperar o estado interno do sistema"</string>
+ <string name="permdesc_dump">"Permite que um aplicativo recupere o estado interno do sistema. Aplicativos maliciosos podem recuperar uma grande variedade de informações privadas e de segurança que normalmente não precisariam."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"monitorar e controlar toda inicialização de aplicativo"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Permite que um aplicativo monitore e controle a maneira como o sistema inicia as atividades. Aplicativos maliciosos podem comprometer todo o sistema. Essa permissão é necessária apenas para desenvolvimento, nunca para uso normal do telefone."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"enviar transmissão removida do pacote"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Permite que um aplicativo transmita uma notificação informando que um pacote de aplicativo foi removido. Aplicativos maliciosos podem usar isso para encerrar qualquer outro aplicativo em execução."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"enviar transmissão SMS recebida"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Permite que um aplicativo transmita uma notificação de que uma mensagem SMS foi recebida. Aplicativos maliciosos podem usar isso para forjar o recebimento de mensagens SMS."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar transmissão WAP-PUSH recebida"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Permite que um aplicativo transmita uma notificação de que uma mensagem WAP PUSH foi recebida. Aplicativos maliciosos podem usar isso para forjar o recebimento de mensagem MMS ou substituir silenciosamente o conteúdo de qualquer página da web por variantes maliciosas."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar número de processos em execução"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Permite que um aplicativo controle o número máximo de processos que serão executados. Aplicativos normais não precisam disso em momento algum."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"fechar todos os aplicativos em segundo plano"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Permite que um aplicativo controle se as atividades são sempre concluídas assim que vão para o segundo plano. Aplicativos normais não precisam disso em momento algum."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"modificar estatísticas da bateria"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Permite a modificação das estatísticas de bateria coletadas. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_runSetActivityWatcher">"monitorar e controlar toda inicialização de aplicativo"</string>
+ <string name="permdesc_runSetActivityWatcher">"Permite que um aplicativo monitore e controle a maneira como o sistema inicia as atividades. Aplicativos maliciosos podem comprometer todo o sistema. Essa permissão é necessária apenas para desenvolvimento, nunca para uso normal do telefone."</string>
+ <string name="permlab_broadcastPackageRemoved">"enviar transmissão removida do pacote"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Permite que um aplicativo transmita uma notificação informando que um pacote de aplicativo foi removido. Aplicativos maliciosos podem usar isso para encerrar qualquer outro aplicativo em execução."</string>
+ <string name="permlab_broadcastSmsReceived">"enviar transmissão SMS recebida"</string>
+ <string name="permdesc_broadcastSmsReceived">"Permite que um aplicativo transmita uma notificação de que uma mensagem SMS foi recebida. Aplicativos maliciosos podem usar isso para forjar o recebimento de mensagens SMS."</string>
+ <string name="permlab_broadcastWapPush">"enviar transmissão WAP-PUSH recebida"</string>
+ <string name="permdesc_broadcastWapPush">"Permite que um aplicativo transmita uma notificação de que uma mensagem WAP PUSH foi recebida. Aplicativos maliciosos podem usar isso para forjar o recebimento de mensagem MMS ou substituir silenciosamente o conteúdo de qualquer página da web por variantes maliciosas."</string>
+ <string name="permlab_setProcessLimit">"limitar número de processos em execução"</string>
+ <string name="permdesc_setProcessLimit">"Permite que um aplicativo controle o número máximo de processos que serão executados. Aplicativos normais não precisam disso em momento algum."</string>
+ <string name="permlab_setAlwaysFinish">"fechar todos os aplicativos em segundo plano"</string>
+ <string name="permdesc_setAlwaysFinish">"Permite que um aplicativo controle se as atividades são sempre concluídas assim que vão para o segundo plano. Aplicativos normais não precisam disso em momento algum."</string>
+ <string name="permlab_batteryStats">"modificar estatísticas da bateria"</string>
+ <string name="permdesc_batteryStats">"Permite a modificação das estatísticas de bateria coletadas. Não deve ser usado por aplicativos normais."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"exibir janelas não autorizadas"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite a criação de janelas destinadas ao uso pela interface de usuário do sistema interno. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"exibir alertas de nível do sistema"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Permite que um aplicativo mostre janelas de alerta do sistema. Aplicativos maliciosos podem assumir o controle de toda a tela do telefone."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar velocidade de animação global"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Permite que um aplicativo altere a velocidade de animação global (animação mais rápida ou mais lenta) a qualquer momento."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"gerenciar tokens do aplicativo"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Permite que os aplicativos criem e gerenciem seus próprios tokens, ignorando a ordem Z normal. Aplicativos normais não devem precisar disso em momento algum."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"pressionar as teclas e os botões de controle"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Permite que um aplicativo use seus próprios eventos de entrada (pressionamentos de teclas etc.) em outros aplicativos. Aplicativos maliciosos podem usar isso para assumir o controle do telefone."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"registrar o que você digita e as ações que realiza"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Permite que os aplicativos vejam as teclas que você pressiona, mesmo quando estiver interagindo com outro aplicativo (como ao digitar uma senha). Aplicativos normais não devem precisar disso em momento algum."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a um método de entrada"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permite que o detentor se sujeite à interface de nível superior de um método de entrada. Aplicativos normais não devem precisar disso em momento algum."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"alterar orientação da tela"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Permite que um aplicativo altere a rotação da tela a qualquer momento. Aplicativos normais não devem precisar disso em momento algum."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"enviar sinais de Linux para os aplicativos"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Permite que o aplicativo solicite que o sinal fornecido seja enviado a todos os processos persistentes."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"executar sempre o aplicativo"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Permite que um aplicativo torne partes de si mesmo persistentes, de modo que o sistema não possa usar essas partes para outros aplicativos."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"excluir aplicativos"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Permite que um aplicativo exclua pacotes do Android. Aplicativos maliciosos podem usar isso para excluir aplicativos importantes."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"excluir dados de outros aplicativos"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Permite que um aplicativo limpe os dados do usuário."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"excluir os caches de outros aplicativos"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Permite que um aplicativo exclua os arquivos do cache."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"medir espaço de armazenamento do aplicativo"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Permite que um aplicativo recupere seu código, seus dados e os tamanhos do cache."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"instalar diretamente os aplicativos"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Permite que um aplicativo instale pacotes novos ou atualizados do Android. Aplicativos maliciosos podem usar isso para adicionar novos aplicativos com permissões arbitrariamente avançadas."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"excluir todos os dados de cache do aplicativo"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite que um aplicativo libere o espaço de armazenamento do telefone excluindo arquivos no diretório de cache do aplicativo. O acesso é normalmente muito restrito para o processo do sistema."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"ler arquivos de registro do sistema"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Permite que um aplicativo leia os diversos arquivos de registro do sistema. Isso permite que ele descubra informações gerais sobre o que você está fazendo com o telefone, porém esses arquivos não devem conter informações pessoais ou privadas."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos; por exemplo, arquivos em /dev. Isso possivelmente pode afetar a estabilidade e a segurança do sistema. Isso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pelo operador."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"ativar ou desativar os componentes do aplicativo"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Permite que um aplicativo altere se um componente de outro aplicativo está ativado ou não. Aplicativos maliciosos podem usar isso para desativar recursos de telefone importantes. É preciso ter cuidado com a permissão, pois é possível deixar os componentes do aplicativo em um estado inutilizável, inconsistente ou instável."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"definir os aplicativos preferidos"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Permite que um aplicativo modifique os seus aplicativos preferidos. Isso pode permitir que aplicativos maliciosos alterem silenciosamente os aplicativos em execução, falsificando os seus aplicativos existentes para coletar os seus dados particulares."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"modificar configurações globais do sistema"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Permite que um aplicativo modifique os dados de configuração do sistema. Aplicativos maliciosos podem corromper a configuração do seu sistema."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificar configurações do sistema de segurança"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Permite que um aplicativo modifique os dados de configuração de segurança dos sistemas. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"modificar o mapa de serviços do Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Permite que um aplicativo modifique o mapa de serviços do Google. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"iniciar automaticamente na inicialização"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Permite que um aplicativo inicie assim que o sistema conclui a inicialização. Isso pode retardar a inicialização do telefone e permitir que o aplicativo deixe o telefone mais lento por estar sempre em execução."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar transmissão persistente"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Permite que um aplicativo envie uma transmissão persistente, que permanece após o término da transmissão. Aplicativos maliciosos podem tornar o telefone lento ou instável fazendo com que ele use muita memória."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"ler dados do contato"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Permite que um aplicativo leia todos os dados de contato (endereço) armazenados no seu telefone. Aplicativos maliciosos podem usar isso para enviar os seus dados para outras pessoas."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"gravar dados de contato"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Permite que um aplicativo modifique os dados de contato (endereço) armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar os seus dados de contato."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"gravar dados do proprietário"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Permite que um aplicativo modifique os dados de proprietário do telefone armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar dados do proprietário."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"ler dados do proprietário"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Permite que um aplicativo leia os dados de proprietário do telefone armazenados no seu telefone. Aplicativos maliciosos podem usar isso para ler os dados de proprietário do telefone."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"ler dados da agenda"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Permite que um aplicativo leia todos os eventos da agenda armazenados no seu telefone. Aplicativos maliciosos podem usar isso para enviar eventos da sua agenda para outras pessoas."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"gravar dados da agenda"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Permite que um aplicativo modifique os eventos da agenda armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar os seus dados da agenda."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fontes de locais fictícios para teste"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Cria fontes de locais fictícios para teste. Aplicativos maliciosos podem usar isso para substituir o local e/ou o status retornado pelas fontes de locais reais como GPS ou provedores de rede."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acessar comandos extras do provedor de localização"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Acessa comandos extras do provedor de localização. Aplicativos maliciosos podem usar isso para interferir na operação do GPS ou de outras fontes de localização."</string>
+ <string name="permlab_internalSystemWindow">"exibir janelas não autorizadas"</string>
+ <string name="permdesc_internalSystemWindow">"Permite a criação de janelas destinadas ao uso pela interface de usuário do sistema interno. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_systemAlertWindow">"exibir alertas de nível do sistema"</string>
+ <string name="permdesc_systemAlertWindow">"Permite que um aplicativo mostre janelas de alerta do sistema. Aplicativos maliciosos podem assumir o controle de toda a tela do telefone."</string>
+ <string name="permlab_setAnimationScale">"modificar velocidade de animação global"</string>
+ <string name="permdesc_setAnimationScale">"Permite que um aplicativo altere a velocidade de animação global (animação mais rápida ou mais lenta) a qualquer momento."</string>
+ <string name="permlab_manageAppTokens">"gerenciar tokens do aplicativo"</string>
+ <string name="permdesc_manageAppTokens">"Permite que os aplicativos criem e gerenciem seus próprios tokens, ignorando a ordem Z normal. Aplicativos normais não devem precisar disso em momento algum."</string>
+ <string name="permlab_injectEvents">"pressionar as teclas e os botões de controle"</string>
+ <string name="permdesc_injectEvents">"Permite que um aplicativo use seus próprios eventos de entrada (pressionamentos de teclas etc.) em outros aplicativos. Aplicativos maliciosos podem usar isso para assumir o controle do telefone."</string>
+ <string name="permlab_readInputState">"registrar o que você digita e as ações que realiza"</string>
+ <string name="permdesc_readInputState">"Permite que os aplicativos vejam as teclas que você pressiona, mesmo quando estiver interagindo com outro aplicativo (como ao digitar uma senha). Aplicativos normais não devem precisar disso em momento algum."</string>
+ <string name="permlab_bindInputMethod">"vincular a um método de entrada"</string>
+ <string name="permdesc_bindInputMethod">"Permite que o detentor se sujeite à interface de nível superior de um método de entrada. Aplicativos normais não devem precisar disso em momento algum."</string>
+ <string name="permlab_setOrientation">"alterar orientação da tela"</string>
+ <string name="permdesc_setOrientation">"Permite que um aplicativo altere a rotação da tela a qualquer momento. Aplicativos normais não devem precisar disso em momento algum."</string>
+ <string name="permlab_signalPersistentProcesses">"enviar sinais de Linux para os aplicativos"</string>
+ <string name="permdesc_signalPersistentProcesses">"Permite que o aplicativo solicite que o sinal fornecido seja enviado a todos os processos persistentes."</string>
+ <string name="permlab_persistentActivity">"executar sempre o aplicativo"</string>
+ <string name="permdesc_persistentActivity">"Permite que um aplicativo torne partes de si mesmo persistentes, de modo que o sistema não possa usar essas partes para outros aplicativos."</string>
+ <string name="permlab_deletePackages">"excluir aplicativos"</string>
+ <string name="permdesc_deletePackages">"Permite que um aplicativo exclua pacotes do Android. Aplicativos maliciosos podem usar isso para excluir aplicativos importantes."</string>
+ <string name="permlab_clearAppUserData">"excluir dados de outros aplicativos"</string>
+ <string name="permdesc_clearAppUserData">"Permite que um aplicativo limpe os dados do usuário."</string>
+ <string name="permlab_deleteCacheFiles">"excluir os caches de outros aplicativos"</string>
+ <string name="permdesc_deleteCacheFiles">"Permite que um aplicativo exclua os arquivos do cache."</string>
+ <string name="permlab_getPackageSize">"medir espaço de armazenamento do aplicativo"</string>
+ <string name="permdesc_getPackageSize">"Permite que um aplicativo recupere seu código, seus dados e os tamanhos do cache."</string>
+ <string name="permlab_installPackages">"instalar diretamente os aplicativos"</string>
+ <string name="permdesc_installPackages">"Permite que um aplicativo instale pacotes novos ou atualizados do Android. Aplicativos maliciosos podem usar isso para adicionar novos aplicativos com permissões arbitrariamente avançadas."</string>
+ <string name="permlab_clearAppCache">"excluir todos os dados de cache do aplicativo"</string>
+ <string name="permdesc_clearAppCache">"Permite que um aplicativo libere o espaço de armazenamento do telefone excluindo arquivos no diretório de cache do aplicativo. O acesso é normalmente muito restrito para o processo do sistema."</string>
+ <string name="permlab_readLogs">"ler arquivos de registro do sistema"</string>
+ <string name="permdesc_readLogs">"Permite que um aplicativo leia os diversos arquivos de registro do sistema. Isso permite que ele descubra informações gerais sobre o que você está fazendo com o telefone, porém esses arquivos não devem conter informações pessoais ou privadas."</string>
+ <string name="permlab_diagnostic">"ler/gravar em recursos pertencentes ao diag"</string>
+ <string name="permdesc_diagnostic">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos; por exemplo, arquivos em /dev. Isso possivelmente pode afetar a estabilidade e a segurança do sistema. Isso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pelo operador."</string>
+ <string name="permlab_changeComponentState">"ativar ou desativar os componentes do aplicativo"</string>
+ <string name="permdesc_changeComponentState">"Permite que um aplicativo altere se um componente de outro aplicativo está ativado ou não. Aplicativos maliciosos podem usar isso para desativar recursos de telefone importantes. É preciso ter cuidado com a permissão, pois é possível deixar os componentes do aplicativo em um estado inutilizável, inconsistente ou instável."</string>
+ <string name="permlab_setPreferredApplications">"definir os aplicativos preferidos"</string>
+ <string name="permdesc_setPreferredApplications">"Permite que um aplicativo modifique os seus aplicativos preferidos. Isso pode permitir que aplicativos maliciosos alterem silenciosamente os aplicativos em execução, falsificando os seus aplicativos existentes para coletar os seus dados particulares."</string>
+ <string name="permlab_writeSettings">"modificar configurações globais do sistema"</string>
+ <string name="permdesc_writeSettings">"Permite que um aplicativo modifique os dados de configuração do sistema. Aplicativos maliciosos podem corromper a configuração do seu sistema."</string>
+ <string name="permlab_writeSecureSettings">"modificar configurações do sistema de segurança"</string>
+ <string name="permdesc_writeSecureSettings">"Permite que um aplicativo modifique os dados de configuração de segurança dos sistemas. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_writeGservices">"modificar o mapa de serviços do Google"</string>
+ <string name="permdesc_writeGservices">"Permite que um aplicativo modifique o mapa de serviços do Google. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_receiveBootCompleted">"iniciar automaticamente na inicialização"</string>
+ <string name="permdesc_receiveBootCompleted">"Permite que um aplicativo inicie assim que o sistema conclui a inicialização. Isso pode retardar a inicialização do telefone e permitir que o aplicativo deixe o telefone mais lento por estar sempre em execução."</string>
+ <string name="permlab_broadcastSticky">"enviar transmissão persistente"</string>
+ <string name="permdesc_broadcastSticky">"Permite que um aplicativo envie uma transmissão persistente, que permanece após o término da transmissão. Aplicativos maliciosos podem tornar o telefone lento ou instável fazendo com que ele use muita memória."</string>
+ <string name="permlab_readContacts">"ler dados do contato"</string>
+ <string name="permdesc_readContacts">"Permite que um aplicativo leia todos os dados de contato (endereço) armazenados no seu telefone. Aplicativos maliciosos podem usar isso para enviar os seus dados para outras pessoas."</string>
+ <string name="permlab_writeContacts">"gravar dados de contato"</string>
+ <string name="permdesc_writeContacts">"Permite que um aplicativo modifique os dados de contato (endereço) armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar os seus dados de contato."</string>
+ <string name="permlab_writeOwnerData">"gravar dados do proprietário"</string>
+ <string name="permdesc_writeOwnerData">"Permite que um aplicativo modifique os dados de proprietário do telefone armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar dados do proprietário."</string>
+ <string name="permlab_readOwnerData">"ler dados do proprietário"</string>
+ <string name="permdesc_readOwnerData">"Permite que um aplicativo leia os dados de proprietário do telefone armazenados no seu telefone. Aplicativos maliciosos podem usar isso para ler os dados de proprietário do telefone."</string>
+ <string name="permlab_readCalendar">"ler dados da agenda"</string>
+ <string name="permdesc_readCalendar">"Permite que um aplicativo leia todos os eventos da agenda armazenados no seu telefone. Aplicativos maliciosos podem usar isso para enviar eventos da sua agenda para outras pessoas."</string>
+ <string name="permlab_writeCalendar">"gravar dados da agenda"</string>
+ <string name="permdesc_writeCalendar">"Permite que um aplicativo modifique os eventos da agenda armazenados no seu telefone. Aplicativos maliciosos podem usar isso para apagar ou modificar os seus dados da agenda."</string>
+ <string name="permlab_accessMockLocation">"fontes de locais fictícios para teste"</string>
+ <string name="permdesc_accessMockLocation">"Cria fontes de locais fictícios para teste. Aplicativos maliciosos podem usar isso para substituir o local e/ou o status retornado pelas fontes de locais reais como GPS ou provedores de rede."</string>
+ <string name="permlab_accessLocationExtraCommands">"acessar comandos extras do provedor de localização"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Acessa comandos extras do provedor de localização. Aplicativos maliciosos podem usar isso para interferir na operação do GPS ou de outras fontes de localização."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"Localização precisa (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Acessa fontes de localização precisa como o GPS (Global Positioning System) no telefone, onde disponível. Aplicativos maliciosos podem usar isso para determinar onde você está e podem consumir energia adicional da bateria."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"local aproximado (com base na rede)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Acessa fontes de localização aproximada como o banco de dados de rede celular para determinar a localização aproximada de um telefone, onde disponível. Aplicativos maliciosos podem usar isso para determinar aproximadamente onde você está."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"acessar SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permite que o aplicativo use recursos de nível inferior do SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"ler o buffer do frame"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Permite que o aplicativo a ser usado leia o conteúdo do buffer de frame."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"alterar as suas configurações de áudio"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Permite que o aplicativo modifique as configurações globais de áudio como volume e roteamento."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"gravar áudio"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Permite que um aplicativo acesse o caminho de gravação do áudio."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"tirar fotos"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Permite que o aplicativo tire fotos com a câmera. Isso permite que o aplicativo colete imagens vistas pela câmera a qualquer momento."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"desativar permanentemente o telefone"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Permite que o aplicativo desative o telefone inteiro permanentemente. Isso é muito perigoso."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"forçar reinicialização do telefone"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Permite que o aplicativo force a reinicialização do telefone."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar e desmontar sistemas de arquivos"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permite que o aplicativo monte e desmonte arquivos de sistema para armazenamento removível."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatar armazenamento externo"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Permite que o aplicativo formate o armazenamento removível."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"controlar o vibrador"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Permite que o aplicativo controle o vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Permite que o aplicativo controle a lanterna."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"testar hardware"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite que o aplicativo controle diversos periféricos para teste do hardware."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"chamar diretamente os números de telefone"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Permite que o aplicativo ligue para números de telefones sem a sua intervenção. Aplicativos maliciosos podem causar chamadas inesperadas na conta do seu telefone. Observe que isso não permite que o aplicativo ligue para números de emergência."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"chamar diretamente quaisquer números de telefone"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Permite que o aplicativo ligue para qualquer número de telefone, incluindo números de emergência, sem a sua intervenção. Aplicativos maliciosos podem fazer chamadas desnecessárias e ilegais para serviços de emergência."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar as notificações de atualização do local"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite a ativação/desativação de notificações de atualização do local a partir do rádio. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"acessar propriedades de verificação"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Permite o acesso de leitura/gravação às propriedades enviadas pelo serviço de verificação. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"escolher widgets"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Permite que o aplicativo informe ao sistema quais widgets podem ser usados por quais aplicativos. Com essa permissão, os aplicativos podem conceder acesso aos dados pessoais a outros aplicativos. Não deve ser usado por aplicativos normais."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar estado do telefone"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Permite que o aplicativo controle os recursos de telefone do dispositivo. Um aplicativo com essa permissão pode alternar redes, ligar e desligar o rádio do telefone e outras ações parecidas sem notificá-lo."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"impedir modo de inatividade do telefone"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Permite que um aplicativo impeça o telefone de entrar no modo de inatividade."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"ligar ou desligar o telefone"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Permite que o aplicativo ative ou desative o telefone."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"executar no modo de teste de fábrica"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Executa como um teste do fabricante de nível inferior, permitindo o acesso completo ao hardware do telefone. Disponível apenas quando um telefone está em execução no modo de teste do fabricante."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"definir papel de parede"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permite que o aplicativo defina o papel de parede do sistema."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"definir dicas de tamanho do papel de parede"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Permite que o aplicativo defina as dicas de tamanho do papel de parede do sistema."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"redefinir o sistema para os padrões de fábrica"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Permite que um aplicativo redefina completamente o sistema para as configurações de fábrica, apagando todos os dados, configuração e aplicativos instalados."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"definir fuso horário"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Permite que um aplicativo altere o fuso horário do telefone."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"descobrir contas conhecidas"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Permite que um aplicativo obtenha a lista de contas conhecidas pelo telefone."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ver estado da rede"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Permite que um aplicativo veja o estado de todas as redes."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"acesso total da internet"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Permite que um aplicativo crie soquetes de rede."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"gravar as configurações do Nome do ponto de acesso"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Permite que um aplicativo modifique as configurações de APN, como Proxy e Porta de qualquer APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"alterar conectividade da rede"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Permite que um aplicativo altere o estado da conectividade de rede."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"alterar configuração de uso dos dados de segundo plano"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Permite que um aplicativo altere a configuração de uso dos dados de segundo plano."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"visualizar estado da rede Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Permite que um aplicativo veja as informações sobre o estado de Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"alterar o estado de Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite que um aplicativo se conecte e desconecte dos pontos de acesso Wi-Fi e faça alterações nas redes Wi-Fi configuradas."</string>
+ <string name="permlab_accessFineLocation">"Localização precisa (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Acessa fontes de localização precisa como o GPS (Global Positioning System) no telefone, onde disponível. Aplicativos maliciosos podem usar isso para determinar onde você está e podem consumir energia adicional da bateria."</string>
+ <string name="permlab_accessCoarseLocation">"local aproximado (com base na rede)"</string>
+ <string name="permdesc_accessCoarseLocation">"Acessa fontes de localização aproximada como o banco de dados de rede celular para determinar a localização aproximada de um telefone, onde disponível. Aplicativos maliciosos podem usar isso para determinar aproximadamente onde você está."</string>
+ <string name="permlab_accessSurfaceFlinger">"acessar SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Permite que o aplicativo use recursos de nível inferior do SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"ler o buffer do frame"</string>
+ <string name="permdesc_readFrameBuffer">"Permite que o aplicativo a ser usado leia o conteúdo do buffer de frame."</string>
+ <string name="permlab_modifyAudioSettings">"alterar as suas configurações de áudio"</string>
+ <string name="permdesc_modifyAudioSettings">"Permite que o aplicativo modifique as configurações globais de áudio como volume e roteamento."</string>
+ <string name="permlab_recordAudio">"gravar áudio"</string>
+ <string name="permdesc_recordAudio">"Permite que um aplicativo acesse o caminho de gravação do áudio."</string>
+ <string name="permlab_camera">"tirar fotos"</string>
+ <string name="permdesc_camera">"Permite que o aplicativo tire fotos com a câmera. Isso permite que o aplicativo colete imagens vistas pela câmera a qualquer momento."</string>
+ <string name="permlab_brick">"desativar permanentemente o telefone"</string>
+ <string name="permdesc_brick">"Permite que o aplicativo desative o telefone inteiro permanentemente. Isso é muito perigoso."</string>
+ <string name="permlab_reboot">"forçar reinicialização do telefone"</string>
+ <string name="permdesc_reboot">"Permite que o aplicativo force a reinicialização do telefone."</string>
+ <string name="permlab_mount_unmount_filesystems">"montar e desmontar sistemas de arquivos"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Permite que o aplicativo monte e desmonte arquivos de sistema para armazenamento removível."</string>
+ <string name="permlab_mount_format_filesystems">"formatar armazenamento externo"</string>
+ <string name="permdesc_mount_format_filesystems">"Permite que o aplicativo formate o armazenamento removível."</string>
+ <string name="permlab_vibrate">"controlar o vibrador"</string>
+ <string name="permdesc_vibrate">"Permite que o aplicativo controle o vibrador."</string>
+ <string name="permlab_flashlight">"controlar lanterna"</string>
+ <string name="permdesc_flashlight">"Permite que o aplicativo controle a lanterna."</string>
+ <string name="permlab_hardware_test">"testar hardware"</string>
+ <string name="permdesc_hardware_test">"Permite que o aplicativo controle diversos periféricos para teste do hardware."</string>
+ <string name="permlab_callPhone">"chamar diretamente os números de telefone"</string>
+ <string name="permdesc_callPhone">"Permite que o aplicativo ligue para números de telefones sem a sua intervenção. Aplicativos maliciosos podem causar chamadas inesperadas na conta do seu telefone. Observe que isso não permite que o aplicativo ligue para números de emergência."</string>
+ <string name="permlab_callPrivileged">"chamar diretamente quaisquer números de telefone"</string>
+ <string name="permdesc_callPrivileged">"Permite que o aplicativo ligue para qualquer número de telefone, incluindo números de emergência, sem a sua intervenção. Aplicativos maliciosos podem fazer chamadas desnecessárias e ilegais para serviços de emergência."</string>
+ <string name="permlab_locationUpdates">"controlar as notificações de atualização do local"</string>
+ <string name="permdesc_locationUpdates">"Permite a ativação/desativação de notificações de atualização do local a partir do rádio. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_checkinProperties">"acessar propriedades de verificação"</string>
+ <string name="permdesc_checkinProperties">"Permite o acesso de leitura/gravação às propriedades enviadas pelo serviço de verificação. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_bindGadget">"escolher widgets"</string>
+ <string name="permdesc_bindGadget">"Permite que o aplicativo informe ao sistema quais widgets podem ser usados por quais aplicativos. Com essa permissão, os aplicativos podem conceder acesso aos dados pessoais a outros aplicativos. Não deve ser usado por aplicativos normais."</string>
+ <string name="permlab_modifyPhoneState">"modificar estado do telefone"</string>
+ <string name="permdesc_modifyPhoneState">"Permite que o aplicativo controle os recursos de telefone do dispositivo. Um aplicativo com essa permissão pode alternar redes, ligar e desligar o rádio do telefone e outras ações parecidas sem notificá-lo."</string>
+ <string name="permlab_readPhoneState">"ler estado do telefone"</string>
+ <string name="permdesc_readPhoneState">"Permite que o aplicativo acesse os recursos de telefone do dispositivo. Um aplicativo com essa permissão pode determinar o número desse telefone, se uma chamada está ativa, o número ao qual a chamada está conectada e outras informações parecidas."</string>
+ <string name="permlab_wakeLock">"impedir modo de inatividade do telefone"</string>
+ <string name="permdesc_wakeLock">"Permite que um aplicativo impeça o telefone de entrar no modo de inatividade."</string>
+ <string name="permlab_devicePower">"ligar ou desligar o telefone"</string>
+ <string name="permdesc_devicePower">"Permite que o aplicativo ative ou desative o telefone."</string>
+ <string name="permlab_factoryTest">"executar no modo de teste de fábrica"</string>
+ <string name="permdesc_factoryTest">"Executa como um teste do fabricante de nível inferior, permitindo o acesso completo ao hardware do telefone. Disponível apenas quando um telefone está em execução no modo de teste do fabricante."</string>
+ <string name="permlab_setWallpaper">"definir papel de parede"</string>
+ <string name="permdesc_setWallpaper">"Permite que o aplicativo defina o papel de parede do sistema."</string>
+ <string name="permlab_setWallpaperHints">"definir dicas de tamanho do papel de parede"</string>
+ <string name="permdesc_setWallpaperHints">"Permite que o aplicativo defina as dicas de tamanho do papel de parede do sistema."</string>
+ <string name="permlab_masterClear">"redefinir o sistema para os padrões de fábrica"</string>
+ <string name="permdesc_masterClear">"Permite que um aplicativo redefina completamente o sistema para as configurações de fábrica, apagando todos os dados, configuração e aplicativos instalados."</string>
+ <string name="permlab_setTimeZone">"definir fuso horário"</string>
+ <string name="permdesc_setTimeZone">"Permite que um aplicativo altere o fuso horário do telefone."</string>
+ <string name="permlab_getAccounts">"descobrir contas conhecidas"</string>
+ <string name="permdesc_getAccounts">"Permite que um aplicativo obtenha a lista de contas conhecidas pelo telefone."</string>
+ <string name="permlab_accessNetworkState">"ver estado da rede"</string>
+ <string name="permdesc_accessNetworkState">"Permite que um aplicativo veja o estado de todas as redes."</string>
+ <string name="permlab_createNetworkSockets">"acesso total da internet"</string>
+ <string name="permdesc_createNetworkSockets">"Permite que um aplicativo crie soquetes de rede."</string>
+ <string name="permlab_writeApnSettings">"gravar as configurações do Nome do ponto de acesso"</string>
+ <string name="permdesc_writeApnSettings">"Permite que um aplicativo modifique as configurações de APN, como Proxy e Porta de qualquer APN."</string>
+ <string name="permlab_changeNetworkState">"alterar conectividade da rede"</string>
+ <string name="permdesc_changeNetworkState">"Permite que um aplicativo altere o estado da conectividade de rede."</string>
+ <string name="permlab_changeBackgroundDataSetting">"alterar configuração de uso dos dados de segundo plano"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Permite que um aplicativo altere a configuração de uso dos dados de segundo plano."</string>
+ <string name="permlab_accessWifiState">"visualizar estado da rede Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"Permite que um aplicativo veja as informações sobre o estado de Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"alterar o estado de Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"Permite que um aplicativo se conecte e desconecte dos pontos de acesso Wi-Fi e faça alterações nas redes Wi-Fi configuradas."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administração de Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permite que um aplicativo configure o telefone Bluetooth local, descubra e pareie com dispositivos remotos."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"criar conexões Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Permite que um aplicativo veja a configuração do telefone Bluetooth local e que possa fazer e aceitar conexões com dispositivos pareados."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"desativar o bloqueio de teclas"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permite que um aplicativo desative o bloqueio de teclas e qualquer segurança por senha associada. Um exemplo legítimo disso é a desativação do bloqueio de teclas pelo telefone ao receber uma chamada e a reativação do bloqueio quando a chamada é finalizada."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler as configurações de sincronização"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Permite que um aplicativo leia as configurações de sincronização, como se a sincronização está ativada para Contatos."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"gravar configurações de sincronização"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Permite que um aplicativo modifique as configurações de sincronização, como a ativação da sincronização para Contatos."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"ler estatísticas de sincronização"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Permite que um aplicativo leia as estatísticas de sincronização; por exemplo, o histórico de sincronizações ocorridas."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds inscritos"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Permite que um aplicativo obtenha detalhes sobre os feeds sincronizados no momento."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"gravar feeds inscritos"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Permite que um aplicativo modifique os seus feeds atualmente sincronizados. Isso pode permitir que um aplicativo malicioso altere os seus feeds sincronizados."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"ler dicionário definido pelo usuário"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Permite que um aplicativo leia quaisquer palavras, nomes e frases particulares armazenados pelo usuário no dicionário do usuário."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"gravar no dicionário definido pelo usuário"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Permite que um aplicativo grave novas palavras no dicionário do usuário."</string>
+ <string name="permlab_bluetoothAdmin">"administração de Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Permite que um aplicativo configure o telefone Bluetooth local, descubra e pareie com dispositivos remotos."</string>
+ <string name="permlab_bluetooth">"criar conexões Bluetooth"</string>
+ <string name="permdesc_bluetooth">"Permite que um aplicativo veja a configuração do telefone Bluetooth local e que possa fazer e aceitar conexões com dispositivos pareados."</string>
+ <string name="permlab_disableKeyguard">"desativar o bloqueio de teclas"</string>
+ <string name="permdesc_disableKeyguard">"Permite que um aplicativo desative o bloqueio de teclas e qualquer segurança por senha associada. Um exemplo legítimo disso é a desativação do bloqueio de teclas pelo telefone ao receber uma chamada e a reativação do bloqueio quando a chamada é finalizada."</string>
+ <string name="permlab_readSyncSettings">"ler as configurações de sincronização"</string>
+ <string name="permdesc_readSyncSettings">"Permite que um aplicativo leia as configurações de sincronização, como se a sincronização está ativada para Contatos."</string>
+ <string name="permlab_writeSyncSettings">"gravar configurações de sincronização"</string>
+ <string name="permdesc_writeSyncSettings">"Permite que um aplicativo modifique as configurações de sincronização, como a ativação da sincronização para Contatos."</string>
+ <string name="permlab_readSyncStats">"ler estatísticas de sincronização"</string>
+ <string name="permdesc_readSyncStats">"Permite que um aplicativo leia as estatísticas de sincronização; por exemplo, o histórico de sincronizações ocorridas."</string>
+ <string name="permlab_subscribedFeedsRead">"ler feeds inscritos"</string>
+ <string name="permdesc_subscribedFeedsRead">"Permite que um aplicativo obtenha detalhes sobre os feeds sincronizados no momento."</string>
+ <string name="permlab_subscribedFeedsWrite">"gravar feeds inscritos"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Permite que um aplicativo modifique os seus feeds atualmente sincronizados. Isso pode permitir que um aplicativo malicioso altere os seus feeds sincronizados."</string>
+ <string name="permlab_readDictionary">"ler dicionário definido pelo usuário"</string>
+ <string name="permdesc_readDictionary">"Permite que um aplicativo leia quaisquer palavras, nomes e frases particulares armazenados pelo usuário no dicionário do usuário."</string>
+ <string name="permlab_writeDictionary">"gravar no dicionário definido pelo usuário"</string>
+ <string name="permdesc_writeDictionary">"Permite que um aplicativo grave novas palavras no dicionário do usuário."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Página inicial"</item>
- <item msgid="869923650527136615">"Celular"</item>
- <item msgid="7897544654242874543">"Trabalho"</item>
- <item msgid="1103601433382158155">"Fax do trabalho"</item>
- <item msgid="1735177144948329370">"Fax doméstico"</item>
- <item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Outros"</item>
- <item msgid="9192514806975898961">"Personalizado"</item>
+ <item>"Página inicial"</item>
+ <item>"Celular"</item>
+ <item>"Trabalho"</item>
+ <item>"Fax do trabalho"</item>
+ <item>"Fax doméstico"</item>
+ <item>"Pager"</item>
+ <item>"Outros"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Página inicial"</item>
- <item msgid="7084237356602625604">"Trabalho"</item>
- <item msgid="1112044410659011023">"Outros"</item>
- <item msgid="2374913952870110618">"Personalizado"</item>
+ <item>"Página inicial"</item>
+ <item>"Trabalho"</item>
+ <item>"Outros"</item>
+ <item>"Personalizado"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Celular"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Página inicial"</item>
- <item msgid="5629153956045109251">"Trabalho"</item>
- <item msgid="4966604264500343469">"Outros"</item>
- <item msgid="4932682847595299369">"Personalizado"</item>
+ <item>"Página inicial"</item>
+ <item>"Trabalho"</item>
+ <item>"Outros"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Página inicial"</item>
- <item msgid="1359644565647383708">"Trabalho"</item>
- <item msgid="7868549401053615677">"Outros"</item>
- <item msgid="3145118944639869809">"Personalizado"</item>
+ <item>"Página inicial"</item>
+ <item>"Trabalho"</item>
+ <item>"Outros"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Trabalho"</item>
- <item msgid="4378074129049520373">"Outros"</item>
- <item msgid="3455047468583965104">"Personalizado"</item>
+ <item>"Trabalho"</item>
+ <item>"Outros"</item>
+ <item>"Personalizado"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Digite o código PIN"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Código PIN incorreto!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, pressione Menu e, em seguida, 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Número de emergência"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Sem serviço)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Tela bloqueada."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pressione Menu para desbloquear."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenhe o padrão para desbloquear"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Chamada de emergência"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correto!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Tente novamente"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Carregando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Digite o código PIN"</string>
+ <string name="keyguard_password_wrong_pin_code">"Código PIN incorreto!"</string>
+ <string name="keyguard_label_text">"Para desbloquear, pressione Menu e, em seguida, 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Número de emergência"</string>
+ <string name="lockscreen_carrier_default">"(Sem serviço)"</string>
+ <string name="lockscreen_screen_locked">"Tela bloqueada."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Pressione Menu para desbloquear."</string>
+ <string name="lockscreen_pattern_instructions">"Desenhe o padrão para desbloquear"</string>
+ <string name="lockscreen_emergency_call">"Chamada de emergência"</string>
+ <string name="lockscreen_pattern_correct">"Correto!"</string>
+ <string name="lockscreen_pattern_wrong">"Tente novamente"</string>
+ <string name="lockscreen_plugged_in">"Carregando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecte o seu carregador."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Sem cartão SIM."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Não há um cartão SIM no telefone."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Insira um cartão SIM."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rede bloqueada"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"O cartão SIM está bloqueado pelo PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Consulte o Guia do Usuário ou entre em contato com o Serviço de atendimento ao cliente."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O cartão SIM está bloqueado."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando o cartão SIM…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Você desenhou incorretamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Você desenhou o seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas e você receberá uma solicitação para desbloquear o seu telefone usando o seu login do Google."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Esqueceu o padrão?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Muitas tentativas de padrão!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Para desbloquear, faça login com a sua Conta do Google."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nome de usuário (e-mail)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Senha"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Fazer login"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nome de usuário ou senha inválida."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Conecte o seu carregador."</string>
+ <string name="lockscreen_missing_sim_message_short">"Sem cartão SIM."</string>
+ <string name="lockscreen_missing_sim_message">"Não há um cartão SIM no telefone."</string>
+ <string name="lockscreen_missing_sim_instructions">"Insira um cartão SIM."</string>
+ <string name="lockscreen_network_locked_message">"Rede bloqueada"</string>
+ <string name="lockscreen_sim_puk_locked_message">"O cartão SIM está bloqueado pelo PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Consulte o Guia do Usuário ou entre em contato com o Serviço de atendimento ao cliente."</string>
+ <string name="lockscreen_sim_locked_message">"O cartão SIM está bloqueado."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Desbloqueando o cartão SIM…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Você desenhou incorretamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Você desenhou o seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas e você receberá uma solicitação para desbloquear o seu telefone usando o seu login do Google."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Esqueceu o padrão?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Muitas tentativas de padrão!"</string>
+ <string name="lockscreen_glogin_instructions">"Para desbloquear, faça login com a sua Conta do Google."</string>
+ <string name="lockscreen_glogin_username_hint">"Nome de usuário (e-mail)"</string>
+ <string name="lockscreen_glogin_password_hint">"Senha"</string>
+ <string name="lockscreen_glogin_submit_button">"Fazer login"</string>
+ <string name="lockscreen_glogin_invalid_input">"Nome de usuário ou senha inválida."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em andamento"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Carregando..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Conecte o carregador"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"A bateria está ficando baixa:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"menos de <xliff:g id="NUMBER">%d%%</xliff:g> restantes."</string>
+ <string name="status_bar_no_notifications_title">"Sem notificações"</string>
+ <string name="status_bar_ongoing_events_title">"Em andamento"</string>
+ <string name="status_bar_latest_events_title">"Notificações"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Carregando..."</string>
+ <string name="battery_low_title">"Conecte o carregador"</string>
+ <string name="battery_low_subtitle">"A bateria está ficando baixa:"</string>
+ <string name="battery_low_percent_format">"menos de <xliff:g id="NUMBER">%d%%</xliff:g> restantes."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Falha no teste de fábrica"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"A ação FACTORY_TEST é suportada apenas para pacotes instalados em /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Nenhum pacote que forneça a ação FACTORY_TEST foi encontrado."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" mostra:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Deseja sair desta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecione OK para continuar ou Cancelar para permanecer na página atual."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
+ <string name="factorytest_failed">"Falha no teste de fábrica"</string>
+ <string name="factorytest_not_system">"A ação FACTORY_TEST é suportada apenas para pacotes instalados em /system/app."</string>
+ <string name="factorytest_no_action">"Nenhum pacote que forneça a ação FACTORY_TEST foi encontrado."</string>
+ <string name="factorytest_reboot">"Reiniciar"</string>
+ <string name="js_dialog_title">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" mostra:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Deseja sair desta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecione OK para continuar ou Cancelar para permanecer na página atual."</string>
+ <string name="save_password_label">"Confirmar"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Deseja que o navegador lembre desta senha?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Nunca"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Você não tem permissão para abrir esta página."</string>
- <string name="text_copied" msgid="4985729524670131385">"Texto copiado para a área de transferência."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Mais"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"espaço"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"excluir"</string>
- <string name="search_go" msgid="8298016669822141719">"Pesquisar"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mês atrás"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Antes de 1 mês atrás"</string>
+ <string name="save_password_message">"Deseja que o navegador lembre desta senha?"</string>
+ <string name="save_password_notnow">"Agora não"</string>
+ <string name="save_password_remember">"Lembrar"</string>
+ <string name="save_password_never">"Nunca"</string>
+ <string name="open_permission_deny">"Você não tem permissão para abrir esta página."</string>
+ <string name="text_copied">"Texto copiado para a área de transferência."</string>
+ <string name="more_item_label">"Mais"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"espaço"</string>
+ <string name="menu_enter_shortcut_label">"enter"</string>
+ <string name="menu_delete_shortcut_label">"excluir"</string>
+ <string name="search_go">"Pesquisar"</string>
+ <string name="oneMonthDurationPast">"1 mês atrás"</string>
+ <string name="beforeOneMonthDurationPast">"Antes de 1 mês atrás"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 segundo atrás"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> segundos atrás"</item>
+ <item quantity="one">"1 segundo atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> segundos atrás"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 minuto atrás"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
+ <item quantity="one">"1 minuto atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 hora atrás"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
+ <item quantity="one">"1 hora atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"ontem"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
+ <item quantity="one">"ontem"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"em 1 segundo"</item>
- <item quantity="other" msgid="1241926116443974687">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"em 1 segundo"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"em 1 minuto"</item>
- <item quantity="other" msgid="3330713936399448749">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"em 1 minuto"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"em 1 hora"</item>
- <item quantity="other" msgid="547290677353727389">"Em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"em 1 hora"</item>
+ <item quantity="other">"Em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"amanhã"</item>
- <item quantity="other" msgid="5109449375100953247">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"amanhã"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 seg. atrás"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> segundos\n atrás"</item>
+ <item quantity="one">"1 seg. atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> segundos\n atrás"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 minuto atrás"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
+ <item quantity="one">"1 minuto atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 hora atrás"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
+ <item quantity="one">"1 hora atrás"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"ontem"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
+ <item quantity="one">"ontem"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"em 1 segundo"</item>
- <item quantity="other" msgid="5495880108825805108">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ <item quantity="one">"em 1 segundo"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"em 1 minuto"</item>
- <item quantity="other" msgid="4216113292706568726">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ <item quantity="one">"em 1 minuto"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"em 1 hora"</item>
- <item quantity="other" msgid="3705373766798013406">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ <item quantity="one">"em 1 hora"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"amanhã"</item>
- <item quantity="other" msgid="2973062968038355991">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
+ <item quantity="one">"amanhã"</item>
+ <item quantity="other">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"em %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"às %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"em %s"</string>
- <string name="day" msgid="8144195776058119424">"dia"</string>
- <string name="days" msgid="4774547661021344602">"dias"</string>
- <string name="hour" msgid="2126771916426189481">"hora"</string>
- <string name="hours" msgid="894424005266852993">"horas"</string>
- <string name="minute" msgid="9148878657703769868">"min."</string>
- <string name="minutes" msgid="5646001005827034509">"min."</string>
- <string name="second" msgid="3184235808021478">"seg."</string>
- <string name="seconds" msgid="3161515347216589235">"segundos"</string>
- <string name="week" msgid="5617961537173061583">"semana"</string>
- <string name="weeks" msgid="6509623834583944518">"semanas"</string>
- <string name="year" msgid="4001118221013892076">"ano"</string>
- <string name="years" msgid="6881577717993213522">"anos"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Todos os dias da semana (de segunda a sexta)"</string>
- <string name="daily" msgid="5738949095624133403">"Diariamente"</string>
- <string name="weekly" msgid="983428358394268344">"Semanalmente na <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Mensalmente"</string>
- <string name="yearly" msgid="1519577999407493836">"Anualmente"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Não é possível reproduzir o vídeo"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Este vídeo não é válido para transmissão com este dispositivo."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Este vídeo não pode ser reproduzido."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"meio-dia"</string>
- <string name="Noon" msgid="3342127745230013127">"Meio-dia"</string>
- <string name="midnight" msgid="7166259508850457595">"meia-noite"</string>
- <string name="Midnight" msgid="5630806906897892201">"Meia-noite"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Selecionar tudo"</string>
- <string name="selectText" msgid="3889149123626888637">"Selecionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Parar seleção de texto"</string>
- <string name="cut" msgid="3092569408438626261">"Recortar"</string>
- <string name="cutAll" msgid="2436383270024931639">"Recortar tudo"</string>
- <string name="copy" msgid="2681946229533511987">"Copiar"</string>
- <string name="copyAll" msgid="2590829068100113057">"Copiar tudo"</string>
- <string name="paste" msgid="5629880836805036433">"Colar"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Método de entrada"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Adicionar \"%s\" ao dicionário"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Editar texto"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Pouco espaço"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"O espaço de armazenamento do telefone está ficando baixo."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Cancelar"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Atenção"</string>
- <string name="capital_on" msgid="1544682755514494298">"ATIVADO"</string>
- <string name="capital_off" msgid="6815870386972805832">"DESATIVADO"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Complete a ação usando"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Use o como padrão para esta ação."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Limpar o padrão em Configurações da página inicial &gt; Aplicativos &gt; Gerenciar aplicativos."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Selecionar uma ação"</string>
- <string name="noApplications" msgid="1691104391758345586">"Nenhum aplicativo pode realizar esta ação."</string>
- <string name="aerr_title" msgid="653922989522758100">"Desculpe!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou inesperadamente. Tente novamente."</string>
- <string name="aerr_process" msgid="1551785535966089511">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> parou inesperadamente. Tente novamente."</string>
- <string name="anr_title" msgid="3100070910664756057">"Desculpe!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no aplicativo <xliff:g id="APPLICATION">%2$s</xliff:g>) não está respondendo."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está respondendo."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está respondendo."</string>
- <string name="anr_process" msgid="1246866008169975783">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está respondendo."</string>
- <string name="force_close" msgid="3653416315450806396">"Forçar fechamento"</string>
+ <string name="preposition_for_date">"em %s"</string>
+ <string name="preposition_for_time">"às %s"</string>
+ <string name="preposition_for_year">"em %s"</string>
+ <string name="day">"dia"</string>
+ <string name="days">"dias"</string>
+ <string name="hour">"hora"</string>
+ <string name="hours">"horas"</string>
+ <string name="minute">"min."</string>
+ <string name="minutes">"min."</string>
+ <string name="second">"seg."</string>
+ <string name="seconds">"segundos"</string>
+ <string name="week">"semana"</string>
+ <string name="weeks">"semanas"</string>
+ <string name="year">"ano"</string>
+ <string name="years">"anos"</string>
+ <string name="every_weekday">"Todos os dias da semana (de segunda a sexta)"</string>
+ <string name="daily">"Diariamente"</string>
+ <string name="weekly">"Semanalmente na <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Mensalmente"</string>
+ <string name="yearly">"Anualmente"</string>
+ <string name="VideoView_error_title">"Não é possível reproduzir o vídeo"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Este vídeo não é válido para transmissão com este dispositivo."</string>
+ <string name="VideoView_error_text_unknown">"Este vídeo não pode ser reproduzido."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"meio-dia"</string>
+ <string name="Noon">"Meio-dia"</string>
+ <string name="midnight">"meia-noite"</string>
+ <string name="Midnight">"Meia-noite"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Selecionar tudo"</string>
+ <string name="selectText">"Selecionar texto"</string>
+ <string name="stopSelectingText">"Parar seleção de texto"</string>
+ <string name="cut">"Recortar"</string>
+ <string name="cutAll">"Recortar tudo"</string>
+ <string name="copy">"Copiar"</string>
+ <string name="copyAll">"Copiar tudo"</string>
+ <string name="paste">"Colar"</string>
+ <string name="copyUrl">"Copiar URL"</string>
+ <string name="inputMethod">"Método de entrada"</string>
+ <string name="addToDictionary">"Adicionar \"%s\" ao dicionário"</string>
+ <string name="editTextMenuTitle">"Editar texto"</string>
+ <string name="low_internal_storage_view_title">"Pouco espaço"</string>
+ <string name="low_internal_storage_view_text">"O espaço de armazenamento do telefone está ficando baixo."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Cancelar"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Cancelar"</string>
+ <string name="dialog_alert_title">"Atenção"</string>
+ <string name="capital_on">"ATIVADO"</string>
+ <string name="capital_off">"DESATIVADO"</string>
+ <string name="whichApplication">"Complete a ação usando"</string>
+ <string name="alwaysUse">"Use o como padrão para esta ação."</string>
+ <string name="clearDefaultHintMsg">"Limpar o padrão em Configurações da página inicial &gt; Aplicativos &gt; Gerenciar aplicativos."</string>
+ <string name="chooseActivity">"Selecionar uma ação"</string>
+ <string name="noApplications">"Nenhum aplicativo pode realizar esta ação."</string>
+ <string name="aerr_title">"Desculpe!"</string>
+ <string name="aerr_application">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou inesperadamente. Tente novamente."</string>
+ <string name="aerr_process">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> parou inesperadamente. Tente novamente."</string>
+ <string name="anr_title">"Desculpe!"</string>
+ <string name="anr_activity_application">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no aplicativo <xliff:g id="APPLICATION">%2$s</xliff:g>) não está respondendo."</string>
+ <string name="anr_activity_process">"A atividade <xliff:g id="ACTIVITY">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está respondendo."</string>
+ <string name="anr_application_process">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (no processo <xliff:g id="PROCESS">%2$s</xliff:g>) não está respondendo."</string>
+ <string name="anr_process">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> não está respondendo."</string>
+ <string name="force_close">"Forçar fechamento"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Aguardar"</string>
- <string name="debug" msgid="9103374629678531849">"Depurar"</string>
- <string name="sendText" msgid="5132506121645618310">"Selecione uma ação para o texto"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string>
- <string name="volume_music" msgid="5421651157138628171">"Volume da mídia"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Reproduzindo por meio de Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Volume na chamada"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volume de chamada Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Volume do alarme"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Volume da notificação"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volume"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Toque padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Silencioso"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string>
+ <string name="wait">"Aguardar"</string>
+ <string name="debug">"Depurar"</string>
+ <string name="sendText">"Selecione uma ação para o texto"</string>
+ <string name="volume_ringtone">"Volume da campainha"</string>
+ <string name="volume_music">"Volume da mídia"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Reproduzindo por meio de Bluetooth"</string>
+ <string name="volume_call">"Volume na chamada"</string>
+ <string name="volume_bluetooth_call">"Volume de chamada Bluetooth"</string>
+ <string name="volume_alarm">"Volume do alarme"</string>
+ <string name="volume_notification">"Volume da notificação"</string>
+ <string name="volume_unknown">"Volume"</string>
+ <string name="ringtone_default">"Toque padrão"</string>
+ <string name="ringtone_default_with_actual">"Toque padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Silencioso"</string>
+ <string name="ringtone_picker_title">"Toques"</string>
+ <string name="ringtone_unknown">"Toque desconhecido"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Rede Wi-Fi disponível"</item>
- <item quantity="other" msgid="4192424489168397386">"Redes Wi-Fi disponíveis"</item>
+ <item quantity="one">"Rede Wi-Fi disponível"</item>
+ <item quantity="other">"Redes Wi-Fi disponíveis"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Rede Wi-Fi aberta disponível"</item>
- <item quantity="other" msgid="7915895323644292768">"Redes Wi-Fi abertas disponíveis"</item>
+ <item quantity="one">"Rede Wi-Fi aberta disponível"</item>
+ <item quantity="other">"Redes Wi-Fi abertas disponíveis"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Inserir caractere"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Aplicativo desconhecido"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensagens SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Muitas mensagens SMS estão sendo enviadas. Selecione \"OK\" para continuar ou \"Cancelar\" para interromper o envio."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Definir"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Padrão"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Nenhuma permissão necessária"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Ocultar"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar todas"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Carregando..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"Conectado por USB"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Você conectou o telefone ao computador via USB. Selecione \"Montar\" se quiser copiar arquivos entre o computador e o cartão SD do seu telefone."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Montar"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Não montar"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Há um problema com o uso do seu cartão SD para armazenamento USB."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"Conectado por USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Selecione para copiar arquivos para/do seu computador."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Desativar o armazenamento USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Selecione para desativar o armazenamento USB."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Desativar o armazenamento USB"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Antes de desativar o armazenamento USB, desmonte o host USB. Selecione \"Desativar\" para desativar o armazenamento USB."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Desativar"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Cancelar"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Encontramos um problema ao desativar o armazenamento USB. Verifique se desmontou o host USB e tente novamente."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatar cartão SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Tem certeza de que deseja formatar o cartão SD? Todos os dados no seu cartão serão perdidos."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatar"</string>
+ <string name="select_character">"Inserir caractere"</string>
+ <string name="sms_control_default_app_name">"Aplicativo desconhecido"</string>
+ <string name="sms_control_title">"Enviando mensagens SMS"</string>
+ <string name="sms_control_message">"Muitas mensagens SMS estão sendo enviadas. Selecione \"OK\" para continuar ou \"Cancelar\" para interromper o envio."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Cancelar"</string>
+ <string name="date_time_set">"Definir"</string>
+ <string name="default_permission_group">"Padrão"</string>
+ <string name="no_permissions">"Nenhuma permissão necessária"</string>
+ <string name="perms_hide"><b>"Ocultar"</b></string>
+ <string name="perms_show_all"><b>"Mostrar todas"</b></string>
+ <string name="googlewebcontenthelper_loading">"Carregando..."</string>
+ <string name="usb_storage_title">"Conectado por USB"</string>
+ <string name="usb_storage_message">"Você conectou o telefone ao computador via USB. Selecione \"Montar\" se quiser copiar arquivos entre o computador e o cartão SD do seu telefone."</string>
+ <string name="usb_storage_button_mount">"Montar"</string>
+ <string name="usb_storage_button_unmount">"Não montar"</string>
+ <string name="usb_storage_error_message">"Há um problema com o uso do seu cartão SD para armazenamento USB."</string>
+ <string name="usb_storage_notification_title">"Conectado por USB"</string>
+ <string name="usb_storage_notification_message">"Selecione para copiar arquivos para/do seu computador."</string>
+ <string name="usb_storage_stop_notification_title">"Desativar o armazenamento USB"</string>
+ <string name="usb_storage_stop_notification_message">"Selecione para desativar o armazenamento USB."</string>
+ <string name="usb_storage_stop_title">"Desativar o armazenamento USB"</string>
+ <string name="usb_storage_stop_message">"Antes de desativar o armazenamento USB, desmonte o host USB. Selecione \"Desativar\" para desativar o armazenamento USB."</string>
+ <string name="usb_storage_stop_button_mount">"Desativar"</string>
+ <string name="usb_storage_stop_button_unmount">"Cancelar"</string>
+ <string name="usb_storage_stop_error_message">"Encontramos um problema ao desativar o armazenamento USB. Verifique se desmontou o host USB e tente novamente."</string>
+ <string name="extmedia_format_title">"Formatar cartão SD"</string>
+ <string name="extmedia_format_message">"Tem certeza de que deseja formatar o cartão SD? Todos os dados no seu cartão serão perdidos."</string>
+ <string name="extmedia_format_button_format">"Formatar"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Selecionar método de entrada"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Preparando o cartão SD"</string>
+ <string name="select_input_method">"Selecionar método de entrada"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidatos"</u></string>
+ <string name="ext_media_checking_notification_title">"Preparando o cartão SD"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Cartão SD em branco"</string>
+ <string name="ext_media_nofs_notification_title">"Cartão SD em branco"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Cartão SD danificado"</string>
+ <string name="ext_media_unmountable_notification_title">"Cartão SD danificado"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Cartão SD removido inesperadamente."</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Desmonte o cartão SD antes da remoção para evitar a perda de dados."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"O cartão SD já pode ser removido com segurança."</string>
+ <string name="ext_media_badremoval_notification_title">"Cartão SD removido inesperadamente."</string>
+ <string name="ext_media_badremoval_notification_message">"Desmonte o cartão SD antes da remoção para evitar a perda de dados."</string>
+ <string name="ext_media_safe_unmount_notification_title">"O cartão SD já pode ser removido com segurança."</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Cartão SD removido"</string>
+ <string name="ext_media_nomedia_notification_title">"Cartão SD removido"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Nenhum atividade correspondente foi encontrada"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"atualizar estatísticas de uso do componente"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permite a modificação das estatísticas de uso do componente coletadas. Não deve ser usado por aplicativos normais."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Toque duas vezes para ter controle do zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Erro ao aumentar o widget"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Ir"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Pesquisar"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Enviar"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Próximo"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Concluído"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Executar"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Discar número"\n"usando <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Criar contato "\n"usando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Nenhum atividade correspondente foi encontrada"</string>
+ <string name="permlab_pkgUsageStats">"atualizar estatísticas de uso do componente"</string>
+ <string name="permdesc_pkgUsageStats">"Permite a modificação das estatísticas de uso do componente coletadas. Não deve ser usado por aplicativos normais."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Toque duas vezes para ter controle do zoom"</string>
+ <string name="gadget_host_error_inflating">"Erro ao aumentar o widget"</string>
+ <string name="ime_action_go">"Ir"</string>
+ <string name="ime_action_search">"Pesquisar"</string>
+ <string name="ime_action_send">"Enviar"</string>
+ <string name="ime_action_next">"Próximo"</string>
+ <string name="ime_action_done">"Concluído"</string>
+ <string name="ime_action_default">"Executar"</string>
+ <string name="dial_number_using">"Discar número"\n"usando <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Criar contato "\n"usando <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8613540..22120f6 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"Б"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"КБ"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"МБ"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"ГБ"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TБ"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"ПБ"</string>
+ <string name="byteShort">"Б"</string>
+ <string name="kilobyteShort">"КБ"</string>
+ <string name="megabyteShort">"МБ"</string>
+ <string name="gigabyteShort">"ГБ"</string>
+ <string name="terabyteShort">"TБ"</string>
+ <string name="petabyteShort">"ПБ"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"&lt;без названиÑ&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Ðет номера телефона)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(ÐеизвеÑтно)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ГолоÑÐ¾Ð²Ð°Ñ Ð¿Ð¾Ñ‡Ñ‚Ð°"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Ðеполадки Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ неверный код MMI."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Служба включена."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Служба подключена длÑ:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Служба отключена."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¾Ð¹Ð´ÐµÐ½Ð° уÑпешно."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Удаление выполнено уÑпешно."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Ðеверный пароль."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"Ð—Ð°Ð¿Ñ€Ð¾Ñ MMI завершен."</string>
- <string name="badPin" msgid="5085454289896032547">"Введен неверный Ñтарый PUK."</string>
- <string name="badPuk" msgid="5702522162746042460">"Введен неверный PUK."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Введенные PIN-коды не Ñовпадают."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Введите PIN-код (от 4 до 8 цифр)."</string>
- <string name="needPuk" msgid="919668385956251611">"SIM-карта заблокирована Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ кода PUK. Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ введите код PUK."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ SIM-карты введите PUK2."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð²Ñ‹Ð·Ñ‹Ð²Ð°ÑŽÑ‰ÐµÐ³Ð¾ абонента"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð·Ð²Ð¾Ð½Ñщего абонента"</string>
- <string name="CfMmi" msgid="5123218989141573515">"ПереадреÑÐ°Ñ†Ð¸Ñ Ð²Ñ‹Ð·Ð¾Ð²Ð°"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Параллельный вызов"</string>
- <string name="BaMmi" msgid="455193067926770581">"Запрет вызовов"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Смена паролÑ"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Смена PIN"</string>
+ <string name="untitled">"&lt;без названиÑ&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Ðет номера телефона)"</string>
+ <string name="unknownName">"(ÐеизвеÑтно)"</string>
+ <string name="defaultVoiceMailAlphaTag">"ГолоÑÐ¾Ð²Ð°Ñ Ð¿Ð¾Ñ‡Ñ‚Ð°"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Ðеполадки Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ неверный код MMI."</string>
+ <string name="serviceEnabled">"Служба включена."</string>
+ <string name="serviceEnabledFor">"Служба подключена длÑ:"</string>
+ <string name="serviceDisabled">"Служба отключена."</string>
+ <string name="serviceRegistered">"РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¾Ð¹Ð´ÐµÐ½Ð° уÑпешно."</string>
+ <string name="serviceErased">"Удаление выполнено уÑпешно."</string>
+ <string name="passwordIncorrect">"Ðеверный пароль."</string>
+ <string name="mmiComplete">"Ð—Ð°Ð¿Ñ€Ð¾Ñ MMI завершен."</string>
+ <string name="badPin">"Введен неверный Ñтарый PUK."</string>
+ <string name="badPuk">"Введен неверный PUK."</string>
+ <string name="mismatchPin">"Введенные PIN-коды не Ñовпадают."</string>
+ <string name="invalidPin">"Введите PIN-код (от 4 до 8 цифр)."</string>
+ <string name="needPuk">"SIM-карта заблокирована Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ кода PUK. Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ введите код PUK."</string>
+ <string name="needPuk2">"Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ SIM-карты введите PUK2."</string>
+ <string name="ClipMmi">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð²Ñ‹Ð·Ñ‹Ð²Ð°ÑŽÑ‰ÐµÐ³Ð¾ абонента"</string>
+ <string name="ClirMmi">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð·Ð²Ð¾Ð½Ñщего абонента"</string>
+ <string name="CfMmi">"ПереадреÑÐ°Ñ†Ð¸Ñ Ð²Ñ‹Ð·Ð¾Ð²Ð°"</string>
+ <string name="CwMmi">"Параллельный вызов"</string>
+ <string name="BaMmi">"Запрет вызовов"</string>
+ <string name="PwdMmi">"Смена паролÑ"</string>
+ <string name="PinMmi">"Смена PIN"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð°Ð±Ð¾Ð½ÐµÐ½Ñ‚Ð° по умолчанию запрещена. След. вызов: запрещена"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð°Ð±Ð¾Ð½ÐµÐ½Ñ‚Ð° по умолчанию запрещена. След. вызов: разрешена"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð°Ð±Ð¾Ð½ÐµÐ½Ñ‚Ð° по умолчанию не запрещена. След. вызов: запрещена"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð°Ð±Ð¾Ð½ÐµÐ½Ñ‚Ð° по умолчанию не запрещена. След. вызов: разрешена"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"УÑлуга не предоÑтавлÑетÑÑ."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Ðевозможно изменить наÑтройку идентификации абонента."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"ÐžÐ³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтупа изменены"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Служба данных заблокирована."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Служба ÑкÑтренной помощи заблокирована."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Служба передачи SMS/голоÑовых Ñообщений заблокирована."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Ð’Ñе Ñлужбы передачи SMS/голоÑовых Ñообщений заблокированы."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"ГолоÑÐ¾Ð²Ð°Ñ ÑвÑзь"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Данные"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"ФÐКС"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"ÐÑинхр."</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Синхр."</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Пакет"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð°Ð±Ð¾Ð½ÐµÐ½Ñ‚Ð° по умолчанию запрещена. След. вызов: запрещена"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð°Ð±Ð¾Ð½ÐµÐ½Ñ‚Ð° по умолчанию запрещена. След. вызов: разрешена"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð°Ð±Ð¾Ð½ÐµÐ½Ñ‚Ð° по умолчанию не запрещена. След. вызов: запрещена"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð°Ð±Ð¾Ð½ÐµÐ½Ñ‚Ð° по умолчанию не запрещена. След. вызов: разрешена"</string>
+ <string name="serviceNotProvisioned">"УÑлуга не предоÑтавлÑетÑÑ."</string>
+ <string name="CLIRPermanent">"Ðевозможно изменить наÑтройку идентификации абонента."</string>
+ <string name="RestrictedChangedTitle">"ÐžÐ³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтупа изменены"</string>
+ <string name="RestrictedOnData">"Служба данных заблокирована."</string>
+ <string name="RestrictedOnEmergency">"Служба ÑкÑтренной помощи заблокирована."</string>
+ <string name="RestrictedOnNormal">"Служба передачи SMS/голоÑовых Ñообщений заблокирована."</string>
+ <string name="RestrictedOnAll">"Ð’Ñе Ñлужбы передачи SMS/голоÑовых Ñообщений заблокированы."</string>
+ <string name="serviceClassVoice">"ГолоÑÐ¾Ð²Ð°Ñ ÑвÑзь"</string>
+ <string name="serviceClassData">"Данные"</string>
+ <string name="serviceClassFAX">"ФÐКС"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"ÐÑинхр."</string>
+ <string name="serviceClassDataSync">"Синхр."</string>
+ <string name="serviceClassPacket">"Пакет"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не переадреÑовано"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> через <xliff:g id="TIME_DELAY">{2}</xliff:g> Ñ."</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ðе переадреÑовано"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ðе переадреÑовано"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не переадреÑовано"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> через <xliff:g id="TIME_DELAY">{2}</xliff:g> Ñ."</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ðе переадреÑовано"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ðе переадреÑовано"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"ОК"</string>
- <string name="httpError" msgid="2567300624552921790">"Ошибка на веб-Ñтранице."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Ðе удалоÑÑŒ найти URL."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Схема аутентификации Ñайта не поддерживаетÑÑ."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Ðе удалоÑÑŒ провеÑти аутентификацию."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Ðе удалоÑÑŒ выполнить аутентификацию через прокÑи-Ñервер."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Ðе удалоÑÑŒ подключитьÑÑ Ðº Ñерверу."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Сервер не отвечает. Повторите попытку позднее."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Ð’Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ Ñервером иÑтекло."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Страница Ñодержит Ñлишком много перенаправлений Ñервера."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Этот протокол не поддерживаетÑÑ."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Ðе удалоÑÑŒ уÑтановить безопаÑное Ñоединение."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Ðе удалоÑÑŒ открыть Ñтраницу. Указан недопуÑтимый URL."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ доÑтуп к файлу."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Ðе удалоÑÑŒ найти указанные файлы."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"ОбрабатываетÑÑ Ñлишком много запроÑов. Повторите попытку позднее."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Синхр."</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхр."</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Слишком много удалений <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" msgid="6632412458436461203">"ПамÑÑ‚ÑŒ телефона заполнена! Удалите файлы, чтобы оÑвободить меÑто."</string>
- <string name="me" msgid="6545696007631404292">"Я"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Параметры телефона"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Тихий режим"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Включить беÑпроводную ÑвÑзь"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Отключить беÑпроводное Ñоединение"</string>
- <string name="screen_lock" msgid="799094655496098153">"Блокировка Ñкрана"</string>
- <string name="power_off" msgid="4266614107412865048">"Выключить ÑвÑзь"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Выключение..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Телефон будет отключен."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Ðет поÑледних приложений."</string>
- <string name="global_actions" msgid="2406416831541615258">"Параметры телефона"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Блокировка Ñкрана"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Отключить питание"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Тихий режим"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Звук ВЫКЛ"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Звук ВКЛЮЧЕÐ"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим полета"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим полета ВКЛЮЧЕÐ"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим полета ВЫКЛЮЧЕÐ"</string>
- <string name="safeMode" msgid="2788228061547930246">"БезопаÑный режим"</string>
- <string name="android_system_label" msgid="6577375335728551336">"СиÑтема Android"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Платные уÑлуги"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Разрешать приложениÑм иÑпользовать платные уÑлуги."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"СообщениÑ"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Считывать и запиÑывать SMS, Ñлектронные пиÑьма и другие ÑообщениÑ."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Ð›Ð¸Ñ‡Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"ПрÑмой доÑтуп к контактам и ÑобытиÑм календарÑ, Ñохраненным в памÑти телефона."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Ваше меÑтоположение"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"ОтÑлеживание физичеÑкого меÑтоположениÑ"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Сетевой обмен данными"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"ПозволÑет приложениÑм получать доÑтуп к различным Ñетевым функциÑм."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Ваши аккаунты Google"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Входить в доÑтупные аккаунты Google."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Элементы ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð°Ð¿Ð¿Ð°Ñ€Ð°Ñ‚Ð½Ñ‹Ð¼ обеÑпечением"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"ПрÑмой доÑтуп к аппаратному обеÑпечению телефона."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Телефонные вызовы"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"ОтÑлеживать, запиÑывать и обрабатывать телефонные звонки."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"СиÑтемные инÑтрументы"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"ДоÑтуп нижнего ÑƒÑ€Ð¾Ð²Ð½Ñ Ð¸ управление ÑиÑтемой."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"ИнÑтрументы разработки"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Функции, необходимые только разработчикам приложений."</string>
+ <string name="httpErrorOk">"ОК"</string>
+ <string name="httpError">"Ошибка на веб-Ñтранице."</string>
+ <string name="httpErrorLookup">"Ðе удалоÑÑŒ найти URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Схема аутентификации Ñайта не поддерживаетÑÑ."</string>
+ <string name="httpErrorAuth">"Ðе удалоÑÑŒ провеÑти аутентификацию."</string>
+ <string name="httpErrorProxyAuth">"Ðе удалоÑÑŒ выполнить аутентификацию через прокÑи-Ñервер."</string>
+ <string name="httpErrorConnect">"Ðе удалоÑÑŒ подключитьÑÑ Ðº Ñерверу."</string>
+ <string name="httpErrorIO">"Сервер не отвечает. Повторите попытку позднее."</string>
+ <string name="httpErrorTimeout">"Ð’Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ Ñервером иÑтекло."</string>
+ <string name="httpErrorRedirectLoop">"Страница Ñодержит Ñлишком много перенаправлений Ñервера."</string>
+ <string name="httpErrorUnsupportedScheme">"Этот протокол не поддерживаетÑÑ."</string>
+ <string name="httpErrorFailedSslHandshake">"Ðе удалоÑÑŒ уÑтановить безопаÑное Ñоединение."</string>
+ <string name="httpErrorBadUrl">"Ðе удалоÑÑŒ открыть Ñтраницу. Указан недопуÑтимый URL."</string>
+ <string name="httpErrorFile">"Ðе удаетÑÑ Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ доÑтуп к файлу."</string>
+ <string name="httpErrorFileNotFound">"Ðе удалоÑÑŒ найти указанные файлы."</string>
+ <string name="httpErrorTooManyRequests">"ОбрабатываетÑÑ Ñлишком много запроÑов. Повторите попытку позднее."</string>
+ <string name="contentServiceSync">"Синхр."</string>
+ <string name="contentServiceSyncNotificationTitle">"Синхр."</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Слишком много удалений <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"ПамÑÑ‚ÑŒ телефона заполнена! Удалите файлы, чтобы оÑвободить меÑто."</string>
+ <string name="me">"Я"</string>
+ <string name="power_dialog">"Параметры телефона"</string>
+ <string name="silent_mode">"Беззвучный режим"</string>
+ <string name="turn_on_radio">"Включить беÑпроводную ÑвÑзь"</string>
+ <string name="turn_off_radio">"Отключить беÑпроводное Ñоединение"</string>
+ <string name="screen_lock">"Блокировка Ñкрана"</string>
+ <string name="power_off">"Выключить ÑвÑзь"</string>
+ <string name="shutdown_progress">"Выключение..."</string>
+ <string name="shutdown_confirm">"Телефон будет отключен."</string>
+ <string name="no_recent_tasks">"Ðет поÑледних приложений."</string>
+ <string name="global_actions">"Параметры телефона"</string>
+ <string name="global_action_lock">"Блокировка Ñкрана"</string>
+ <string name="global_action_power_off">"Отключить питание"</string>
+ <string name="global_action_toggle_silent_mode">"Беззвучный режим"</string>
+ <string name="global_action_silent_mode_on_status">"Звук ВЫКЛ"</string>
+ <string name="global_action_silent_mode_off_status">"Звук ВКЛЮЧЕÐ"</string>
+ <string name="global_actions_toggle_airplane_mode">"Режим полета"</string>
+ <string name="global_actions_airplane_mode_on_status">"Режим полета ВКЛЮЧЕÐ"</string>
+ <string name="global_actions_airplane_mode_off_status">"Режим полета ВЫКЛЮЧЕÐ"</string>
+ <string name="safeMode">"БезопаÑный режим"</string>
+ <string name="android_system_label">"СиÑтема Android"</string>
+ <string name="permgrouplab_costMoney">"Платные уÑлуги"</string>
+ <string name="permgroupdesc_costMoney">"Разрешать приложениÑм иÑпользовать платные уÑлуги."</string>
+ <string name="permgrouplab_messages">"СообщениÑ"</string>
+ <string name="permgroupdesc_messages">"Считывать и запиÑывать SMS, Ñлектронные пиÑьма и другие ÑообщениÑ."</string>
+ <string name="permgrouplab_personalInfo">"Ð›Ð¸Ñ‡Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ"</string>
+ <string name="permgroupdesc_personalInfo">"ПрÑмой доÑтуп к контактам и ÑобытиÑм календарÑ, Ñохраненным в памÑти телефона."</string>
+ <string name="permgrouplab_location">"Ваше меÑтоположение"</string>
+ <string name="permgroupdesc_location">"ОтÑлеживание физичеÑкого меÑтоположениÑ"</string>
+ <string name="permgrouplab_network">"Сетевой обмен данными"</string>
+ <string name="permgroupdesc_network">"ПозволÑет приложениÑм получать доÑтуп к различным Ñетевым функциÑм."</string>
+ <string name="permgrouplab_accounts">"Ваши аккаунты Google"</string>
+ <string name="permgroupdesc_accounts">"Входить в доÑтупные аккаунты Google."</string>
+ <string name="permgrouplab_hardwareControls">"Элементы ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð°Ð¿Ð¿Ð°Ñ€Ð°Ñ‚Ð½Ñ‹Ð¼ обеÑпечением"</string>
+ <string name="permgroupdesc_hardwareControls">"ПрÑмой доÑтуп к аппаратному обеÑпечению телефона."</string>
+ <string name="permgrouplab_phoneCalls">"Телефонные вызовы"</string>
+ <string name="permgroupdesc_phoneCalls">"ОтÑлеживать, запиÑывать и обрабатывать телефонные звонки."</string>
+ <string name="permgrouplab_systemTools">"СиÑтемные инÑтрументы"</string>
+ <string name="permgroupdesc_systemTools">"ДоÑтуп нижнего ÑƒÑ€Ð¾Ð²Ð½Ñ Ð¸ управление ÑиÑтемой."</string>
+ <string name="permgrouplab_developmentTools">"ИнÑтрументы разработки"</string>
+ <string name="permgroupdesc_developmentTools">"Функции, необходимые только разработчикам приложений."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"отключать или изменÑÑ‚ÑŒ Ñтроку ÑоÑтоÑниÑ"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"ПозволÑет приложению отключать Ñтроку ÑоÑтоÑÐ½Ð¸Ñ Ð¸Ð»Ð¸ добавлÑÑ‚ÑŒ/удалÑÑ‚ÑŒ ÑиÑтемные значки."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"разворачивать/Ñворачивать Ñтроку ÑоÑтоÑниÑ"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"ПозволÑет приложению разворачивать или Ñворачивать Ñтроку ÑоÑтоÑниÑ."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"перехватывать иÑходÑщие вызовы"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"ПозволÑет приложению обрабатывать иÑходÑщие вызовы и изменÑÑ‚ÑŒ набираемый номер. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отÑлеживать, перенаправлÑÑ‚ÑŒ или запрещать иÑходÑщие вызовы."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"получать SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"ПозволÑет приложению получать и обрабатывать SMS-ÑообщениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отÑлеживать ваши ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ удалÑÑ‚ÑŒ их, не Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°Ñ Ð²Ð°Ð¼."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"получать MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"ПозволÑет приложению получать и обрабатывать MMS-ÑообщениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отÑлеживать ваши ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ удалÑÑ‚ÑŒ их, не Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°Ñ Ð²Ð°Ð¼."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"отправлÑÑ‚ÑŒ SMS-ÑообщениÑ"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"ПозволÑет приложению отправлÑÑ‚ÑŒ SMS-ÑообщениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отправлÑÑ‚ÑŒ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð±ÐµÐ· уведомлениÑ, что приведет к непредвиденным раÑходам."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"Ñчитывать SMS или MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"ПозволÑет приложению Ñчитывать SMS-ÑообщениÑ, Ñохраненные на телефоне или SIM-карте. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ Ñчитывать конфиденциальные ÑообщениÑ."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"изменÑÑ‚ÑŒ SMS или MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"ПозволÑет приложению перезапиÑывать SMS-ÑообщениÑ, Ñохраненные на телефоне или SIM-карте. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ удалить ÑообщениÑ."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"получать WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"ПозволÑет приложению получать и обрабатывать WAP-ÑообщениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отÑлеживать ваши ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ удалÑÑ‚ÑŒ их, не Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°Ñ Ð²Ð°Ð¼."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"извлечь запущенные приложениÑ"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"ПозволÑет приложению получать ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ поÑледних и текущих задачах. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ получить доÑтуп к конфиденциальной информации о других приложениÑÑ…."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"изменÑÑ‚ÑŒ порÑдок запущенных приложений"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"ПозволÑет приложению переключать режим Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð´Ð°Ñ‡Ð¸ Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ð¾Ð³Ð¾ на фоновый. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ уÑтановить Ð´Ð»Ñ ÑÐµÐ±Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ñ‹Ð¹ режим без уведомлениÑ."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"запуÑкать отладку приложениÑ"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"ПозволÑет приложению запуÑкать процеÑÑ Ð¾Ñ‚Ð»Ð°Ð´ÐºÐ¸ другого приложениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¾Ñтановки других приложений."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"изменÑÑ‚ÑŒ наÑтройки пользовательÑкого интерфейÑа"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"ПозволÑет приложению изменÑÑ‚ÑŒ текущую конфигурацию, например региональные наÑтройки или размер шрифта."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"перезапуÑкать другие приложениÑ"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"ПозволÑет приложению принудительно перезапуÑкать другие приложениÑ."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"принудительно закрывать приложениÑ"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"ПозволÑет приложению принудительно закрыть или вернуть в иÑходное ÑоÑтоÑние процеÑÑÑ‹, выполнÑемые в активном режиме. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"извлекать данные о внутреннем ÑоÑтоÑнии ÑиÑтемы"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"ПозволÑет приложению извлекать внутренние ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ ÑоÑтоÑнии ÑиÑтемы. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñмогут извлечь разнообразные личные и защищенные ÑведениÑ, в которых обычно нет необходимоÑти."</string>
+ <string name="permlab_statusBar">"отключить или изменить Ñтроку ÑоÑтоÑниÑ"</string>
+ <string name="permdesc_statusBar">"ПозволÑет приложению отключать Ñтроку ÑоÑтоÑÐ½Ð¸Ñ Ð¸Ð»Ð¸ добавлÑÑ‚ÑŒ/удалÑÑ‚ÑŒ ÑиÑтемные значки."</string>
+ <string name="permlab_expandStatusBar">"разворачивать/Ñворачивать Ñтроку ÑоÑтоÑниÑ"</string>
+ <string name="permdesc_expandStatusBar">"ПозволÑет приложению разворачивать или Ñворачивать Ñтроку ÑоÑтоÑниÑ."</string>
+ <string name="permlab_processOutgoingCalls">"перехватывать иÑходÑщие вызовы"</string>
+ <string name="permdesc_processOutgoingCalls">"ПозволÑет приложению обрабатывать иÑходÑщие вызовы и изменÑÑ‚ÑŒ набираемый номер. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отÑлеживать, перенаправлÑÑ‚ÑŒ или запрещать иÑходÑщие вызовы."</string>
+ <string name="permlab_receiveSms">"получать SMS"</string>
+ <string name="permdesc_receiveSms">"ПозволÑет приложению получать и обрабатывать SMS-ÑообщениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отÑлеживать ваши ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ удалÑÑ‚ÑŒ их, не Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°Ñ Ð²Ð°Ð¼."</string>
+ <string name="permlab_receiveMms">"получать MMS"</string>
+ <string name="permdesc_receiveMms">"ПозволÑет приложению получать и обрабатывать MMS-ÑообщениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отÑлеживать ваши ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ удалÑÑ‚ÑŒ их, не Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°Ñ Ð²Ð°Ð¼."</string>
+ <string name="permlab_sendSms">"отправлÑÑ‚ÑŒ SMS-ÑообщениÑ"</string>
+ <string name="permdesc_sendSms">"ПозволÑет приложению отправлÑÑ‚ÑŒ SMS-ÑообщениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отправлÑÑ‚ÑŒ ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð±ÐµÐ· уведомлениÑ, что приведет к непредвиденным раÑходам."</string>
+ <string name="permlab_readSms">"Ñчитывать SMS или MMS"</string>
+ <string name="permdesc_readSms">"ПозволÑет приложению Ñчитывать SMS-ÑообщениÑ, Ñохраненные на телефоне или SIM-карте. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ Ñчитывать конфиденциальные ÑообщениÑ."</string>
+ <string name="permlab_writeSms">"изменить SMS или MMS"</string>
+ <string name="permdesc_writeSms">"ПозволÑет приложению перезапиÑывать SMS-ÑообщениÑ, Ñохраненные на телефоне или SIM-карте. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ удалить ÑообщениÑ."</string>
+ <string name="permlab_receiveWapPush">"получать WAP"</string>
+ <string name="permdesc_receiveWapPush">"ПозволÑет приложению получать и обрабатывать WAP-ÑообщениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отÑлеживать ваши ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ удалÑÑ‚ÑŒ их, не Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°Ñ Ð²Ð°Ð¼."</string>
+ <string name="permlab_getTasks">"извлечь запущенные приложениÑ"</string>
+ <string name="permdesc_getTasks">"ПозволÑет приложению получать ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ поÑледних и текущих задачах. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ получить доÑтуп к конфиденциальной информации о других приложениÑÑ…."</string>
+ <string name="permlab_reorderTasks">"изменÑÑ‚ÑŒ порÑдок запущенных приложений"</string>
+ <string name="permdesc_reorderTasks">"ПозволÑет приложению переключать режим Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð´Ð°Ñ‡Ð¸ Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ð¾Ð³Ð¾ на фоновый. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ уÑтановить Ð´Ð»Ñ ÑÐµÐ±Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ñ‹Ð¹ режим без уведомлениÑ."</string>
+ <string name="permlab_setDebugApp">"запуÑкать отладку приложениÑ"</string>
+ <string name="permdesc_setDebugApp">"ПозволÑет приложению запуÑкать процеÑÑ Ð¾Ñ‚Ð»Ð°Ð´ÐºÐ¸ другого приложениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¾Ñтановки других приложений."</string>
+ <string name="permlab_changeConfiguration">"изменÑÑ‚ÑŒ наÑтройки пользовательÑкого интерфейÑа"</string>
+ <string name="permdesc_changeConfiguration">"ПозволÑет приложению изменÑÑ‚ÑŒ текущую конфигурацию, например региональные наÑтройки или размер шрифта."</string>
+ <string name="permlab_restartPackages">"перезапуÑкать другие приложениÑ"</string>
+ <string name="permdesc_restartPackages">"ПозволÑет приложению принудительно перезапуÑкать другие приложениÑ."</string>
+ <string name="permlab_forceBack">"принудительно закрывать приложениÑ"</string>
+ <string name="permdesc_forceBack">"ПозволÑет приложению принудительно закрыть или вернуть в иÑходное ÑоÑтоÑние процеÑÑÑ‹, выполнÑемые в активном режиме. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
+ <string name="permlab_dump">"извлекать данные о внутреннем ÑоÑтоÑнии ÑиÑтемы"</string>
+ <string name="permdesc_dump">"ПозволÑет приложению извлекать внутренние ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ ÑоÑтоÑнии ÑиÑтемы. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñмогут извлечь разнообразные личные и защищенные ÑведениÑ, в которых обычно нет необходимоÑти."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"отÑлеживать и управлÑÑ‚ÑŒ запуÑком вÑех приложений"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"ПозволÑет приложению отÑлеживать и управлÑÑ‚ÑŒ ÑпоÑобом Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ ÑиÑтемы. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ разглаÑить конфиденциальную информацию о ÑиÑтеме. Это разрешение необходимо только при разработке, но не при обычной работе Ñ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½Ð¾Ð¼."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"отправлÑÑ‚ÑŒ раÑÑылку об удалении пакета"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"ПозволÑет приложению выполнÑÑ‚ÑŒ раÑÑылку уведомлений об удалении пакета приложениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¾Ñтановки вÑех оÑтальных выполнÑющихÑÑ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ð¹."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"отправлÑÑ‚ÑŒ раÑÑылку уведомлений о получении SMS"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"ПозволÑет приложению отправлÑÑ‚ÑŒ ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ получении SMS-ÑообщениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¸Ð¼Ð¸Ñ‚Ð°Ñ†Ð¸Ð¸ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ SMS -Ñообщений."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"отправлÑÑ‚ÑŒ раÑÑылку уведомлений о получении WAP-Ñообщений поÑтавщика уÑлуг"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"ПозволÑет приложению отправлÑÑ‚ÑŒ ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ получении WAP-ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñтавщика уÑлуг. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¸Ð¼Ð¸Ñ‚Ð°Ñ†Ð¸Ð¸ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ MMS-ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ замены Ñодержимого любой веб-Ñтраницы на вредоноÑное без уведомлениÑ."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"ограничивать количеÑтво запущенных процеÑÑов"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"ПозволÑет приложению управлÑÑ‚ÑŒ макÑимальным количеÑтвом выполнÑемых процеÑÑов. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"закрывать вÑе приложениÑ, работающие в фоновом режиме"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"ПозволÑет приложению контролировать, были ли дейÑÑ‚Ð²Ð¸Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ñ‹ Ñразу же поÑле их перехода в фоновый режим. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"изменÑÑ‚ÑŒ ÑтатиÑтику батареи"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"ПозволÑет изменÑÑ‚ÑŒ Ñобранную ÑтатиÑтику батареи. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
+ <string name="permlab_runSetActivityWatcher">"отÑлеживать и управлÑÑ‚ÑŒ запуÑком вÑех приложений"</string>
+ <string name="permdesc_runSetActivityWatcher">"ПозволÑет приложению отÑлеживать и управлÑÑ‚ÑŒ ÑпоÑобом Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ ÑиÑтемы. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ разглаÑить конфиденциальную информацию о ÑиÑтеме. Это разрешение необходимо только при разработке, но не при обычной работе Ñ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½Ð¾Ð¼."</string>
+ <string name="permlab_broadcastPackageRemoved">"отправлÑÑ‚ÑŒ раÑÑылку об удалении пакета"</string>
+ <string name="permdesc_broadcastPackageRemoved">"ПозволÑет приложению выполнÑÑ‚ÑŒ раÑÑылку уведомлений об удалении пакета приложениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¾Ñтановки вÑех оÑтальных выполнÑющихÑÑ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ð¹."</string>
+ <string name="permlab_broadcastSmsReceived">"отправлÑÑ‚ÑŒ раÑÑылку уведомлений о получении SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"ПозволÑет приложению отправлÑÑ‚ÑŒ ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ получении SMS-ÑообщениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¸Ð¼Ð¸Ñ‚Ð°Ñ†Ð¸Ð¸ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ SMS -Ñообщений."</string>
+ <string name="permlab_broadcastWapPush">"отправлÑÑ‚ÑŒ раÑÑылку уведомлений о получении WAP-Ñообщений поÑтавщика уÑлуг"</string>
+ <string name="permdesc_broadcastWapPush">"ПозволÑет приложению отправлÑÑ‚ÑŒ ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ получении WAP-ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñтавщика уÑлуг. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¸Ð¼Ð¸Ñ‚Ð°Ñ†Ð¸Ð¸ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ MMS-ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ замены Ñодержимого любой веб-Ñтраницы на вредоноÑное без уведомлениÑ."</string>
+ <string name="permlab_setProcessLimit">"ограничивать количеÑтво запущенных процеÑÑов"</string>
+ <string name="permdesc_setProcessLimit">"ПозволÑет приложению управлÑÑ‚ÑŒ макÑимальным количеÑтвом выполнÑемых процеÑÑов. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
+ <string name="permlab_setAlwaysFinish">"закрывать вÑе приложениÑ, работающие в фоновом режиме"</string>
+ <string name="permdesc_setAlwaysFinish">"ПозволÑет приложению контролировать, были ли дейÑÑ‚Ð²Ð¸Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ñ‹ Ñразу же поÑле их перехода в фоновый режим. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
+ <string name="permlab_batteryStats">"изменÑÑ‚ÑŒ ÑтатиÑтику батареи"</string>
+ <string name="permdesc_batteryStats">"ПозволÑет изменÑÑ‚ÑŒ Ñобранную ÑтатиÑтику батареи. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"показывать неавторизованные окна"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Разрешает Ñоздание окон, предназначенных Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð²Ð½ÑƒÑ‚Ñ€ÐµÐ½Ð½Ð¸Ð¼ пользовательÑким интерфейÑом ÑиÑтемы. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"показывать Ð¾Ð¿Ð¾Ð²ÐµÑ‰ÐµÐ½Ð¸Ñ ÑиÑтемного уровнÑ"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"ПозволÑет приложению отображать окна предупреждений ÑиÑтемы. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñмогут получить контроль над вÑем Ñкраном телефона."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"изменÑÑ‚ÑŒ глобальную ÑкороÑÑ‚ÑŒ анимации"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"ПозволÑет приложению в любое Ð²Ñ€ÐµÐ¼Ñ Ð¸Ð·Ð¼ÐµÐ½ÑÑ‚ÑŒ общую ÑкороÑÑ‚ÑŒ анимации (уÑÐºÐ¾Ñ€ÐµÐ½Ð½Ð°Ñ Ð¸Ð»Ð¸ Ð·Ð°Ð¼ÐµÐ´Ð»ÐµÐ½Ð½Ð°Ñ Ð°Ð½Ð¸Ð¼Ð°Ñ†Ð¸Ñ)."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"управлÑÑ‚ÑŒ маркерами приложений"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"ПозволÑет приложениÑм Ñоздавать ÑобÑтвенные маркеры и управлÑÑ‚ÑŒ ими, Ð¾Ð±Ñ…Ð¾Ð´Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ð¾Ðµ Z-упорÑдочивание. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"отрабатывать Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ и кнопок управлениÑ"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"ПозволÑет приложению передавать ÑобÑтвенные ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð²Ð²Ð¾Ð´Ð° (например, Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ) в другие приложениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑƒÑтановки полного ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ñ Ð½Ð°Ð´ телефоном."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"запиÑывать вводимый текÑÑ‚ и Ñовершаемые дейÑтвиÑ"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"ПозволÑет приложению раÑпознавать нажатые пользователем клавиши даже при работе Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼ приложением (например, при вводе паролÑ). Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"ÑвÑзывать Ñ Ð¼ÐµÑ‚Ð¾Ð´Ð¾Ð¼ ввода"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"ПозволÑет выполнÑÑ‚ÑŒ привÑзку к интерфейÑу ввода верхнего уровнÑ. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"изменÑÑ‚ÑŒ ориентацию Ñкрана"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"ПозволÑет приложению изменÑÑ‚ÑŒ ориентацию Ñкрана в любое времÑ. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"отправлÑÑ‚ÑŒ приложениÑм Ñигналы Linux"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"ПозволÑет приложению направлÑÑ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° передачу предоÑтавленного Ñигнала вÑем поÑтоÑнным процеÑÑам."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"запуÑкать поÑтоÑнную работу приложениÑ"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"ПозволÑет приложению Ñделать Ñвои компоненты поÑтоÑнными, Ð±Ð»Ð°Ð³Ð¾Ð´Ð°Ñ€Ñ Ñ‡ÐµÐ¼Ñƒ ÑиÑтема не может иÑпользовать их Ð´Ð»Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… приложений."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"удалÑÑ‚ÑŒ приложениÑ"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"ПозволÑет приложению удалÑÑ‚ÑŒ пакеты Android. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð²Ð°Ð¶Ð½Ñ‹Ñ… приложений."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"удалÑÑ‚ÑŒ данные других приложений"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"ПозволÑет приложению удалÑÑ‚ÑŒ данные пользователÑ."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"очищать кÑши других приложений"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"ПозволÑет приложению удалÑÑ‚ÑŒ файлы из кÑша."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"определÑÑ‚ÑŒ объем памÑти приложений"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"ПозволÑет приложению получать ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ размере кода, данных и кÑша."</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"уÑтанавливать Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð½ÐµÐ¿Ð¾ÑредÑтвенно"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"ПозволÑет приложению уÑтанавливать новые или обновленные пакеты Android. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ñ‹Ñ… приложений Ñо Ñколь угодно выÑоким уровнем разрешениÑ."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"удалÑÑ‚ÑŒ вÑе данные из кÑша приложений"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"ПозволÑет приложению оÑвобождать памÑÑ‚ÑŒ телефона Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² из каталога кÑша приложений. Обычно Ñто разрешаетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ ÑиÑтемным процеÑÑам."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"Ñчитывать ÑиÑтемные файлы журналов"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"ПозволÑет приложению Ñчитывать информацию из различных журналов ÑиÑтемы. Приложение может получить ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ работе Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½Ð¾Ð¼, но они не должны Ñодержать какой-либо личной или конфиденциальной информации."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"Ñчитывать/запиÑывать данные в реÑурÑÑ‹, принадлежащие группе диагноÑтики"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"ПозволÑет приложению Ñчитывать и запиÑывать данные в любые реÑурÑÑ‹, принадлежащие группе диагноÑтики (например, файлы в каталоге /dev). Это может повлиÑÑ‚ÑŒ на ÑтабильноÑÑ‚ÑŒ и безопаÑноÑÑ‚ÑŒ ÑиÑтемы. Эта возможноÑÑ‚ÑŒ может быть иÑпользована ТОЛЬКО производителем или оператором Ð´Ð»Ñ Ð´Ð¸Ð°Ð³Ð½Ð¾Ñтики аппаратного обеÑпечениÑ."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"включать или отключать компоненты приложениÑ"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"ПозволÑет приложению отключать или включать компоненты другого приложениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñто разрешение Ð´Ð»Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð²Ð°Ð¶Ð½Ñ‹Ñ… возможноÑтей телефона. Это разрешение Ñледует иÑпользовать Ñ Ð¾ÑторожноÑтью, так как Ñто может привеÑти к неÑовмеÑтимоÑти, неÑтабильноÑти и неработоÑпоÑобноÑти компонентов приложениÑ."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"выбирать предпочтительные приложениÑ"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"ПозволÑет приложению изменÑÑ‚ÑŒ предпочтительные приложениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð½ÐµÐ·Ð°Ð¼ÐµÑ‚Ð½Ð¾Ð³Ð¾ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿ÑƒÑ‰ÐµÐ½Ð½Ñ‹Ñ… приложений и Ð´Ð»Ñ Ñбора конфиденциальной информации Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ имитации Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ ÑущеÑтвующих приложений."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"изменÑÑ‚ÑŒ общие наÑтройки ÑиÑтемы"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"ПозволÑет приложению изменÑÑ‚ÑŒ данные наÑтроек ÑиÑтемы. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ повредить конфигурацию ÑиÑтемы."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"изменÑÑ‚ÑŒ наÑтройки ÑиÑтемы безопаÑноÑти"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"ПозволÑет приложению изменÑÑ‚ÑŒ данные наÑтроек безопаÑноÑти ÑиÑтемы. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"изменÑÑ‚ÑŒ карту Ñлужб Google"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"ПозволÑет приложению изменÑÑ‚ÑŒ карту Ñлужб Google. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"автоматичеÑки запуÑкать при загрузке"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"ПозволÑет приложению запуÑкатьÑÑ Ñразу же по завершении загрузки. Это может увеличить Ð²Ñ€ÐµÐ¼Ñ Ð·Ð°Ð¿ÑƒÑка телефона и замедлить его работу в ÑвÑзи Ñ Ð¿Ð¾ÑтоÑнной работой приложениÑ."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"отправить неÑрочную раÑÑылку"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"ПозволÑет приложению отправлÑÑ‚ÑŒ неÑрочные раÑÑылки, которые оÑталиÑÑŒ по завершении данной раÑÑылки. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ замедлить работу телефона или Ñделать ее неÑтабильной Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñлишком большого объема памÑти."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"Ñчитывать данные контакта"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"ПозволÑет приложению Ñчитывать вÑе данные контактов (адреÑов), Ñохраненные в памÑти телефона. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ð¸ данных поÑторонним лицам."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"перезапиÑывать данные контакта"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"ПозволÑет приложению изменÑÑ‚ÑŒ данные (адреÑ) контакта, Ñохраненные в памÑти телефона. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… контакта."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"перезапиÑывать данные о владельце"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"ПозволÑет приложению изменÑÑ‚ÑŒ ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ владельце, Ñохраненные на телефоне. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… владельца."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"Ñчитывать данные о владельце"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"ПозволÑет приложению Ñчитывать ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ владельце, Ñохраненные в памÑти телефона. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑÑ‡Ð¸Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… владельца."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"Ñчитывать данные календарÑ"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"ПозволÑет приложению Ñчитывать вÑе ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ, Ñохраненные на телефоне. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ð¸ ваших Ñобытий ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ Ð¿Ð¾Ñторонним лицам."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"запиÑывать данные календарÑ"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"ПозволÑет приложению изменÑÑ‚ÑŒ ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ, Ñохраненные на телефоне. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñобытий календарÑ."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"копировать иÑточники меÑÑ‚ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Создавать копии иÑточников данных о меÑтоположении Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñи меÑта и/или ÑоÑтоÑниÑ, возвращаемого дейÑтвительными иÑточниками данных о меÑтоположении, такими как GPS или операторы ÑвÑзи."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"получать доÑтуп к дополнительным командам иÑточника данных о меÑтоположении"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Получать доÑтуп к дополнительным командам поÑтавщика данных о меÑтоположении. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð²Ð¼ÐµÑˆÐ°Ñ‚ÐµÐ»ÑŒÑтва в работу GPS или других иÑточников меÑта."</string>
+ <string name="permlab_internalSystemWindow">"показывать неавторизованные окна"</string>
+ <string name="permdesc_internalSystemWindow">"Разрешает Ñоздание окон, предназначенных Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð²Ð½ÑƒÑ‚Ñ€ÐµÐ½Ð½Ð¸Ð¼ пользовательÑким интерфейÑом ÑиÑтемы. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
+ <string name="permlab_systemAlertWindow">"показывать Ð¾Ð¿Ð¾Ð²ÐµÑ‰ÐµÐ½Ð¸Ñ ÑиÑтемного уровнÑ"</string>
+ <string name="permdesc_systemAlertWindow">"ПозволÑет приложению отображать окна предупреждений ÑиÑтемы. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñмогут получить контроль над вÑем Ñкраном телефона."</string>
+ <string name="permlab_setAnimationScale">"изменÑÑ‚ÑŒ глобальную ÑкороÑÑ‚ÑŒ анимации"</string>
+ <string name="permdesc_setAnimationScale">"ПозволÑет приложению в любое Ð²Ñ€ÐµÐ¼Ñ Ð¸Ð·Ð¼ÐµÐ½ÑÑ‚ÑŒ общую ÑкороÑÑ‚ÑŒ анимации (уÑÐºÐ¾Ñ€ÐµÐ½Ð½Ð°Ñ Ð¸Ð»Ð¸ Ð·Ð°Ð¼ÐµÐ´Ð»ÐµÐ½Ð½Ð°Ñ Ð°Ð½Ð¸Ð¼Ð°Ñ†Ð¸Ñ)."</string>
+ <string name="permlab_manageAppTokens">"управлÑÑ‚ÑŒ маркерами приложений"</string>
+ <string name="permdesc_manageAppTokens">"ПозволÑет приложениÑм Ñоздавать ÑобÑтвенные маркеры и управлÑÑ‚ÑŒ ими, Ð¾Ð±Ñ…Ð¾Ð´Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ð¾Ðµ Z-упорÑдочивание. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
+ <string name="permlab_injectEvents">"отрабатывать Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ и кнопок управлениÑ"</string>
+ <string name="permdesc_injectEvents">"ПозволÑет приложению передавать ÑобÑтвенные ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð²Ð²Ð¾Ð´Ð° (например, Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ) в другие приложениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑƒÑтановки полного ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ñ Ð½Ð°Ð´ телефоном."</string>
+ <string name="permlab_readInputState">"запиÑывать вводимый текÑÑ‚ и Ñовершаемые дейÑтвиÑ"</string>
+ <string name="permdesc_readInputState">"ПозволÑет приложению раÑпознавать нажатые пользователем клавиши даже при работе Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼ приложением (например, при вводе паролÑ). Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
+ <string name="permlab_bindInputMethod">"ÑвÑзывать Ñ Ð¼ÐµÑ‚Ð¾Ð´Ð¾Ð¼ ввода"</string>
+ <string name="permdesc_bindInputMethod">"ПозволÑет выполнÑÑ‚ÑŒ привÑзку к интерфейÑу ввода верхнего уровнÑ. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
+ <string name="permlab_setOrientation">"изменÑÑ‚ÑŒ ориентацию Ñкрана"</string>
+ <string name="permdesc_setOrientation">"ПозволÑет приложению изменÑÑ‚ÑŒ ориентацию Ñкрана в любое времÑ. Ðе требуетÑÑ Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ñ… приложений."</string>
+ <string name="permlab_signalPersistentProcesses">"отправлÑÑ‚ÑŒ приложениÑм Ñигналы Linux"</string>
+ <string name="permdesc_signalPersistentProcesses">"ПозволÑет приложению направлÑÑ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° передачу предоÑтавленного Ñигнала вÑем поÑтоÑнным процеÑÑам."</string>
+ <string name="permlab_persistentActivity">"запуÑкать поÑтоÑнную работу приложениÑ"</string>
+ <string name="permdesc_persistentActivity">"ПозволÑет приложению Ñделать Ñвои компоненты поÑтоÑнными, Ð±Ð»Ð°Ð³Ð¾Ð´Ð°Ñ€Ñ Ñ‡ÐµÐ¼Ñƒ ÑиÑтема не может иÑпользовать их Ð´Ð»Ñ Ð´Ñ€ÑƒÐ³Ð¸Ñ… приложений."</string>
+ <string name="permlab_deletePackages">"удалÑÑ‚ÑŒ приложениÑ"</string>
+ <string name="permdesc_deletePackages">"ПозволÑет приложению удалÑÑ‚ÑŒ пакеты Android. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð²Ð°Ð¶Ð½Ñ‹Ñ… приложений."</string>
+ <string name="permlab_clearAppUserData">"удалÑÑ‚ÑŒ данные других приложений"</string>
+ <string name="permdesc_clearAppUserData">"ПозволÑет приложению удалÑÑ‚ÑŒ данные пользователÑ."</string>
+ <string name="permlab_deleteCacheFiles">"очищать кÑши других приложений"</string>
+ <string name="permdesc_deleteCacheFiles">"ПозволÑет приложению удалÑÑ‚ÑŒ файлы из кÑша."</string>
+ <string name="permlab_getPackageSize">"определÑÑ‚ÑŒ объем памÑти приложений"</string>
+ <string name="permdesc_getPackageSize">"ПозволÑет приложению получать ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ размере кода, данных и кÑша."</string>
+ <string name="permlab_installPackages">"уÑтанавливать Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð½ÐµÐ¿Ð¾ÑредÑтвенно"</string>
+ <string name="permdesc_installPackages">"ПозволÑет приложению уÑтанавливать новые или обновленные пакеты Android. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ñ‹Ñ… приложений Ñо Ñколь угодно выÑоким уровнем разрешениÑ."</string>
+ <string name="permlab_clearAppCache">"удалÑÑ‚ÑŒ вÑе данные из кÑша приложений"</string>
+ <string name="permdesc_clearAppCache">"ПозволÑет приложению оÑвобождать памÑÑ‚ÑŒ телефона Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² из каталога кÑша приложений. Обычно Ñто разрешаетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ ÑиÑтемным процеÑÑам."</string>
+ <string name="permlab_readLogs">"Ñчитывать ÑиÑтемные файлы журналов"</string>
+ <string name="permdesc_readLogs">"ПозволÑет приложению Ñчитывать информацию из различных журналов ÑиÑтемы. Приложение может получить ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ работе Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½Ð¾Ð¼, но они не должны Ñодержать какой-либо личной или конфиденциальной информации."</string>
+ <string name="permlab_diagnostic">"Ñчитывать/запиÑывать данные в реÑурÑÑ‹, принадлежащие группе диагноÑтики"</string>
+ <string name="permdesc_diagnostic">"ПозволÑет приложению Ñчитывать и запиÑывать данные в любые реÑурÑÑ‹, принадлежащие группе диагноÑтики (например, файлы в каталоге /dev). Это может повлиÑÑ‚ÑŒ на ÑтабильноÑÑ‚ÑŒ и безопаÑноÑÑ‚ÑŒ ÑиÑтемы. Эта возможноÑÑ‚ÑŒ может быть иÑпользована ТОЛЬКО производителем или оператором Ð´Ð»Ñ Ð´Ð¸Ð°Ð³Ð½Ð¾Ñтики аппаратного обеÑпечениÑ."</string>
+ <string name="permlab_changeComponentState">"включать или отключать компоненты приложениÑ"</string>
+ <string name="permdesc_changeComponentState">"ПозволÑет приложению отключать или включать компоненты другого приложениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñто разрешение Ð´Ð»Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð²Ð°Ð¶Ð½Ñ‹Ñ… возможноÑтей телефона. Это разрешение Ñледует иÑпользовать Ñ Ð¾ÑторожноÑтью, так как Ñто может привеÑти к неÑовмеÑтимоÑти, неÑтабильноÑти и неработоÑпоÑобноÑти компонентов приложениÑ."</string>
+ <string name="permlab_setPreferredApplications">"выбирать предпочтительные приложениÑ"</string>
+ <string name="permdesc_setPreferredApplications">"ПозволÑет приложению изменÑÑ‚ÑŒ предпочтительные приложениÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð½ÐµÐ·Ð°Ð¼ÐµÑ‚Ð½Ð¾Ð³Ð¾ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿ÑƒÑ‰ÐµÐ½Ð½Ñ‹Ñ… приложений и Ð´Ð»Ñ Ñбора конфиденциальной информации Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ имитации Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ ÑущеÑтвующих приложений."</string>
+ <string name="permlab_writeSettings">"изменить общие наÑтройки ÑиÑтемы"</string>
+ <string name="permdesc_writeSettings">"ПозволÑет приложению изменÑÑ‚ÑŒ данные наÑтроек ÑиÑтемы. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ повредить конфигурацию ÑиÑтемы."</string>
+ <string name="permlab_writeSecureSettings">"изменÑÑ‚ÑŒ наÑтройки ÑиÑтемы безопаÑноÑти"</string>
+ <string name="permdesc_writeSecureSettings">"ПозволÑет приложению изменÑÑ‚ÑŒ данные наÑтроек безопаÑноÑти ÑиÑтемы. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
+ <string name="permlab_writeGservices">"изменить карту Ñлужб Google"</string>
+ <string name="permdesc_writeGservices">"ПозволÑет приложению изменÑÑ‚ÑŒ карту Ñлужб Google. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
+ <string name="permlab_receiveBootCompleted">"автоматичеÑки запуÑкать при загрузке"</string>
+ <string name="permdesc_receiveBootCompleted">"ПозволÑет приложению запуÑкатьÑÑ Ñразу же по завершении загрузки. Это может увеличить Ð²Ñ€ÐµÐ¼Ñ Ð·Ð°Ð¿ÑƒÑка телефона и замедлить его работу в ÑвÑзи Ñ Ð¿Ð¾ÑтоÑнной работой приложениÑ."</string>
+ <string name="permlab_broadcastSticky">"отправить неÑрочную раÑÑылку"</string>
+ <string name="permdesc_broadcastSticky">"ПозволÑет приложению отправлÑÑ‚ÑŒ неÑрочные раÑÑылки, которые оÑталиÑÑŒ по завершении данной раÑÑылки. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ замедлить работу телефона или Ñделать ее неÑтабильной Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñлишком большого объема памÑти."</string>
+ <string name="permlab_readContacts">"Ñчитывать данные контакта"</string>
+ <string name="permdesc_readContacts">"ПозволÑет приложению Ñчитывать вÑе данные контактов (адреÑов), Ñохраненные в памÑти телефона. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ð¸ данных поÑторонним лицам."</string>
+ <string name="permlab_writeContacts">"перезапиÑывать данные контакта"</string>
+ <string name="permdesc_writeContacts">"ПозволÑет приложению изменÑÑ‚ÑŒ данные (адреÑ) контакта, Ñохраненные в памÑти телефона. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… контакта."</string>
+ <string name="permlab_writeOwnerData">"перезапиÑывать данные о владельце"</string>
+ <string name="permdesc_writeOwnerData">"ПозволÑет приложению изменÑÑ‚ÑŒ ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ владельце, Ñохраненные на телефоне. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… владельца."</string>
+ <string name="permlab_readOwnerData">"Ñчитывать данные о владельце"</string>
+ <string name="permdesc_readOwnerData">"ПозволÑет приложению Ñчитывать ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ владельце, Ñохраненные в памÑти телефона. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑÑ‡Ð¸Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… владельца."</string>
+ <string name="permlab_readCalendar">"Ñчитывать данные календарÑ"</string>
+ <string name="permdesc_readCalendar">"ПозволÑет приложению Ñчитывать вÑе ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ, Ñохраненные на телефоне. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ð¸ ваших Ñобытий ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ Ð¿Ð¾Ñторонним лицам."</string>
+ <string name="permlab_writeCalendar">"запиÑывать данные календарÑ"</string>
+ <string name="permdesc_writeCalendar">"ПозволÑет приложению изменÑÑ‚ÑŒ ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ, Ñохраненные на телефоне. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñобытий календарÑ."</string>
+ <string name="permlab_accessMockLocation">"копировать иÑточники меÑÑ‚ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸"</string>
+ <string name="permdesc_accessMockLocation">"Создавать копии иÑточников данных о меÑтоположении Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñи меÑта и/или ÑоÑтоÑниÑ, возвращаемого дейÑтвительными иÑточниками данных о меÑтоположении, такими как GPS или операторы ÑвÑзи."</string>
+ <string name="permlab_accessLocationExtraCommands">"получать доÑтуп к дополнительным командам иÑточника данных о меÑтоположении"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Получать доÑтуп к дополнительным командам поÑтавщика данных о меÑтоположении. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð²Ð¼ÐµÑˆÐ°Ñ‚ÐµÐ»ÑŒÑтва в работу GPS или других иÑточников меÑта."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"точное меÑтоположение (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Получать доÑтуп к иÑточникам точного меÑтоположениÑ, таким как GPS, еÑли возможно. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñто разрешение Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ меÑÑ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸ раÑходовать реÑÑƒÑ€Ñ Ð±Ð°Ñ‚Ð°Ñ€ÐµÐ¸."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"отÑлеживать меÑтоположение по Ñигналам Ñети"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Получать доÑтуп к иÑточникам данных о меÑтоположении, таким как база данных Ñотовой Ñети, Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ð±Ð»Ð¸Ð·Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð³Ð¾ меÑÑ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½Ð°, еÑли возможно. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ приблизительного меÑтоположениÑ."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"получать доÑтуп к SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"ПозволÑет приложению иÑпользовать функции SurfaceFlinger нижнего уровнÑ."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Ñчитывать буфер фреймов"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"ПозволÑет приложению иÑпользовать функцию Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñодержимого буфера фреймов."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"изменÑÑ‚ÑŒ наÑтройки аудио"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"ПозволÑет приложению изменÑÑ‚ÑŒ глобальные аудионаÑтройки, такие как громкоÑÑ‚ÑŒ и маршрутизацию."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"запиÑывать аудио"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"ПозволÑет приложению получать доÑтуп к пути аудиозапиÑи."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"Ñнимать фотографии"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"ПозволÑет приложению делать Ñнимки Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ камеры. Это разрешение позволÑет приложению в любое Ð²Ñ€ÐµÐ¼Ñ Ñобирать изображениÑ, видимые через объектив камеры."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"отключать телефон"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"ПозволÑет данному приложению отключить телефон навÑегда. Это очень опаÑно."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"принудительно перезагружать телефон"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"ПозволÑет приложению принудительно перезагружать телефон."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"монтировать и удалÑÑ‚ÑŒ файловые ÑиÑтемы"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"ПозволÑет приложению монтировать и удалÑÑ‚ÑŒ файловые ÑиÑтемы Ñъемных ноÑителей."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"форматировать внешний накопитель"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"ПозволÑет приложению форматировать Ñъемный накопитель."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"управлÑÑ‚ÑŒ вибровызовом"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"ПозволÑет приложению управлÑÑ‚ÑŒ виброзвонком."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"управлÑÑ‚ÑŒ вÑпышкой"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"ПозволÑет приложению управлÑÑ‚ÑŒ вÑпышкой."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"проверÑÑ‚ÑŒ аппаратное обеÑпечение"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"ПозволÑет приложению управлÑÑ‚ÑŒ различными периферийными уÑтройÑтвами Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ аппаратного обеÑпечениÑ."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"поÑылать прÑмые вызовы на номера телефонов"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"ПозволÑет приложению вызывать телефонные номера без вмешательÑтва пользователÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ оÑущеÑтвлÑÑ‚ÑŒ нежелательные вызовы. Это разрешение не позволÑет приложению Ñовершать вызовы Ñлужб ÑкÑтренной помощи."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"поÑылать прÑмые вызовы на любые номера"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"ПозволÑет приложению оÑущеÑтвлÑÑ‚ÑŒ вызов любого номера, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð½Ð¾Ð¼ÐµÑ€Ð° ÑкÑтренной помощи, без вмешательÑтва пользователÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ оÑущеÑтвить нежелательные или незаконные вызовы Ñлужб ÑкÑтренной помощи."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"управлÑÑ‚ÑŒ уведомлениÑми об обновлении меÑтоположениÑ"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"ПозволÑет включать/отключать отправку уведомлений об обновлениÑÑ… меÑÑ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾ радиоÑвÑзи. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"получать доÑтуп к ÑвойÑтвам региÑтрации"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"ПозволÑет получать доÑтуп Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ/запиÑи ÑвойÑтв, загруженных Ñлужбой региÑтрации. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"выбирать виджеты"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"ПозволÑет приложению Ñообщить ÑиÑтеме, какие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать какие виджеты. Это разрешение позволÑет приложениÑм предоÑтавлÑÑ‚ÑŒ другим приложениÑм доÑтуп к личной информации. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"изменÑÑ‚ÑŒ ÑоÑтоÑние телефона"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"ПозволÑет приложению управлÑÑ‚ÑŒ функциÑми телефона в уÑтройÑтве. Приложение, обладающее Ñтим разрешением, может переключать Ñети, включать и выключать радио на телефоне и выполнÑÑ‚ÑŒ другие подобные дейÑÑ‚Ð²Ð¸Ñ Ð±ÐµÐ· ÑоответÑтвующего уведомлениÑ."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"предотвратить переключение телефона в ÑпÑщий режим"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"ПозволÑет приложению запретить переход телефона в ÑпÑщий режим"</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"включать и выключать питание телефона"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"ПозволÑет приложению включать и отключать телефон."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"запуÑтить в теÑтовом режиме"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Выполнить Ñтандартную проверку нижнего уровнÑ, обеÑпечивающую полный доÑтуп к аппаратному обеÑпечению телефона. ДоÑтупно, только в режиме Ñтандартной проверки."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"уÑтанавливать фоновый риÑунок"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"ПозволÑет данному приложению уÑтанавливать ÑиÑтемный фоновый риÑунок."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"давать рекомендации по размеру фоновых риÑунков"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"ПозволÑет данному приложению уÑтанавливать Ñоветы по размеру фоновых риÑунков."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"воÑÑтанавливать параметры ÑиÑтемы по умолчанию, уÑтановленные на заводе-изготовителе"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"ПозволÑет приложению воÑÑтановить Ñтандартные наÑтройки ÑиÑтемы, удалив вÑе данные, конфигурацию и уÑтановленные приложениÑ."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"наÑтраивать чаÑовой поÑÑ"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"ПозволÑет приложению изменÑÑ‚ÑŒ чаÑовой поÑÑ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½Ð°."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"обнаруживать извеÑтные аккаунты"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"ПозволÑет приложению получать ÑпиÑок аккаунтов, извеÑтных телефону."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"проÑматривать ÑоÑтоÑние Ñети"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"ПозволÑет приложению проÑматривать ÑоÑтоÑние вÑех Ñетей."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"неограниченный доÑтуп в Интернет"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"ПозволÑет приложению Ñоздавать Ñетевые Ñокеты."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"запиÑывать наÑтройки имени точки доÑтупа"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"ПозволÑет приложению изменÑÑ‚ÑŒ наÑтройки APN, такие как прокÑи-Ñервер и порт любого APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"изменÑÑ‚ÑŒ наÑтройки Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñети"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"ПозволÑет приложению изменÑÑ‚ÑŒ ÑоÑтоÑние подключаемоÑти Ñети."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"изменÑÑ‚ÑŒ наÑтройки иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… в фоновом режиме"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"ПозволÑет приложению изменÑÑ‚ÑŒ наÑтройку иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… в фоновом режиме."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"проÑматривать ÑоÑтоÑние Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"ПозволÑет приложению проÑматривать ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ ÑоÑтоÑнии Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"изменÑÑ‚ÑŒ ÑоÑтоÑние Wi-Fi"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"ПозволÑет приложению подключатьÑÑ Ðº точкам доÑтупа Wi-Fi и отключатьÑÑ Ð¾Ñ‚ них, а также вноÑить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² конфигурацию Ñетей Wi-Fi."</string>
+ <string name="permlab_accessFineLocation">"точное меÑтоположение (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Получать доÑтуп к иÑточникам точного меÑтоположениÑ, таким как GPS, еÑли возможно. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñто разрешение Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ меÑÑ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸ раÑходовать реÑÑƒÑ€Ñ Ð±Ð°Ñ‚Ð°Ñ€ÐµÐ¸."</string>
+ <string name="permlab_accessCoarseLocation">"отÑлеживать меÑтоположение по Ñигналам Ñети"</string>
+ <string name="permdesc_accessCoarseLocation">"Получать доÑтуп к иÑточникам данных о меÑтоположении, таким как база данных Ñотовой Ñети, Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ð±Ð»Ð¸Ð·Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð³Ð¾ меÑÑ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½Ð°, еÑли возможно. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ приблизительного меÑтоположениÑ."</string>
+ <string name="permlab_accessSurfaceFlinger">"получать доÑтуп к SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"ПозволÑет приложению иÑпользовать функции SurfaceFlinger нижнего уровнÑ."</string>
+ <string name="permlab_readFrameBuffer">"Ñчитывать буфер фреймов"</string>
+ <string name="permdesc_readFrameBuffer">"ПозволÑет приложению иÑпользовать функцию Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñодержимого буфера фреймов."</string>
+ <string name="permlab_modifyAudioSettings">"изменÑÑ‚ÑŒ наÑтройки аудио"</string>
+ <string name="permdesc_modifyAudioSettings">"ПозволÑет приложению изменÑÑ‚ÑŒ глобальные аудионаÑтройки, такие как громкоÑÑ‚ÑŒ и маршрутизацию."</string>
+ <string name="permlab_recordAudio">"запиÑывать аудио"</string>
+ <string name="permdesc_recordAudio">"ПозволÑет приложению получать доÑтуп к пути аудиозапиÑи."</string>
+ <string name="permlab_camera">"Ñнимать фотографии"</string>
+ <string name="permdesc_camera">"ПозволÑет приложению делать Ñнимки Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ камеры. Это разрешение позволÑет приложению в любое Ð²Ñ€ÐµÐ¼Ñ Ñобирать изображениÑ, видимые через объектив камеры."</string>
+ <string name="permlab_brick">"отключать телефон"</string>
+ <string name="permdesc_brick">"ПозволÑет данному приложению отключить телефон навÑегда. Это очень опаÑно."</string>
+ <string name="permlab_reboot">"принудительно перезагружать телефон"</string>
+ <string name="permdesc_reboot">"ПозволÑет приложению принудительно перезагружать телефон."</string>
+ <string name="permlab_mount_unmount_filesystems">"монтировать и удалÑÑ‚ÑŒ файловые ÑиÑтемы"</string>
+ <string name="permdesc_mount_unmount_filesystems">"ПозволÑет приложению монтировать и удалÑÑ‚ÑŒ файловые ÑиÑтемы Ñъемных ноÑителей."</string>
+ <string name="permlab_mount_format_filesystems">"форматировать внешний накопитель"</string>
+ <string name="permdesc_mount_format_filesystems">"ПозволÑет приложению форматировать Ñъемный накопитель."</string>
+ <string name="permlab_vibrate">"управлÑÑ‚ÑŒ вибровызовом"</string>
+ <string name="permdesc_vibrate">"ПозволÑет приложению управлÑÑ‚ÑŒ виброзвонком."</string>
+ <string name="permlab_flashlight">"управлÑÑ‚ÑŒ вÑпышкой"</string>
+ <string name="permdesc_flashlight">"ПозволÑет приложению управлÑÑ‚ÑŒ вÑпышкой."</string>
+ <string name="permlab_hardware_test">"проверÑÑ‚ÑŒ аппаратное обеÑпечение"</string>
+ <string name="permdesc_hardware_test">"ПозволÑет приложению управлÑÑ‚ÑŒ различными периферийными уÑтройÑтвами Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ аппаратного обеÑпечениÑ."</string>
+ <string name="permlab_callPhone">"поÑылать прÑмые вызовы на номера телефонов"</string>
+ <string name="permdesc_callPhone">"ПозволÑет приложению вызывать телефонные номера без вмешательÑтва пользователÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ оÑущеÑтвлÑÑ‚ÑŒ нежелательные вызовы. Это разрешение не позволÑет приложению Ñовершать вызовы Ñлужб ÑкÑтренной помощи."</string>
+ <string name="permlab_callPrivileged">"поÑылать прÑмые вызовы на любые номера"</string>
+ <string name="permdesc_callPrivileged">"ПозволÑет приложению оÑущеÑтвлÑÑ‚ÑŒ вызов любого номера, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð½Ð¾Ð¼ÐµÑ€Ð° ÑкÑтренной помощи, без вмешательÑтва пользователÑ. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ оÑущеÑтвить нежелательные или незаконные вызовы Ñлужб ÑкÑтренной помощи."</string>
+ <string name="permlab_locationUpdates">"управлÑÑ‚ÑŒ уведомлениÑми об обновлении меÑтоположениÑ"</string>
+ <string name="permdesc_locationUpdates">"ПозволÑет включать/отключать отправку уведомлений об обновлениÑÑ… меÑÑ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾ радиоÑвÑзи. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
+ <string name="permlab_checkinProperties">"получать доÑтуп к ÑвойÑтвам региÑтрации"</string>
+ <string name="permdesc_checkinProperties">"ПозволÑет получать доÑтуп Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ/запиÑи ÑвойÑтв, загруженных Ñлужбой региÑтрации. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
+ <string name="permlab_bindGadget">"выбирать виджеты"</string>
+ <string name="permdesc_bindGadget">"ПозволÑет приложению Ñообщить ÑиÑтеме, какие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать какие виджеты. Это разрешение позволÑет приложениÑм предоÑтавлÑÑ‚ÑŒ другим приложениÑм доÑтуп к личной информации. Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
+ <string name="permlab_modifyPhoneState">"изменÑÑ‚ÑŒ ÑоÑтоÑние телефона"</string>
+ <string name="permdesc_modifyPhoneState">"ПозволÑет приложению управлÑÑ‚ÑŒ функциÑми телефона в уÑтройÑтве. Приложение, обладающее Ñтим разрешением, может переключать Ñети, включать и выключать радио на телефоне и выполнÑÑ‚ÑŒ другие подобные дейÑÑ‚Ð²Ð¸Ñ Ð±ÐµÐ· ÑоответÑтвующего уведомлениÑ."</string>
+ <string name="permlab_readPhoneState">"Ñчитывать ÑоÑтоÑние телефона"</string>
+ <string name="permdesc_readPhoneState">"ПозволÑет приложению получить доÑтуп к функциÑм телефона на уÑтройÑтве. Приложение Ñ Ñ‚Ð°ÐºÐ¸Ð¼ разрешением может определить номер телефона уÑтройÑтва, наличие активного вызова, номер вызываемого/вызывающего абонента и тому подобное."</string>
+ <string name="permlab_wakeLock">"предотвратить переключение телефона в ÑпÑщий режим"</string>
+ <string name="permdesc_wakeLock">"ПозволÑет приложению запретить переход телефона в ÑпÑщий режим"</string>
+ <string name="permlab_devicePower">"включать и выключать питание телефона"</string>
+ <string name="permdesc_devicePower">"ПозволÑет приложению включать и отключать телефон."</string>
+ <string name="permlab_factoryTest">"запуÑтить в теÑтовом режиме"</string>
+ <string name="permdesc_factoryTest">"Выполнить Ñтандартную проверку нижнего уровнÑ, обеÑпечивающую полный доÑтуп к аппаратному обеÑпечению телефона. ДоÑтупно, только в режиме Ñтандартной проверки."</string>
+ <string name="permlab_setWallpaper">"уÑтанавливать фоновый риÑунок"</string>
+ <string name="permdesc_setWallpaper">"ПозволÑет данному приложению уÑтанавливать ÑиÑтемный фоновый риÑунок."</string>
+ <string name="permlab_setWallpaperHints">"давать рекомендации по размеру фоновых риÑунков"</string>
+ <string name="permdesc_setWallpaperHints">"ПозволÑет данному приложению уÑтанавливать Ñоветы по размеру фоновых риÑунков."</string>
+ <string name="permlab_masterClear">"воÑÑтанавливать параметры ÑиÑтемы по умолчанию, уÑтановленные на заводе-изготовителе"</string>
+ <string name="permdesc_masterClear">"ПозволÑет приложению воÑÑтановить Ñтандартные наÑтройки ÑиÑтемы, удалив вÑе данные, конфигурацию и уÑтановленные приложениÑ."</string>
+ <string name="permlab_setTimeZone">"наÑтраивать чаÑовой поÑÑ"</string>
+ <string name="permdesc_setTimeZone">"ПозволÑет приложению изменÑÑ‚ÑŒ чаÑовой поÑÑ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½Ð°."</string>
+ <string name="permlab_getAccounts">"обнаруживать извеÑтные аккаунты"</string>
+ <string name="permdesc_getAccounts">"ПозволÑет приложению получать ÑпиÑок аккаунтов, извеÑтных телефону."</string>
+ <string name="permlab_accessNetworkState">"проÑматривать ÑоÑтоÑние Ñети"</string>
+ <string name="permdesc_accessNetworkState">"ПозволÑет приложению проÑматривать ÑоÑтоÑние вÑех Ñетей."</string>
+ <string name="permlab_createNetworkSockets">"неограниченный доÑтуп в Интернет"</string>
+ <string name="permdesc_createNetworkSockets">"ПозволÑет приложению Ñоздавать Ñетевые Ñокеты."</string>
+ <string name="permlab_writeApnSettings">"запиÑывать наÑтройки имени точки доÑтупа"</string>
+ <string name="permdesc_writeApnSettings">"ПозволÑет приложению изменÑÑ‚ÑŒ наÑтройки APN, такие как прокÑи-Ñервер и порт любого APN."</string>
+ <string name="permlab_changeNetworkState">"изменÑÑ‚ÑŒ наÑтройки Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñети"</string>
+ <string name="permdesc_changeNetworkState">"ПозволÑет приложению изменÑÑ‚ÑŒ ÑоÑтоÑние подключаемоÑти Ñети."</string>
+ <string name="permlab_changeBackgroundDataSetting">"изменить наÑтройку иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… в фоновом режиме"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"ПозволÑет приложению изменÑÑ‚ÑŒ наÑтройку иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… в фоновом режиме."</string>
+ <string name="permlab_accessWifiState">"проÑматривать ÑоÑтоÑние Wi-Fi"</string>
+ <string name="permdesc_accessWifiState">"ПозволÑет приложению проÑматривать ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ ÑоÑтоÑнии Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"изменÑÑ‚ÑŒ ÑоÑтоÑние Wi-Fi"</string>
+ <string name="permdesc_changeWifiState">"ПозволÑет приложению подключатьÑÑ Ðº точкам доÑтупа Wi-Fi и отключатьÑÑ Ð¾Ñ‚ них, а также вноÑить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² конфигурацию Ñетей Wi-Fi."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"управление Bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"ПозволÑет приложению наÑтраивать локальный телефон Bluetooth, обнаруживать и выполнÑÑ‚ÑŒ ÑопрÑжение удаленных уÑтройÑтв."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Ñоздавать Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"ПозволÑет приложению проÑматривать конфигурацию локального телефона Bluetooth, Ñоздавать Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ñ ÑопрÑженными уÑтройÑтвами."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"отключать блокировку клавиатуры"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"ПозволÑет приложению отключить блокировку клавиатуры и другие функции защиты паролем. Примером допуÑтимого иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñтой функции ÑвлÑетÑÑ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ðµ блокировки клавиатуры при получении входÑщего вызова и включение блокировки поÑле Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð³Ð¾Ð²Ð¾Ñ€Ð°."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Ñчитывать наÑтройки Ñинхронизации"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"ПозволÑет приложению Ñчитывать наÑтройки Ñинхронизации, такие как включение Ñинхронизации Контактов."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"запиÑывать наÑтройки Ñинхронизации"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"ПозволÑет приложению изменÑÑ‚ÑŒ наÑтройки Ñинхронизации, например включение Ñинхронизации Контактов."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"Ñчитывать ÑтатиÑтику Ñинхронизации"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"ПозволÑет приложению Ñчитывать ÑтатиÑтику Ñинхронизации, например иÑторию произведенных Ñинхронизаций."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"Ñчитывать каналы, на которые еÑÑ‚ÑŒ подпиÑка"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"ПозволÑет приложению получить ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ поÑледних Ñинхронизированных каналах."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"изменÑÑ‚ÑŒ каналы, на которые еÑÑ‚ÑŒ подпиÑка"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"ПозволÑет приложению изменÑÑ‚ÑŒ Ñинхронизированные каналы. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñинхронизированных каналов."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"выполнÑÑ‚ÑŒ чтение из пользовательÑкого ÑловарÑ"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"ПозволÑет приложению Ñчитывать любые Ñлова, имена и фразы личного пользованиÑ, которые могут хранитьÑÑ Ð² пользовательÑком Ñловаре."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"запиÑывать в пользовательÑкий Ñловарь"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"ПозволÑет приложению запиÑывать новые Ñлова в пользовательÑкий Ñловарь."</string>
+ <string name="permlab_bluetoothAdmin">"управление Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"ПозволÑет приложению наÑтраивать локальный телефон Bluetooth, обнаруживать и выполнÑÑ‚ÑŒ ÑопрÑжение удаленных уÑтройÑтв."</string>
+ <string name="permlab_bluetooth">"Ñоздавать Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Bluetooth"</string>
+ <string name="permdesc_bluetooth">"ПозволÑет приложению проÑматривать конфигурацию локального телефона Bluetooth, Ñоздавать Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ñ ÑопрÑженными уÑтройÑтвами."</string>
+ <string name="permlab_disableKeyguard">"отключать блокировку клавиатуры"</string>
+ <string name="permdesc_disableKeyguard">"ПозволÑет приложению отключить блокировку клавиатуры и другие функции защиты паролем. Примером допуÑтимого иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñтой функции ÑвлÑетÑÑ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ðµ блокировки клавиатуры при получении входÑщего вызова и включение блокировки поÑле Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð³Ð¾Ð²Ð¾Ñ€Ð°."</string>
+ <string name="permlab_readSyncSettings">"Ñчитывать наÑтройки Ñинхронизации"</string>
+ <string name="permdesc_readSyncSettings">"ПозволÑет приложению Ñчитывать наÑтройки Ñинхронизации, такие как включение Ñинхронизации Контактов."</string>
+ <string name="permlab_writeSyncSettings">"запиÑывать наÑтройки Ñинхронизации"</string>
+ <string name="permdesc_writeSyncSettings">"ПозволÑет приложению изменÑÑ‚ÑŒ наÑтройки Ñинхронизации, например включение Ñинхронизации Контактов."</string>
+ <string name="permlab_readSyncStats">"Ñчитывать ÑтатиÑтику Ñинхронизации"</string>
+ <string name="permdesc_readSyncStats">"ПозволÑет приложению Ñчитывать ÑтатиÑтику Ñинхронизации, например иÑторию произведенных Ñинхронизаций."</string>
+ <string name="permlab_subscribedFeedsRead">"Ñчитывать каналы, на которые еÑÑ‚ÑŒ подпиÑка"</string>
+ <string name="permdesc_subscribedFeedsRead">"ПозволÑет приложению получить ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ поÑледних Ñинхронизированных каналах."</string>
+ <string name="permlab_subscribedFeedsWrite">"изменÑÑ‚ÑŒ каналы, на которые еÑÑ‚ÑŒ подпиÑка"</string>
+ <string name="permdesc_subscribedFeedsWrite">"ПозволÑет приложению изменÑÑ‚ÑŒ Ñинхронизированные каналы. ВредоноÑные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользовать Ñту возможноÑÑ‚ÑŒ Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñинхронизированных каналов."</string>
+ <string name="permlab_readDictionary">"выполнÑÑ‚ÑŒ чтение из пользовательÑкого ÑловарÑ"</string>
+ <string name="permdesc_readDictionary">"ПозволÑет приложению Ñчитывать любые Ñлова, имена и фразы личного пользованиÑ, которые могут хранитьÑÑ Ð² пользовательÑком Ñловаре."</string>
+ <string name="permlab_writeDictionary">"запиÑывать в пользовательÑкий Ñловарь"</string>
+ <string name="permdesc_writeDictionary">"ПозволÑет приложению запиÑывать новые Ñлова в пользовательÑкий Ñловарь."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Домашний"</item>
- <item msgid="869923650527136615">"Мобильный"</item>
- <item msgid="7897544654242874543">"Рабочий"</item>
- <item msgid="1103601433382158155">"Рабочий факÑ"</item>
- <item msgid="1735177144948329370">"Домашний факÑ"</item>
- <item msgid="603878674477207394">"Пейджер"</item>
- <item msgid="1650824275177931637">"Другой"</item>
- <item msgid="9192514806975898961">"ОÑобый"</item>
+ <item>"Домашний"</item>
+ <item>"Мобильный"</item>
+ <item>"Рабочий"</item>
+ <item>"Рабочий факÑ"</item>
+ <item>"Домашний факÑ"</item>
+ <item>"Пейджер"</item>
+ <item>"Другой"</item>
+ <item>"ОÑобый"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Домашний"</item>
- <item msgid="7084237356602625604">"Рабочий"</item>
- <item msgid="1112044410659011023">"Другой"</item>
- <item msgid="2374913952870110618">"ОÑобый"</item>
+ <item>"Домашний"</item>
+ <item>"Рабочий"</item>
+ <item>"Другой"</item>
+ <item>"ОÑобый"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Мобильный"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Домашний"</item>
- <item msgid="5629153956045109251">"Рабочий"</item>
- <item msgid="4966604264500343469">"Другой"</item>
- <item msgid="4932682847595299369">"ОÑобый"</item>
+ <item>"Домашний"</item>
+ <item>"Рабочий"</item>
+ <item>"Другой"</item>
+ <item>"ОÑобый"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Домашний"</item>
- <item msgid="1359644565647383708">"Рабочий"</item>
- <item msgid="7868549401053615677">"Другое"</item>
- <item msgid="3145118944639869809">"ОÑобый"</item>
+ <item>"Домашний"</item>
+ <item>"Рабочий"</item>
+ <item>"Другое"</item>
+ <item>"ОÑобый"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Рабочий"</item>
- <item msgid="4378074129049520373">"Другой"</item>
- <item msgid="3455047468583965104">"ОÑобый"</item>
+ <item>"Рабочий"</item>
+ <item>"Другой"</item>
+ <item>"ОÑобый"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Введите PIN-код"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Ðеверный PIN-код!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ нажмите \"Меню\", а затем 0."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ЭкÑÑ‚Ñ€ÐµÐ½Ð½Ð°Ñ Ñлужба"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Сеть не найдена)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Экран заблокирован."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Ðажмите \"Меню\", чтобы разблокировать Ñкран или вызвать Ñлужбу ÑкÑтренной помощи."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ нажмите \"Меню\"."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ введите графичеÑкий ключ"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Вызов Ñлужбы ÑкÑтренной помощи"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Правильно!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Повторите попытку"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Идет зарÑдка (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Введите PIN-код"</string>
+ <string name="keyguard_password_wrong_pin_code">"Ðеверный PIN-код!"</string>
+ <string name="keyguard_label_text">"Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ нажмите \"Меню\", а затем 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Ðомер ÑкÑтренной Ñлужбы"</string>
+ <string name="lockscreen_carrier_default">"(Сеть не найдена)"</string>
+ <string name="lockscreen_screen_locked">"Экран заблокирован."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Ðажмите \"Меню\", чтобы разблокировать Ñкран или вызвать Ñлужбу ÑкÑтренной помощи."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ нажмите \"Меню\"."</string>
+ <string name="lockscreen_pattern_instructions">"Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ введите графичеÑкий ключ"</string>
+ <string name="lockscreen_emergency_call">"Вызов Ñлужбы ÑкÑтренной помощи"</string>
+ <string name="lockscreen_pattern_correct">"Правильно!"</string>
+ <string name="lockscreen_pattern_wrong">"Повторите попытку"</string>
+ <string name="lockscreen_plugged_in">"Идет зарÑдка (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Подключите зарÑдное уÑтройÑтво."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Ðет SIM-карты."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"SIM-карта не уÑтановлена."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Ð’Ñтавьте SIM-карту."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Сеть заблокирована"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-карта заблокирована Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ кода PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"См. руководÑтво Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð»Ð¸ ÑвÑжитеÑÑŒ Ñо Ñлужбой поддержки."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-карта заблокирована."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Разблокировка SIM-карты…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"КоличеÑтво неудачных попыток ввода графичеÑкого ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторите попытку через <xliff:g id="NUMBER_1">%d</xliff:g> Ñ."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"КоличеÑтво неудачных попыток ввода графичеÑкого ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. ПоÑле <xliff:g id="NUMBER_1">%d</xliff:g> неудачных попыток вам будет предложено разблокировать телефон Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ учетных данных Google.\n "\n\n" Повторите попытку через <xliff:g id="NUMBER_2">%d</xliff:g> Ñ."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Повторите попытку через <xliff:g id="NUMBER">%d</xliff:g> Ñ."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Забыли графичеÑкий ключ?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Слишком много попыток ввода графичеÑкого ключа!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ войдите Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Ñвоего аккаунта Google"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ (ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ñ‡Ñ‚Ð°)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Пароль"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Вход"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ðеверное Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð»Ð¸ пароль."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Подключите зарÑдное уÑтройÑтво."</string>
+ <string name="lockscreen_missing_sim_message_short">"Ðет SIM-карты."</string>
+ <string name="lockscreen_missing_sim_message">"SIM-карта не уÑтановлена."</string>
+ <string name="lockscreen_missing_sim_instructions">"Ð’Ñтавьте SIM-карту."</string>
+ <string name="lockscreen_network_locked_message">"Сеть заблокирована"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-карта заблокирована Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ кода PUK."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"См. руководÑтво Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð»Ð¸ ÑвÑжитеÑÑŒ Ñо Ñлужбой поддержки."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-карта заблокирована."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Разблокировка SIM-карты…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"КоличеÑтво неудачных попыток ввода графичеÑкого ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторите попытку через <xliff:g id="NUMBER_1">%d</xliff:g> Ñ."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"КоличеÑтво неудачных попыток ввода графичеÑкого ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. ПоÑле <xliff:g id="NUMBER_1">%d</xliff:g> неудачных попыток вам будет предложено разблокировать телефон Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ учетных данных Google.\n "\n\n" Повторите попытку через <xliff:g id="NUMBER_2">%d</xliff:g> Ñ."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Повторите попытку через <xliff:g id="NUMBER">%d</xliff:g> Ñ."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Забыли графичеÑкий ключ?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Слишком много попыток ввода графичеÑкого ключа!"</string>
+ <string name="lockscreen_glogin_instructions">"Ð”Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ войдите Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Ñвоего аккаунта Google"</string>
+ <string name="lockscreen_glogin_username_hint">"Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ (ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ñ‡Ñ‚Ð°)"</string>
+ <string name="lockscreen_glogin_password_hint">"Пароль"</string>
+ <string name="lockscreen_glogin_submit_button">"Вход"</string>
+ <string name="lockscreen_glogin_invalid_input">"Ðеверное Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð»Ð¸ пароль."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ðет уведомлений"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текущие"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"УведомлениÑ"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Идет зарÑдка..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Подключите зарÑдное уÑтройÑтво"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Ð‘Ð°Ñ‚Ð°Ñ€ÐµÑ Ñ€Ð°Ð·Ñ€Ñжена:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"оÑталоÑÑŒ менее <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="status_bar_no_notifications_title">"Ðет уведомлений"</string>
+ <string name="status_bar_ongoing_events_title">"Текущие"</string>
+ <string name="status_bar_latest_events_title">"УведомлениÑ"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Идет зарÑдка..."</string>
+ <string name="battery_low_title">"Подключите зарÑдное уÑтройÑтво"</string>
+ <string name="battery_low_subtitle">"Ð‘Ð°Ñ‚Ð°Ñ€ÐµÑ Ñ€Ð°Ð·Ñ€Ñжена:"</string>
+ <string name="battery_low_percent_format">"оÑталоÑÑŒ менее <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Ðе удалоÑÑŒ провеÑти Ñтандартный теÑÑ‚"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"ДейÑтвие FACTORY_TEST поддерживаетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ Ð´Ð»Ñ Ð¿Ð°ÐºÐµÑ‚Ð¾Ð², уÑтановленных в /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Пакет, обеÑпечивающий дейÑтвие FACTORY_TEST, не найден."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Перезагрузка"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Ðа Ñтранице по адреÑу \"<xliff:g id="TITLE">%s</xliff:g>\" Ñказано:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Перейти Ñ Ñтой Ñтраницы?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Ðажмите \"ОК\", чтобы продолжить, или \"Отмена\", чтобы оÑтатьÑÑ Ð½Ð° текущей Ñтранице."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Подтвердите"</string>
+ <string name="factorytest_failed">"Ðе удалоÑÑŒ провеÑти Ñтандартный теÑÑ‚"</string>
+ <string name="factorytest_not_system">"ДейÑтвие FACTORY_TEST поддерживаетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ Ð´Ð»Ñ Ð¿Ð°ÐºÐµÑ‚Ð¾Ð², уÑтановленных в /system/app."</string>
+ <string name="factorytest_no_action">"Пакет, обеÑпечивающий дейÑтвие FACTORY_TEST, не найден."</string>
+ <string name="factorytest_reboot">"Перезагрузка"</string>
+ <string name="js_dialog_title">"Ðа Ñтранице по адреÑу \"<xliff:g id="TITLE">%s</xliff:g>\" Ñказано:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Перейти Ñ Ñтой Ñтраницы?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Ðажмите \"ОК\", чтобы продолжить, или \"Отмена\", чтобы оÑтатьÑÑ Ð½Ð° текущей Ñтранице."</string>
+ <string name="save_password_label">"Подтвердите"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Ð’Ñ‹ хотите, чтобы браузер запомнил Ñтот пароль?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Ðе ÑейчаÑ"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Запомнить"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Ðикогда"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"У Ð²Ð°Ñ Ð½ÐµÑ‚ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° открытие Ñтой Ñтраницы."</string>
- <string name="text_copied" msgid="4985729524670131385">"ТекÑÑ‚ Ñкопирован в буфер обмена."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Дополнительно"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Меню+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"пробел"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"ввод"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"удалить"</string>
- <string name="search_go" msgid="8298016669822141719">"ПоиÑк"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 меÑÑц назад"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Более меÑÑца назад"</string>
+ <string name="save_password_message">"Ð’Ñ‹ хотите, чтобы браузер запомнил Ñтот пароль?"</string>
+ <string name="save_password_notnow">"Ðе ÑейчаÑ"</string>
+ <string name="save_password_remember">"Запомнить"</string>
+ <string name="save_password_never">"Ðикогда"</string>
+ <string name="open_permission_deny">"У Ð²Ð°Ñ Ð½ÐµÑ‚ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° открытие Ñтой Ñтраницы."</string>
+ <string name="text_copied">"ТекÑÑ‚ Ñкопирован в буфер обмена."</string>
+ <string name="more_item_label">"Дополнительно"</string>
+ <string name="prepend_shortcut_label">"Меню+"</string>
+ <string name="menu_space_shortcut_label">"пробел"</string>
+ <string name="menu_enter_shortcut_label">"ввод"</string>
+ <string name="menu_delete_shortcut_label">"удалить"</string>
+ <string name="search_go">"ПоиÑк"</string>
+ <string name="oneMonthDurationPast">"1 меÑÑц назад"</string>
+ <string name="beforeOneMonthDurationPast">"Более меÑÑца назад"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 Ñекунду назад"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> Ñ. назад"</item>
+ <item quantity="one">"1 Ñекунду назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> Ñ. назад"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 минуту назад"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
+ <item quantity="one">"1 минуту назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 Ñ‡Ð°Ñ Ð½Ð°Ð·Ð°Ð´"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
+ <item quantity="one">"1 Ñ‡Ð°Ñ Ð½Ð°Ð·Ð°Ð´"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"вчера"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
+ <item quantity="one">"вчера"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"через 1 Ñекунду"</item>
- <item quantity="other" msgid="1241926116443974687">"через <xliff:g id="COUNT">%d</xliff:g> Ñ."</item>
+ <item quantity="one">"через 1 Ñекунду"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> Ñ."</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"через 1 минуту"</item>
- <item quantity="other" msgid="3330713936399448749">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
+ <item quantity="one">"через 1 минуту"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"через 1 чаÑ"</item>
- <item quantity="other" msgid="547290677353727389">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
+ <item quantity="one">"через 1 чаÑ"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"завтра"</item>
- <item quantity="other" msgid="5109449375100953247">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
+ <item quantity="one">"завтра"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 Ñек. назад"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> Ñек. назад"</item>
+ <item quantity="one">"1 Ñек. назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> Ñек. назад"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 мин. назад"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
+ <item quantity="one">"1 мин. назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 Ñ‡Ð°Ñ Ð½Ð°Ð·Ð°Ð´"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
+ <item quantity="one">"1 Ñ‡Ð°Ñ Ð½Ð°Ð·Ð°Ð´"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"вчера"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
+ <item quantity="one">"вчера"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"через 1 Ñ."</item>
- <item quantity="other" msgid="5495880108825805108">"через <xliff:g id="COUNT">%d</xliff:g> Ñ."</item>
+ <item quantity="one">"через 1 Ñ."</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> Ñ."</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"через 1 мин."</item>
- <item quantity="other" msgid="4216113292706568726">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
+ <item quantity="one">"через 1 мин."</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"через 1 чаÑ"</item>
- <item quantity="other" msgid="3705373766798013406">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
+ <item quantity="one">"через 1 чаÑ"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"завтра"</item>
- <item quantity="other" msgid="2973062968038355991">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
+ <item quantity="one">"завтра"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"в %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"в %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"через %s"</string>
- <string name="day" msgid="8144195776058119424">"дн."</string>
- <string name="days" msgid="4774547661021344602">"дн."</string>
- <string name="hour" msgid="2126771916426189481">"ч."</string>
- <string name="hours" msgid="894424005266852993">"ч."</string>
- <string name="minute" msgid="9148878657703769868">"мин."</string>
- <string name="minutes" msgid="5646001005827034509">"мин."</string>
- <string name="second" msgid="3184235808021478">"Ñ."</string>
- <string name="seconds" msgid="3161515347216589235">"Ñ."</string>
- <string name="week" msgid="5617961537173061583">"нед."</string>
- <string name="weeks" msgid="6509623834583944518">"нед."</string>
- <string name="year" msgid="4001118221013892076">"г."</string>
- <string name="years" msgid="6881577717993213522">"г."</string>
- <string name="every_weekday" msgid="8777593878457748503">"Каждый рабочий день (пн-пт)"</string>
- <string name="daily" msgid="5738949095624133403">"Ежедневно"</string>
- <string name="weekly" msgid="983428358394268344">"Еженедельно, <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"ЕжемеÑÑчно"</string>
- <string name="yearly" msgid="1519577999407493836">"Ежегодно"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Ðе удалоÑÑŒ воÑпроизвеÑти видео"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Это видео не подходит Ð´Ð»Ñ Ð¿Ð¾Ñ‚Ð¾ÐºÐ¾Ð²Ð¾Ð³Ð¾ воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð½Ð° данном уÑтройÑтве."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Ðевозможно воÑпроизвеÑти видео."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"ОК"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"полдень"</string>
- <string name="Noon" msgid="3342127745230013127">"Полдень"</string>
- <string name="midnight" msgid="7166259508850457595">"полночь"</string>
- <string name="Midnight" msgid="5630806906897892201">"Полночь"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Выбрать вÑе"</string>
- <string name="selectText" msgid="3889149123626888637">"Выбрать текÑÑ‚"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"ОÑтановить выделение текÑта"</string>
- <string name="cut" msgid="3092569408438626261">"Вырезать"</string>
- <string name="cutAll" msgid="2436383270024931639">"Вырезать вÑе"</string>
- <string name="copy" msgid="2681946229533511987">"Копировать"</string>
- <string name="copyAll" msgid="2590829068100113057">"Копировать вÑе"</string>
- <string name="paste" msgid="5629880836805036433">"Ð’Ñтавить"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Копировать URL"</string>
- <string name="inputMethod" msgid="7673923508389094672">"СпоÑоб ввода"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Добавить \"%s\" в Ñловарь"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Изменить текÑÑ‚"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"ÐедоÑтаточно меÑта"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"ЗаканчиваетÑÑ Ð¼ÐµÑто в памÑти телефона."</string>
- <string name="ok" msgid="5970060430562524910">"ОК"</string>
- <string name="cancel" msgid="6442560571259935130">"Отмена"</string>
- <string name="yes" msgid="5362982303337969312">"ОК"</string>
- <string name="no" msgid="5141531044935541497">"Отмена"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
- <string name="capital_on" msgid="1544682755514494298">"ВКЛ"</string>
- <string name="capital_off" msgid="6815870386972805832">"ВЫКЛ"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Завершить дейÑтвие Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"ИÑпользовать по умолчанию Ð´Ð»Ñ Ñтого дейÑтвиÑ."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Удалить наÑтройки по умолчанию: главный Ñкран &gt; \"ÐаÑтройки\" &gt; \"ПриложениÑ\" &gt; \"Управление приложениÑми\"."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Выберите дейÑтвие"</string>
- <string name="noApplications" msgid="1691104391758345586">"Это дейÑтвие не может выполнÑÑ‚ÑŒ ни одно приложение."</string>
- <string name="aerr_title" msgid="653922989522758100">"Ошибка приложениÑ!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Произошла Ð½ÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð°Ñ Ð¾Ñтановка Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ <xliff:g id="APPLICATION">%1$s</xliff:g> (процеÑÑ <xliff:g id="PROCESS">%2$s</xliff:g>). Повторите попытку."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Произошла Ð½ÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð°Ñ Ð¾Ñтановка процеÑÑа <xliff:g id="PROCESS">%1$s</xliff:g>. Повторите попытку."</string>
- <string name="anr_title" msgid="3100070910664756057">"Извините!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"ДейÑтвие <xliff:g id="ACTIVITY">%1$s</xliff:g> (в приложении <xliff:g id="APPLICATION">%2$s</xliff:g>) не отвечает."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"ДейÑтвие <xliff:g id="ACTIVITY">%1$s</xliff:g> (в процеÑÑе <xliff:g id="PROCESS">%2$s</xliff:g>) не отвечает."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Приложение <xliff:g id="APPLICATION">%1$s</xliff:g> (в процеÑÑе <xliff:g id="PROCESS">%2$s</xliff:g>) не отвечает."</string>
- <string name="anr_process" msgid="1246866008169975783">"ПроцеÑÑ <xliff:g id="PROCESS">%1$s</xliff:g> не отвечает."</string>
- <string name="force_close" msgid="3653416315450806396">"Принудительное закрытие"</string>
+ <string name="preposition_for_date">"в %s"</string>
+ <string name="preposition_for_time">"в %s"</string>
+ <string name="preposition_for_year">"через %s"</string>
+ <string name="day">"дн."</string>
+ <string name="days">"дн."</string>
+ <string name="hour">"ч."</string>
+ <string name="hours">"ч."</string>
+ <string name="minute">"мин."</string>
+ <string name="minutes">"мин."</string>
+ <string name="second">"Ñ."</string>
+ <string name="seconds">"Ñ."</string>
+ <string name="week">"нед."</string>
+ <string name="weeks">"нед."</string>
+ <string name="year">"г."</string>
+ <string name="years">"г."</string>
+ <string name="every_weekday">"Каждый рабочий день (пн-пт)"</string>
+ <string name="daily">"Ежедневно"</string>
+ <string name="weekly">"Еженедельно, <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"ЕжемеÑÑчно"</string>
+ <string name="yearly">"Ежегодно"</string>
+ <string name="VideoView_error_title">"Ðе удалоÑÑŒ воÑпроизвеÑти видео"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Это видео не подходит Ð´Ð»Ñ Ð¿Ð¾Ñ‚Ð¾ÐºÐ¾Ð²Ð¾Ð³Ð¾ воÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð½Ð° данном уÑтройÑтве."</string>
+ <string name="VideoView_error_text_unknown">"Ðевозможно воÑпроизвеÑти видео."</string>
+ <string name="VideoView_error_button">"ОК"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"полдень"</string>
+ <string name="Noon">"Полдень"</string>
+ <string name="midnight">"полночь"</string>
+ <string name="Midnight">"Полночь"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Выбрать вÑе"</string>
+ <string name="selectText">"Выбрать текÑÑ‚"</string>
+ <string name="stopSelectingText">"ОÑтановить выделение текÑта"</string>
+ <string name="cut">"Вырезать"</string>
+ <string name="cutAll">"Вырезать вÑе"</string>
+ <string name="copy">"Копировать"</string>
+ <string name="copyAll">"Копировать вÑе"</string>
+ <string name="paste">"Ð’Ñтавить"</string>
+ <string name="copyUrl">"Копировать URL"</string>
+ <string name="inputMethod">"СпоÑоб ввода"</string>
+ <string name="addToDictionary">"Добавить \"%s\" в Ñловарь"</string>
+ <string name="editTextMenuTitle">"Изменить текÑÑ‚"</string>
+ <string name="low_internal_storage_view_title">"ÐедоÑтаточно меÑта"</string>
+ <string name="low_internal_storage_view_text">"ЗаканчиваетÑÑ Ð¼ÐµÑто в памÑти телефона."</string>
+ <string name="ok">"ОК"</string>
+ <string name="cancel">"Отмена"</string>
+ <string name="yes">"ОК"</string>
+ <string name="no">"Отмена"</string>
+ <string name="dialog_alert_title">"Внимание"</string>
+ <string name="capital_on">"ВКЛ"</string>
+ <string name="capital_off">"ВЫКЛ"</string>
+ <string name="whichApplication">"Завершить дейÑтвие Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ"</string>
+ <string name="alwaysUse">"ИÑпользовать по умолчанию Ð´Ð»Ñ Ñтого дейÑтвиÑ."</string>
+ <string name="clearDefaultHintMsg">"Удалить наÑтройки по умолчанию: главный Ñкран &gt; \"ÐаÑтройки\" &gt; \"ПриложениÑ\" &gt; \"Управление приложениÑми\"."</string>
+ <string name="chooseActivity">"Выберите дейÑтвие"</string>
+ <string name="noApplications">"Это дейÑтвие не может выполнÑÑ‚ÑŒ ни одно приложение."</string>
+ <string name="aerr_title">"Ошибка приложениÑ!"</string>
+ <string name="aerr_application">"Произошла Ð½ÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð°Ñ Ð¾Ñтановка Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ <xliff:g id="APPLICATION">%1$s</xliff:g> (процеÑÑ <xliff:g id="PROCESS">%2$s</xliff:g>). Повторите попытку."</string>
+ <string name="aerr_process">"Произошла Ð½ÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð°Ñ Ð¾Ñтановка процеÑÑа <xliff:g id="PROCESS">%1$s</xliff:g>. Повторите попытку."</string>
+ <string name="anr_title">"Извините!"</string>
+ <string name="anr_activity_application">"ДейÑтвие <xliff:g id="ACTIVITY">%1$s</xliff:g> (в приложении <xliff:g id="APPLICATION">%2$s</xliff:g>) не отвечает."</string>
+ <string name="anr_activity_process">"ДейÑтвие <xliff:g id="ACTIVITY">%1$s</xliff:g> (в процеÑÑе <xliff:g id="PROCESS">%2$s</xliff:g>) не отвечает."</string>
+ <string name="anr_application_process">"Приложение <xliff:g id="APPLICATION">%1$s</xliff:g> (в процеÑÑе <xliff:g id="PROCESS">%2$s</xliff:g>) не отвечает."</string>
+ <string name="anr_process">"ПроцеÑÑ <xliff:g id="PROCESS">%1$s</xliff:g> не отвечает."</string>
+ <string name="force_close">"Принудительное закрытие"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Подождите"</string>
- <string name="debug" msgid="9103374629678531849">"Выполнить отладку"</string>
- <string name="sendText" msgid="5132506121645618310">"Выберите дейÑтвие Ð´Ð»Ñ Ñ‚ÐµÐºÑта"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"ГромкоÑÑ‚ÑŒ звонка"</string>
- <string name="volume_music" msgid="5421651157138628171">"ГромкоÑÑ‚ÑŒ мультимедиа"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"ВоÑпроизведение по каналу Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"ГромкоÑÑ‚ÑŒ входÑщего вызова"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"ГромкоÑÑ‚ÑŒ входÑщего вызова Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"ГромкоÑÑ‚ÑŒ Ñигнала предупреждениÑ"</string>
- <string name="volume_notification" msgid="2422265656744276715">"ГромкоÑÑ‚ÑŒ уведомлениÑ"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"ГромкоÑÑ‚ÑŒ"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"ÐœÐµÐ»Ð¾Ð´Ð¸Ñ Ð¿Ð¾ умолчанию"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"ÐœÐµÐ»Ð¾Ð´Ð¸Ñ Ð¿Ð¾ умолчанию (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Без звука"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¼ÐµÐ»Ð¾Ð´Ð¸Ñ"</string>
+ <string name="wait">"Подождите"</string>
+ <string name="debug">"Выполнить отладку"</string>
+ <string name="sendText">"Выберите дейÑтвие Ð´Ð»Ñ Ñ‚ÐµÐºÑта"</string>
+ <string name="volume_ringtone">"ГромкоÑÑ‚ÑŒ звонка"</string>
+ <string name="volume_music">"ГромкоÑÑ‚ÑŒ мультимедиа"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"ВоÑпроизведение по каналу Bluetooth"</string>
+ <string name="volume_call">"ГромкоÑÑ‚ÑŒ входÑщего вызова"</string>
+ <string name="volume_bluetooth_call">"ГромкоÑÑ‚ÑŒ входÑщего вызова Bluetooth"</string>
+ <string name="volume_alarm">"ГромкоÑÑ‚ÑŒ Ñигнала предупреждениÑ"</string>
+ <string name="volume_notification">"ГромкоÑÑ‚ÑŒ уведомлениÑ"</string>
+ <string name="volume_unknown">"ГромкоÑÑ‚ÑŒ"</string>
+ <string name="ringtone_default">"ÐœÐµÐ»Ð¾Ð´Ð¸Ñ Ð¿Ð¾ умолчанию"</string>
+ <string name="ringtone_default_with_actual">"ÐœÐµÐ»Ð¾Ð´Ð¸Ñ Ð¿Ð¾ умолчанию (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Без звука"</string>
+ <string name="ringtone_picker_title">"Мелодии"</string>
+ <string name="ringtone_unknown">"ÐеизвеÑÑ‚Ð½Ð°Ñ Ð¼ÐµÐ»Ð¾Ð´Ð¸Ñ"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"ДоÑтупна Ñеть Wi-Fi"</item>
- <item quantity="other" msgid="4192424489168397386">"ДоÑтупна Ñеть Wi-Fi"</item>
+ <item quantity="one">"ДоÑтупна Ñеть Wi-Fi"</item>
+ <item quantity="other">"ДоÑтупна Ñеть Wi-Fi"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Ðайдена доÑÑ‚ÑƒÐ¿Ð½Ð°Ñ Ñеть Wi-Fi"</item>
- <item quantity="other" msgid="7915895323644292768">"Ðайдены доÑтупные Ñети Wi-Fi"</item>
+ <item quantity="one">"Ðайдена доÑÑ‚ÑƒÐ¿Ð½Ð°Ñ Ñеть Wi-Fi"</item>
+ <item quantity="other">"Ðайдены доÑтупные Ñети Wi-Fi"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Введите Ñимвол"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"ÐеизвеÑтное приложение"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Отправка SMS-Ñообщений"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"ОтправлÑетÑÑ Ð±Ð¾Ð»ÑŒÑˆÐ¾Ðµ количеÑтво SMS-Ñообщений. Ðажмите \"ОК\" Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ \"Отмена\" Ð´Ð»Ñ Ð¿Ñ€ÐµÐºÑ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"ОК"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Отмена"</string>
- <string name="date_time_set" msgid="5777075614321087758">"УÑтановить"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"По умолчанию"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Ðе требуетÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ð¹"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Скрыть"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Показать вÑе"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Идет загрузка…"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"уÑтройÑтво USB подключено"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Телефон подключен к компьютеру через порт USB. ЕÑли необходимо копировать файлы Ñ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð° на SD-карту телефона (или наоборот), выберите \"УÑтановить\"."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Смонтировать"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Ðе монтировать"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"При иÑпользовании SD-карты как USB-Ð½Ð°ÐºÐ¾Ð¿Ð¸Ñ‚ÐµÐ»Ñ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ»Ð° неполадка."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"уÑтройÑтво USB подключено"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Выберите копирование файлов на компьютер или Ñ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð°."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Выключить USB-накопитель"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Выберите, чтобы выключить USB-накопитель."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Выключить USB-накопитель"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Перед выключением USB-Ð½Ð°ÐºÐ¾Ð¿Ð¸Ñ‚ÐµÐ»Ñ Ð¾Ð±Ñзательно отключите USB-хоÑÑ‚. Выберите \"Выключить\", чтобы выключить USB-накопитель."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Выключить"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Отмена"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"При выключении USB-Ð½Ð°ÐºÐ¾Ð¿Ð¸Ñ‚ÐµÐ»Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð¾ÑˆÐ»Ð° неполадка. УбедитеÑÑŒ, что USB-хоÑÑ‚ отключен, и повторите попытку."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Форматировать карту SD"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Отформатировать карту SD? Ð’Ñе данные, находÑщиеÑÑ Ð½Ð° карте, будут уничтожены."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Формат"</string>
+ <string name="select_character">"Введите Ñимвол"</string>
+ <string name="sms_control_default_app_name">"ÐеизвеÑтное приложение"</string>
+ <string name="sms_control_title">"Отправка SMS-Ñообщений"</string>
+ <string name="sms_control_message">"ОтправлÑетÑÑ Ð±Ð¾Ð»ÑŒÑˆÐ¾Ðµ количеÑтво SMS-Ñообщений. Ðажмите \"ОК\" Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ \"Отмена\" Ð´Ð»Ñ Ð¿Ñ€ÐµÐºÑ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸."</string>
+ <string name="sms_control_yes">"ОК"</string>
+ <string name="sms_control_no">"Отмена"</string>
+ <string name="date_time_set">"УÑтановить"</string>
+ <string name="default_permission_group">"По умолчанию"</string>
+ <string name="no_permissions">"Ðе требуетÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ð¹"</string>
+ <string name="perms_hide"><b>"Скрыть"</b></string>
+ <string name="perms_show_all"><b>"Показать вÑе"</b></string>
+ <string name="googlewebcontenthelper_loading">"Идет загрузка…"</string>
+ <string name="usb_storage_title">"уÑтройÑтво USB подключено"</string>
+ <string name="usb_storage_message">"Телефон подключен к компьютеру через порт USB. ЕÑли необходимо копировать файлы Ñ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð° на SD-карту телефона (или наоборот), выберите \"УÑтановить\"."</string>
+ <string name="usb_storage_button_mount">"Смонтировать"</string>
+ <string name="usb_storage_button_unmount">"Ðе монтировать"</string>
+ <string name="usb_storage_error_message">"При иÑпользовании SD-карты как USB-Ð½Ð°ÐºÐ¾Ð¿Ð¸Ñ‚ÐµÐ»Ñ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ»Ð° неполадка."</string>
+ <string name="usb_storage_notification_title">"уÑтройÑтво USB подключено"</string>
+ <string name="usb_storage_notification_message">"Выберите копирование файлов на компьютер или Ñ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð°."</string>
+ <string name="usb_storage_stop_notification_title">"Выключить USB-накопитель"</string>
+ <string name="usb_storage_stop_notification_message">"Выберите, чтобы выключить USB-накопитель."</string>
+ <string name="usb_storage_stop_title">"Выключить USB-накопитель"</string>
+ <string name="usb_storage_stop_message">"Перед выключением USB-Ð½Ð°ÐºÐ¾Ð¿Ð¸Ñ‚ÐµÐ»Ñ Ð¾Ð±Ñзательно отключите USB-хоÑÑ‚. Выберите \"Выключить\", чтобы выключить USB-накопитель."</string>
+ <string name="usb_storage_stop_button_mount">"Выключить"</string>
+ <string name="usb_storage_stop_button_unmount">"Отмена"</string>
+ <string name="usb_storage_stop_error_message">"При выключении USB-Ð½Ð°ÐºÐ¾Ð¿Ð¸Ñ‚ÐµÐ»Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð¾ÑˆÐ»Ð° неполадка. УбедитеÑÑŒ, что USB-хоÑÑ‚ отключен, и повторите попытку."</string>
+ <string name="extmedia_format_title">"Форматировать карту SD"</string>
+ <string name="extmedia_format_message">"Отформатировать карту SD? Ð’Ñе данные, находÑщиеÑÑ Ð½Ð° карте, будут уничтожены."</string>
+ <string name="extmedia_format_button_format">"Формат"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Выберите ÑпоÑоб ввода"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Подготовка карты SD"</string>
+ <string name="select_input_method">"Выберите ÑпоÑоб ввода"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"варианты"</u></string>
+ <string name="ext_media_checking_notification_title">"Подготовка карты SD"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"ПуÑÑ‚Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð° SD"</string>
+ <string name="ext_media_nofs_notification_title">"ПуÑÑ‚Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð° SD"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"ÐŸÐ¾Ð²Ñ€ÐµÐ¶Ð´ÐµÐ½Ð½Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð° SD"</string>
+ <string name="ext_media_unmountable_notification_title">"ÐŸÐ¾Ð²Ñ€ÐµÐ¶Ð´ÐµÐ½Ð½Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð° SD"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"Карта SD неожиданно извлечена"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Перед извлечением карты SD отключите ее во избежание потери данных."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"БезопаÑное удаление карты SD"</string>
+ <string name="ext_media_badremoval_notification_title">"Карта SD неожиданно извлечена"</string>
+ <string name="ext_media_badremoval_notification_message">"Перед извлечением карты SD отключите ее во избежание потери данных."</string>
+ <string name="ext_media_safe_unmount_notification_title">"БезопаÑное удаление карты SD"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"ОтÑутÑтвует карта SD"</string>
+ <string name="ext_media_nomedia_notification_title">"ОтÑутÑтвует карта SD"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"ПодходÑщих дейÑтвий не найдено"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"обновлÑÑ‚ÑŒ ÑтатиÑтику иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÐµÐ½Ñ‚Ð¾Ð²"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"ПозволÑет изменÑÑ‚ÑŒ Ñобранную ÑтатиÑтику иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÐµÐ½Ñ‚Ð¾Ð². Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Ðажмите дважды Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð°Ñштаба"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Ошибка при наполнении виджета"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Выбрать"</string>
- <string name="ime_action_search" msgid="658110271822807811">"ПоиÑк"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Отправить"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Далее"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Готово"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Выполнить"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Ðабрать номер"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Создать контакт"\n"Ñ Ð½Ð¾Ð¼ÐµÑ€Ð¾Ð¼ <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"ПодходÑщих дейÑтвий не найдено"</string>
+ <string name="permlab_pkgUsageStats">"обновлÑÑ‚ÑŒ ÑтатиÑтику иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÐµÐ½Ñ‚Ð¾Ð²"</string>
+ <string name="permdesc_pkgUsageStats">"ПозволÑет изменÑÑ‚ÑŒ Ñобранную ÑтатиÑтику иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÐµÐ½Ñ‚Ð¾Ð². Ðе предназначено Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ñ‹Ð¼Ð¸ приложениÑми."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Ðажмите дважды Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð°Ñштаба"</string>
+ <string name="gadget_host_error_inflating">"Ошибка при наполнении виджета"</string>
+ <string name="ime_action_go">"Выбрать"</string>
+ <string name="ime_action_search">"ПоиÑк"</string>
+ <string name="ime_action_send">"Отправить"</string>
+ <string name="ime_action_next">"Далее"</string>
+ <string name="ime_action_done">"Готово"</string>
+ <string name="ime_action_default">"Выполнить"</string>
+ <string name="dial_number_using">"Ðабрать номер"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Создать контакт"\n"Ñ Ð½Ð¾Ð¼ÐµÑ€Ð¾Ð¼ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 611bfaa..40d2500 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"kB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"kB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"&lt;utan titel&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Inget telefonnummer)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Okänd)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Röstbrevlåda"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Anslutningsproblem eller ogiltig MMI-kod."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Tjänsten har aktiverats."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Tjänsten har aktiverats för:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Tjänsten har inaktiverats."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Registreringen slutförd."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Radering lyckades."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Fel lösenord."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI slutförd."</string>
- <string name="badPin" msgid="5085454289896032547">"Den gamla PIN-koden som du angav är fel."</string>
- <string name="badPuk" msgid="5702522162746042460">"PUK-koden som du angav är fel."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"PIN-koderna som du angav matchar inte."</string>
- <string name="invalidPin" msgid="3850018445187475377">"Ange en PIN-kod som är 4 till 8 siffror."</string>
- <string name="needPuk" msgid="919668385956251611">"Ditt SIM-kort är PUK-låst. Ange PUK-koden om du vill låsa upp det."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Ange PUK2-koden för att häva spärren av SIM-kortet."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Nummerpresentatör för inkommande samtal"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Nummerpresentatör för utgående samtal"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Vidarebefordra samtal"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Samtal väntar"</string>
- <string name="BaMmi" msgid="455193067926770581">"Samtalsspärr"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Byt lösenord"</string>
- <string name="PinMmi" msgid="3113117780361190304">"Byt PIN-kod"</string>
+ <string name="untitled">"&lt;utan titel&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Inget telefonnummer)"</string>
+ <string name="unknownName">"(Okänd)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Röstbrevlåda"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Anslutningsproblem eller ogiltig MMI-kod."</string>
+ <string name="serviceEnabled">"Tjänsten har aktiverats."</string>
+ <string name="serviceEnabledFor">"Tjänsten har aktiverats för:"</string>
+ <string name="serviceDisabled">"Tjänsten har inaktiverats."</string>
+ <string name="serviceRegistered">"Registreringen slutförd."</string>
+ <string name="serviceErased">"Radering lyckades."</string>
+ <string name="passwordIncorrect">"Fel lösenord."</string>
+ <string name="mmiComplete">"MMI slutförd."</string>
+ <string name="badPin">"Den gamla PIN-koden som du angav är fel."</string>
+ <string name="badPuk">"PUK-koden som du angav är fel."</string>
+ <string name="mismatchPin">"PIN-koderna som du angav matchar inte."</string>
+ <string name="invalidPin">"Ange en PIN-kod som är 4 till 8 siffror."</string>
+ <string name="needPuk">"Ditt SIM-kort är PUK-låst. Ange PUK-koden om du vill låsa upp det."</string>
+ <string name="needPuk2">"Ange PUK2-koden för att häva spärren av SIM-kortet."</string>
+ <string name="ClipMmi">"Nummerpresentatör för inkommande samtal"</string>
+ <string name="ClirMmi">"Nummerpresentatör för utgående samtal"</string>
+ <string name="CfMmi">"Vidarebefordra samtal"</string>
+ <string name="CwMmi">"Samtal väntar"</string>
+ <string name="BaMmi">"Samtalsspärr"</string>
+ <string name="PwdMmi">"Byt lösenord"</string>
+ <string name="PinMmi">"Byt PIN-kod"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Nummerpresentatören är begränsad som standard. Nästa samtal: Begränsad"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Nummerpresentatörens standardinställning är begränsad. Nästa samtal: Inte begränsad"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Begränsad"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Inte begränsad"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Tjänsten är inte etablerad."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Det går inte att ändra inställningen för nummerpresentatör."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Begränsad åtkomst har ändrats"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Datatjänsten är blockerad."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Räddningstjänsten är blockerad."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Tjänsten röst/SMS är blockerad."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Alla röst-/SMS-tjänster har blockerats."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Röst"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Data"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asynkront"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Synkronisera"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paket"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Nummerpresentatören är begränsad som standard. Nästa samtal: Begränsad"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Nummerpresentatörens standardinställning är begränsad. Nästa samtal: Inte begränsad"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Begränsad"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Nummerpresentatörens standardinställning är inte begränsad. Nästa samtal: Inte begränsad"</string>
+ <string name="serviceNotProvisioned">"Tjänsten är inte etablerad."</string>
+ <string name="CLIRPermanent">"Det går inte att ändra inställningen för nummerpresentatör."</string>
+ <string name="RestrictedChangedTitle">"Begränsad åtkomst har ändrats"</string>
+ <string name="RestrictedOnData">"Datatjänsten är blockerad."</string>
+ <string name="RestrictedOnEmergency">"Räddningstjänsten är blockerad."</string>
+ <string name="RestrictedOnNormal">"Tjänsten röst/SMS är blockerad."</string>
+ <string name="RestrictedOnAll">"Alla röst-/SMS-tjänster har blockerats."</string>
+ <string name="serviceClassVoice">"Röst"</string>
+ <string name="serviceClassData">"Data"</string>
+ <string name="serviceClassFAX">"FAX"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynkront"</string>
+ <string name="serviceClassDataSync">"Synkronisera"</string>
+ <string name="serviceClassPacket">"Paket"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Vidarebefordras inte"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. Vidarebefordras inte"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Vidarebefordras inte"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Vidarebefordras inte"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. Vidarebefordras inte"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Vidarebefordras inte"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="2567300624552921790">"Webbsidan innehåller ett fel."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Webbadressen kunde inte hittas."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Webbplatsens autentiseringsmetod stöds inte."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Det gick inte att autentisera."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Det gick inte att autentisera via proxyservern."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Det gick inte att ansluta till servern."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Servern kommunicerade inte. Försök igen senare."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Anslutningen till servern har kopplats ifrån."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Sidan innehåller för många serveromdirigeringar."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokollet stöds inte."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Det gick inte att upprätta en säker anslutning."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Sidan kunde inte öppnas eftersom webbadressen är ogiltig."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Det gick inte att komma åt filen."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Den begärda filen hittades inte."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"För många begäranden bearbetas. Försök igen senare."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Synkronisera"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronisera"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"För många <xliff:g id="CONTENT_TYPE">%s</xliff:g>-borttagningar."</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefonens lagringsutrymme är fullt! Radera några filer för att frigöra utrymme."</string>
- <string name="me" msgid="6545696007631404292">"Jag"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefonalternativ"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Tyst läge"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Aktivera trådlöst"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Inaktivera trådlöst"</string>
- <string name="screen_lock" msgid="799094655496098153">"Skärmlås"</string>
- <string name="power_off" msgid="4266614107412865048">"Stäng av"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Avslutar…"</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Din telefon stängs av."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Inga nya program."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefonalternativ"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Skärmlås"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Stäng av"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tyst läge"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ljudet är AV"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ljudet är PÅ"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flygplansläge"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flygplansläge är AKTIVERAT"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flygplansläge är INAKTIVERAT"</string>
- <string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tjänster som kostar pengar"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Tillåter att program gör saker som kostar pengar."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Dina meddelanden"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"Läs och skriv SMS, e-post och andra meddelanden."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Dina personliga uppgifter"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Direktåtkomst till dina kontakter och kalendern som har lagrats på telefonen."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Din plats"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Övervaka din fysiska plats"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"Nätverkskommunikation"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Tillåt att program kommer åt olika nätverksfunktioner."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Dina Google-konton"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Få åtkomst till tillgängliga Google-konton."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Kontroller för maskinvara"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Direkt åtkomst till maskinvara på handenheten."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefonsamtal"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Övervaka, spela in och bearbeta telefonsamtal"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Systemverktyg"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Åtkomst och kontroll av systemet på lägre nivå."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Utvecklingsverktyg"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funktioner som endast behövs för programutvecklare."</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Webbsidan innehåller ett fel."</string>
+ <string name="httpErrorLookup">"Webbadressen kunde inte hittas."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Webbplatsens autentiseringsmetod stöds inte."</string>
+ <string name="httpErrorAuth">"Det gick inte att autentisera."</string>
+ <string name="httpErrorProxyAuth">"Det gick inte att autentisera via proxyservern."</string>
+ <string name="httpErrorConnect">"Det gick inte att ansluta till servern."</string>
+ <string name="httpErrorIO">"Servern kommunicerade inte. Försök igen senare."</string>
+ <string name="httpErrorTimeout">"Anslutningen till servern har kopplats ifrån."</string>
+ <string name="httpErrorRedirectLoop">"Sidan innehåller för många serveromdirigeringar."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokollet stöds inte."</string>
+ <string name="httpErrorFailedSslHandshake">"Det gick inte att upprätta en säker anslutning."</string>
+ <string name="httpErrorBadUrl">"Sidan kunde inte öppnas eftersom webbadressen är ogiltig."</string>
+ <string name="httpErrorFile">"Det gick inte att komma åt filen."</string>
+ <string name="httpErrorFileNotFound">"Den begärda filen hittades inte."</string>
+ <string name="httpErrorTooManyRequests">"För många begäranden bearbetas. Försök igen senare."</string>
+ <string name="contentServiceSync">"Synkronisera"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synkronisera"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"För många <xliff:g id="CONTENT_TYPE">%s</xliff:g>-borttagningar."</string>
+ <string name="low_memory">"Telefonens lagringsutrymme är fullt! Radera några filer för att frigöra utrymme."</string>
+ <string name="me">"Jag"</string>
+ <string name="power_dialog">"Telefonalternativ"</string>
+ <string name="silent_mode">"Tyst läge"</string>
+ <string name="turn_on_radio">"Aktivera trådlöst"</string>
+ <string name="turn_off_radio">"Inaktivera trådlöst"</string>
+ <string name="screen_lock">"Skärmlås"</string>
+ <string name="power_off">"Stäng av"</string>
+ <string name="shutdown_progress">"Avslutar…"</string>
+ <string name="shutdown_confirm">"Din telefon stängs av."</string>
+ <string name="no_recent_tasks">"Inga nya program."</string>
+ <string name="global_actions">"Telefonalternativ"</string>
+ <string name="global_action_lock">"Skärmlås"</string>
+ <string name="global_action_power_off">"Stäng av"</string>
+ <string name="global_action_toggle_silent_mode">"Tyst läge"</string>
+ <string name="global_action_silent_mode_on_status">"Ljudet är AV"</string>
+ <string name="global_action_silent_mode_off_status">"Ljudet är PÅ"</string>
+ <string name="global_actions_toggle_airplane_mode">"Flygplansläge"</string>
+ <string name="global_actions_airplane_mode_on_status">"Flygplansläge är AKTIVERAT"</string>
+ <string name="global_actions_airplane_mode_off_status">"Flygplansläge är INAKTIVERAT"</string>
+ <string name="safeMode">"Säkert läge"</string>
+ <string name="android_system_label">"Android-system"</string>
+ <string name="permgrouplab_costMoney">"Tjänster som kostar pengar"</string>
+ <string name="permgroupdesc_costMoney">"Tillåter att program gör saker som kostar pengar."</string>
+ <string name="permgrouplab_messages">"Dina meddelanden"</string>
+ <string name="permgroupdesc_messages">"Läs och skriv SMS, e-post och andra meddelanden."</string>
+ <string name="permgrouplab_personalInfo">"Dina personliga uppgifter"</string>
+ <string name="permgroupdesc_personalInfo">"Direktåtkomst till dina kontakter och kalendern som har lagrats på telefonen."</string>
+ <string name="permgrouplab_location">"Din plats"</string>
+ <string name="permgroupdesc_location">"Övervaka din fysiska plats"</string>
+ <string name="permgrouplab_network">"Nätverkskommunikation"</string>
+ <string name="permgroupdesc_network">"Tillåt att program kommer åt olika nätverksfunktioner."</string>
+ <string name="permgrouplab_accounts">"Dina Google-konton"</string>
+ <string name="permgroupdesc_accounts">"Få åtkomst till tillgängliga Google-konton."</string>
+ <string name="permgrouplab_hardwareControls">"Kontroller för maskinvara"</string>
+ <string name="permgroupdesc_hardwareControls">"Direkt åtkomst till maskinvara på handenheten."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonsamtal"</string>
+ <string name="permgroupdesc_phoneCalls">"Övervaka, spela in och bearbeta telefonsamtal"</string>
+ <string name="permgrouplab_systemTools">"Systemverktyg"</string>
+ <string name="permgroupdesc_systemTools">"Åtkomst och kontroll av systemet på lägre nivå."</string>
+ <string name="permgrouplab_developmentTools">"Utvecklingsverktyg"</string>
+ <string name="permgroupdesc_developmentTools">"Funktioner som endast behövs för programutvecklare."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"inaktivera eller ändra statusfält"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Tillåter att programmet inaktiverar statusfältet eller lägger till och tar bort systemikoner."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expandera/komprimera statusfält"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Tillåter att program expanderar eller komprimerar statusfältet."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"spärra utgående samtal"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Tillåter att program hanterar utgående samtal och ändrar numret som ska ringas upp. Skadliga program kan övervaka, omdirigera eller förhindra utgående samtal."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"ta emot SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Tillåter att program tar emot och bearbetar SMS-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem utan att visa dem för dig."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"ta emot MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Tillåter att program tar emot och bearbetar MMS-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem innan du har sett dem."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"skicka SMS"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Tillåter att programmet skickar SMS-meddelanden. Skadliga program kan skicka meddelanden utan ditt godkännande vilket kan kosta pengar."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"läsa SMS eller MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Tillåter att program läser SMS-meddelanden som sparats på din telefon eller SIM-kort. Skadliga program kan läsa dina konfidentiella meddelanden."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"redigera SMS eller MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Tillåter att program skriver till SMS-meddelanden som lagrats på din telefon eller SIM-kort. Skadliga program kan radera dina meddelanden."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"ta emot WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Tillåter att program tar emot och bearbetar WAP-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem utan att visa dem för dig."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"hämta program som körs"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Tillåter att program hämtar information om uppgifter som körs och har körts. Skadliga program kan upptäcka privat information om andra program."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"byt ordning på program som körs"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillåter att ett program flyttar uppgifter till förgrunden eller bakgrunden. Skadliga program kan tvinga sig till förgrunden utan att du kan styra det."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"aktivera felsökning av program"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Tillåter att ett program aktiverar felsökning för ett annat program. Skadliga program kan använda detta för att avsluta andra program."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"ändra dina gränssnittsinställningar"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Tillåter att ett program ändrar den aktuella konfigurationen, till exempel språk eller övergripande teckenformat."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"starta om andra program"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Tillåter att ett program framtvingar omstart av andra program."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"tvinga program att avsluta"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Tillåter att ett program tvingar en aktivitet som finns i förgrunden att avsluta och gå tillbaka. Behövs inte för vanliga program."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"hämta systemets interna status"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Tillåter att ett program hämtar systemets interna status. Skadliga program kan hämta privat och skyddad information som de normalt aldrig ska behöva."</string>
+ <string name="permlab_statusBar">"inaktivera eller ändra statusfält"</string>
+ <string name="permdesc_statusBar">"Tillåter att programmet inaktiverar statusfältet eller lägger till och tar bort systemikoner."</string>
+ <string name="permlab_expandStatusBar">"expandera/komprimera statusfält"</string>
+ <string name="permdesc_expandStatusBar">"Tillåter att program expanderar eller komprimerar statusfältet."</string>
+ <string name="permlab_processOutgoingCalls">"spärra utgående samtal"</string>
+ <string name="permdesc_processOutgoingCalls">"Tillåter att program hanterar utgående samtal och ändrar numret som ska ringas upp. Skadliga program kan övervaka, omdirigera eller förhindra utgående samtal."</string>
+ <string name="permlab_receiveSms">"ta emot SMS"</string>
+ <string name="permdesc_receiveSms">"Tillåter att program tar emot och bearbetar SMS-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem utan att visa dem för dig."</string>
+ <string name="permlab_receiveMms">"ta emot MMS"</string>
+ <string name="permdesc_receiveMms">"Tillåter att program tar emot och bearbetar MMS-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem innan du har sett dem."</string>
+ <string name="permlab_sendSms">"skicka SMS"</string>
+ <string name="permdesc_sendSms">"Tillåter att programmet skickar SMS-meddelanden. Skadliga program kan skicka meddelanden utan ditt godkännande vilket kan kosta pengar."</string>
+ <string name="permlab_readSms">"läsa SMS eller MMS"</string>
+ <string name="permdesc_readSms">"Tillåter att program läser SMS-meddelanden som sparats på din telefon eller SIM-kort. Skadliga program kan läsa dina konfidentiella meddelanden."</string>
+ <string name="permlab_writeSms">"redigera SMS eller MMS"</string>
+ <string name="permdesc_writeSms">"Tillåter att program skriver till SMS-meddelanden som lagrats på din telefon eller SIM-kort. Skadliga program kan radera dina meddelanden."</string>
+ <string name="permlab_receiveWapPush">"ta emot WAP"</string>
+ <string name="permdesc_receiveWapPush">"Tillåter att program tar emot och bearbetar WAP-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem utan att visa dem för dig."</string>
+ <string name="permlab_getTasks">"hämta program som körs"</string>
+ <string name="permdesc_getTasks">"Tillåter att program hämtar information om uppgifter som körs och har körts. Skadliga program kan upptäcka privat information om andra program."</string>
+ <string name="permlab_reorderTasks">"byt ordning på program som körs"</string>
+ <string name="permdesc_reorderTasks">"Tillåter att ett program flyttar uppgifter till förgrunden eller bakgrunden. Skadliga program kan tvinga sig till förgrunden utan att du kan styra det."</string>
+ <string name="permlab_setDebugApp">"aktivera felsökning av program"</string>
+ <string name="permdesc_setDebugApp">"Tillåter att ett program aktiverar felsökning för ett annat program. Skadliga program kan använda detta för att avsluta andra program."</string>
+ <string name="permlab_changeConfiguration">"ändra dina gränssnittsinställningar"</string>
+ <string name="permdesc_changeConfiguration">"Tillåter att ett program ändrar den aktuella konfigurationen, till exempel språk eller övergripande teckenformat."</string>
+ <string name="permlab_restartPackages">"starta om andra program"</string>
+ <string name="permdesc_restartPackages">"Tillåter att ett program framtvingar omstart av andra program."</string>
+ <string name="permlab_forceBack">"tvinga program att avsluta"</string>
+ <string name="permdesc_forceBack">"Tillåter att ett program tvingar en aktivitet som finns i förgrunden att avsluta och gå tillbaka. Behövs inte för vanliga program."</string>
+ <string name="permlab_dump">"hämta systemets interna status"</string>
+ <string name="permdesc_dump">"Tillåter att ett program hämtar systemets interna status. Skadliga program kan hämta privat och skyddad information som de normalt aldrig ska behöva."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"övervaka och styra alla program som öppnas"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Tillåter att ett program övervakar och styr hur systemet startar aktiviteter. Skadliga program kan bryta systemet helt. Den här behörigheten behövs bara för programmering, aldrig för vanlig telefonanvändning."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"skicka meddelande om borttaget paket"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Tillåter att ett program skickar ett meddelande om att ett programpaket har tagits bort. Skadliga program kan använda detta för att avsluta alla andra program som körs."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"skicka SMS-mottagen sändning"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Tillåter att ett program sänder ut en avisering när SMS tas emot. Skadliga program kan använda detta för att förfalska inkommande SMS-meddelanden."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"skicka WAP-PUSH-mottagen sändning"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Tillåter att ett program skickar ut en avisering när ett WAP PUSH-meddelande tas emot. Skadliga program kan använda detta för att förfalska mottagning av MMS eller för att obemärkt byta ut innehållet på en webbsida mot skadligt innehåll."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"begränsa antalet processer som körs"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Tillåter att ett program styr högsta antalet processer som körs. Behövs inte för vanliga program."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"gör så att alla bakgrundsprogram stängs"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Tillåter att ett program bestämmer om aktiviteter alltid är slutförda när de hamnar i bakgrunden. Ska inte behövas för vanliga program."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"ändra batteristatistik"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Tillåter att samlad batteristatistik ändras. Används inte av vanliga program."</string>
+ <string name="permlab_runSetActivityWatcher">"övervaka och styra alla program som öppnas"</string>
+ <string name="permdesc_runSetActivityWatcher">"Tillåter att ett program övervakar och styr hur systemet startar aktiviteter. Skadliga program kan bryta systemet helt. Den här behörigheten behövs bara för programmering, aldrig för vanlig telefonanvändning."</string>
+ <string name="permlab_broadcastPackageRemoved">"skicka meddelande om borttaget paket"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Tillåter att ett program skickar ett meddelande om att ett programpaket har tagits bort. Skadliga program kan använda detta för att avsluta alla andra program som körs."</string>
+ <string name="permlab_broadcastSmsReceived">"skicka SMS-mottagen sändning"</string>
+ <string name="permdesc_broadcastSmsReceived">"Tillåter att ett program sänder ut en avisering när SMS tas emot. Skadliga program kan använda detta för att förfalska inkommande SMS-meddelanden."</string>
+ <string name="permlab_broadcastWapPush">"skicka WAP-PUSH-mottagen sändning"</string>
+ <string name="permdesc_broadcastWapPush">"Tillåter att ett program skickar ut en avisering när ett WAP PUSH-meddelande tas emot. Skadliga program kan använda detta för att förfalska mottagning av MMS eller för att obemärkt byta ut innehållet på en webbsida mot skadligt innehåll."</string>
+ <string name="permlab_setProcessLimit">"begränsa antalet processer som körs"</string>
+ <string name="permdesc_setProcessLimit">"Tillåter att ett program styr högsta antalet processer som körs. Behövs inte för vanliga program."</string>
+ <string name="permlab_setAlwaysFinish">"gör så att alla bakgrundsprogram stängs"</string>
+ <string name="permdesc_setAlwaysFinish">"Tillåter att ett program bestämmer om aktiviteter alltid är slutförda när de hamnar i bakgrunden. Ska inte behövas för vanliga program."</string>
+ <string name="permlab_batteryStats">"ändra batteristatistik"</string>
+ <string name="permdesc_batteryStats">"Tillåter att samlad batteristatistik ändras. Används inte av vanliga program."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"visa otillåtna fönster"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Tillåter att fönster skapas och används av det interna systemgränssnittet. Används inte av vanliga program."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"visa varningar på systemnivå"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Tillåter att ett program visar fönster med systemvarningar. Skadliga program kan överta hela telefonens skärm."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"ändra global animeringshastighet"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Tillåter att ett program när som helst ändrar den globala animeringshastigheten (snabbare eller långsammare)."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"hantera programtoken"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Tillåter att program skapar och hanterar egna token och förbigår normala Z-beställningar. Behövs inte för vanliga program."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"trycka på knappar och styrknappar"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Tillåter att ett program levererar egna inmatningshändelser (knapptryckningar, osv.) till andra program. Skadliga program använder detta för att kapa telefonen."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"registrera vad du skriver och vilka åtgärder du vidtar"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Tillåter att program övervakar knapparna som du trycker på, till och med när du använder andra program (till exempel när du anger ett lösenord). Ska inte behövas för vanliga program."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"binda till en metod för indata"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en inmatningsmetod. Ska inte behövas för vanliga program."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"ändra bildskärmens rikting"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Tillåter att ett program när som helst ändrar skärmens rotering. Behövs inte för vanliga program."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"skicka Linux-signaler till program"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Tillåter att programmet begär att den angivna signalen skickas till alla beständiga processer."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"se till att programmet alltid körs"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Tillåter att ett program gör vissa delar beständiga så att systemet inte kan använda det för andra program."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"ta bort program"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Tillåter att ett program tar bort Android-paket. Skadliga program kan använda detta för att ta bort viktiga program."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"ta bort de andra programmens uppgifter"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Tillåter att ett program tar bort användardata."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"ta bort de andra programmens cacheminnen"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Tillåter att ett program raderar cachefiler."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"mäta telefonens lagringsutrymme"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Tillåter att ett program hämtar kod, data och cachestorlekar"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"installera program direkt"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Tillåter att ett program installerar nya eller uppdaterade Android-paket. Skadliga program kan använda detta för att lägga till nya program med godtyckliga och starka behörigheter."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"ta bort cacheinformation för alla program"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Tillåter att ett program frigör lagringsutrymme i telefonen genom att ta bort filer i programmets katalog för cachelagring. Åtkomst är mycket begränsad, vanligtvis till systemprocesser."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"läsa systemets loggfiler"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Tillåter att ett program läser från systemets olika loggfiler. Det innebär att programmet kan upptäcka allmän information om vad du gör med telefonen, men den bör inte innehålla personlig eller privat information."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Tillåter att ett program läser och skriver till en resurs som ägs av diag-gruppen; till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST används av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"aktivera eller inaktivera programkomponenter"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Tillåter att ett program ändrar inställningen för om en komponent i ett annat program har aktiverats eller inte. Skadliga program kan använda detta för att inaktivera viktiga telefonfunktioner. Var försiktig med behörigheten, eftersom programkomponenter kan bli oanvändbara, inkonsekventa eller ostabila."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"ange önskade program"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Tillåter att ett program ändrar dina önskade program. Skadliga program kan utan varning ändra de program som körs och förfalska dina befintliga program så att de samlar privata data från dig."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"ändra globala systeminställningar"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Tillåter att ett program ändrar systemets inställningar. Skadliga program kan skada systemets konfiguration."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"ändra skyddade systeminställningar"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Tillåter att ett program ändrar systemets data för skyddade inställningar. Används inte av vanliga program."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"ändra kartan för Googles tjänster"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Tillåter att ett program ändrar kartan för Google-tjänster. Används inte av vanliga program."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"starta automatiskt vid systemstart"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Tillåter att ett program startar när systemet har startats om. Detta kan innebära att det tar längre tid att starta om telefonen och att telefonen blir långsammare i och med att programmet hela tiden körs i bakgrunden."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"Skicka sticky broadcast"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Tillåter att ett program skickar sticky broadcasts, som finns kvar när sändningen är slut. Skadliga program kan göra telefonen seg eller instabil genom att se till att den använder för mycket minne."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"läsa kontaktinformation"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Tillåter att ett program läser alla kontaktuppgifter (adresser) som har lagrats på din telefon. Skadliga program kan använda detta för att skicka dina data till andra personer."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"skriva kontaktuppgifter"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Tillåter att ett program ändrar kontaktuppgifter (adress) som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra kontaktuppgifter."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"skriva ägarinformation"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Tillåter att ett program ändrar information om telefonens ägare som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra ägaruppgifter."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"läsa information om ägare"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Tillåter att ett program läser information om telefonens ägare som har lagrats på telefonen. Skadliga program kan använda detta för att läsa telefonens ägaruppgifter."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"läsa kalenderinformation"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Tillåter att ett program läser alla händelser i kalendern som har lagrats på din telefon. Skadliga program kan använda detta för att skicka din kalender till andra personer."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"skriva kalenderdata"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Tillåter att ett program ändrar kalenderuppgifterna som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra kalenderuppgifter."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"skenplatser för att testa"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Skapa skenplatser för att testa. Skadliga program kan använda detta för att åsidosätta platsen och/eller statusen som returneras av riktiga platser, till exempel GPS- eller nätverksleverantörer."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"få åtkomst till extra kommandon för platsleverantör"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Få åtkomst till extra kommandon för platsleverantörer. Skadliga program kan använda detta för att störa hur GPS eller andra platskällor fungerar."</string>
+ <string name="permlab_internalSystemWindow">"visa otillåtna fönster"</string>
+ <string name="permdesc_internalSystemWindow">"Tillåter att fönster skapas och används av det interna systemgränssnittet. Används inte av vanliga program."</string>
+ <string name="permlab_systemAlertWindow">"visa varningar på systemnivå"</string>
+ <string name="permdesc_systemAlertWindow">"Tillåter att ett program visar fönster med systemvarningar. Skadliga program kan överta hela telefonens skärm."</string>
+ <string name="permlab_setAnimationScale">"ändra global animeringshastighet"</string>
+ <string name="permdesc_setAnimationScale">"Tillåter att ett program när som helst ändrar den globala animeringshastigheten (snabbare eller långsammare)."</string>
+ <string name="permlab_manageAppTokens">"hantera programtoken"</string>
+ <string name="permdesc_manageAppTokens">"Tillåter att program skapar och hanterar egna token och förbigår normala Z-beställningar. Behövs inte för vanliga program."</string>
+ <string name="permlab_injectEvents">"trycka på knappar och styrknappar"</string>
+ <string name="permdesc_injectEvents">"Tillåter att ett program levererar egna inmatningshändelser (knapptryckningar, osv.) till andra program. Skadliga program använder detta för att kapa telefonen."</string>
+ <string name="permlab_readInputState">"registrera vad du skriver och vilka åtgärder du vidtar"</string>
+ <string name="permdesc_readInputState">"Tillåter att program övervakar knapparna som du trycker på, till och med när du använder andra program (till exempel när du anger ett lösenord). Ska inte behövas för vanliga program."</string>
+ <string name="permlab_bindInputMethod">"binda till en metod för indata"</string>
+ <string name="permdesc_bindInputMethod">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en inmatningsmetod. Ska inte behövas för vanliga program."</string>
+ <string name="permlab_setOrientation">"ändra bildskärmens rikting"</string>
+ <string name="permdesc_setOrientation">"Tillåter att ett program när som helst ändrar skärmens rotering. Behövs inte för vanliga program."</string>
+ <string name="permlab_signalPersistentProcesses">"skicka Linux-signaler till program"</string>
+ <string name="permdesc_signalPersistentProcesses">"Tillåter att programmet begär att den angivna signalen skickas till alla beständiga processer."</string>
+ <string name="permlab_persistentActivity">"se till att programmet alltid körs"</string>
+ <string name="permdesc_persistentActivity">"Tillåter att ett program gör vissa delar beständiga så att systemet inte kan använda det för andra program."</string>
+ <string name="permlab_deletePackages">"ta bort program"</string>
+ <string name="permdesc_deletePackages">"Tillåter att ett program tar bort Android-paket. Skadliga program kan använda detta för att ta bort viktiga program."</string>
+ <string name="permlab_clearAppUserData">"ta bort de andra programmens uppgifter"</string>
+ <string name="permdesc_clearAppUserData">"Tillåter att ett program tar bort användardata."</string>
+ <string name="permlab_deleteCacheFiles">"ta bort de andra programmens cacheminnen"</string>
+ <string name="permdesc_deleteCacheFiles">"Tillåter att ett program raderar cachefiler."</string>
+ <string name="permlab_getPackageSize">"mäta telefonens lagringsutrymme"</string>
+ <string name="permdesc_getPackageSize">"Tillåter att ett program hämtar kod, data och cachestorlekar"</string>
+ <string name="permlab_installPackages">"installera program direkt"</string>
+ <string name="permdesc_installPackages">"Tillåter att ett program installerar nya eller uppdaterade Android-paket. Skadliga program kan använda detta för att lägga till nya program med godtyckliga och starka behörigheter."</string>
+ <string name="permlab_clearAppCache">"ta bort cacheinformation för alla program"</string>
+ <string name="permdesc_clearAppCache">"Tillåter att ett program frigör lagringsutrymme i telefonen genom att ta bort filer i programmets katalog för cachelagring. Åtkomst är mycket begränsad, vanligtvis till systemprocesser."</string>
+ <string name="permlab_readLogs">"läsa systemets loggfiler"</string>
+ <string name="permdesc_readLogs">"Tillåter att ett program läser från systemets olika loggfiler. Det innebär att programmet kan upptäcka allmän information om vad du gör med telefonen, men den bör inte innehålla personlig eller privat information."</string>
+ <string name="permlab_diagnostic">"läsa/skriva till resurser som ägs av diag"</string>
+ <string name="permdesc_diagnostic">"Tillåter att ett program läser och skriver till en resurs som ägs av diag-gruppen; till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST används av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
+ <string name="permlab_changeComponentState">"aktivera eller inaktivera programkomponenter"</string>
+ <string name="permdesc_changeComponentState">"Tillåter att ett program ändrar inställningen för om en komponent i ett annat program har aktiverats eller inte. Skadliga program kan använda detta för att inaktivera viktiga telefonfunktioner. Var försiktig med behörigheten, eftersom programkomponenter kan bli oanvändbara, inkonsekventa eller ostabila."</string>
+ <string name="permlab_setPreferredApplications">"ange önskade program"</string>
+ <string name="permdesc_setPreferredApplications">"Tillåter att ett program ändrar dina önskade program. Skadliga program kan utan varning ändra de program som körs och förfalska dina befintliga program så att de samlar privata data från dig."</string>
+ <string name="permlab_writeSettings">"ändra globala systeminställningar"</string>
+ <string name="permdesc_writeSettings">"Tillåter att ett program ändrar systemets inställningar. Skadliga program kan skada systemets konfiguration."</string>
+ <string name="permlab_writeSecureSettings">"ändra skyddade systeminställningar"</string>
+ <string name="permdesc_writeSecureSettings">"Tillåter att ett program ändrar systemets data för skyddade inställningar. Används inte av vanliga program."</string>
+ <string name="permlab_writeGservices">"ändra kartan för Googles tjänster"</string>
+ <string name="permdesc_writeGservices">"Tillåter att ett program ändrar kartan för Google-tjänster. Används inte av vanliga program."</string>
+ <string name="permlab_receiveBootCompleted">"starta automatiskt vid systemstart"</string>
+ <string name="permdesc_receiveBootCompleted">"Tillåter att ett program startar när systemet har startats om. Detta kan innebära att det tar längre tid att starta om telefonen och att telefonen blir långsammare i och med att programmet hela tiden körs i bakgrunden."</string>
+ <string name="permlab_broadcastSticky">"Skicka sticky broadcast"</string>
+ <string name="permdesc_broadcastSticky">"Tillåter att ett program skickar sticky broadcasts, som finns kvar när sändningen är slut. Skadliga program kan göra telefonen seg eller instabil genom att se till att den använder för mycket minne."</string>
+ <string name="permlab_readContacts">"läsa kontaktinformation"</string>
+ <string name="permdesc_readContacts">"Tillåter att ett program läser alla kontaktuppgifter (adresser) som har lagrats på din telefon. Skadliga program kan använda detta för att skicka dina data till andra personer."</string>
+ <string name="permlab_writeContacts">"skriva kontaktuppgifter"</string>
+ <string name="permdesc_writeContacts">"Tillåter att ett program ändrar kontaktuppgifter (adress) som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra kontaktuppgifter."</string>
+ <string name="permlab_writeOwnerData">"skriva ägarinformation"</string>
+ <string name="permdesc_writeOwnerData">"Tillåter att ett program ändrar information om telefonens ägare som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra ägaruppgifter."</string>
+ <string name="permlab_readOwnerData">"läsa information om ägare"</string>
+ <string name="permdesc_readOwnerData">"Tillåter att ett program läser information om telefonens ägare som har lagrats på telefonen. Skadliga program kan använda detta för att läsa telefonens ägaruppgifter."</string>
+ <string name="permlab_readCalendar">"läsa kalenderinformation"</string>
+ <string name="permdesc_readCalendar">"Tillåter att ett program läser alla händelser i kalendern som har lagrats på din telefon. Skadliga program kan använda detta för att skicka din kalender till andra personer."</string>
+ <string name="permlab_writeCalendar">"skriva kalenderdata"</string>
+ <string name="permdesc_writeCalendar">"Tillåter att ett program ändrar kalenderuppgifterna som har lagrats på din telefon. Skadliga program kan använda detta för att radera eller ändra kalenderuppgifter."</string>
+ <string name="permlab_accessMockLocation">"skenplatser för att testa"</string>
+ <string name="permdesc_accessMockLocation">"Skapa skenplatser för att testa. Skadliga program kan använda detta för att åsidosätta platsen och/eller statusen som returneras av riktiga platser, till exempel GPS- eller nätverksleverantörer."</string>
+ <string name="permlab_accessLocationExtraCommands">"få åtkomst till extra kommandon för platsleverantör"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Få åtkomst till extra kommandon för platsleverantörer. Skadliga program kan använda detta för att störa hur GPS eller andra platskällor fungerar."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"hitta plats (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Få åtkomst till detaljerade platskällor som Global Positioning System på telefonen, om det är tillgängligt. Skadliga program kan använda detta för att identifiera var du befinner dig, vilket drar mycket batteri."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"grov (nätverksbaserad) plats"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Få åtkomst till grova platser, till exempel mobilnätverkets databas, för att bestämma ungefärlig plats för en telefon. Skadliga program kan använda detta för att avgöra ungefär var du befinner dig."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"få åtkomst till SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Tillåter att program använder lågnivåfunktioner i SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"läsa rambuffert"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Tillåter att program använder innehållet i rambufferten."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ändra dina ljudinställningar"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Tillåter att ett program ändrar globala ljudinställningar, till exempel volym och routning."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"spela in ljud"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Tillåter att program får åtkomst till sökvägen för ljudinspelning."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"ta bilder"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Tillåter att program tar kort med kameran. Då kan programmet när som helst samla bilderna som visas i kameran."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"inaktivera telefonen permanent"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Tillåter att programmet inaktiverar hela telefonen permanent. Detta är mycket farligt."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"tvinga omstart av telefon"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Tillåter att ett program tvingar telefonen att starta om."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montering och demontering av filsystem"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Tillåter att programmet monterar och demonterar filsystem för flyttbara lagringsmedia."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formatera extern lagring"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Tillåter att programmet formaterar flyttbara lagringsmedia."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"kontrollera vibration"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Tillåter att programmet styr vibratorn."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"styra lampa"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Tillåter att programmet styr lampan."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"testa maskinvara"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Tillåter att ett program styr kringutrustning i syfte att testa maskinvara."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"ringa telefonnummer direkt"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Tillåter att programmet ringer telefonnummer utan åtgärd från dig. Skadliga program kan orsaka oväntade samtal på din telefonräkning. Observera att programmet inte tillåts att ringa nödsamtal."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"ringa telefonnummer direkt"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Tillåter att programmet ringer ett telefonnummer, inklusive nödnummer, utan att du behöver göra något. Skadliga program kan ringa onödiga och olagliga samtal till räddningtjänsten."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"styra meddelanden för platsuppdatering"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Tillåter aktivering och inaktivering av avisering om platsuppdatering i radion. Används inte av vanliga program."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"få åtkomst till incheckningsegenskaper"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Tillåter läs/skrivåtkomst till egenskaper som läggs upp via incheckningstjänsten. Används inte av vanliga program."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"välja widgetar"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Tillåter att programmet instruerar systemet vilka widgetar som kan användas av vilket program. Med den här behörigheten kan åtkomst till personliga data beviljas andra program. Används inte av vanliga program."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"ändra telefonstatus"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Tillåter att programmet styr enhetens telefonfunktioner. Ett program med denna behörighet kan växla nätverk, aktivera och inaktivera telefonens radio och så vidare utan att ens meddela dig."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"förhindra att telefonen sätts i viloläge"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Tillåter att ett program förhindrar att telefonen går in i viloläge."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"sätta på eller stänga av telefonen"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Tillåter att ett program sätter på eller stänger av telefonen."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"kör i fabrikstestläge"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Köra som ett testläge för tillverkaren på låg nivå. På så sätt får du fullständig åtkomst till telefonens maskinvara. Är endast tillgänglig när telefonen körs i tillverkarens testläge."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"ange bakgrund"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Tillåter att programmet anger systemets bakgrund."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"ange tips för bakgrundsstorlek"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Tillåter att programmet ger tips om systemets bakgrundsstorlek."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"återställa systemets fabriksinställningar"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Tillåter att ett program helt återställer systemets fabriksinställningar. Alla data, inställningar och installerade program raderas."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"ange tidszon"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Tillåter att ett program ändrar telefonens tidszon."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"upptäcka kända konton"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Tillåter att ett program hämtar en lista över konton som telefonen känner till."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"visa nätverksstatus"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Tillåter att ett program ser status för alla nätverk."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"fullständig Internetåtkomst"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Tillåter att ett program skapar nätverksuttag."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"skriva inställningar för åtkomstpunktens namn"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Tillåter att ett program ändrar APN-inställningarna, till exempel Proxy och Port för alla APN."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"ändra nätverksanslutning"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Tillåter att ett program ändrar statusens nätverksanslutning."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"ändra inställningar för användning av bakgrundsdata"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Tillåter att ett program ändrar inställningen för användning av bakgrundsdata."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"visa Wi-Fi-status"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Tillåter att ett program visar information om statusen för Wi-Fi."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"byta Wi-Fi-status"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Tillåter att ett program ansluter till och kopplar från Wi-Fi-åtkomstpunkter och gör ändringar i konfigurerade Wi-Fi-nätverk."</string>
+ <string name="permlab_accessFineLocation">"hitta plats (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"Få åtkomst till detaljerade platskällor som Global Positioning System på telefonen, om det är tillgängligt. Skadliga program kan använda detta för att identifiera var du befinner dig, vilket drar mycket batteri."</string>
+ <string name="permlab_accessCoarseLocation">"grov (nätverksbaserad) plats"</string>
+ <string name="permdesc_accessCoarseLocation">"Få åtkomst till grova platser, till exempel mobilnätverkets databas, för att bestämma ungefärlig plats för en telefon. Skadliga program kan använda detta för att avgöra ungefär var du befinner dig."</string>
+ <string name="permlab_accessSurfaceFlinger">"få åtkomst till SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Tillåter att program använder lågnivåfunktioner i SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"läsa rambuffert"</string>
+ <string name="permdesc_readFrameBuffer">"Tillåter att program använder innehållet i rambufferten."</string>
+ <string name="permlab_modifyAudioSettings">"ändra dina ljudinställningar"</string>
+ <string name="permdesc_modifyAudioSettings">"Tillåter att ett program ändrar globala ljudinställningar, till exempel volym och routning."</string>
+ <string name="permlab_recordAudio">"spela in ljud"</string>
+ <string name="permdesc_recordAudio">"Tillåter att program får åtkomst till sökvägen för ljudinspelning."</string>
+ <string name="permlab_camera">"ta bilder"</string>
+ <string name="permdesc_camera">"Tillåter att program tar kort med kameran. Då kan programmet när som helst samla bilderna som visas i kameran."</string>
+ <string name="permlab_brick">"inaktivera telefonen permanent"</string>
+ <string name="permdesc_brick">"Tillåter att programmet inaktiverar hela telefonen permanent. Detta är mycket farligt."</string>
+ <string name="permlab_reboot">"tvinga omstart av telefon"</string>
+ <string name="permdesc_reboot">"Tillåter att ett program tvingar telefonen att starta om."</string>
+ <string name="permlab_mount_unmount_filesystems">"montering och demontering av filsystem"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Tillåter att programmet monterar och demonterar filsystem för flyttbara lagringsmedia."</string>
+ <string name="permlab_mount_format_filesystems">"formatera extern lagring"</string>
+ <string name="permdesc_mount_format_filesystems">"Tillåter att programmet formaterar flyttbara lagringsmedia."</string>
+ <string name="permlab_vibrate">"kontrollera vibration"</string>
+ <string name="permdesc_vibrate">"Tillåter att programmet styr vibratorn."</string>
+ <string name="permlab_flashlight">"styra lampa"</string>
+ <string name="permdesc_flashlight">"Tillåter att programmet styr lampan."</string>
+ <string name="permlab_hardware_test">"testa maskinvara"</string>
+ <string name="permdesc_hardware_test">"Tillåter att ett program styr kringutrustning i syfte att testa maskinvara."</string>
+ <string name="permlab_callPhone">"ringa telefonnummer direkt"</string>
+ <string name="permdesc_callPhone">"Tillåter att programmet ringer telefonnummer utan åtgärd från dig. Skadliga program kan orsaka oväntade samtal på din telefonräkning. Observera att programmet inte tillåts att ringa nödsamtal."</string>
+ <string name="permlab_callPrivileged">"ringa telefonnummer direkt"</string>
+ <string name="permdesc_callPrivileged">"Tillåter att programmet ringer ett telefonnummer, inklusive nödnummer, utan att du behöver göra något. Skadliga program kan ringa onödiga och olagliga samtal till räddningtjänsten."</string>
+ <string name="permlab_locationUpdates">"styra meddelanden för platsuppdatering"</string>
+ <string name="permdesc_locationUpdates">"Tillåter aktivering och inaktivering av avisering om platsuppdatering i radion. Används inte av vanliga program."</string>
+ <string name="permlab_checkinProperties">"få åtkomst till incheckningsegenskaper"</string>
+ <string name="permdesc_checkinProperties">"Tillåter läs/skrivåtkomst till egenskaper som läggs upp via incheckningstjänsten. Används inte av vanliga program."</string>
+ <string name="permlab_bindGadget">"välja widgetar"</string>
+ <string name="permdesc_bindGadget">"Tillåter att programmet instruerar systemet vilka widgetar som kan användas av vilket program. Med den här behörigheten kan åtkomst till personliga data beviljas andra program. Används inte av vanliga program."</string>
+ <string name="permlab_modifyPhoneState">"ändra telefonstatus"</string>
+ <string name="permdesc_modifyPhoneState">"Tillåter att programmet styr enhetens telefonfunktioner. Ett program med denna behörighet kan växla nätverk, aktivera och inaktivera telefonens radio och så vidare utan att ens meddela dig."</string>
+ <string name="permlab_readPhoneState">"läsa telefonstatus"</string>
+ <string name="permdesc_readPhoneState">"Tillåter att programmet kommer åt enhetens telefonfunktioner. Ett program som har den här behörigheten kan identifiera telefonens telefonnummer, om ett samtal pågår, numret som samtalet är kopplat till och så vidare."</string>
+ <string name="permlab_wakeLock">"förhindra att telefonen sätts i viloläge"</string>
+ <string name="permdesc_wakeLock">"Tillåter att ett program förhindrar att telefonen går in i viloläge."</string>
+ <string name="permlab_devicePower">"sätta på eller stänga av telefonen"</string>
+ <string name="permdesc_devicePower">"Tillåter att ett program sätter på eller stänger av telefonen."</string>
+ <string name="permlab_factoryTest">"kör i fabrikstestläge"</string>
+ <string name="permdesc_factoryTest">"Köra som ett testläge för tillverkaren på låg nivå. På så sätt får du fullständig åtkomst till telefonens maskinvara. Är endast tillgänglig när telefonen körs i tillverkarens testläge."</string>
+ <string name="permlab_setWallpaper">"ange bakgrund"</string>
+ <string name="permdesc_setWallpaper">"Tillåter att programmet anger systemets bakgrund."</string>
+ <string name="permlab_setWallpaperHints">"ange tips för bakgrundsstorlek"</string>
+ <string name="permdesc_setWallpaperHints">"Tillåter att programmet ger tips om systemets bakgrundsstorlek."</string>
+ <string name="permlab_masterClear">"återställa systemets fabriksinställningar"</string>
+ <string name="permdesc_masterClear">"Tillåter att ett program helt återställer systemets fabriksinställningar. Alla data, inställningar och installerade program raderas."</string>
+ <string name="permlab_setTimeZone">"ange tidszon"</string>
+ <string name="permdesc_setTimeZone">"Tillåter att ett program ändrar telefonens tidszon."</string>
+ <string name="permlab_getAccounts">"upptäcka kända konton"</string>
+ <string name="permdesc_getAccounts">"Tillåter att ett program hämtar en lista över konton som telefonen känner till."</string>
+ <string name="permlab_accessNetworkState">"visa nätverksstatus"</string>
+ <string name="permdesc_accessNetworkState">"Tillåter att ett program ser status för alla nätverk."</string>
+ <string name="permlab_createNetworkSockets">"fullständig Internetåtkomst"</string>
+ <string name="permdesc_createNetworkSockets">"Tillåter att ett program skapar nätverksuttag."</string>
+ <string name="permlab_writeApnSettings">"skriva inställningar för åtkomstpunktens namn"</string>
+ <string name="permdesc_writeApnSettings">"Tillåter att ett program ändrar APN-inställningarna, till exempel Proxy och Port för alla APN."</string>
+ <string name="permlab_changeNetworkState">"ändra nätverksanslutning"</string>
+ <string name="permdesc_changeNetworkState">"Tillåter att ett program ändrar statusens nätverksanslutning."</string>
+ <string name="permlab_changeBackgroundDataSetting">"ändra inställningar för användning av bakgrundsdata"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Tillåter att ett program ändrar inställningen för användning av bakgrundsdata."</string>
+ <string name="permlab_accessWifiState">"visa Wi-Fi-status"</string>
+ <string name="permdesc_accessWifiState">"Tillåter att ett program visar information om statusen för Wi-Fi."</string>
+ <string name="permlab_changeWifiState">"byta Wi-Fi-status"</string>
+ <string name="permdesc_changeWifiState">"Tillåter att ett program ansluter till och kopplar från Wi-Fi-åtkomstpunkter och gör ändringar i konfigurerade Wi-Fi-nätverk."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administrera bluetooth"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Tillåter att ett program konfigurerar den lokala Bluetooth-telefonen samt upptäcker och parkopplar den med fjärranslutna enheter."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"skapa Bluetooth-anslutningar"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Tillåter att ett program ser den lokala Bluetooth-telefonens konfiguration, och skapar och accepterar anslutningar med parkopplade enheter."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"inaktivera tangentlås"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Tillåter att ett program inaktiverar tangentlåset och tillhörande lösenordsskydd. Ett exempel på detta är att telefonen inaktiverar tangentlåset vid inkommande samtal och sedan aktiverar det igen när samtalet är avslutat."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"läsa synkroniseringsinställningar"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Tillåter att ett program läser synkroniseringsinställningarna, till exempel om synkronisering har aktiverats för kontakter."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"skriva synkroniseringsinställningar"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Tillåter att ett program ändrar synkroniseringsinställningarna, till exempel om synkronisering har aktiverats för kontakter."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"läsa synkroniseringsstatistik"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Tillåter att ett program läser synkroniseringsstatistiken, t.ex. historiken över synkroniseringar som har inträffat."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"läsa flöden som du prenumererar på"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Tillåter att ett program får information om aktuella synkroniserade flöden."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"skriva flöden som du prenumererar på"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Tillåter att ett program ändrar dina aktuella synkroniserade flöden. Det kan innebära att ett skadligt program kan ändra dina synkroniserade flöden."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"läsa användardefinierad ordlista"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Tillåt att ett program läser alla privata ord, namn och fraser som användaren lagrar i sin ordlista."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"skriva till användardefinierad ordlista"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Tillåter att ett program skriver in nya ord i användarordlistan."</string>
+ <string name="permlab_bluetoothAdmin">"administrera bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin">"Tillåter att ett program konfigurerar den lokala Bluetooth-telefonen samt upptäcker och parkopplar den med fjärranslutna enheter."</string>
+ <string name="permlab_bluetooth">"skapa Bluetooth-anslutningar"</string>
+ <string name="permdesc_bluetooth">"Tillåter att ett program ser den lokala Bluetooth-telefonens konfiguration, och skapar och accepterar anslutningar med parkopplade enheter."</string>
+ <string name="permlab_disableKeyguard">"inaktivera tangentlås"</string>
+ <string name="permdesc_disableKeyguard">"Tillåter att ett program inaktiverar tangentlåset och tillhörande lösenordsskydd. Ett exempel på detta är att telefonen inaktiverar tangentlåset vid inkommande samtal och sedan aktiverar det igen när samtalet är avslutat."</string>
+ <string name="permlab_readSyncSettings">"läsa synkroniseringsinställningar"</string>
+ <string name="permdesc_readSyncSettings">"Tillåter att ett program läser synkroniseringsinställningarna, till exempel om synkronisering har aktiverats för kontakter."</string>
+ <string name="permlab_writeSyncSettings">"skriva synkroniseringsinställningar"</string>
+ <string name="permdesc_writeSyncSettings">"Tillåter att ett program ändrar synkroniseringsinställningarna, till exempel om synkronisering har aktiverats för kontakter."</string>
+ <string name="permlab_readSyncStats">"läsa synkroniseringsstatistik"</string>
+ <string name="permdesc_readSyncStats">"Tillåter att ett program läser synkroniseringsstatistiken, t.ex. historiken över synkroniseringar som har inträffat."</string>
+ <string name="permlab_subscribedFeedsRead">"läsa flöden som du prenumererar på"</string>
+ <string name="permdesc_subscribedFeedsRead">"Tillåter att ett program får information om aktuella synkroniserade flöden."</string>
+ <string name="permlab_subscribedFeedsWrite">"skriva flöden som du prenumererar på"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Tillåter att ett program ändrar dina aktuella synkroniserade flöden. Det kan innebära att ett skadligt program kan ändra dina synkroniserade flöden."</string>
+ <string name="permlab_readDictionary">"läsa användardefinierad ordlista"</string>
+ <string name="permdesc_readDictionary">"Tillåt att ett program läser alla privata ord, namn och fraser som användaren lagrar i sin ordlista."</string>
+ <string name="permlab_writeDictionary">"skriva till användardefinierad ordlista"</string>
+ <string name="permdesc_writeDictionary">"Tillåter att ett program skriver in nya ord i användarordlistan."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Hem"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Arbete"</item>
- <item msgid="1103601433382158155">"Fax, arbete"</item>
- <item msgid="1735177144948329370">"Hemfax"</item>
- <item msgid="603878674477207394">"Personsökare"</item>
- <item msgid="1650824275177931637">"Övrigt"</item>
- <item msgid="9192514806975898961">"Anpassad"</item>
+ <item>"Hem"</item>
+ <item>"Mobil"</item>
+ <item>"Arbete"</item>
+ <item>"Fax, arbete"</item>
+ <item>"Hemfax"</item>
+ <item>"Personsökare"</item>
+ <item>"Övrigt"</item>
+ <item>"Anpassad"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Hem"</item>
- <item msgid="7084237356602625604">"Arbete"</item>
- <item msgid="1112044410659011023">"Övrigt"</item>
- <item msgid="2374913952870110618">"Anpassad"</item>
+ <item>"Hem"</item>
+ <item>"Arbete"</item>
+ <item>"Övrigt"</item>
+ <item>"Anpassad"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobil"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Hem"</item>
- <item msgid="5629153956045109251">"Arbete"</item>
- <item msgid="4966604264500343469">"Övrigt"</item>
- <item msgid="4932682847595299369">"Anpassad"</item>
+ <item>"Hem"</item>
+ <item>"Arbete"</item>
+ <item>"Övrigt"</item>
+ <item>"Anpassad"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Hem"</item>
- <item msgid="1359644565647383708">"Arbete"</item>
- <item msgid="7868549401053615677">"Övrigt"</item>
- <item msgid="3145118944639869809">"Anpassad"</item>
+ <item>"Hem"</item>
+ <item>"Arbete"</item>
+ <item>"Övrigt"</item>
+ <item>"Anpassad"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Arbete"</item>
- <item msgid="4378074129049520373">"Övrigt"</item>
- <item msgid="3455047468583965104">"Anpassad"</item>
+ <item>"Arbete"</item>
+ <item>"Övrigt"</item>
+ <item>"Anpassad"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Ange PIN-kod"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Fel PIN-kod!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Tryck på Meny och sedan på 0 om du vill låsa upp."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Nödsamtalsnummer"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Ingen tjänst)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Skärmen har låsts."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Tryck på Meny om du vill låsa upp eller ringa nödsamtal."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Tryck på Meny om du vill låsa upp."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Rita grafiskt lösenord för att låsa upp"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Nödsamtal"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Korrekt!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Försök igen"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Laddar (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"Ange PIN-kod"</string>
+ <string name="keyguard_password_wrong_pin_code">"Fel PIN-kod!"</string>
+ <string name="keyguard_label_text">"Tryck på Meny och sedan på 0 om du vill låsa upp."</string>
+ <string name="emergency_call_dialog_number_for_display">"Nödsamtalsnummer"</string>
+ <string name="lockscreen_carrier_default">"(Ingen tjänst)"</string>
+ <string name="lockscreen_screen_locked">"Skärmen har låsts."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Tryck på Meny om du vill låsa upp eller ringa nödsamtal."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Tryck på Meny om du vill låsa upp."</string>
+ <string name="lockscreen_pattern_instructions">"Rita grafiskt lösenord för att låsa upp"</string>
+ <string name="lockscreen_emergency_call">"Nödsamtal"</string>
+ <string name="lockscreen_pattern_correct">"Korrekt!"</string>
+ <string name="lockscreen_pattern_wrong">"Försök igen"</string>
+ <string name="lockscreen_plugged_in">"Laddar (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Anslut din laddare."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Inget SIM-kort."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Inget SIM-kort i telefonen."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Sätt i ett SIM-kort."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Nätverk låst"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-kortet är PUK-låst."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Se användarhandboken eller kontakta Kundtjänst."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-kortet är låst."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Låser upp SIM-kort…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> försök till kommer du att uppmanas att låsa upp telefonen med din Google-inloggning."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Försök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Glömt ditt grafiska lösenord?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"För många försök med grafiskt lösenord!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Logga in med ditt Google-konto om du vill låsa upp"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Användarnamn (e-post)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Lösenord"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Logga in"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ogiltigt användarnamn eller lösenord."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Anslut din laddare."</string>
+ <string name="lockscreen_missing_sim_message_short">"Inget SIM-kort."</string>
+ <string name="lockscreen_missing_sim_message">"Inget SIM-kort i telefonen."</string>
+ <string name="lockscreen_missing_sim_instructions">"Sätt i ett SIM-kort."</string>
+ <string name="lockscreen_network_locked_message">"Nätverk låst"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-kortet är PUK-låst."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Se användarhandboken eller kontakta Kundtjänst."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-kortet är låst."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Låser upp SIM-kort…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> försök till kommer du att uppmanas att låsa upp telefonen med din Google-inloggning."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Försök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Glömt ditt grafiska lösenord?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"För många försök med grafiskt lösenord!"</string>
+ <string name="lockscreen_glogin_instructions">"Logga in med ditt Google-konto om du vill låsa upp"</string>
+ <string name="lockscreen_glogin_username_hint">"Användarnamn (e-post)"</string>
+ <string name="lockscreen_glogin_password_hint">"Lösenord"</string>
+ <string name="lockscreen_glogin_submit_button">"Logga in"</string>
+ <string name="lockscreen_glogin_invalid_input">"Ogiltigt användarnamn eller lösenord."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Inga aviseringar"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Pågående"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelanden"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Laddar…"</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Anslut laddaren"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet håller på att ta slut:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"Mindre än <xliff:g id="NUMBER">%d%%</xliff:g> återstår."</string>
+ <string name="status_bar_no_notifications_title">"Inga aviseringar"</string>
+ <string name="status_bar_ongoing_events_title">"Pågående"</string>
+ <string name="status_bar_latest_events_title">"Meddelanden"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Laddar…"</string>
+ <string name="battery_low_title">"Anslut laddaren"</string>
+ <string name="battery_low_subtitle">"Batteriet håller på att ta slut:"</string>
+ <string name="battery_low_percent_format">"Mindre än <xliff:g id="NUMBER">%d%%</xliff:g> återstår."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Det gick fel vid fabrikstestet"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"Åtgärden FACTORY_TEST stöds endast för paket som har installerats i /system/app."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"Vi hittade inget paket som erbjuder åtgärden FACTORY_TEST."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Starta om"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"På sidan på <xliff:g id="TITLE">%s</xliff:g> står det:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Vill du lämna den här den här sidan?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryck på OK om du vill fortsätta eller på Avbryt om du vill vara kvar på den aktuella sidan."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Bekräfta"</string>
+ <string name="factorytest_failed">"Det gick fel vid fabrikstestet"</string>
+ <string name="factorytest_not_system">"Åtgärden FACTORY_TEST stöds endast för paket som har installerats i /system/app."</string>
+ <string name="factorytest_no_action">"Vi hittade inget paket som erbjuder åtgärden FACTORY_TEST."</string>
+ <string name="factorytest_reboot">"Starta om"</string>
+ <string name="js_dialog_title">"På sidan på <xliff:g id="TITLE">%s</xliff:g> står det:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Vill du lämna den här den här sidan?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryck på OK om du vill fortsätta eller på Avbryt om du vill vara kvar på den aktuella sidan."</string>
+ <string name="save_password_label">"Bekräfta"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Vill du att webbläsaren ska komma ihåg lösenordet?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Inte nu"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Kom ihåg"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Aldrig"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Du har inte behörighet att öppna den här sidan."</string>
- <string name="text_copied" msgid="4985729524670131385">"Text har kopierats till urklipp."</string>
- <string name="more_item_label" msgid="4650918923083320495">"Mer"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Meny+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"utrymme"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"retur"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"ta bort"</string>
- <string name="search_go" msgid="8298016669822141719">"Sök"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"för 1 månad sedan"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"För mer än en månad sedan"</string>
+ <string name="save_password_message">"Vill du att webbläsaren ska komma ihåg lösenordet?"</string>
+ <string name="save_password_notnow">"Inte nu"</string>
+ <string name="save_password_remember">"Kom ihåg"</string>
+ <string name="save_password_never">"Aldrig"</string>
+ <string name="open_permission_deny">"Du har inte behörighet att öppna den här sidan."</string>
+ <string name="text_copied">"Text har kopierats till urklipp."</string>
+ <string name="more_item_label">"Mer"</string>
+ <string name="prepend_shortcut_label">"Meny+"</string>
+ <string name="menu_space_shortcut_label">"utrymme"</string>
+ <string name="menu_enter_shortcut_label">"retur"</string>
+ <string name="menu_delete_shortcut_label">"ta bort"</string>
+ <string name="search_go">"Sök"</string>
+ <string name="oneMonthDurationPast">"för 1 månad sedan"</string>
+ <string name="beforeOneMonthDurationPast">"För mer än en månad sedan"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"för 1 sekund sedan"</item>
- <item quantity="other" msgid="3903706804349556379">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
+ <item quantity="one">"för 1 sekund sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"för 1 minut sedan"</item>
- <item quantity="other" msgid="2176942008915455116">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
+ <item quantity="one">"för 1 minut sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"för 1 timme sedan"</item>
- <item quantity="other" msgid="2467273239587587569">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
+ <item quantity="one">"för 1 timme sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"igår"</item>
- <item quantity="other" msgid="2479586466153314633">"för <xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
+ <item quantity="one">"igår"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"om 1 sekund"</item>
- <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ <item quantity="one">"om 1 sekund"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"om 1 minut"</item>
- <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
+ <item quantity="one">"om 1 minut"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"om 1 timme"</item>
- <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
+ <item quantity="one">"om 1 timme"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"imorgon"</item>
- <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
+ <item quantity="one">"imorgon"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"för 1 sek sedan"</item>
- <item quantity="other" msgid="3699169366650930415">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
+ <item quantity="one">"för 1 sek sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"för 1 minut sedan"</item>
- <item quantity="other" msgid="851164968597150710">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
+ <item quantity="one">"för 1 minut sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"för 1 timme sedan"</item>
- <item quantity="other" msgid="6889970745748538901">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
+ <item quantity="one">"för 1 timme sedan"</item>
+ <item quantity="other">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"igår"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
+ <item quantity="one">"igår"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"om 1 sekund"</item>
- <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
+ <item quantity="one">"om 1 sekund"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"om 1 minut"</item>
- <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
+ <item quantity="one">"om 1 minut"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"om 1 timme"</item>
- <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
+ <item quantity="one">"om 1 timme"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"imorgon"</item>
- <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
+ <item quantity="one">"imorgon"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"den %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"vid %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s"</string>
- <string name="day" msgid="8144195776058119424">"dag"</string>
- <string name="days" msgid="4774547661021344602">"dagar"</string>
- <string name="hour" msgid="2126771916426189481">"timme"</string>
- <string name="hours" msgid="894424005266852993">"timmar"</string>
- <string name="minute" msgid="9148878657703769868">"minut"</string>
- <string name="minutes" msgid="5646001005827034509">"minuter"</string>
- <string name="second" msgid="3184235808021478">"sekunder"</string>
- <string name="seconds" msgid="3161515347216589235">"sekunder"</string>
- <string name="week" msgid="5617961537173061583">"vecka"</string>
- <string name="weeks" msgid="6509623834583944518">"veckor"</string>
- <string name="year" msgid="4001118221013892076">"Ã¥r"</string>
- <string name="years" msgid="6881577717993213522">"Ã¥r"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Alla vardagar (mån–fre)"</string>
- <string name="daily" msgid="5738949095624133403">"Varje dag"</string>
- <string name="weekly" msgid="983428358394268344">"Varje vecka på <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"Varje månad"</string>
- <string name="yearly" msgid="1519577999407493836">"Varje år"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Det går inte att spela upp videon"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Videon kan tyvärr inte spelas upp i den här enheten."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Det går tyvärr inte att spela upp den här videon."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"eftermiddag"</string>
- <string name="Noon" msgid="3342127745230013127">"Mitt på dagen"</string>
- <string name="midnight" msgid="7166259508850457595">"midnatt"</string>
- <string name="Midnight" msgid="5630806906897892201">"Midnatt"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Välj alla"</string>
- <string name="selectText" msgid="3889149123626888637">"Markera text"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Sluta välja text"</string>
- <string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
- <string name="cutAll" msgid="2436383270024931639">"Klipp ut alla"</string>
- <string name="copy" msgid="2681946229533511987">"Kopiera"</string>
- <string name="copyAll" msgid="2590829068100113057">"Kopiera alla"</string>
- <string name="paste" msgid="5629880836805036433">"Klistra in"</string>
- <string name="copyUrl" msgid="2538211579596067402">"Kopiera webbadress"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Indatametod"</string>
- <string name="addToDictionary" msgid="726256909274177272">"Lägg till %s i ordlistan"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Redigera text"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"DÃ¥ligt med utrymme"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Telefonens lagringsutrymme håller på att ta slut."</string>
- <string name="ok" msgid="5970060430562524910">"OK"</string>
- <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
- <string name="yes" msgid="5362982303337969312">"OK"</string>
- <string name="no" msgid="5141531044935541497">"Avbryt"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Obs!"</string>
- <string name="capital_on" msgid="1544682755514494298">"PÃ…"</string>
- <string name="capital_off" msgid="6815870386972805832">"AV"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Slutför åtgärd genom att använda"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Använd som standard för denna åtgärd."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Rensa standardinställning i Startinställningar &gt; Program &gt; Hantera program."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Välj en åtgärd"</string>
- <string name="noApplications" msgid="1691104391758345586">"Inga program kan utföra den här åtgärden."</string>
- <string name="aerr_title" msgid="653922989522758100">"Tyvärr!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"Processen <xliff:g id="PROCESS">%2$s</xliff:g> för programmet <xliff:g id="APPLICATION">%1$s</xliff:g> stoppades oväntat. Försök igen."</string>
- <string name="aerr_process" msgid="1551785535966089511">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> avslutades oväntat. Försök igen."</string>
- <string name="anr_title" msgid="3100070910664756057">"Tyvärr!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> (i programmet <xliff:g id="APPLICATION">%2$s</xliff:g>) svarar inte."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
- <string name="anr_process" msgid="1246866008169975783">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarar inte."</string>
- <string name="force_close" msgid="3653416315450806396">"Tvinga fram en stängning"</string>
+ <string name="preposition_for_date">"den %s"</string>
+ <string name="preposition_for_time">"vid %s"</string>
+ <string name="preposition_for_year">"%s"</string>
+ <string name="day">"dag"</string>
+ <string name="days">"dagar"</string>
+ <string name="hour">"timme"</string>
+ <string name="hours">"timmar"</string>
+ <string name="minute">"minut"</string>
+ <string name="minutes">"minuter"</string>
+ <string name="second">"sekunder"</string>
+ <string name="seconds">"sekunder"</string>
+ <string name="week">"vecka"</string>
+ <string name="weeks">"veckor"</string>
+ <string name="year">"Ã¥r"</string>
+ <string name="years">"Ã¥r"</string>
+ <string name="every_weekday">"Alla vardagar (mån–fre)"</string>
+ <string name="daily">"Varje dag"</string>
+ <string name="weekly">"Varje vecka på <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"Varje månad"</string>
+ <string name="yearly">"Varje år"</string>
+ <string name="VideoView_error_title">"Det går inte att spela upp videon"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Videon kan tyvärr inte spelas upp i den här enheten."</string>
+ <string name="VideoView_error_text_unknown">"Det går tyvärr inte att spela upp den här videon."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"eftermiddag"</string>
+ <string name="Noon">"Mitt på dagen"</string>
+ <string name="midnight">"midnatt"</string>
+ <string name="Midnight">"Midnatt"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Välj alla"</string>
+ <string name="selectText">"Markera text"</string>
+ <string name="stopSelectingText">"Sluta välja text"</string>
+ <string name="cut">"Klipp ut"</string>
+ <string name="cutAll">"Klipp ut alla"</string>
+ <string name="copy">"Kopiera"</string>
+ <string name="copyAll">"Kopiera alla"</string>
+ <string name="paste">"Klistra in"</string>
+ <string name="copyUrl">"Kopiera webbadress"</string>
+ <string name="inputMethod">"Indatametod"</string>
+ <string name="addToDictionary">"Lägg till %s i ordlistan"</string>
+ <string name="editTextMenuTitle">"Redigera text"</string>
+ <string name="low_internal_storage_view_title">"DÃ¥ligt med utrymme"</string>
+ <string name="low_internal_storage_view_text">"Telefonens lagringsutrymme håller på att ta slut."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Avbryt"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Avbryt"</string>
+ <string name="dialog_alert_title">"Obs!"</string>
+ <string name="capital_on">"PÃ…"</string>
+ <string name="capital_off">"AV"</string>
+ <string name="whichApplication">"Slutför åtgärd genom att använda"</string>
+ <string name="alwaysUse">"Använd som standard för denna åtgärd."</string>
+ <string name="clearDefaultHintMsg">"Rensa standardinställning i Startinställningar &gt; Program &gt; Hantera program."</string>
+ <string name="chooseActivity">"Välj en åtgärd"</string>
+ <string name="noApplications">"Inga program kan utföra den här åtgärden."</string>
+ <string name="aerr_title">"Tyvärr!"</string>
+ <string name="aerr_application">"Processen <xliff:g id="PROCESS">%2$s</xliff:g> för programmet <xliff:g id="APPLICATION">%1$s</xliff:g> stoppades oväntat. Försök igen."</string>
+ <string name="aerr_process">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> avslutades oväntat. Försök igen."</string>
+ <string name="anr_title">"Tyvärr!"</string>
+ <string name="anr_activity_application">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> (i programmet <xliff:g id="APPLICATION">%2$s</xliff:g>) svarar inte."</string>
+ <string name="anr_activity_process">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
+ <string name="anr_application_process">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
+ <string name="anr_process">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarar inte."</string>
+ <string name="force_close">"Tvinga fram en stängning"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Vänta"</string>
- <string name="debug" msgid="9103374629678531849">"Felsökning"</string>
- <string name="sendText" msgid="5132506121645618310">"Välj en åtgärd för text"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Ringvolym"</string>
- <string name="volume_music" msgid="5421651157138628171">"Mediavolym"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Spelar upp genom Bluetooth"</string>
- <string name="volume_call" msgid="3941680041282788711">"Samtalsvolym"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Samtalsvolym för Bluetooth"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Larmvolym"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Aviseringsvolym"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Volym"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Standardringsignal"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Standardringsignal (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Tyst"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringsignaler"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Okänd ringsignal"</string>
+ <string name="wait">"Vänta"</string>
+ <string name="debug">"Felsökning"</string>
+ <string name="sendText">"Välj en åtgärd för text"</string>
+ <string name="volume_ringtone">"Ringvolym"</string>
+ <string name="volume_music">"Mediavolym"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Spelar upp genom Bluetooth"</string>
+ <string name="volume_call">"Samtalsvolym"</string>
+ <string name="volume_bluetooth_call">"Samtalsvolym för Bluetooth"</string>
+ <string name="volume_alarm">"Larmvolym"</string>
+ <string name="volume_notification">"Aviseringsvolym"</string>
+ <string name="volume_unknown">"Volym"</string>
+ <string name="ringtone_default">"Standardringsignal"</string>
+ <string name="ringtone_default_with_actual">"Standardringsignal (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Tyst"</string>
+ <string name="ringtone_picker_title">"Ringsignaler"</string>
+ <string name="ringtone_unknown">"Okänd ringsignal"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fi-nätverk är tillgängliga"</item>
- <item quantity="other" msgid="4192424489168397386">"Wi-Fi-nätverk är tillgängliga"</item>
+ <item quantity="one">"Wi-Fi-nätverk är tillgängliga"</item>
+ <item quantity="other">"Wi-Fi-nätverk är tillgängliga"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
- <item quantity="other" msgid="7915895323644292768">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
+ <item quantity="one">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
+ <item quantity="other">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Infoga tecken"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Okänt program"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"Skickar SMS"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Flera SMS-meddelanden skickas. Tryck på OK om du vill fortsätta eller på Avbryt om du vill avsluta sändningen."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Avbryt"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Ställ in"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Standardinställning"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Inga behörigheter krävs"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Dölj"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Visa alla"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Läser in…"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB-ansluten"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Du har anslutit telefonen till datorn via USB. Välj Montera om du vill kopiera filer mellan datorn och telefonens SD-kort."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"Montera"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"Montera inte"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"Det gick inte att använda ditt SD-kort för USB-lagring."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-ansluten"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Välj om du vill kopiera filer till/från din dator."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Inaktivera USB-lagring"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Välj om USB-lagring ska inaktiveras."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"Inaktivera USB-lagring"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"Innan du inaktiverar USB-lagring måste du kontrollera att du har demonterat USB-värden. Välj Inaktivera om du vill inaktivera USB-lagring."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Inaktivera"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Avbryt"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"Ett problem uppstod när vi skulle inaktivera USB-lagringsplatsen. Kontrollera att USB-värden har demonterats och försök igen."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"Formatera SD-kort"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"Vill du formatera SD-kortet? Alla data på ditt kort kommer att gå förlorade."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
+ <string name="select_character">"Infoga tecken"</string>
+ <string name="sms_control_default_app_name">"Okänt program"</string>
+ <string name="sms_control_title">"Skickar SMS"</string>
+ <string name="sms_control_message">"Flera SMS-meddelanden skickas. Tryck på OK om du vill fortsätta eller på Avbryt om du vill avsluta sändningen."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Avbryt"</string>
+ <string name="date_time_set">"Ställ in"</string>
+ <string name="default_permission_group">"Standardinställning"</string>
+ <string name="no_permissions">"Inga behörigheter krävs"</string>
+ <string name="perms_hide"><b>"Dölj"</b></string>
+ <string name="perms_show_all"><b>"Visa alla"</b></string>
+ <string name="googlewebcontenthelper_loading">"Läser in…"</string>
+ <string name="usb_storage_title">"USB-ansluten"</string>
+ <string name="usb_storage_message">"Du har anslutit telefonen till datorn via USB. Välj Montera om du vill kopiera filer mellan datorn och telefonens SD-kort."</string>
+ <string name="usb_storage_button_mount">"Montera"</string>
+ <string name="usb_storage_button_unmount">"Montera inte"</string>
+ <string name="usb_storage_error_message">"Det gick inte att använda ditt SD-kort för USB-lagring."</string>
+ <string name="usb_storage_notification_title">"USB-ansluten"</string>
+ <string name="usb_storage_notification_message">"Välj om du vill kopiera filer till/från din dator."</string>
+ <string name="usb_storage_stop_notification_title">"Inaktivera USB-lagring"</string>
+ <string name="usb_storage_stop_notification_message">"Välj om USB-lagring ska inaktiveras."</string>
+ <string name="usb_storage_stop_title">"Inaktivera USB-lagring"</string>
+ <string name="usb_storage_stop_message">"Innan du inaktiverar USB-lagring måste du kontrollera att du har demonterat USB-värden. Välj Inaktivera om du vill inaktivera USB-lagring."</string>
+ <string name="usb_storage_stop_button_mount">"Inaktivera"</string>
+ <string name="usb_storage_stop_button_unmount">"Avbryt"</string>
+ <string name="usb_storage_stop_error_message">"Ett problem uppstod när vi skulle inaktivera USB-lagringsplatsen. Kontrollera att USB-värden har demonterats och försök igen."</string>
+ <string name="extmedia_format_title">"Formatera SD-kort"</string>
+ <string name="extmedia_format_message">"Vill du formatera SD-kortet? Alla data på ditt kort kommer att gå förlorade."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Välj indatametod"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"Förbereder SD-kort"</string>
+ <string name="select_input_method">"Välj indatametod"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"kandidater"</u></string>
+ <string name="ext_media_checking_notification_title">"Förbereder SD-kort"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"Tomt SD-kort"</string>
+ <string name="ext_media_nofs_notification_title">"Tomt SD-kort"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Skadat SD-kort"</string>
+ <string name="ext_media_unmountable_notification_title">"Skadat SD-kort"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD-kort togs oväntat bort"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Demontera SD-kort innan borttagning för att undvika dataförlust."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"Säkert att ta bort SD-kort"</string>
+ <string name="ext_media_badremoval_notification_title">"SD-kort togs oväntat bort"</string>
+ <string name="ext_media_badremoval_notification_message">"Demontera SD-kort innan borttagning för att undvika dataförlust."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Säkert att ta bort SD-kort"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"Borttaget SD-kort"</string>
+ <string name="ext_media_nomedia_notification_title">"Borttaget SD-kort"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Inga matchande aktiviteter hittades"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"uppdatera statistik över användning av komponenter"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Tillåter att samlad komponentstatistik ändras. Används inte av vanliga program."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Peka två gånger för zoomkontroll"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Fel när widgeten expanderades"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Kör"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Sök"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Skicka"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Nästa"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Färdig"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Utför"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Slå nummer "\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"Skapa kontakt"\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="activity_list_empty">"Inga matchande aktiviteter hittades"</string>
+ <string name="permlab_pkgUsageStats">"uppdatera statistik över användning av komponenter"</string>
+ <string name="permdesc_pkgUsageStats">"Tillåter att samlad komponentstatistik ändras. Används inte av vanliga program."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Peka två gånger för zoomkontroll"</string>
+ <string name="gadget_host_error_inflating">"Fel när widgeten expanderades"</string>
+ <string name="ime_action_go">"Kör"</string>
+ <string name="ime_action_search">"Sök"</string>
+ <string name="ime_action_send">"Skicka"</string>
+ <string name="ime_action_next">"Nästa"</string>
+ <string name="ime_action_done">"Färdig"</string>
+ <string name="ime_action_default">"Utför"</string>
+ <string name="dial_number_using">"Slå nummer "\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"Skapa kontakt"\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a8625fd..bda67c7 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"&lt;başlıksız&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"…"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Telefon numarası yok)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(Bilinmiyor)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Sesli Mesaj"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"Bağlantı sorunu veya geçersiz MMI kodu."</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"Hizmet etkindi."</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"Hizmet şunun için etkinleştirildi:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Hizmet devre dışı bırakıldı."</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"Kayıt işlemi başarılı oldu."</string>
- <string name="serviceErased" msgid="1288584695297200972">"Silme işlemi başarılı."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"Yanlış şifre."</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI tamamlandı."</string>
- <string name="badPin" msgid="5085454289896032547">"Yazdığınız eski PIN doğru değil."</string>
- <string name="badPuk" msgid="5702522162746042460">"Yazdığınız PUK doğru değil."</string>
- <string name="mismatchPin" msgid="3695902225843339274">"Girdiğiniz PIN kodları eşleşmiyor."</string>
- <string name="invalidPin" msgid="3850018445187475377">"4 ila 8 rakamdan oluÅŸan bir PIN girin."</string>
- <string name="needPuk" msgid="919668385956251611">"SIM kartınızın PUK kilidi devrede. Kilidi açmak için PUK kodunu yazın."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Engellenen SIM kartı açmak için PUK2 kodunu yazın."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Gelen Çağrı Kimliği"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Giden Çağrı Kimliği"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Çağrı yönlendirme"</string>
- <string name="CwMmi" msgid="9129678056795016867">"Çağrı bekletme"</string>
- <string name="BaMmi" msgid="455193067926770581">"Çağrı engelleme"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"Åžifre deÄŸiÅŸikliÄŸi"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN kodu deÄŸiÅŸikliÄŸi"</string>
+ <string name="untitled">"&lt;başlıksız&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Telefon numarası yok)"</string>
+ <string name="unknownName">"(Bilinmiyor)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Sesli Mesaj"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Bağlantı sorunu veya geçersiz MMI kodu."</string>
+ <string name="serviceEnabled">"Hizmet etkindi."</string>
+ <string name="serviceEnabledFor">"Hizmet şunun için etkinleştirildi:"</string>
+ <string name="serviceDisabled">"Hizmet devre dışı bırakıldı."</string>
+ <string name="serviceRegistered">"Kayıt işlemi başarılı oldu."</string>
+ <string name="serviceErased">"Silme işlemi başarılı."</string>
+ <string name="passwordIncorrect">"Yanlış şifre."</string>
+ <string name="mmiComplete">"MMI tamamlandı."</string>
+ <string name="badPin">"Yazdığınız eski PIN doğru değil."</string>
+ <string name="badPuk">"Yazdığınız PUK doğru değil."</string>
+ <string name="mismatchPin">"Girdiğiniz PIN kodları eşleşmiyor."</string>
+ <string name="invalidPin">"4 ila 8 rakamdan oluÅŸan bir PIN girin."</string>
+ <string name="needPuk">"SIM kartınızın PUK kilidi devrede. Kilidi açmak için PUK kodunu yazın."</string>
+ <string name="needPuk2">"Engellenen SIM kartı açmak için PUK2 kodunu yazın."</string>
+ <string name="ClipMmi">"Gelen Çağrı Kimliği"</string>
+ <string name="ClirMmi">"Giden Çağrı Kimliği"</string>
+ <string name="CfMmi">"Çağrı yönlendirme"</string>
+ <string name="CwMmi">"Çağrı bekletme"</string>
+ <string name="BaMmi">"Çağrı engelleme"</string>
+ <string name="PwdMmi">"Åžifre deÄŸiÅŸikliÄŸi"</string>
+ <string name="PinMmi">"PIN kodu deÄŸiÅŸikliÄŸi"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Arayan kimliği varsayılanları kısıtlanmıştır. Sonraki çağrı: Kısıtlanmış"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Arayan kimliği varsayılanları kısıtlanmıştır. Sonraki çağrı: Kısıtlanmamış"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmış"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmamış"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"Hizmet sağlanamadı."</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"Arayan kimliği ayarı değiştirilemez."</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Kısıtlanmış erişim değiştirildi"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"Veri hizmeti engellendi."</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Acil durum hizmeti engellendi."</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"Ses/SMS hizmeti engellendi."</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"Tüm ses/SMS hizmetleri engellendi."</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Ses"</string>
- <string name="serviceClassData" msgid="872456782077937893">"Veri"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"FAKS"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asenk."</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Senk."</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"Paket"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Arayan kimliği varsayılanları kısıtlanmıştır. Sonraki çağrı: Kısıtlanmış"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Arayan kimliği varsayılanları kısıtlanmıştır. Sonraki çağrı: Kısıtlanmamış"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmış"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmamış"</string>
+ <string name="serviceNotProvisioned">"Hizmet sağlanamadı."</string>
+ <string name="CLIRPermanent">"Arayan kimliği ayarı değiştirilemez."</string>
+ <string name="RestrictedChangedTitle">"Kısıtlanmış erişim değiştirildi"</string>
+ <string name="RestrictedOnData">"Veri hizmeti engellendi."</string>
+ <string name="RestrictedOnEmergency">"Acil durum hizmeti engellendi."</string>
+ <string name="RestrictedOnNormal">"Ses/SMS hizmeti engellendi."</string>
+ <string name="RestrictedOnAll">"Tüm ses/SMS hizmetleri engellendi."</string>
+ <string name="serviceClassVoice">"Ses"</string>
+ <string name="serviceClassData">"Veri"</string>
+ <string name="serviceClassFAX">"FAKS"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asenk."</string>
+ <string name="serviceClassDataSync">"Senk."</string>
+ <string name="serviceClassPacket">"Paket"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> saniye sonra <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> saniye sonra <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"Tamam"</string>
- <string name="httpError" msgid="2567300624552921790">"Web sayfası hata içeriyor."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"URL bulunamadı."</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"Site kimlik doğrulaması şeması desteklenmiyor."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Kimlik doğrulanamadı."</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Proxy sunucusu üzerinden kimlik doğrulanamadı."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Sunucu ile bağlantı kurulamadı."</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"Sunucu iletişim kuramadı. Daha sonra yeniden deneyin."</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"Sunucuya bağlanma işlemi zaman aşımına uğradı."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Sayfada çok fazla sunucu yeniden yönlendirmesi bulunuyor."</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"Protokol desteklenmiyor."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Güvenli bir bağlantı kurulamadı."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"URL geçersiz olduğundan sayfa açılamadı."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Dosyaya eriÅŸilemedi."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"İstenen dosya bulunamadı."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Çok fazla sayıda istek işleniyor. Daha sonra yeniden deneyin."</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Senk."</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Senk."</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Çok fazla <xliff:g id="CONTENT_TYPE">%s</xliff:g> silme var."</string>
- <string name="low_memory" msgid="6632412458436461203">"Telefonun depolama alanı doldu! Yer açmak için bazı dosyaları silin."</string>
- <string name="me" msgid="6545696007631404292">"Ben"</string>
- <string name="power_dialog" msgid="1319919075463988638">"Telefon seçenekleri"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Sessiz mod"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Kablosuzu aç"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Kablosuzu kapat"</string>
- <string name="screen_lock" msgid="799094655496098153">"Ekran kilidi"</string>
- <string name="power_off" msgid="4266614107412865048">"Kapat"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Kapanıyor…"</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"Telefonunuz kapanacak."</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Hiçbir yeni uygulama yok."</string>
- <string name="global_actions" msgid="2406416831541615258">"Telefon seçenekleri"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Ekran kilidi"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Kapat"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Sessiz mod"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ses KAPALI"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ses AÇIK"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Uçak modu"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uçak modu AÇIK"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Uçak modu KAPALI"</string>
- <string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Size maliyet getiren hizmetler"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Uygulamaların size maliyet getirebilecek işlemler yapmasına izin verir."</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajlarınız"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"SMS mesajlarınızı, e-posta iletilerinizi ve diğer mesajlarınızı okuyup yazın."</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"KiÅŸisel bilgileriniz"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Telefonunuzda depolanan kiÅŸilere ve takvime doÄŸrudan eriÅŸim."</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Konumunuz"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Fiziksel konumunuzu izleyin"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"AÄŸ iletiÅŸimi"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Uygulamaların çeşitli ağ özelliklerine erişmesine izin verir."</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"Google hesaplarınız"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Kullanılabilir Google hesaplarına erişin."</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Donanım denetimleri"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Telefon donanımına doğrudan erişim."</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Telefon çağrıları"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Telefon görüşmelerini izleyin, kaydedin ve işleyin."</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Sistem araçları"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Sisteme alt düzey erişim ve denetimi."</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Geliştirme araçları"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Yalnızca uygulama geliştiriciler için gerekli özellikler."</string>
+ <string name="httpErrorOk">"Tamam"</string>
+ <string name="httpError">"Web sayfası hata içeriyor."</string>
+ <string name="httpErrorLookup">"URL bulunamadı."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Site kimlik doğrulaması şeması desteklenmiyor."</string>
+ <string name="httpErrorAuth">"Kimlik doğrulanamadı."</string>
+ <string name="httpErrorProxyAuth">"Proxy sunucusu üzerinden kimlik doğrulanamadı."</string>
+ <string name="httpErrorConnect">"Sunucu ile bağlantı kurulamadı."</string>
+ <string name="httpErrorIO">"Sunucu iletişim kuramadı. Daha sonra yeniden deneyin."</string>
+ <string name="httpErrorTimeout">"Sunucuya bağlanma işlemi zaman aşımına uğradı."</string>
+ <string name="httpErrorRedirectLoop">"Sayfada çok fazla sunucu yeniden yönlendirmesi bulunuyor."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokol desteklenmiyor."</string>
+ <string name="httpErrorFailedSslHandshake">"Güvenli bir bağlantı kurulamadı."</string>
+ <string name="httpErrorBadUrl">"URL geçersiz olduğundan sayfa açılamadı."</string>
+ <string name="httpErrorFile">"Dosyaya eriÅŸilemedi."</string>
+ <string name="httpErrorFileNotFound">"İstenen dosya bulunamadı."</string>
+ <string name="httpErrorTooManyRequests">"Çok fazla sayıda istek işleniyor. Daha sonra yeniden deneyin."</string>
+ <string name="contentServiceSync">"Senk."</string>
+ <string name="contentServiceSyncNotificationTitle">"Senk."</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"Çok fazla <xliff:g id="CONTENT_TYPE">%s</xliff:g> silme var."</string>
+ <string name="low_memory">"Telefonun depolama alanı doldu! Yer açmak için bazı dosyaları silin."</string>
+ <string name="me">"Ben"</string>
+ <string name="power_dialog">"Telefon seçenekleri"</string>
+ <string name="silent_mode">"Sessiz mod"</string>
+ <string name="turn_on_radio">"Kablosuzu aç"</string>
+ <string name="turn_off_radio">"Kablosuzu kapat"</string>
+ <string name="screen_lock">"Ekran kilidi"</string>
+ <string name="power_off">"Kapat"</string>
+ <string name="shutdown_progress">"Kapanıyor…"</string>
+ <string name="shutdown_confirm">"Telefonunuz kapanacak."</string>
+ <string name="no_recent_tasks">"Hiçbir yeni uygulama yok."</string>
+ <string name="global_actions">"Telefon seçenekleri"</string>
+ <string name="global_action_lock">"Ekran kilidi"</string>
+ <string name="global_action_power_off">"Kapat"</string>
+ <string name="global_action_toggle_silent_mode">"Sessiz mod"</string>
+ <string name="global_action_silent_mode_on_status">"Ses KAPALI"</string>
+ <string name="global_action_silent_mode_off_status">"Ses AÇIK"</string>
+ <string name="global_actions_toggle_airplane_mode">"Uçak modu"</string>
+ <string name="global_actions_airplane_mode_on_status">"Uçak modu AÇIK"</string>
+ <string name="global_actions_airplane_mode_off_status">"Uçak modu KAPALI"</string>
+ <string name="safeMode">"Güvenli mod"</string>
+ <string name="android_system_label">"Android Sistemi"</string>
+ <string name="permgrouplab_costMoney">"Size maliyet getiren hizmetler"</string>
+ <string name="permgroupdesc_costMoney">"Uygulamaların size maliyet getirebilecek işlemler yapmasına izin verir."</string>
+ <string name="permgrouplab_messages">"Mesajlarınız"</string>
+ <string name="permgroupdesc_messages">"SMS mesajlarınızı, e-postanızı ve diğer mesajlarınızı okuyup yazın."</string>
+ <string name="permgrouplab_personalInfo">"KiÅŸisel bilgileriniz"</string>
+ <string name="permgroupdesc_personalInfo">"Telefonunuzda depolanan kiÅŸilere ve takvime doÄŸrudan eriÅŸim."</string>
+ <string name="permgrouplab_location">"Konumunuz"</string>
+ <string name="permgroupdesc_location">"Fiziksel konumunuzu izleyin"</string>
+ <string name="permgrouplab_network">"AÄŸ iletiÅŸimi"</string>
+ <string name="permgroupdesc_network">"Uygulamaların çeşitli ağ özelliklerine erişmesine izin verir."</string>
+ <string name="permgrouplab_accounts">"Google hesaplarınız"</string>
+ <string name="permgroupdesc_accounts">"Kullanılabilir Google hesaplarına erişin."</string>
+ <string name="permgrouplab_hardwareControls">"Donanım denetimleri"</string>
+ <string name="permgroupdesc_hardwareControls">"Telefon donanımına doğrudan erişim."</string>
+ <string name="permgrouplab_phoneCalls">"Telefon çağrıları"</string>
+ <string name="permgroupdesc_phoneCalls">"Telefon görüşmelerini izleyin, kaydedin ve işleyin."</string>
+ <string name="permgrouplab_systemTools">"Sistem araçları"</string>
+ <string name="permgroupdesc_systemTools">"Sisteme alt düzey erişim ve denetimi."</string>
+ <string name="permgrouplab_developmentTools">"Geliştirme araçları"</string>
+ <string name="permgroupdesc_developmentTools">"Yalnızca uygulama geliştiriciler için gerekli özellikler."</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"durum çubuğunu devre dışı bırak veya değiştir"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Uygulamanın durum çubuğunu devre dışı bırakmasına veya sistem simgeleri ekleyip kaldırmasına izin verir."</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"durum çubuğunu genişlet/daralt"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Uygulamanın, durum çubuğunu genişletip daraltmasına izin verir."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"giden aramalarda araya gir"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Uygulamanın, giden çağrıları işlemesine ve aranacak numarayı değiştirmesine izin verir. Kötü amaçlı uygulamalar giden çağrıları izleyebilir, yönlendirebilir veya engelleyebilir."</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"SMS al"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Uygulamanın SMS mesajları alıp işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya bunları size göstermeden silebilir."</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"MMS al"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Uygulamanın MMS mesajları almasına ve işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya size göstermeden silebilir."</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"SMS mesajları gönder"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Uygulamaların SMS mesajları göndermesine izin verir. Kötü amaçlı uygulamalar, onayınızı almadan mesaj göndererek size maliyet çıkarabilir."</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"SMS veya MMS oku"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Uygulamaların, telefonunuzda veya SIM kartta depolanan SMS mesajlarını okumasına izin verir. Kötü amaçlı uygulamalar gizli mesajlarınızı okuyabilir."</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"SMS veya MMS düzenle"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Uygulamanın telefonunuzda veya SIM kartta depolanan SMS mesajlarına yazmasına izin verir. Kötü amaçlı uygulamalar mesajlarınızı silebilir."</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP al"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Uygulamanın WAP mesajları alıp işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya bunları size göstermeden silebilir."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"çalışan uygulamaları al"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Uygulamaların şu anda ve yakın geçmişte çalışmakta olan işlemler hakkında bilgi almasına izin verir. Kötü amaçlı uygulamaların diğer uygulamalar ile ilgili gizli bilgileri keşfetmesine izin verebilir."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"çalışan uygulamaları yeniden sırala"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Uygulamaların görevleri ön plana ve arka plana taşımasına izin verir. Kötü amaçlı uygulamalar kendilerini sizin denetiminiz dışında zorla ön plana çıkarabilir."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"uygulama hata ayıklamayı etkinleştir"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Bir uygulamanın başka bir uygulama için hata ayıklamayı çalıştırmasına izin verir. Kötü amaçlı uygulamalar bu işlevi başka uygulamaları kapatmak için kullanabilir."</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"kullanıcı arayüzü ayarlarınızı değiştirin"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Uygulamaların güncel yapılandırmayı; örneğin yerel ayarı veya genel yazı tipi boyutunu değiştirmesine izin verir."</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"diğer uygulamaları yeniden başlat"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"Uygulamaların başka uygulamaları zorla yeniden başlatmasına izin verir."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"uygulamayı kapanmaya zorla"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Uygulamaların, ön plandaki herhangi bir etkinliği kapanmaya ve arka plana geçmeye zorlamasına izin verir. Normal uygulamalarda hiçbir zaman gerekmemelidir."</string>
- <string name="permlab_dump" msgid="1681799862438954752">"sistemin dahili durumunu al"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Uygulamanın dahili sistem durumunu almasına izin verir. Kötü amaçlı uygulamalar, normalde gerekli olmaması gereken çok çeşitli özel ve koruma altındaki bilgiyi alabilir."</string>
+ <string name="permlab_statusBar">"durum çubuğunu devre dışı bırak veya değiştir"</string>
+ <string name="permdesc_statusBar">"Uygulamanın durum çubuğunu devre dışı bırakmasına veya sistem simgeleri ekleyip kaldırmasına izin verir."</string>
+ <string name="permlab_expandStatusBar">"durum çubuğunu genişlet/daralt"</string>
+ <string name="permdesc_expandStatusBar">"Uygulamanın, durum çubuğunu genişletip daraltmasına izin verir."</string>
+ <string name="permlab_processOutgoingCalls">"giden aramalarda araya gir"</string>
+ <string name="permdesc_processOutgoingCalls">"Uygulamanın, giden çağrıları işlemesine ve aranacak numarayı değiştirmesine izin verir. Kötü amaçlı uygulamalar giden çağrıları izleyebilir, yönlendirebilir veya engelleyebilir."</string>
+ <string name="permlab_receiveSms">"SMS al"</string>
+ <string name="permdesc_receiveSms">"Uygulamanın SMS mesajları alıp işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya bunları size göstermeden silebilir."</string>
+ <string name="permlab_receiveMms">"MMS al"</string>
+ <string name="permdesc_receiveMms">"Uygulamanın MMS mesajları almasına ve işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya size göstermeden silebilir."</string>
+ <string name="permlab_sendSms">"SMS mesajları gönder"</string>
+ <string name="permdesc_sendSms">"Uygulamaların SMS mesajları göndermesine izin verir. Kötü amaçlı uygulamalar, onayınızı almadan mesaj göndererek size maliyet çıkarabilir."</string>
+ <string name="permlab_readSms">"SMS veya MMS oku"</string>
+ <string name="permdesc_readSms">"Uygulamaların, telefonunuzda veya SIM kartta depolanan SMS mesajlarını okumasına izin verir. Kötü amaçlı uygulamalar gizli mesajlarınızı okuyabilir."</string>
+ <string name="permlab_writeSms">"SMS veya MMS düzenle"</string>
+ <string name="permdesc_writeSms">"Uygulamanın telefonunuzda veya SIM kartta depolanan SMS mesajlarına yazmasına izin verir. Kötü amaçlı uygulamalar mesajlarınızı silebilir."</string>
+ <string name="permlab_receiveWapPush">"WAP al"</string>
+ <string name="permdesc_receiveWapPush">"Uygulamanın WAP mesajları alıp işlemesine izin verir. Kötü amaçlı uygulamalar mesajlarınızı izleyebilir veya bunları size göstermeden silebilir."</string>
+ <string name="permlab_getTasks">"çalışan uygulamaları al"</string>
+ <string name="permdesc_getTasks">"Uygulamaların şu anda ve yakın geçmişte çalışmakta olan işlemler hakkında bilgi almasına izin verir. Kötü amaçlı uygulamaların diğer uygulamalar ile ilgili gizli bilgileri keşfetmesine izin verebilir."</string>
+ <string name="permlab_reorderTasks">"çalışan uygulamaları yeniden sırala"</string>
+ <string name="permdesc_reorderTasks">"Uygulamaların görevleri ön plana ve arka plana taşımasına izin verir. Kötü amaçlı uygulamalar kendilerini sizin denetiminiz dışında zorla ön plana çıkarabilir."</string>
+ <string name="permlab_setDebugApp">"uygulama hata ayıklamayı etkinleştir"</string>
+ <string name="permdesc_setDebugApp">"Bir uygulamanın başka bir uygulama için hata ayıklamayı çalıştırmasına izin verir. Kötü amaçlı uygulamalar bu işlevi başka uygulamaları kapatmak için kullanabilir."</string>
+ <string name="permlab_changeConfiguration">"kullanıcı arayüzü ayarlarınızı değiştirin"</string>
+ <string name="permdesc_changeConfiguration">"Uygulamaların güncel yapılandırmayı; örneğin yerel ayarı veya genel yazı tipi boyutunu değiştirmesine izin verir."</string>
+ <string name="permlab_restartPackages">"diğer uygulamaları yeniden başlat"</string>
+ <string name="permdesc_restartPackages">"Uygulamaların başka uygulamaları zorla yeniden başlatmasına izin verir."</string>
+ <string name="permlab_forceBack">"uygulamayı kapanmaya zorla"</string>
+ <string name="permdesc_forceBack">"Uygulamaların, ön plandaki herhangi bir etkinliği kapanmaya ve arka plana geçmeye zorlamasına izin verir. Normal uygulamalarda hiçbir zaman gerekmemelidir."</string>
+ <string name="permlab_dump">"sistemin dahili durumunu al"</string>
+ <string name="permdesc_dump">"Uygulamanın dahili sistem durumunu almasına izin verir. Kötü amaçlı uygulamalar, normalde gerekli olmaması gereken çok çeşitli özel ve koruma altındaki bilgiyi alabilir."</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"tüm uygulama başlatma işlemlerini izle ve denetle"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Uygulamaların, sistemin etkinlikleri nasıl başlattığını izlemesine ve denetlemesine izin verir. Kötü amaçlı uygulamalar sistemin güvenliğini tamamen tehlikeye atabilir. Bu izin yalnızca program geliştirme amacıyla gereklidir, normal telefon kullanımı için gerekli değildir."</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"paket ile kaldırılan yayını gönder"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Uygulamaların bir uygulama paketinin kaldırıldığında dair bir bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bunu çalışan diğer herhangi bir uygulamayı kapatmak için kullanabilir."</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"SMS ile alınan yayın gönder"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Uygulamaların bir SMS mesajı alındığında dair bir bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bu işlevi telefona sahte SMS mesajları göndermek için kullanabilir."</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH ile alınan yayın gönder"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Uygulamaların, WAP PUSH mesajının alındığına dair bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bu işlevi, sahte MMS alındıları göndermek veya bir web sayfasını sessizce kötü amaçla tasarlanmış başkaları ile değiştirmek için kullanabilir."</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"çalışan işlem sayısını sınırla"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Uygulamaların, çalışacak maksimum işlem sayısını denetlemesine izin verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"tüm arka plan uygulamalarını kapat"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Uygulamaların, etkinliklerin arka planda daima tamamlanıp tamamlanmadığını denetlemesine izin verir. Normal uygulamalar için hiçbir zaman gerekli değildir."</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"pil istatistiklerini deÄŸiÅŸtir"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"Toplanan pil istatistiklerinin değiştirilmesine izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
+ <string name="permlab_runSetActivityWatcher">"tüm uygulama başlatma işlemlerini izle ve denetle"</string>
+ <string name="permdesc_runSetActivityWatcher">"Uygulamaların, sistemin etkinlikleri nasıl başlattığını izlemesine ve denetlemesine izin verir. Kötü amaçlı uygulamalar sistemin güvenliğini tamamen tehlikeye atabilir. Bu izin yalnızca program geliştirme amacıyla gereklidir, normal telefon kullanımı için gerekli değildir."</string>
+ <string name="permlab_broadcastPackageRemoved">"paket ile kaldırılan yayını gönder"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Uygulamaların bir uygulama paketinin kaldırıldığında dair bir bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bunu çalışan diğer herhangi bir uygulamayı kapatmak için kullanabilir."</string>
+ <string name="permlab_broadcastSmsReceived">"SMS ile alınan yayın gönder"</string>
+ <string name="permdesc_broadcastSmsReceived">"Uygulamaların bir SMS mesajı alındığında dair bir bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bu işlevi telefona sahte SMS mesajları göndermek için kullanabilir."</string>
+ <string name="permlab_broadcastWapPush">"WAP-PUSH ile alınan yayın gönder"</string>
+ <string name="permdesc_broadcastWapPush">"Uygulamaların, WAP PUSH mesajının alındığına dair bildirim yayınlamasına izin verir. Kötü amaçlı uygulamalar bu işlevi, sahte MMS alındıları göndermek veya bir web sayfasını sessizce kötü amaçla tasarlanmış başkaları ile değiştirmek için kullanabilir."</string>
+ <string name="permlab_setProcessLimit">"çalışan işlem sayısını sınırla"</string>
+ <string name="permdesc_setProcessLimit">"Uygulamaların, çalışacak maksimum işlem sayısını denetlemesine izin verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
+ <string name="permlab_setAlwaysFinish">"tüm arka plan uygulamaları kapat"</string>
+ <string name="permdesc_setAlwaysFinish">"Uygulamaların, etkinliklerin arka planda daima tamamlanıp tamamlanmadığını denetlemesine izin verir. Normal uygulamalar için hiçbir zaman gerekli değildir."</string>
+ <string name="permlab_batteryStats">"pil istatistiklerini deÄŸiÅŸtir"</string>
+ <string name="permdesc_batteryStats">"Toplanan pil istatistiklerinin değiştirilmesine izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"yetkisiz pencereleri görüntüle"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Dahili sistem kullanıcı arayüzü tarafından kullanılmak üzere tasarlanmış pencerelerin oluşturulmasına izin verir. Normal uygulamalarda kullanılmaz."</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"sistem düzeyi uyarıları görüntüle"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Uygulamaların sistem uyarı pencereleri göstermesine izin verir. Kötü amaçlı uygulamalar telefonun tüm ekranını işgal edebilir."</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"genel animasyon hızını değiştir"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Uygulamaların, istedikleri zaman genel animasyon hızını değiştirmesine (animasyonları hızlandırmasına veya yavaşlatmasına) izin verir."</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"uygulama simgelerini yönet"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"Uygulamaların, kendi normal Z sıralamalarını atlayarak kendi simgelerini oluşturup yönetmelerine izin verir. Normal uygulamalar için hiçbir zaman gerekli olmamalıdır."</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"tuşlara bas ve düğmeleri denetle"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Uygulamaların kendi giriş işlemlerini (tuşa basma vb.) başka uygulamalara göndermesine izin verir. Kötü amaçlı uygulamalar bunu telefonun denetimini ele geçirmek için kullanabilir."</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"yazdıklarınızı ve yaptığınız işlemleri kaydet"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Uygulamaların, başka bir uygulama ile etkileşim halindeyken (örneğin bir şifre girerken) bile bastığınız tuşları izlemesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmamalıdır."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"bir giriş yöntemine bağla"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Tutucunun bir giriş yönteminin en üst düzey arayüzüne bağlanmasına izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmamalıdır."</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"ekran yönünü değiştir"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Uygulamaların ekran yönünü istedikleri zaman değiştirmesine izin verir. Normal uygulamalarda hiçbir zaman gerekmemelidir."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"uygulamalara Linux sinyalleri gönder"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Uygulamaların, sağlanan sinyalin tüm kalıcı işlemlere gönderilmesini istemesine izin verir."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"uygulamayı her zaman çalıştır"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Uygulamaların, sistemin başka uygulamalarda kullanamaması için kendi parçalarını kalıcı kılmasına izin verir."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"uygulamaları sil"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Uygulamaların Android paketlerini silmesine izin verir. Kötü amaçlı uygulamalar bu işlevi önemli uygulamaları silmek için kullanabilir."</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"diğer uygulamaların verilerini sil"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Uygulamaların kullanıcı verilerini temizlemesine izin verir."</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"diğer uygulamaların önbelleklerini sil"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Uygulamaların önbellek dosyalarını silmesine izin verir."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"uygulama depolama alanını ölç"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Uygulamanın kodunu, verilerini ve önbellek boyutunu almasına izin verir"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"doğrudan uygulama yükle"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Uygulamaların yeni veya güncellenmiş Android paketleri yüklemesine izin verir. Kötü amaçlı uygulamalar bunu, kendilerine verilen izin derecesi keyfi olarak değişen yeni uygulamalar eklemek için kullanabilir."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"tüm uygulama önbelleği verilerini sil"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Uygulamaların uygulama önbelleği dizinindeki dosyaları silerek telefonda yer açmasına izin verir. Erişim genellikle sistem işlemlerine ve yüksek düzeyde kısıtlı olarak verilir."</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"sistem günlük dosyalarını oku"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"Uygulamaların sistemin çeşitli günlük dosyalarından okumalarına izin verir. Bu, uygulamaların telefon ile neler yaptığınız ile ilgili genel bilgi bulmasına izin verir, ancak bunlar kişisel veya özel bir bilgi içermemelidir."</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Uygulamanın tanılama grubundaki bir kaynağa ait herhangi bir kaynağı; örneğin /dev içindeki dosyaları okumasına ve bunlara yazmasına izin verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Uygulamaların başka bir uygulamanın bir bileşenini etkinleştirme ayarını değiştirmesine izin verir. Kötü amaçlı uygulamalar bu ayarı telefonun önemli yeteneklerini devre dışı bırakmak için kullanabilir. Bu iznin verilmesi uygulama bileşenlerini kullanılamaz, tutarsız veya kararsız bir duruma sokabileceği için izin verilirken dikkatli olunmalıdır."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"tercih edilen uygulamaları ayarla"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Uygulamanın tercih ettiğiniz uygulamaları değiştirmesine izin verir. Bu işlem, kötü amaçlı uygulamaların, çalışmakta olan uygulamaları sessizce değiştirerek mevcut uygulamalarınızı aldatıp kişisel bilgilerinizi almasına izin verebilir."</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"genel sistem ayarlarını değiştir"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Uygulamaların sistem ayar verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar sisteminizin yapılandırmasını bozabilir."</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"güvenli sistem ayarlarını değiştir"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"Uygulamaların sistemin güvenlik ayarları verilerini değiştirmesine izin verir. Normal uygulamalarda kullanılmaz."</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"Google hizmetler haritasını değiştir"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Uygulamanın, Google hizmetleri haritasını değiştirmesine izin verir. Normal uygulamalarda kullanılmaz."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"açılışta otomatik başlat"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Uygulamaların, sistem açıldıktan hemen sonra kendini başlatmasına izin verir. Bu işlev, telefonu başlatma süresini uzatabilir ve uygulama, sürekli çalışması nedeniyle telefonun çalışmasını genel olarak yavaşlatabilir."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"sabit yayın gönder"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Uygulamaların yayın bittikten sonra da kalan sabit yayınlar göndermesine izin verir. Kötü amaçlı uygulamalar telefonun aşırı miktarda bellek kullanmasına neden olarak telefonu yavaşlatabilir veya telefonun kararsız hale gelmesine neden olabilir."</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"kiÅŸi verilerini oku"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Uygulamaların telefonunuzda depolanan tüm kişi (adres) verilerini okumasına izin verir. Kötü amaçlı uygulamalar bu işlevi verilerinizi başkalarına göndermek için kullanabilir."</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"kiÅŸi verileri yaz"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Uygulamaların telefonunuzda depolanan kişi (adres) verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar bu işlevi kişi verilerinizi silmek veya değiştirmek için kullanabilir."</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"sahip verilerini yaz"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"Uygulamaların telefonunuzda depolanan telefon sahibi verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar bu işlevi kullanıcı verilerini silmek veya değiştirmek için kullanabilir."</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"sahip verilerini oku"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"Uygulamaların telefonunuzda depolanan telefon sahibi verilerini okumasına izin verir. Kötü amaçlı uygulamalar bunu telefon sahibi verilerini okumak için kullanabilir."</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"takvim verilerini oku"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Uygulamaların telefonunuzda depolanan takvim etkinliklerinin tümünü okumasına izin verir. Kötü amaçlı uygulamalar bunu, takvim etkinliklerinizi başkalarına göndermek için kullanabilir."</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"takvim verilerini yaz"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"Uygulamaların telefonunuzda depolanan takvim etkinliklerini değiştirmesine izin verir. Kötü amaçlı uygulamaları bunu takvim verilerinizi silmek veya değiştirmek için kullanabilir."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"test için sahte konum kaynakları"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Test amacıyla sahte konum kaynakları oluşturur. Kötü amaçlı uygulamalar bu işlevi GPS veya Ağ Hizmeti sağlayıcılar gibi gerçek kaynaklardan gelen konum ve/veya durum bilgilerini geçersiz kılmak için kullanabilir."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ek konum sağlayıcı komutlarına eriş"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Ek konum sağlayıcı komutlarına erişin. Kötü amaçlı uygulamalar bu işlevi GPS veya diğer konum kaynaklarının işleyişine müdahale etmek için kullanabilir."</string>
+ <string name="permlab_internalSystemWindow">"yetkisiz pencereleri görüntüle"</string>
+ <string name="permdesc_internalSystemWindow">"Dahili sistem kullanıcı arayüzü tarafından kullanılmak üzere tasarlanmış pencerelerin oluşturulmasına izin verir. Normal uygulamalarda kullanılmaz."</string>
+ <string name="permlab_systemAlertWindow">"sistem düzeyi uyarıları görüntüle"</string>
+ <string name="permdesc_systemAlertWindow">"Uygulamaların sistem uyarı pencereleri göstermesine izin verir. Kötü amaçlı uygulamalar telefonun tüm ekranını işgal edebilir."</string>
+ <string name="permlab_setAnimationScale">"genel animasyon hızını değiştir"</string>
+ <string name="permdesc_setAnimationScale">"Uygulamaların, istedikleri zaman genel animasyon hızını değiştirmesine (animasyonları hızlandırmasına veya yavaşlatmasına) izin verir."</string>
+ <string name="permlab_manageAppTokens">"uygulama simgelerini yönet"</string>
+ <string name="permdesc_manageAppTokens">"Uygulamaların, kendi normal Z sıralamalarını atlayarak kendi simgelerini oluşturup yönetmelerine izin verir. Normal uygulamalar için hiçbir zaman gerekli olmamalıdır."</string>
+ <string name="permlab_injectEvents">"tuşlara bas ve düğmeleri denetle"</string>
+ <string name="permdesc_injectEvents">"Uygulamaların kendi giriş işlemlerini (tuşa basma vb.) başka uygulamalara göndermesine izin verir. Kötü amaçlı uygulamalar bunu telefonun denetimini ele geçirmek için kullanabilir."</string>
+ <string name="permlab_readInputState">"yazdıklarınızı ve yaptığınız işlemleri kaydedin"</string>
+ <string name="permdesc_readInputState">"Uygulamaların, başka bir uygulama ile etkileşim halindeyken (örneğin bir şifre girerken) bile bastığınız tuşları izlemesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmamalıdır."</string>
+ <string name="permlab_bindInputMethod">"bir giriş yöntemine bağla"</string>
+ <string name="permdesc_bindInputMethod">"Tutucunun bir giriş yönteminin en üst düzey arayüzüne bağlanmasına izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmamalıdır."</string>
+ <string name="permlab_setOrientation">"ekran yönünü değiştir"</string>
+ <string name="permdesc_setOrientation">"Uygulamaların ekran yönünü istedikleri zaman değiştirmesine izin verir. Normal uygulamalarda hiçbir zaman gerekmemelidir."</string>
+ <string name="permlab_signalPersistentProcesses">"uygulamalara Linux sinyalleri gönder"</string>
+ <string name="permdesc_signalPersistentProcesses">"Uygulamaların, sağlanan sinyalin tüm kalıcı işlemlere gönderilmesini istemesine izin verir."</string>
+ <string name="permlab_persistentActivity">"uygulamayı her zaman çalıştır"</string>
+ <string name="permdesc_persistentActivity">"Uygulamaların, sistemin başka uygulamalarda kullanamaması için kendi parçalarını kalıcı kılmasına izin verir."</string>
+ <string name="permlab_deletePackages">"uygulamaları sil"</string>
+ <string name="permdesc_deletePackages">"Uygulamaların Android paketlerini silmesine izin verir. Kötü amaçlı uygulamalar bu işlevi önemli uygulamaları silmek için kullanabilir."</string>
+ <string name="permlab_clearAppUserData">"diğer uygulamaların verilerini sil"</string>
+ <string name="permdesc_clearAppUserData">"Uygulamaların kullanıcı verilerini temizlemesine izin verir."</string>
+ <string name="permlab_deleteCacheFiles">"diğer uygulamaların önbelleklerini sil"</string>
+ <string name="permdesc_deleteCacheFiles">"Uygulamaların önbellek dosyalarını silmesine izin verir."</string>
+ <string name="permlab_getPackageSize">"uygulama depolama alanını ölç"</string>
+ <string name="permdesc_getPackageSize">"Uygulamanın kodunu, verilerini ve önbellek boyutunu almasına izin verir"</string>
+ <string name="permlab_installPackages">"doğrudan uygulama yükle"</string>
+ <string name="permdesc_installPackages">"Uygulamaların yeni veya güncellenmiş Android paketleri yüklemesine izin verir. Kötü amaçlı uygulamalar bunu, kendilerine verilen izin derecesi keyfi olarak değişen yeni uygulamalar eklemek için kullanabilir."</string>
+ <string name="permlab_clearAppCache">"tüm uygulama önbelleği verilerini sil"</string>
+ <string name="permdesc_clearAppCache">"Uygulamaların uygulama önbelleği dizinindeki dosyaları silerek telefonda yer açmasına izin verir. Erişim genellikle sistem işlemlerine ve yüksek düzeyde kısıtlı olarak verilir."</string>
+ <string name="permlab_readLogs">"sistem günlük dosyalarını oku"</string>
+ <string name="permdesc_readLogs">"Uygulamaların sistemin çeşitli günlük dosyalarından okumalarına izin verir. Bu, uygulamaların telefon ile neler yaptığınız ile ilgili genel bilgi bulmasına izin verir, ancak bunlar kişisel veya özel bir bilgi içermemelidir."</string>
+ <string name="permlab_diagnostic">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
+ <string name="permdesc_diagnostic">"Uygulamanın tanılama grubundaki bir kaynağa ait herhangi bir kaynağı; örneğin /dev içindeki dosyaları okumasına ve bunlara yazmasına izin verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
+ <string name="permlab_changeComponentState">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
+ <string name="permdesc_changeComponentState">"Uygulamaların başka bir uygulamanın bir bileşenini etkinleştirme ayarını değiştirmesine izin verir. Kötü amaçlı uygulamalar bu ayarı telefonun önemli yeteneklerini devre dışı bırakmak için kullanabilir. Bu iznin verilmesi uygulama bileşenlerini kullanılamaz, tutarsız veya kararsız bir duruma sokabileceği için izin verilirken dikkatli olunmalıdır."</string>
+ <string name="permlab_setPreferredApplications">"tercih edilen uygulamaları ayarla"</string>
+ <string name="permdesc_setPreferredApplications">"Uygulamanın tercih ettiğiniz uygulamaları değiştirmesine izin verir. Bu işlem, kötü amaçlı uygulamaların, çalışmakta olan uygulamaları sessizce değiştirerek mevcut uygulamalarınızı aldatıp kişisel bilgilerinizi almasına izin verebilir."</string>
+ <string name="permlab_writeSettings">"genel sistem ayarlarını değiştir"</string>
+ <string name="permdesc_writeSettings">"Uygulamaların sistem ayar verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar sisteminizin yapılandırmasını bozabilir."</string>
+ <string name="permlab_writeSecureSettings">"güvenli sistem ayarlarını değiştir"</string>
+ <string name="permdesc_writeSecureSettings">"Uygulamaların sistemin güvenlik ayarları verilerini değiştirmesine izin verir. Normal uygulamalarda kullanılmaz."</string>
+ <string name="permlab_writeGservices">"Google hizmetler haritasını değiştir"</string>
+ <string name="permdesc_writeGservices">"Uygulamanın, Google hizmetleri haritasını değiştirmesine izin verir. Normal uygulamalarda kullanılmaz."</string>
+ <string name="permlab_receiveBootCompleted">"açılışta otomatik başlat"</string>
+ <string name="permdesc_receiveBootCompleted">"Uygulamaların, sistem açıldıktan hemen sonra kendini başlatmasına izin verir. Bu işlev, telefonu başlatma süresini uzatabilir ve uygulama, sürekli çalışması nedeniyle telefonun çalışmasını genel olarak yavaşlatabilir."</string>
+ <string name="permlab_broadcastSticky">"sabit yayın gönder"</string>
+ <string name="permdesc_broadcastSticky">"Uygulamaların yayın bittikten sonra da kalan sabit yayınlar göndermesine izin verir. Kötü amaçlı uygulamalar telefonun aşırı miktarda bellek kullanmasına neden olarak telefonu yavaşlatabilir veya telefonun kararsız hale gelmesine neden olabilir."</string>
+ <string name="permlab_readContacts">"kiÅŸi verilerini oku"</string>
+ <string name="permdesc_readContacts">"Uygulamaların telefonunuzda depolanan tüm kişi (adres) verilerini okumasına izin verir. Kötü amaçlı uygulamalar bu işlevi verilerinizi başkalarına göndermek için kullanabilir."</string>
+ <string name="permlab_writeContacts">"kiÅŸi verileri yaz"</string>
+ <string name="permdesc_writeContacts">"Uygulamaların telefonunuzda depolanan kişi (adres) verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar bu işlevi kişi verilerinizi silmek veya değiştirmek için kullanabilir."</string>
+ <string name="permlab_writeOwnerData">"sahip verilerini yaz"</string>
+ <string name="permdesc_writeOwnerData">"Uygulamaların telefonunuzda depolanan telefon sahibi verilerini değiştirmesine izin verir. Kötü amaçlı uygulamalar bu işlevi kullanıcı verilerini silmek veya değiştirmek için kullanabilir."</string>
+ <string name="permlab_readOwnerData">"sahip verilerini oku"</string>
+ <string name="permdesc_readOwnerData">"Uygulamaların telefonunuzda depolanan telefon sahibi verilerini okumasına izin verir. Kötü amaçlı uygulamalar bunu telefon sahibi verilerini okumak için kullanabilir."</string>
+ <string name="permlab_readCalendar">"takvim verilerini oku"</string>
+ <string name="permdesc_readCalendar">"Uygulamaların telefonunuzda depolanan takvim etkinliklerinin tümünü okumasına izin verir. Kötü amaçlı uygulamalar bunu, takvim etkinliklerinizi başkalarına göndermek için kullanabilir."</string>
+ <string name="permlab_writeCalendar">"takvim verilerini yaz"</string>
+ <string name="permdesc_writeCalendar">"Uygulamaların telefonunuzda depolanan takvim etkinliklerini değiştirmesine izin verir. Kötü amaçlı uygulamaları bunu takvim verilerinizi silmek veya değiştirmek için kullanabilir."</string>
+ <string name="permlab_accessMockLocation">"test için sahte konum kaynakları"</string>
+ <string name="permdesc_accessMockLocation">"Test amacıyla sahte konum kaynakları oluşturur. Kötü amaçlı uygulamalar bu işlevi GPS veya Ağ Hizmeti sağlayıcılar gibi gerçek kaynaklardan gelen konum ve/veya durum bilgilerini geçersiz kılmak için kullanabilir."</string>
+ <string name="permlab_accessLocationExtraCommands">"ek konum sağlayıcı komutlarına eriş"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Ek konum sağlayıcı komutlarına erişin. Kötü amaçlı uygulamalar bu işlevi GPS veya diğer konum kaynaklarının işleyişine müdahale etmek için kullanabilir."</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"kesinliği yüksek (GPS) konum"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Bulunduğu yerlerde telefondan Küresel Konumlandırma Sistemi gibi hassas konum bulma kaynaklarına erişin. Kötü amaçlı uygulamalar bu işlevi bulunduğunuz yeri belirlemek için kullanabilir ve ek pil gücü tüketebilir."</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"kesinliği düşük (ağ tabanlı) konum"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Telefonun yaklaşık yerini belirlemek için bulunduğu yerlerde hücresel ağ veritabanı gibi tahmini konum kaynaklarına erişir. Kötü amaçlı uygulamalar, bu işlevi bulunduğunuz yeri yaklaşık olarak belirlemek için kullanabilir."</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"SurfaceFlinger\'a eriÅŸ"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Uygulamanın SurfaceFlinger alt düzey özelliklerini kullanmasına izin verir."</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"çerçeve arabelleğini oku"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"Kullanılacak uygulamanın çerçeve arabelleğinin içeriğini okumasına izin verir."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ses ayarlarınızı değiştirin"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Uygulamaların, ses düzeyi ve yönlendirme gibi genel ses ayarlarını değiştirmesine izin verir."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"ses kaydet"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Uygulamanın, ses kayıt yoluna erişmesine izin verir."</string>
- <string name="permlab_camera" msgid="8059288807274039014">"resim çek"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"Uygulamaların kamera ile resim çekmesine izin verir. Bu işlev herhangi bir zamanda kameranın görmekte olduğu görüntüyü uygulamaların toplamasına izin verir."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"telefonu tamamen devre dışı bırak"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Uygulamaların tüm telefonu kalıcı olarak devre dışı bırakmasına izin verir. Bu çok tehlikelidir."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"telefonu yeniden baÅŸlamaya zorla"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Uygulamanın telefonu yeniden açılmaya zorlamasına izin verir."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"dosya sistemlerini bağla ve bağlantısını kes"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Uygulamaların çıkarılabilir depolama birimleri için dosya sistemleri ile bağlantı kurmasına ve bağlantıyı kesmesine izin verir."</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"harici depolama birimini biçimlendir"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Uygulamanın çıkarılabilir depolama birimini biçimlendirmesine izin verir."</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"titreÅŸimi denetle"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Uygulamanın titreşimi denetlemesine izin verir."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"flaşı denetle"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Uygulamaların flaş ışığını denetlemesine izin verir."</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"donanımı test et"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Uygulamanın donanım testi için çeşitli çevre birimlerini denetlemesine izin verir."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"telefon numaralarını doğrudan ara"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Uygulamanın müdahaleniz olmadan telefon numaralarını aramasına izin verir. Kötü amaçlı uygulamalar, telefon faturanızda beklenmedik görüşmeler çıkmasına neden olabilir. Bu işlev, uygulamanın acil numara aramasına izin vermez."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"herhangi bir telefon numarasını doğrudan ara"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Uygulamanın, siz müdahale etmeden acil numaralar dahil herhangi bir numarayı aramasına izin verir. Kötü amaçlı uygulamalar acil servisleri gereksiz yere ve yasal olmayan şekilde arayabilir."</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"konum güncelleme bildirimlerini denetle"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"Radyo ile alınan konum güncelleme bildirimlerini etkinleştirmeye/devreden çıkarmaya izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"erişim giriş özellikleri"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"Kayıt hizmeti tarafından karşıya yüklenen özelliklere okuma/yazma erişimi verir. Normal uygulamalarda kullanılmamalıdır."</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"widget seç"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Uygulamaların sisteme hangi uygulamalar tarafından hangi widget\'ların kullanılabileceğini söylemesine izin verir. Bu izin sayesinde uygulamalar, başka uygulamalara kişisel verilere erişim verebilir. Normal uygulamalarda kullanılmaz."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"telefon durumunu deÄŸiÅŸtir"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Uygulamaların cihazın telefon özelliklerini kullanmasına izin verir. Bu izne sahip bir uygulama, size bildirmeden ağ değiştirebilir ve telefon radyosunu kapatıp açabilir."</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"telefonunun uykuya geçmesini önle"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Uygulamaların telefonun uykuya geçmesini önlemesine izin verir."</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"telefonu aç veya kapat"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Uygulamaların telefonunuzu açmasına veya kapatmasına izin verir."</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"fabrika test modunda çalıştır"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Telefon donanımına tam erişim veren alt düzey bir üretici testi olarak çalıştırılır. Yalnızca telefon üretici test modunda çalışırken kullanılabilir."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"duvar kağıdını ayarla"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Uygulamanın sistem duvar kağıdını ayarlamasına izin verir."</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"duvar kağıdı boyutu ipuçlarını ayarla"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Uygulamanın sistem duvar kağıdı boyutu ipuçlarını ayarlamasına izin verir."</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"sistemi fabrika değerlerine sıfırla"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Uygulamanın, sistemi tamamen fabrika ayarlarına sıfırlamasına; verileri, yapılandırmayı ve yüklü uygulamaları silmesine izin verir."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"saat dilimini ayarla"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Uygulamaların telefonun saat dilimini değiştirmesine izin verir."</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"bilinen hesapları keşfet"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Uygulamaların telefonda bilinen hesapların listesini almasına izin verir."</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"ağ durumunu görüntüle"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Uygulamaların, tüm ağların durumunu görmesine izin verir."</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"tam Ä°nternet eriÅŸimi"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Uygulamaların ağ yuvaları oluşturmasına izin verir."</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"Erişim Noktası Adı ayarlarını yaz"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Uygulamaların herhangi bir APN\'nin Proxy ve Bağlantı Noktası gibi APN ayarlarını değiştirmesine izin verir."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"ağ bağlantısını değiştir"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"Uygulamaların ağ bağlantı durumunu değiştirmesine izin verir."</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"arka plan veri kullanımı ayarını değiştir"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Uygulamaların arka plan veri kullanımı ayarını değiştirmesine izin verir."</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"Kablosuz durumunu görüntüle"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Uygulamaların, kablosuz bağlantının durumu ile ilgili bilgileri görüntülemesine izin verir."</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"Kablosuz durumunu deÄŸiÅŸtir"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Uygulamaların kablosuz erişim noktalarına bağlanıp bunlarla bağlantısını kesmesine ve yapılandırılmış kablosuz ağlarda değişiklikler yapmasına izin verir."</string>
+ <string name="permlab_accessFineLocation">"iyi (GPS) konum"</string>
+ <string name="permdesc_accessFineLocation">"Bulunduğu yerlerde telefondan Küresel Konumlandırma Sistemi gibi hassas konum bulma kaynaklarına erişin. Kötü amaçlı uygulamalar bu işlevi bulunduğunuz yeri belirlemek için kullanabilir ve ek pil gücü tüketebilir."</string>
+ <string name="permlab_accessCoarseLocation">"kesinliksiz (ağ tabanlı) konum"</string>
+ <string name="permdesc_accessCoarseLocation">"Telefonun yaklaşık yerini belirlemek için bulunduğu yerlerde hücresel ağ veritabanı gibi tahmini konum kaynaklarına erişir. Kötü amaçlı uygulamalar, bu işlevi bulunduğunuz yeri yaklaşık olarak belirlemek için kullanabilir."</string>
+ <string name="permlab_accessSurfaceFlinger">"SurfaceFlinger\'a eriÅŸ"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Uygulamanın SurfaceFlinger alt düzey özelliklerini kullanmasına izin verir."</string>
+ <string name="permlab_readFrameBuffer">"çerçeve arabelleğini oku"</string>
+ <string name="permdesc_readFrameBuffer">"Kullanılacak uygulamanın çerçeve arabelleğinin içeriğini okumasına izin verir."</string>
+ <string name="permlab_modifyAudioSettings">"ses ayarlarınızı değiştirin"</string>
+ <string name="permdesc_modifyAudioSettings">"Uygulamaların, ses düzeyi ve yönlendirme gibi genel ses ayarlarını değiştirmesine izin verir."</string>
+ <string name="permlab_recordAudio">"ses kaydet"</string>
+ <string name="permdesc_recordAudio">"Uygulamanın, ses kayıt yoluna erişmesine izin verir."</string>
+ <string name="permlab_camera">"resim çek"</string>
+ <string name="permdesc_camera">"Uygulamaların kamera ile resim çekmesine izin verir. Bu işlev herhangi bir zamanda kameranın görmekte olduğu görüntüyü uygulamaların toplamasına izin verir."</string>
+ <string name="permlab_brick">"telefonu tamamen devre dışı bırak"</string>
+ <string name="permdesc_brick">"Uygulamaların tüm telefonu kalıcı olarak devre dışı bırakmasına izin verir. Bu çok tehlikelidir."</string>
+ <string name="permlab_reboot">"telefonu yeniden baÅŸlamaya zorla"</string>
+ <string name="permdesc_reboot">"Uygulamanın telefonu yeniden açılmaya zorlamasına izin verir."</string>
+ <string name="permlab_mount_unmount_filesystems">"dosya sistemlerini bağlama ve bağlantısını kesme"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Uygulamaların çıkarılabilir depolama birimleri için dosya sistemleri ile bağlantı kurmasına ve bağlantıyı kesmesine izin verir."</string>
+ <string name="permlab_mount_format_filesystems">"harici depolama birimini biçimlendir"</string>
+ <string name="permdesc_mount_format_filesystems">"Uygulamanın çıkarılabilir depolama birimini biçimlendirmesine izin verir."</string>
+ <string name="permlab_vibrate">"titreÅŸimi denetle"</string>
+ <string name="permdesc_vibrate">"Uygulamanın titreşimi denetlemesine izin verir."</string>
+ <string name="permlab_flashlight">"flaşı denetle"</string>
+ <string name="permdesc_flashlight">"Uygulamaların flaş ışığını denetlemesine izin verir."</string>
+ <string name="permlab_hardware_test">"donanımı test et"</string>
+ <string name="permdesc_hardware_test">"Uygulamanın donanım testi için çeşitli çevre birimlerini denetlemesine izin verir."</string>
+ <string name="permlab_callPhone">"telefon numaralarını doğrudan ara"</string>
+ <string name="permdesc_callPhone">"Uygulamanın müdahaleniz olmadan telefon numaralarını aramasına izin verir. Kötü amaçlı uygulamalar, telefon faturanızda beklenmedik görüşmeler çıkmasına neden olabilir. Bu işlev, uygulamanın acil numara aramasına izin vermez."</string>
+ <string name="permlab_callPrivileged">"herhangi bir telefon numarasını doğrudan ara"</string>
+ <string name="permdesc_callPrivileged">"Uygulamanın, siz müdahale etmeden acil numaralar dahil herhangi bir numarayı aramasına izin verir. Kötü amaçlı uygulamalar acil servisleri gereksiz yere ve yasal olmayan şekilde arayabilir."</string>
+ <string name="permlab_locationUpdates">"konum güncelleme bildirimlerini denetle"</string>
+ <string name="permdesc_locationUpdates">"Radyo ile alınan konum güncelleme bildirimlerini etkinleştirmeye/devreden çıkarmaya izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
+ <string name="permlab_checkinProperties">"erişim giriş özellikleri"</string>
+ <string name="permdesc_checkinProperties">"Kayıt hizmeti tarafından karşıya yüklenen özelliklere okuma/yazma erişimi verir. Normal uygulamalarda kullanılmamalıdır."</string>
+ <string name="permlab_bindGadget">"widget seç"</string>
+ <string name="permdesc_bindGadget">"Uygulamaların sisteme hangi uygulamalar tarafından hangi widget\'ların kullanılabileceğini söylemesine izin verir. Bu izin sayesinde uygulamalar, başka uygulamalara kişisel verilere erişim verebilir. Normal uygulamalarda kullanılmaz."</string>
+ <string name="permlab_modifyPhoneState">"telefon durumunu deÄŸiÅŸtir"</string>
+ <string name="permdesc_modifyPhoneState">"Uygulamaların cihazın telefon özelliklerini kullanmasına izin verir. Bu izne sahip bir uygulama, size bildirmeden ağ değiştirebilir ve telefon radyosunu kapatıp açabilir."</string>
+ <string name="permlab_readPhoneState">"telefon durumunu oku"</string>
+ <string name="permdesc_readPhoneState">"Uygulamaların cihazın telefon özelliklerine erişmesine izin verir. Bu izne sahip bir uygulama telefonun telefon numarasını, o anda bir çağrı sürmekte olup olmadığını, çağrının bağlanmış olduğu numarayı ve benzerini belirleyebilir."</string>
+ <string name="permlab_wakeLock">"telefonunun uykuya geçmesini önle"</string>
+ <string name="permdesc_wakeLock">"Uygulamaların telefonun uykuya geçmesini önlemesine izin verir."</string>
+ <string name="permlab_devicePower">"telefonu aç veya kapat"</string>
+ <string name="permdesc_devicePower">"Uygulamaların telefonunuzu açmasına veya kapatmasına izin verir."</string>
+ <string name="permlab_factoryTest">"fabrika test modunda çalıştır"</string>
+ <string name="permdesc_factoryTest">"Telefon donanımına tam erişim veren alt düzey bir üretici testi olarak çalıştırılır. Yalnızca telefon üretici test modunda çalışırken kullanılabilir."</string>
+ <string name="permlab_setWallpaper">"duvar kağıdını ayarla"</string>
+ <string name="permdesc_setWallpaper">"Uygulamanın sistem duvar kağıdını ayarlamasına izin verir."</string>
+ <string name="permlab_setWallpaperHints">"duvar kağıdı boyutu ipuçlarını ayarla"</string>
+ <string name="permdesc_setWallpaperHints">"Uygulamanın sistem duvar kağıdı boyutu ipuçlarını ayarlamasına izin verir."</string>
+ <string name="permlab_masterClear">"sistemi fabrika değerlerine sıfırla"</string>
+ <string name="permdesc_masterClear">"Uygulamanın, sistemi tamamen fabrika ayarlarına sıfırlamasına; verileri, yapılandırmayı ve yüklü uygulamaları silmesine izin verir."</string>
+ <string name="permlab_setTimeZone">"saat dilimini ayarla"</string>
+ <string name="permdesc_setTimeZone">"Uygulamaların telefonun saat dilimini değiştirmesine izin verir."</string>
+ <string name="permlab_getAccounts">"bilinen hesapları keşfet"</string>
+ <string name="permdesc_getAccounts">"Uygulamaların telefonda bilinen hesapların listesini almasına izin verir."</string>
+ <string name="permlab_accessNetworkState">"ağ durumunu görüntüle"</string>
+ <string name="permdesc_accessNetworkState">"Uygulamaların, tüm ağların durumunu görmesine izin verir."</string>
+ <string name="permlab_createNetworkSockets">"tam Ä°nternet eriÅŸimi"</string>
+ <string name="permdesc_createNetworkSockets">"Uygulamaların ağ yuvaları oluşturmasına izin verir."</string>
+ <string name="permlab_writeApnSettings">"Erişim Noktası Adı ayarlarını yaz"</string>
+ <string name="permdesc_writeApnSettings">"Uygulamaların herhangi bir APN\'nin Proxy ve Bağlantı Noktası gibi APN ayarlarını değiştirmesine izin verir."</string>
+ <string name="permlab_changeNetworkState">"ağ bağlantısını değiştir"</string>
+ <string name="permdesc_changeNetworkState">"Uygulamaların ağ bağlantı durumunu değiştirmesine izin verir."</string>
+ <string name="permlab_changeBackgroundDataSetting">"arka plan veri kullanımı ayarını değiştir"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Uygulamaların arka plan veri kullanımı ayarını değiştirmesine izin verir."</string>
+ <string name="permlab_accessWifiState">"Kablosuz durumunu görüntüle"</string>
+ <string name="permdesc_accessWifiState">"Uygulamaların, kablosuz bağlantının durumu ile ilgili bilgileri görüntülemesine izin verir."</string>
+ <string name="permlab_changeWifiState">"Kablosuz durumunu deÄŸiÅŸtir"</string>
+ <string name="permdesc_changeWifiState">"Uygulamaların kablosuz erişim noktalarına bağlanıp bunlarla bağlantısını kesmesine ve yapılandırılmış kablosuz ağlarda değişiklikler yapmasına izin verir."</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth yönetimi"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Uygulamaların yerel Bluetooth telefonunu yapılandırmasına ve uzak cihazları keşfedip bunlar ile eşleşmesine izin verir."</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth bağlantıları oluştur"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Uygulamaların yerel Bluetooth telefonunun yapılandırmasını görüntülemesine ve eşleşilmiş cihazlar ile bağlantı kurup kabul etmesine izin verir."</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"tuş kilidini devre dışı bırak"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Uygulamaların tuş kilidini ve ilgili şifreli güvenlik önlemini devre dışı bırakmasına izin verir. Bunun geçerli bir örneği gelen bir çağrı alındığında tuş kilidinin devre dışı bırakılması, sonra çağrı bittiğinde kilidin yeniden devreye sokulmasıdır."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"senk. ayarlarını oku"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Uygulamanın, senkronizasyon işlevinin Kişiler için devrede olup olmadığı gibi senkronizasyon ayarlarını okumasına izin verir."</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"senk. ayarlarını yaz"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Uygulamanın, senkronizasyon işlevinin Kişiler için devrede olup olmadığı gibi senkronizasyon ayarlarını değiştirmesine izin verir."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"senk. istatistiklerini oku"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Uygulamaların senk. istatistiklerini; örn. geçmişte yapılmış senkronizasyonları okumasına izin verir."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"abone olunan yayınları oku"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Uygulamaların, o anda senkronize olan yayınlar ile ilgili bilgi almasına izin verir."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"abone olunan yayınları yaz"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Uygulamaların senkronize edilmiş yayınlarınızı değiştirmesine izin verir. Bu ayar, kötü amaçlı bir uygulamanın senkronize edilmiş yayınlarınızı değiştirmesine izin verebilir."</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"kullanıcı tanımlı sözlüğü oku"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Kullanıcının kullanıcı sözlüğünde depolamış olabileceği kişisel kelimeleri, adları ve kelime öbeklerini uygulamaların okumasına izin verir."</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"kullanıcı tanımlı sözlüğe yaz"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Uygulamaların kullanıcı sözlüğüne yeni kelimeler yazmasına izin verir."</string>
+ <string name="permlab_bluetoothAdmin">"bluetooth yönetimi"</string>
+ <string name="permdesc_bluetoothAdmin">"Uygulamaların yerel Bluetooth telefonunu yapılandırmasına ve uzak cihazları keşfedip bunlar ile eşleşmesine izin verir."</string>
+ <string name="permlab_bluetooth">"Bluetooth bağlantıları oluştur"</string>
+ <string name="permdesc_bluetooth">"Uygulamaların yerel Bluetooth telefonunun yapılandırmasını görüntülemesine ve eşleşilmiş cihazlar ile bağlantı kurup kabul etmesine izin verir."</string>
+ <string name="permlab_disableKeyguard">"tuş kilidini devre dışı bırak"</string>
+ <string name="permdesc_disableKeyguard">"Uygulamaların tuş kilidini ve ilgili şifreli güvenlik önlemini devre dışı bırakmasına izin verir. Bunun geçerli bir örneği gelen bir çağrı alındığında tuş kilidinin devre dışı bırakılması, sonra çağrı bittiğinde kilidin yeniden devreye sokulmasıdır."</string>
+ <string name="permlab_readSyncSettings">"senk. ayarlarını oku"</string>
+ <string name="permdesc_readSyncSettings">"Uygulamanın, senkronizasyon işlevinin Kişiler için devrede olup olmadığı gibi senkronizasyon ayarlarını okumasına izin verir."</string>
+ <string name="permlab_writeSyncSettings">"senk. ayarlarını yaz"</string>
+ <string name="permdesc_writeSyncSettings">"Uygulamanın, senkronizasyon işlevinin Kişiler için devrede olup olmadığı gibi senkronizasyon ayarlarını değiştirmesine izin verir."</string>
+ <string name="permlab_readSyncStats">"senk. istatistiklerini oku"</string>
+ <string name="permdesc_readSyncStats">"Uygulamaların senk. istatistiklerini; örn. geçmişte yapılmış senkronizasyonları okumasına izin verir."</string>
+ <string name="permlab_subscribedFeedsRead">"abone olunan yayınları oku"</string>
+ <string name="permdesc_subscribedFeedsRead">"Uygulamaların, o anda senkronize olan yayınlar ile ilgili bilgi almasına izin verir."</string>
+ <string name="permlab_subscribedFeedsWrite">"abone olunan yayınları yaz"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Uygulamaların senkronize edilmiş yayınlarınızı değiştirmesine izin verir. Bu ayar, kötü amaçlı bir uygulamanın senkronize edilmiş yayınlarınızı değiştirmesine izin verebilir."</string>
+ <string name="permlab_readDictionary">"kullanıcı tanımlı sözlüğü oku"</string>
+ <string name="permdesc_readDictionary">"Kullanıcının kullanıcı sözlüğünde depolamış olabileceği kişisel kelimeleri, adları ve kelime öbeklerini uygulamaların okumasına izin verir."</string>
+ <string name="permlab_writeDictionary">"kullanıcı tanımlı sözlüğe yaz"</string>
+ <string name="permdesc_writeDictionary">"Uygulamaların kullanıcı sözlüğüne yeni kelimeler yazmasına izin verir."</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Ev"</item>
- <item msgid="869923650527136615">"Mobil"</item>
- <item msgid="7897544654242874543">"Ä°ÅŸ"</item>
- <item msgid="1103601433382158155">"Ä°ÅŸ Faks"</item>
- <item msgid="1735177144948329370">"Ev Faks"</item>
- <item msgid="603878674477207394">"Çağrı cihazı"</item>
- <item msgid="1650824275177931637">"DiÄŸer"</item>
- <item msgid="9192514806975898961">"Özel"</item>
+ <item>"Ev"</item>
+ <item>"Mobil"</item>
+ <item>"Ä°ÅŸ"</item>
+ <item>"Ä°ÅŸ Faks"</item>
+ <item>"Ev Faks"</item>
+ <item>"Çağrı cihazı"</item>
+ <item>"DiÄŸer"</item>
+ <item>"Özel"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Ev"</item>
- <item msgid="7084237356602625604">"Ä°ÅŸ"</item>
- <item msgid="1112044410659011023">"DiÄŸer"</item>
- <item msgid="2374913952870110618">"Özel"</item>
+ <item>"Ev"</item>
+ <item>"Ä°ÅŸ"</item>
+ <item>"DiÄŸer"</item>
+ <item>"Özel"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"Mobil"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"Ev"</item>
- <item msgid="5629153956045109251">"Ä°ÅŸ"</item>
- <item msgid="4966604264500343469">"DiÄŸer"</item>
- <item msgid="4932682847595299369">"Özel"</item>
+ <item>"Ev"</item>
+ <item>"Ä°ÅŸ"</item>
+ <item>"DiÄŸer"</item>
+ <item>"Özel"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Ev"</item>
- <item msgid="1359644565647383708">"Ä°ÅŸ"</item>
- <item msgid="7868549401053615677">"DiÄŸer"</item>
- <item msgid="3145118944639869809">"Özel"</item>
+ <item>"Ev"</item>
+ <item>"Ä°ÅŸ"</item>
+ <item>"DiÄŸer"</item>
+ <item>"Özel"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"Ä°ÅŸ"</item>
- <item msgid="4378074129049520373">"DiÄŸer"</item>
- <item msgid="3455047468583965104">"Özel"</item>
+ <item>"Ä°ÅŸ"</item>
+ <item>"DiÄŸer"</item>
+ <item>"Özel"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"PIN kodunu gir"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Yanlış PIN kodu!"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Kilidi açmak için önce Menü\'ye, sonra 0\'a basın."</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Acil durum numarası"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Hizmet yok)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran kilitli."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Kilidi açmak veya acil çağrı yapmak için Menü\'ye basın."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Kilidi açmak için Menü\'ye basın."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Kilit açmak için deseni çizin"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Acil durum çağrısı"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"DoÄŸru!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Üzgünüz, lütfen yeniden deneyin"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"Åžarj oluyor (<xliff:g id="PERCENT">%%</xliff:g><xliff:g id="NUMBER">%d</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"PIN kodunu gir"</string>
+ <string name="keyguard_password_wrong_pin_code">"Yanlış PIN kodu!"</string>
+ <string name="keyguard_label_text">"Kilidi açmak için önce Menü\'ye, sonra 0\'a basın."</string>
+ <string name="emergency_call_dialog_number_for_display">"Acil durum numarası"</string>
+ <string name="lockscreen_carrier_default">"(Hizmet yok)"</string>
+ <string name="lockscreen_screen_locked">"Ekran kilitli."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Kilidi açmak veya acil çağrı yapmak için Menü\'ye basın."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Kilidi açmak için Menü\'ye basın."</string>
+ <string name="lockscreen_pattern_instructions">"Kilit açmak için deseni çizin"</string>
+ <string name="lockscreen_emergency_call">"Acil durum çağrısı"</string>
+ <string name="lockscreen_pattern_correct">"DoÄŸru!"</string>
+ <string name="lockscreen_pattern_wrong">"Üzgünüz, lütfen yeniden deneyin"</string>
+ <string name="lockscreen_plugged_in">"Åžarj oluyor (<xliff:g id="PERCENT">%%</xliff:g><xliff:g id="NUMBER">%d</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"Şarj cihazınızı bağlayın."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"SIM kart yok."</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"Telefonda SIM kart yok."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Lütfen SIM kart takın."</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"AÄŸ kilitli"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM kart PUK kilidi devrede."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Lütfen Kullanıcı Rehberi\'ne bakın veya Müşteri Hizmetleri\'ne başvurun."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kart kilitli."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM kart kilidi açılıyor…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. "\n\n"Lütfen <xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde yeniden deneyin."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu Google oturum açma bilgilerinizi kullanarak açmanız istenir."\n\n" Lütfen <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde yeniden deneyin."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde yeniden deneyin."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Deseni unuttunuz mu?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Çok fazla sayıda desen denemesi yapıldı!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Kilidi açmak için Google hesabınızla oturum açın"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Kullanıcı adı (e-posta)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Åžifre"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Oturum aç"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Geçersiz kullanıcı adı veya şifre."</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
+ <string name="lockscreen_low_battery">"Şarj cihazınızı bağlayın."</string>
+ <string name="lockscreen_missing_sim_message_short">"SIM kart yok."</string>
+ <string name="lockscreen_missing_sim_message">"Telefonda SIM kart yok."</string>
+ <string name="lockscreen_missing_sim_instructions">"Lütfen SIM kart takın."</string>
+ <string name="lockscreen_network_locked_message">"AÄŸ kilitli"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM kart PUK kilidi devrede."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Lütfen Kullanıcı Rehberi\'ne bakın veya Müşteri Hizmetleri\'ne başvurun."</string>
+ <string name="lockscreen_sim_locked_message">"SIM kart kilitli."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM kart kilidi açılıyor…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. "\n\n"Lütfen <xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu Google oturum açma bilgilerinizi kullanarak açmanız istenir."\n\n" Lütfen <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Deseni unuttunuz mu?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Çok fazla sayıda desen denemesi yapıldı!"</string>
+ <string name="lockscreen_glogin_instructions">"Kilidi açmak için Google hesabınızla oturum açın"</string>
+ <string name="lockscreen_glogin_username_hint">"Kullanıcı adı (e-posta)"</string>
+ <string name="lockscreen_glogin_password_hint">"Åžifre"</string>
+ <string name="lockscreen_glogin_submit_button">"Oturum aç"</string>
+ <string name="lockscreen_glogin_invalid_input">"Geçersiz kullanıcı adı veya şifre."</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g> <xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bildirim yok"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sürüyor"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirimler"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"Şarj oluyor…"</string>
- <string name="battery_low_title" msgid="7923774589611311406">"Lütfen şarj cihazını takın"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"Pil tükeniyor:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"<xliff:g id="NUMBER">%d%%</xliff:g> adetten daha az kaldı."</string>
+ <string name="status_bar_no_notifications_title">"Bildirim yok"</string>
+ <string name="status_bar_ongoing_events_title">"Sürüyor"</string>
+ <string name="status_bar_latest_events_title">"Bildirimler"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"Şarj oluyor…"</string>
+ <string name="battery_low_title">"Lütfen şarj cihazını takın"</string>
+ <string name="battery_low_subtitle">"Pil tükeniyor:"</string>
+ <string name="battery_low_percent_format">"<xliff:g id="NUMBER">%d%%</xliff:g> adetten daha az kaldı."</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"Fabrika testi yapılamadı"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"FACTORY_TEST işlemi yalnızca /system/app dizinine yüklenmiş paketler için desteklenir."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"FACTORY_TEST işlemini sağlayan hiçbir paket bulunamadı."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Yeniden baÅŸlat"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"\"<xliff:g id="TITLE">%s</xliff:g>\" adresindeki sayfada ÅŸunlar belirtiliyor:"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"Bu sayfadan ayrılıyor musunuz?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Devam etmek için Tamam\'ı, sayfada kalmak için İptal\'i tıklatın."</string>
- <string name="save_password_label" msgid="6860261758665825069">"Onayla"</string>
+ <string name="factorytest_failed">"Fabrika testi yapılamadı"</string>
+ <string name="factorytest_not_system">"FACTORY_TEST işlemi yalnızca /system/app dizinine yüklenmiş paketler için desteklenir."</string>
+ <string name="factorytest_no_action">"FACTORY_TEST işlemini sağlayan hiçbir paket bulunamadı."</string>
+ <string name="factorytest_reboot">"Yeniden baÅŸlat"</string>
+ <string name="js_dialog_title">"\"<xliff:g id="TITLE">%s</xliff:g>\" adresindeki sayfada ÅŸunlar belirtiliyor:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Bu sayfadan ayrılıyor musunuz?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Devam etmek için Tamam\'ı, sayfada kalmak için İptal\'i tıklatın."</string>
+ <string name="save_password_label">"Onayla"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"Tarayıcının bu şifreyi anımsamasını istiyor musunuz?"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"Åžimdi deÄŸil"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"Anımsa"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Hiçbir zaman"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"Bu sayfayı açma izniniz yok."</string>
- <string name="text_copied" msgid="4985729524670131385">"Metin panoya kopyalandı."</string>
- <string name="more_item_label" msgid="4650918923083320495">"DiÄŸer"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menü+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"boÅŸluk"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"gir"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"sil"</string>
- <string name="search_go" msgid="8298016669822141719">"Ara"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ay önce"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ay önce"</string>
+ <string name="save_password_message">"Tarayıcının bu şifreyi anımsamasını istiyor musunuz?"</string>
+ <string name="save_password_notnow">"Åžimdi deÄŸil"</string>
+ <string name="save_password_remember">"Anımsa"</string>
+ <string name="save_password_never">"Hiçbir zaman"</string>
+ <string name="open_permission_deny">"Bu sayfayı açma izniniz yok."</string>
+ <string name="text_copied">"Metin panoya kopyalandı."</string>
+ <string name="more_item_label">"DiÄŸer"</string>
+ <string name="prepend_shortcut_label">"Menü+"</string>
+ <string name="menu_space_shortcut_label">"boÅŸluk"</string>
+ <string name="menu_enter_shortcut_label">"gir"</string>
+ <string name="menu_delete_shortcut_label">"sil"</string>
+ <string name="search_go">"Ara"</string>
+ <string name="oneMonthDurationPast">"1 ay önce"</string>
+ <string name="beforeOneMonthDurationPast">"1 ay önce"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 saniye önce"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
+ <item quantity="one">"1 saniye önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 dakika önce"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
+ <item quantity="one">"1 dakika önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 saat önce"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
+ <item quantity="one">"1 saat önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"dün"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
+ <item quantity="one">"dün"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 saniye içinde"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
+ <item quantity="one">"1 saniye içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 dakika içinde"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
+ <item quantity="one">"1 dakika içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 saat içinde"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
+ <item quantity="one">"1 saat içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"yarın"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
+ <item quantity="one">"yarın"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 saniye önce"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
+ <item quantity="one">"1 saniye önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 dak. önce"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
+ <item quantity="one">"1 dak. önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 saat önce"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
+ <item quantity="one">"1 saat önce"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"dün"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
+ <item quantity="one">"dün"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 san. içinde"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
+ <item quantity="one">"1 san. içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 dak. içinde"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
+ <item quantity="one">"1 dak. içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 saat içinde"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
+ <item quantity="one">"1 saat içinde"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"yarın"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
+ <item quantity="one">"yarın"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s üzerinde"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"saat: %s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s içinde"</string>
- <string name="day" msgid="8144195776058119424">"gün"</string>
- <string name="days" msgid="4774547661021344602">"gün"</string>
- <string name="hour" msgid="2126771916426189481">"saat"</string>
- <string name="hours" msgid="894424005266852993">"saat"</string>
- <string name="minute" msgid="9148878657703769868">"dak"</string>
- <string name="minutes" msgid="5646001005827034509">"dakika"</string>
- <string name="second" msgid="3184235808021478">"san."</string>
- <string name="seconds" msgid="3161515347216589235">"saniye"</string>
- <string name="week" msgid="5617961537173061583">"hafta"</string>
- <string name="weeks" msgid="6509623834583944518">"hafta"</string>
- <string name="year" msgid="4001118221013892076">"yıl"</string>
- <string name="years" msgid="6881577717993213522">"yıl"</string>
- <string name="every_weekday" msgid="8777593878457748503">"Hafta içi her gün (Pzt-Cum)"</string>
- <string name="daily" msgid="5738949095624133403">"Her gün"</string>
- <string name="weekly" msgid="983428358394268344">"Her hafta <xliff:g id="DAY">%s</xliff:g> günü"</string>
- <string name="monthly" msgid="2667202947170988834">"Aylık"</string>
- <string name="yearly" msgid="1519577999407493836">"Yılda bir"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"Video oynatılamıyor"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"Maalesef, bu video cihaza akışla göndermek için uygun değil."</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"Maalesef bu video oynatılamıyor."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"Tamam"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"öğle"</string>
- <string name="Noon" msgid="3342127745230013127">"Öğle"</string>
- <string name="midnight" msgid="7166259508850457595">"geceyarısı"</string>
- <string name="Midnight" msgid="5630806906897892201">"Gece Yarısı"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Tümünü seç"</string>
- <string name="selectText" msgid="3889149123626888637">"Metni seç"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Metin seçmeyi durdur"</string>
- <string name="cut" msgid="3092569408438626261">"Kes"</string>
- <string name="cutAll" msgid="2436383270024931639">"Tümünü kes"</string>
- <string name="copy" msgid="2681946229533511987">"Kopyala"</string>
- <string name="copyAll" msgid="2590829068100113057">"Tümünü kopyala"</string>
- <string name="paste" msgid="5629880836805036433">"Yapıştır"</string>
- <string name="copyUrl" msgid="2538211579596067402">"URL\'yi kopyala"</string>
- <string name="inputMethod" msgid="7673923508389094672">"Giriş Yöntemi"</string>
- <string name="addToDictionary" msgid="726256909274177272">"\"%s\" kelimesini sözlüğe ekle"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"Metin düzenle"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Yer az"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Telefonun depolama alanı azalıyor."</string>
- <string name="ok" msgid="5970060430562524910">"Tamam"</string>
- <string name="cancel" msgid="6442560571259935130">"Ä°ptal"</string>
- <string name="yes" msgid="5362982303337969312">"Tamam"</string>
- <string name="no" msgid="5141531044935541497">"Ä°ptal"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"Dikkat"</string>
- <string name="capital_on" msgid="1544682755514494298">"AÇIK"</string>
- <string name="capital_off" msgid="6815870386972805832">"KAPALI"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Ä°ÅŸlemi ÅŸunu kullanarak tamamla"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Varsayılan olarak bu işlem için kullan."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Giriş Ayarları &gt; Uygulamalar &gt; Uygulamaları yönet\'te varsayılanı temizleyin."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"İşlem seç"</string>
- <string name="noApplications" msgid="1691104391758345586">"Hiçbir uygulama bu işlemi yapamaz."</string>
- <string name="aerr_title" msgid="653922989522758100">"Üzgünüz!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) beklenmedik biçimde durdu. Lütfen yeniden deneyin."</string>
- <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi beklenmedik biçimde durdu. Lütfen yeniden deneyin."</string>
- <string name="anr_title" msgid="3100070910664756057">"Üzgünüz!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="ACTIVITY">%1$s</xliff:g> etkinliği (<xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasında) yanıt vermiyor."</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g> etkinliği (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
- <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi yanıt vermiyor."</string>
- <string name="force_close" msgid="3653416315450806396">"Kapanmaya zorla"</string>
+ <string name="preposition_for_date">"%s üzerinde"</string>
+ <string name="preposition_for_time">"saat: %s"</string>
+ <string name="preposition_for_year">"%s içinde"</string>
+ <string name="day">"gün"</string>
+ <string name="days">"gün"</string>
+ <string name="hour">"saat"</string>
+ <string name="hours">"saat"</string>
+ <string name="minute">"dak"</string>
+ <string name="minutes">"dakika"</string>
+ <string name="second">"san."</string>
+ <string name="seconds">"saniye"</string>
+ <string name="week">"hafta"</string>
+ <string name="weeks">"hafta"</string>
+ <string name="year">"yıl"</string>
+ <string name="years">"yıl"</string>
+ <string name="every_weekday">"Hafta içi her gün (Pzt-Cum)"</string>
+ <string name="daily">"Günlük"</string>
+ <string name="weekly">"Her hafta <xliff:g id="DAY">%s</xliff:g> günü"</string>
+ <string name="monthly">"Aylık"</string>
+ <string name="yearly">"Yılda bir"</string>
+ <string name="VideoView_error_title">"Video oynatılamıyor"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"Maalesef, bu video cihaza akışla göndermek için uygun değil."</string>
+ <string name="VideoView_error_text_unknown">"Maalesef bu video oynatılamıyor."</string>
+ <string name="VideoView_error_button">"Tamam"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"öğle"</string>
+ <string name="Noon">"Öğle"</string>
+ <string name="midnight">"geceyarısı"</string>
+ <string name="Midnight">"Gece Yarısı"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Tümünü seç"</string>
+ <string name="selectText">"Metni seç"</string>
+ <string name="stopSelectingText">"Metin seçmeyi durdur"</string>
+ <string name="cut">"Kes"</string>
+ <string name="cutAll">"Tümünü kes"</string>
+ <string name="copy">"Kopyala"</string>
+ <string name="copyAll">"Tümünü kopyala"</string>
+ <string name="paste">"Yapıştır"</string>
+ <string name="copyUrl">"URL\'yi kopyala"</string>
+ <string name="inputMethod">"Giriş Yöntemi"</string>
+ <string name="addToDictionary">"\"%s\" kelimesini sözlüğe ekle"</string>
+ <string name="editTextMenuTitle">"Metin düzenle"</string>
+ <string name="low_internal_storage_view_title">"Yer az"</string>
+ <string name="low_internal_storage_view_text">"Telefonun depolama alanı azalıyor."</string>
+ <string name="ok">"Tamam"</string>
+ <string name="cancel">"Ä°ptal"</string>
+ <string name="yes">"Tamam"</string>
+ <string name="no">"Ä°ptal"</string>
+ <string name="dialog_alert_title">"Dikkat"</string>
+ <string name="capital_on">"AÇIK"</string>
+ <string name="capital_off">"KAPALI"</string>
+ <string name="whichApplication">"Ä°ÅŸlemi ÅŸunu kullanarak tamamla"</string>
+ <string name="alwaysUse">"Varsayılan olarak bu işlem için kullan."</string>
+ <string name="clearDefaultHintMsg">"Giriş Ayarları &gt; Uygulamalar &gt; Uygulamaları yönet\'te varsayılanı temizleyin."</string>
+ <string name="chooseActivity">"İşlem seç"</string>
+ <string name="noApplications">"Hiçbir uygulama bu işlemi yapamaz."</string>
+ <string name="aerr_title">"Üzgünüz!"</string>
+ <string name="aerr_application">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) beklenmedik biçimde durdu. Lütfen yeniden deneyin."</string>
+ <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi beklenmedik biçimde durdu. Lütfen yeniden deneyin."</string>
+ <string name="anr_title">"Üzgünüz!"</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g> etkinliği (<xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasında) yanıt vermiyor."</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g> etkinliği (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
+ <string name="anr_application_process">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi yanıt vermiyor."</string>
+ <string name="force_close">"Kapanmaya zorla"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"Bekle"</string>
- <string name="debug" msgid="9103374629678531849">"Hata ayıkla"</string>
- <string name="sendText" msgid="5132506121645618310">"Metin için bir işlem seçin"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Zil sesi düzeyi"</string>
- <string name="volume_music" msgid="5421651157138628171">"Medya ses düzeyi"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Bluetooth üzerinden çalıyor"</string>
- <string name="volume_call" msgid="3941680041282788711">"Gelen çağrı ses düzeyi"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetooth gelen çağrı ses düzeyi"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"Alarm ses düzeyi"</string>
- <string name="volume_notification" msgid="2422265656744276715">"Bildirim ses düzeyi"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"Ses"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Varsayılan zil sesi"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Varsayılan zil sesi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"Sessiz"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"Zil sesleri"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"Bilinmeyen zil sesi"</string>
+ <string name="wait">"Bekle"</string>
+ <string name="debug">"Hata ayıkla"</string>
+ <string name="sendText">"Metin için bir işlem seçin"</string>
+ <string name="volume_ringtone">"Zil sesi düzeyi"</string>
+ <string name="volume_music">"Medya ses düzeyi"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Bluetooth üzerinden çalıyor"</string>
+ <string name="volume_call">"Gelen çağrı ses düzeyi"</string>
+ <string name="volume_bluetooth_call">"Bluetooth gelen çağrı ses düzeyi"</string>
+ <string name="volume_alarm">"Alarm ses düzeyi"</string>
+ <string name="volume_notification">"Bildirim ses düzeyi"</string>
+ <string name="volume_unknown">"Ses"</string>
+ <string name="ringtone_default">"Varsayılan zil sesi"</string>
+ <string name="ringtone_default_with_actual">"Varsayılan zil sesi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Sessiz"</string>
+ <string name="ringtone_picker_title">"Zil sesleri"</string>
+ <string name="ringtone_unknown">"Bilinmeyen zil sesi"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Kablosuz aÄŸ var"</item>
- <item quantity="other" msgid="4192424489168397386">"Kablosuz aÄŸlar var"</item>
+ <item quantity="one">"Kablosuz aÄŸ var"</item>
+ <item quantity="other">"Kablosuz aÄŸlar var"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"Kullanılabilir kablosuz ağı aç"</item>
- <item quantity="other" msgid="7915895323644292768">"Kullanılabilir kablosuz ağları aç"</item>
+ <item quantity="one">"Kullanılabilir kablosuz ağı aç"</item>
+ <item quantity="other">"Kullanılabilir kablosuz ağları aç"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"Karakter ekle"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Bilinmeyen uygulama"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"SMS mesajları gönderiliyor"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"Çok sayıda SMS mesajı gönderiliyor. Devam etmek için \"Tamam\"ı, göndermeyi durdurmak için \"İptal\"i seçin."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Tamam"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Ä°ptal"</string>
- <string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"Varsayılan"</string>
- <string name="no_permissions" msgid="7283357728219338112">"Ä°zin gerektirmez"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Gizle"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"Tümünü göster"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"Yükleniyor…"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB bağlandı"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"Telefonunuzu bilgisayarınıza USB ile bağladınız. Bilgisayarınız ve telefonunuzun SD kartı arasında dosya kopyalamak istiyorsanız, \"Bağla\"\'yı seçin."</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"BaÄŸla"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"BaÄŸlama"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"SD kartınızı USB depolama birimi için kullanmada bir sorun var."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB bağlandı"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Bilgisayarınıza/bilgisayarınızdan dosya kopyalamak için seçin."</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB depolama birimini kapat"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"USB depolama birimini kapatmak için seçin."</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"USB depolama birimini kapat"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"USB depolama birimini kapatmadan önce USB ana makinesinde bağlantıyı kestiğinizden emin olun. USB depolama birimini kapatmak için \"Kapat\"ı seçin."</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"Kapat"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"Ä°ptal"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"USB depolama birimini kapatırken bir sorunla karşılaştık. USB ana makinesinde bağlantıyı kestiğinizden emin olun, sonra yeniden deneyin."</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"SD kartı biçimlendir"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"SD kartı biçimlendirmek istediğinizden emin misiniz? Kartınızdaki tüm veriler yok olacak."</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"Biçimlendir"</string>
+ <string name="select_character">"Karakter ekle"</string>
+ <string name="sms_control_default_app_name">"Bilinmeyen uygulama"</string>
+ <string name="sms_control_title">"SMS mesajları gönderme"</string>
+ <string name="sms_control_message">"Çok sayıda SMS mesajı gönderiliyor. Devam etmek için \"Tamam\"ı, göndermeyi durdurmak için \"İptal\"i seçin."</string>
+ <string name="sms_control_yes">"Tamam"</string>
+ <string name="sms_control_no">"Ä°ptal"</string>
+ <string name="date_time_set">"Ayarla"</string>
+ <string name="default_permission_group">"Varsayılan"</string>
+ <string name="no_permissions">"Ä°zin gerektirmez"</string>
+ <string name="perms_hide"><b>"Gizle"</b></string>
+ <string name="perms_show_all"><b>"Tümünü göster"</b></string>
+ <string name="googlewebcontenthelper_loading">"Yükleniyor…"</string>
+ <string name="usb_storage_title">"USB bağlandı"</string>
+ <string name="usb_storage_message">"Telefonunuzu bilgisayarınıza USB ile bağladınız. Bilgisayarınız ve telefonunuzun SD kartı arasında dosya kopyalamak istiyorsanız, \"Bağla\"\'yı seçin."</string>
+ <string name="usb_storage_button_mount">"BaÄŸla"</string>
+ <string name="usb_storage_button_unmount">"BaÄŸlama"</string>
+ <string name="usb_storage_error_message">"SD kartınızı USB depolama birimi için kullanmada bir sorun var."</string>
+ <string name="usb_storage_notification_title">"USB bağlandı"</string>
+ <string name="usb_storage_notification_message">"Bilgisayarınıza/bilgisayarınızdan dosya kopyalamak için seçin."</string>
+ <string name="usb_storage_stop_notification_title">"USB depolama birimini kapat"</string>
+ <string name="usb_storage_stop_notification_message">"USB depolama birimini kapatmak için seçin."</string>
+ <string name="usb_storage_stop_title">"USB depolama birimini kapat"</string>
+ <string name="usb_storage_stop_message">"USB depolama birimini kapatmadan önce USB ana makinesinde bağlantıyı kestiğinizden emin olun. USB depolama birimini kapatmak için \"Kapat\"ı seçin."</string>
+ <string name="usb_storage_stop_button_mount">"Kapat"</string>
+ <string name="usb_storage_stop_button_unmount">"Ä°ptal"</string>
+ <string name="usb_storage_stop_error_message">"USB depolama birimini kapatırken bir sorunla karşılaştık. USB ana makinesinde bağlantıyı kestiğinizden emin olun, sonra yeniden deneyin."</string>
+ <string name="extmedia_format_title">"SD kartı biçimlendir"</string>
+ <string name="extmedia_format_message">"SD kartı biçimlendirmek istediğinizden emin misiniz? Kartınızdaki tüm veriler yok olacak."</string>
+ <string name="extmedia_format_button_format">"Biçimlendir"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"Giriş Yöntemini Seç"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"SD kart hazırlanıyor"</string>
+ <string name="select_input_method">"Giriş Yöntemini Seç"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"adaylar"</u></string>
+ <string name="ext_media_checking_notification_title">"SD kart hazırlanıyor"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"BoÅŸ SD kart"</string>
+ <string name="ext_media_nofs_notification_title">"BoÅŸ SD kart"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"Hasarlı SD kart"</string>
+ <string name="ext_media_unmountable_notification_title">"Hasarlı SD kart"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD kart beklenmedik biçimde çıkarıldı"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"Veri kaybından kaçınmak için SD kartı çıkarmadan önce bağlantısını kesin."</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SD kart güvenle çıkarılabilir"</string>
+ <string name="ext_media_badremoval_notification_title">"SD kart beklenmedik biçimde çıkarıldı"</string>
+ <string name="ext_media_badremoval_notification_message">"Veri kaybından kaçınmak için SD kartı çıkarmadan önce bağlantısını kesin."</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD kart güvenle çıkarılabilir"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"SD kart çıkarılmış"</string>
+ <string name="ext_media_nomedia_notification_title">"SD kart çıkarılmış"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"Eşleşen hiçbir etkinlik bulunamadı"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"bileşen kullanım istatistiklerini güncelle"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Toplanmış bileşen istatistiklerinin değiştirilmesine izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Zum denetimi için iki kez dokun"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Widget\'ı genişletirken hata oluştu"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"Git"</string>
- <string name="ime_action_search" msgid="658110271822807811">"Ara"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"Gönder"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"Ä°leri"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Bitti"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Çalıştır"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"Numarayı çevir:"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>"\n" ile kiÅŸi oluÅŸtur"</string>
+ <string name="activity_list_empty">"Eşleşen hiçbir etkinlik bulunamadı"</string>
+ <string name="permlab_pkgUsageStats">"bileşen kullanım istatistiklerini güncelle"</string>
+ <string name="permdesc_pkgUsageStats">"Toplanmış bileşen istatistiklerinin değiştirilmesine izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Zum denetimi için iki kez dokun"</string>
+ <string name="gadget_host_error_inflating">"Widget\'ı genişletirken hata oluştu"</string>
+ <string name="ime_action_go">"Git"</string>
+ <string name="ime_action_search">"Ara"</string>
+ <string name="ime_action_send">"Gönder"</string>
+ <string name="ime_action_next">"Ä°leri"</string>
+ <string name="ime_action_done">"Bitti"</string>
+ <string name="ime_action_default">"Çalıştır"</string>
+ <string name="dial_number_using">"Numarayı çevir:"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"<xliff:g id="NUMBER">%s</xliff:g>"\n" ile kiÅŸi oluÅŸtur"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index c7eb522..6741b3b 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -15,41 +15,41 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"B"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
<!-- no translation found for fileSizeSuffix (7670819340156489359) -->
<skip />
- <string name="untitled" msgid="6071602020171759109">"&lt;无标题&gt;"</string>
- <string name="ellipsis" msgid="7899829516048813237">"..."</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(无电è¯å·ç ï¼‰"</string>
- <string name="unknownName" msgid="2277556546742746522">"(未知)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"语音信箱"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"出现连接问题或 MMI ç æ— æ•ˆã€‚"</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"æœåŠ¡å·²å¯ç”¨ã€‚"</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"已针对以下内容å¯ç”¨äº†æœåŠ¡ï¼š"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"æœåŠ¡å·²è¢«åœç”¨ã€‚"</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"注册æˆåŠŸã€‚"</string>
- <string name="serviceErased" msgid="1288584695297200972">"清除æˆåŠŸã€‚"</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"密ç ä¸æ­£ç¡®ã€‚"</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI 完æˆã€‚"</string>
- <string name="badPin" msgid="5085454289896032547">"您输入的旧 PIN ä¸æ­£ç¡®ã€‚"</string>
- <string name="badPuk" msgid="5702522162746042460">"您输入的 PUK ä¸æ­£ç¡®ã€‚"</string>
- <string name="mismatchPin" msgid="3695902225843339274">"您输入的 PIN ç ä¸ä¸€è‡´ã€‚"</string>
- <string name="invalidPin" msgid="3850018445187475377">"输入一个 4 至 8 ä½æ•°çš„ PIN。"</string>
- <string name="needPuk" msgid="919668385956251611">"您的 SIM å¡è¢« PUK é”定。请输入 PUK ç è¿›è¡Œè§£é”。"</string>
- <string name="needPuk2" msgid="4526033371987193070">"输入 PUK2 ä»¥è§£é” SIM å¡ã€‚"</string>
- <string name="ClipMmi" msgid="6952821216480289285">"æ¥ç”µæ˜¾ç¤º"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"外拨电è¯æ˜¾ç¤º"</string>
- <string name="CfMmi" msgid="5123218989141573515">"呼å«è½¬æŽ¥"</string>
- <string name="CwMmi" msgid="9129678056795016867">"呼å«ç­‰å¾…"</string>
- <string name="BaMmi" msgid="455193067926770581">"呼å«é™åˆ¶"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"密ç æ›´æ”¹"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN ç æ›´æ”¹"</string>
+ <string name="untitled">"&lt;无标题&gt;"</string>
+ <string name="ellipsis">"..."</string>
+ <string name="emptyPhoneNumber">"(无电è¯å·ç ï¼‰"</string>
+ <string name="unknownName">"(未知)"</string>
+ <string name="defaultVoiceMailAlphaTag">"语音信箱"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"出现连接问题或 MMI ç æ— æ•ˆã€‚"</string>
+ <string name="serviceEnabled">"æœåŠ¡å·²å¯ç”¨ã€‚"</string>
+ <string name="serviceEnabledFor">"已针对以下内容å¯ç”¨äº†æœåŠ¡ï¼š"</string>
+ <string name="serviceDisabled">"æœåŠ¡å·²è¢«åœç”¨ã€‚"</string>
+ <string name="serviceRegistered">"注册æˆåŠŸã€‚"</string>
+ <string name="serviceErased">"清除æˆåŠŸã€‚"</string>
+ <string name="passwordIncorrect">"密ç ä¸æ­£ç¡®ã€‚"</string>
+ <string name="mmiComplete">"MMI 完æˆã€‚"</string>
+ <string name="badPin">"您输入的旧 PIN ä¸æ­£ç¡®ã€‚"</string>
+ <string name="badPuk">"您输入的 PUK ä¸æ­£ç¡®ã€‚"</string>
+ <string name="mismatchPin">"您输入的 PIN ç ä¸ä¸€è‡´ã€‚"</string>
+ <string name="invalidPin">"输入一个 4 至 8 ä½æ•°çš„ PIN。"</string>
+ <string name="needPuk">"您的 SIM å¡è¢« PUK é”定。请输入 PUK ç è¿›è¡Œè§£é”。"</string>
+ <string name="needPuk2">"输入 PUK2 ä»¥è§£é” SIM å¡ã€‚"</string>
+ <string name="ClipMmi">"收到æ¥ç”µæ˜¾ç¤º"</string>
+ <string name="ClirMmi">"外拨电è¯æ˜¾ç¤º"</string>
+ <string name="CfMmi">"呼å«è½¬æŽ¥"</string>
+ <string name="CwMmi">"呼å«ç­‰å¾…"</string>
+ <string name="BaMmi">"呼å«é™åˆ¶"</string>
+ <string name="PwdMmi">"密ç æ›´æ”¹"</string>
+ <string name="PinMmi">"PIN ç æ›´æ”¹"</string>
<!-- no translation found for CnipMmi (3110534680557857162) -->
<skip />
<!-- no translation found for CnirMmi (3062102121430548731) -->
@@ -62,25 +62,25 @@
<skip />
<!-- no translation found for DndMmi (1265478932418334331) -->
<skip />
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"æ¥ç”µæ˜¾ç¤ºé»˜è®¤è®¾ç½®ä¸ºå—é™åˆ¶ã€‚下一个呼å«ï¼šå—é™åˆ¶"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"æ¥ç”µæ˜¾ç¤ºé»˜è®¤è®¾ç½®ä¸ºå—é™åˆ¶ã€‚下一个呼å«ï¼šä¸å—é™åˆ¶"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"æ¥ç”µæ˜¾ç¤ºé»˜è®¤è®¾ç½®ä¸ºä¸å—é™åˆ¶ã€‚下一个呼å«ï¼šå—é™åˆ¶"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"æ¥ç”µæ˜¾ç¤ºé»˜è®¤è®¾ç½®ä¸ºä¸å—é™åˆ¶ã€‚下一个呼å«ï¼šä¸å—é™åˆ¶"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"未æä¾›æœåŠ¡ã€‚"</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"无法更改æ¥ç”µæ˜¾ç¤ºè®¾ç½®ã€‚"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"访问å—é™æƒ…况已å‘生å˜åŒ–"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"æ•°æ®æœåŠ¡å·²ç¦ç”¨ã€‚"</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"紧急æœåŠ¡å·²ç¦ç”¨ã€‚"</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"语音/短信æœåŠ¡å·²ç¦ç”¨ã€‚"</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"所有语音/短信æœåŠ¡å‡å·²ç¦ç”¨ã€‚"</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"语音"</string>
- <string name="serviceClassData" msgid="872456782077937893">"æ•°æ®"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"传真"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"短信"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"异步"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"åŒæ­¥"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"å°åŒ…"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
+ <string name="CLIRDefaultOnNextCallOn">"æ¥ç”µæ˜¾ç¤ºé»˜è®¤è®¾ç½®ä¸ºå—é™åˆ¶ã€‚下一个呼å«ï¼šå—é™åˆ¶"</string>
+ <string name="CLIRDefaultOnNextCallOff">"æ¥ç”µæ˜¾ç¤ºé»˜è®¤è®¾ç½®ä¸ºå—é™åˆ¶ã€‚下一个呼å«ï¼šä¸å—é™åˆ¶"</string>
+ <string name="CLIRDefaultOffNextCallOn">"æ¥ç”µæ˜¾ç¤ºé»˜è®¤è®¾ç½®ä¸ºä¸å—é™åˆ¶ã€‚下一个呼å«ï¼šå—é™åˆ¶"</string>
+ <string name="CLIRDefaultOffNextCallOff">"æ¥ç”µæ˜¾ç¤ºé»˜è®¤è®¾ç½®ä¸ºä¸å—é™åˆ¶ã€‚下一个呼å«ï¼šä¸å—é™åˆ¶"</string>
+ <string name="serviceNotProvisioned">"未æä¾›æœåŠ¡ã€‚"</string>
+ <string name="CLIRPermanent">"无法更改æ¥ç”µæ˜¾ç¤ºè®¾ç½®ã€‚"</string>
+ <string name="RestrictedChangedTitle">"访问å—é™æƒ…况已å‘生å˜åŒ–"</string>
+ <string name="RestrictedOnData">"æ•°æ®æœåŠ¡å·²ç¦ç”¨ã€‚"</string>
+ <string name="RestrictedOnEmergency">"紧急æœåŠ¡å·²ç¦ç”¨ã€‚"</string>
+ <string name="RestrictedOnNormal">"语音/短信æœåŠ¡å·²ç¦ç”¨ã€‚"</string>
+ <string name="RestrictedOnAll">"所有语音/短信æœåŠ¡å‡å·²ç¦ç”¨ã€‚"</string>
+ <string name="serviceClassVoice">"语音"</string>
+ <string name="serviceClassData">"æ•°æ®"</string>
+ <string name="serviceClassFAX">"传真"</string>
+ <string name="serviceClassSMS">"短信"</string>
+ <string name="serviceClassDataAsync">"异步"</string>
+ <string name="serviceClassDataSync">"åŒæ­¥"</string>
+ <string name="serviceClassPacket">"å°åŒ…"</string>
+ <string name="serviceClassPAD">"PAD"</string>
<!-- no translation found for roamingText0 (7170335472198694945) -->
<skip />
<!-- no translation found for roamingText1 (5314861519752538922) -->
@@ -109,112 +109,112 @@
<skip />
<!-- no translation found for roamingTextSearching (8360141885972279963) -->
<skip />
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:无法转接"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g> 秒åŽæ‹¨æ‰“ <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:没有转接"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:没有转接"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:无法转接"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g> 秒åŽæ‹¨æ‰“ <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:没有转接"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:没有转接"</string>
<!-- no translation found for fcComplete (3118848230966886575) -->
<skip />
<!-- no translation found for fcError (3327560126588500777) -->
<skip />
- <string name="httpErrorOk" msgid="1191919378083472204">"确定"</string>
- <string name="httpError" msgid="2567300624552921790">"网页包å«é”™è¯¯ã€‚"</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"找ä¸åˆ°ç½‘å€ã€‚"</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"ä¸æ”¯æŒæ­¤ç½‘站身份验è¯æ–¹æ¡ˆã€‚"</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"身份验è¯å¤±è´¥ã€‚"</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"通过代ç†æœåŠ¡å™¨è¿›è¡Œèº«ä»½éªŒè¯å¤±è´¥ã€‚"</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"未能连接到æœåŠ¡å™¨ã€‚"</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"æœåŠ¡å™¨æ— æ³•é€šä¿¡ï¼Œè¯·ç¨åŽé‡è¯•ã€‚"</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"与æœåŠ¡å™¨çš„连接超时。"</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"网页包å«è¿‡å¤šæœåŠ¡å™¨é‡å®šå‘。"</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"ä¸æ”¯æŒè¯¥å议。"</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"无法建立安全连接。"</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"网å€æ— æ•ˆï¼Œæ­¤ç½‘页无法打开。"</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"无法访问该文件。"</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"找ä¸åˆ°è¯·æ±‚的文件。"</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"正在处ç†çš„请求太多,请ç¨åŽé‡è¯•ã€‚"</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"åŒæ­¥"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"åŒæ­¥"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"太多<xliff:g id="CONTENT_TYPE">%s</xliff:g>删除项。"</string>
- <string name="low_memory" msgid="6632412458436461203">"手机存储空间已满ï¼è¯·åˆ é™¤ä¸€äº›æ–‡ä»¶æ¥è…¾å‡ºç©ºé—´ã€‚"</string>
- <string name="me" msgid="6545696007631404292">"我"</string>
- <string name="power_dialog" msgid="1319919075463988638">"手机选项"</string>
- <string name="silent_mode" msgid="7167703389802618663">"é™éŸ³æ¨¡å¼"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"打开无线电"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"关闭无线电"</string>
- <string name="screen_lock" msgid="799094655496098153">"å±å¹•é”定"</string>
- <string name="power_off" msgid="4266614107412865048">"关机"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"正在关机..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"您的手机会关闭。"</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"无最近的应用程åºã€‚"</string>
- <string name="global_actions" msgid="2406416831541615258">"手机选项"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"å±å¹•é”定"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"关机"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"é™éŸ³æ¨¡å¼"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"声音已“关闭â€"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"声音已“开å¯â€"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飞行模å¼"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飞行模å¼å·²å¼€å¯"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飞行模å¼å·²å…³é—­"</string>
- <string name="safeMode" msgid="2788228061547930246">"安全模å¼"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"需è¦æ‚¨ä»˜è´¹çš„æœåŠ¡"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"å…许应用程åºæ‰§è¡Œå¯èƒ½éœ€è¦æ‚¨ä»˜è´¹çš„æ“作。"</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"您的消æ¯"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"读/写短信ã€ç”µå­é‚®ä»¶å’Œå…¶ä»–消æ¯ã€‚"</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"您的个人信æ¯"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"直接访问手机上存储的è”系人和日历。"</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"您的ä½ç½®"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"监视您的物ç†ä½ç½®"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"网络通信"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"å…许应用程åºè®¿é—®å„ç§ç½‘络功能。"</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"您的 Google å¸æˆ·"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"访问å¯ç”¨çš„ Google å¸æˆ·ã€‚"</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"硬件控制"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"直接访问手机上的硬件。"</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"手机通è¯"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"监视ã€è®°å½•å’Œå¤„ç†ç”µè¯ã€‚"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"系统工具"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"对系统的低级别访问和控制。"</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"å¼€å‘工具"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"åªæœ‰åº”用程åºå¼€å‘人员需è¦è¿™äº›åŠŸèƒ½ã€‚"</string>
+ <string name="httpErrorOk">"确定"</string>
+ <string name="httpError">"网页包å«é”™è¯¯ã€‚"</string>
+ <string name="httpErrorLookup">"找ä¸åˆ°ç½‘å€ã€‚"</string>
+ <string name="httpErrorUnsupportedAuthScheme">"ä¸æ”¯æŒæ­¤ç½‘站身份验è¯æ–¹æ¡ˆã€‚"</string>
+ <string name="httpErrorAuth">"身份验è¯å¤±è´¥ã€‚"</string>
+ <string name="httpErrorProxyAuth">"通过代ç†æœåŠ¡å™¨è¿›è¡Œèº«ä»½éªŒè¯å¤±è´¥ã€‚"</string>
+ <string name="httpErrorConnect">"未能连接到æœåŠ¡å™¨ã€‚"</string>
+ <string name="httpErrorIO">"æœåŠ¡å™¨æ— æ³•é€šä¿¡ï¼Œè¯·ç¨åŽé‡è¯•ã€‚"</string>
+ <string name="httpErrorTimeout">"与æœåŠ¡å™¨çš„连接超时。"</string>
+ <string name="httpErrorRedirectLoop">"网页包å«è¿‡å¤šæœåŠ¡å™¨é‡å®šå‘。"</string>
+ <string name="httpErrorUnsupportedScheme">"ä¸æ”¯æŒè¯¥å议。"</string>
+ <string name="httpErrorFailedSslHandshake">"无法建立安全连接。"</string>
+ <string name="httpErrorBadUrl">"网å€æ— æ•ˆï¼Œæ­¤ç½‘页无法打开。"</string>
+ <string name="httpErrorFile">"无法访问该文件。"</string>
+ <string name="httpErrorFileNotFound">"找ä¸åˆ°è¯·æ±‚的文件。"</string>
+ <string name="httpErrorTooManyRequests">"正在处ç†çš„请求太多,请ç¨åŽé‡è¯•ã€‚"</string>
+ <string name="contentServiceSync">"åŒæ­¥"</string>
+ <string name="contentServiceSyncNotificationTitle">"åŒæ­¥"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"太多<xliff:g id="CONTENT_TYPE">%s</xliff:g>删除项。"</string>
+ <string name="low_memory">"手机存储空间已满ï¼è¯·åˆ é™¤ä¸€äº›æ–‡ä»¶æ¥è…¾å‡ºç©ºé—´ã€‚"</string>
+ <string name="me">"我"</string>
+ <string name="power_dialog">"手机选项"</string>
+ <string name="silent_mode">"é™éŸ³æ¨¡å¼"</string>
+ <string name="turn_on_radio">"打开收音机"</string>
+ <string name="turn_off_radio">"关闭收音机"</string>
+ <string name="screen_lock">"å±å¹•é”定"</string>
+ <string name="power_off">"关机"</string>
+ <string name="shutdown_progress">"正在关机..."</string>
+ <string name="shutdown_confirm">"您的手机会关闭。"</string>
+ <string name="no_recent_tasks">"无最近的应用程åºã€‚"</string>
+ <string name="global_actions">"手机选项"</string>
+ <string name="global_action_lock">"å±å¹•é”定"</string>
+ <string name="global_action_power_off">"关机"</string>
+ <string name="global_action_toggle_silent_mode">"é™éŸ³æ¨¡å¼"</string>
+ <string name="global_action_silent_mode_on_status">"声音已“关闭â€"</string>
+ <string name="global_action_silent_mode_off_status">"声音已“开å¯â€"</string>
+ <string name="global_actions_toggle_airplane_mode">"飞行模å¼"</string>
+ <string name="global_actions_airplane_mode_on_status">"飞行模å¼å·²å¼€å¯"</string>
+ <string name="global_actions_airplane_mode_off_status">"飞行模å¼å·²å…³é—­"</string>
+ <string name="safeMode">"安全模å¼"</string>
+ <string name="android_system_label">"Android 系统"</string>
+ <string name="permgrouplab_costMoney">"需è¦æ‚¨ä»˜è´¹çš„æœåŠ¡"</string>
+ <string name="permgroupdesc_costMoney">"å…许应用程åºæ‰§è¡Œå¯èƒ½éœ€è¦æ‚¨ä»˜è´¹çš„æ“作。"</string>
+ <string name="permgrouplab_messages">"您的消æ¯"</string>
+ <string name="permgroupdesc_messages">"读/写短信ã€ç”µå­é‚®ä»¶å’Œå…¶ä»–消æ¯ã€‚"</string>
+ <string name="permgrouplab_personalInfo">"您的个人信æ¯"</string>
+ <string name="permgroupdesc_personalInfo">"直接访问手机上存储的è”系人和日历。"</string>
+ <string name="permgrouplab_location">"您的ä½ç½®"</string>
+ <string name="permgroupdesc_location">"监视您的物ç†ä½ç½®"</string>
+ <string name="permgrouplab_network">"网络通信"</string>
+ <string name="permgroupdesc_network">"å…许应用程åºè®¿é—®å„ç§ç½‘络功能。"</string>
+ <string name="permgrouplab_accounts">"您的 Google å¸æˆ·"</string>
+ <string name="permgroupdesc_accounts">"访问å¯ç”¨çš„ Google å¸æˆ·ã€‚"</string>
+ <string name="permgrouplab_hardwareControls">"硬件控制"</string>
+ <string name="permgroupdesc_hardwareControls">"直接访问手机上的硬件。"</string>
+ <string name="permgrouplab_phoneCalls">"手机通è¯"</string>
+ <string name="permgroupdesc_phoneCalls">"监视ã€è®°å½•å’Œå¤„ç†ç”µè¯ã€‚"</string>
+ <string name="permgrouplab_systemTools">"系统工具"</string>
+ <string name="permgroupdesc_systemTools">"对系统的低级别访问和控制。"</string>
+ <string name="permgrouplab_developmentTools">"å¼€å‘工具"</string>
+ <string name="permgroupdesc_developmentTools">"åªæœ‰åº”用程åºå¼€å‘人员需è¦è¿™äº›åŠŸèƒ½ã€‚"</string>
<!-- no translation found for permgrouplab_storage (1971118770546336966) -->
<skip />
<!-- no translation found for permgroupdesc_storage (9203302214915355774) -->
<skip />
- <string name="permlab_statusBar" msgid="7417192629601890791">"åœç”¨æˆ–修改状æ€æ "</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"å…许应用程åºåœç”¨çŠ¶æ€æ ï¼Œæˆ–者添加和删除系统图标。"</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"展开/折å çŠ¶æ€æ "</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"å…许应用程åºå±•å¼€æˆ–折å çŠ¶æ€æ ã€‚"</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"拦截对外呼å«"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"å…许应用程åºå¤„ç†å¯¹å¤–呼å«å’Œæ›´æ”¹è¦æ‹¨æ‰“çš„å·ç ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ç›‘视ã€é‡å®šå‘或阻止对外呼å«ã€‚"</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"接收短信"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"å…许应用程åºæŽ¥æ”¶å’Œå¤„ç†çŸ­ä¿¡ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ç›‘视您的信æ¯ï¼Œæˆ–者将信æ¯åˆ é™¤è€Œä¸å‘您显示。"</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"接收彩信"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"å…许应用程åºæŽ¥æ”¶å’Œå¤„ç†å½©ä¿¡ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ç›‘视您的信æ¯ï¼Œæˆ–者将信æ¯åˆ é™¤è€Œä¸å‘您显示。"</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"å‘é€çŸ­ä¿¡"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"å…许应用程åºå‘é€çŸ­ä¿¡ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ä¸ç»æ‚¨çš„确认å‘é€ä¿¡æ¯æ¥è®©æ‚¨ä»˜è´¹ã€‚"</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"读å–短信或彩信"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"å…许应用程åºè¯»å–您的手机或 SIM å¡ä¸­å­˜å‚¨çš„短信。æ¶æ„应用程åºå¯å€Ÿæ­¤è¯»å–您的机密信æ¯ã€‚"</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"编辑短信或彩信"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"å…许应用程åºå†™å…¥æ‰‹æœºæˆ– SIM å¡ä¸­å­˜å‚¨çš„短信。æ¶æ„应用程åºå¯å€Ÿæ­¤åˆ é™¤æ‚¨çš„ä¿¡æ¯ã€‚"</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"接收 WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"å…许应用程åºæŽ¥æ”¶å’Œå¤„ç† WAP 消æ¯ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ç›‘视您的消æ¯ï¼Œæˆ–者将消æ¯åˆ é™¤è€Œä¸å‘您显示。"</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"检索所è¿è¡Œçš„应用程åº"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"å…许应用程åºæ£€ç´¢æœ‰å…³å½“å‰å’Œæœ€è¿‘è¿è¡Œçš„任务的信æ¯ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å‘现有关其他应用程åºçš„ç§æœ‰ä¿¡æ¯ã€‚"</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"对正在è¿è¡Œçš„应用程åºé‡æ–°æŽ’åº"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"å…许应用程åºå°†ä»»åŠ¡ç§»è‡³å‰å°å’ŒåŽå°ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å¼ºè¡Œè¿›åˆ°å‰å°ï¼Œè€Œä¸å—您的控制。"</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"å¯ç”¨åº”用程åºè°ƒè¯•"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"å…许应用程åºå¯åŠ¨å¯¹å…¶ä»–应用程åºçš„调试。æ¶æ„应用程åºå¯å€Ÿæ­¤ç»ˆæ­¢å…¶ä»–应用程åºã€‚"</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"更改用户界é¢è®¾ç½®"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"å…许应用程åºæ›´æ”¹å½“å‰é…置,例如语言区域或整体字å·ã€‚"</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"é‡æ–°å¯åŠ¨å…¶ä»–应用程åº"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"å…许应用程åºå¼ºè¡Œé‡æ–°å¯åŠ¨å…¶ä»–应用程åºã€‚"</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"强行关闭应用程åº"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"å…许应用程åºå¼ºè¡Œå…³é—­å‰å°ä¸­çš„任何活动并返回。普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_dump" msgid="1681799862438954752">"检索系统内部状æ€"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"å…许应用程åºæ£€ç´¢ç³»ç»Ÿçš„内部状æ€ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æ£€ç´¢å®ƒä»¬é€šå¸¸å¹¶ä¸éœ€è¦çš„å„ç§ç§æœ‰ä¿¡æ¯å’Œå®‰å…¨ä¿¡æ¯ã€‚"</string>
+ <string name="permlab_statusBar">"åœç”¨æˆ–修改状æ€æ "</string>
+ <string name="permdesc_statusBar">"å…许应用程åºåœç”¨çŠ¶æ€æ ï¼Œæˆ–者添加和删除系统图标。"</string>
+ <string name="permlab_expandStatusBar">"展开/折å çŠ¶æ€æ "</string>
+ <string name="permdesc_expandStatusBar">"å…许应用程åºå±•å¼€æˆ–折å çŠ¶æ€æ ã€‚"</string>
+ <string name="permlab_processOutgoingCalls">"拦截对外呼å«"</string>
+ <string name="permdesc_processOutgoingCalls">"å…许应用程åºå¤„ç†å¯¹å¤–呼å«å’Œæ›´æ”¹è¦æ‹¨æ‰“çš„å·ç ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ç›‘视ã€é‡å®šå‘或阻止对外呼å«ã€‚"</string>
+ <string name="permlab_receiveSms">"接收短信"</string>
+ <string name="permdesc_receiveSms">"å…许应用程åºæŽ¥æ”¶å’Œå¤„ç†çŸ­ä¿¡ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ç›‘视您的信æ¯ï¼Œæˆ–者将信æ¯åˆ é™¤è€Œä¸å‘您显示。"</string>
+ <string name="permlab_receiveMms">"接收彩信"</string>
+ <string name="permdesc_receiveMms">"å…许应用程åºæŽ¥æ”¶å’Œå¤„ç†å½©ä¿¡ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ç›‘视您的信æ¯ï¼Œæˆ–者将信æ¯åˆ é™¤è€Œä¸å‘您显示。"</string>
+ <string name="permlab_sendSms">"å‘é€çŸ­ä¿¡"</string>
+ <string name="permdesc_sendSms">"å…许应用程åºå‘é€çŸ­ä¿¡ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ä¸ç»æ‚¨çš„确认å‘é€ä¿¡æ¯æ¥è®©æ‚¨ä»˜è´¹ã€‚"</string>
+ <string name="permlab_readSms">"读å–短信或彩信"</string>
+ <string name="permdesc_readSms">"å…许应用程åºè¯»å–您的手机或 SIM å¡ä¸­å­˜å‚¨çš„短信。æ¶æ„应用程åºå¯å€Ÿæ­¤è¯»å–您的机密信æ¯ã€‚"</string>
+ <string name="permlab_writeSms">"编辑短信或彩信"</string>
+ <string name="permdesc_writeSms">"å…许应用程åºå†™å…¥æ‰‹æœºæˆ– SIM å¡ä¸­å­˜å‚¨çš„短信。æ¶æ„应用程åºå¯å€Ÿæ­¤åˆ é™¤æ‚¨çš„ä¿¡æ¯ã€‚"</string>
+ <string name="permlab_receiveWapPush">"接收 WAP"</string>
+ <string name="permdesc_receiveWapPush">"å…许应用程åºæŽ¥æ”¶å’Œå¤„ç† WAP 消æ¯ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ç›‘视您的消æ¯ï¼Œæˆ–者将消æ¯åˆ é™¤è€Œä¸å‘您显示。"</string>
+ <string name="permlab_getTasks">"检索所è¿è¡Œçš„应用程åº"</string>
+ <string name="permdesc_getTasks">"å…许应用程åºæ£€ç´¢æœ‰å…³å½“å‰å’Œæœ€è¿‘è¿è¡Œçš„任务的信æ¯ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å‘现有关其他应用程åºçš„ç§æœ‰ä¿¡æ¯ã€‚"</string>
+ <string name="permlab_reorderTasks">"对正在è¿è¡Œçš„应用程åºé‡æ–°æŽ’åº"</string>
+ <string name="permdesc_reorderTasks">"å…许应用程åºå°†ä»»åŠ¡ç§»è‡³å‰å°å’ŒåŽå°ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å¼ºè¡Œè¿›åˆ°å‰å°ï¼Œè€Œä¸å—您的控制。"</string>
+ <string name="permlab_setDebugApp">"å¯ç”¨åº”用程åºè°ƒè¯•"</string>
+ <string name="permdesc_setDebugApp">"å…许应用程åºå¯åŠ¨å¯¹å…¶ä»–应用程åºçš„调试。æ¶æ„应用程åºå¯å€Ÿæ­¤ç»ˆæ­¢å…¶ä»–应用程åºã€‚"</string>
+ <string name="permlab_changeConfiguration">"更改您的用户界é¢è®¾ç½®"</string>
+ <string name="permdesc_changeConfiguration">"å…许应用程åºæ›´æ”¹å½“å‰é…置,例如语言区域或整体字å·ã€‚"</string>
+ <string name="permlab_restartPackages">"é‡æ–°å¯åŠ¨å…¶ä»–应用程åº"</string>
+ <string name="permdesc_restartPackages">"å…许应用程åºå¼ºè¡Œé‡æ–°å¯åŠ¨å…¶ä»–应用程åºã€‚"</string>
+ <string name="permlab_forceBack">"强行关闭应用程åº"</string>
+ <string name="permdesc_forceBack">"å…许应用程åºå¼ºè¡Œå…³é—­å‰å°ä¸­çš„任何活动并返回。普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_dump">"检索系统内部状æ€"</string>
+ <string name="permdesc_dump">"å…许应用程åºæ£€ç´¢ç³»ç»Ÿçš„内部状æ€ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æ£€ç´¢å®ƒä»¬é€šå¸¸å¹¶ä¸éœ€è¦çš„å„ç§ç§æœ‰ä¿¡æ¯å’Œå®‰å…¨ä¿¡æ¯ã€‚"</string>
<!-- no translation found for permlab_shutdown (7185747824038909016) -->
<skip />
<!-- no translation found for permdesc_shutdown (7046500838746291775) -->
@@ -223,296 +223,293 @@
<skip />
<!-- no translation found for permdesc_stopAppSwitches (3857886086919033794) -->
<skip />
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"监控所有应用程åºçš„å¯åŠ¨"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"å…许应用程åºç›‘控系统å¯åŠ¨æ´»åŠ¨çš„æ–¹å¼ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å½»åº•æŸå系统。这一æƒé™åªåœ¨å¼€å‘过程中需è¦ï¼Œæ™®é€šçš„手机æ“作ä¸éœ€è¦ã€‚"</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"å‘é€å·²åˆ é™¤åŒ…的广播"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"å…许应用程åºå¹¿æ’­å·²åˆ é™¤åº”用程åºåŒ…的通知。æ¶æ„应用程åºå¯å€Ÿæ­¤ç»ˆæ­¢ä»»ä½•æ­£åœ¨è¿è¡Œçš„其他应用程åºã€‚"</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"å‘é€å¯é€šè¿‡çŸ­ä¿¡æŽ¥æ”¶çš„广播"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"å…许应用程åºå¹¿æ’­å·²æ”¶åˆ°çŸ­ä¿¡çš„通知。æ¶æ„应用程åºå¯å€Ÿæ­¤ä¼ªé€ æ”¶åˆ°çš„短信。"</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"å‘é€ WAP 一键接收广播"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"å…许应用程åºå¹¿æ’­æ”¶åˆ° WAP 一键信æ¯çš„通知。æ¶æ„应用程åºå¯å€Ÿæ­¤ä¹±å‘彩信或暗中用æ¶æ„内容替æ¢ä»»æ„网页中的内容。"</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"é™åˆ¶æ‰€è¿è¡Œè¿›ç¨‹çš„æ•°é‡"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"å…许应用程åºæŽ§åˆ¶å°†è¿è¡Œçš„最大进程数。普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"关闭所有åŽå°åº”用程åº"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"å…许应用程åºæŽ§åˆ¶æ´»åŠ¨æ˜¯å¦å§‹ç»ˆæ˜¯ä¸€è½¬è‡³åŽå°å°±å®Œæˆã€‚普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"修改电池使用情况统计信æ¯"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"å…许修改收集的电池使用情况统计信æ¯ã€‚普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_runSetActivityWatcher">"监控所有应用程åºçš„å¯åŠ¨"</string>
+ <string name="permdesc_runSetActivityWatcher">"å…许应用程åºç›‘控系统å¯åŠ¨æ´»åŠ¨çš„æ–¹å¼ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å½»åº•æŸå系统。这一æƒé™åªåœ¨å¼€å‘过程中需è¦ï¼Œæ™®é€šçš„手机æ“作ä¸éœ€è¦ã€‚"</string>
+ <string name="permlab_broadcastPackageRemoved">"å‘é€å·²åˆ é™¤åŒ…的广播"</string>
+ <string name="permdesc_broadcastPackageRemoved">"å…许应用程åºå¹¿æ’­å·²åˆ é™¤åº”用程åºåŒ…的通知。æ¶æ„应用程åºå¯å€Ÿæ­¤ç»ˆæ­¢ä»»ä½•æ­£åœ¨è¿è¡Œçš„其他应用程åºã€‚"</string>
+ <string name="permlab_broadcastSmsReceived">"å‘é€å¯é€šè¿‡çŸ­ä¿¡æŽ¥æ”¶çš„广播"</string>
+ <string name="permdesc_broadcastSmsReceived">"å…许应用程åºå¹¿æ’­å·²æ”¶åˆ°çŸ­ä¿¡çš„通知。æ¶æ„应用程åºå¯å€Ÿæ­¤ä¼ªé€ æ”¶åˆ°çš„短信。"</string>
+ <string name="permlab_broadcastWapPush">"å‘é€ WAP 一键接收广播"</string>
+ <string name="permdesc_broadcastWapPush">"å…许应用程åºå¹¿æ’­æ”¶åˆ° WAP 一键信æ¯çš„通知。æ¶æ„应用程åºå¯å€Ÿæ­¤ä¹±å‘彩信或暗中用æ¶æ„内容替æ¢ä»»æ„网页中的内容。"</string>
+ <string name="permlab_setProcessLimit">"é™åˆ¶æ‰€è¿è¡Œè¿›ç¨‹çš„æ•°é‡"</string>
+ <string name="permdesc_setProcessLimit">"å…许应用程åºæŽ§åˆ¶å°†è¿è¡Œçš„最大进程数。普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_setAlwaysFinish">"关闭所有åŽå°åº”用程åº"</string>
+ <string name="permdesc_setAlwaysFinish">"å…许应用程åºæŽ§åˆ¶æ´»åŠ¨æ˜¯å¦å§‹ç»ˆæ˜¯ä¸€è½¬è‡³åŽå°å°±å®Œæˆã€‚普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_batteryStats">"修改电池使用情况统计信æ¯"</string>
+ <string name="permdesc_batteryStats">"å…许修改收集的电池使用情况统计信æ¯ã€‚普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
<!-- no translation found for permlab_backup (470013022865453920) -->
<skip />
<!-- no translation found for permdesc_backup (2305432853944929371) -->
<skip />
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"显示未授æƒçš„窗å£"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"å…许创建专供内部系统用户界é¢ä½¿ç”¨çš„窗å£ã€‚普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"显示系统级警报"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"å…许应用程åºæ˜¾ç¤ºç³»ç»Ÿè­¦æŠ¥çª—å£ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æŽŒæŽ§æ•´ä¸ªæ‰‹æœºå±å¹•ã€‚"</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"修改全局动画速度"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"å…许应用程åºéšæ—¶æ›´æ”¹å…¨å±€åŠ¨ç”»é€Ÿåº¦ï¼ˆåŠ å¿«æˆ–放慢动画)。"</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"管ç†åº”用程åºä»¤ç‰Œ"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"å…许应用程åºåˆ›å»ºå’Œç®¡ç†è‡ªå·±çš„令牌,从而绕开正常的 Z 排åºæ–¹å¼ã€‚普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"按键和控制按钮"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"å…许应用程åºå°†å…¶è‡ªå·±çš„输入活动(按键等)æ供给其他应用程åºã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æŽŒæŽ§æ‰‹æœºã€‚"</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"记录您输入的内容和采å–çš„æ“作"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"å…许应用程åºæŸ¥çœ‹æ‚¨æŒ‰çš„键,å³ä½¿åœ¨ä¸Žå…¶ä»–应用程åºäº¤äº’(例如输入密ç ï¼‰æ—¶ä¹Ÿä¸ä¾‹å¤–。普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"绑定至输入法"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"å…许手机用户绑定至输入法的顶级界é¢ã€‚普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"更改å±å¹•æµè§ˆæ¨¡å¼"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"å…许应用程åºéšæ—¶æ›´æ”¹å±å¹•çš„旋转方å‘。普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"å‘应用程åºå‘é€ Linux ä¿¡å·"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"å…许应用程åºè¯·æ±‚å°†æ供的信å·å‘é€ç»™æ‰€æœ‰æŒç»­çš„进程。"</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"让应用程åºå§‹ç»ˆè¿è¡Œ"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"å…许应用程åºéƒ¨åˆ†æŒç»­è¿è¡Œï¼Œè¿™æ ·ç³»ç»Ÿä¾¿ä¸èƒ½å°†å…¶ç”¨äºŽå…¶ä»–应用程åºã€‚"</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"删除应用程åº"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"å…许应用程åºåˆ é™¤ Android 包。æ¶æ„应用程åºå¯å€Ÿæ­¤åˆ é™¤é‡è¦çš„应用程åºã€‚"</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"删除其他应用程åºçš„æ•°æ®"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"å…许应用程åºæ¸…除用户数æ®ã€‚"</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"删除其他应用程åºç¼“å­˜"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"å…许应用程åºåˆ é™¤ç¼“存文件。"</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"计算应用程åºå­˜å‚¨ç©ºé—´"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"å…许应用程åºæ£€ç´¢å…¶ä»£ç ã€æ•°æ®å’Œç¼“存大å°"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"直接安装应用程åº"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"å…许应用程åºå®‰è£…新的或更新的 Android 包。æ¶æ„应用程åºå¯å€Ÿæ­¤æ·»åŠ å…·æœ‰æžå¤§æƒé™çš„新应用程åºã€‚"</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"删除所有应用程åºç¼“存数æ®"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"å…许应用程åºé€šè¿‡åˆ é™¤åº”用程åºç¼“存目录中的文件释放手机存储空间。对系统进程的访问通常å—到严格é™åˆ¶ã€‚"</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"读å–系统日志文件"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"å…许应用程åºè¯»å–系统的å„日志文件。这样应用程åºå¯ä»¥å‘现有关您æ“作手机的一般信æ¯ï¼Œä½†è¿™äº›ä¿¡æ¯ä¸åº”包å«ä»»ä½•ä¸ªäººä¿¡æ¯æˆ–ç§æœ‰ä¿¡æ¯ã€‚"</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"读å–/写入诊断所拥有的资æº"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"å…许应用程åºè¯»å–/写入诊断组所拥有的任何资æºï¼›ä¾‹å¦‚,/dev 中的文件。这å¯èƒ½ä¼šå½±å“系统稳定性和安全性。此æƒé™åªåº”由制造商或è¿è¥å•†ç”¨äºŽç¡¬ä»¶ç‰¹å®šçš„诊断。"</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"å¯ç”¨æˆ–åœç”¨åº”用程åºç»„件"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"å…许应用程åºæ›´æ”¹æ˜¯å¦å¯ç”¨å…¶ä»–应用程åºçš„组件。æ¶æ„应用程åºå¯å€Ÿæ­¤åœç”¨é‡è¦çš„手机功能。使用此æƒé™æ—¶åŠ¡å¿…谨慎,因为这å¯èƒ½å¯¼è‡´åº”用程åºç»„件进入ä¸å¯ç”¨ã€ä¸ä¸€è‡´æˆ–ä¸ç¨³å®šçš„状æ€ã€‚"</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"设置首选应用程åº"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"å…许应用程åºä¿®æ”¹é¦–选的应用程åºã€‚这样æ¶æ„应用程åºå¯èƒ½ä¼šæš—中更改è¿è¡Œçš„应用程åºï¼Œä»Žè€Œéª—过您的现有应用程åºæ¥æ”¶é›†æ‚¨çš„ç§æœ‰æ•°æ®ã€‚"</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"修改全局系统设置"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"å…许应用程åºä¿®æ”¹ç³»ç»Ÿçš„设置数æ®ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ç ´å您的系统é…置。"</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"修改安全系统设置"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"å…许应用程åºä¿®æ”¹ç³»ç»Ÿå®‰å…¨è®¾ç½®æ•°æ®ã€‚普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"修改 Google æœåŠ¡åœ°å›¾"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"å…许应用程åºä¿®æ”¹ Google æœåŠ¡åœ°å›¾ã€‚普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"开机时自动å¯åŠ¨"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"å…许应用程åºåœ¨ç³»ç»Ÿå®Œæˆå¯åŠ¨åŽå³è‡ªè¡Œå¯åŠ¨ã€‚这样会延长手机的å¯åŠ¨æ—¶é—´ï¼Œè€Œä¸”如果应用程åºä¸€ç›´è¿è¡Œï¼Œä¼šé™ä½Žæ‰‹æœºçš„整体速度。"</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"å‘é€é¡½å›ºå¹¿æ’­"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"å…许应用程åºå‘é€é¡½å›ºå¹¿æ’­ï¼Œè¿™äº›å¹¿æ’­åœ¨ç»“æŸåŽä»ä¼šä¿ç•™ã€‚æ¶æ„应用程åºå¯èƒ½ä¼šå€Ÿæ­¤ä½¿æ‰‹æœºè€—用太多内存,从而é™ä½Žå…¶é€Ÿåº¦æˆ–稳定性。"</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"读å–è”系人数æ®"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"å…许应用程åºè¯»å–您手机上存储的所有è”系人(地å€ï¼‰æ•°æ®ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å°†æ‚¨çš„æ•°æ®å‘é€ç»™å…¶ä»–人。"</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"写入è”系数æ®"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"å…许应用程åºä¿®æ”¹æ‚¨æ‰‹æœºä¸Šå­˜å‚¨çš„è”系人(地å€ï¼‰æ•°æ®ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æ¸…除或修改您的è”系人数æ®ã€‚"</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"写入拥有者数æ®"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"å…许应用程åºä¿®æ”¹æ‚¨æ‰‹æœºä¸Šå­˜å‚¨çš„手机拥有者数æ®ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æ¸…除或修改拥有者数æ®ã€‚"</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"读å–拥有者数æ®"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"å…许应用程åºè¯»å–您手机上存储的手机拥有者数æ®ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤è¯»å–手机拥有者数æ®ã€‚"</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"读å–日历数æ®"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"å…许应用程åºè¯»å–您手机上存储的所有日历活动。æ¶æ„应用程åºå¯å€Ÿæ­¤å°†æ‚¨çš„日历活动å‘é€ç»™å…¶ä»–人。"</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"写入日历数æ®"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"å…许应用程åºä¿®æ”¹æ‚¨æ‰‹æœºä¸Šå­˜å‚¨çš„日历活动。æ¶æ„应用程åºå¯å€Ÿæ­¤æ¸…除或修改您的日历数æ®ã€‚"</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"用于测试的模拟ä½ç½®æº"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"创建用于测试的模拟ä½ç½®æºã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æ›¿ä»£çœŸæ­£çš„ä½ç½®æºï¼ˆå¦‚ GPS 或网络æ供商)返回的ä½ç½®å’Œ/或状æ€ã€‚"</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"接收é¢å¤–çš„ä½ç½®æ供者命令"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"访问é¢å¤–çš„ä½ç½®æ供程åºå‘½ä»¤ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å¹²æ‰° GPS 或其他ä½ç½®æºçš„è¿ä½œã€‚"</string>
+ <string name="permlab_internalSystemWindow">"显示未授æƒçš„窗å£"</string>
+ <string name="permdesc_internalSystemWindow">"å…许创建专供内部系统用户界é¢ä½¿ç”¨çš„窗å£ã€‚普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_systemAlertWindow">"显示系统级警报"</string>
+ <string name="permdesc_systemAlertWindow">"å…许应用程åºæ˜¾ç¤ºç³»ç»Ÿè­¦æŠ¥çª—å£ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æŽŒæŽ§æ•´ä¸ªæ‰‹æœºå±å¹•ã€‚"</string>
+ <string name="permlab_setAnimationScale">"修改全局动画速度"</string>
+ <string name="permdesc_setAnimationScale">"å…许应用程åºéšæ—¶æ›´æ”¹å…¨å±€åŠ¨ç”»é€Ÿåº¦ï¼ˆåŠ å¿«æˆ–放慢动画)。"</string>
+ <string name="permlab_manageAppTokens">"管ç†åº”用程åºä»¤ç‰Œ"</string>
+ <string name="permdesc_manageAppTokens">"å…许应用程åºåˆ›å»ºå’Œç®¡ç†è‡ªå·±çš„令牌,从而绕开正常的 Z 排åºæ–¹å¼ã€‚普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_injectEvents">"按键和控制按钮"</string>
+ <string name="permdesc_injectEvents">"å…许应用程åºå°†å…¶è‡ªå·±çš„输入活动(按键等)æ供给其他应用程åºã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æŽŒæŽ§æ‰‹æœºã€‚"</string>
+ <string name="permlab_readInputState">"记录您输入的内容和采å–çš„æ“作"</string>
+ <string name="permdesc_readInputState">"å…许应用程åºæŸ¥çœ‹æ‚¨æŒ‰çš„键,å³ä½¿åœ¨ä¸Žå…¶ä»–应用程åºäº¤äº’(例如输入密ç ï¼‰æ—¶ä¹Ÿä¸ä¾‹å¤–。普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_bindInputMethod">"绑定至输入法"</string>
+ <string name="permdesc_bindInputMethod">"å…许手机用户绑定至输入法的顶级界é¢ã€‚普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_setOrientation">"更改å±å¹•æµè§ˆæ¨¡å¼"</string>
+ <string name="permdesc_setOrientation">"å…许应用程åºéšæ—¶æ›´æ”¹å±å¹•çš„旋转方å‘。普通应用程åºä»Žä¸éœ€è¦ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_signalPersistentProcesses">"å‘应用程åºå‘é€ Linux ä¿¡å·"</string>
+ <string name="permdesc_signalPersistentProcesses">"å…许应用程åºè¯·æ±‚å°†æ供的信å·å‘é€ç»™æ‰€æœ‰æŒç»­çš„进程。"</string>
+ <string name="permlab_persistentActivity">"让应用程åºå§‹ç»ˆè¿è¡Œ"</string>
+ <string name="permdesc_persistentActivity">"å…许应用程åºéƒ¨åˆ†æŒç»­è¿è¡Œï¼Œè¿™æ ·ç³»ç»Ÿä¾¿ä¸èƒ½å°†å…¶ç”¨äºŽå…¶ä»–应用程åºã€‚"</string>
+ <string name="permlab_deletePackages">"删除应用程åº"</string>
+ <string name="permdesc_deletePackages">"å…许应用程åºåˆ é™¤ Android 包。æ¶æ„应用程åºå¯å€Ÿæ­¤åˆ é™¤é‡è¦çš„应用程åºã€‚"</string>
+ <string name="permlab_clearAppUserData">"删除其他应用程åºçš„æ•°æ®"</string>
+ <string name="permdesc_clearAppUserData">"å…许应用程åºæ¸…除用户数æ®ã€‚"</string>
+ <string name="permlab_deleteCacheFiles">"删除其他应用程åºç¼“å­˜"</string>
+ <string name="permdesc_deleteCacheFiles">"å…许应用程åºåˆ é™¤ç¼“存文件。"</string>
+ <string name="permlab_getPackageSize">"计算应用程åºå­˜å‚¨ç©ºé—´"</string>
+ <string name="permdesc_getPackageSize">"å…许应用程åºæ£€ç´¢å…¶ä»£ç ã€æ•°æ®å’Œç¼“存大å°"</string>
+ <string name="permlab_installPackages">"直接安装应用程åº"</string>
+ <string name="permdesc_installPackages">"å…许应用程åºå®‰è£…新的或更新的 Android 包。æ¶æ„应用程åºå¯å€Ÿæ­¤æ·»åŠ å…·æœ‰æžå¤§æƒé™çš„新应用程åºã€‚"</string>
+ <string name="permlab_clearAppCache">"删除所有应用程åºç¼“存数æ®"</string>
+ <string name="permdesc_clearAppCache">"å…许应用程åºé€šè¿‡åˆ é™¤åº”用程åºç¼“存目录中的文件释放手机存储空间。对系统进程的访问通常å—到严格é™åˆ¶ã€‚"</string>
+ <string name="permlab_readLogs">"读å–系统日志文件"</string>
+ <string name="permdesc_readLogs">"å…许应用程åºè¯»å–系统的å„日志文件。这样应用程åºå¯ä»¥å‘现有关您æ“作手机的一般信æ¯ï¼Œä½†è¿™äº›ä¿¡æ¯ä¸åº”包å«ä»»ä½•ä¸ªäººä¿¡æ¯æˆ–ç§æœ‰ä¿¡æ¯ã€‚"</string>
+ <string name="permlab_diagnostic">"读å–/写入诊断所拥有的资æº"</string>
+ <string name="permdesc_diagnostic">"å…许应用程åºè¯»å–/写入诊断组所拥有的任何资æºï¼›ä¾‹å¦‚,/dev 中的文件。这å¯èƒ½ä¼šå½±å“系统稳定性和安全性。此æƒé™åªåº”由制造商或è¿è¥å•†ç”¨äºŽç¡¬ä»¶ç‰¹å®šçš„诊断。"</string>
+ <string name="permlab_changeComponentState">"å¯ç”¨æˆ–åœç”¨åº”用程åºç»„件"</string>
+ <string name="permdesc_changeComponentState">"å…许应用程åºæ›´æ”¹æ˜¯å¦å¯ç”¨å…¶ä»–应用程åºçš„组件。æ¶æ„应用程åºå¯å€Ÿæ­¤åœç”¨é‡è¦çš„手机功能。使用此æƒé™æ—¶åŠ¡å¿…谨慎,因为这å¯èƒ½å¯¼è‡´åº”用程åºç»„件进入ä¸å¯ç”¨ã€ä¸ä¸€è‡´æˆ–ä¸ç¨³å®šçš„状æ€ã€‚"</string>
+ <string name="permlab_setPreferredApplications">"设置首选应用程åº"</string>
+ <string name="permdesc_setPreferredApplications">"å…许应用程åºä¿®æ”¹é¦–选的应用程åºã€‚这样æ¶æ„应用程åºå¯èƒ½ä¼šæš—中更改è¿è¡Œçš„应用程åºï¼Œä»Žè€Œéª—过您的现有应用程åºæ¥æ”¶é›†æ‚¨çš„ç§æœ‰æ•°æ®ã€‚"</string>
+ <string name="permlab_writeSettings">"修改全局系统设置"</string>
+ <string name="permdesc_writeSettings">"å…许应用程åºä¿®æ”¹ç³»ç»Ÿçš„设置数æ®ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤ç ´å您的系统é…置。"</string>
+ <string name="permlab_writeSecureSettings">"修改安全系统设置"</string>
+ <string name="permdesc_writeSecureSettings">"å…许应用程åºä¿®æ”¹ç³»ç»Ÿå®‰å…¨è®¾ç½®æ•°æ®ã€‚普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_writeGservices">"修改 Google æœåŠ¡åœ°å›¾"</string>
+ <string name="permdesc_writeGservices">"å…许应用程åºä¿®æ”¹ Google æœåŠ¡åœ°å›¾ã€‚普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_receiveBootCompleted">"开机时自动å¯åŠ¨"</string>
+ <string name="permdesc_receiveBootCompleted">"å…许应用程åºåœ¨ç³»ç»Ÿå®Œæˆå¯åŠ¨åŽå³è‡ªè¡Œå¯åŠ¨ã€‚这样会延长手机的å¯åŠ¨æ—¶é—´ï¼Œè€Œä¸”如果应用程åºä¸€ç›´è¿è¡Œï¼Œä¼šé™ä½Žæ‰‹æœºçš„整体速度。"</string>
+ <string name="permlab_broadcastSticky">"å‘é€é¡½å›ºå¹¿æ’­"</string>
+ <string name="permdesc_broadcastSticky">"å…许应用程åºå‘é€é¡½å›ºå¹¿æ’­ï¼Œè¿™äº›å¹¿æ’­åœ¨ç»“æŸåŽä»ä¼šä¿ç•™ã€‚æ¶æ„应用程åºå¯èƒ½ä¼šå€Ÿæ­¤ä½¿æ‰‹æœºè€—用太多内存,从而é™ä½Žå…¶é€Ÿåº¦æˆ–稳定性。"</string>
+ <string name="permlab_readContacts">"读å–è”系人数æ®"</string>
+ <string name="permdesc_readContacts">"å…许应用程åºè¯»å–您手机上存储的所有è”系人(地å€ï¼‰æ•°æ®ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å°†æ‚¨çš„æ•°æ®å‘é€ç»™å…¶ä»–人。"</string>
+ <string name="permlab_writeContacts">"写入è”系数æ®"</string>
+ <string name="permdesc_writeContacts">"å…许应用程åºä¿®æ”¹æ‚¨æ‰‹æœºä¸Šå­˜å‚¨çš„è”系人(地å€ï¼‰æ•°æ®ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æ¸…除或修改您的è”系人数æ®ã€‚"</string>
+ <string name="permlab_writeOwnerData">"写入拥有者数æ®"</string>
+ <string name="permdesc_writeOwnerData">"å…许应用程åºä¿®æ”¹æ‚¨æ‰‹æœºä¸Šå­˜å‚¨çš„手机拥有者数æ®ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æ¸…除或修改拥有者数æ®ã€‚"</string>
+ <string name="permlab_readOwnerData">"读å–拥有者数æ®"</string>
+ <string name="permdesc_readOwnerData">"å…许应用程åºè¯»å–您手机上存储的手机拥有者数æ®ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤è¯»å–手机拥有者数æ®ã€‚"</string>
+ <string name="permlab_readCalendar">"读å–日历数æ®"</string>
+ <string name="permdesc_readCalendar">"å…许应用程åºè¯»å–您手机上存储的所有日历活动。æ¶æ„应用程åºå¯å€Ÿæ­¤å°†æ‚¨çš„日历活动å‘é€ç»™å…¶ä»–人。"</string>
+ <string name="permlab_writeCalendar">"写入日历数æ®"</string>
+ <string name="permdesc_writeCalendar">"å…许应用程åºä¿®æ”¹æ‚¨æ‰‹æœºä¸Šå­˜å‚¨çš„日历活动。æ¶æ„应用程åºå¯å€Ÿæ­¤æ¸…除或修改您的日历数æ®ã€‚"</string>
+ <string name="permlab_accessMockLocation">"用于测试的模拟ä½ç½®æº"</string>
+ <string name="permdesc_accessMockLocation">"创建用于测试的模拟ä½ç½®æºã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤æ›¿ä»£çœŸæ­£çš„ä½ç½®æºï¼ˆå¦‚ GPS 或网络æ供商)返回的ä½ç½®å’Œ/或状æ€ã€‚"</string>
+ <string name="permlab_accessLocationExtraCommands">"å…许访问é¢å¤–çš„ä½ç½®æ供命令"</string>
+ <string name="permdesc_accessLocationExtraCommands">"访问é¢å¤–çš„ä½ç½®æ供程åºå‘½ä»¤ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å¹²æ‰° GPS 或其他ä½ç½®æºçš„è¿ä½œã€‚"</string>
<!-- no translation found for permlab_installLocationProvider (6578101199825193873) -->
<skip />
<!-- no translation found for permdesc_installLocationProvider (5449175116732002106) -->
<skip />
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"精准ä½ç½® (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"访问精准的ä½ç½®æºï¼Œä¾‹å¦‚手机上的全çƒå®šä½ç³»ç»Ÿï¼ˆå¦‚果适用)。æ¶æ„应用程åºå¯èƒ½å€Ÿæ­¤ç¡®å®šæ‚¨æ‰€å¤„çš„ä½ç½®ï¼Œå¹¶æ¶ˆè€—é¢å¤–的电池电é‡ã€‚"</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ç²—ç•¥ä½ç½®ï¼ˆä»¥ç½‘络为基础)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"访问粗略的ä½ç½®æºï¼ˆä¾‹å¦‚蜂çªç½‘络数æ®åº“)以确定手机的大体ä½ç½®ï¼ˆå¦‚果适用)。æ¶æ„应用程åºå¯å€Ÿæ­¤ç¡®å®šæ‚¨æ‰€å¤„的大体ä½ç½®ã€‚"</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"访问 SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"å…许应用程åºä½¿ç”¨ SurfaceFlinger 低级别功能。"</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"读å–帧缓冲区"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"å…许应用程åºè¯»å–帧缓冲区的内容。"</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"更改您的音频设置"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"å…许应用程åºä¿®æ”¹å…¨å±€éŸ³é¢‘设置,如音é‡å’Œè·¯ç”±ã€‚"</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"录音"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"å…许应用程åºè®¿é—®å½•éŸ³è·¯å¾„。"</string>
- <string name="permlab_camera" msgid="8059288807274039014">"æ‹ç…§"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"å…许应用程åºä½¿ç”¨ç›¸æœºæ‹ç…§ã€‚æ­¤æƒé™å…许应用程åºéšæ—¶æ”¶é›†ç›¸æœºçœ‹åˆ°çš„图片。"</string>
- <string name="permlab_brick" msgid="8337817093326370537">"永久åœç”¨æ‰‹æœº"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"å…许应用程åºæ°¸ä¹…åœç”¨æ•´ä¸ªæ‰‹æœºï¼Œè¿™éžå¸¸å±é™©ã€‚"</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"强行é‡æ–°å¯åŠ¨æ‰‹æœº"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"å…许应用程åºå¼ºè¡Œé‡æ–°å¯åŠ¨æ‰‹æœºã€‚"</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"安装和å¸è½½æ–‡ä»¶ç³»ç»Ÿ"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"å…许应用程åºå®‰è£…å’Œå¸è½½å¯ç§»åŠ¨å­˜å‚¨å™¨çš„文件系统。"</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"æ ¼å¼åŒ–外部存储设备"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"å…许应用程åºæ ¼å¼åŒ–å¯ç§»é™¤çš„存储设备。"</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"控制振动器"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"å…许应用程åºæŽ§åˆ¶æŒ¯åŠ¨å™¨ã€‚"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"控制闪光ç¯"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"å…许应用程åºæŽ§åˆ¶é—ªå…‰ç¯ã€‚"</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"测试硬件"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"å…许应用程åºæŽ§åˆ¶å„ç§ç”¨äºŽç¡¬ä»¶æµ‹è¯•çš„外围设备。"</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"直接拨打电è¯å·ç "</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"å…许应用程åºåœ¨æ²¡æœ‰æ‚¨å¹²é¢„的情况下呼å«ç”µè¯å·ç ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤åœ¨æ‚¨çš„è¯è´¹å•ä¸Šäº§ç”Ÿæ„外通è¯è´¹ã€‚请注æ„,此æƒé™ä¸å…许应用程åºå‘¼å«ç´§æ€¥ç”µè¯å·ç ã€‚"</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"直接呼å«ä»»ä½•ç”µè¯å·ç "</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"å…许应用程åºåœ¨æ²¡æœ‰æ‚¨å¹²é¢„的情况下呼å«ä»»ä½•ç”µè¯å·ç ï¼ˆåŒ…括紧急电è¯å·ç ï¼‰ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å¯¹ç´§æ€¥æœåŠ¡æ‹¨æ‰“骚扰电è¯å’Œéžæ³•ç”µè¯ã€‚"</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"控制ä½ç½®æ›´æ–°é€šçŸ¥"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"å…许å¯ç”¨/åœç”¨æ”¶éŸ³æœºçš„ä½ç½®æ›´æ–°é€šçŸ¥ã€‚普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"访问检入属性"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"å…许对检入æœåŠ¡ä¸Šä¼ çš„属性进行读/写访问。普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"选择窗å£å°éƒ¨ä»¶"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"å…许应用程åºå‘Šè¯‰ç³»ç»Ÿå“ªä¸ªåº”用程åºå¯ä»¥ä½¿ç”¨å“ªäº›çª—å£å°éƒ¨ä»¶ã€‚具有该æƒé™çš„应用程åºå¯ä»¥å…许其他应用程åºè®¿é—®ä¸ªäººæ•°æ®ã€‚普通应用程åºä¸é€‚åˆä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"修改手机状æ€"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"å…许应用程åºæŽ§åˆ¶è®¾å¤‡çš„手机功能。具有此æƒé™çš„应用程åºå¯åˆ‡æ¢ç½‘络ã€æ‰“开和关闭手机收音机等,而ä¸é€šçŸ¥æ‚¨ã€‚"</string>
- <!-- no translation found for permlab_readPhoneState (2326172951448691631) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (188877305147626781) -->
- <skip />
- <string name="permlab_wakeLock" msgid="573480187941496130">"防止手机休眠"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"å…许应用程åºé˜²æ­¢æ‰‹æœºè¿›å…¥ä¼‘眠状æ€ã€‚"</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"开机或关机"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"å…许应用程åºæ‰“开或关闭手机。"</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"在出厂测试模å¼ä¸‹è¿è¡Œ"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"作为低级别制造商测试è¿è¡Œï¼Œä»¥å…许完全访问手机硬件。此æƒé™åªæœ‰å½“手机在制造商测试模å¼ä¸‹è¿è¡Œæ—¶æ‰å¯ç”¨ã€‚"</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"设置å£çº¸"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"å…许应用程åºè®¾ç½®ç³»ç»Ÿå£çº¸ã€‚"</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"设置å£çº¸å¤§å°æ示"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"å…许应用程åºè®¾ç½®ç³»ç»Ÿå£çº¸å¤§å°æ示。"</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"将系统é‡ç½®ä¸ºå‡ºåŽ‚时的默认设置"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"å…许应用程åºå°†ç³»ç»Ÿå®Œå…¨é‡ç½®ä¸ºå‡ºåŽ‚设置,å³æ¸…除所有数æ®ã€é…置和安装的应用程åºã€‚"</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"设置时区"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"å…许应用程åºæ›´æ”¹æ‰‹æœºçš„时区。"</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"å‘现已知å¸æˆ·"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"å…许应用程åºèŽ·å–手机已知的å¸æˆ·åˆ—表。"</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"查看网络状æ€"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"å…许应用程åºæŸ¥çœ‹æ‰€æœ‰ç½‘络的状æ€ã€‚"</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"互è”网完全访问"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"å…许应用程åºåˆ›å»ºç½‘络套接字。"</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"写入接入点å称设置"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"å…许应用程åºä¿®æ”¹ APN 设置,例如任何 APN 的代ç†å’Œç«¯å£ã€‚"</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"更改网络连接"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"å…许应用程åºæ›´æ”¹ç½‘络连接状æ€ã€‚"</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"更改背景数æ®ä½¿ç”¨è®¾ç½®"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"å…许应用程åºæ›´æ”¹èƒŒæ™¯æ•°æ®ä½¿ç”¨è®¾ç½®ã€‚"</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"查看 Wi-Fi 状æ€"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"å…许应用程åºæŸ¥çœ‹æœ‰å…³ Wi-Fi 状æ€çš„ä¿¡æ¯ã€‚"</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"更改 Wi-Fi 状æ€"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"å…许应用程åºè¿žæŽ¥åˆ° Wi-Fi 接入点以åŠä¸Ž Wi-Fi 接入点断开连接,并对é…置的 Wi-Fi 网络进行更改。"</string>
+ <string name="permlab_accessFineLocation">"精准ä½ç½® (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"访问精准的ä½ç½®æºï¼Œä¾‹å¦‚手机上的全çƒå®šä½ç³»ç»Ÿï¼ˆå¦‚果适用)。æ¶æ„应用程åºå¯èƒ½å€Ÿæ­¤ç¡®å®šæ‚¨æ‰€å¤„çš„ä½ç½®ï¼Œå¹¶æ¶ˆè€—é¢å¤–的电池电é‡ã€‚"</string>
+ <string name="permlab_accessCoarseLocation">"ç²—ç•¥ä½ç½®ï¼ˆæ‰€åœ¨ç½‘络)"</string>
+ <string name="permdesc_accessCoarseLocation">"访问粗略的ä½ç½®æºï¼ˆä¾‹å¦‚蜂çªç½‘络数æ®åº“)以确定手机的大体ä½ç½®ï¼ˆå¦‚果适用)。æ¶æ„应用程åºå¯å€Ÿæ­¤ç¡®å®šæ‚¨æ‰€å¤„的大体ä½ç½®ã€‚"</string>
+ <string name="permlab_accessSurfaceFlinger">"访问 SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"å…许应用程åºä½¿ç”¨ SurfaceFlinger 低级别功能。"</string>
+ <string name="permlab_readFrameBuffer">"读å–帧缓冲区"</string>
+ <string name="permdesc_readFrameBuffer">"å…许应用程åºè¯»å–帧缓冲区的内容。"</string>
+ <string name="permlab_modifyAudioSettings">"更改您的音频设置"</string>
+ <string name="permdesc_modifyAudioSettings">"å…许应用程åºä¿®æ”¹å…¨å±€éŸ³é¢‘设置,如音é‡å’Œè·¯ç”±ã€‚"</string>
+ <string name="permlab_recordAudio">"录音"</string>
+ <string name="permdesc_recordAudio">"å…许应用程åºè®¿é—®å½•éŸ³è·¯å¾„。"</string>
+ <string name="permlab_camera">"æ‹ç…§"</string>
+ <string name="permdesc_camera">"å…许应用程åºä½¿ç”¨ç›¸æœºæ‹ç…§ã€‚æ­¤æƒé™å…许应用程åºéšæ—¶æ”¶é›†ç›¸æœºçœ‹åˆ°çš„图片。"</string>
+ <string name="permlab_brick">"永久åœç”¨æ‰‹æœº"</string>
+ <string name="permdesc_brick">"å…许应用程åºæ°¸ä¹…åœç”¨æ•´ä¸ªæ‰‹æœºï¼Œè¿™éžå¸¸å±é™©ã€‚"</string>
+ <string name="permlab_reboot">"强行é‡æ–°å¯åŠ¨æ‰‹æœº"</string>
+ <string name="permdesc_reboot">"å…许应用程åºå¼ºè¡Œé‡æ–°å¯åŠ¨æ‰‹æœºã€‚"</string>
+ <string name="permlab_mount_unmount_filesystems">"安装和å¸è½½æ–‡ä»¶ç³»ç»Ÿ"</string>
+ <string name="permdesc_mount_unmount_filesystems">"å…许应用程åºå®‰è£…å’Œå¸è½½å¯ç§»åŠ¨å­˜å‚¨å™¨çš„文件系统。"</string>
+ <string name="permlab_mount_format_filesystems">"æ ¼å¼åŒ–外部存储设备"</string>
+ <string name="permdesc_mount_format_filesystems">"å…许应用程åºæ ¼å¼åŒ–å¯ç§»é™¤çš„存储设备。"</string>
+ <string name="permlab_vibrate">"控制振动器"</string>
+ <string name="permdesc_vibrate">"å…许应用程åºæŽ§åˆ¶æŒ¯åŠ¨å™¨ã€‚"</string>
+ <string name="permlab_flashlight">"控制闪光ç¯"</string>
+ <string name="permdesc_flashlight">"å…许应用程åºæŽ§åˆ¶é—ªå…‰ç¯ã€‚"</string>
+ <string name="permlab_hardware_test">"测试硬件"</string>
+ <string name="permdesc_hardware_test">"å…许应用程åºæŽ§åˆ¶å„ç§ç”¨äºŽç¡¬ä»¶æµ‹è¯•çš„外围设备。"</string>
+ <string name="permlab_callPhone">"直接拨打电è¯å·ç "</string>
+ <string name="permdesc_callPhone">"å…许应用程åºåœ¨æ²¡æœ‰æ‚¨å¹²é¢„的情况下呼å«ç”µè¯å·ç ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤åœ¨æ‚¨çš„è¯è´¹å•ä¸Šäº§ç”Ÿæ„外通è¯è´¹ã€‚请注æ„,此æƒé™ä¸å…许应用程åºå‘¼å«ç´§æ€¥ç”µè¯å·ç ã€‚"</string>
+ <string name="permlab_callPrivileged">"直接呼å«ä»»ä½•ç”µè¯å·ç "</string>
+ <string name="permdesc_callPrivileged">"å…许应用程åºåœ¨æ²¡æœ‰æ‚¨å¹²é¢„的情况下呼å«ä»»ä½•ç”µè¯å·ç ï¼ˆåŒ…括紧急电è¯å·ç ï¼‰ã€‚æ¶æ„应用程åºå¯å€Ÿæ­¤å¯¹ç´§æ€¥æœåŠ¡æ‹¨æ‰“骚扰电è¯å’Œéžæ³•ç”µè¯ã€‚"</string>
+ <string name="permlab_locationUpdates">"控制ä½ç½®æ›´æ–°é€šçŸ¥"</string>
+ <string name="permdesc_locationUpdates">"å…许å¯ç”¨/åœç”¨æ”¶éŸ³æœºçš„ä½ç½®æ›´æ–°é€šçŸ¥ã€‚普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_checkinProperties">"访问检入属性"</string>
+ <string name="permdesc_checkinProperties">"å…许对检入æœåŠ¡ä¸Šä¼ çš„属性进行读/写访问。普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_bindGadget">"选择窗å£å°éƒ¨ä»¶"</string>
+ <string name="permdesc_bindGadget">"å…许应用程åºå‘Šè¯‰ç³»ç»Ÿå“ªä¸ªåº”用程åºå¯ä»¥ä½¿ç”¨å“ªäº›çª—å£å°éƒ¨ä»¶ã€‚具有该æƒé™çš„应用程åºå¯ä»¥å…许其他应用程åºè®¿é—®ä¸ªäººæ•°æ®ã€‚普通应用程åºä¸é€‚åˆä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="permlab_modifyPhoneState">"修改手机状æ€"</string>
+ <string name="permdesc_modifyPhoneState">"å…许应用程åºæŽ§åˆ¶è®¾å¤‡çš„手机功能。具有此æƒé™çš„应用程åºå¯åˆ‡æ¢ç½‘络ã€æ‰“开和关闭手机收音机等,而ä¸é€šçŸ¥æ‚¨ã€‚"</string>
+ <string name="permlab_readPhoneState">"读å–手机状æ€"</string>
+ <string name="permdesc_readPhoneState">"å…许应用程åºè®¿é—®è®¾å¤‡çš„手机功能。具有此æƒé™çš„应用程åºå¯ç¡®å®šæ­¤æ‰‹æœºçš„å·ç ã€æ˜¯å¦åœ¨é€šè¯ä»¥åŠé€šè¯å¯¹æ–¹çš„å·ç ç­‰ã€‚"</string>
+ <string name="permlab_wakeLock">"防止手机休眠"</string>
+ <string name="permdesc_wakeLock">"å…许应用程åºé˜²æ­¢æ‰‹æœºè¿›å…¥ä¼‘眠状æ€ã€‚"</string>
+ <string name="permlab_devicePower">"开机或关机"</string>
+ <string name="permdesc_devicePower">"å…许应用程åºæ‰“开或关闭手机。"</string>
+ <string name="permlab_factoryTest">"在出厂测试模å¼ä¸‹è¿è¡Œ"</string>
+ <string name="permdesc_factoryTest">"作为低级别制造商测试è¿è¡Œï¼Œä»¥å…许完全访问手机硬件。此æƒé™åªæœ‰å½“手机在制造商测试模å¼ä¸‹è¿è¡Œæ—¶æ‰å¯ç”¨ã€‚"</string>
+ <string name="permlab_setWallpaper">"设置å£çº¸"</string>
+ <string name="permdesc_setWallpaper">"å…许应用程åºè®¾ç½®ç³»ç»Ÿå£çº¸ã€‚"</string>
+ <string name="permlab_setWallpaperHints">"设置å£çº¸å¤§å°æ示"</string>
+ <string name="permdesc_setWallpaperHints">"å…许应用程åºè®¾ç½®ç³»ç»Ÿå£çº¸å¤§å°æ示。"</string>
+ <string name="permlab_masterClear">"将系统é‡ç½®ä¸ºå‡ºåŽ‚时的默认设置"</string>
+ <string name="permdesc_masterClear">"å…许应用程åºå°†ç³»ç»Ÿå®Œå…¨é‡ç½®ä¸ºå‡ºåŽ‚设置,å³æ¸…除所有数æ®ã€é…置和安装的应用程åºã€‚"</string>
+ <string name="permlab_setTimeZone">"设置时区"</string>
+ <string name="permdesc_setTimeZone">"å…许应用程åºæ›´æ”¹æ‰‹æœºçš„时区。"</string>
+ <string name="permlab_getAccounts">"å‘现已知å¸æˆ·"</string>
+ <string name="permdesc_getAccounts">"å…许应用程åºèŽ·å–手机已知的å¸æˆ·åˆ—表。"</string>
+ <string name="permlab_accessNetworkState">"查看网络状æ€"</string>
+ <string name="permdesc_accessNetworkState">"å…许应用程åºæŸ¥çœ‹æ‰€æœ‰ç½‘络的状æ€ã€‚"</string>
+ <string name="permlab_createNetworkSockets">"ä¸å—é™åˆ¶çš„互è”网访问æƒé™"</string>
+ <string name="permdesc_createNetworkSockets">"å…许应用程åºåˆ›å»ºç½‘络套接字。"</string>
+ <string name="permlab_writeApnSettings">"写入接入点å称设置"</string>
+ <string name="permdesc_writeApnSettings">"å…许应用程åºä¿®æ”¹ APN 设置,例如任何 APN 的代ç†å’Œç«¯å£ã€‚"</string>
+ <string name="permlab_changeNetworkState">"更改网络连接"</string>
+ <string name="permdesc_changeNetworkState">"å…许应用程åºæ›´æ”¹ç½‘络连接状æ€ã€‚"</string>
+ <string name="permlab_changeBackgroundDataSetting">"更改背景数æ®ä½¿ç”¨è®¾ç½®"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"å…许应用程åºæ›´æ”¹èƒŒæ™¯æ•°æ®ä½¿ç”¨è®¾ç½®ã€‚"</string>
+ <string name="permlab_accessWifiState">"查看 Wi-Fi 状æ€"</string>
+ <string name="permdesc_accessWifiState">"å…许应用程åºæŸ¥çœ‹æœ‰å…³ Wi-Fi 状æ€çš„ä¿¡æ¯ã€‚"</string>
+ <string name="permlab_changeWifiState">"更改 Wi-Fi 状æ€"</string>
+ <string name="permdesc_changeWifiState">"å…许应用程åºè¿žæŽ¥åˆ° Wi-Fi 接入点以åŠä¸Ž Wi-Fi 接入点断开连接,并对é…置的 Wi-Fi 网络进行更改。"</string>
<!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
<skip />
<!-- no translation found for permdesc_changeWifiMulticastState (8199464507656067553) -->
<skip />
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"è“牙管ç†"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"å…许应用程åºé…置本地è“牙手机,以åŠæŸ¥æ‰¾è¿œç¨‹è®¾å¤‡å¹¶ä¸Žä¹‹é…对。"</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"创建è“牙连接"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"å…许应用程åºæŸ¥çœ‹æœ¬åœ°è“牙手机的é…置,以åŠå»ºç«‹å’ŒæŽ¥å—与é…对设备的连接。"</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"åœç”¨é”®é”"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"å…许应用程åºåœç”¨é”®é”和任何关è”的密ç å®‰å…¨è®¾ç½®ã€‚è¿™ç§æƒ…况的一个æ°å½“示例就是这样一个手机:在接å¬æ¥ç”µæ—¶åœç”¨é”®é”,在通è¯ç»“æŸåŽé‡æ–°å¯ç”¨é”®é”。"</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"读å–åŒæ­¥è®¾ç½®"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"å…许应用程åºè¯»å–åŒæ­¥è®¾ç½®ï¼Œä¾‹å¦‚是å¦é’ˆå¯¹è”系人å¯ç”¨åŒæ­¥ã€‚"</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"写入åŒæ­¥è®¾ç½®"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"å…许应用程åºä¿®æ”¹åŒæ­¥è®¾ç½®ï¼Œä¾‹å¦‚是å¦é’ˆå¯¹è”系人å¯ç”¨åŒæ­¥ã€‚"</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"读å–åŒæ­¥ç»Ÿè®¡ä¿¡æ¯"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"å…许应用程åºè¯»å–åŒæ­¥ç»Ÿè®¡ä¿¡æ¯ï¼›ä¾‹å¦‚å·²å‘生的åŒæ­¥åŽ†å²è®°å½•ã€‚"</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"读å–订阅的供稿"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"å…许应用程åºèŽ·å–有关当å‰åŒæ­¥çš„供稿的详细信æ¯ã€‚"</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"写入订阅的供稿"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"å…许应用程åºä¿®æ”¹æ‚¨å½“å‰åŒæ­¥çš„供稿。æ¶æ„应用程åºå¯å€Ÿæ­¤æ›´æ”¹æ‚¨åŒæ­¥çš„供稿。"</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"读å–用户定义的è¯å…¸"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"å…许应用程åºè¯»å–用户在用户è¯å…¸ä¸­å­˜å‚¨çš„ä»»æ„ç§æœ‰å­—è¯ã€å称和短语。"</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"写入用户定义的è¯å…¸"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"å…许应用程åºå‘用户è¯å…¸ä¸­å†™å…¥æ–°è¯ã€‚"</string>
+ <string name="permlab_bluetoothAdmin">"è“牙管ç†"</string>
+ <string name="permdesc_bluetoothAdmin">"å…许应用程åºé…置本地è“牙手机,以åŠæŸ¥æ‰¾è¿œç¨‹è®¾å¤‡å¹¶ä¸Žä¹‹é…对。"</string>
+ <string name="permlab_bluetooth">"创建è“牙连接"</string>
+ <string name="permdesc_bluetooth">"å…许应用程åºæŸ¥çœ‹æœ¬åœ°è“牙手机的é…置,以åŠå»ºç«‹å’ŒæŽ¥å—与é…对设备的连接。"</string>
+ <string name="permlab_disableKeyguard">"åœç”¨é”®é”"</string>
+ <string name="permdesc_disableKeyguard">"å…许应用程åºåœç”¨é”®é”和任何关è”的密ç å®‰å…¨è®¾ç½®ã€‚è¿™ç§æƒ…况的一个æ°å½“示例就是这样一个手机:在接å¬æ¥ç”µæ—¶åœç”¨é”®é”,在通è¯ç»“æŸåŽé‡æ–°å¯ç”¨é”®é”。"</string>
+ <string name="permlab_readSyncSettings">"读å–åŒæ­¥è®¾ç½®"</string>
+ <string name="permdesc_readSyncSettings">"å…许应用程åºè¯»å–åŒæ­¥è®¾ç½®ï¼Œä¾‹å¦‚是å¦é’ˆå¯¹è”系人å¯ç”¨åŒæ­¥ã€‚"</string>
+ <string name="permlab_writeSyncSettings">"写入åŒæ­¥è®¾ç½®"</string>
+ <string name="permdesc_writeSyncSettings">"å…许应用程åºä¿®æ”¹åŒæ­¥è®¾ç½®ï¼Œä¾‹å¦‚是å¦é’ˆå¯¹è”系人å¯ç”¨åŒæ­¥ã€‚"</string>
+ <string name="permlab_readSyncStats">"读å–åŒæ­¥ç»Ÿè®¡ä¿¡æ¯"</string>
+ <string name="permdesc_readSyncStats">"å…许应用程åºè¯»å–åŒæ­¥ç»Ÿè®¡ä¿¡æ¯ï¼›ä¾‹å¦‚å·²å‘生的åŒæ­¥åŽ†å²è®°å½•ã€‚"</string>
+ <string name="permlab_subscribedFeedsRead">"读å–订阅的供稿"</string>
+ <string name="permdesc_subscribedFeedsRead">"å…许应用程åºèŽ·å–有关当å‰åŒæ­¥çš„供稿的详细信æ¯ã€‚"</string>
+ <string name="permlab_subscribedFeedsWrite">"写入订阅的供稿"</string>
+ <string name="permdesc_subscribedFeedsWrite">"å…许应用程åºä¿®æ”¹æ‚¨å½“å‰åŒæ­¥çš„供稿。æ¶æ„应用程åºå¯å€Ÿæ­¤æ›´æ”¹æ‚¨åŒæ­¥çš„供稿。"</string>
+ <string name="permlab_readDictionary">"读å–用户定义的è¯å…¸"</string>
+ <string name="permdesc_readDictionary">"å…许应用程åºè¯»å–用户在用户è¯å…¸ä¸­å­˜å‚¨çš„ä»»æ„ç§æœ‰å­—è¯ã€å称和短语。"</string>
+ <string name="permlab_writeDictionary">"写入用户定义的è¯å…¸"</string>
+ <string name="permdesc_writeDictionary">"å…许应用程åºå‘用户è¯å…¸ä¸­å†™å…¥æ–°è¯ã€‚"</string>
<!-- no translation found for permlab_sdcardWrite (8079403759001777291) -->
<skip />
<!-- no translation found for permdesc_sdcardWrite (6643963204976471878) -->
<skip />
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"ä½å®…电è¯"</item>
- <item msgid="869923650527136615">"手机"</item>
- <item msgid="7897544654242874543">"å•ä½ç”µè¯"</item>
- <item msgid="1103601433382158155">"å•ä½ä¼ çœŸ"</item>
- <item msgid="1735177144948329370">"ä½å®…传真"</item>
- <item msgid="603878674477207394">"寻呼机"</item>
- <item msgid="1650824275177931637">"其他电è¯"</item>
- <item msgid="9192514806975898961">"自定义电è¯"</item>
+ <item>"ä½å®…电è¯"</item>
+ <item>"手机"</item>
+ <item>"å•ä½ç”µè¯"</item>
+ <item>"å•ä½ä¼ çœŸ"</item>
+ <item>"ä½å®…传真"</item>
+ <item>"寻呼机"</item>
+ <item>"其他电è¯"</item>
+ <item>"自定义电è¯"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"主è¦é‚®ç®±"</item>
- <item msgid="7084237356602625604">"å•ä½é‚®ç®±"</item>
- <item msgid="1112044410659011023">"其他邮箱"</item>
- <item msgid="2374913952870110618">"自定义邮箱"</item>
+ <item>"ä½å®…邮箱"</item>
+ <item>"å•ä½é‚®ç®±"</item>
+ <item>"其他邮箱"</item>
+ <item>"自定义邮箱"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"手机"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"ä½å®…地å€"</item>
- <item msgid="5629153956045109251">"å•ä½åœ°å€"</item>
- <item msgid="4966604264500343469">"其他地å€"</item>
- <item msgid="4932682847595299369">"自定义地å€"</item>
+ <item>"ä½å®…地å€"</item>
+ <item>"å•ä½åœ°å€"</item>
+ <item>"其他地å€"</item>
+ <item>"自定义地å€"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"ä½å®…èŠå¤©å·¥å…·"</item>
- <item msgid="1359644565647383708">"å•ä½èŠå¤©å·¥å…·"</item>
- <item msgid="7868549401053615677">"其他èŠå¤©å·¥å…·"</item>
- <item msgid="3145118944639869809">"自定义èŠå¤©å·¥å…·"</item>
+ <item>"ä½å®…èŠå¤©å·¥å…·"</item>
+ <item>"å•ä½èŠå¤©å·¥å…·"</item>
+ <item>"其他èŠå¤©å·¥å…·"</item>
+ <item>"自定义èŠå¤©å·¥å…·"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"å•ä½"</item>
- <item msgid="4378074129049520373">"其他组织"</item>
- <item msgid="3455047468583965104">"自定义组织"</item>
+ <item>"å•ä½"</item>
+ <item>"其他组织"</item>
+ <item>"自定义组织"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"中国雅虎"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"中国雅虎"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"输入 PIN ç "</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"PIN ç ä¸æ­£ç¡®ï¼"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"è¦è§£é”,请先按 MENU å†æŒ‰ 0。"</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"紧急电è¯å·ç "</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(无æœåŠ¡ï¼‰"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"å±å¹•å·²é”定。"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"按 MENU 解é”或拨打紧急电è¯ã€‚"</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"按 MENU 解é”。"</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"绘制解é”图案"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"紧急呼å«"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"正确ï¼"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"很抱歉,请é‡è¯•"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"正在充电 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_password_enter_pin_code">"输入 PIN ç "</string>
+ <string name="keyguard_password_wrong_pin_code">"PIN ç ä¸æ­£ç¡®ï¼"</string>
+ <string name="keyguard_label_text">"è¦è§£é”,请先按 MENU å†æŒ‰ 0。"</string>
+ <string name="emergency_call_dialog_number_for_display">"紧急电è¯å·ç "</string>
+ <string name="lockscreen_carrier_default">"(无æœåŠ¡ï¼‰"</string>
+ <string name="lockscreen_screen_locked">"å±å¹•å·²é”定。"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"按 MENU 解é”或拨打紧急电è¯ã€‚"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"按 MENU 解é”。"</string>
+ <string name="lockscreen_pattern_instructions">"绘制解é”图案"</string>
+ <string name="lockscreen_emergency_call">"紧急呼å«"</string>
+ <string name="lockscreen_pattern_correct">"正确ï¼"</string>
+ <string name="lockscreen_pattern_wrong">"很抱歉,请é‡è¯•"</string>
+ <string name="lockscreen_plugged_in">"正在充电 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
<!-- no translation found for lockscreen_charged (4938930459620989972) -->
<skip />
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"连接您的充电器。"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"没有 SIM å¡ã€‚"</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"手机中无 SIM å¡ã€‚"</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"请æ’å…¥ SIM å¡ã€‚"</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"网络已é”定"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM å¡è¢« PUK é”定。"</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"请å‚阅《用户指å—》或è”系客æœäººå‘˜ã€‚"</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM å¡è¢«é”定。"</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"æ­£åœ¨è§£é” SIM å¡..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"æ‚¨å·²ç» <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解é”图案。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒åŽé‡è¯•ã€‚"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"æ‚¨å·²ç» <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解é”图案。如果å†å°è¯• <xliff:g id="NUMBER_1">%d</xliff:g> 次åŽä»ä¸æˆåŠŸï¼Œç³»ç»Ÿä¼šè¦æ±‚您使用自己的 Google 登录信æ¯è§£é”手机。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒åŽé‡è¯•ã€‚"</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> 秒åŽé‡è¯•ã€‚"</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"忘记了图案?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"图案å°è¯•æ¬¡æ•°è¿‡å¤šï¼"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"è¦è§£é™¤é”定,请使用您的 Google å¸æˆ·ç™»å½•"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"用户å(电å­é‚®ä»¶ï¼‰"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"密ç "</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"登录"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"用户å或密ç æ— æ•ˆã€‚"</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="AMPM">%P</xliff:g><xliff:g id="HOUR">%-l</xliff:g>点"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="AMPM">%p</xliff:g><xliff:g id="HOUR">%-l</xliff:g>点"</string>
+ <string name="lockscreen_low_battery">"连接您的充电器。"</string>
+ <string name="lockscreen_missing_sim_message_short">"没有 SIM å¡ã€‚"</string>
+ <string name="lockscreen_missing_sim_message">"手机中无 SIM å¡ã€‚"</string>
+ <string name="lockscreen_missing_sim_instructions">"请æ’å…¥ SIM å¡ã€‚"</string>
+ <string name="lockscreen_network_locked_message">"网络已é”定"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM å¡è¢« PUK é”定。"</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"请å‚阅《用户指å—》或è”系客æœäººå‘˜ã€‚"</string>
+ <string name="lockscreen_sim_locked_message">"SIM å¡è¢«é”定。"</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"æ­£åœ¨è§£é” SIM å¡..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"æ‚¨å·²ç» <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解é”图案。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒åŽé‡è¯•ã€‚"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"æ‚¨å·²ç» <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解é”图案。如果å†å°è¯• <xliff:g id="NUMBER_1">%d</xliff:g> 次åŽä»ä¸æˆåŠŸï¼Œç³»ç»Ÿä¼šè¦æ±‚您使用自己的 Google 登录信æ¯è§£é”手机。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒åŽé‡è¯•ã€‚"</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g> 秒åŽé‡è¯•ã€‚"</string>
+ <string name="lockscreen_forgot_pattern_button_text">"忘记了图案?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"图案å°è¯•æ¬¡æ•°è¿‡å¤šï¼"</string>
+ <string name="lockscreen_glogin_instructions">"è¦è§£é™¤é”定,请使用您的 Google å¸æˆ·ç™»å½•"</string>
+ <string name="lockscreen_glogin_username_hint">"用户å(电å­é‚®ä»¶ï¼‰"</string>
+ <string name="lockscreen_glogin_password_hint">"密ç "</string>
+ <string name="lockscreen_glogin_submit_button">"登录"</string>
+ <string name="lockscreen_glogin_invalid_input">"用户å或密ç æ— æ•ˆã€‚"</string>
+ <string name="hour_ampm">"<xliff:g id="AMPM">%P</xliff:g><xliff:g id="HOUR">%-l</xliff:g>点"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="AMPM">%p</xliff:g><xliff:g id="HOUR">%-l</xliff:g>点"</string>
<!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
<skip />
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"无通知"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"正在进行"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"正在充电..."</string>
- <string name="battery_low_title" msgid="7923774589611311406">"请连接充电器"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"电é‡åœ¨å‡å°‘:"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"剩余电é‡ä¸è¶³ <xliff:g id="NUMBER">%d%%</xliff:g>。"</string>
+ <string name="status_bar_no_notifications_title">"无通知"</string>
+ <string name="status_bar_ongoing_events_title">"正在进行"</string>
+ <string name="status_bar_latest_events_title">"通知"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"正在充电..."</string>
+ <string name="battery_low_title">"请连接充电器"</string>
+ <string name="battery_low_subtitle">"电é‡åœ¨å‡å°‘:"</string>
+ <string name="battery_low_percent_format">"剩余电é‡ä¸è¶³ <xliff:g id="NUMBER">%d%%</xliff:g>。"</string>
<!-- no translation found for battery_low_why (7655196144309694753) -->
<skip />
- <string name="factorytest_failed" msgid="5410270329114212041">"出厂测试失败"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"åªæœ‰ /system/app ä¸­å®‰è£…çš„åŒ…æ”¯æŒ FACTORY_TEST æ“作。"</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"未å‘çŽ°æ”¯æŒ FACTORY_TEST æ“作的包。"</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"é‡æ–°å¯åŠ¨"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"“<xliff:g id="TITLE">%s</xliff:g>â€å¤„的页é¢è¡¨æ˜Žï¼š"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"是å¦ä»Žè¯¥é¡µé¢å¯¼èˆªè‡³å®ƒå¤„?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"选择“确定â€ç»§ç»­ï¼Œæˆ–选择“å–消â€ç•™åœ¨å½“å‰é¡µé¢ã€‚"</string>
- <string name="save_password_label" msgid="6860261758665825069">"确认"</string>
+ <string name="factorytest_failed">"出厂测试失败"</string>
+ <string name="factorytest_not_system">"åªæœ‰ /system/app ä¸­å®‰è£…çš„åŒ…æ”¯æŒ FACTORY_TEST æ“作。"</string>
+ <string name="factorytest_no_action">"未å‘çŽ°æ”¯æŒ FACTORY_TEST æ“作的包。"</string>
+ <string name="factorytest_reboot">"é‡æ–°å¯åŠ¨"</string>
+ <string name="js_dialog_title">"“<xliff:g id="TITLE">%s</xliff:g>â€å¤„的页é¢è¡¨æ˜Žï¼š"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"是å¦ä»Žè¯¥é¡µé¢å¯¼èˆªè‡³å®ƒå¤„?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"选择“确定â€ç»§ç»­ï¼Œæˆ–选择“å–消â€ç•™åœ¨å½“å‰é¡µé¢ã€‚"</string>
+ <string name="save_password_label">"确认"</string>
<!-- no translation found for permlab_readHistoryBookmarks (1284843728203412135) -->
<skip />
<!-- no translation found for permdesc_readHistoryBookmarks (4981489815467617191) -->
@@ -521,243 +518,243 @@
<skip />
<!-- no translation found for permdesc_writeHistoryBookmarks (945571990357114950) -->
<skip />
- <string name="save_password_message" msgid="767344687139195790">"是å¦å¸Œæœ›æµè§ˆå™¨è®°ä½æ­¤å¯†ç ï¼Ÿ"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"此时ä¸ä¿å­˜å¯†ç "</string>
- <string name="save_password_remember" msgid="6491879678996749466">"è®°ä½"</string>
- <string name="save_password_never" msgid="8274330296785855105">"从ä¸"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"您无æƒæ‰“开此网页。"</string>
- <string name="text_copied" msgid="4985729524670131385">"文字已å¤åˆ¶åˆ°å‰ªè´´æ¿ã€‚"</string>
- <string name="more_item_label" msgid="4650918923083320495">"更多"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"MENU+"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"空格"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Enter é”®"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"删除"</string>
- <string name="search_go" msgid="8298016669822141719">"æœç´¢"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 个月å‰"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 个月å‰"</string>
+ <string name="save_password_message">"是å¦å¸Œæœ›æµè§ˆå™¨è®°ä½æ­¤å¯†ç ï¼Ÿ"</string>
+ <string name="save_password_notnow">"此时ä¸ä¿å­˜å¯†ç "</string>
+ <string name="save_password_remember">"è®°ä½"</string>
+ <string name="save_password_never">"从ä¸"</string>
+ <string name="open_permission_deny">"您无æƒæ‰“开此网页。"</string>
+ <string name="text_copied">"文字已å¤åˆ¶åˆ°å‰ªè´´æ¿ã€‚"</string>
+ <string name="more_item_label">"更多"</string>
+ <string name="prepend_shortcut_label">"MENU+"</string>
+ <string name="menu_space_shortcut_label">"空格"</string>
+ <string name="menu_enter_shortcut_label">"Enter é”®"</string>
+ <string name="menu_delete_shortcut_label">"删除"</string>
+ <string name="search_go">"æœç´¢"</string>
+ <string name="oneMonthDurationPast">"1 个月å‰"</string>
+ <string name="beforeOneMonthDurationPast">"1 个月å‰"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 秒å‰"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒å‰"</item>
+ <item quantity="one">"1 秒å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒å‰"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 分钟å‰"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分钟å‰"</item>
+ <item quantity="one">"1 分钟å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分钟å‰"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 å°æ—¶å‰"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> å°æ—¶å‰"</item>
+ <item quantity="one">"1 å°æ—¶å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> å°æ—¶å‰"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"昨天"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天å‰"</item>
+ <item quantity="one">"昨天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天å‰"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 秒åŽ"</item>
- <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> 秒åŽ"</item>
+ <item quantity="one">"1 秒åŽ"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒åŽ"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 分钟åŽ"</item>
- <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> 分钟åŽ"</item>
+ <item quantity="one">"1 分钟åŽ"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分钟åŽ"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 å°æ—¶åŽ"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> å°æ—¶åŽ"</item>
+ <item quantity="one">"1 å°æ—¶åŽ"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> å°æ—¶åŽ"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"明天"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天åŽ"</item>
+ <item quantity="one">"明天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天åŽ"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 秒å‰"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> 秒å‰"</item>
+ <item quantity="one">"1 秒å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒å‰"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 分钟å‰"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> 分钟å‰"</item>
+ <item quantity="one">"1 分钟å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分钟å‰"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 å°æ—¶å‰"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> å°æ—¶å‰"</item>
+ <item quantity="one">"1 å°æ—¶å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> å°æ—¶å‰"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"昨天"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天å‰"</item>
+ <item quantity="one">"昨天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天å‰"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 秒åŽ"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> 秒åŽ"</item>
+ <item quantity="one">"1 秒åŽ"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒åŽ"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 分钟åŽ"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> 分钟åŽ"</item>
+ <item quantity="one">"1 分钟åŽ"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分钟åŽ"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 å°æ—¶åŽ"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> å°æ—¶åŽ"</item>
+ <item quantity="one">"1 å°æ—¶åŽ"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> å°æ—¶åŽ"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"明天"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天åŽ"</item>
+ <item quantity="one">"明天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天åŽ"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"在 %s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"在%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s å¹´"</string>
- <string name="day" msgid="8144195776058119424">"天"</string>
- <string name="days" msgid="4774547661021344602">"天"</string>
- <string name="hour" msgid="2126771916426189481">"å°æ—¶"</string>
- <string name="hours" msgid="894424005266852993">"å°æ—¶"</string>
- <string name="minute" msgid="9148878657703769868">"分钟"</string>
- <string name="minutes" msgid="5646001005827034509">"分钟"</string>
- <string name="second" msgid="3184235808021478">"秒"</string>
- <string name="seconds" msgid="3161515347216589235">"秒"</string>
- <string name="week" msgid="5617961537173061583">"周"</string>
- <string name="weeks" msgid="6509623834583944518">"周"</string>
- <string name="year" msgid="4001118221013892076">"å¹´"</string>
- <string name="years" msgid="6881577717993213522">"å¹´"</string>
- <string name="every_weekday" msgid="8777593878457748503">"æ¯ä¸ªå·¥ä½œæ—¥ï¼ˆå‘¨ä¸€è‡³å‘¨äº”)"</string>
- <string name="daily" msgid="5738949095624133403">"æ¯å¤©"</string>
- <string name="weekly" msgid="983428358394268344">"æ¯å‘¨çš„<xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"æ¯æœˆ"</string>
- <string name="yearly" msgid="1519577999407493836">"æ¯å¹´"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"无法播放视频"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"抱歉,该视频ä¸é€‚åˆåœ¨æ­¤è®¾å¤‡ä¸Šæ’­æ”¾ã€‚"</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"很抱歉,无法播放此视频。"</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"确定"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>,<xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"中åˆ"</string>
- <string name="Noon" msgid="3342127745230013127">"中åˆ"</string>
- <string name="midnight" msgid="7166259508850457595">"åˆå¤œ"</string>
- <string name="Midnight" msgid="5630806906897892201">"åˆå¤œ"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"全选"</string>
- <string name="selectText" msgid="3889149123626888637">"选择文字"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"åœæ­¢é€‰æ‹©æ–‡å­—"</string>
- <string name="cut" msgid="3092569408438626261">"剪切"</string>
- <string name="cutAll" msgid="2436383270024931639">"全部剪切"</string>
- <string name="copy" msgid="2681946229533511987">"å¤åˆ¶"</string>
- <string name="copyAll" msgid="2590829068100113057">"全部å¤åˆ¶"</string>
- <string name="paste" msgid="5629880836805036433">"粘贴"</string>
- <string name="copyUrl" msgid="2538211579596067402">"å¤åˆ¶ç½‘å€"</string>
- <string name="inputMethod" msgid="7673923508389094672">"输入法"</string>
- <string name="addToDictionary" msgid="726256909274177272">"将“%sâ€æ·»åŠ åˆ°è¯å…¸"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"编辑文字"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"空间ä¸è¶³"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"手机存储空间正在å‡å°‘。"</string>
- <string name="ok" msgid="5970060430562524910">"确定"</string>
- <string name="cancel" msgid="6442560571259935130">"å–消"</string>
- <string name="yes" msgid="5362982303337969312">"确定"</string>
- <string name="no" msgid="5141531044935541497">"å–消"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"注æ„事项"</string>
- <string name="capital_on" msgid="1544682755514494298">"å¼€å¯"</string>
- <string name="capital_off" msgid="6815870386972805832">"关闭"</string>
- <string name="whichApplication" msgid="4533185947064773386">"使用以下内容完æˆæ“作"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"默认用于执行此æ“作。"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"清除“主å±å¹•è®¾ç½®â€&gt;“应用程åºâ€&gt;“管ç†åº”用程åºâ€ä¸­çš„默认设置。"</string>
- <string name="chooseActivity" msgid="1009246475582238425">"选择一项æ“作"</string>
- <string name="noApplications" msgid="1691104391758345586">"没有应用程åºå¯æ‰§è¡Œæ­¤æ“作。"</string>
- <string name="aerr_title" msgid="653922989522758100">"很抱歉ï¼"</string>
- <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g>应用程åºï¼ˆ<xliff:g id="PROCESS">%2$s</xliff:g> 进程)æ„外åœæ­¢ï¼Œè¯·é‡è¯•ã€‚"</string>
- <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g> 进程æ„外åœæ­¢ï¼Œè¯·é‡è¯•ã€‚"</string>
- <string name="anr_title" msgid="3100070910664756057">"很抱歉ï¼"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="ACTIVITY">%1$s</xliff:g>活动(在<xliff:g id="APPLICATION">%2$s</xliff:g>应用程åºä¸­ï¼‰æ— å“应。"</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g>活动(在 <xliff:g id="PROCESS">%2$s</xliff:g> 进程中)无å“应。"</string>
- <string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g>应用程åºï¼ˆåœ¨ <xliff:g id="PROCESS">%2$s</xliff:g> 进程中)无å“应。"</string>
- <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> 进程无å“应。"</string>
- <string name="force_close" msgid="3653416315450806396">"强行关闭"</string>
+ <string name="preposition_for_date">"在 %s"</string>
+ <string name="preposition_for_time">"在%s"</string>
+ <string name="preposition_for_year">"%s å¹´"</string>
+ <string name="day">"天"</string>
+ <string name="days">"天"</string>
+ <string name="hour">"å°æ—¶"</string>
+ <string name="hours">"å°æ—¶"</string>
+ <string name="minute">"分钟"</string>
+ <string name="minutes">"分钟"</string>
+ <string name="second">"秒"</string>
+ <string name="seconds">"秒"</string>
+ <string name="week">"周"</string>
+ <string name="weeks">"周"</string>
+ <string name="year">"å¹´"</string>
+ <string name="years">"å¹´"</string>
+ <string name="every_weekday">"æ¯ä¸ªå·¥ä½œæ—¥ï¼ˆå‘¨ä¸€è‡³å‘¨äº”)"</string>
+ <string name="daily">"æ¯å¤©"</string>
+ <string name="weekly">"æ¯å‘¨çš„<xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"æ¯æœˆ"</string>
+ <string name="yearly">"æ¯å¹´"</string>
+ <string name="VideoView_error_title">"无法播放视频"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"抱歉,该视频ä¸é€‚åˆåœ¨æ­¤è®¾å¤‡ä¸Šæ’­æ”¾ã€‚"</string>
+ <string name="VideoView_error_text_unknown">"很抱歉,无法播放此视频。"</string>
+ <string name="VideoView_error_button">"确定"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>,<xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"中åˆ"</string>
+ <string name="Noon">"中åˆ"</string>
+ <string name="midnight">"åˆå¤œ"</string>
+ <string name="Midnight">"åˆå¤œ"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"全选"</string>
+ <string name="selectText">"选择文字"</string>
+ <string name="stopSelectingText">"åœæ­¢é€‰æ‹©æ–‡å­—"</string>
+ <string name="cut">"剪切"</string>
+ <string name="cutAll">"全部剪切"</string>
+ <string name="copy">"å¤åˆ¶"</string>
+ <string name="copyAll">"全部å¤åˆ¶"</string>
+ <string name="paste">"粘贴"</string>
+ <string name="copyUrl">"å¤åˆ¶ç½‘å€"</string>
+ <string name="inputMethod">"输入法"</string>
+ <string name="addToDictionary">"将“%sâ€æ·»åŠ åˆ°è¯å…¸"</string>
+ <string name="editTextMenuTitle">"编辑文字"</string>
+ <string name="low_internal_storage_view_title">"空间ä¸è¶³"</string>
+ <string name="low_internal_storage_view_text">"手机存储空间正在å‡å°‘。"</string>
+ <string name="ok">"确定"</string>
+ <string name="cancel">"å–消"</string>
+ <string name="yes">"确定"</string>
+ <string name="no">"å–消"</string>
+ <string name="dialog_alert_title">"注æ„事项"</string>
+ <string name="capital_on">"å¼€å¯"</string>
+ <string name="capital_off">"关闭"</string>
+ <string name="whichApplication">"使用以下内容完æˆæ“作"</string>
+ <string name="alwaysUse">"默认用于执行此æ“作。"</string>
+ <string name="clearDefaultHintMsg">"清除“主å±å¹•è®¾ç½®â€&gt;“应用程åºâ€&gt;“管ç†åº”用程åºâ€ä¸­çš„默认设置。"</string>
+ <string name="chooseActivity">"选择一项æ“作"</string>
+ <string name="noApplications">"没有应用程åºå¯æ‰§è¡Œæ­¤æ“作。"</string>
+ <string name="aerr_title">"很抱歉ï¼"</string>
+ <string name="aerr_application">"应用程åº<xliff:g id="APPLICATION">%1$s</xliff:g>(进程 <xliff:g id="PROCESS">%2$s</xliff:g>)æ„外åœæ­¢ï¼Œè¯·é‡è¯•ã€‚"</string>
+ <string name="aerr_process">"进程 <xliff:g id="PROCESS">%1$s</xliff:g> å·²æ„外åœæ­¢ï¼Œè¯·é‡è¯•ã€‚"</string>
+ <string name="anr_title">"很抱歉ï¼"</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g>活动(在 <xliff:g id="APPLICATION">%2$s</xliff:g>应用程åºä¸­ï¼‰æ— å“应。"</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g>活动(在<xliff:g id="PROCESS">%2$s</xliff:g>进程中)无å“应。"</string>
+ <string name="anr_application_process">"<xliff:g id="APPLICATION">%1$s</xliff:g>应用程åºï¼ˆåœ¨<xliff:g id="PROCESS">%2$s</xliff:g>进程中)无å“应。"</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>进程无å“应。"</string>
+ <string name="force_close">"强行关闭"</string>
<!-- no translation found for report (4060218260984795706) -->
<skip />
- <string name="wait" msgid="7147118217226317732">"等待"</string>
- <string name="debug" msgid="9103374629678531849">"调试"</string>
- <string name="sendText" msgid="5132506121645618310">"选择è¦å¯¹æ–‡å­—执行的æ“作"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"铃声音é‡"</string>
- <string name="volume_music" msgid="5421651157138628171">"媒体音é‡"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"通过è“牙播放"</string>
- <string name="volume_call" msgid="3941680041282788711">"通è¯éŸ³é‡"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"使用è“牙时的通è¯éŸ³é‡"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"闹钟音é‡"</string>
- <string name="volume_notification" msgid="2422265656744276715">"通知音é‡"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"音é‡"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"默认铃声"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"默认铃声(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"é™éŸ³"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"铃声"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"未知铃声"</string>
+ <string name="wait">"等待"</string>
+ <string name="debug">"调试"</string>
+ <string name="sendText">"选择è¦å¯¹æ–‡å­—执行的æ“作"</string>
+ <string name="volume_ringtone">"铃声音é‡"</string>
+ <string name="volume_music">"媒体音é‡"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"通过è“牙播放"</string>
+ <string name="volume_call">"通è¯éŸ³é‡"</string>
+ <string name="volume_bluetooth_call">"使用è“牙时的通è¯éŸ³é‡"</string>
+ <string name="volume_alarm">"闹钟音é‡"</string>
+ <string name="volume_notification">"通知音é‡"</string>
+ <string name="volume_unknown">"音é‡"</string>
+ <string name="ringtone_default">"默认铃声"</string>
+ <string name="ringtone_default_with_actual">"默认铃声(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"é™éŸ³"</string>
+ <string name="ringtone_picker_title">"铃声"</string>
+ <string name="ringtone_unknown">"未知铃声"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"有å¯ç”¨çš„ Wi-Fi 网络"</item>
- <item quantity="other" msgid="4192424489168397386">"有å¯ç”¨çš„ Wi-Fi 网络"</item>
+ <item quantity="one">"有å¯ç”¨çš„ Wi-Fi 网络"</item>
+ <item quantity="other">"有å¯ç”¨çš„ Wi-Fi 网络"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"打开å¯ç”¨çš„ Wi-Fi 网络"</item>
- <item quantity="other" msgid="7915895323644292768">"打开å¯ç”¨çš„ Wi-Fi 网络"</item>
+ <item quantity="one">"打开å¯ç”¨çš„ Wi-Fi 网络"</item>
+ <item quantity="other">"打开å¯ç”¨çš„ Wi-Fi 网络"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"æ’入字符"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"未知的应用程åº"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"正在å‘é€çŸ­ä¿¡"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"正在å‘é€å¤§é‡çŸ­ä¿¡ã€‚选择“确定â€ç»§ç»­ï¼Œæˆ–选择“å–消â€åœæ­¢å‘é€ã€‚"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"确定"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"å–消"</string>
- <string name="date_time_set" msgid="5777075614321087758">"设置"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"默认"</string>
- <string name="no_permissions" msgid="7283357728219338112">"ä¸éœ€è¦ä»»ä½•æƒé™"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"éšè—"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"全部显示"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"正在载入..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB 已连接"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"您已通过 USB 将手机连接至计算机。如果è¦åœ¨è®¡ç®—机和手机的 SD å¡ä¹‹é—´å¤åˆ¶æ–‡ä»¶ï¼Œè¯·é€‰æ‹©â€œå®‰è£…â€ã€‚"</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"安装"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"ä¸å®‰è£…"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"使用 SD å¡è¿›è¡Œ USB 存储时出现问题。"</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB 已连接"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"选择以将文件å¤åˆ¶åˆ°è®¡ç®—机/从计算机å¤åˆ¶æ–‡ä»¶ã€‚"</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"关闭 USB 存储设备"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"选中以关闭 USB 存储设备。"</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"关闭 USB 存储设备"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"在关闭 USB 存储设备å‰ï¼Œè¯·ç¡®ä¿æ‚¨å·²å¸è½½äº† USB 主设备。选择“关闭â€å…³é—­ USB 存储设备。"</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"关闭"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"å–消"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"关闭 USB 存储设备时é‡åˆ°é—®é¢˜ã€‚请检查是å¦å¸è½½äº† USB 主设备,然åŽé‡è¯•ã€‚"</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"æ ¼å¼åŒ– SD å¡"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"您确定è¦æ ¼å¼åŒ– SD å¡ï¼Ÿå¡ä¸Šçš„所有数æ®éƒ½ä¼šä¸¢å¤±ã€‚"</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"æ ¼å¼åŒ–"</string>
+ <string name="select_character">"æ’入字符"</string>
+ <string name="sms_control_default_app_name">"未知的应用程åº"</string>
+ <string name="sms_control_title">"正在å‘é€çŸ­ä¿¡"</string>
+ <string name="sms_control_message">"正在å‘é€å¤§é‡çŸ­ä¿¡ã€‚选择“确定â€ç»§ç»­ï¼Œæˆ–选择“å–消â€åœæ­¢å‘é€ã€‚"</string>
+ <string name="sms_control_yes">"确定"</string>
+ <string name="sms_control_no">"å–消"</string>
+ <string name="date_time_set">"设置"</string>
+ <string name="default_permission_group">"默认"</string>
+ <string name="no_permissions">"ä¸éœ€è¦ä»»ä½•æƒé™"</string>
+ <string name="perms_hide"><b>"éšè—"</b></string>
+ <string name="perms_show_all"><b>"全部显示"</b></string>
+ <string name="googlewebcontenthelper_loading">"正在载入..."</string>
+ <string name="usb_storage_title">"USB 已连接"</string>
+ <string name="usb_storage_message">"您已通过 USB 将手机连接至计算机。如果è¦åœ¨è®¡ç®—机和手机的 SD å¡ä¹‹é—´å¤åˆ¶æ–‡ä»¶ï¼Œè¯·é€‰æ‹©â€œå®‰è£…â€ã€‚"</string>
+ <string name="usb_storage_button_mount">"安装"</string>
+ <string name="usb_storage_button_unmount">"ä¸å®‰è£…"</string>
+ <string name="usb_storage_error_message">"使用 SD å¡è¿›è¡Œ USB 存储时出现问题。"</string>
+ <string name="usb_storage_notification_title">"USB 已连接"</string>
+ <string name="usb_storage_notification_message">"选择以将文件å¤åˆ¶åˆ°è®¡ç®—机/从计算机å¤åˆ¶æ–‡ä»¶ã€‚"</string>
+ <string name="usb_storage_stop_notification_title">"关闭 USB 存储设备"</string>
+ <string name="usb_storage_stop_notification_message">"选中以关闭 USB 存储设备。"</string>
+ <string name="usb_storage_stop_title">"关闭 USB 存储设备"</string>
+ <string name="usb_storage_stop_message">"在关闭 USB 存储设备å‰ï¼Œè¯·ç¡®ä¿æ‚¨å·²å¸è½½äº† USB 主设备。选择“关闭â€å…³é—­ USB 存储设备。"</string>
+ <string name="usb_storage_stop_button_mount">"关闭"</string>
+ <string name="usb_storage_stop_button_unmount">"å–消"</string>
+ <string name="usb_storage_stop_error_message">"关闭 USB 存储设备时é‡åˆ°é—®é¢˜ã€‚请检查是å¦å¸è½½äº† USB 主设备,然åŽé‡è¯•ã€‚"</string>
+ <string name="extmedia_format_title">"æ ¼å¼åŒ– SD å¡"</string>
+ <string name="extmedia_format_message">"您确定è¦æ ¼å¼åŒ– SD å¡ï¼Ÿå¡ä¸Šçš„所有数æ®éƒ½ä¼šä¸¢å¤±ã€‚"</string>
+ <string name="extmedia_format_button_format">"æ ¼å¼åŒ–"</string>
<!-- no translation found for adb_active_notification_title (6729044778949189918) -->
<skip />
<!-- no translation found for adb_active_notification_message (4661997077344501389) -->
<skip />
- <string name="select_input_method" msgid="2086499663193509436">"选择输入法"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"正在准备 SD å¡"</string>
+ <string name="select_input_method">"选择输入法"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"候选"</u></string>
+ <string name="ext_media_checking_notification_title">"正在准备 SD å¡"</string>
<!-- no translation found for ext_media_checking_notification_message (8287319882926737053) -->
<skip />
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"空 SD å¡"</string>
+ <string name="ext_media_nofs_notification_title">"空 SD å¡"</string>
<!-- no translation found for ext_media_nofs_notification_message (3817704088027829380) -->
<skip />
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"SD å¡å—æŸ"</string>
+ <string name="ext_media_unmountable_notification_title">"SD å¡å—æŸ"</string>
<!-- no translation found for ext_media_unmountable_notification_message (6902531775948238989) -->
<skip />
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD å¡è¢«æ„外拔除"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"å…ˆå¸è½½ SD å¡å†æ‹”除,以é¿å…æ•°æ®ä¸¢å¤±ã€‚"</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"SD å¡å·²å®‰å…¨ç§»é™¤"</string>
+ <string name="ext_media_badremoval_notification_title">"SD å¡è¢«æ„外拔除"</string>
+ <string name="ext_media_badremoval_notification_message">"å…ˆå¸è½½ SD å¡å†æ‹”除,以é¿å…æ•°æ®ä¸¢å¤±ã€‚"</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD å¡å·²å®‰å…¨ç§»é™¤"</string>
<!-- no translation found for ext_media_safe_unmount_notification_message (568841278138377604) -->
<skip />
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"已移除 SD å¡"</string>
+ <string name="ext_media_nomedia_notification_title">"已移除 SD å¡"</string>
<!-- no translation found for ext_media_nomedia_notification_message (3870120652983659641) -->
<skip />
- <string name="activity_list_empty" msgid="4168820609403385789">"找ä¸åˆ°åŒ¹é…的活动"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"更新组件使用情况统计"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"å…许修改收集的组件使用情况统计。普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"åŒå‡»å¯ä»¥è¿›è¡Œç¼©æ”¾æŽ§åˆ¶"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"放大窗å£å°éƒ¨ä»¶æ—¶å‡ºé”™"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"开始"</string>
- <string name="ime_action_search" msgid="658110271822807811">"æœç´¢"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"å‘é€"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"下一步"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"完æˆ"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"执行"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"拨打电è¯"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"创建电è¯å·ç ä¸º"\n"<xliff:g id="NUMBER">%s</xliff:g> çš„è”系人"</string>
+ <string name="activity_list_empty">"找ä¸åˆ°åŒ¹é…的活动"</string>
+ <string name="permlab_pkgUsageStats">"更新组件使用情况统计"</string>
+ <string name="permdesc_pkgUsageStats">"å…许修改收集的组件使用情况统计。普通应用程åºä¸èƒ½ä½¿ç”¨æ­¤æƒé™ã€‚"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"åŒå‡»å¯ä»¥è¿›è¡Œç¼©æ”¾æŽ§åˆ¶"</string>
+ <string name="gadget_host_error_inflating">"放大窗å£å°éƒ¨ä»¶æ—¶å‡ºé”™"</string>
+ <string name="ime_action_go">"开始"</string>
+ <string name="ime_action_search">"æœç´¢"</string>
+ <string name="ime_action_send">"å‘é€"</string>
+ <string name="ime_action_next">"下一步"</string>
+ <string name="ime_action_done">"完æˆ"</string>
+ <string name="ime_action_default">"执行"</string>
+ <string name="dial_number_using">"拨打电è¯"\n"<xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using">"创建电è¯å·ç ä¸º"\n"<xliff:g id="NUMBER">%s</xliff:g> çš„è”系人"</string>
<!-- no translation found for accessibility_compound_button_selected (5612776946036285686) -->
<skip />
<!-- no translation found for accessibility_compound_button_unselected (8864512895673924091) -->
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 7b4b962..f355a71 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -15,695 +15,698 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort" msgid="8340973892742019101">"ä½å…ƒçµ„"</string>
- <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
- <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
- <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
- <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
- <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
- <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="untitled" msgid="6071602020171759109">"(未命å)"</string>
- <string name="ellipsis" msgid="7899829516048813237">"..."</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(沒有電話號碼)"</string>
- <string name="unknownName" msgid="2277556546742746522">"(未知的)"</string>
- <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"語音留言"</string>
- <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
- <string name="mmiError" msgid="5154499457739052907">"連線發生å•é¡Œæˆ–錯誤的 MMI 碼。"</string>
- <string name="serviceEnabled" msgid="8147278346414714315">"æœå‹™å·²å•Ÿç”¨ã€‚"</string>
- <string name="serviceEnabledFor" msgid="6856228140453471041">"已啟用æœå‹™ï¼š"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"æœå‹™å·²åœç”¨ã€‚"</string>
- <string name="serviceRegistered" msgid="6275019082598102493">"註冊æˆåŠŸã€‚"</string>
- <string name="serviceErased" msgid="1288584695297200972">"清除æˆåŠŸã€‚"</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"密碼錯誤。"</string>
- <string name="mmiComplete" msgid="8232527495411698359">"MMI 完æˆã€‚"</string>
- <string name="badPin" msgid="5085454289896032547">"您輸入的舊 PIN ä¸æ­£ç¢ºã€‚"</string>
- <string name="badPuk" msgid="5702522162746042460">"您輸入的 PUK ä¸æ­£ç¢ºã€‚"</string>
- <string name="mismatchPin" msgid="3695902225843339274">"您輸入的 PIN ä¸ç¬¦åˆã€‚"</string>
- <string name="invalidPin" msgid="3850018445187475377">"輸入 4~8 個數字的 PIN。"</string>
- <string name="needPuk" msgid="919668385956251611">"SIM å¡çš„ PUK 已鎖定。請輸入 PUK 碼解除鎖定。"</string>
- <string name="needPuk2" msgid="4526033371987193070">"請輸入 PUK2 以解鎖 SIM å¡ã€‚"</string>
- <string name="ClipMmi" msgid="6952821216480289285">"來電顯示"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"本機號碼"</string>
- <string name="CfMmi" msgid="5123218989141573515">"來電轉接"</string>
- <string name="CwMmi" msgid="9129678056795016867">"來電待接"</string>
- <string name="BaMmi" msgid="455193067926770581">"通話é™åˆ¶"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"變更密碼"</string>
- <string name="PinMmi" msgid="3113117780361190304">"PIN 已變更"</string>
- <string name="CnipMmi" msgid="3110534680557857162">"顯示來電號碼"</string>
- <string name="CnirMmi" msgid="3062102121430548731">"éš±è—發話號碼"</string>
- <string name="ThreeWCMmi" msgid="9051047170321190368">"三方通話"</string>
- <string name="RuacMmi" msgid="7827887459138308886">"拒接ä¸æƒ³æŽ¥è½çš„騷擾電話"</string>
- <string name="CndMmi" msgid="3116446237081575808">"顯示發話號碼"</string>
- <string name="DndMmi" msgid="1265478932418334331">"勿干擾"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"é è¨­ä¸é¡¯ç¤ºæœ¬æ©Ÿè™Ÿç¢¼ï¼Œä¸‹ä¸€é€šé›»è©±ä¹Ÿä¸é¡¯ç¤ºã€‚"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"é è¨­ä¸é¡¯ç¤ºæœ¬æ©Ÿè™Ÿç¢¼ï¼Œä½†ä¸‹ä¸€é€šé›»è©±é¡¯ç¤ºã€‚"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"é è¨­é¡¯ç¤ºæœ¬æ©Ÿè™Ÿç¢¼ï¼Œä½†ä¸‹ä¸€é€šé›»è©±ä¸é¡¯ç¤ºã€‚"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"é è¨­é¡¯ç¤ºæœ¬æ©Ÿè™Ÿç¢¼ï¼Œä¸‹ä¸€é€šé›»è©±ä¹Ÿç¹¼çºŒé¡¯ç¤ºã€‚"</string>
- <string name="serviceNotProvisioned" msgid="8614830180508686666">"無法æ供此æœå‹™ã€‚"</string>
- <string name="CLIRPermanent" msgid="5460892159398802465">"本機號碼顯示設定無法變更。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"å—é™å­˜å–已變更"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"å·²å°éŽ–資料傳輸æœå‹™ã€‚"</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"å·²å°éŽ–緊急æœå‹™ã€‚"</string>
- <string name="RestrictedOnNormal" msgid="2045364908281990708">"å·²å°éŽ–語音/SMS æœå‹™ã€‚"</string>
- <string name="RestrictedOnAll" msgid="4923139582141626159">"å·²å°éŽ–所有語音/SMS æœå‹™ã€‚"</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"語音"</string>
- <string name="serviceClassData" msgid="872456782077937893">"資料"</string>
- <string name="serviceClassFAX" msgid="5566624998840486475">"傳真"</string>
- <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
- <string name="serviceClassDataAsync" msgid="4523454783498551468">"éžåŒæ­¥"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"åŒæ­¥è™•ç†"</string>
- <string name="serviceClassPacket" msgid="6991006557993423453">"å°åŒ…"</string>
- <string name="serviceClassPAD" msgid="3235259085648271037">"按éµ"</string>
- <string name="roamingText0" msgid="7170335472198694945">"漫éŠæŒ‡ç¤ºé–‹å•Ÿ"</string>
- <string name="roamingText1" msgid="5314861519752538922">"漫éŠæŒ‡ç¤ºé—œé–‰"</string>
- <string name="roamingText2" msgid="8969929049081268115">"漫éŠæŒ‡ç¤ºé–ƒçˆ"</string>
- <string name="roamingText3" msgid="5148255027043943317">"超出鄰近範åœ"</string>
- <string name="roamingText4" msgid="8808456682550796530">"超出建築物範åœ"</string>
- <string name="roamingText5" msgid="7604063252850354350">"æ¼«éŠ - å好系統"</string>
- <string name="roamingText6" msgid="2059440825782871513">"æ¼«éŠ - å¯ç”¨ç³»çµ±"</string>
- <string name="roamingText7" msgid="7112078724097233605">"æ¼«éŠ - è¯ç›Ÿåˆä½œå¤¥ä¼´"</string>
- <string name="roamingText8" msgid="5989569778604089291">"æ¼«éŠ - Google Premium åˆä½œå¤¥ä¼´"</string>
- <string name="roamingText9" msgid="7969296811355152491">"æ¼«éŠ - 完整æœå‹™åŠŸèƒ½"</string>
- <string name="roamingText10" msgid="3992906999815316417">"æ¼«éŠ - 部份æœå‹™åŠŸèƒ½"</string>
- <string name="roamingText11" msgid="4154476854426920970">"漫éŠæ©«å¹…é–‹å•Ÿ"</string>
- <string name="roamingText12" msgid="1189071119992726320">"漫éŠæ©«å¹…關閉"</string>
- <string name="roamingTextSearching" msgid="8360141885972279963">"正在æœå°‹æœå‹™"</string>
- <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
- <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g> 秒後 <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
- <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
- <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
- <string name="fcComplete" msgid="3118848230966886575">"功能碼輸入完æˆã€‚"</string>
- <string name="fcError" msgid="3327560126588500777">"連線發生å•é¡Œæˆ–功能碼無效。"</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"確定"</string>
- <string name="httpError" msgid="2567300624552921790">"網é å…§å®¹éŒ¯èª¤ã€‚"</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"找ä¸åˆ°ç¶²å€ã€‚"</string>
- <string name="httpErrorUnsupportedAuthScheme" msgid="2781440683514730227">"ä¸æ”¯æ´æ­¤ç¶²ç«™é©—證機制。"</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"驗證失敗。"</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"é€éŽ proxy 伺æœå™¨é©—證失敗。"</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"連線到伺æœå™¨å¤±æ•—。"</string>
- <string name="httpErrorIO" msgid="5047872902739125260">"無法與伺æœå™¨æºé€šï¼Œè«‹ç¨å¾Œå†è©¦ä¸€æ¬¡ 。"</string>
- <string name="httpErrorTimeout" msgid="4743403703762883954">"連線到伺æœå™¨é€¾æ™‚。"</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"此網é åŒ…å«å¤ªå¤šä¼ºæœå™¨è½‰å€ã€‚"</string>
- <string name="httpErrorUnsupportedScheme" msgid="5257172771607996054">"ä¸æ”¯æ´æ­¤é€šè¨Šå”定。"</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"無法建立安全連線。"</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"由於網å€éŒ¯èª¤ï¼Œç„¡æ³•é–‹å•Ÿæ­¤ç¶²é ã€‚"</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"無法存å–此檔案。"</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"找ä¸åˆ°è¦æ±‚的檔案。"</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"太多執行è¦æ±‚。請ç¨å¾Œå†è©¦ä¸€æ¬¡ã€‚"</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"åŒæ­¥è™•ç†"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"åŒæ­¥è™•ç†"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"åŒæ™‚刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
- <string name="low_memory" msgid="6632412458436461203">"手機儲存空間已滿ï¼è«‹åˆªé™¤ä¸€äº›æª”案增加空間。"</string>
- <string name="me" msgid="6545696007631404292">"我"</string>
- <string name="power_dialog" msgid="1319919075463988638">"電話é¸é …"</string>
- <string name="silent_mode" msgid="7167703389802618663">"éœéŸ³æ¨¡å¼"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"開啟無線網路"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"關閉無線網路"</string>
- <string name="screen_lock" msgid="799094655496098153">"螢幕鎖定"</string>
- <string name="power_off" msgid="4266614107412865048">"關機"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"關機中..."</string>
- <string name="shutdown_confirm" msgid="649792175242821353">"手機å³å°‡é—œæ©Ÿã€‚"</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"最近沒有存å–應用程å¼ã€‚"</string>
- <string name="global_actions" msgid="2406416831541615258">"電話é¸é …"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"關機"</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"éœéŸ³æ¨¡å¼"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"音效已關閉"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"音效已開啟"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛航模å¼"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模å¼ç‚º [é–‹å•Ÿ]"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛航模å¼ç‚º [關閉]"</string>
- <string name="safeMode" msgid="2788228061547930246">"安全模å¼"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
- <string name="permgrouplab_costMoney" msgid="5429808217861460401">"需è¦é¡å¤–費用的æœå‹™ã€‚"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"若您å…許應用程å¼åŸ·è¡Œæ­¤æ“作,å¯èƒ½éœ€è¦æ”¯ä»˜ä¸€äº›è²»ç”¨ã€‚"</string>
- <string name="permgrouplab_messages" msgid="7521249148445456662">"您的簡訊"</string>
- <string name="permgroupdesc_messages" msgid="7045736972019211994">"讀å–編輯 SMSã€é›»å­éƒµä»¶èˆ‡å…¶ä»–簡訊。"</string>
- <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"您的個人資訊"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"直接存å–手機上的è¯çµ¡äººèˆ‡æ—¥æ›†ã€‚"</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"您的ä½ç½®"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"監視實際ä½ç½®"</string>
- <string name="permgrouplab_network" msgid="5808983377727109831">"網路通訊"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"å…許應用程å¼å­˜å–多項網路功能。"</string>
- <string name="permgrouplab_accounts" msgid="7140261692496314430">"您的 Google 帳戶"</string>
- <string name="permgroupdesc_accounts" msgid="6735915929704895193">"å­˜å–å¯ç”¨ Google 帳戶。"</string>
- <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"硬體控制"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"在å…æŒè¨­å‚™ä¸Šç›´æŽ¥å­˜å–硬體。"</string>
- <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"撥打電話"</string>
- <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"監控ã€è¨˜éŒ„與進行通話。"</string>
- <string name="permgrouplab_systemTools" msgid="4652191644082714048">"系統工具"</string>
- <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"系統低階存å–與控制。"</string>
- <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"開發工具"</string>
- <string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"åªæœ‰é–‹ç™¼è€…需è¦æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"儲存"</string>
- <string name="permgroupdesc_storage" msgid="9203302214915355774">"å­˜å– SD å¡ã€‚"</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"åœç”¨æˆ–變更狀態列"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"å…許應用程å¼åœç”¨ç‹€æ…‹åˆ—或新增ã€ç§»é™¤ç³»çµ±åœ–示。"</string>
- <string name="permlab_expandStatusBar" msgid="1148198785937489264">"展開/收æ”狀態列"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"å…許應用程å¼å±•é–‹æˆ–收æ”狀態列。"</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"攔截撥出電話"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"å…許應用程å¼è™•ç†æ’¥å‡ºé›»è©±åŠè®Šæ›´æ’¥è™Ÿã€‚請注æ„:惡æ„程å¼å¯èƒ½è—‰ä»¥ç›£æŽ§ï¼Œè½‰æŽ¥æˆ–阻擋電話撥出。"</string>
- <string name="permlab_receiveSms" msgid="2697628268086208535">"接收 SMS"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"å…許應用程å¼æŽ¥æ”¶ã€è™•ç† SMS 簡訊。請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½ç›£æŽ§ç°¡è¨Šæˆ–在您讀å–å‰æ“…自刪除。"</string>
- <string name="permlab_receiveMms" msgid="8894700916188083287">"接收 MMS"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"å…許應用程å¼æŽ¥æ”¶ã€è™•ç† MMS 簡訊。請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½ç›£æŽ§ç°¡è¨Šæˆ–在您讀å–å‰æ“…自刪除。"</string>
- <string name="permlab_sendSms" msgid="5600830612147671529">"å‚³é€ SMS 簡訊"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"å…許應用程å¼å‚³é€ SMS 簡訊。請注æ„:惡æ„程å¼å¯èƒ½æœƒæ“…自傳é€ç°¡è¨Šï¼Œå¢žåŠ æ‚¨çš„支出。"</string>
- <string name="permlab_readSms" msgid="4085333708122372256">"è®€å– SMS 或 MMS"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"å…許應用程å¼è®€å–手機或 SIM å¡ä¸Šçš„ SMS 簡訊。請注æ„:惡æ„程å¼å¯èƒ½æœƒåˆ©ç”¨æ­¤åŠŸèƒ½è®€å–您的機密簡訊。"</string>
- <string name="permlab_writeSms" msgid="6881122575154940744">"編輯 SMS 或 MMS"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"å…許應用程å¼ç·¨è¼¯ SMS 簡訊,存入手機或 SIM å¡ã€‚請注æ„:惡æ„程å¼å¯èƒ½æœƒåˆªé™¤æ‚¨çš„簡訊。"</string>
- <string name="permlab_receiveWapPush" msgid="8258226427716551388">"接收 WAP"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"å…許應用程å¼ç‚ºå…¶ä»–程å¼é–‹å•ŸåµéŒ¯åŠŸèƒ½ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½çµ‚止其他應用程å¼ã€‚"</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"å–得執行中應用程å¼"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"å…許應用程å¼å–得最近執行任務的資訊。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½æ‰¾å‡ºå…¶ä»–應用程å¼çš„éš±ç§è³‡è¨Šã€‚"</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"é‡æ–°å®‰æŽ’執行中的應用程å¼"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"å…許應用程å¼å°‡å·¥ä½œç§»è‡³å‰ç«¯æˆ–背景作業。請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½è‡ªè¡ŒæŠŠè‡ªå·±æ‹‰åˆ°å‰ç«¯ã€‚"</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"啟用應用程å¼åµéŒ¯"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"å…許應用程å¼ç‚ºå…¶ä»–程å¼é–‹å•ŸåµéŒ¯åŠŸèƒ½ã€‚請注æ„:惡æ„程å¼å¯åˆ©ç”¨æ­¤åŠŸèƒ½çµ‚止其他應用程å¼ã€‚"</string>
- <string name="permlab_changeConfiguration" msgid="8214475779521218295">"變更介é¢è¨­å®š"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"å…許應用程å¼è®Šæ›´ç›®å‰è¨­å®šï¼Œä¾‹å¦‚:地å€è¨­å®šæˆ–字型大å°ã€‚"</string>
- <string name="permlab_restartPackages" msgid="2386396847203622628">"é‡æ–°å•Ÿå‹•å…¶ä»–應用程å¼"</string>
- <string name="permdesc_restartPackages" msgid="1076364837492936814">"å…許應用程å¼å¼·åˆ¶é‡æ–°å•Ÿå‹•å…¶ä»–應用程å¼ã€‚"</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"強制關閉應用程å¼"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"å…許應用程å¼å¼·åˆ¶é—œé–‰åœ¨å‰ç«¯é‹ä½œçš„活動並返回。一般應用程å¼ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_dump" msgid="1681799862438954752">"接收系統內部狀態"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"å…許應用程å¼å–得系統內部狀態。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œä¸ç•¶å–å¾—ç§äººæˆ–安全性資料。"</string>
- <string name="permlab_shutdown" msgid="7185747824038909016">"部分關機"</string>
- <string name="permdesc_shutdown" msgid="7046500838746291775">"讓活動管ç†å“¡é€²å…¥é—œæ©Ÿç‹€æ…‹ï¼Œè€Œä¸åŸ·è¡Œå®Œæ•´çš„關機程åºã€‚"</string>
- <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"防止切æ›æ‡‰ç”¨ç¨‹å¼"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"防止使用者切æ›åˆ°å…¶ä»–應用程å¼ã€‚"</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"監視控制所有應用程å¼å•Ÿå‹•ç‹€æ…‹ã€‚"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"å…許應用程å¼ç›£æŽ§ç®¡ç†ç³»çµ±å•Ÿå‹•æ´»å‹•ã€‚請注æ„:惡æ„程å¼å¯èƒ½å› æ­¤ç™±ç˜“整個系統。此權é™åªåœ¨é–‹ç™¼æ™‚需è¦ï¼Œä¸€èˆ¬æ‰‹æ©Ÿä½¿ç”¨ä¸éœ€è¦æ­¤æ¬Šé™ã€‚"</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"傳é€ç¨‹å¼å·²ç§»é™¤å»£æ’­"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"å…許應用程å¼åœ¨å…¶ä»–應用程å¼è¢«ç§»é™¤æ™‚發é€é€šçŸ¥ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œé—œé–‰å…¶ä»–執行中的程å¼ã€‚"</string>
- <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"傳é€å·²æŽ¥æ”¶ SMS 廣播"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"å…許應用程å¼åœ¨æ”¶åˆ° SMS 簡訊時發出通知。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½å½é€  SMS 簡訊。"</string>
- <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"é€å‡ºã€ŒWAP PUSH 已接收ã€å»£æ’­"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"å…許應用程å¼åœ¨æ”¶åˆ° WAP PUSH 簡訊時發é€é€šçŸ¥ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œå½é€  MMS 簡訊回æ¢æˆ–秘密更æ›ç¶²é å…§å®¹ã€‚"</string>
- <string name="permlab_setProcessLimit" msgid="2451873664363662666">"執行程åºé™åˆ¶æ•¸"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"å…許應用程å¼æŽ§åˆ¶å¯ä½¿ç”¨çš„最大執行緒。一般應用程å¼ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"關閉所有背景程å¼"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"å…許應用程å¼æŽ§åˆ¶å“ªäº›æ´»å‹•åœ¨è¢«ç§»åˆ°èƒŒæ™¯åŸ·è¡Œæ™‚,儘速çµæŸã€‚一般應用程å¼ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_batteryStats" msgid="7863923071360031652">"編輯電池狀態"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"å…許修改電池狀態。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_backup" msgid="470013022865453920">"控制系統備份與還原"</string>
- <string name="permdesc_backup" msgid="2305432853944929371">"å…許應用程å¼æŽ§åˆ¶ç³»çµ±å‚™ä»½èˆ‡é‚„原機制,但一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"顯示未授權視窗"</string>
- <string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"å…許內部系統使用介é¢å»ºç«‹è¦–窗。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"顯示系統警示"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"å…許應用程å¼é¡¯ç¤ºç³»çµ±è­¦å‘Šè¦–窗。請注æ„:惡æ„程å¼å¯ä½¿ç”¨æ­¤åŠŸèƒ½æŽ¥ç®¡æ‰‹æ©Ÿèž¢å¹•ã€‚"</string>
- <string name="permlab_setAnimationScale" msgid="2805103241153907174">"編輯全域動畫速度"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"å…許應用程å¼è®Šæ›´å…¨åŸŸå‹•ç•«é€Ÿåº¦ (更快或更慢)。"</string>
- <string name="permlab_manageAppTokens" msgid="17124341698093865">"管ç†æ‡‰ç”¨ç¨‹å¼ token"</string>
- <string name="permdesc_manageAppTokens" msgid="977127907524195988">"å…許應用程å¼ç•¥éŽä¸€èˆ¬ Z-ordering,建立與管ç†è‡ªå·±çš„ token。一般應用程å¼ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_injectEvents" msgid="1378746584023586600">"按éµåŠæŽ§åˆ¶æŒ‰éˆ•"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"å…許應用程å¼ç™¼é€è¼¸å…¥äº‹ä»¶ (按éµç­‰) 給其他應用程å¼ã€‚請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½æŽ¥ç®¡æ‰‹æ©Ÿã€‚"</string>
- <string name="permlab_readInputState" msgid="469428900041249234">"記錄您的輸入內容與æ“作"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"å…許應用程å¼åœ¨ä½¿ç”¨è€…æ“作其他程å¼æ™‚ (例如:輸入密碼),ä»å¯ç›£çœ‹è¼¸å…¥çš„按éµã€‚一般應用程å¼æ‡‰ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"連çµè‡³è¼¸å…¥æ³•"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"å…許æ“有人連çµè‡³è¼¸å…¥æ³•çš„最頂層介é¢ã€‚一般應用程å¼ä¸éœ€ä½¿ç”¨æ­¤é¸é …。"</string>
- <string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方å‘"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"å…許應用程å¼éš¨æ™‚變更螢幕顯示方å‘。一般應用程å¼ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"å‚³é€ Linux 訊號到應用程å¼"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"å…許應用程å¼è¦æ±‚將支æ´çš„訊號傳é€åˆ°æ‰€æœ‰æŒçºŒçš„程åºã€‚"</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"設定應用程å¼æŒçºŒåŸ·è¡Œ"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"å…許應用程å¼æŒçºŒåŸ·è¡Œï¼Œé¿å…系統將它應用到其他程å¼ã€‚"</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"刪除應用程å¼"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"å…許應用程å¼åˆªé™¤ Android 程å¼ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½åˆªé™¤é‡è¦æ‡‰ç”¨ç¨‹å¼ã€‚"</string>
- <string name="permlab_clearAppUserData" msgid="2192134353540277878">"刪除其他應用程å¼è³‡æ–™"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"å…許應用程å¼æ¸…除使用者資料。"</string>
- <string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"刪除其他應用程å¼å¿«å–"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"å…許應用程å¼åˆªé™¤å¿«å–檔案。"</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"估算應用程å¼å ç”¨çš„儲存空間"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"å…許應用程å¼å–得程å¼ç¢¼ã€è³‡æ–™èˆ‡å¿«å–大å°"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"直接安è£æ‡‰ç”¨ç¨‹å¼"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"å…許應用程å¼å®‰è£æ–°çš„ Android 程å¼æˆ–更新。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½æ–°å¢žå…·æœ‰æ¥µé«˜æ¬Šé™çš„程å¼ã€‚"</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"刪除所有應用程å¼å¿«å–資料。"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"å…許應用程å¼åˆªé™¤å¿«å–目錄裡的檔案,釋放儲存空間。此æ“作通常å—到系統程åºåš´æ ¼é™åˆ¶ã€‚"</string>
- <string name="permlab_readLogs" msgid="4811921703882532070">"讀å–系統記錄檔"</string>
- <string name="permdesc_readLogs" msgid="2257937955580475902">"å…許應用程å¼è®€å–系統記錄檔。此項æ“作å¯è®“應用程å¼äº†è§£ç›®å‰æ‰‹æ©Ÿæ“作狀態,但內容應ä¸å«ä»»ä½•å€‹äººæˆ–éš±ç§è³‡è¨Šã€‚"</string>
- <string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag æ“有的資æº"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"å…許應用程å¼è®€å¯« diag 群組的資æºï¼›ä¾‹å¦‚:/dev 裡的檔案。這å¯èƒ½æœƒå½±éŸ¿ç³»çµ±ç©©å®šæ€§èˆ‡å®‰å…¨æ€§ã€‚此功能僅供製造商或技術人員用於硬體è¦æ ¼åµæ¸¬ã€‚"</string>
- <string name="permlab_changeComponentState" msgid="79425198834329406">"啟用或åœç”¨æ‡‰ç”¨ç¨‹å¼å…ƒä»¶"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"å…許應用程å¼è®Šæ›´æ˜¯å¦å•Ÿç”¨å…¶ä»–元件或應用程å¼ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œåœç”¨é‡è¦çš„手機功能。由於此功能å¯èƒ½å°Žè‡´æ‡‰ç”¨ç¨‹å¼å…ƒä»¶ç„¡æ³•ä½¿ç”¨ã€ä¸ä¸€è‡´æˆ–ä¸ç©©å®šï¼Œè«‹å°å¿ƒæ–Ÿé…ŒæŽˆæ¬Šã€‚"</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"設定喜好的應用程å¼"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"å…許應用程å¼ä¿®æ”¹æ‚¨å好的應用程å¼ã€‚請注æ„:惡æ„程å¼å¯èƒ½è—‰ä»¥ç§˜å¯†ç«„改執行的程å¼ï¼Œæˆ–å½é€ å·²å­˜åœ¨çš„程å¼ä»¥æ”¶é›†ç§äººè³‡æ–™ã€‚"</string>
- <string name="permlab_writeSettings" msgid="1365523497395143704">"編輯全域系統設定"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"å…許應用程å¼ä¿®æ”¹ç³»çµ±è¨­å®šã€‚請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½æ毀系統設定。"</string>
- <string name="permlab_writeSecureSettings" msgid="204676251876718288">"編輯安全系統設定"</string>
- <string name="permdesc_writeSecureSettings" msgid="4116616249170428132">"å…許應用程å¼ä¿®æ”¹ç³»çµ±çš„安全設定資料。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_writeGservices" msgid="2149426664226152185">"修改 Google æœå‹™åœ°åœ–"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"å…許應用程å¼ä¿®æ”¹ Google æœå‹™åœ°åœ–。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"開機時自動啟用"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"å…許應用程å¼åœ¨é–‹æ©Ÿå¾Œç›¡å¿«å•Ÿå‹•ã€‚此項設定會讓開機時間拉長,並å…許應用程å¼æŒçºŒåŸ·è¡Œï¼Œå› æ­¤æ‹–慢手機速度。"</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"傳é€é™„屬廣播"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"å…許應用程å¼å‚³é€æŒä¹…的廣播。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ä¾†ä½”æ“šéŽå¤šè¨˜æ†¶é«”,讓手機速度變慢或ä¸ç©©å®šã€‚"</string>
- <string name="permlab_readContacts" msgid="6219652189510218240">"讀å–è¯çµ¡äººè³‡æ–™"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"å…許應用程å¼è®€å–手機上所有è¯çµ¡äºº (地å€)。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½å°‡æ‚¨çš„資料傳é€çµ¦å…¶ä»–人。"</string>
- <string name="permlab_writeContacts" msgid="644616215860933284">"輸入è¯çµ¡äººè³‡æ–™"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"å…許應用程å¼æ›´æ”¹è¯çµ¡è³‡è¨Š (地å€)。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œæ¸…除或修改è¯çµ¡è³‡æ–™ã€‚"</string>
- <string name="permlab_writeOwnerData" msgid="4892555913849295393">"寫入æŒæœ‰è€…的資料"</string>
- <string name="permdesc_writeOwnerData" msgid="2344055317969787124">"å…許應用程å¼æ›´æ”¹æ‰‹æ©ŸæŒæœ‰è€…的資料。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œæ¸…除或修改æŒæœ‰è€…的資料。"</string>
- <string name="permlab_readOwnerData" msgid="6668525984731523563">"讀å–æŒæœ‰è€…的資料"</string>
- <string name="permdesc_readOwnerData" msgid="3088486383128434507">"å…許應用程å¼è®€å–手機æŒæœ‰è€…資料。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½è®€å–æŒæœ‰è€…的資料。"</string>
- <string name="permlab_readCalendar" msgid="3728905909383989370">"讀å–日曆資料"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"å…許應用程å¼è®€å–手機上所有日曆資料。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½å°‡æ‚¨çš„日曆資料傳é€çµ¦å…¶ä»–人。"</string>
- <string name="permlab_writeCalendar" msgid="377926474603567214">"寫入日曆資料"</string>
- <string name="permdesc_writeCalendar" msgid="8674240662630003173">"å…許應用程å¼ç·¨è¼¯æ—¥æ›†è³‡æ–™ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œæ¸…除或修改您的日曆資料。"</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"模擬ä½ç½®ä¾†æºä»¥ä¾›æ¸¬è©¦"</string>
- <string name="permdesc_accessMockLocation" msgid="7648286063459727252">"建立模擬ä½ç½®ä¾†æºä»¥ä¾›æ¸¬è©¦ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½è¦†å¯« GPS 或電信業者傳回的ä½ç½®åŠ/或狀態。"</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"接收é¡å¤–çš„ä½ç½®æ供者指令"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"å­˜å–é¡å¤–ä½ç½®æ供者命令。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½å¹²æ“¾ GPS 或其他ä½ç½®ä¾†æºã€‚"</string>
- <string name="permlab_installLocationProvider" msgid="6578101199825193873">"准許安è£ä½ç½®æ供者"</string>
- <string name="permdesc_installLocationProvider" msgid="5449175116732002106">"建立虛構的ä½ç½®ä¾†æºä»¥ä¾›æ¸¬è©¦ã€‚請注æ„:惡æ„應用程å¼å¯èƒ½åˆ©ç”¨æ­¤é¸é …覆寫由真實ä½ç½®ä¾†æº (例如 GPS 或網路供應商) 所傳回的ä½ç½®åŠ/或狀態,或者監控您的ä½ç½®ä¸¦å°‡ä¹‹æ供給外部來æºã€‚"</string>
- <string name="permlab_accessFineLocation" msgid="8116127007541369477">"ç²¾ç¢ºå®šä½ (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"接收精確的ä½ç½®ä¾†æº (例如:手機 GPS)。請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½å¾—知您的ä½ç½®ï¼Œä¸¦å¯èƒ½æ¶ˆè€—é¡å¤–é›»æºã€‚"</string>
- <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ç´„ç•¥ä½ç½® (以網路為基準)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"接收約略的ä½ç½®ä¾†æº (例如:行動網路資料庫),計算出目å‰å¤§æ¦‚ä½ç½®ã€‚請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½å¾—知您的所在地。"</string>
- <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"å­˜å– SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"å…許應用程å¼ä½¿ç”¨ SurfaceFlinger 低階功能。"</string>
- <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"讀å–框架緩è¡"</string>
- <string name="permdesc_readFrameBuffer" msgid="5777679658669057819">"å…許應用程å¼è®€å–框架緩è¡çš„內容。"</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"變更音訊設定"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"å…許應用程å¼ç·¨è¼¯å…¨åŸŸéŸ³è¨Šè¨­å®šï¼Œä¾‹å¦‚音é‡èˆ‡è·¯ç”±ã€‚"</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"錄製音訊"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"å…許應用程å¼å­˜å–音訊錄製路徑。"</string>
- <string name="permlab_camera" msgid="8059288807274039014">"照相"</string>
- <string name="permdesc_camera" msgid="9013476258810982546">"å…許應用程å¼ä½¿ç”¨ç›¸æ©Ÿæ‹ç…§ã€‚此功能å¯è®“應用程å¼éš¨æ™‚é€éŽç›¸æ©Ÿæ‹æ”照片。"</string>
- <string name="permlab_brick" msgid="8337817093326370537">"永久åœç”¨é›»è©±"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"å…許應用程å¼æ°¸ä¹…åœç”¨æ‰‹æ©Ÿã€‚此項æ“作éžå¸¸å±éšªã€‚"</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"強制é‡é–‹æ©Ÿ"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"å…許應用程å¼å¼·åˆ¶é‡é–‹æ©Ÿã€‚"</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"掛載/å¸è¼‰æª”案系統"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"å…許應用程å¼æŽ›è¼‰/å¸è¼‰æŠ½å–å¼å„²å­˜è¨­å‚™çš„檔案系統。"</string>
- <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"將外接å¼å„²å­˜è£ç½®æ ¼å¼åŒ–"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"å…許應用程å¼å°‡å¯ç§»é™¤å¼å„²å­˜è£ç½®æ ¼å¼åŒ–。"</string>
- <string name="permlab_vibrate" msgid="7768356019980849603">"控制震動"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"å…許應用程å¼æŽ§åˆ¶éœ‡å‹•ã€‚"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"å…許應用程å¼æŽ§åˆ¶é–ƒå…‰ç‡ˆã€‚"</string>
- <string name="permlab_hardware_test" msgid="4148290860400659146">"測試硬體"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"å…許應用程å¼æŽ§åˆ¶å„種週邊設備,以供測試用。"</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"å…許應用程å¼è‡ªè¡Œæ’¥æ‰“電話。請注æ„:惡æ„程å¼å¯èƒ½ä»»æ„撥打電話,造æˆé æœŸå¤–的支出。但此é¸é …並ä¸å…許應用程å¼æ’¥æ‰“緊急電話號碼。"</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"直接撥打任何電話號碼"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"å…許應用程å¼è‡ªè¡Œæ’¥æ‰“任何電話號碼,包括緊急電話號碼。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½æ¿«ç”¨ç·Šæ€¥æœå‹™ï¼Œæ’¥æ‰“ä¸å¿…è¦æˆ–é•æ³•çš„電話。"</string>
- <string name="permlab_locationUpdates" msgid="7785408253364335740">"控制ä½ç½®æ›´æ–°é€šçŸ¥"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"å…許啟用/åœç”¨ç„¡ç·šé€šè¨Šä½ç½®æ›´æ–°é€šçŸ¥ã€‚一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_checkinProperties" msgid="7855259461268734914">"å­˜å–登機é¸é …"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"å…許讀寫登機æœå‹™ä¸Šå‚³çš„資料。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_bindGadget" msgid="776905339015863471">"é¸æ“‡å°å·¥å…·"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"å…許應用程å¼å‘ŠçŸ¥ç³»çµ±å“ªå€‹æ‡‰ç”¨ç¨‹å¼å¯ä»¥ä½¿ç”¨å“ªäº›å°å·¥å…·ã€‚開啟此權é™å¾Œï¼Œæ‡‰ç”¨ç¨‹å¼æœƒè®“其他程å¼ä½¿ç”¨å€‹äººè³‡æ–™ï¼Œä½†ä¸€èˆ¬æ‡‰ç”¨ç¨‹å¼ä¸é©åˆä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"修改手機狀態"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"å…許應用程å¼æŽ§åˆ¶é›»è©±åŠŸèƒ½ã€‚æ“有此權é™çš„程å¼å¯è‡ªè¡Œåˆ‡æ›ç¶²è·¯ã€é–‹é—œç„¡ç·šé€šè¨ŠåŠŸèƒ½ã€‚"</string>
- <string name="permlab_readPhoneState" msgid="2326172951448691631">"讀å–手機狀態和識別碼"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"å…許應用程å¼å­˜å–è£ç½®çš„電話功能資料。ç²å¾—此權é™çš„應用程å¼å¯å–得手機的號碼和åºè™Ÿã€æ˜¯å¦åœ¨é€šè©±ä¸­ï¼Œä»¥åŠé€šè©±å¦ä¸€æ–¹çš„電話號碼等資料。"</string>
- <string name="permlab_wakeLock" msgid="573480187941496130">"防止手機進入待命狀態"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"å…許應用程å¼é˜²æ­¢æ‰‹æ©Ÿé€²å…¥å¾…命。"</string>
- <string name="permlab_devicePower" msgid="4928622470980943206">"開啟或關閉電æº"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"å…許應用程å¼é–‹å•Ÿæˆ–關閉電話。"</string>
- <string name="permlab_factoryTest" msgid="3715225492696416187">"在出廠測試模å¼ä¸‹åŸ·è¡Œ"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"執行低階製造商測試,å…許完全存å–手機硬體。此功能åªèƒ½åœ¨æ‰‹æ©Ÿæ˜¯è£½é€ å•†æ¸¬è©¦æ¨¡å¼ä¸‹æ‰å¯åŸ·è¡Œã€‚"</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"設定桌布"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"å…許應用程å¼è¨­å®šç³»çµ±æ¡Œå¸ƒã€‚"</string>
- <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"設定桌布大å°æ示"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"å…許應用程å¼è¨­å®šç³»çµ±æ¡Œå¸ƒå¤§å°æ示。"</string>
- <string name="permlab_masterClear" msgid="2315750423139697397">"將系統還原至出廠é è¨­å€¼"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"å…許應用程å¼å°‡æ‰‹æ©Ÿå®Œå…¨é‡è¨­è‡³å‡ºå» è¨­å®šï¼Œæ¸…除所有資料ã€è¨­å®šèˆ‡å·²å®‰è£ç¨‹å¼ã€‚"</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"設定時å€"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"å…許應用程å¼è®Šæ›´æ™‚å€ã€‚"</string>
- <string name="permlab_getAccounts" msgid="4549918644233460103">"發ç¾å·²çŸ¥å¸³æˆ¶ã€‚"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"å…許應用程å¼å–得手機上的帳戶清單。"</string>
- <string name="permlab_accessNetworkState" msgid="6865575199464405769">"檢視網路狀態"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"å…許應用程å¼æª¢è¦–網路狀態。"</string>
- <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"網際網路完整存å–"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"å…許應用程å¼å»ºç«‹ç¶²è·¯è¨­å®šã€‚"</string>
- <string name="permlab_writeApnSettings" msgid="7823599210086622545">"輸入存å–點å稱設定"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"å…許應用程å¼ä¿®æ”¹ APN 設定,例如:Proxy åŠ APN 的連接埠。"</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"變更網路連線"</string>
- <string name="permdesc_changeNetworkState" msgid="6278115726355634395">"å…許應用程å¼è®Šæ›´ç¶²è·¯é€£ç·šç‹€æ…‹ã€‚"</string>
- <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"變更背景資料使用設定"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"å…許應用程å¼è®Šæ›´èƒŒæ™¯è³‡æ–™ä½¿ç”¨è¨­å®šã€‚"</string>
- <string name="permlab_accessWifiState" msgid="8100926650211034400">"檢視 Wi-Fi 狀態"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"å…許應用程å¼æª¢è¦– Wi-Fi 狀態資訊。"</string>
- <string name="permlab_changeWifiState" msgid="7280632711057112137">"變更 Wi-Fi 狀態"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"å…許應用程å¼èˆ‡ Wi-Fi å­˜å–點連線或中斷連線,並å¯è®Šæ›´ Wi-Fi 網路設定。"</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"å…許接收 Wi-Fi 多點傳播å°åŒ…"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"å…許應用程å¼æŽ¥æ”¶ä¸¦éžæŒ‡å®šå‚³é€çµ¦æ‚¨è£ç½®çš„å°åŒ…,這在您發ç¾é™„近有æœå‹™å¯ä½¿ç”¨æ™‚很有用,但消耗的電力比éžå¤šé»žå‚³æ’­æ¨¡å¼é‚„è¦å¤šã€‚"</string>
- <string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"è—牙管ç†"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"å…許應用程å¼è¨­å®šæœ¬æ©Ÿè—牙電話,以åŠåµæ¸¬èˆ‡é…å°å…¶ä»–é ç«¯è£ç½®ã€‚"</string>
- <string name="permlab_bluetooth" msgid="8361038707857018732">"建立è—牙連線"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"å…許應用程å¼æª¢è¦–本機è—牙電話設定,並與其他é…å°è£ç½®é€£ç·šã€‚"</string>
- <string name="permlab_disableKeyguard" msgid="4977406164311535092">"åœç”¨æŒ‰éµéŽ–定"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"å…許應用程å¼åœç”¨æŒ‰éµéŽ–定以åŠå…¶ä»–相關的密碼安全性。例如:收到來電時解除按éµéŽ–定,通話çµæŸå¾Œé‡æ–°å•Ÿå‹•æŒ‰éµéŽ–定。"</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"讀å–åŒæ­¥è™•ç†è¨­å®š"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"å…許應用程å¼è®€å–åŒæ­¥è™•ç†è¨­å®šï¼Œä¾‹å¦‚:是å¦åŒæ­¥è™•ç† [è¯çµ¡äºº]。"</string>
- <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"編輯åŒæ­¥è™•ç†è¨­å®š"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"å…許應用程å¼ä¿®æ”¹åŒæ­¥è™•ç†è¨­å®šï¼Œä¾‹å¦‚:是å¦è¦åŒæ­¥è™•ç† [è¯çµ¡äºº]。"</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"讀å–åŒæ­¥è™•ç†ç‹€æ…‹"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"å…許應用程å¼è®€å–åŒæ­¥è™•ç†ç‹€æ…‹ï¼›ä¾‹å¦‚:åŒæ­¥è™•ç†è¨˜éŒ„。"</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"讀å–訂閱資訊æä¾›"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"å…許應用程å¼å–å¾—ç›®å‰å·²åŒæ­¥è™•ç†çš„資訊æ供。"</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"寫入訂閱資訊æä¾›"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"å…許應用程å¼ä¿®æ”¹å·²åŒæ­¥è™•ç†çš„資訊æ供。請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½è®Šæ›´å·²åŒæ­¥è™•ç†çš„資訊æ供。"</string>
- <string name="permlab_readDictionary" msgid="432535716804748781">"讀å–使用者定義的字典"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"å…許應用程å¼è®€å–使用者儲存在使用者字典內的任何ç§äººå­—è©žã€å稱和詞組。"</string>
- <string name="permlab_writeDictionary" msgid="6703109511836343341">"寫入使用者定義的字典"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"å…許應用程å¼å°‡æ–°å­—詞寫入使用者的字典。"</string>
- <string name="permlab_sdcardWrite" msgid="8079403759001777291">"修改/刪除 SD å¡çš„內容"</string>
- <string name="permdesc_sdcardWrite" msgid="6643963204976471878">"å…許應用程å¼å¯«å…¥ SD å¡ã€‚"</string>
+ <string name="byteShort">"ä½å…ƒçµ„"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="fileSizeSuffix">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="untitled">"(未命å)"</string>
+ <string name="ellipsis">"..."</string>
+ <string name="emptyPhoneNumber">"(沒有電話號碼)"</string>
+ <string name="unknownName">"(未知的)"</string>
+ <string name="defaultVoiceMailAlphaTag">"語音留言"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"連線發生å•é¡Œæˆ–錯誤的 MMI 碼。"</string>
+ <string name="serviceEnabled">"æœå‹™å·²å•Ÿç”¨ã€‚"</string>
+ <string name="serviceEnabledFor">"已啟用æœå‹™ï¼š"</string>
+ <string name="serviceDisabled">"æœå‹™å·²åœç”¨ã€‚"</string>
+ <string name="serviceRegistered">"註冊æˆåŠŸã€‚"</string>
+ <string name="serviceErased">"清除æˆåŠŸã€‚"</string>
+ <string name="passwordIncorrect">"密碼錯誤。"</string>
+ <string name="mmiComplete">"MMI 完æˆã€‚"</string>
+ <string name="badPin">"您輸入的舊 PIN ä¸æ­£ç¢ºã€‚"</string>
+ <string name="badPuk">"您輸入的 PUK ä¸æ­£ç¢ºã€‚"</string>
+ <string name="mismatchPin">"您輸入的 PIN ä¸ç¬¦åˆã€‚"</string>
+ <string name="invalidPin">"輸入 4~8 個數字的 PIN。"</string>
+ <string name="needPuk">"SIM å¡çš„ PUK 已鎖定。請輸入 PUK 碼解除鎖定。"</string>
+ <string name="needPuk2">"請輸入 PUK2 以解鎖 SIM å¡ã€‚"</string>
+ <string name="ClipMmi">"來電顯示"</string>
+ <string name="ClirMmi">"本機號碼"</string>
+ <string name="CfMmi">"來電轉接"</string>
+ <string name="CwMmi">"來電待接"</string>
+ <string name="BaMmi">"通話é™åˆ¶"</string>
+ <string name="PwdMmi">"變更密碼"</string>
+ <string name="PinMmi">"PIN 已變更"</string>
+ <string name="CnipMmi">"顯示來電號碼"</string>
+ <string name="CnirMmi">"éš±è—發話號碼"</string>
+ <string name="ThreeWCMmi">"三方通話"</string>
+ <string name="RuacMmi">"拒接ä¸æƒ³æŽ¥è½çš„騷擾電話"</string>
+ <string name="CndMmi">"顯示發話號碼"</string>
+ <string name="DndMmi">"勿干擾"</string>
+ <string name="CLIRDefaultOnNextCallOn">"é è¨­ä¸é¡¯ç¤ºæœ¬æ©Ÿè™Ÿç¢¼ï¼Œä¸‹ä¸€é€šé›»è©±ä¹Ÿä¸é¡¯ç¤ºã€‚"</string>
+ <string name="CLIRDefaultOnNextCallOff">"é è¨­ä¸é¡¯ç¤ºæœ¬æ©Ÿè™Ÿç¢¼ï¼Œä½†ä¸‹ä¸€é€šé›»è©±é¡¯ç¤ºã€‚"</string>
+ <string name="CLIRDefaultOffNextCallOn">"é è¨­é¡¯ç¤ºæœ¬æ©Ÿè™Ÿç¢¼ï¼Œä½†ä¸‹ä¸€é€šé›»è©±ä¸é¡¯ç¤ºã€‚"</string>
+ <string name="CLIRDefaultOffNextCallOff">"é è¨­é¡¯ç¤ºæœ¬æ©Ÿè™Ÿç¢¼ï¼Œä¸‹ä¸€é€šé›»è©±ä¹Ÿç¹¼çºŒé¡¯ç¤ºã€‚"</string>
+ <string name="serviceNotProvisioned">"無法æ供此æœå‹™ã€‚"</string>
+ <string name="CLIRPermanent">"本機號碼顯示設定無法變更。"</string>
+ <string name="RestrictedChangedTitle">"å—é™å­˜å–已變更"</string>
+ <string name="RestrictedOnData">"å·²å°éŽ–資料傳輸æœå‹™ã€‚"</string>
+ <string name="RestrictedOnEmergency">"å·²å°éŽ–緊急æœå‹™ã€‚"</string>
+ <string name="RestrictedOnNormal">"å·²å°éŽ–語音/SMS æœå‹™ã€‚"</string>
+ <string name="RestrictedOnAll">"å·²å°éŽ–所有語音/SMS æœå‹™ã€‚"</string>
+ <string name="serviceClassVoice">"語音"</string>
+ <string name="serviceClassData">"資料"</string>
+ <string name="serviceClassFAX">"傳真"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"éžåŒæ­¥"</string>
+ <string name="serviceClassDataSync">"åŒæ­¥è™•ç†"</string>
+ <string name="serviceClassPacket">"å°åŒ…"</string>
+ <string name="serviceClassPAD">"按éµ"</string>
+ <string name="roamingText0">"漫éŠæŒ‡ç¤ºé–‹å•Ÿ"</string>
+ <string name="roamingText1">"漫éŠæŒ‡ç¤ºé—œé–‰"</string>
+ <string name="roamingText2">"漫éŠæŒ‡ç¤ºé–ƒçˆ"</string>
+ <string name="roamingText3">"超出鄰近範åœ"</string>
+ <string name="roamingText4">"超出建築物範åœ"</string>
+ <string name="roamingText5">"æ¼«éŠ - å好系統"</string>
+ <string name="roamingText6">"æ¼«éŠ - å¯ç”¨ç³»çµ±"</string>
+ <string name="roamingText7">"æ¼«éŠ - è¯ç›Ÿåˆä½œå¤¥ä¼´"</string>
+ <string name="roamingText8">"æ¼«éŠ - Google Premium åˆä½œå¤¥ä¼´"</string>
+ <string name="roamingText9">"æ¼«éŠ - 完整æœå‹™åŠŸèƒ½"</string>
+ <string name="roamingText10">"æ¼«éŠ - 部份æœå‹™åŠŸèƒ½"</string>
+ <string name="roamingText11">"漫éŠæ©«å¹…é–‹å•Ÿ"</string>
+ <string name="roamingText12">"漫éŠæ©«å¹…關閉"</string>
+ <string name="roamingTextSearching">"正在æœå°‹æœå‹™"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g> 秒後 <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
+ <string name="fcComplete">"功能碼輸入完æˆã€‚"</string>
+ <string name="fcError">"連線發生å•é¡Œæˆ–功能碼無效。"</string>
+ <string name="httpErrorOk">"確定"</string>
+ <string name="httpError">"網é å…§å®¹éŒ¯èª¤ã€‚"</string>
+ <string name="httpErrorLookup">"找ä¸åˆ°ç¶²å€ã€‚"</string>
+ <string name="httpErrorUnsupportedAuthScheme">"ä¸æ”¯æ´æ­¤ç¶²ç«™é©—證機制。"</string>
+ <string name="httpErrorAuth">"驗證失敗。"</string>
+ <string name="httpErrorProxyAuth">"é€éŽ proxy 伺æœå™¨é©—證失敗。"</string>
+ <string name="httpErrorConnect">"連線到伺æœå™¨å¤±æ•—。"</string>
+ <string name="httpErrorIO">"無法與伺æœå™¨æºé€šï¼Œè«‹ç¨å¾Œå†è©¦ä¸€æ¬¡ 。"</string>
+ <string name="httpErrorTimeout">"連線到伺æœå™¨é€¾æ™‚。"</string>
+ <string name="httpErrorRedirectLoop">"此網é åŒ…å«å¤ªå¤šä¼ºæœå™¨è½‰å€ã€‚"</string>
+ <string name="httpErrorUnsupportedScheme">"ä¸æ”¯æ´æ­¤é€šè¨Šå”定。"</string>
+ <string name="httpErrorFailedSslHandshake">"無法建立安全連線。"</string>
+ <string name="httpErrorBadUrl">"由於網å€éŒ¯èª¤ï¼Œç„¡æ³•é–‹å•Ÿæ­¤ç¶²é ã€‚"</string>
+ <string name="httpErrorFile">"無法存å–此檔案。"</string>
+ <string name="httpErrorFileNotFound">"找ä¸åˆ°è¦æ±‚的檔案。"</string>
+ <string name="httpErrorTooManyRequests">"太多執行è¦æ±‚。請ç¨å¾Œå†è©¦ä¸€æ¬¡ã€‚"</string>
+ <string name="contentServiceSync">"åŒæ­¥è™•ç†"</string>
+ <string name="contentServiceSyncNotificationTitle">"åŒæ­¥è™•ç†"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"åŒæ™‚刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
+ <string name="low_memory">"手機儲存空間已滿ï¼è«‹åˆªé™¤ä¸€äº›æª”案增加空間。"</string>
+ <string name="me">"我"</string>
+ <string name="power_dialog">"電話é¸é …"</string>
+ <string name="silent_mode">"éœéŸ³æ¨¡å¼"</string>
+ <string name="turn_on_radio">"開啟無線網路"</string>
+ <string name="turn_off_radio">"關閉無線網路"</string>
+ <string name="screen_lock">"螢幕鎖定"</string>
+ <string name="power_off">"關機"</string>
+ <string name="shutdown_progress">"關機中..."</string>
+ <string name="shutdown_confirm">"手機å³å°‡é—œæ©Ÿã€‚"</string>
+ <string name="no_recent_tasks">"最近沒有存å–應用程å¼ã€‚"</string>
+ <string name="global_actions">"電話é¸é …"</string>
+ <string name="global_action_lock">"螢幕鎖定"</string>
+ <string name="global_action_power_off">"關機"</string>
+ <string name="global_action_toggle_silent_mode">"éœéŸ³æ¨¡å¼"</string>
+ <string name="global_action_silent_mode_on_status">"音效已關閉"</string>
+ <string name="global_action_silent_mode_off_status">"音效已開啟"</string>
+ <string name="global_actions_toggle_airplane_mode">"飛航模å¼"</string>
+ <string name="global_actions_airplane_mode_on_status">"飛航模å¼ç‚º [é–‹å•Ÿ]"</string>
+ <string name="global_actions_airplane_mode_off_status">"飛航模å¼ç‚º [關閉]"</string>
+ <string name="safeMode">"安全模å¼"</string>
+ <string name="android_system_label">"Android 系統"</string>
+ <string name="permgrouplab_costMoney">"需è¦é¡å¤–費用的æœå‹™ã€‚"</string>
+ <string name="permgroupdesc_costMoney">"若您å…許應用程å¼åŸ·è¡Œæ­¤æ“作,å¯èƒ½éœ€è¦æ”¯ä»˜ä¸€äº›è²»ç”¨ã€‚"</string>
+ <string name="permgrouplab_messages">"您的簡訊"</string>
+ <string name="permgroupdesc_messages">"讀å–編輯 SMSã€é›»å­éƒµä»¶èˆ‡å…¶ä»–簡訊。"</string>
+ <string name="permgrouplab_personalInfo">"您的個人資訊"</string>
+ <string name="permgroupdesc_personalInfo">"直接存å–手機上的è¯çµ¡äººèˆ‡æ—¥æ›†ã€‚"</string>
+ <string name="permgrouplab_location">"您的ä½ç½®"</string>
+ <string name="permgroupdesc_location">"監視實際ä½ç½®"</string>
+ <string name="permgrouplab_network">"網路通訊"</string>
+ <string name="permgroupdesc_network">"å…許應用程å¼å­˜å–多項網路功能。"</string>
+ <string name="permgrouplab_accounts">"您的 Google 帳戶"</string>
+ <string name="permgroupdesc_accounts">"å­˜å–å¯ç”¨ Google 帳戶。"</string>
+ <string name="permgrouplab_hardwareControls">"硬體控制"</string>
+ <string name="permgroupdesc_hardwareControls">"在å…æŒè¨­å‚™ä¸Šç›´æŽ¥å­˜å–硬體。"</string>
+ <string name="permgrouplab_phoneCalls">"撥打電話"</string>
+ <string name="permgroupdesc_phoneCalls">"監控ã€è¨˜éŒ„與進行通話。"</string>
+ <string name="permgrouplab_systemTools">"系統工具"</string>
+ <string name="permgroupdesc_systemTools">"系統低階存å–與控制。"</string>
+ <string name="permgrouplab_developmentTools">"開發工具"</string>
+ <string name="permgroupdesc_developmentTools">"åªæœ‰é–‹ç™¼è€…需è¦æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permgrouplab_storage">"儲存"</string>
+ <string name="permgroupdesc_storage">"å­˜å– SD å¡ã€‚"</string>
+ <string name="permlab_statusBar">"åœç”¨æˆ–變更狀態列"</string>
+ <string name="permdesc_statusBar">"å…許應用程å¼åœç”¨ç‹€æ…‹åˆ—或新增ã€ç§»é™¤ç³»çµ±åœ–示。"</string>
+ <string name="permlab_expandStatusBar">"展開/收æ”狀態列"</string>
+ <string name="permdesc_expandStatusBar">"å…許應用程å¼å±•é–‹æˆ–收æ”狀態列。"</string>
+ <string name="permlab_processOutgoingCalls">"攔截撥出電話"</string>
+ <string name="permdesc_processOutgoingCalls">"å…許應用程å¼è™•ç†æ’¥å‡ºé›»è©±åŠè®Šæ›´æ’¥è™Ÿã€‚請注æ„:惡æ„程å¼å¯èƒ½è—‰ä»¥ç›£æŽ§ï¼Œè½‰æŽ¥æˆ–阻擋電話撥出。"</string>
+ <string name="permlab_receiveSms">"接收 SMS"</string>
+ <string name="permdesc_receiveSms">"å…許應用程å¼æŽ¥æ”¶ã€è™•ç† SMS 簡訊。請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½ç›£æŽ§ç°¡è¨Šæˆ–在您讀å–å‰æ“…自刪除。"</string>
+ <string name="permlab_receiveMms">"接收 MMS"</string>
+ <string name="permdesc_receiveMms">"å…許應用程å¼æŽ¥æ”¶ã€è™•ç† MMS 簡訊。請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½ç›£æŽ§ç°¡è¨Šæˆ–在您讀å–å‰æ“…自刪除。"</string>
+ <string name="permlab_sendSms">"å‚³é€ SMS 簡訊"</string>
+ <string name="permdesc_sendSms">"å…許應用程å¼å‚³é€ SMS 簡訊。請注æ„:惡æ„程å¼å¯èƒ½æœƒæ“…自傳é€ç°¡è¨Šï¼Œå¢žåŠ æ‚¨çš„支出。"</string>
+ <string name="permlab_readSms">"è®€å– SMS 或 MMS"</string>
+ <string name="permdesc_readSms">"å…許應用程å¼è®€å–手機或 SIM å¡ä¸Šçš„ SMS 簡訊。請注æ„:惡æ„程å¼å¯èƒ½æœƒåˆ©ç”¨æ­¤åŠŸèƒ½è®€å–您的機密簡訊。"</string>
+ <string name="permlab_writeSms">"編輯 SMS 或 MMS"</string>
+ <string name="permdesc_writeSms">"å…許應用程å¼ç·¨è¼¯ SMS 簡訊,存入手機或 SIM å¡ã€‚請注æ„:惡æ„程å¼å¯èƒ½æœƒåˆªé™¤æ‚¨çš„簡訊。"</string>
+ <string name="permlab_receiveWapPush">"接收 WAP"</string>
+ <string name="permdesc_receiveWapPush">"å…許應用程å¼ç‚ºå…¶ä»–程å¼é–‹å•ŸåµéŒ¯åŠŸèƒ½ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½çµ‚止其他應用程å¼ã€‚"</string>
+ <string name="permlab_getTasks">"å–得執行中應用程å¼"</string>
+ <string name="permdesc_getTasks">"å…許應用程å¼å–得最近執行任務的資訊。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½æ‰¾å‡ºå…¶ä»–應用程å¼çš„éš±ç§è³‡è¨Šã€‚"</string>
+ <string name="permlab_reorderTasks">"é‡æ–°å®‰æŽ’執行中的應用程å¼"</string>
+ <string name="permdesc_reorderTasks">"å…許應用程å¼å°‡å·¥ä½œç§»è‡³å‰ç«¯æˆ–背景作業。請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½è‡ªè¡ŒæŠŠè‡ªå·±æ‹‰åˆ°å‰ç«¯ã€‚"</string>
+ <string name="permlab_setDebugApp">"啟用應用程å¼åµéŒ¯"</string>
+ <string name="permdesc_setDebugApp">"å…許應用程å¼ç‚ºå…¶ä»–程å¼é–‹å•ŸåµéŒ¯åŠŸèƒ½ã€‚請注æ„:惡æ„程å¼å¯åˆ©ç”¨æ­¤åŠŸèƒ½çµ‚止其他應用程å¼ã€‚"</string>
+ <string name="permlab_changeConfiguration">"變更介é¢è¨­å®š"</string>
+ <string name="permdesc_changeConfiguration">"å…許應用程å¼è®Šæ›´ç›®å‰è¨­å®šï¼Œä¾‹å¦‚:地å€è¨­å®šæˆ–字型大å°ã€‚"</string>
+ <string name="permlab_restartPackages">"é‡æ–°å•Ÿå‹•å…¶ä»–應用程å¼"</string>
+ <string name="permdesc_restartPackages">"å…許應用程å¼å¼·åˆ¶é‡æ–°å•Ÿå‹•å…¶ä»–應用程å¼ã€‚"</string>
+ <string name="permlab_forceBack">"強制關閉應用程å¼"</string>
+ <string name="permdesc_forceBack">"å…許應用程å¼å¼·åˆ¶é—œé–‰åœ¨å‰ç«¯é‹ä½œçš„活動並返回。一般應用程å¼ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_dump">"接收系統內部狀態"</string>
+ <string name="permdesc_dump">"å…許應用程å¼å–得系統內部狀態。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œä¸ç•¶å–å¾—ç§äººæˆ–安全性資料。"</string>
+ <string name="permlab_shutdown">"部分關機"</string>
+ <string name="permdesc_shutdown">"讓活動管ç†å“¡é€²å…¥é—œæ©Ÿç‹€æ…‹ï¼Œè€Œä¸åŸ·è¡Œå®Œæ•´çš„關機程åºã€‚"</string>
+ <string name="permlab_stopAppSwitches">"防止切æ›æ‡‰ç”¨ç¨‹å¼"</string>
+ <string name="permdesc_stopAppSwitches">"防止使用者切æ›åˆ°å…¶ä»–應用程å¼ã€‚"</string>
+ <string name="permlab_runSetActivityWatcher">"監視控制所有應用程å¼å•Ÿå‹•ç‹€æ…‹ã€‚"</string>
+ <string name="permdesc_runSetActivityWatcher">"å…許應用程å¼ç›£æŽ§ç®¡ç†ç³»çµ±å•Ÿå‹•æ´»å‹•ã€‚請注æ„:惡æ„程å¼å¯èƒ½å› æ­¤ç™±ç˜“整個系統。此權é™åªåœ¨é–‹ç™¼æ™‚需è¦ï¼Œä¸€èˆ¬æ‰‹æ©Ÿä½¿ç”¨ä¸éœ€è¦æ­¤æ¬Šé™ã€‚"</string>
+ <string name="permlab_broadcastPackageRemoved">"傳é€ç¨‹å¼å·²ç§»é™¤å»£æ’­"</string>
+ <string name="permdesc_broadcastPackageRemoved">"å…許應用程å¼åœ¨å…¶ä»–應用程å¼è¢«ç§»é™¤æ™‚發é€é€šçŸ¥ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œé—œé–‰å…¶ä»–執行中的程å¼ã€‚"</string>
+ <string name="permlab_broadcastSmsReceived">"傳é€å·²æŽ¥æ”¶ SMS 廣播"</string>
+ <string name="permdesc_broadcastSmsReceived">"å…許應用程å¼åœ¨æ”¶åˆ° SMS 簡訊時發出通知。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½å½é€  SMS 簡訊。"</string>
+ <string name="permlab_broadcastWapPush">"é€å‡ºã€ŒWAP PUSH 已接收ã€å»£æ’­"</string>
+ <string name="permdesc_broadcastWapPush">"å…許應用程å¼åœ¨æ”¶åˆ° WAP PUSH 簡訊時發é€é€šçŸ¥ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œå½é€  MMS 簡訊回æ¢æˆ–秘密更æ›ç¶²é å…§å®¹ã€‚"</string>
+ <string name="permlab_setProcessLimit">"執行程åºé™åˆ¶æ•¸"</string>
+ <string name="permdesc_setProcessLimit">"å…許應用程å¼æŽ§åˆ¶å¯ä½¿ç”¨çš„最大執行緒。一般應用程å¼ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_setAlwaysFinish">"關閉所有背景程å¼"</string>
+ <string name="permdesc_setAlwaysFinish">"å…許應用程å¼æŽ§åˆ¶å“ªäº›æ´»å‹•åœ¨è¢«ç§»åˆ°èƒŒæ™¯åŸ·è¡Œæ™‚,儘速çµæŸã€‚一般應用程å¼ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_batteryStats">"編輯電池狀態"</string>
+ <string name="permdesc_batteryStats">"å…許修改電池狀態。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_backup">"控制系統備份與還原"</string>
+ <string name="permdesc_backup">"å…許應用程å¼æŽ§åˆ¶ç³»çµ±å‚™ä»½èˆ‡é‚„原機制,但一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_internalSystemWindow">"顯示未授權視窗"</string>
+ <string name="permdesc_internalSystemWindow">"å…許內部系統使用介é¢å»ºç«‹è¦–窗。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_systemAlertWindow">"顯示系統警示"</string>
+ <string name="permdesc_systemAlertWindow">"å…許應用程å¼é¡¯ç¤ºç³»çµ±è­¦å‘Šè¦–窗。請注æ„:惡æ„程å¼å¯ä½¿ç”¨æ­¤åŠŸèƒ½æŽ¥ç®¡æ‰‹æ©Ÿèž¢å¹•ã€‚"</string>
+ <string name="permlab_setAnimationScale">"編輯全域動畫速度"</string>
+ <string name="permdesc_setAnimationScale">"å…許應用程å¼è®Šæ›´å…¨åŸŸå‹•ç•«é€Ÿåº¦ (更快或更慢)。"</string>
+ <string name="permlab_manageAppTokens">"管ç†æ‡‰ç”¨ç¨‹å¼ token"</string>
+ <string name="permdesc_manageAppTokens">"å…許應用程å¼ç•¥éŽä¸€èˆ¬ Z-ordering,建立與管ç†è‡ªå·±çš„ token。一般應用程å¼ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_injectEvents">"按éµåŠæŽ§åˆ¶æŒ‰éˆ•"</string>
+ <string name="permdesc_injectEvents">"å…許應用程å¼ç™¼é€è¼¸å…¥äº‹ä»¶ (按éµç­‰) 給其他應用程å¼ã€‚請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½æŽ¥ç®¡æ‰‹æ©Ÿã€‚"</string>
+ <string name="permlab_readInputState">"記錄您的輸入內容與æ“作"</string>
+ <string name="permdesc_readInputState">"å…許應用程å¼åœ¨ä½¿ç”¨è€…æ“作其他程å¼æ™‚ (例如:輸入密碼),ä»å¯ç›£çœ‹è¼¸å…¥çš„按éµã€‚一般應用程å¼æ‡‰ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_bindInputMethod">"連çµè‡³è¼¸å…¥æ³•"</string>
+ <string name="permdesc_bindInputMethod">"å…許æ“有人連çµè‡³è¼¸å…¥æ³•çš„最頂層介é¢ã€‚一般應用程å¼ä¸éœ€ä½¿ç”¨æ­¤é¸é …。"</string>
+ <string name="permlab_setOrientation">"變更螢幕顯示方å‘"</string>
+ <string name="permdesc_setOrientation">"å…許應用程å¼éš¨æ™‚變更螢幕顯示方å‘。一般應用程å¼ä¸éœ€è¦æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_signalPersistentProcesses">"å‚³é€ Linux 訊號到應用程å¼"</string>
+ <string name="permdesc_signalPersistentProcesses">"å…許應用程å¼è¦æ±‚將支æ´çš„訊號傳é€åˆ°æ‰€æœ‰æŒçºŒçš„程åºã€‚"</string>
+ <string name="permlab_persistentActivity">"設定應用程å¼æŒçºŒåŸ·è¡Œ"</string>
+ <string name="permdesc_persistentActivity">"å…許應用程å¼æŒçºŒåŸ·è¡Œï¼Œé¿å…系統將它應用到其他程å¼ã€‚"</string>
+ <string name="permlab_deletePackages">"刪除應用程å¼"</string>
+ <string name="permdesc_deletePackages">"å…許應用程å¼åˆªé™¤ Android 程å¼ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½åˆªé™¤é‡è¦æ‡‰ç”¨ç¨‹å¼ã€‚"</string>
+ <string name="permlab_clearAppUserData">"刪除其他應用程å¼è³‡æ–™"</string>
+ <string name="permdesc_clearAppUserData">"å…許應用程å¼æ¸…除使用者資料。"</string>
+ <string name="permlab_deleteCacheFiles">"刪除其他應用程å¼å¿«å–"</string>
+ <string name="permdesc_deleteCacheFiles">"å…許應用程å¼åˆªé™¤å¿«å–檔案。"</string>
+ <string name="permlab_getPackageSize">"估算應用程å¼å ç”¨çš„儲存空間"</string>
+ <string name="permdesc_getPackageSize">"å…許應用程å¼å–得程å¼ç¢¼ã€è³‡æ–™èˆ‡å¿«å–大å°"</string>
+ <string name="permlab_installPackages">"直接安è£æ‡‰ç”¨ç¨‹å¼"</string>
+ <string name="permdesc_installPackages">"å…許應用程å¼å®‰è£æ–°çš„ Android 程å¼æˆ–更新。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½æ–°å¢žå…·æœ‰æ¥µé«˜æ¬Šé™çš„程å¼ã€‚"</string>
+ <string name="permlab_clearAppCache">"刪除所有應用程å¼å¿«å–資料。"</string>
+ <string name="permdesc_clearAppCache">"å…許應用程å¼åˆªé™¤å¿«å–目錄裡的檔案,釋放儲存空間。此æ“作通常å—到系統程åºåš´æ ¼é™åˆ¶ã€‚"</string>
+ <string name="permlab_readLogs">"讀å–系統記錄檔"</string>
+ <string name="permdesc_readLogs">"å…許應用程å¼è®€å–系統記錄檔。此項æ“作å¯è®“應用程å¼äº†è§£ç›®å‰æ‰‹æ©Ÿæ“作狀態,但內容應ä¸å«ä»»ä½•å€‹äººæˆ–éš±ç§è³‡è¨Šã€‚"</string>
+ <string name="permlab_diagnostic">"讀寫 diag æ“有的資æº"</string>
+ <string name="permdesc_diagnostic">"å…許應用程å¼è®€å¯« diag 群組的資æºï¼›ä¾‹å¦‚:/dev 裡的檔案。這å¯èƒ½æœƒå½±éŸ¿ç³»çµ±ç©©å®šæ€§èˆ‡å®‰å…¨æ€§ã€‚此功能僅供製造商或技術人員用於硬體è¦æ ¼åµæ¸¬ã€‚"</string>
+ <string name="permlab_changeComponentState">"啟用或åœç”¨æ‡‰ç”¨ç¨‹å¼å…ƒä»¶"</string>
+ <string name="permdesc_changeComponentState">"å…許應用程å¼è®Šæ›´æ˜¯å¦å•Ÿç”¨å…¶ä»–元件或應用程å¼ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œåœç”¨é‡è¦çš„手機功能。由於此功能å¯èƒ½å°Žè‡´æ‡‰ç”¨ç¨‹å¼å…ƒä»¶ç„¡æ³•ä½¿ç”¨ã€ä¸ä¸€è‡´æˆ–ä¸ç©©å®šï¼Œè«‹å°å¿ƒæ–Ÿé…ŒæŽˆæ¬Šã€‚"</string>
+ <string name="permlab_setPreferredApplications">"設定喜好的應用程å¼"</string>
+ <string name="permdesc_setPreferredApplications">"å…許應用程å¼ä¿®æ”¹æ‚¨å好的應用程å¼ã€‚請注æ„:惡æ„程å¼å¯èƒ½è—‰ä»¥ç§˜å¯†ç«„改執行的程å¼ï¼Œæˆ–å½é€ å·²å­˜åœ¨çš„程å¼ä»¥æ”¶é›†ç§äººè³‡æ–™ã€‚"</string>
+ <string name="permlab_writeSettings">"編輯全域系統設定"</string>
+ <string name="permdesc_writeSettings">"å…許應用程å¼ä¿®æ”¹ç³»çµ±è¨­å®šã€‚請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½æ毀系統設定。"</string>
+ <string name="permlab_writeSecureSettings">"編輯安全系統設定"</string>
+ <string name="permdesc_writeSecureSettings">"å…許應用程å¼ä¿®æ”¹ç³»çµ±çš„安全設定資料。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_writeGservices">"修改 Google æœå‹™åœ°åœ–"</string>
+ <string name="permdesc_writeGservices">"å…許應用程å¼ä¿®æ”¹ Google æœå‹™åœ°åœ–。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_receiveBootCompleted">"開機時自動啟用"</string>
+ <string name="permdesc_receiveBootCompleted">"å…許應用程å¼åœ¨é–‹æ©Ÿå¾Œç›¡å¿«å•Ÿå‹•ã€‚此項設定會讓開機時間拉長,並å…許應用程å¼æŒçºŒåŸ·è¡Œï¼Œå› æ­¤æ‹–慢手機速度。"</string>
+ <string name="permlab_broadcastSticky">"傳é€é™„屬廣播"</string>
+ <string name="permdesc_broadcastSticky">"å…許應用程å¼å‚³é€æŒä¹…的廣播。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ä¾†ä½”æ“šéŽå¤šè¨˜æ†¶é«”,讓手機速度變慢或ä¸ç©©å®šã€‚"</string>
+ <string name="permlab_readContacts">"讀å–è¯çµ¡äººè³‡æ–™"</string>
+ <string name="permdesc_readContacts">"å…許應用程å¼è®€å–手機上所有è¯çµ¡äºº (地å€)。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½å°‡æ‚¨çš„資料傳é€çµ¦å…¶ä»–人。"</string>
+ <string name="permlab_writeContacts">"輸入è¯çµ¡äººè³‡æ–™"</string>
+ <string name="permdesc_writeContacts">"å…許應用程å¼æ›´æ”¹è¯çµ¡è³‡è¨Š (地å€)。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œæ¸…除或修改è¯çµ¡è³‡æ–™ã€‚"</string>
+ <string name="permlab_writeOwnerData">"寫入æŒæœ‰è€…的資料"</string>
+ <string name="permdesc_writeOwnerData">"å…許應用程å¼æ›´æ”¹æ‰‹æ©ŸæŒæœ‰è€…的資料。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œæ¸…除或修改æŒæœ‰è€…的資料。"</string>
+ <string name="permlab_readOwnerData">"讀å–æŒæœ‰è€…的資料"</string>
+ <string name="permdesc_readOwnerData">"å…許應用程å¼è®€å–手機æŒæœ‰è€…資料。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½è®€å–æŒæœ‰è€…的資料。"</string>
+ <string name="permlab_readCalendar">"讀å–日曆資料"</string>
+ <string name="permdesc_readCalendar">"å…許應用程å¼è®€å–手機上所有日曆資料。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½å°‡æ‚¨çš„日曆資料傳é€çµ¦å…¶ä»–人。"</string>
+ <string name="permlab_writeCalendar">"寫入日曆資料"</string>
+ <string name="permdesc_writeCalendar">"å…許應用程å¼ç·¨è¼¯æ—¥æ›†è³‡æ–™ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½ï¼Œæ¸…除或修改您的日曆資料。"</string>
+ <string name="permlab_accessMockLocation">"模擬ä½ç½®ä¾†æºä»¥ä¾›æ¸¬è©¦"</string>
+ <string name="permdesc_accessMockLocation">"建立模擬ä½ç½®ä¾†æºä»¥ä¾›æ¸¬è©¦ã€‚請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½è¦†å¯« GPS 或電信業者傳回的ä½ç½®åŠ/或狀態。"</string>
+ <string name="permlab_accessLocationExtraCommands">"接收é¡å¤–çš„ä½ç½®æ供者指令"</string>
+ <string name="permdesc_accessLocationExtraCommands">"å­˜å–é¡å¤–ä½ç½®æ供者命令。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½å¹²æ“¾ GPS 或其他ä½ç½®ä¾†æºã€‚"</string>
+ <string name="permlab_installLocationProvider">"准許安è£ä½ç½®æ供者"</string>
+ <string name="permdesc_installLocationProvider">"建立虛構的ä½ç½®ä¾†æºä»¥ä¾›æ¸¬è©¦ã€‚請注æ„:惡æ„應用程å¼å¯èƒ½åˆ©ç”¨æ­¤é¸é …覆寫由真實ä½ç½®ä¾†æº (例如 GPS 或網路供應商) 所傳回的ä½ç½®åŠ/或狀態,或者監控您的ä½ç½®ä¸¦å°‡ä¹‹æ供給外部來æºã€‚"</string>
+ <string name="permlab_accessFineLocation">"ç²¾ç¢ºå®šä½ (GPS)"</string>
+ <string name="permdesc_accessFineLocation">"接收精確的ä½ç½®ä¾†æº (例如:手機 GPS)。請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½å¾—知您的ä½ç½®ï¼Œä¸¦å¯èƒ½æ¶ˆè€—é¡å¤–é›»æºã€‚"</string>
+ <string name="permlab_accessCoarseLocation">"ç´„ç•¥ä½ç½® (以網路為基準)"</string>
+ <string name="permdesc_accessCoarseLocation">"接收約略的ä½ç½®ä¾†æº (例如:行動網路資料庫),計算出目å‰å¤§æ¦‚ä½ç½®ã€‚請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½å¾—知您的所在地。"</string>
+ <string name="permlab_accessSurfaceFlinger">"å­˜å– SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"å…許應用程å¼ä½¿ç”¨ SurfaceFlinger 低階功能。"</string>
+ <string name="permlab_readFrameBuffer">"讀å–框架緩è¡"</string>
+ <string name="permdesc_readFrameBuffer">"å…許應用程å¼è®€å–框架緩è¡çš„內容。"</string>
+ <string name="permlab_modifyAudioSettings">"變更音訊設定"</string>
+ <string name="permdesc_modifyAudioSettings">"å…許應用程å¼ç·¨è¼¯å…¨åŸŸéŸ³è¨Šè¨­å®šï¼Œä¾‹å¦‚音é‡èˆ‡è·¯ç”±ã€‚"</string>
+ <string name="permlab_recordAudio">"錄製音訊"</string>
+ <string name="permdesc_recordAudio">"å…許應用程å¼å­˜å–音訊錄製路徑。"</string>
+ <string name="permlab_camera">"照相"</string>
+ <string name="permdesc_camera">"å…許應用程å¼ä½¿ç”¨ç›¸æ©Ÿæ‹ç…§ã€‚此功能å¯è®“應用程å¼éš¨æ™‚é€éŽç›¸æ©Ÿæ‹æ”照片。"</string>
+ <string name="permlab_brick">"永久åœç”¨é›»è©±"</string>
+ <string name="permdesc_brick">"å…許應用程å¼æ°¸ä¹…åœç”¨æ‰‹æ©Ÿã€‚此項æ“作éžå¸¸å±éšªã€‚"</string>
+ <string name="permlab_reboot">"強制é‡é–‹æ©Ÿ"</string>
+ <string name="permdesc_reboot">"å…許應用程å¼å¼·åˆ¶é‡é–‹æ©Ÿã€‚"</string>
+ <string name="permlab_mount_unmount_filesystems">"掛載/å¸è¼‰æª”案系統"</string>
+ <string name="permdesc_mount_unmount_filesystems">"å…許應用程å¼æŽ›è¼‰/å¸è¼‰æŠ½å–å¼å„²å­˜è¨­å‚™çš„檔案系統。"</string>
+ <string name="permlab_mount_format_filesystems">"將外接å¼å„²å­˜è£ç½®æ ¼å¼åŒ–"</string>
+ <string name="permdesc_mount_format_filesystems">"å…許應用程å¼å°‡å¯ç§»é™¤å¼å„²å­˜è£ç½®æ ¼å¼åŒ–。"</string>
+ <string name="permlab_vibrate">"控制震動"</string>
+ <string name="permdesc_vibrate">"å…許應用程å¼æŽ§åˆ¶éœ‡å‹•ã€‚"</string>
+ <string name="permlab_flashlight">"控制閃光燈"</string>
+ <string name="permdesc_flashlight">"å…許應用程å¼æŽ§åˆ¶é–ƒå…‰ç‡ˆã€‚"</string>
+ <string name="permlab_hardware_test">"測試硬體"</string>
+ <string name="permdesc_hardware_test">"å…許應用程å¼æŽ§åˆ¶å„種週邊設備,以供測試用。"</string>
+ <string name="permlab_callPhone">"直接撥打電話號碼"</string>
+ <string name="permdesc_callPhone">"å…許應用程å¼è‡ªè¡Œæ’¥æ‰“電話。請注æ„:惡æ„程å¼å¯èƒ½ä»»æ„撥打電話,造æˆé æœŸå¤–的支出。但此é¸é …並ä¸å…許應用程å¼æ’¥æ‰“緊急電話號碼。"</string>
+ <string name="permlab_callPrivileged">"直接撥打任何電話號碼"</string>
+ <string name="permdesc_callPrivileged">"å…許應用程å¼è‡ªè¡Œæ’¥æ‰“任何電話號碼,包括緊急電話號碼。請注æ„:惡æ„程å¼å¯èƒ½åˆ©ç”¨æ­¤åŠŸèƒ½æ¿«ç”¨ç·Šæ€¥æœå‹™ï¼Œæ’¥æ‰“ä¸å¿…è¦æˆ–é•æ³•çš„電話。"</string>
+ <string name="permlab_locationUpdates">"控制ä½ç½®æ›´æ–°é€šçŸ¥"</string>
+ <string name="permdesc_locationUpdates">"å…許啟用/åœç”¨ç„¡ç·šé€šè¨Šä½ç½®æ›´æ–°é€šçŸ¥ã€‚一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_checkinProperties">"å­˜å–登機é¸é …"</string>
+ <string name="permdesc_checkinProperties">"å…許讀寫登機æœå‹™ä¸Šå‚³çš„資料。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_bindGadget">"é¸æ“‡å°å·¥å…·"</string>
+ <string name="permdesc_bindGadget">"å…許應用程å¼å‘ŠçŸ¥ç³»çµ±å“ªå€‹æ‡‰ç”¨ç¨‹å¼å¯ä»¥ä½¿ç”¨å“ªäº›å°å·¥å…·ã€‚開啟此權é™å¾Œï¼Œæ‡‰ç”¨ç¨‹å¼æœƒè®“其他程å¼ä½¿ç”¨å€‹äººè³‡æ–™ï¼Œä½†ä¸€èˆ¬æ‡‰ç”¨ç¨‹å¼ä¸é©åˆä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="permlab_modifyPhoneState">"修改手機狀態"</string>
+ <string name="permdesc_modifyPhoneState">"å…許應用程å¼æŽ§åˆ¶é›»è©±åŠŸèƒ½ã€‚æ“有此權é™çš„程å¼å¯è‡ªè¡Œåˆ‡æ›ç¶²è·¯ã€é–‹é—œç„¡ç·šé€šè¨ŠåŠŸèƒ½ã€‚"</string>
+ <string name="permlab_readPhoneState">"讀å–手機狀態"</string>
+ <string name="permdesc_readPhoneState">"å…許應用程å¼å­˜å–è£ç½®çš„電話功能。有此權é™çš„應用程å¼å¯å–得手機的號碼ã€æ˜¯å¦åœ¨é€šè©±ä¸­ï¼Œä»¥åŠé€šè©±å¦ä¸€æ–¹çš„電話號碼等資料。"</string>
+ <string name="permlab_wakeLock">"防止手機進入待命狀態"</string>
+ <string name="permdesc_wakeLock">"å…許應用程å¼é˜²æ­¢æ‰‹æ©Ÿé€²å…¥å¾…命。"</string>
+ <string name="permlab_devicePower">"開啟或關閉電æº"</string>
+ <string name="permdesc_devicePower">"å…許應用程å¼é–‹å•Ÿæˆ–關閉電話。"</string>
+ <string name="permlab_factoryTest">"在出廠測試模å¼ä¸‹åŸ·è¡Œ"</string>
+ <string name="permdesc_factoryTest">"執行低階製造商測試,å…許完全存å–手機硬體。此功能åªèƒ½åœ¨æ‰‹æ©Ÿæ˜¯è£½é€ å•†æ¸¬è©¦æ¨¡å¼ä¸‹æ‰å¯åŸ·è¡Œã€‚"</string>
+ <string name="permlab_setWallpaper">"設定桌布"</string>
+ <string name="permdesc_setWallpaper">"å…許應用程å¼è¨­å®šç³»çµ±æ¡Œå¸ƒã€‚"</string>
+ <string name="permlab_setWallpaperHints">"設定桌布大å°æ示"</string>
+ <string name="permdesc_setWallpaperHints">"å…許應用程å¼è¨­å®šç³»çµ±æ¡Œå¸ƒå¤§å°æ示。"</string>
+ <string name="permlab_masterClear">"將系統還原至出廠é è¨­å€¼"</string>
+ <string name="permdesc_masterClear">"å…許應用程å¼å°‡æ‰‹æ©Ÿå®Œå…¨é‡è¨­è‡³å‡ºå» è¨­å®šï¼Œæ¸…除所有資料ã€è¨­å®šèˆ‡å·²å®‰è£ç¨‹å¼ã€‚"</string>
+ <string name="permlab_setTimeZone">"設定時å€"</string>
+ <string name="permdesc_setTimeZone">"å…許應用程å¼è®Šæ›´æ™‚å€ã€‚"</string>
+ <string name="permlab_getAccounts">"發ç¾å·²çŸ¥å¸³æˆ¶ã€‚"</string>
+ <string name="permdesc_getAccounts">"å…許應用程å¼å–得手機上的帳戶清單。"</string>
+ <string name="permlab_accessNetworkState">"檢視網路狀態"</string>
+ <string name="permdesc_accessNetworkState">"å…許應用程å¼æª¢è¦–網路狀態。"</string>
+ <string name="permlab_createNetworkSockets">"網際網路完整存å–"</string>
+ <string name="permdesc_createNetworkSockets">"å…許應用程å¼å»ºç«‹ç¶²è·¯è¨­å®šã€‚"</string>
+ <string name="permlab_writeApnSettings">"輸入存å–點å稱設定"</string>
+ <string name="permdesc_writeApnSettings">"å…許應用程å¼ä¿®æ”¹ APN 設定,例如:Proxy åŠ APN 的連接埠。"</string>
+ <string name="permlab_changeNetworkState">"變更網路連線"</string>
+ <string name="permdesc_changeNetworkState">"å…許應用程å¼è®Šæ›´ç¶²è·¯é€£ç·šç‹€æ…‹ã€‚"</string>
+ <string name="permlab_changeBackgroundDataSetting">"變更背景資料使用設定"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"å…許應用程å¼è®Šæ›´èƒŒæ™¯è³‡æ–™ä½¿ç”¨è¨­å®šã€‚"</string>
+ <string name="permlab_accessWifiState">"檢視 Wi-Fi 狀態"</string>
+ <string name="permdesc_accessWifiState">"å…許應用程å¼æª¢è¦– Wi-Fi 狀態資訊。"</string>
+ <string name="permlab_changeWifiState">"變更 Wi-Fi 狀態"</string>
+ <string name="permdesc_changeWifiState">"å…許應用程å¼èˆ‡ Wi-Fi å­˜å–點連線或中斷連線,並å¯è®Šæ›´ Wi-Fi 網路設定。"</string>
+ <string name="permlab_changeWifiMulticastState">"å…許接收 Wi-Fi 多點傳播å°åŒ…"</string>
+ <string name="permdesc_changeWifiMulticastState">"å…許應用程å¼æŽ¥æ”¶ä¸¦éžæŒ‡å®šå‚³é€çµ¦æ‚¨è£ç½®çš„å°åŒ…,這在您發ç¾é™„近有æœå‹™å¯ä½¿ç”¨æ™‚很有用,但消耗的電力比éžå¤šé»žå‚³æ’­æ¨¡å¼é‚„è¦å¤šã€‚"</string>
+ <string name="permlab_bluetoothAdmin">"è—牙管ç†"</string>
+ <string name="permdesc_bluetoothAdmin">"å…許應用程å¼è¨­å®šæœ¬æ©Ÿè—牙電話,以åŠåµæ¸¬èˆ‡é…å°å…¶ä»–é ç«¯è£ç½®ã€‚"</string>
+ <string name="permlab_bluetooth">"建立è—牙連線"</string>
+ <string name="permdesc_bluetooth">"å…許應用程å¼æª¢è¦–本機è—牙電話設定,並與其他é…å°è£ç½®é€£ç·šã€‚"</string>
+ <string name="permlab_disableKeyguard">"åœç”¨æŒ‰éµéŽ–定"</string>
+ <string name="permdesc_disableKeyguard">"å…許應用程å¼åœç”¨æŒ‰éµéŽ–定以åŠå…¶ä»–相關的密碼安全性。例如:收到來電時解除按éµéŽ–定,通話çµæŸå¾Œé‡æ–°å•Ÿå‹•æŒ‰éµéŽ–定。"</string>
+ <string name="permlab_readSyncSettings">"讀å–åŒæ­¥è™•ç†è¨­å®š"</string>
+ <string name="permdesc_readSyncSettings">"å…許應用程å¼è®€å–åŒæ­¥è™•ç†è¨­å®šï¼Œä¾‹å¦‚:是å¦åŒæ­¥è™•ç† [è¯çµ¡äºº]。"</string>
+ <string name="permlab_writeSyncSettings">"編輯åŒæ­¥è™•ç†è¨­å®š"</string>
+ <string name="permdesc_writeSyncSettings">"å…許應用程å¼ä¿®æ”¹åŒæ­¥è™•ç†è¨­å®šï¼Œä¾‹å¦‚:是å¦è¦åŒæ­¥è™•ç† [è¯çµ¡äºº]。"</string>
+ <string name="permlab_readSyncStats">"讀å–åŒæ­¥è™•ç†ç‹€æ…‹"</string>
+ <string name="permdesc_readSyncStats">"å…許應用程å¼è®€å–åŒæ­¥è™•ç†ç‹€æ…‹ï¼›ä¾‹å¦‚:åŒæ­¥è™•ç†è¨˜éŒ„。"</string>
+ <string name="permlab_subscribedFeedsRead">"讀å–訂閱資訊æä¾›"</string>
+ <string name="permdesc_subscribedFeedsRead">"å…許應用程å¼å–å¾—ç›®å‰å·²åŒæ­¥è™•ç†çš„資訊æ供。"</string>
+ <string name="permlab_subscribedFeedsWrite">"寫入訂閱資訊æä¾›"</string>
+ <string name="permdesc_subscribedFeedsWrite">"å…許應用程å¼ä¿®æ”¹å·²åŒæ­¥è™•ç†çš„資訊æ供。請注æ„:惡æ„程å¼å¯èƒ½ä½¿ç”¨æ­¤åŠŸèƒ½è®Šæ›´å·²åŒæ­¥è™•ç†çš„資訊æ供。"</string>
+ <string name="permlab_readDictionary">"讀å–使用者定義的字典"</string>
+ <string name="permdesc_readDictionary">"å…許應用程å¼è®€å–使用者儲存在使用者字典內的任何ç§äººå­—è©žã€å稱和詞組。"</string>
+ <string name="permlab_writeDictionary">"寫入使用者定義的字典"</string>
+ <string name="permdesc_writeDictionary">"å…許應用程å¼å°‡æ–°å­—詞寫入使用者的字典。"</string>
+ <string name="permlab_sdcardWrite">"修改/刪除 SD å¡çš„內容"</string>
+ <string name="permdesc_sdcardWrite">"å…許應用程å¼å¯«å…¥ SD å¡ã€‚"</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"ä½å®¶é›»è©±"</item>
- <item msgid="869923650527136615">"行動電話"</item>
- <item msgid="7897544654242874543">"å…¬å¸é›»è©±"</item>
- <item msgid="1103601433382158155">"å…¬å¸å‚³çœŸ"</item>
- <item msgid="1735177144948329370">"ä½å®¶å‚³çœŸ"</item>
- <item msgid="603878674477207394">"呼å«å™¨"</item>
- <item msgid="1650824275177931637">"其他"</item>
- <item msgid="9192514806975898961">"自訂"</item>
+ <item>"ä½å®¶é›»è©±"</item>
+ <item>"行動電話"</item>
+ <item>"å…¬å¸é›»è©±"</item>
+ <item>"å…¬å¸å‚³çœŸ"</item>
+ <item>"ä½å®¶å‚³çœŸ"</item>
+ <item>"呼å«å™¨"</item>
+ <item>"其他"</item>
+ <item>"自訂"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"主è¦ä¿¡ç®±"</item>
- <item msgid="7084237356602625604">"å…¬å¸ä¿¡ç®±"</item>
- <item msgid="1112044410659011023">"其他信箱"</item>
- <item msgid="2374913952870110618">"自訂"</item>
+ <item>"主è¦ä¿¡ç®±"</item>
+ <item>"å…¬å¸ä¿¡ç®±"</item>
+ <item>"其他信箱"</item>
+ <item>"自訂"</item>
</string-array>
- <string name="mobileEmailTypeName" msgid="2858957283716687707">"行動è£ç½®"</string>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"ä½å®¶"</item>
- <item msgid="5629153956045109251">"å…¬å¸"</item>
- <item msgid="4966604264500343469">"其他"</item>
- <item msgid="4932682847595299369">"自訂"</item>
+ <item>"ä½å®¶"</item>
+ <item>"å…¬å¸"</item>
+ <item>"其他"</item>
+ <item>"自訂"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"ä½å®¶"</item>
- <item msgid="1359644565647383708">"工作"</item>
- <item msgid="7868549401053615677">"其他"</item>
- <item msgid="3145118944639869809">"自訂"</item>
+ <item>"ä½å®¶"</item>
+ <item>"工作"</item>
+ <item>"其他"</item>
+ <item>"自訂"</item>
</string-array>
<string-array name="organizationTypes">
- <item msgid="7546335612189115615">"工作"</item>
- <item msgid="4378074129049520373">"其他"</item>
- <item msgid="3455047468583965104">"自訂"</item>
+ <item>"工作"</item>
+ <item>"其他"</item>
+ <item>"自訂"</item>
</string-array>
<string-array name="imProtocols">
- <item msgid="8595261363518459565">"AIM"</item>
- <item msgid="7390473628275490700">"Windows Live"</item>
- <item msgid="7882877134931458217">"Yahoo"</item>
- <item msgid="5035376313200585242">"Skype"</item>
- <item msgid="7532363178459444943">"QQ"</item>
- <item msgid="3713441034299660749">"Google Talk"</item>
- <item msgid="2506857312718630823">"ICQ"</item>
- <item msgid="1648797903785279353">"Jabber"</item>
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"輸入 PIN 碼"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"PIN 碼錯誤ï¼"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"如è¦è§£éŽ–,請按 Menu éµï¼Œç„¶å¾ŒæŒ‰ 0。"</string>
- <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"緊急電話號碼"</string>
- <string name="lockscreen_carrier_default" msgid="8812714795156374435">"(沒有æœå‹™)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"螢幕已鎖定。"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"按下 [Menu] 解鎖或撥打緊急電話。"</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"按下 Menu éµè§£éŽ–。"</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"畫出解鎖圖形"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"緊急電話"</string>
- <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"正確ï¼"</string>
- <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"很抱歉,請å†è©¦ä¸€æ¬¡"</string>
- <string name="lockscreen_plugged_in" msgid="613343852842944435">"正在充電 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"充電完æˆã€‚"</string>
- <string name="lockscreen_low_battery" msgid="1482873981919249740">"請連接充電器。"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"沒有 SIM å¡ã€‚"</string>
- <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"手機未æ’å…¥ SIM å¡ã€‚"</string>
- <string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"è«‹æ’å…¥ SIM å¡ã€‚"</string>
- <string name="lockscreen_network_locked_message" msgid="143389224986028501">"網路已鎖定"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM 的 PUK 已鎖定。"</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"è«‹åƒé–±ã€Šä½¿ç”¨è€…指å—》或è¯çµ¡å®¢æˆ¶æœå‹™ä¸­å¿ƒã€‚"</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM å¡å·²éŽ–定。"</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"解鎖 SIM å¡ä¸­..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\n\n" 請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後å†å˜—試。"</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。å†éŒ¯èª¤ <xliff:g id="NUMBER_1">%d</xliff:g> 次後,系統會è¦æ±‚使用 Google 登入來解鎖。"\n\n" 請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後å†è©¦ä¸€æ¬¡ã€‚"</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> 秒後å†è©¦ä¸€æ¬¡ã€‚"</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"忘記解鎖圖形?"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"解鎖圖形出錯次數éŽå¤šï¼"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"如è¦è§£é™¤éŽ–定,請使用 Google 帳戶登入"</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"使用者å稱 (é›»å­éƒµä»¶)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"密碼"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"登入"</string>
- <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"使用者å稱或密碼錯誤。"</string>
- <string name="hour_ampm" msgid="4329881288269772723">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
- <string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"清除"</string>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"沒有通知"</string>
- <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"進行中"</string>
- <string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <string name="battery_status_text_percent_format" msgid="7660311274698797147">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="battery_status_charging" msgid="756617993998772213">"充電中"</string>
- <string name="battery_low_title" msgid="7923774589611311406">"請連接充電器"</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"電池電é‡å³å°‡ä¸è¶³ï¼š"</string>
- <string name="battery_low_percent_format" msgid="6564958083485073855">"電池電é‡ä¸åˆ° <xliff:g id="NUMBER">%d%%</xliff:g>。"</string>
- <string name="battery_low_why" msgid="7655196144309694753">"原因"</string>
- <string name="factorytest_failed" msgid="5410270329114212041">"出廠測試失敗"</string>
- <string name="factorytest_not_system" msgid="4435201656767276723">"åªæœ‰å®‰è£åœ¨ /system/app 裡的程å¼æ‰èƒ½æ”¯æ´ FACTORY_TEST æ“作。"</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"找ä¸åˆ°æä¾› FACTORY_TEST 的程å¼ã€‚"</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"é‡æ–°é–‹æ©Ÿ"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"「<xliff:g id="TITLE">%s</xliff:g>ã€çš„網é æŒ‡å‡ºï¼š"</string>
- <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="1901675448179653089">"離開此é ï¼Ÿ"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" é¸å– [確定] 離開此é ï¼›æˆ– [å–消] 留在此é ã€‚"</string>
- <string name="save_password_label" msgid="6860261758665825069">"確èª"</string>
- <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"讀å–ç€è¦½å™¨çš„記錄與書籤"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"å…許應用程å¼è®€å–ç€è¦½å™¨æ›¾ç¶“造訪éŽçš„所有網å€ï¼Œä»¥åŠç€è¦½å™¨çš„所有書籤。"</string>
- <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"寫入ç€è¦½å™¨çš„記錄與書籤"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"å…許應用程å¼ä¿®æ”¹å„²å­˜åœ¨é›»è©±ä¸Šçš„ç€è¦½è¨˜éŒ„或書籤。請注æ„:惡æ„應用程å¼å¯èƒ½æœƒä½¿ç”¨æ­¤é¸é …來清除或修改您ç€è¦½å™¨çš„資料。"</string>
- <string name="save_password_message" msgid="767344687139195790">"是å¦è¨˜æ†¶æ­¤å¯†ç¢¼ï¼Ÿ"</string>
- <string name="save_password_notnow" msgid="6389675316706699758">"ç¾åœ¨ä¸è¦"</string>
- <string name="save_password_remember" msgid="6491879678996749466">"記ä½"</string>
- <string name="save_password_never" msgid="8274330296785855105">"從ä¸"</string>
- <string name="open_permission_deny" msgid="5661861460947222274">"您沒有開啟此é çš„權é™ã€‚"</string>
- <string name="text_copied" msgid="4985729524670131385">"文字已複製到剪貼簿。"</string>
- <string name="more_item_label" msgid="4650918923083320495">"更多"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"[Menu] +"</string>
- <string name="menu_space_shortcut_label" msgid="2410328639272162537">"空白éµ"</string>
- <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"輸入"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"刪除"</string>
- <string name="search_go" msgid="8298016669822141719">"æœå°‹"</string>
- <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 個月以å‰"</string>
- <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月å‰"</string>
+ <string name="keyguard_password_enter_pin_code">"輸入 PIN 碼"</string>
+ <string name="keyguard_password_wrong_pin_code">"PIN 碼錯誤ï¼"</string>
+ <string name="keyguard_label_text">"如è¦è§£éŽ–,請按 Menu éµï¼Œç„¶å¾ŒæŒ‰ 0。"</string>
+ <string name="emergency_call_dialog_number_for_display">"緊急電話號碼"</string>
+ <string name="lockscreen_carrier_default">"(沒有æœå‹™)"</string>
+ <string name="lockscreen_screen_locked">"螢幕已鎖定。"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"按下 [é¸å–®] 解鎖或撥打緊急電話。"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"按下 Menu éµè§£éŽ–。"</string>
+ <string name="lockscreen_pattern_instructions">"畫出解鎖圖形"</string>
+ <string name="lockscreen_emergency_call">"緊急電話"</string>
+ <string name="lockscreen_pattern_correct">"正確ï¼"</string>
+ <string name="lockscreen_pattern_wrong">"很抱歉,請å†è©¦ä¸€æ¬¡"</string>
+ <string name="lockscreen_plugged_in">"正在充電 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_charged (4938930459620989972) -->
+ <skip />
+ <string name="lockscreen_low_battery">"請連接充電器。"</string>
+ <string name="lockscreen_missing_sim_message_short">"沒有 SIM å¡ã€‚"</string>
+ <string name="lockscreen_missing_sim_message">"手機未æ’å…¥ SIM å¡ã€‚"</string>
+ <string name="lockscreen_missing_sim_instructions">"è«‹æ’å…¥ SIM å¡ã€‚"</string>
+ <string name="lockscreen_network_locked_message">"網路已鎖定"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM 的 PUK 已鎖定。"</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"è«‹åƒé–±ã€Šä½¿ç”¨è€…指å—》或è¯çµ¡å®¢æˆ¶æœå‹™ä¸­å¿ƒã€‚"</string>
+ <string name="lockscreen_sim_locked_message">"SIM å¡å·²éŽ–定。"</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"解鎖 SIM å¡ä¸­..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\n\n" 請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後å†å˜—試。"</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。å†éŒ¯èª¤ <xliff:g id="NUMBER_1">%d</xliff:g> 次後,系統會è¦æ±‚使用 Google 登入來解鎖。"\n\n" 請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後å†è©¦ä¸€æ¬¡ã€‚"</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g> 秒後å†è©¦ä¸€æ¬¡ã€‚"</string>
+ <string name="lockscreen_forgot_pattern_button_text">"忘記解鎖圖形?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"解鎖圖形出錯次數éŽå¤šï¼"</string>
+ <string name="lockscreen_glogin_instructions">"如è¦è§£é™¤éŽ–定,請使用 Google 帳戶登入"</string>
+ <string name="lockscreen_glogin_username_hint">"使用者å稱 (é›»å­éƒµä»¶)"</string>
+ <string name="lockscreen_glogin_password_hint">"密碼"</string>
+ <string name="lockscreen_glogin_submit_button">"登入"</string>
+ <string name="lockscreen_glogin_invalid_input">"使用者å稱或密碼錯誤。"</string>
+ <string name="hour_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for status_bar_clear_all_button (7774721344716731603) -->
+ <skip />
+ <string name="status_bar_no_notifications_title">"沒有通知"</string>
+ <string name="status_bar_ongoing_events_title">"進行中"</string>
+ <string name="status_bar_latest_events_title">"通知"</string>
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="battery_status_charging">"充電中"</string>
+ <string name="battery_low_title">"請連接充電器"</string>
+ <string name="battery_low_subtitle">"電池電é‡å³å°‡ä¸è¶³ï¼š"</string>
+ <string name="battery_low_percent_format">"電池電é‡ä¸åˆ° <xliff:g id="NUMBER">%d%%</xliff:g>。"</string>
+ <string name="battery_low_why">"原因"</string>
+ <string name="factorytest_failed">"出廠測試失敗"</string>
+ <string name="factorytest_not_system">"åªæœ‰å®‰è£åœ¨ /system/app 裡的程å¼æ‰èƒ½æ”¯æ´ FACTORY_TEST æ“作。"</string>
+ <string name="factorytest_no_action">"找ä¸åˆ°æä¾› FACTORY_TEST 的程å¼ã€‚"</string>
+ <string name="factorytest_reboot">"é‡æ–°é–‹æ©Ÿ"</string>
+ <string name="js_dialog_title">"「<xliff:g id="TITLE">%s</xliff:g>ã€çš„網é æŒ‡å‡ºï¼š"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"離開此é ï¼Ÿ"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" é¸å– [確定] 離開此é ï¼›æˆ– [å–消] 留在此é ã€‚"</string>
+ <string name="save_password_label">"確èª"</string>
+ <string name="permlab_readHistoryBookmarks">"讀å–ç€è¦½å™¨çš„記錄與書籤"</string>
+ <string name="permdesc_readHistoryBookmarks">"å…許應用程å¼è®€å–ç€è¦½å™¨æ›¾ç¶“造訪éŽçš„所有網å€ï¼Œä»¥åŠç€è¦½å™¨çš„所有書籤。"</string>
+ <string name="permlab_writeHistoryBookmarks">"寫入ç€è¦½å™¨çš„記錄與書籤"</string>
+ <string name="permdesc_writeHistoryBookmarks">"å…許應用程å¼ä¿®æ”¹å„²å­˜åœ¨é›»è©±ä¸Šçš„ç€è¦½è¨˜éŒ„或書籤。請注æ„:惡æ„應用程å¼å¯èƒ½æœƒä½¿ç”¨æ­¤é¸é …來清除或修改您ç€è¦½å™¨çš„資料。"</string>
+ <string name="save_password_message">"是å¦è¨˜æ†¶æ­¤å¯†ç¢¼ï¼Ÿ"</string>
+ <string name="save_password_notnow">"ç¾åœ¨ä¸è¦"</string>
+ <string name="save_password_remember">"記ä½"</string>
+ <string name="save_password_never">"從ä¸"</string>
+ <string name="open_permission_deny">"您沒有開啟此é çš„權é™ã€‚"</string>
+ <string name="text_copied">"文字已複製到剪貼簿。"</string>
+ <string name="more_item_label">"更多"</string>
+ <string name="prepend_shortcut_label">"[é¸å–®] +"</string>
+ <string name="menu_space_shortcut_label">"空白éµ"</string>
+ <string name="menu_enter_shortcut_label">"輸入"</string>
+ <string name="menu_delete_shortcut_label">"刪除"</string>
+ <string name="search_go">"æœå°‹"</string>
+ <string name="oneMonthDurationPast">"1 個月以å‰"</string>
+ <string name="beforeOneMonthDurationPast">"1 個月å‰"</string>
<plurals name="num_seconds_ago">
- <item quantity="one" msgid="4869870056547896011">"1 秒以å‰"</item>
- <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒以å‰"</item>
+ <item quantity="one">"1 秒以å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒以å‰"</item>
</plurals>
<plurals name="num_minutes_ago">
- <item quantity="one" msgid="3306787433088810191">"1 分é˜ä»¥å‰"</item>
- <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分é˜ä»¥å‰"</item>
+ <item quantity="one">"1 分é˜ä»¥å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分é˜ä»¥å‰"</item>
</plurals>
<plurals name="num_hours_ago">
- <item quantity="one" msgid="9150797944610821849">"1 å°æ™‚以å‰"</item>
- <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> å°æ™‚以å‰"</item>
+ <item quantity="one">"1 å°æ™‚以å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> å°æ™‚以å‰"</item>
</plurals>
<plurals name="num_days_ago">
- <item quantity="one" msgid="861358534398115820">"昨天"</item>
- <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天以å‰"</item>
+ <item quantity="one">"昨天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天以å‰"</item>
</plurals>
<plurals name="in_num_seconds">
- <item quantity="one" msgid="2729745560954905102">"1 秒內"</item>
- <item quantity="other" msgid="1241926116443974687">"在 <xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
+ <item quantity="one">"1 秒內"</item>
+ <item quantity="other">"在 <xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
</plurals>
<plurals name="in_num_minutes">
- <item quantity="one" msgid="8793095251325200395">"1 分é˜å…§"</item>
- <item quantity="other" msgid="3330713936399448749">"在 <xliff:g id="COUNT">%d</xliff:g> 分é˜å…§"</item>
+ <item quantity="one">"1 分é˜å…§"</item>
+ <item quantity="other">"在 <xliff:g id="COUNT">%d</xliff:g> 分é˜å…§"</item>
</plurals>
<plurals name="in_num_hours">
- <item quantity="one" msgid="7164353342477769999">"1 å°æ™‚å…§"</item>
- <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> å°æ™‚å…§"</item>
+ <item quantity="one">"1 å°æ™‚å…§"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> å°æ™‚å…§"</item>
</plurals>
<plurals name="in_num_days">
- <item quantity="one" msgid="5413088743009839518">"明天"</item>
- <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
+ <item quantity="one">"明天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
- <item quantity="one" msgid="1849036840200069118">"1 秒以å‰"</item>
- <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> 秒以å‰"</item>
+ <item quantity="one">"1 秒以å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒以å‰"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
- <item quantity="one" msgid="6361490147113871545">"1 分é˜ä»¥å‰"</item>
- <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> 分é˜ä»¥å‰"</item>
+ <item quantity="one">"1 分é˜ä»¥å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分é˜ä»¥å‰"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
- <item quantity="one" msgid="4796212039724722116">"1 å°æ™‚以å‰"</item>
- <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> å°æ™‚以å‰"</item>
+ <item quantity="one">"1 å°æ™‚以å‰"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> å°æ™‚以å‰"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
- <item quantity="one" msgid="8463161711492680309">"昨天"</item>
- <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天以å‰"</item>
+ <item quantity="one">"昨天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天以å‰"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
- <item quantity="one" msgid="5842225370795066299">"1 秒內"</item>
- <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
+ <item quantity="one">"1 秒內"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
- <item quantity="one" msgid="562786149928284878">"1 分é˜å…§"</item>
- <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> 分é˜å…§"</item>
+ <item quantity="one">"1 分é˜å…§"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分é˜å…§"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
- <item quantity="one" msgid="3274708118124045246">"1 å°æ™‚å…§"</item>
- <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> å°æ™‚å…§"</item>
+ <item quantity="one">"1 å°æ™‚å…§"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> å°æ™‚å…§"</item>
</plurals>
<plurals name="abbrev_in_num_days">
- <item quantity="one" msgid="2178576254385739855">"明天"</item>
- <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
+ <item quantity="one">"明天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
</plurals>
- <string name="preposition_for_date" msgid="4316283606614248634">"%s"</string>
- <string name="preposition_for_time" msgid="6179700075291054938">"%s"</string>
- <string name="preposition_for_year" msgid="3852279354896963571">"%s"</string>
- <string name="day" msgid="8144195776058119424">"天"</string>
- <string name="days" msgid="4774547661021344602">"天"</string>
- <string name="hour" msgid="2126771916426189481">"å°æ™‚"</string>
- <string name="hours" msgid="894424005266852993">"å°æ™‚"</string>
- <string name="minute" msgid="9148878657703769868">"分é˜"</string>
- <string name="minutes" msgid="5646001005827034509">"分é˜"</string>
- <string name="second" msgid="3184235808021478">"秒"</string>
- <string name="seconds" msgid="3161515347216589235">"秒"</string>
- <string name="week" msgid="5617961537173061583">"週"</string>
- <string name="weeks" msgid="6509623834583944518">"週"</string>
- <string name="year" msgid="4001118221013892076">"å¹´"</string>
- <string name="years" msgid="6881577717993213522">"å¹´"</string>
- <string name="every_weekday" msgid="8777593878457748503">"æ¯å¤© (週一至週五)"</string>
- <string name="daily" msgid="5738949095624133403">"æ¯å¤©"</string>
- <string name="weekly" msgid="983428358394268344">"æ¯é€±<xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly" msgid="2667202947170988834">"æ¯æœˆ"</string>
- <string name="yearly" msgid="1519577999407493836">"æ¯å¹´"</string>
- <string name="VideoView_error_title" msgid="3359437293118172396">"無法播放影片"</string>
- <string name="VideoView_error_text_invalid_progressive_playback" msgid="897920883624437033">"很抱歉,影片格å¼ç„¡æ•ˆï¼Œè£ç½®ç„¡æ³•é€²è¡Œä¸²æµè™•ç†ã€‚"</string>
- <string name="VideoView_error_text_unknown" msgid="710301040038083944">"很抱歉,此影片無法播放。"</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"確定"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>,<xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="noon" msgid="7245353528818587908">"中åˆ"</string>
- <string name="Noon" msgid="3342127745230013127">"中åˆ"</string>
- <string name="midnight" msgid="7166259508850457595">"åˆå¤œ"</string>
- <string name="Midnight" msgid="5630806906897892201">"åˆå¤œ"</string>
- <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
- <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"全部é¸å–"</string>
- <string name="selectText" msgid="3889149123626888637">"é¸å–文字"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"åœæ­¢é¸å–文字"</string>
- <string name="cut" msgid="3092569408438626261">"剪下"</string>
- <string name="cutAll" msgid="2436383270024931639">"全部剪下"</string>
- <string name="copy" msgid="2681946229533511987">"複製"</string>
- <string name="copyAll" msgid="2590829068100113057">"全部複製"</string>
- <string name="paste" msgid="5629880836805036433">"貼上"</string>
- <string name="copyUrl" msgid="2538211579596067402">"複製網å€"</string>
- <string name="inputMethod" msgid="7673923508389094672">"輸入法"</string>
- <string name="addToDictionary" msgid="726256909274177272">"將「%sã€æ–°å¢žåˆ°å­—å…¸"</string>
- <string name="editTextMenuTitle" msgid="1672989176958581452">"編輯文字"</string>
- <string name="low_internal_storage_view_title" msgid="1399732408701697546">"儲存空間å³å°‡ä¸è¶³"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"手機儲存空間å³å°‡ä¸è¶³ã€‚"</string>
- <string name="ok" msgid="5970060430562524910">"確定"</string>
- <string name="cancel" msgid="6442560571259935130">"å–消"</string>
- <string name="yes" msgid="5362982303337969312">"確定"</string>
- <string name="no" msgid="5141531044935541497">"å–消"</string>
- <string name="dialog_alert_title" msgid="2049658708609043103">"請注æ„"</string>
- <string name="capital_on" msgid="1544682755514494298">"é–‹å•Ÿ"</string>
- <string name="capital_off" msgid="6815870386972805832">"關閉"</string>
- <string name="whichApplication" msgid="4533185947064773386">"完æˆæ“作需使用"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"以此為本æ“作é è¨­å€¼ã€‚"</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"清除首é è¨­å®š (應用程å¼) 管ç†æ‡‰ç”¨ç¨‹å¼çš„é è¨­å€¼ã€‚"</string>
- <string name="chooseActivity" msgid="1009246475582238425">"é¸å–一項æ“作"</string>
- <string name="noApplications" msgid="1691104391758345586">"沒有應用程å¼å¯åŸ·è¡Œæ­¤é …æ“作。"</string>
- <string name="aerr_title" msgid="653922989522758100">"很抱歉ï¼"</string>
- <string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> æ‡‰ç”¨ç¨‹å¼ (程åºï¼š<xliff:g id="PROCESS">%2$s</xliff:g>) 異常終止。請å†è©¦ä¸€æ¬¡ã€‚"</string>
- <string name="aerr_process" msgid="1551785535966089511">"<xliff:g id="PROCESS">%1$s</xliff:g> 異常終止。請å†è©¦ä¸€æ¬¡ã€‚"</string>
- <string name="anr_title" msgid="3100070910664756057">"很抱歉ï¼"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"<xliff:g id="ACTIVITY">%1$s</xliff:g> (應用程å¼ï¼š<xliff:g id="APPLICATION">%2$s</xliff:g>) 無回應。"</string>
- <string name="anr_activity_process" msgid="5420826626009561014">"<xliff:g id="ACTIVITY">%1$s</xliff:g> (程åºï¼š<xliff:g id="PROCESS">%2$s</xliff:g>) 無回應。"</string>
- <string name="anr_application_process" msgid="4185842666452210193">"æ‡‰ç”¨ç¨‹å¼ <xliff:g id="APPLICATION">%1$s</xliff:g> (程åºï¼š<xliff:g id="PROCESS">%2$s</xliff:g>) 無回應。"</string>
- <string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> 程åºç„¡å›žæ‡‰ã€‚"</string>
- <string name="force_close" msgid="3653416315450806396">"強制關閉"</string>
- <string name="report" msgid="4060218260984795706">"回報"</string>
- <string name="wait" msgid="7147118217226317732">"等待"</string>
- <string name="debug" msgid="9103374629678531849">"åµéŒ¯"</string>
- <string name="sendText" msgid="5132506121645618310">"訊æ¯å‚³é€æ–¹å¼"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"鈴è²éŸ³é‡"</string>
- <string name="volume_music" msgid="5421651157138628171">"媒體音é‡"</string>
- <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"é€éŽè—牙播放"</string>
- <string name="volume_call" msgid="3941680041282788711">"來電音é‡"</string>
- <string name="volume_bluetooth_call" msgid="2002891926351151534">"è—牙通話音é‡"</string>
- <string name="volume_alarm" msgid="1985191616042689100">"鬧é˜éŸ³é‡"</string>
- <string name="volume_notification" msgid="2422265656744276715">"通知音é‡"</string>
- <string name="volume_unknown" msgid="1400219669770445902">"音é‡"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"é è¨­éˆ´è²"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"é è¨­éˆ´è² (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="4440324407807468713">"éœéŸ³"</string>
- <string name="ringtone_picker_title" msgid="3515143939175119094">"鈴è²"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"未知的鈴è²"</string>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"%s"</string>
+ <string name="day">"天"</string>
+ <string name="days">"天"</string>
+ <string name="hour">"å°æ™‚"</string>
+ <string name="hours">"å°æ™‚"</string>
+ <string name="minute">"分é˜"</string>
+ <string name="minutes">"分é˜"</string>
+ <string name="second">"秒"</string>
+ <string name="seconds">"秒"</string>
+ <string name="week">"週"</string>
+ <string name="weeks">"週"</string>
+ <string name="year">"å¹´"</string>
+ <string name="years">"å¹´"</string>
+ <string name="every_weekday">"æ¯å¤© (週一至週五)"</string>
+ <string name="daily">"æ¯å¤©"</string>
+ <string name="weekly">"æ¯é€±<xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"æ¯æœˆ"</string>
+ <string name="yearly">"æ¯å¹´"</string>
+ <string name="VideoView_error_title">"無法播放影片"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback">"很抱歉,影片格å¼ç„¡æ•ˆï¼Œè£ç½®ç„¡æ³•é€²è¡Œä¸²æµè™•ç†ã€‚"</string>
+ <string name="VideoView_error_text_unknown">"很抱歉,此影片無法播放。"</string>
+ <string name="VideoView_error_button">"確定"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>,<xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon">"中åˆ"</string>
+ <string name="Noon">"中åˆ"</string>
+ <string name="midnight">"åˆå¤œ"</string>
+ <string name="Midnight">"åˆå¤œ"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"全部é¸å–"</string>
+ <string name="selectText">"é¸å–文字"</string>
+ <string name="stopSelectingText">"åœæ­¢é¸å–文字"</string>
+ <string name="cut">"剪下"</string>
+ <string name="cutAll">"全部剪下"</string>
+ <string name="copy">"複製"</string>
+ <string name="copyAll">"全部複製"</string>
+ <string name="paste">"貼上"</string>
+ <string name="copyUrl">"複製網å€"</string>
+ <string name="inputMethod">"輸入法"</string>
+ <string name="addToDictionary">"將「%sã€æ–°å¢žåˆ°å­—å…¸"</string>
+ <string name="editTextMenuTitle">"編輯文字"</string>
+ <string name="low_internal_storage_view_title">"儲存空間å³å°‡ä¸è¶³"</string>
+ <string name="low_internal_storage_view_text">"手機儲存空間å³å°‡ä¸è¶³ã€‚"</string>
+ <string name="ok">"確定"</string>
+ <string name="cancel">"å–消"</string>
+ <string name="yes">"確定"</string>
+ <string name="no">"å–消"</string>
+ <string name="dialog_alert_title">"請注æ„"</string>
+ <string name="capital_on">"é–‹å•Ÿ"</string>
+ <string name="capital_off">"關閉"</string>
+ <string name="whichApplication">"完æˆæ“作需使用"</string>
+ <string name="alwaysUse">"以此為本æ“作é è¨­å€¼ã€‚"</string>
+ <string name="clearDefaultHintMsg">"清除首é è¨­å®š (應用程å¼) 管ç†æ‡‰ç”¨ç¨‹å¼çš„é è¨­å€¼ã€‚"</string>
+ <string name="chooseActivity">"é¸å–一項æ“作"</string>
+ <string name="noApplications">"沒有應用程å¼å¯åŸ·è¡Œæ­¤é …æ“作。"</string>
+ <string name="aerr_title">"很抱歉ï¼"</string>
+ <string name="aerr_application">"<xliff:g id="APPLICATION">%1$s</xliff:g> æ‡‰ç”¨ç¨‹å¼ (程åºï¼š<xliff:g id="PROCESS">%2$s</xliff:g>) 異常終止。請å†è©¦ä¸€æ¬¡ã€‚"</string>
+ <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> 異常終止。請å†è©¦ä¸€æ¬¡ã€‚"</string>
+ <string name="anr_title">"很抱歉ï¼"</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g> (應用程å¼ï¼š<xliff:g id="APPLICATION">%2$s</xliff:g>) 無回應。"</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g> (程åºï¼š<xliff:g id="PROCESS">%2$s</xliff:g>) 無回應。"</string>
+ <string name="anr_application_process">"æ‡‰ç”¨ç¨‹å¼ <xliff:g id="APPLICATION">%1$s</xliff:g> (程åºï¼š<xliff:g id="PROCESS">%2$s</xliff:g>) 無回應。"</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> 程åºç„¡å›žæ‡‰ã€‚"</string>
+ <string name="force_close">"強制關閉"</string>
+ <string name="report">"回報"</string>
+ <string name="wait">"等待"</string>
+ <string name="debug">"åµéŒ¯"</string>
+ <string name="sendText">"訊æ¯å‚³é€æ–¹å¼"</string>
+ <string name="volume_ringtone">"鈴è²éŸ³é‡"</string>
+ <string name="volume_music">"媒體音é‡"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"é€éŽè—牙播放"</string>
+ <string name="volume_call">"來電音é‡"</string>
+ <string name="volume_bluetooth_call">"è—牙通話音é‡"</string>
+ <string name="volume_alarm">"鬧é˜éŸ³é‡"</string>
+ <string name="volume_notification">"通知音é‡"</string>
+ <string name="volume_unknown">"音é‡"</string>
+ <string name="ringtone_default">"é è¨­éˆ´è²"</string>
+ <string name="ringtone_default_with_actual">"é è¨­éˆ´è² (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"éœéŸ³"</string>
+ <string name="ringtone_picker_title">"鈴è²"</string>
+ <string name="ringtone_unknown">"未知的鈴è²"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"å·²åµæ¸¬åˆ° Wi-Fi 網路"</item>
- <item quantity="other" msgid="4192424489168397386">"å·²åµæ¸¬åˆ° Wi-Fi 網路"</item>
+ <item quantity="one">"å·²åµæ¸¬åˆ° Wi-Fi 網路"</item>
+ <item quantity="other">"å·²åµæ¸¬åˆ° Wi-Fi 網路"</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one" msgid="1634101450343277345">"é–‹å•Ÿå¯ç”¨ Wi-Fi 網路"</item>
- <item quantity="other" msgid="7915895323644292768">"é–‹å•Ÿå¯ç”¨ Wi-Fi 網路"</item>
+ <item quantity="one">"é–‹å•Ÿå¯ç”¨ Wi-Fi 網路"</item>
+ <item quantity="other">"é–‹å•Ÿå¯ç”¨ Wi-Fi 網路"</item>
</plurals>
- <string name="select_character" msgid="3365550120617701745">"æ’入字元"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"未知的應用程å¼"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"å‚³é€ SMS 簡訊"</string>
- <string name="sms_control_message" msgid="1289331457999236205">"å³å°‡å‚³é€å¤§é‡ SMS 簡訊。é¸å– [確定] 繼續或 [å–消] åœæ­¢å‚³é€ã€‚"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"確定"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"å–消"</string>
- <string name="date_time_set" msgid="5777075614321087758">"設定"</string>
- <string name="default_permission_group" msgid="2690160991405646128">"é è¨­å€¼"</string>
- <string name="no_permissions" msgid="7283357728219338112">"無須許å¯"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>" éš±è—"</b></string>
- <string name="perms_show_all" msgid="2671791163933091180"><b>"顯示全部"</b></string>
- <string name="googlewebcontenthelper_loading" msgid="4722128368651947186">"載入中..."</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"USB 已連接"</string>
- <string name="usb_storage_message" msgid="2759542180575016871">"å·²é€éŽ USB 連接手機與電腦。如è¦å¾žé›»è…¦æˆ– SD å¡è¤‡è£½æª”案,請é¸å– [掛載]。"</string>
- <string name="usb_storage_button_mount" msgid="8063426289195405456">"掛載"</string>
- <string name="usb_storage_button_unmount" msgid="6092146330053864766">"ä¸è¦æŽ›è¼‰"</string>
- <string name="usb_storage_error_message" msgid="2534784751603345363">"把 SD å¡ç•¶æˆ USB 儲存è£ç½®æ™‚發生å•é¡Œã€‚"</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB 已連接"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"é¸å–此項將檔案複製到電腦,或從電腦複製。"</string>
- <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"關閉 USB 儲存è£ç½®"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"é¸å–此處關閉 USB 儲存è£ç½®ã€‚"</string>
- <string name="usb_storage_stop_title" msgid="6014127947456185321">"關閉 USB 儲存è£ç½®"</string>
- <string name="usb_storage_stop_message" msgid="2390958966725232848">"關閉 USB 儲存è£ç½®ä¹‹å‰ï¼Œè«‹ç¢ºå®šå…ˆå¾ž USB Host å¸è¼‰ã€‚é¸å– [關閉] å³å¯é—œé–‰ USB 儲存è£ç½®ã€‚"</string>
- <string name="usb_storage_stop_button_mount" msgid="1181858854166273345">"關閉"</string>
- <string name="usb_storage_stop_button_unmount" msgid="3774611918660582898">"å–消"</string>
- <string name="usb_storage_stop_error_message" msgid="3917317248440072084">"關閉 USB 儲存è£ç½®æ™‚發生å•é¡Œã€‚請檢查確èªæ‚¨æ˜¯å¦å·²å¸è¼‰ USB Host,然後å†è©¦ä¸€æ¬¡ã€‚"</string>
- <string name="extmedia_format_title" msgid="8663247929551095854">"å°‡ SD å¡æ ¼å¼åŒ–"</string>
- <string name="extmedia_format_message" msgid="3621369962433523619">"確定è¦å°‡ SD å¡æ ¼å¼åŒ–嗎?該 SD å¡ä¸­çš„所有資料將會éºå¤±ã€‚"</string>
- <string name="extmedia_format_button_format" msgid="4131064560127478695">"æ ¼å¼åŒ–"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USB åµéŒ¯æ¨¡å¼å·²å•Ÿç”¨"</string>
- <string name="adb_active_notification_message" msgid="4661997077344501389">"您的手機已連接至電腦。"</string>
- <string name="select_input_method" msgid="2086499663193509436">"é¸å–輸入法"</string>
- <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style" msgid="4333913089637062257"><u>"å¾…é¸é …ç›®"</u></string>
- <string name="ext_media_checking_notification_title" msgid="5457603418970994050">"正在準備 SD å¡"</string>
- <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"正在檢查錯誤。"</string>
- <string name="ext_media_nofs_notification_title" msgid="780477838241212997">"SD å¡ç‚ºç©ºç™½"</string>
- <string name="ext_media_nofs_notification_message" msgid="3817704088027829380">"SD å¡å…§ç„¡æª”案系統,或檔案系統ä¸å—支æ´ã€‚"</string>
- <string name="ext_media_unmountable_notification_title" msgid="6410723906019100189">"SD å¡å·²æ壞"</string>
- <string name="ext_media_unmountable_notification_message" msgid="6902531775948238989">"SD å¡å·²æ¯€æ,您å¯èƒ½å¿…須予以é‡æ–°æ ¼å¼åŒ–。"</string>
- <string name="ext_media_badremoval_notification_title" msgid="6872152882604407837">"SD å¡æœªæ­£å¸¸ç§»é™¤"</string>
- <string name="ext_media_badremoval_notification_message" msgid="7260183293747448241">"è«‹å…ˆå¸è¼‰ SD å¡ï¼Œå†å°‡å…¶ç§»é™¤ï¼Œä»¥å…資料éºå¤±ã€‚"</string>
- <string name="ext_media_safe_unmount_notification_title" msgid="6729801130790616200">"å¯å®‰å…¨ç§»é™¤ SD å¡"</string>
- <string name="ext_media_safe_unmount_notification_message" msgid="568841278138377604">"您ç¾åœ¨å¯ä»¥å®‰å…¨åœ°ç§»é™¤ SD å¡ã€‚"</string>
- <string name="ext_media_nomedia_notification_title" msgid="8902518030404381318">"已移除 SD å¡"</string>
- <string name="ext_media_nomedia_notification_message" msgid="3870120652983659641">"SD å¡å·²ç§»é™¤ï¼Œè«‹æ’入新的 SD å¡ã€‚"</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"找ä¸åˆ°ç¬¦åˆçš„活動"</string>
- <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"更新元件使用統計資料"</string>
- <string name="permdesc_pkgUsageStats" msgid="891553695716752835">"å…許修改收集到的元件使用統計資料。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
- <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"點兩下以進行縮放控制"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"擴大å°å·¥å…·æ™‚發生錯誤"</string>
- <string name="ime_action_go" msgid="8320845651737369027">"開始"</string>
- <string name="ime_action_search" msgid="658110271822807811">"æœå°‹"</string>
- <string name="ime_action_send" msgid="2316166556349314424">"傳é€"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"下一步"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"完æˆ"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"執行"</string>
- <string name="dial_number_using" msgid="5789176425167573586">"使用 <xliff:g id="NUMBER">%s</xliff:g>"\n"撥號"</string>
- <string name="create_contact_using" msgid="4947405226788104538">"建立手機號碼為 <xliff:g id="NUMBER">%s</xliff:g>"\n"çš„è¯çµ¡äºº"</string>
- <string name="accessibility_compound_button_selected" msgid="5612776946036285686">"已勾é¸"</string>
- <string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"未勾é¸"</string>
+ <string name="select_character">"æ’入字元"</string>
+ <string name="sms_control_default_app_name">"未知的應用程å¼"</string>
+ <string name="sms_control_title">"å‚³é€ SMS 簡訊"</string>
+ <string name="sms_control_message">"å³å°‡å‚³é€å¤§é‡ SMS 簡訊。é¸å– [確定] 繼續或 [å–消] åœæ­¢å‚³é€ã€‚"</string>
+ <string name="sms_control_yes">"確定"</string>
+ <string name="sms_control_no">"å–消"</string>
+ <string name="date_time_set">"設定"</string>
+ <string name="default_permission_group">"é è¨­å€¼"</string>
+ <string name="no_permissions">"無須許å¯"</string>
+ <string name="perms_hide"><b>" éš±è—"</b></string>
+ <string name="perms_show_all"><b>"顯示全部"</b></string>
+ <string name="googlewebcontenthelper_loading">"載入中..."</string>
+ <string name="usb_storage_title">"USB 已連接"</string>
+ <string name="usb_storage_message">"å·²é€éŽ USB 連接手機與電腦。如è¦å¾žé›»è…¦æˆ– SD å¡è¤‡è£½æª”案,請é¸å– [掛載]。"</string>
+ <string name="usb_storage_button_mount">"掛載"</string>
+ <string name="usb_storage_button_unmount">"ä¸è¦æŽ›è¼‰"</string>
+ <string name="usb_storage_error_message">"把 SD å¡ç•¶æˆ USB 儲存è£ç½®æ™‚發生å•é¡Œã€‚"</string>
+ <string name="usb_storage_notification_title">"USB 已連接"</string>
+ <string name="usb_storage_notification_message">"é¸å–此項將檔案複製到電腦,或從電腦複製。"</string>
+ <string name="usb_storage_stop_notification_title">"關閉 USB 儲存è£ç½®"</string>
+ <string name="usb_storage_stop_notification_message">"é¸å–此處關閉 USB 儲存è£ç½®ã€‚"</string>
+ <string name="usb_storage_stop_title">"關閉 USB 儲存è£ç½®"</string>
+ <string name="usb_storage_stop_message">"關閉 USB 儲存è£ç½®ä¹‹å‰ï¼Œè«‹ç¢ºå®šå…ˆå¾ž USB Host å¸è¼‰ã€‚é¸å– [關閉] å³å¯é—œé–‰ USB 儲存è£ç½®ã€‚"</string>
+ <string name="usb_storage_stop_button_mount">"關閉"</string>
+ <string name="usb_storage_stop_button_unmount">"å–消"</string>
+ <string name="usb_storage_stop_error_message">"關閉 USB 儲存è£ç½®æ™‚發生å•é¡Œã€‚請檢查確èªæ‚¨æ˜¯å¦å·²å¸è¼‰ USB Host,然後å†è©¦ä¸€æ¬¡ã€‚"</string>
+ <string name="extmedia_format_title">"å°‡ SD å¡æ ¼å¼åŒ–"</string>
+ <string name="extmedia_format_message">"確定è¦å°‡ SD å¡æ ¼å¼åŒ–嗎?該 SD å¡ä¸­çš„所有資料將會éºå¤±ã€‚"</string>
+ <string name="extmedia_format_button_format">"æ ¼å¼åŒ–"</string>
+ <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+ <skip />
+ <!-- no translation found for adb_active_notification_message (4661997077344501389) -->
+ <skip />
+ <string name="select_input_method">"é¸å–輸入法"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"å¾…é¸é …ç›®"</u></string>
+ <string name="ext_media_checking_notification_title">"正在準備 SD å¡"</string>
+ <string name="ext_media_checking_notification_message">"正在檢查錯誤。"</string>
+ <string name="ext_media_nofs_notification_title">"SD å¡ç‚ºç©ºç™½"</string>
+ <string name="ext_media_nofs_notification_message">"SD å¡å…§ç„¡æª”案系統,或檔案系統ä¸å—支æ´ã€‚"</string>
+ <string name="ext_media_unmountable_notification_title">"SD å¡å·²æ壞"</string>
+ <string name="ext_media_unmountable_notification_message">"SD å¡å·²æ¯€æ,您å¯èƒ½å¿…須予以é‡æ–°æ ¼å¼åŒ–。"</string>
+ <string name="ext_media_badremoval_notification_title">"SD å¡æœªæ­£å¸¸ç§»é™¤"</string>
+ <string name="ext_media_badremoval_notification_message">"è«‹å…ˆå¸è¼‰ SD å¡ï¼Œå†å°‡å…¶ç§»é™¤ï¼Œä»¥å…資料éºå¤±ã€‚"</string>
+ <string name="ext_media_safe_unmount_notification_title">"å¯å®‰å…¨ç§»é™¤ SD å¡"</string>
+ <string name="ext_media_safe_unmount_notification_message">"您ç¾åœ¨å¯ä»¥å®‰å…¨åœ°ç§»é™¤ SD å¡ã€‚"</string>
+ <string name="ext_media_nomedia_notification_title">"已移除 SD å¡"</string>
+ <string name="ext_media_nomedia_notification_message">"SD å¡å·²ç§»é™¤ï¼Œè«‹æ’入新的 SD å¡ã€‚"</string>
+ <string name="activity_list_empty">"找ä¸åˆ°ç¬¦åˆçš„活動"</string>
+ <string name="permlab_pkgUsageStats">"更新元件使用統計資料"</string>
+ <string name="permdesc_pkgUsageStats">"å…許修改收集到的元件使用統計資料。一般應用程å¼ä¸æœƒä½¿ç”¨æ­¤åŠŸèƒ½ã€‚"</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"點兩下以進行縮放控制"</string>
+ <string name="gadget_host_error_inflating">"擴大å°å·¥å…·æ™‚發生錯誤"</string>
+ <string name="ime_action_go">"開始"</string>
+ <string name="ime_action_search">"æœå°‹"</string>
+ <string name="ime_action_send">"傳é€"</string>
+ <string name="ime_action_next">"下一步"</string>
+ <string name="ime_action_done">"完æˆ"</string>
+ <string name="ime_action_default">"執行"</string>
+ <string name="dial_number_using">"使用 <xliff:g id="NUMBER">%s</xliff:g>"\n"撥號"</string>
+ <string name="create_contact_using">"建立手機號碼為 <xliff:g id="NUMBER">%s</xliff:g>"\n"çš„è¯çµ¡äºº"</string>
+ <string name="accessibility_compound_button_selected">"已勾é¸"</string>
+ <string name="accessibility_compound_button_unselected">"未勾é¸"</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index fd78f83..7e7bfca 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -215,6 +215,9 @@
<attr name="windowIsFloating" format="boolean" />
<!-- Flag indicating whether this is a translucent window. -->
<attr name="windowIsTranslucent" format="boolean" />
+ <!-- Flag indicating that this window's background should be the
+ user's current wallpaper. -->
+ <attr name="windowShowWallpaper" format="boolean" />
<!-- This Drawable is overlaid over the foreground of the Window's content area, usually
to place a shadow below the title. -->
<attr name="windowContentOverlay" format="reference" />
@@ -358,7 +361,7 @@
<!-- Small inverse ProgressBar style. This is a small circular progress bar. -->
<attr name="progressBarStyleSmallInverse" format="reference" />
<!-- Large inverse ProgressBar style. This is a large circular progress bar. -->
- <attr name="progressBarStyleLargeInverse" format="reference" />
+ <attr name="progressBarStyleLargeInverse" format="reference" />
<!-- Default SeekBar style. -->
<attr name="seekBarStyle" format="reference" />
<!-- Default RatingBar style. -->
@@ -598,7 +601,7 @@
<flag name="time" value="0x00000024" />
</attr>
- <!-- Additional features you can enable in an IME associated with an editor,
+ <!-- Additional features you can enable in an IME associated with an editor
to improve the integration with your application. The constants
here correspond to those defined by
{@link android.view.inputmethod.EditorInfo#imeOptions}. -->
@@ -682,7 +685,7 @@
<attr name="y" format="dimension" />
<!-- Specifies how to place the content of an object, both
- on the x and y axis, within the object itself. -->
+ on the x- and y-axis, within the object itself. -->
<attr name="gravity">
<!-- Push object to the top of its container, not changing its size. -->
<flag name="top" value="0x30" />
@@ -738,7 +741,7 @@
<attr name="entries" format="reference" />
<!-- Standard gravity constant that a child can supply to its parent.
- Defines how to place the view, both its x and y axis, within its parent view group. -->
+ Defines how to place the view, both its x- and y-axis, within its parent view group. -->
<attr name="layout_gravity">
<!-- Push object to the top of its container, not changing its size. -->
<flag name="top" value="0x30" />
@@ -900,6 +903,7 @@
<attr name="windowFullscreen" />
<attr name="windowIsFloating" />
<attr name="windowIsTranslucent" />
+ <attr name="windowShowWallpaper" />
<attr name="windowAnimationStyle" />
<attr name="windowSoftInputMode" />
<attr name="windowDisablePreview" />
@@ -933,18 +937,68 @@
<attr name="windowShowAnimation" format="reference" />
<!-- The animation used when a window is going from VISIBLE to INVISIBLE. -->
<attr name="windowHideAnimation" format="reference" />
+
+ <!-- When opening a new activity, this is the animation that is
+ run on the next activity (which is entering the screen). -->
<attr name="activityOpenEnterAnimation" format="reference" />
+ <!-- When opening a new activity, this is the animation that is
+ run on the previous activity (which is exiting the screen). -->
<attr name="activityOpenExitAnimation" format="reference" />
+ <!-- When closing the current activity, this is the animation that is
+ run on the next activity (which is entering the screen). -->
<attr name="activityCloseEnterAnimation" format="reference" />
+ <!-- When closing the current activity, this is the animation that is
+ run on the current activity (which is exiting the screen). -->
<attr name="activityCloseExitAnimation" format="reference" />
+ <!-- When opening an activity in a new task, this is the animation that is
+ run on the activity of the new task (which is entering the screen). -->
<attr name="taskOpenEnterAnimation" format="reference" />
+ <!-- When opening an activity in a new task, this is the animation that is
+ run on the activity of the old task (which is exiting the screen). -->
<attr name="taskOpenExitAnimation" format="reference" />
+ <!-- When closing the last activity of a task, this is the animation that is
+ run on the activity of the next task (which is entering the screen). -->
<attr name="taskCloseEnterAnimation" format="reference" />
+ <!-- When opening an activity in a new task, this is the animation that is
+ run on the activity of the old task (which is exiting the screen). -->
<attr name="taskCloseExitAnimation" format="reference" />
+ <!-- When bringing an existing task to the foreground, this is the
+ animation that is run on the top activity of the task being brought
+ to the foreground (which is entering the screen). -->
<attr name="taskToFrontEnterAnimation" format="reference" />
+ <!-- When bringing an existing task to the foreground, this is the
+ animation that is run on the current foreground activity
+ (which is exiting the screen). -->
<attr name="taskToFrontExitAnimation" format="reference" />
+ <!-- When sending the current task to the background, this is the
+ animation that is run on the top activity of the task behind
+ it (which is entering the screen). -->
<attr name="taskToBackEnterAnimation" format="reference" />
+ <!-- When sending the current task to the background, this is the
+ animation that is run on the top activity of the current task
+ (which is exiting the screen). -->
<attr name="taskToBackExitAnimation" format="reference" />
+
+ <!-- When opening a new activity that is on top of the wallpaper
+ when the current activity is also on top of the wallpaper,
+ this is the animation that is run on the new activity
+ (which is entering the screen). -->
+ <attr name="wallpaperActivityOpenEnterAnimation" format="reference" />
+ <!-- When opening a new activity that is on top of the wallpaper
+ when the current activity is also on top of the wallpaper,
+ this is the animation that is run on the current activity
+ (which is exiting the screen). -->
+ <attr name="wallpaperActivityOpenExitAnimation" format="reference" />
+ <!-- When closing a foreround activity that is on top of the wallpaper
+ when the previous activity is also on top of the wallpaper,
+ this is the animation that is run on the previous activity
+ (which is entering the screen). -->
+ <attr name="wallpaperActivityCloseEnterAnimation" format="reference" />
+ <!-- When closing a foreround activity that is on top of the wallpaper
+ when the previous activity is also on top of the wallpaper,
+ this is the animation that is run on the current activity
+ (which is exiting the screen). -->
+ <attr name="wallpaperActivityCloseExitAnimation" format="reference" />
</declare-styleable>
<!-- ============================= -->
@@ -1817,7 +1871,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
@@ -2220,6 +2274,10 @@
of the states. If false, the size will vary based on the
current state. -->
<attr name="constantSize" format="boolean" />
+ <!-- Enables or disables dithering of the bitmap if the bitmap does not have the
+ same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
+ an RGB 565 screen.) -->
+ <attr name="dither" format="boolean" />
</declare-styleable>
<declare-styleable name="AnimationDrawable">
@@ -2344,7 +2402,7 @@
<attr name="pivotY" />
<attr name="drawable" />
</declare-styleable>
-
+
<declare-styleable name="InsetDrawable">
<attr name="visible" />
<attr name="drawable" />
@@ -2366,7 +2424,7 @@
<!-- Enables or disables dithering of the bitmap if the bitmap does not have the
same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
an RGB 565 screen.) -->
- <attr name="dither" format="boolean" />
+ <attr name="dither" />
<!-- Defines the gravity for the bitmap. The gravity indicates where to position
the drawable in its container if the bitmap is smaller than the container. -->
<attr name="gravity" />
@@ -2882,7 +2940,6 @@
results for "bo", it would not be queried again for "bob".
The default value is <code>false</code>. <i>Optional attribute.</i>. -->
<attr name="queryAfterZeroResults" format="boolean" />
-
<!-- If provided, this string will be used to describe the searchable item in the
searchable items settings within system search settings. <i>Optional
attribute.</i> -->
@@ -3328,6 +3385,49 @@
<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"/>
+ <!-- the user-visible name of the authenticator. -->
+ <attr name="label"/>
+ <!-- the icon of the authenticator. -->
+ <attr name="icon"/>
+ </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"/>
+ <attr name="userVisible" format="boolean"/>
+ <attr name="supportsUploading" format="boolean"/>
+ </declare-styleable>
+
+ <!-- =============================== -->
+ <!-- Contacts meta-data attributes -->
+ <!-- =============================== -->
+
+ <declare-styleable name="Icon">
+ <attr name="icon" />
+ <attr name="mimeType" />
+ </declare-styleable>
+
+ <declare-styleable name="IconDefault">
+ <attr name="icon" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 442357e..ce421db 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -781,6 +781,15 @@
represent the minor number. For example for GL 1.2 referring to
0x00000102, the actual value should be set as 0x00010002. -->
<attr name="glEsVersion" format="integer"/>
+ <!-- The name of the feature that is being used. -->
+ <attr name="name" />
+ <!-- Specify whether this feature is required for the application.
+ The default is true, meaning the application requires the
+ feature, and does not want to be installed on devices that
+ don't support it. If you set this to false, then this will
+ not impose a restriction on where the application can be
+ installed. -->
+ <attr name="required" format="boolean" />
</declare-styleable>
<!-- The <code>uses-sdk</code> tag describes the SDK features that the
@@ -823,6 +832,14 @@
<declare-styleable name="AndroidManifestUsesLibrary" parent="AndroidManifestApplication">
<!-- Required name of the library you use. -->
<attr name="name" />
+ <!-- Specify whether this library is required for the application.
+ The default is true, meaning the application requires the
+ library, and does not want to be installed on devices that
+ don't support it. If you set this to false, then this will
+ allow the application to be installed even if the library
+ doesn't exist, and you will need to check for its presence
+ dynamically at runtime. -->
+ <attr name="required" />
</declare-styleable>
<!-- The <code>supports-screens</code> specifies the screen dimensions an
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 0fd6861..1057c09 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -19,7 +19,7 @@
-->
<resources>
<drawable name="screen_background_light">#fff9f9f9</drawable>
- <drawable name="screen_background_dark">#ff1a1a1a</drawable>
+ <drawable name="screen_background_dark">#ff202020</drawable>
<drawable name="status_bar_closed_default_background">#ff000000</drawable>
<drawable name="status_bar_opened_default_background">#ff000000</drawable>
<drawable name="search_bar_default_color">#ff000000</drawable>
@@ -28,7 +28,7 @@
<color name="white">#ffffffff</color>
<color name="black">#ff000000</color>
<color name="transparent">#00000000</color>
- <color name="background_dark">#ff1a1a1a</color>
+ <color name="background_dark">#ff202020</color>
<color name="bright_foreground_dark">#ffffffff</color>
<color name="bright_foreground_dark_disabled">#80ffffff</color>
<color name="bright_foreground_dark_inverse">#ff000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7215685..abb575c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -35,7 +35,50 @@
<!-- The duration (in milliseconds) of a long animation. -->
<integer name="config_longAnimTime">300</integer>
- <!-- Flag indicating whether Last Name comes before First Name.
- This becomes true in Japan, for example.-->
- <bool name="config_lastname_comes_before_firstname">false</bool>
+ <!-- This string array should be overridden by the device to present a list of network attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardward -->
+ <!-- An Array of "[type-name],[associated radio-name],[priority] -->
+ <string-array translatable="false" name="networkAttributes">
+ <item>"default,wifi,0"</item>
+ <item>"default,mobile,0"</item>
+ <item>"mms,mobile,1"</item>
+ <item>"supl,mobile,1"</item>
+ <item>"dun,mobile,1"</item>
+ <item>"hipri,mobile,2"</item>
+ </string-array>
+
+ <!-- This string array should be overridden by the device to present a list of radio attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardware -->
+ <!-- An Array of "[radio-name],[priority] -->
+ <!-- [# simultaneous connection types]" -->
+ <string-array translatable="false" name="radioAttributes">
+ <item>"wifi,1,1"</item>
+ <item>"mobile,0,1"</item>
+ </string-array>
+
+ <!-- The number of degrees to rotate the display when the keyboard is open. -->
+ <integer name="config_lidOpenRotation">90</integer>
+
+ <!-- The number of degrees to rotate the display when the device is in a dock. -->
+ <integer name="config_dockedRotation">90</integer>
+
+ <!-- Flag indicating whether the keyguard should be bypassed when
+ the slider is open. This can be set or unset depending how easily
+ the slider can be opened (for example, in a pocket or purse). -->
+ <bool name="config_bypass_keyguard_if_slider_open">true</bool>
+
+ <!-- Vibrator pattern for feedback about a long screen/key press -->
+ <integer-array name="config_longPressVibePattern">
+ <item>0</item>
+ <item>1</item>
+ <item>20</item>
+ <item>21</item>
+ </integer-array>
+
+ <!-- Vibrator pattern for feedback about touching a virtual key -->
+ <integer-array name="config_virtualKeyVibePattern">
+ <item>0</item>
+ <item>10</item>
+ <item>20</item>
+ <item>30</item>
+ </integer-array>
+
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6461460..6a3538d 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -28,4 +28,10 @@
<dimen name="toast_y_offset">64dip</dimen>
<!-- Height of the status bar -->
<dimen name="status_bar_height">25dip</dimen>
+ <!-- Size of the fastscroll hint letter -->
+ <dimen name="fastscroll_overlay_size">104dp</dimen>
+ <!-- Width of the fastscroll thumb -->
+ <dimen name="fastscroll_thumb_width">64dp</dimen>
+ <!-- Height of the fastscroll thumb -->
+ <dimen name="fastscroll_thumb_height">52dp</dimen>
</resources>
diff --git a/core/res/res/values/donottranslate-names.xml b/core/res/res/values/donottranslate-names.xml
new file mode 100644
index 0000000..56ae47a
--- /dev/null
+++ b/core/res/res/values/donottranslate-names.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Various locale-specific string resources for Contacts -->
+ <string-array name="common_nicknames"></string-array>
+ <string name="common_name_prefixes"></string>
+ <string name="common_name_suffixes"></string>
+ <string name="common_last_name_prefixes"></string>
+ <string name="common_name_conjunctions"></string>
+</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c92cf51..0fba0f6 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" />
@@ -1130,14 +1130,35 @@
<public type="style" name="Widget.ProgressBar.Inverse" id="0x0103005b" />
<public type="style" name="Widget.ProgressBar.Large.Inverse" id="0x0103005c" />
- <public type="style" name="Widget.ProgressBar.Small.Inverse" id="0x0103005d" />
+ <public type="style" name="Widget.ProgressBar.Small.Inverse" id="0x0103005d" />
<public type="drawable" name="stat_sys_vp_phone_call" id="0x010800a7" />
<public type="drawable" name="stat_sys_vp_phone_call_on_hold" id="0x010800a8" />
-
+
<public type="anim" name="anticipate_interpolator" id="0x010a0007" />
<public type="anim" name="overshoot_interpolator" id="0x010a0008" />
<public type="anim" name="anticipate_overshoot_interpolator" id="0x010a0009" />
<public type="anim" name="bounce_interpolator" id="0x010a000a" />
<public type="anim" name="linear_interpolator" id="0x010a000b" />
+
+<!-- ===============================================================
+ Resources added in Eclair.
+ =============================================================== -->
+ <eat-comment />
+
+ <public type="attr" name="required" id="0x0101028e" />
+ <public type="attr" name="accountType" />
+ <public type="attr" name="contentAuthority" />
+ <public type="attr" name="userVisible" />
+ <public type="attr" name="windowShowWallpaper" />
+ <public type="attr" name="wallpaperActivityOpenEnterAnimation" />
+ <public type="attr" name="wallpaperActivityOpenExitAnimation" />
+ <public type="attr" name="wallpaperActivityCloseEnterAnimation" />
+ <public type="attr" name="wallpaperActivityCloseExitAnimation" />
+
+ <public type="style" name="Theme.Wallpaper" />
+ <public type="style" name="Theme.Wallpaper.NoTitleBar" />
+ <public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" />
+
+ <public type="attr" name="supportsUploading" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index aaaebbb..70c9385 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -134,7 +134,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>
@@ -229,6 +229,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>
@@ -299,7 +306,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. -->
@@ -542,7 +549,12 @@
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_backup">control system backup and restore</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_backup">Allows the application to control the system's backup and restore mechanism. Not for use by normal applications.</string>
+ <string name="permdesc_backup">Allows the application to control the system\'s backup and restore mechanism. Not for use by normal applications.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_backup_data">back up and restore the application\'s data</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_backup_data">Allows the application to participate in the system\'s backup and restore mechanism.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_internalSystemWindow">display unauthorized windows</string>
@@ -592,6 +604,12 @@
interface of an input method. Should never be needed for normal applications.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindWallpaper">bind to a wallpaper</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_bindWallpaper">Allows the holder to bind to the top-level
+ interface of a wallpaper. Should never be needed for normal applications.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_setOrientation">change screen orientation</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_setOrientation">Allows an application to change
@@ -689,7 +707,7 @@
<string name="permlab_writeSecureSettings">modify secure system settings</string>
<string name="permdesc_writeSecureSettings">Allows an application to modify the
- system's secure settings data. Not for use by normal applications.</string>
+ system\'s secure settings data. Not for use by normal applications.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_writeGservices">modify the Google services map</string>
@@ -800,7 +818,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. -->
@@ -880,6 +898,12 @@
services.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_performCdmaProvisioning">directly start CDMA phone setup</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_performCdmaProvisioning">Allows the application to start CDMA provisioning.
+ Malicious applications may unnecessarily start CDMA provisioning</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_locationUpdates">control location update notifications</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_locationUpdates">Allows enabling/disabling location
@@ -961,12 +985,40 @@
the phone\'s time zone.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_accountManagerService">act as the AccountManagerService</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_accountManagerService">Allows an
+ application to make calls to AccountAuthenticators</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_getAccounts">discover known accounts</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_getAccounts">Allows an application to get
the list of accounts known by the phone.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_authenticateAccounts">act as an account authenticator</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_authenticateAccounts">Allows an application
+ to use the account authenticator capabilities of the
+ AccountManager, including creating accounts and getting and
+ setting their passwords.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_manageAccounts">manage the accounts list</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_manageAccounts">Allows an application to
+ perform operations like adding, and removing accounts and deleting
+ their password.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_useCredentials">use the authentication
+ credentials of an account</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_useCredentials">Allows an application to
+ request authentication tokens.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessNetworkState">view network state</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_accessNetworkState">Allows an application to view
@@ -1109,9 +1161,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">
@@ -1251,7 +1300,11 @@
their lock gesture -->
<string name="lockscreen_forgot_pattern_button_text">Forgot pattern?</string>
- <!-- Title of the unlock screen that uses your Google login and password -->
+ <!-- Title of the unlock screen that uses your Google login and password when the user hit
+ the 'forgot pattern' button.-->
+ <string name="lockscreen_glogin_forgot_pattern">Account unlock</string>
+ <!-- Title of the unlock screen that uses your Google login and password when the user attempted
+ too many patterns and we are forcing them to use their account instead. -->
<string name="lockscreen_glogin_too_many_attempts">Too many pattern attempts!</string>
<!-- In the unlock screen, message telling the user that they need to use their Google login and password to unlock the phone -->
<string name="lockscreen_glogin_instructions">To unlock, sign in with your Google account</string>
@@ -1264,6 +1317,9 @@
<!-- Displayed to the user when unlocking the phone with a username and password fails. -->
<string name="lockscreen_glogin_invalid_input">Invalid username or password.</string>
+ <!-- Displayed in a progress dialog while a username and password are being checked. -->
+ <string name="lockscreen_glogin_checking_password">Checking...</string>
+
<!-- A format string for 12-hour time of day, just the hour, not the minute, with lower-case "am" or "pm" (example: "3pm"). -->
<string name="hour_ampm">"<xliff:g id="hour" example="3">%-l</xliff:g><xliff:g id="ampm" example="pm">%P</xliff:g>"</string>
@@ -1307,7 +1363,7 @@
<!-- When the battery is low, this is the label of the button to go to the
power usage activity to find out what drained the battery. -->
- <string name="battery_low_why">Why?</string>
+ <string name="battery_low_why">Battery use</string>
<!-- Title of the alert when something went wrong in the factory test. -->
<string name="factorytest_failed">Factory test failed</string>
@@ -1322,7 +1378,7 @@
<!-- Do not translate. WebView User Agent string -->
<string name="web_user_agent"><xliff:g id="x">Mozilla/5.0 (Linux; U; Android %s)
- AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1</xliff:g></string>
+ AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17</xliff:g></string>
<!-- Title for a JavaScript dialog. "The page at <url of current page> says:" -->
<string name="js_dialog_title">The page at \'<xliff:g id="title">%s</xliff:g>\' says:</string>
@@ -1378,8 +1434,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>
@@ -1435,7 +1491,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>
@@ -1485,11 +1541,11 @@
</plurals>
<!-- String used to display the date. Preposition for date display ("on May 29") -->
- <string name="preposition_for_date">on %s</string>
+ <string name="preposition_for_date">on <xliff:g id="date" example="May 29">%s</xliff:g></string>
<!-- String used to display the date. Preposition for time display ("at 2:33am") -->
- <string name="preposition_for_time">at %s</string>
+ <string name="preposition_for_time">at <xliff:g id="time" example="2:33 am">%s</xliff:g></string>
<!-- String used to display the date. Preposition for year display ("in 2008") -->
- <string name="preposition_for_year">in %s</string>
+ <string name="preposition_for_year">in <xliff:g id="year" example="2003">%s</xliff:g></string>
<!-- Appened to express the value is this unit of time: singular day -->
<string name="day">day</string>
@@ -1598,11 +1654,11 @@
<string name="copyUrl">Copy URL</string>
<!-- EditText context menu -->
- <string name="inputMethod">Input Method</string>
+ <string name="inputMethod">Input method</string>
<!-- Item on EditText context menu, used to add a word to the
input method dictionary. -->
- <string name="addToDictionary">"Add \"%s\" to dictionary</string>
+ <string name="addToDictionary">"Add \"<xliff:g id="word" example="rickroll">%s</xliff:g>\" to dictionary</string>
<!-- Title for EditText context menu -->
<string name="editTextMenuTitle">Edit text</string>
@@ -1677,6 +1733,8 @@
<string name="volume_music">Media volume</string>
<!-- Hint shown in the volume toast to inform the user that the media audio is playing through Bluetooth. -->
<string name="volume_music_hint_playing_through_bluetooth">Playing through Bluetooth</string>
+ <!-- Hint shown in the volume toast to inform the user that the current ringtone is the silent ringtone. -->
+ <string name="volume_music_hint_silent_ringtone_selected">Silent ringtone selected</string>
<!-- Title of the dialog where the user is adjusting the phone call volume -->
<string name="volume_call">In-call volume</string>
<!-- Title of the dialog where the user is adjusting the phone call volume when connected on bluetooth-->
@@ -1754,7 +1812,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>
@@ -1775,8 +1833,8 @@
<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. -->
- <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>
+ <!-- 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 -->
<!-- This is the label for the activity, and should never be visible to the user. -->
@@ -1791,7 +1849,7 @@
<string name="adb_active_notification_title">USB debugging connected</string>
<!-- Message of notification shown when ADB is actively connected to the phone. -->
<string name="adb_active_notification_message">A computer is connected to your phone.</string>
-
+
<!-- Used to replace %s in urls retreived from the signin server with locales. For Some -->
<!-- devices we don't support all the locales we ship to and need to replace the '%s' with a -->
<!-- locale string based on mcc values. By default (0-length string) we don't replace the %s -->
@@ -1801,10 +1859,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 -->
@@ -1851,23 +1909,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 />
@@ -1878,8 +1936,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. -->
@@ -1888,4 +1949,19 @@
<!-- Title for the unselected state of a CompoundButton. -->
<string name="accessibility_compound_button_unselected">not checked</string>
+ <string name="grant_credentials_permission_message_desc">The
+ listed applications are requesting permission to access the login credentials for account <xliff:g id="account" example="foo@gmail.com">%1$s</xliff:g> from
+ <xliff:g id="application" example="Google Apps">%2$s</xliff:g>. Do you wish to grant this permission? If so, your answer will be remembered and you will not be prompted
+ again.</string>
+
+ <string name="grant_credentials_permission_message_with_authtokenlabel_desc">The
+ listed applications are requesting permission to access the <xliff:g id="type" example="Contacts">%1$s</xliff:g> login credentials for account <xliff:g id="account" example="foo@gmail.com">%2$s</xliff:g> from
+ <xliff:g id="application" example="Google Apps">%3$s</xliff:g>. Do you wish to grant this permission? If so, your answer will be remembered and you will not be prompted
+ again.</string>
+
+ <string name="allow">Allow</string>
+ <string name="deny">Deny</string>
+ <string name="permission_request_notification_title">Permission Requested</string>
+ <string name="permission_request_notification_subtitle">for account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g></string>
+
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 8eda12e..55f8167 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -66,6 +66,10 @@
<item name="taskToFrontExitAnimation">@anim/task_open_exit</item>
<item name="taskToBackEnterAnimation">@anim/task_close_enter</item>
<item name="taskToBackExitAnimation">@anim/task_close_exit</item>
+ <item name="wallpaperActivityOpenEnterAnimation">@anim/wallpaper_activity_open_enter</item>
+ <item name="wallpaperActivityOpenExitAnimation">@anim/wallpaper_activity_open_exit</item>
+ <item name="wallpaperActivityCloseEnterAnimation">@anim/wallpaper_activity_close_enter</item>
+ <item name="wallpaperActivityCloseExitAnimation">@anim/wallpaper_activity_close_exit</item>
</style>
<!-- Standard animations for a non-full-screen window or activity. -->
@@ -130,8 +134,7 @@
<item name="windowExitAnimation">@anim/slide_out_down</item>
</style>
- <!-- Window animations that are applied to input method overlay windows.
- {@hide Pending API council approval} -->
+ <!-- Window animations that are applied to input method overlay windows. -->
<style name="Animation.InputMethod">
<item name="windowEnterAnimation">@anim/input_method_enter</item>
<item name="windowExitAnimation">@anim/input_method_exit</item>
@@ -151,13 +154,18 @@
<item name="windowExitAnimation">@anim/search_bar_exit</item>
</style>
- <!-- Window animations that are applied to the zoom buttons overlay window.
- {@hide Pending API council approval} -->
+ <!-- Window animations that are applied to the zoom buttons overlay window. -->
<style name="Animation.ZoomButtons">
<item name="windowEnterAnimation">@anim/fade_in</item>
<item name="windowExitAnimation">@anim/fade_out</item>
</style>
+ <!-- Standard animations for wallpapers. -->
+ <style name="Animation.Wallpaper">
+ <item name="windowEnterAnimation">@anim/wallpaper_enter</item>
+ <item name="windowExitAnimation">@anim/wallpaper_exit</item>
+ </style>
+
<!-- Status Bar Styles -->
<style name="TextAppearance.StatusBarTitle">
@@ -337,7 +345,7 @@
</style>
<style name="Widget.TextView.ListSeparator">
- <item name="android:background">@android:drawable/dark_header</item>
+ <item name="android:background">@android:drawable/dark_header_dither</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">25dip</item>
<item name="android:textStyle">bold</item>
@@ -349,7 +357,7 @@
<style name="Widget.TextView.ListSeparator.White">
<item name="android:textColor">?textColorPrimaryInverse</item>
- <item name="android:background">@android:drawable/light_header</item>
+ <item name="android:background">@android:drawable/light_header_dither</item>
</style>
<style name="Widget.EditText">
@@ -659,12 +667,12 @@
</style>
<style name="Preference.PreferenceScreen">
- <item name="android:widgetLayout">@android:layout/preferences</item>
</style>
<style name="Preference.DialogPreference">
<item name="android:positiveButtonText">@android:string/ok</item>
<item name="android:negativeButtonText">@android:string/cancel</item>
+ <item name="android:widgetLayout">@android:layout/preference_dialog</item>
</style>
<style name="Preference.DialogPreference.YesNoPreference">
@@ -680,6 +688,7 @@
<item name="android:ringtoneType">ringtone</item>
<item name="android:showSilent">true</item>
<item name="android:showDefault">true</item>
+ <item name="android:widgetLayout">@android:layout/preference_dialog</item>
</style>
<!-- Other Misc Styles -->
@@ -687,8 +696,8 @@
<style name="MediaButton">
<item name="android:background">@android:drawable/media_button_background</item>
- <item name="android:layout_width">71px</item>
- <item name="android:layout_height">52px</item>
+ <item name="android:layout_width">71dip</item>
+ <item name="android:layout_height">52dip</item>
</style>
<style name="MediaButton.Previous">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index e3fffb7..bfdce1e 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -112,6 +112,7 @@
<item name="windowFullscreen">false</item>
<item name="windowIsFloating">false</item>
<item name="windowContentOverlay">@android:drawable/title_bar_shadow</item>
+ <item name="windowShowWallpaper">false</item>
<item name="windowTitleStyle">@android:style/WindowTitle</item>
<item name="windowTitleSize">25dip</item>
<item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>
@@ -280,6 +281,25 @@
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Default theme for windows that want to have the user's selected
+ wallpaper appear behind them. -->
+ <style name="Theme.Wallpaper">
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowShowWallpaper">true</item>
+ </style>
+
+ <!-- Variant of the translucent theme with no title bar -->
+ <style name="Theme.Wallpaper.NoTitleBar">
+ <item name="android:windowNoTitle">true</item>
+ </style>
+
+ <!-- Variant of the translucent theme that has no title bar and
+ fills the entire screen -->
+ <style name="Theme.Wallpaper.NoTitleBar.Fullscreen">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Default theme for translucent activities, that is windows that allow you
to see through them to the windows behind. This sets up the translucent
flag and appropriate animations for your windows. -->
diff --git a/data/etc/android.hardware.camera.autofocus.xml b/data/etc/android.hardware.camera.autofocus.xml
new file mode 100644
index 0000000..d6e2b90
--- /dev/null
+++ b/data/etc/android.hardware.camera.autofocus.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard set of features for an auto-focus camera. -->
+<permissions>
+ <feature name="android.hardware.camera" />
+ <feature name="android.hardware.camera.autofocus" />
+</permissions>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index a3579c7..7322e6c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -133,6 +133,7 @@
<assign-permission name="android.permission.READ_FRAME_BUFFER" uid="shell" />
<assign-permission name="android.permission.DEVICE_POWER" uid="shell" />
<assign-permission name="android.permission.INSTALL_LOCATION_PROVIDER" uid="shell" />
+ <assign-permission name="android.permission.BACKUP" uid="shell" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_DRM" uid="media" />
@@ -145,7 +146,7 @@
<library name="android.test.runner"
file="/system/framework/android.test.runner.jar" />
- <library name="com.android.im.plugin"
- file="/system/framework/com.android.im.plugin.jar"/>
+ <library name="javax.obex"
+ file="/system/framework/javax.obex.jar"/>
</permissions>
diff --git a/docs/html/guide/appendix/faq/commontasks.jd b/docs/html/guide/appendix/faq/commontasks.jd
index 0f89e75..e88a867 100644
--- a/docs/html/guide/appendix/faq/commontasks.jd
+++ b/docs/html/guide/appendix/faq/commontasks.jd
@@ -56,7 +56,7 @@ href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a>
to understand the basics of how an Android application works.</p>
<p>You should also take a look at the ApiDemos application and the other sample
-applications included in the SDK, in the <code>&lt;sdk&gt;/samples/
+applications included in the SDK, in the <code>&lt;sdk&gt;/samples/</code>
folder in the SDK.</p>
<p>Finally, a great way to started with Android development in Eclipse is to
@@ -281,6 +281,15 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data){
<pre>//Hide the title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
</pre>
+<p>A better way to achieve the same end is to specify a theme in your Android
+Manifest file:</p>
+<pre>&lt;application android:icon="@drawable/icon" android:theme="@android:style/Theme.NoTitleBar"&gt;
+</pre>
+<p>This is preferable because it tells the system not to show a title bar while
+your application is starting up. With the explicit method call, your application
+will have a title bar visible to the user until <code>onCreate</code> runs.</p>
+<p>(Note that this can be applied to either the <code>&lt;application&gt;</code>
+tag or to individual <code>&lt;activity&gt;</code> tags.)</p>
<a name="localhostalias" id="localhostalias"></a><h2>Referring to localhost from the emulated environment</h2>
<p>
If you need to refer to your host computer's <em>localhost</em>, such as when you
@@ -427,7 +436,7 @@ user receiving new e-mail.</p>
<td>Activity</td>
<td>By setting the theme of an activity to
{@link android.R.style#Theme_Dialog
- android:theme=&quot;android:style/Theme.Dialog&quot;},
+ android:theme=&quot;&#064;android:style/Theme.Dialog&quot;},
your activity will take on
the appearance of a normal dialog, floating on top of whatever was
underneath it. You usually set the theme through the
diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd
index 5a2a751..9dea053 100644
--- a/docs/html/guide/developing/device.jd
+++ b/docs/html/guide/developing/device.jd
@@ -134,7 +134,7 @@ would on the emulator. There are just a few things to do before you can start.</
<code>SUBSYSTEM=="usb_device", SYSFS{idVendor}=="0bb4", MODE="0666"</code></p>
</li>
<li>Now execute:<br/>
- <code>chmod a+rx /etc/udev/rules.d/51-android.rules</code>
+ <code>chmod a+r /etc/udev/rules.d/51-android.rules</code>
</li>
</ol>
diff --git a/docs/html/guide/developing/tools/adb.jd b/docs/html/guide/developing/tools/adb.jd
index b111047..e8c726f 100644
--- a/docs/html/guide/developing/tools/adb.jd
+++ b/docs/html/guide/developing/tools/adb.jd
@@ -313,7 +313,7 @@ emulator-5558&nbsp;&nbsp;device</pre>
<li><code>&lt;tty&gt;</code> &mdash; the tty for PPP stream. For example <code>dev:/dev/omap_csmi_ttyl</code>. </li>
<li><code>[parm]... </code> &mdash zero or more PPP/PPPD options, such as <code>defaultroute</code>, <code>local</code>, <code>notty</code>, etc.</li></ul>
-<p>Note that you should not automatically start a PDP connection. </p></td>
+<p>Note that you should not automatically start a PPP connection. </p></td>
<td></td>
</tr>
diff --git a/docs/html/guide/developing/tools/aidl.jd b/docs/html/guide/developing/tools/aidl.jd
index f370a80..abfa8b1 100644
--- a/docs/html/guide/developing/tools/aidl.jd
+++ b/docs/html/guide/developing/tools/aidl.jd
@@ -194,7 +194,6 @@ started.</p>
<li>Make your class implement the {@link android.os.Parcelable} interface.</li>
<li>Implement the method <code>public void writeToParcel(Parcel out)</code> that takes the
current state of the object and writes it to a parcel.</li>
-<li>Implement the method <code>public void readFromParcel(Parcel in)</code> that reads the
value in a parcel into your object.</li>
<li>Add a static field called <code>CREATOR</code> to your class which is an object implementing
the {@link android.os.Parcelable.Creator Parcelable.Creator} interface.</li>
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/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index a9d1090..48e598a 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -44,8 +44,11 @@ to "{@code http://schemas.android.com/apk/res/android}".</dd>
<dt><a name="package"></a>{@code package}</dt>
<dd>A full Java package name for the application. The name should
-be unique. For example, applications published by Google could have
-names in the form <code>com.google.app.<i>application_name</i></code>.
+be unique. The name may contain uppercase or lowercase letters ('A'
+through 'Z'), numbers, and underscores ('_'). However, individual
+package name parts may only start with letters. For example, applications
+published by Google could have names in the form
+<code>com.google.app.<i>application_name</i></code>.
<p>
The package name serves as a unique identifier for the application.
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index c8bed24..f60a7be 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -18,6 +18,7 @@ package android.graphics;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import android.os.MemoryFile;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -72,7 +73,7 @@ public class BitmapFactory {
public Bitmap.Config inPreferredConfig;
/**
- * If dither is true, the decoder will atttempt to dither the decoded
+ * If dither is true, the decoder will attempt to dither the decoded
* image.
*/
public boolean inDither;
@@ -336,19 +337,26 @@ public class BitmapFactory {
*/
public static Bitmap decodeResource(Resources res, int id, Options opts) {
Bitmap bm = null;
-
+ InputStream is = null;
+
try {
final TypedValue value = new TypedValue();
- final InputStream is = res.openRawResource(id, value);
+ is = res.openRawResource(id, value);
bm = decodeResourceStream(res, value, is, null, opts);
- is.close();
- } catch (java.io.IOException e) {
+ } catch (Exception e) {
/* do nothing.
If the exception happened on open, bm will be null.
If it happened on close, bm is still valid.
*/
+ } finally {
+ try {
+ if (is != null) is.close();
+ } catch (IOException e) {
+ // Ignore
+ }
}
+
return bm;
}
@@ -451,6 +459,10 @@ public class BitmapFactory {
bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
}
+ return finishDecode(bm, outPadding, opts);
+ }
+
+ private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
if (bm == null || opts == null) {
return bm;
}
@@ -486,7 +498,7 @@ public class BitmapFactory {
return bm;
}
-
+
/**
* Decode an input stream into a bitmap. If the input stream is null, or
* cannot be used to decode a bitmap, the function returns null.
@@ -506,7 +518,7 @@ public class BitmapFactory {
/**
* Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
* return null. The position within the descriptor will not be changed when
- * this returns, so the descriptor can be used again as is.
+ * this returns, so the descriptor can be used again as-is.
*
* @param fd The file descriptor containing the bitmap data to decode
* @param outPadding If not null, return the padding rect for the bitmap if
@@ -518,7 +530,20 @@ public class BitmapFactory {
* @return the decoded bitmap, or null
*/
public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
- return nativeDecodeFileDescriptor(fd, outPadding, opts);
+ try {
+ if (MemoryFile.isMemoryFile(fd)) {
+ int mappedlength = MemoryFile.getMappedSize(fd);
+ MemoryFile file = new MemoryFile(fd, mappedlength, "r");
+ InputStream is = file.getInputStream();
+ Bitmap bm = decodeStream(is, outPadding, opts);
+ return finishDecode(bm, outPadding, opts);
+ }
+ } catch (IOException ex) {
+ // invalid filedescriptor, no need to call nativeDecodeFileDescriptor()
+ return null;
+ }
+ Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
+ return finishDecode(bm, outPadding, opts);
}
/**
@@ -530,7 +555,7 @@ public class BitmapFactory {
* @return the decoded bitmap, or null
*/
public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
- return nativeDecodeFileDescriptor(fd, null, null);
+ return decodeFileDescriptor(fd, null, null);
}
private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 3fc391c..5cefaa3 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -16,6 +16,8 @@
package android.graphics;
+import android.util.MathUtils;
+
import java.util.HashMap;
import java.util.Locale;
@@ -105,6 +107,92 @@ public class Color {
}
/**
+ * Returns the hue component of a color int.
+ *
+ * @return A value between 0.0f and 1.0f
+ *
+ * @hide Pending API council
+ */
+ public static float hue(int color) {
+ int r = (color >> 16) & 0xFF;
+ int g = (color >> 8) & 0xFF;
+ int b = color & 0xFF;
+
+ int V = Math.max(b, Math.max(r, g));
+ int temp = Math.min(b, Math.min(r, g));
+
+ float H;
+
+ if (V == temp) {
+ H = 0;
+ } else {
+ final float vtemp = (float) (V - temp);
+ final float cr = (V - r) / vtemp;
+ final float cg = (V - g) / vtemp;
+ final float cb = (V - b) / vtemp;
+
+ if (r == V) {
+ H = cb - cg;
+ } else if (g == V) {
+ H = 2 + cr - cb;
+ } else {
+ H = 4 + cg - cr;
+ }
+
+ H /= 6.f;
+ if (H < 0) {
+ H++;
+ }
+ }
+
+ return H;
+ }
+
+ /**
+ * Returns the saturation component of a color int.
+ *
+ * @return A value between 0.0f and 1.0f
+ *
+ * @hide Pending API council
+ */
+ public static float saturation(int color) {
+ int r = (color >> 16) & 0xFF;
+ int g = (color >> 8) & 0xFF;
+ int b = color & 0xFF;
+
+
+ int V = Math.max(b, Math.max(r, g));
+ int temp = Math.min(b, Math.min(r, g));
+
+ float S;
+
+ if (V == temp) {
+ S = 0;
+ } else {
+ S = (V - temp) / (float) V;
+ }
+
+ return S;
+ }
+
+ /**
+ * Returns the brightness component of a color int.
+ *
+ * @return A value between 0.0f and 1.0f
+ *
+ * @hide Pending API council
+ */
+ public static float brightness(int color) {
+ int r = (color >> 16) & 0xFF;
+ int g = (color >> 8) & 0xFF;
+ int b = color & 0xFF;
+
+ int V = Math.max(b, Math.max(r, g));
+
+ return (V / 255.f);
+ }
+
+ /**
* Parse the color string, and return the corresponding color-int.
* If the string cannot be parsed, throws an IllegalArgumentException
* exception. Supported formats are:
@@ -134,6 +222,87 @@ public class Color {
}
/**
+ * Convert HSB components to an ARGB color. Alpha set to 0xFF.
+ * hsv[0] is Hue [0 .. 1)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Value [0...1]
+ * If hsv values are out of range, they are pinned.
+ * @param hsb 3 element array which holds the input HSB components.
+ * @return the resulting argb color
+ *
+ * @hide Pending API council
+ */
+ public static int HSBtoColor(float[] hsb) {
+ return HSBtoColor(hsb[0], hsb[1], hsb[2]);
+ }
+
+ /**
+ * Convert HSB components to an ARGB color. Alpha set to 0xFF.
+ * hsv[0] is Hue [0 .. 1)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Value [0...1]
+ * If hsv values are out of range, they are pinned.
+ * @param h Hue component
+ * @param s Saturation component
+ * @param b Brightness component
+ * @return the resulting argb color
+ *
+ * @hide Pending API council
+ */
+ public static int HSBtoColor(float h, float s, float b) {
+ h = MathUtils.constrain(h, 0.0f, 1.0f);
+ s = MathUtils.constrain(s, 0.0f, 1.0f);
+ b = MathUtils.constrain(b, 0.0f, 1.0f);
+
+ float red = 0.0f;
+ float green = 0.0f;
+ float blue = 0.0f;
+
+ final float hf = (h - (int) h) * 6.0f;
+ final int ihf = (int) hf;
+ final float f = hf - ihf;
+ final float pv = b * (1.0f - s);
+ final float qv = b * (1.0f - s * f);
+ final float tv = b * (1.0f - s * (1.0f - f));
+
+ switch (ihf) {
+ case 0: // Red is the dominant color
+ red = b;
+ green = tv;
+ blue = pv;
+ break;
+ case 1: // Green is the dominant color
+ red = qv;
+ green = b;
+ blue = pv;
+ break;
+ case 2:
+ red = pv;
+ green = b;
+ blue = tv;
+ break;
+ case 3: // Blue is the dominant color
+ red = pv;
+ green = qv;
+ blue = b;
+ break;
+ case 4:
+ red = tv;
+ green = pv;
+ blue = b;
+ break;
+ case 5: // Red is the dominant color
+ red = b;
+ green = pv;
+ blue = qv;
+ break;
+ }
+
+ return 0xFF000000 | (((int) (red * 255.0f)) << 16) |
+ (((int) (green * 255.0f)) << 8) | ((int) (blue * 255.0f));
+ }
+
+ /**
* Convert RGB components to HSV.
* hsv[0] is Hue [0 .. 360)
* hsv[1] is Saturation [0...1]
@@ -193,25 +362,24 @@ public class Color {
return nativeHSVToColor(alpha, hsv);
}
- private static native void nativeRGBToHSV(int red, int greed, int blue,
- float hsv[]);
+ private static native void nativeRGBToHSV(int red, int greed, int blue, float hsv[]);
private static native int nativeHSVToColor(int alpha, float hsv[]);
private static final HashMap<String, Integer> sColorNameMap;
static {
- sColorNameMap = new HashMap();
- sColorNameMap.put("black", Integer.valueOf(BLACK));
- sColorNameMap.put("darkgray", Integer.valueOf(DKGRAY));
- sColorNameMap.put("gray", Integer.valueOf(GRAY));
- sColorNameMap.put("lightgray", Integer.valueOf(LTGRAY));
- sColorNameMap.put("white", Integer.valueOf(WHITE));
- sColorNameMap.put("red", Integer.valueOf(RED));
- sColorNameMap.put("green", Integer.valueOf(GREEN));
- sColorNameMap.put("blue", Integer.valueOf(BLUE));
- sColorNameMap.put("yellow", Integer.valueOf(YELLOW));
- sColorNameMap.put("cyan", Integer.valueOf(CYAN));
- sColorNameMap.put("magenta", Integer.valueOf(MAGENTA));
+ sColorNameMap = new HashMap<String, Integer>();
+ sColorNameMap.put("black", BLACK);
+ sColorNameMap.put("darkgray", DKGRAY);
+ sColorNameMap.put("gray", GRAY);
+ sColorNameMap.put("lightgray", LTGRAY);
+ sColorNameMap.put("white", WHITE);
+ sColorNameMap.put("red", RED);
+ sColorNameMap.put("green", GREEN);
+ sColorNameMap.put("blue", BLUE);
+ sColorNameMap.put("yellow", YELLOW);
+ sColorNameMap.put("cyan", CYAN);
+ sColorNameMap.put("magenta", MAGENTA);
}
}
diff --git a/graphics/java/android/graphics/DashPathEffect.java b/graphics/java/android/graphics/DashPathEffect.java
index 3deca4a..4f16dc4 100644
--- a/graphics/java/android/graphics/DashPathEffect.java
+++ b/graphics/java/android/graphics/DashPathEffect.java
@@ -23,13 +23,13 @@ public class DashPathEffect extends PathEffect {
* the even indices specifying the "on" intervals, and the odd indices
* specifying the "off" intervals. phase is an offset into the intervals
* array (mod the sum of all of the intervals). The intervals array
- * controlls the width of the dashes. The paint's strokeWidth controlls the
- * height of the dashes.
+ * controls the length of the dashes. The paint's strokeWidth controls the
+ * thickness of the dashes.
* Note: this patheffect only affects drawing with the paint's style is set
* to STROKE or STROKE_AND_FILL. It is ignored if the drawing is done with
* style == FILL.
* @param intervals array of ON and OFF distances
- * @param phase offset before the first ON interval is drawn
+ * @param phase offset into the intervals array
*/
public DashPathEffect(float intervals[], float phase) {
if (intervals.length < 2) {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index e40e84a..9bcab72 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -172,4 +172,14 @@ public class Typeface {
private static native int nativeGetStyle(int native_instance);
private static native int nativeCreateFromAsset(AssetManager mgr, String path);
private static native int nativeCreateFromFile(String path);
+
+ /**
+ * Set the global gamma coefficients for black and white text. This call is
+ * usually a no-op in shipping products, and only exists for testing during
+ * development.
+ *
+ * @param blackGamma gamma coefficient for black text
+ * @param whiteGamma gamma coefficient for white text
+ */
+ public static native void setGammaForText(float blackGamma, float whiteGamma);
}
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index eade73a..1755d4f 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -76,6 +76,7 @@ public class BitmapDrawable extends Drawable {
* @deprecated Use {@link #BitmapDrawable(Resources)} to ensure
* that the drawable has correctly set its target density.
*/
+ @Deprecated
public BitmapDrawable() {
mBitmapState = new BitmapState((Bitmap) null);
}
@@ -97,6 +98,7 @@ public class BitmapDrawable extends Drawable {
* @deprecated Use {@link #BitmapDrawable(Resources, Bitmap)} to ensure
* that the drawable has correctly set its target density.
*/
+ @Deprecated
public BitmapDrawable(Bitmap bitmap) {
this(new BitmapState(bitmap));
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 0a0e4eb..21b5e39 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -102,7 +102,7 @@ public abstract class Drawable {
private int[] mStateSet = StateSet.WILD_CARD;
private int mLevel = 0;
private int mChangingConfigurations = 0;
- private Rect mBounds = ZERO_BOUNDS_RECT;
+ private Rect mBounds = ZERO_BOUNDS_RECT; // lazily becomes a new Rect()
/*package*/ Callback mCallback = null;
private boolean mVisible = true;
@@ -654,7 +654,7 @@ public abstract class Drawable {
* Create a drawable from an inputstream
*/
public static Drawable createFromStream(InputStream is, String srcName) {
- return createFromResourceStream(null, null, is, srcName);
+ return createFromResourceStream(null, null, is, srcName, null);
}
/**
@@ -663,6 +663,15 @@ public abstract class Drawable {
*/
public static Drawable createFromResourceStream(Resources res, TypedValue value,
InputStream is, String srcName) {
+ return createFromResourceStream(res, value, is, srcName, null);
+ }
+
+ /**
+ * Create a drawable from an inputstream, using the given resources and
+ * value to determine density information.
+ */
+ public static Drawable createFromResourceStream(Resources res, TypedValue value,
+ InputStream is, String srcName, BitmapFactory.Options opts) {
if (is == null) {
return null;
@@ -683,7 +692,7 @@ public abstract class Drawable {
// an application in compatibility mode, without scaling those down
// to the compatibility density only to have them scaled back up when
// drawn to the screen.
- BitmapFactory.Options opts = new BitmapFactory.Options();
+ if (opts == null) opts = new BitmapFactory.Options();
opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
if (bm != null) {
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index dc80cf5..6b50406 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -237,7 +237,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
final int N = mDrawableContainerState.getChildCount();
final Drawable[] drawables = mDrawableContainerState.getChildren();
for (int i = 0; i < N; i++) {
- drawables[i].mutate();
+ if (drawables[i] != null) drawables[i].mutate();
}
mMutated = true;
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index d5c8a08..b175bb6 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -56,6 +56,7 @@ public class NinePatchDrawable extends Drawable {
* @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)}
* to ensure that the drawable has correctly set its target density.
*/
+ @Deprecated
public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
}
@@ -78,6 +79,7 @@ public class NinePatchDrawable extends Drawable {
* @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
* to ensure that the drawable has correctly set its target density.
*/
+ @Deprecated
public NinePatchDrawable(NinePatch patch) {
this(new NinePatchState(patch, null));
}
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index d22a4ba..a8274b1 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -105,6 +105,8 @@ public class StateListDrawable extends DrawableContainer {
mStateListState.setConstantSize(a.getBoolean(
com.android.internal.R.styleable.StateListDrawable_constantSize, false));
+ setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither, false));
+
a.recycle();
int type;
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
new file mode 100644
index 0000000..536f71c
--- /dev/null
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.res.Resources;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.Log;
+import android.util.TypedValue;
+
+/**
+ * @hide
+ *
+ **/
+public class Allocation extends BaseObj {
+ Type mType;
+
+ Allocation(int id, RenderScript rs, Type t) {
+ super(rs);
+ mID = id;
+ mType = t;
+ }
+
+ public void uploadToTexture(int baseMipLevel) {
+ mRS.nAllocationUploadToTexture(mID, baseMipLevel);
+ }
+
+ public void uploadToBufferObject() {
+ mRS.nAllocationUploadToBufferObject(mID);
+ }
+
+ public void data(int[] d) {
+ int size;
+ if(mType != null && mType.mElement != null) {
+ size = mType.mElement.mSize;
+ for(int ct=0; ct < mType.mValues.length; ct++) {
+ if(mType.mValues[ct] != 0) {
+ size *= mType.mValues[ct];
+ }
+ }
+ if((d.length * 4) < size) {
+ throw new IllegalArgumentException("Array too small for allocation type.");
+ }
+ Log.e("rs", "Alloc data size=" + size);
+ mRS.nAllocationData(mID, d, size);
+ return;
+ }
+ mRS.nAllocationData(mID, d, d.length * 4);
+ }
+
+ public void data(float[] d) {
+ int size;
+ if(mType != null && mType.mElement != null) {
+ size = mType.mElement.mSize;
+ for(int ct=0; ct < mType.mValues.length; ct++) {
+ if(mType.mValues[ct] != 0) {
+ size *= mType.mValues[ct];
+ }
+ }
+ if((d.length * 4) < size) {
+ throw new IllegalArgumentException("Array too small for allocation type.");
+ }
+ Log.e("rs", "Alloc data size=" + size);
+ mRS.nAllocationData(mID, d, size);
+ return;
+ }
+ mRS.nAllocationData(mID, d, d.length * 4);
+ }
+
+ public void subData1D(int off, int count, int[] d) {
+ mRS.nAllocationSubData1D(mID, off, count, d, count * 4);
+ }
+
+ public void subData1D(int off, int count, float[] d) {
+ mRS.nAllocationSubData1D(mID, off, count, d, d.length * 4);
+ }
+
+ public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
+ mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d, d.length * 4);
+ }
+
+ public void subData2D(int xoff, int yoff, int w, int h, float[] d) {
+ mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d, d.length * 4);
+ }
+
+ public void readData(int[] d) {
+ mRS.nAllocationRead(mID, d);
+ }
+
+ public void readData(float[] d) {
+ mRS.nAllocationRead(mID, d);
+ }
+
+ public void data(Object o) {
+ mRS.nAllocationDataFromObject(mID, mType, o);
+ }
+
+
+ public class Adapter1D extends BaseObj {
+ Adapter1D(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void setConstraint(Dimension dim, int value) {
+ mRS.nAdapter1DSetConstraint(mID, dim.mID, value);
+ }
+
+ public void data(int[] d) {
+ mRS.nAdapter1DData(mID, d);
+ }
+
+ public void data(float[] d) {
+ mRS.nAdapter1DData(mID, d);
+ }
+
+ public void subData(int off, int count, int[] d) {
+ mRS.nAdapter1DSubData(mID, off, count, d);
+ }
+
+ public void subData(int off, int count, float[] d) {
+ mRS.nAdapter1DSubData(mID, off, count, d);
+ }
+ }
+
+ public Adapter1D createAdapter1D() {
+ int id = mRS.nAdapter1DCreate();
+ if (id != 0) {
+ mRS.nAdapter1DBindAllocation(id, mID);
+ }
+ return new Adapter1D(id, mRS);
+ }
+
+
+ public class Adapter2D extends BaseObj {
+ Adapter2D(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void setConstraint(Dimension dim, int value) {
+ mRS.nAdapter2DSetConstraint(mID, dim.mID, value);
+ }
+
+ public void data(int[] d) {
+ mRS.nAdapter2DData(mID, d);
+ }
+
+ public void data(float[] d) {
+ mRS.nAdapter2DData(mID, d);
+ }
+
+ public void subData(int xoff, int yoff, int w, int h, int[] d) {
+ mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d);
+ }
+
+ public void subData(int xoff, int yoff, int w, int h, float[] d) {
+ mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d);
+ }
+ }
+
+ public Adapter2D createAdapter2D() {
+ int id = mRS.nAdapter2DCreate();
+ if (id != 0) {
+ mRS.nAdapter2DBindAllocation(id, mID);
+ }
+ return new Adapter2D(id, mRS);
+ }
+
+
+ // creation
+
+ private static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
+ static {
+ mBitmapOptions.inScaled = false;
+ }
+
+ static public Allocation createTyped(RenderScript rs, Type type)
+ throws IllegalArgumentException {
+
+ if(type.mID == 0) {
+ throw new IllegalStateException("Bad Type");
+ }
+ int id = rs.nAllocationCreateTyped(type.mID);
+ return new Allocation(id, rs, type);
+ }
+
+ static public Allocation createSized(RenderScript rs, Element e, int count)
+ throws IllegalArgumentException {
+
+ int id;
+ if(e.mIsPredefined) {
+ id = rs.nAllocationCreatePredefSized(e.mPredefinedID, count);
+ } else {
+ id = rs.nAllocationCreateSized(e.mID, count);
+ if(id == 0) {
+ throw new IllegalStateException("Bad element.");
+ }
+ }
+ return new Allocation(id, rs, null);
+ }
+
+ static public Allocation createFromBitmap(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips)
+ throws IllegalArgumentException {
+ if(!dstFmt.mIsPredefined) {
+ throw new IllegalStateException("Attempting to allocate a bitmap with a non-static element.");
+ }
+
+ int id = rs.nAllocationCreateFromBitmap(dstFmt.mPredefinedID, genMips, b);
+ return new Allocation(id, rs, null);
+ }
+
+ static public Allocation createFromBitmapBoxed(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips)
+ throws IllegalArgumentException {
+ if(!dstFmt.mIsPredefined) {
+ throw new IllegalStateException("Attempting to allocate a bitmap with a non-static element.");
+ }
+
+ int id = rs.nAllocationCreateFromBitmapBoxed(dstFmt.mPredefinedID, genMips, b);
+ return new Allocation(id, rs, null);
+ }
+
+ static public Allocation createFromBitmapResource(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips)
+ throws IllegalArgumentException {
+
+ InputStream is = null;
+ try {
+ final TypedValue value = new TypedValue();
+ is = res.openRawResource(id, value);
+
+ int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+ int allocationId = rs.nAllocationCreateFromAssetStream(dstFmt.mPredefinedID, genMips,
+ asset);
+
+ return new Allocation(allocationId, rs, null);
+ } catch (Exception e) {
+ // Ignore
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+ return null;
+ }
+
+ static public Allocation createFromBitmapResourceBoxed(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips)
+ throws IllegalArgumentException {
+
+ Bitmap b = BitmapFactory.decodeResource(res, id, mBitmapOptions);
+ return createFromBitmapBoxed(rs, b, dstFmt, genMips);
+ }
+}
+
+
diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
new file mode 100644
index 0000000..c25f16a
--- /dev/null
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+class BaseObj {
+
+ BaseObj(RenderScript rs) {
+ mRS = rs;
+ mID = 0;
+ mDestroyed = false;
+ }
+
+ public int getID() {
+ return mID;
+ }
+
+ int mID;
+ boolean mDestroyed;
+ String mName;
+ RenderScript mRS;
+
+ public void setName(String s) throws IllegalStateException, IllegalArgumentException
+ {
+ if(s.length() < 1) {
+ throw new IllegalArgumentException("setName does not accept a zero length string.");
+ }
+ if(mName != null) {
+ throw new IllegalArgumentException("setName object already has a name.");
+ }
+
+ try {
+ byte[] bytes = s.getBytes("UTF-8");
+ mRS.nAssignName(mID, bytes);
+ mName = s;
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void finalize() throws Throwable
+ {
+ if (!mDestroyed) {
+ if(mID != 0) {
+ mRS.nObjDestroyOOB(mID);
+ }
+ mID = 0;
+ mDestroyed = true;
+ Log.v(RenderScript.LOG_TAG,
+ getClass() + " auto finalizing object without having released the RS reference.");
+ }
+ super.finalize();
+ }
+
+ public void destroy() {
+ if(mDestroyed) {
+ throw new IllegalStateException("Object already destroyed.");
+ }
+ mDestroyed = true;
+ mRS.nObjDestroy(mID);
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/Dimension.java b/graphics/java/android/renderscript/Dimension.java
new file mode 100644
index 0000000..f29057d
--- /dev/null
+++ b/graphics/java/android/renderscript/Dimension.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+/**
+ * @hide
+ **/
+public enum Dimension {
+ X (0),
+ Y (1),
+ Z (2),
+ LOD (3),
+ FACE (4),
+ ARRAY_0 (100);
+
+ int mID;
+ Dimension(int id) {
+ mID = id;
+ }
+}
+
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
new file mode 100644
index 0000000..0ca112c
--- /dev/null
+++ b/graphics/java/android/renderscript/Element.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.lang.reflect.Field;
+
+/**
+ * @hide
+ *
+ **/
+public class Element extends BaseObj {
+ final int mPredefinedID;
+ final boolean mIsPredefined;
+ final int mSize;
+
+ public static final Element USER_U8 = new Element(0, 1);
+ public static final Element USER_I8 = new Element(1, 1);
+ public static final Element USER_U16 = new Element(2, 2);
+ public static final Element USER_I16 = new Element(3, 2);
+ public static final Element USER_U32 = new Element(4, 4);
+ public static final Element USER_I32 = new Element(5, 4);
+ public static final Element USER_FLOAT = new Element(6, 4);
+
+ public static final Element A_8 = new Element(7, 1);
+ public static final Element RGB_565 = new Element(8, 2);
+ public static final Element RGB_888 = new Element(11, 2);
+ public static final Element RGBA_5551 = new Element(9, 2);
+ public static final Element RGBA_4444 = new Element(10, 2);
+ public static final Element RGBA_8888 = new Element(12, 4);
+
+ public static final Element INDEX_16 = new Element(13, 2);
+ public static final Element INDEX_32 = new Element(14, 2);
+ public static final Element XY_F32 = new Element(15, 8);
+ public static final Element XYZ_F32 = new Element(16, 12);
+ public static final Element ST_XY_F32 = new Element(17, 16);
+ public static final Element ST_XYZ_F32 = new Element(18, 20);
+ public static final Element NORM_XYZ_F32 = new Element(19, 24);
+ public static final Element NORM_ST_XYZ_F32 = new Element(20, 32);
+
+ void initPredef(RenderScript rs) {
+ mID = rs.nElementGetPredefined(mPredefinedID);
+ }
+
+ static void init(RenderScript rs) {
+ USER_U8.initPredef(rs);
+ USER_I8.initPredef(rs);
+ USER_U16.initPredef(rs);
+ USER_I16.initPredef(rs);
+ USER_U32.initPredef(rs);
+ USER_I32.initPredef(rs);
+ USER_FLOAT.initPredef(rs);
+
+ A_8.initPredef(rs);
+ RGB_565.initPredef(rs);
+ RGB_888.initPredef(rs);
+ RGBA_5551.initPredef(rs);
+ RGBA_4444.initPredef(rs);
+ RGBA_8888.initPredef(rs);
+
+ INDEX_16.initPredef(rs);
+ INDEX_32.initPredef(rs);
+ XY_F32.initPredef(rs);
+ XYZ_F32.initPredef(rs);
+ ST_XY_F32.initPredef(rs);
+ ST_XYZ_F32.initPredef(rs);
+ NORM_XYZ_F32.initPredef(rs);
+ NORM_ST_XYZ_F32.initPredef(rs);
+ }
+
+
+ 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),
+ POINT_SIZE(19);
+
+ int mID;
+ DataKind(int id) {
+ mID = id;
+ }
+ }
+
+
+ Element(int predef, int size) {
+ super(null);
+ mID = 0;
+ mPredefinedID = predef;
+ mIsPredefined = true;
+ mSize = size;
+ }
+
+ Element(int id, RenderScript rs, int size) {
+ super(rs);
+ mID = id;
+ mPredefinedID = 0;
+ mIsPredefined = false;
+ mSize = size;
+ }
+
+ public void destroy() throws IllegalStateException {
+ if(mIsPredefined) {
+ throw new IllegalStateException("Attempting to destroy a predefined Element.");
+ }
+ super.destroy();
+ }
+
+ public static Element createFromClass(RenderScript rs, Class c) {
+ Field[] fields = c.getFields();
+ Builder b = new Builder(rs);
+
+ for(Field f: fields) {
+ Class fc = f.getType();
+ if(fc == int.class) {
+ b.add(Element.DataType.SIGNED, Element.DataKind.USER, false, 32, f.getName());
+ } else if(fc == short.class) {
+ b.add(Element.DataType.SIGNED, Element.DataKind.USER, false, 16, f.getName());
+ } else if(fc == byte.class) {
+ b.add(Element.DataType.SIGNED, Element.DataKind.USER, false, 8, f.getName());
+ } else if(fc == float.class) {
+ b.add(Element.DataType.FLOAT, Element.DataKind.USER, false, 32, f.getName());
+ } else {
+ throw new IllegalArgumentException("Unkown field type");
+ }
+ }
+ return b.create();
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Entry[] mEntries;
+ int mEntryCount;
+ int mSizeBits;
+
+ private class Entry {
+ Element mElement;
+ Element.DataType mType;
+ Element.DataKind mKind;
+ boolean mIsNormalized;
+ int mBits;
+ String mName;
+ }
+
+ public Builder(RenderScript rs) {
+ mRS = rs;
+ mEntryCount = 0;
+ mEntries = new Entry[8];
+ mSizeBits = 0;
+ }
+
+ void addEntry(Entry e) {
+ if(mEntries.length >= mEntryCount) {
+ Entry[] en = new Entry[mEntryCount + 8];
+ System.arraycopy(mEntries, 0, en, 0, mEntries.length);
+ mEntries = en;
+ }
+ mEntries[mEntryCount] = e;
+ mEntryCount++;
+ }
+
+ public Builder add(Element e) throws IllegalArgumentException {
+ if(!e.mIsPredefined) {
+ throw new IllegalArgumentException("add requires a predefined Element.");
+ }
+ Entry en = new Entry();
+ en.mElement = e;
+ addEntry(en);
+ mSizeBits += e.mSize * 8;
+ return this;
+ }
+
+ public Builder add(Element.DataType dt, Element.DataKind dk, boolean isNormalized, int bits, String name) {
+ Entry en = new Entry();
+ en.mType = dt;
+ en.mKind = dk;
+ en.mIsNormalized = isNormalized;
+ en.mBits = bits;
+ en.mName = name;
+ mSizeBits += bits;
+ addEntry(en);
+ return this;
+ }
+
+ public Builder add(Element.DataType dt, Element.DataKind dk, boolean isNormalized, int bits) {
+ add(dt, dk, isNormalized, bits, null);
+ return this;
+ }
+
+ public Builder addFloat(Element.DataKind dk) {
+ add(DataType.FLOAT, dk, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloat(Element.DataKind dk, String name) {
+ add(DataType.FLOAT, dk, false, 32, name);
+ return this;
+ }
+
+ public Builder addFloatXY() {
+ add(DataType.FLOAT, DataKind.X, false, 32, null);
+ add(DataType.FLOAT, DataKind.Y, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatXY(String prefix) {
+ add(DataType.FLOAT, DataKind.X, false, 32, prefix + "X");
+ add(DataType.FLOAT, DataKind.Y, false, 32, prefix + "Y");
+ return this;
+ }
+
+ public Builder addFloatXYZ() {
+ add(DataType.FLOAT, DataKind.X, false, 32, null);
+ add(DataType.FLOAT, DataKind.Y, false, 32, null);
+ add(DataType.FLOAT, DataKind.Z, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatXYZ(String prefix) {
+ add(DataType.FLOAT, DataKind.X, false, 32, prefix + "X");
+ add(DataType.FLOAT, DataKind.Y, false, 32, prefix + "Y");
+ add(DataType.FLOAT, DataKind.Z, false, 32, prefix + "Z");
+ return this;
+ }
+
+ public Builder addFloatST() {
+ add(DataType.FLOAT, DataKind.S, false, 32, null);
+ add(DataType.FLOAT, DataKind.T, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatST(String prefix) {
+ add(DataType.FLOAT, DataKind.S, false, 32, prefix + "S");
+ add(DataType.FLOAT, DataKind.T, false, 32, prefix + "T");
+ return this;
+ }
+
+ public Builder addFloatNorm() {
+ add(DataType.FLOAT, DataKind.NX, false, 32, null);
+ add(DataType.FLOAT, DataKind.NY, false, 32, null);
+ add(DataType.FLOAT, DataKind.NZ, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatNorm(String prefix) {
+ add(DataType.FLOAT, DataKind.NX, false, 32, prefix + "NX");
+ add(DataType.FLOAT, DataKind.NY, false, 32, prefix + "NY");
+ add(DataType.FLOAT, DataKind.NZ, false, 32, prefix + "NZ");
+ return this;
+ }
+
+ public Builder addFloatPointSize() {
+ add(DataType.FLOAT, DataKind.POINT_SIZE, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatPointSize(String name) {
+ add(DataType.FLOAT, DataKind.POINT_SIZE, false, 32, name);
+ return this;
+ }
+
+ public Builder addFloatRGB() {
+ add(DataType.FLOAT, DataKind.RED, false, 32, null);
+ add(DataType.FLOAT, DataKind.GREEN, false, 32, null);
+ add(DataType.FLOAT, DataKind.BLUE, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatRGB(String prefix) {
+ add(DataType.FLOAT, DataKind.RED, false, 32, prefix + "R");
+ add(DataType.FLOAT, DataKind.GREEN, false, 32, prefix + "G");
+ add(DataType.FLOAT, DataKind.BLUE, false, 32, prefix + "B");
+ return this;
+ }
+
+ public Builder addFloatRGBA() {
+ add(DataType.FLOAT, DataKind.RED, false, 32, null);
+ add(DataType.FLOAT, DataKind.GREEN, false, 32, null);
+ add(DataType.FLOAT, DataKind.BLUE, false, 32, null);
+ add(DataType.FLOAT, DataKind.ALPHA, false, 32, null);
+ return this;
+ }
+
+ public Builder addFloatRGBA(String prefix) {
+ add(DataType.FLOAT, DataKind.RED, false, 32, prefix + "R");
+ add(DataType.FLOAT, DataKind.GREEN, false, 32, prefix + "G");
+ add(DataType.FLOAT, DataKind.BLUE, false, 32, prefix + "B");
+ add(DataType.FLOAT, DataKind.ALPHA, false, 32, prefix + "A");
+ return this;
+ }
+
+ public Builder addUNorm8RGBA() {
+ add(DataType.UNSIGNED, DataKind.RED, true, 8, null);
+ add(DataType.UNSIGNED, DataKind.GREEN, true, 8, null);
+ add(DataType.UNSIGNED, DataKind.BLUE, true, 8, null);
+ add(DataType.UNSIGNED, DataKind.ALPHA, true, 8, null);
+ return this;
+ }
+
+ public Builder addUNorm8RGBA(String prefix) {
+ add(DataType.UNSIGNED, DataKind.RED, true, 8, prefix + "R");
+ add(DataType.UNSIGNED, DataKind.GREEN, true, 8, prefix + "G");
+ add(DataType.UNSIGNED, DataKind.BLUE, true, 8, prefix + "B");
+ add(DataType.UNSIGNED, DataKind.ALPHA, true, 8, prefix + "A");
+ return this;
+ }
+
+ static synchronized Element internalCreate(RenderScript rs, Builder b) {
+ rs.nElementBegin();
+ for (int ct=0; ct < b.mEntryCount; ct++) {
+ Entry en = b.mEntries[ct];
+ if(en.mElement != null) {
+ rs.nElementAddPredefined(en.mElement.mPredefinedID);
+ } else {
+ int norm = 0;
+ if (en.mIsNormalized) {
+ norm = 1;
+ }
+ rs.nElementAdd(en.mKind.mID, en.mType.mID, norm, en.mBits, en.mName);
+ }
+ }
+ int id = rs.nElementCreate();
+ return new Element(id, rs, (b.mSizeBits + 7) >> 3);
+ }
+
+ public Element create() {
+ return internalCreate(mRS, this);
+ }
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/Light.java b/graphics/java/android/renderscript/Light.java
new file mode 100644
index 0000000..115ae03
--- /dev/null
+++ b/graphics/java/android/renderscript/Light.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+public class Light extends BaseObj {
+ Light(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void setColor(float r, float g, float b) {
+ mRS.nLightSetColor(mID, r, g, b);
+ }
+
+ public void setPosition(float x, float y, float z) {
+ mRS.nLightSetPosition(mID, x, y, z);
+ }
+
+ public static class Builder {
+ RenderScript mRS;
+ boolean mIsMono;
+ boolean mIsLocal;
+
+ public Builder(RenderScript rs) {
+ mRS = rs;
+ mIsMono = false;
+ mIsLocal = false;
+ }
+
+ public void lightSetIsMono(boolean isMono) {
+ mIsMono = isMono;
+ }
+
+ public void lightSetIsLocal(boolean isLocal) {
+ mIsLocal = isLocal;
+ }
+
+ static synchronized Light internalCreate(RenderScript rs, Builder b) {
+ rs.nSamplerBegin();
+ rs.nLightSetIsMono(b.mIsMono);
+ rs.nLightSetIsLocal(b.mIsLocal);
+ int id = rs.nLightCreate();
+ return new Light(id, rs);
+ }
+
+ public Light create() {
+ return internalCreate(mRS, this);
+ }
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/Matrix.java b/graphics/java/android/renderscript/Matrix.java
new file mode 100644
index 0000000..a266d6b
--- /dev/null
+++ b/graphics/java/android/renderscript/Matrix.java
@@ -0,0 +1,192 @@
+/*
+ * 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.renderscript;
+
+import java.lang.Math;
+import android.util.Log;
+
+
+/**
+ * @hide
+ *
+ **/
+public class Matrix {
+
+ public Matrix() {
+ mMat = new float[16];
+ loadIdentity();
+ }
+
+ public float get(int i, int j) {
+ return mMat[i*4 + j];
+ }
+
+ public void set(int i, int j, float v) {
+ mMat[i*4 + j] = v;
+ }
+
+ public void loadIdentity() {
+ mMat[0] = 1;
+ mMat[1] = 0;
+ mMat[2] = 0;
+ mMat[3] = 0;
+
+ mMat[4] = 0;
+ mMat[5] = 1;
+ mMat[6] = 0;
+ mMat[7] = 0;
+
+ mMat[8] = 0;
+ mMat[9] = 0;
+ mMat[10] = 1;
+ mMat[11] = 0;
+
+ mMat[12] = 0;
+ mMat[13] = 0;
+ mMat[14] = 0;
+ mMat[15] = 1;
+ }
+
+ public void load(Matrix src) {
+ mMat = src.mMat;
+ }
+
+ public void loadRotate(float rot, float x, float y, float z) {
+ float c, s;
+ mMat[3] = 0;
+ mMat[7] = 0;
+ mMat[11]= 0;
+ mMat[12]= 0;
+ mMat[13]= 0;
+ mMat[14]= 0;
+ mMat[15]= 1;
+ rot *= (float)(java.lang.Math.PI / 180.0f);
+ c = (float)java.lang.Math.cos(rot);
+ s = (float)java.lang.Math.sin(rot);
+
+ float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z);
+ if (!(len != 1)) {
+ float recipLen = 1.f / len;
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ float nc = 1.0f - c;
+ float xy = x * y;
+ float yz = y * z;
+ float zx = z * x;
+ float xs = x * s;
+ float ys = y * s;
+ float zs = z * s;
+ mMat[ 0] = x*x*nc + c;
+ mMat[ 4] = xy*nc - zs;
+ mMat[ 8] = zx*nc + ys;
+ mMat[ 1] = xy*nc + zs;
+ mMat[ 5] = y*y*nc + c;
+ mMat[ 9] = yz*nc - xs;
+ mMat[ 2] = zx*nc - ys;
+ mMat[ 6] = yz*nc + xs;
+ mMat[10] = z*z*nc + c;
+ }
+
+ public void loadScale(float x, float y, float z) {
+ loadIdentity();
+ mMat[0] = x;
+ mMat[5] = y;
+ mMat[10] = z;
+ }
+
+ public void loadTranslate(float x, float y, float z) {
+ loadIdentity();
+ mMat[12] = x;
+ mMat[13] = y;
+ mMat[14] = z;
+ }
+
+ public void loadMultiply(Matrix lhs, 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++) {
+ 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);
+ }
+ }
+
+ public void loadOrtho(float l, float r, float b, float t, float n, float f) {
+ loadIdentity();
+ mMat[0] = 2 / (r - l);
+ mMat[5] = 2 / (t - b);
+ mMat[10]= -2 / (f - n);
+ mMat[12]= -(r + l) / (r - l);
+ mMat[13]= -(t + b) / (t - b);
+ mMat[14]= -(f + n) / (f - n);
+ }
+
+ public void loadFrustum(float l, float r, float b, float t, float n, float f) {
+ loadIdentity();
+ mMat[0] = 2 * n / (r - l);
+ mMat[5] = 2 * n / (t - b);
+ mMat[8] = (r + l) / (r - l);
+ mMat[9] = (t + b) / (t - b);
+ mMat[10]= -(f + n) / (f - n);
+ mMat[11]= -1;
+ mMat[14]= -2*f*n / (f - n);
+ mMat[15]= 0;
+ }
+
+ public void multiply(Matrix rhs) {
+ Matrix tmp = new Matrix();
+ tmp.loadMultiply(this, rhs);
+ load(tmp);
+ }
+ public void rotate(float rot, float x, float y, float z) {
+ Matrix tmp = new Matrix();
+ tmp.loadRotate(rot, x, y, z);
+ multiply(tmp);
+ }
+ public void scale(float x, float y, float z) {
+ Matrix tmp = new Matrix();
+ tmp.loadScale(x, y, z);
+ multiply(tmp);
+ }
+ public void translate(float x, float y, float z) {
+ Matrix tmp = new Matrix();
+ tmp.loadTranslate(x, y, z);
+ multiply(tmp);
+ }
+
+
+
+ float[] mMat;
+
+}
+
+
+
+
+
diff --git a/graphics/java/android/renderscript/Primitive.java b/graphics/java/android/renderscript/Primitive.java
new file mode 100644
index 0000000..7925cac
--- /dev/null
+++ b/graphics/java/android/renderscript/Primitive.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+/**
+ * @hide
+ **/
+public enum Primitive {
+ POINT (0),
+ LINE (1),
+ LINE_STRIP (2),
+ TRIANGLE (3),
+ TRIANGLE_STRIP (4),
+ TRIANGLE_FAN (5);
+
+ int mID;
+ Primitive(int id) {
+ mID = id;
+ }
+}
+
+
+
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
new file mode 100644
index 0000000..392d93d
--- /dev/null
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+
+import android.util.Config;
+import android.util.Log;
+
+
+/**
+ * @hide
+ *
+ **/
+public class ProgramFragment extends BaseObj {
+ public static final int MAX_SLOT = 2;
+
+ public enum EnvMode {
+ REPLACE (0),
+ MODULATE (1),
+ DECAL (2);
+
+ int mID;
+ EnvMode(int id) {
+ mID = id;
+ }
+ }
+
+
+ ProgramFragment(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void bindTexture(Allocation va, int slot)
+ throws IllegalArgumentException {
+ if((slot < 0) || (slot >= MAX_SLOT)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+
+ mRS.nProgramFragmentBindTexture(mID, slot, va.mID);
+ }
+
+ public void bindSampler(Sampler vs, int slot)
+ throws IllegalArgumentException {
+ if((slot < 0) || (slot >= MAX_SLOT)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+
+ mRS.nProgramFragmentBindSampler(mID, slot, vs.mID);
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Element mIn;
+ Element mOut;
+ boolean mPointSpriteEnable;
+
+ private class Slot {
+ Type mType;
+ EnvMode mEnv;
+ boolean mTexEnable;
+
+ Slot() {
+ mTexEnable = false;
+ }
+ }
+ Slot[] mSlots;
+
+ public Builder(RenderScript rs, Element in, Element out) {
+ mRS = rs;
+ mIn = in;
+ mOut = out;
+ mSlots = new Slot[MAX_SLOT];
+ mPointSpriteEnable = false;
+ for(int ct=0; ct < MAX_SLOT; ct++) {
+ mSlots[ct] = new Slot();
+ }
+ }
+
+ public void setType(int slot, Type t)
+ throws IllegalArgumentException {
+ if((slot < 0) || (slot >= MAX_SLOT)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+
+ mSlots[slot].mType = t;
+ }
+
+ public void setTexEnable(boolean enable, int slot)
+ throws IllegalArgumentException {
+ if((slot < 0) || (slot >= MAX_SLOT)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+
+ mSlots[slot].mTexEnable = enable;
+ }
+
+ public void setTexEnvMode(EnvMode env, int slot)
+ throws IllegalArgumentException {
+ if((slot < 0) || (slot >= MAX_SLOT)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+
+ mSlots[slot].mEnv = env;
+ }
+
+ public void setPointSpriteTexCoordinateReplacement(boolean enable) {
+ mPointSpriteEnable = enable;
+ }
+
+ static synchronized ProgramFragment internalCreate(RenderScript rs, Builder b) {
+ int inID = 0;
+ int outID = 0;
+ if (b.mIn != null) {
+ inID = b.mIn.mID;
+ }
+ if (b.mOut != null) {
+ outID = b.mOut.mID;
+ }
+ rs.nProgramFragmentBegin(inID, outID, b.mPointSpriteEnable);
+ for(int ct=0; ct < MAX_SLOT; ct++) {
+ if(b.mSlots[ct].mTexEnable) {
+ Slot s = b.mSlots[ct];
+ int typeID = 0;
+ if(s.mType != null) {
+ typeID = s.mType.mID;
+ }
+ rs.nProgramFragmentSetSlot(ct, true, s.mEnv.mID, typeID);
+ }
+ }
+
+ int id = rs.nProgramFragmentCreate();
+ return new ProgramFragment(id, rs);
+ }
+
+ public ProgramFragment create() {
+ return internalCreate(mRS, this);
+ }
+ }
+}
+
+
+
diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java
new file mode 100644
index 0000000..b7d987e
--- /dev/null
+++ b/graphics/java/android/renderscript/ProgramStore.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+
+import android.util.Config;
+import android.util.Log;
+
+
+/**
+ * @hide
+ *
+ **/
+public class ProgramStore extends BaseObj {
+ 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;
+ }
+ }
+
+
+ ProgramStore(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Element mIn;
+ Element mOut;
+ DepthFunc mDepthFunc;
+ boolean mDepthMask;
+ boolean mColorMaskR;
+ boolean mColorMaskG;
+ boolean mColorMaskB;
+ boolean mColorMaskA;
+ BlendSrcFunc mBlendSrc;
+ BlendDstFunc mBlendDst;
+ boolean mDither;
+
+
+
+ public Builder(RenderScript rs, Element in, Element out) {
+ mRS = rs;
+ mIn = in;
+ mOut = out;
+ mDepthFunc = DepthFunc.ALWAYS;
+ mDepthMask = false;
+ mColorMaskR = true;
+ mColorMaskG = true;
+ mColorMaskB = true;
+ mColorMaskA = true;
+ mBlendSrc = BlendSrcFunc.ONE;
+ mBlendDst = BlendDstFunc.ZERO;
+
+
+ }
+
+ public void setDepthFunc(DepthFunc func) {
+ mDepthFunc = func;
+ }
+
+ public void setDepthMask(boolean enable) {
+ mDepthMask = enable;
+ }
+
+ public void setColorMask(boolean r, boolean g, boolean b, boolean a) {
+ mColorMaskR = r;
+ mColorMaskG = g;
+ mColorMaskB = b;
+ mColorMaskA = a;
+ }
+
+ public void setBlendFunc(BlendSrcFunc src, BlendDstFunc dst) {
+ mBlendSrc = src;
+ mBlendDst = dst;
+ }
+
+ public void setDitherEnable(boolean enable) {
+ mDither = enable;
+ }
+
+ static synchronized ProgramStore internalCreate(RenderScript rs, Builder b) {
+ int inID = 0;
+ int outID = 0;
+ if (b.mIn != null) {
+ inID = b.mIn.mID;
+ }
+ if (b.mOut != null) {
+ outID = b.mOut.mID;
+ }
+ rs.nProgramFragmentStoreBegin(inID, outID);
+ rs.nProgramFragmentStoreDepthFunc(b.mDepthFunc.mID);
+ rs.nProgramFragmentStoreDepthMask(b.mDepthMask);
+ rs.nProgramFragmentStoreColorMask(b.mColorMaskR,
+ b.mColorMaskG,
+ b.mColorMaskB,
+ b.mColorMaskA);
+ rs.nProgramFragmentStoreBlendFunc(b.mBlendSrc.mID, b.mBlendDst.mID);
+ rs.nProgramFragmentStoreDither(b.mDither);
+
+ int id = rs.nProgramFragmentStoreCreate();
+ return new ProgramStore(id, rs);
+ }
+
+ public ProgramStore create() {
+ return internalCreate(mRS, this);
+ }
+ }
+
+}
+
+
+
+
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
new file mode 100644
index 0000000..2a11bfb
--- /dev/null
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+
+import android.util.Config;
+import android.util.Log;
+
+
+/**
+ * @hide
+ *
+ **/
+public class ProgramVertex extends BaseObj {
+ public static final int MAX_LIGHT = 8;
+
+ ProgramVertex(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void bindAllocation(MatrixAllocation va) {
+ mRS.nProgramVertexBindAllocation(mID, va.mAlloc.mID);
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Element mIn;
+ Element mOut;
+ Light[] mLights;
+ int mLightCount;
+ boolean mTextureMatrixEnable;
+
+
+ public Builder(RenderScript rs, Element in, Element out) {
+ mRS = rs;
+ mIn = in;
+ mOut = out;
+ mLights = new Light[MAX_LIGHT];
+ mLightCount = 0;
+ }
+
+ public void setTextureMatrixEnable(boolean enable) {
+ mTextureMatrixEnable = enable;
+ }
+
+ public void addLight(Light l) throws IllegalStateException {
+ if(mLightCount >= MAX_LIGHT) {
+ throw new IllegalArgumentException("Max light count exceeded.");
+ }
+ mLights[mLightCount] = l;
+ mLightCount++;
+ }
+
+
+
+ static synchronized ProgramVertex internalCreate(RenderScript rs, Builder b) {
+ int inID = 0;
+ int outID = 0;
+ if (b.mIn != null) {
+ inID = b.mIn.mID;
+ }
+ if (b.mOut != null) {
+ outID = b.mOut.mID;
+ }
+ rs.nProgramVertexBegin(inID, outID);
+ for(int ct=0; ct < b.mLightCount; ct++) {
+ rs.nProgramVertexAddLight(b.mLights[ct].mID);
+ }
+ rs.nProgramVertexSetTextureMatrixEnable(b.mTextureMatrixEnable);
+ int id = rs.nProgramVertexCreate();
+ return new ProgramVertex(id, rs);
+ }
+
+ public ProgramVertex create() {
+ return internalCreate(mRS, this);
+ }
+ }
+
+
+
+ public static class MatrixAllocation {
+ static final int MODELVIEW_OFFSET = 0;
+ static final int PROJECTION_OFFSET = 16;
+ static final int TEXTURE_OFFSET = 32;
+
+ Matrix mModel;
+ Matrix mProjection;
+ Matrix mTexture;
+
+ public Allocation mAlloc;
+
+ public MatrixAllocation(RenderScript rs) {
+ mModel = new Matrix();
+ mProjection = new Matrix();
+ mTexture = new Matrix();
+
+ mAlloc = Allocation.createSized(rs, Element.USER_FLOAT, 48);
+ mAlloc.subData1D(MODELVIEW_OFFSET, 16, mModel.mMat);
+ mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat);
+ mAlloc.subData1D(TEXTURE_OFFSET, 16, mTexture.mMat);
+ }
+
+ public void destroy() {
+ mAlloc.destroy();
+ mAlloc = null;
+ }
+
+ public void loadModelview(Matrix m) {
+ mModel = m;
+ mAlloc.subData1D(MODELVIEW_OFFSET, 16, m.mMat);
+ }
+
+ public void loadProjection(Matrix m) {
+ mProjection = m;
+ mAlloc.subData1D(PROJECTION_OFFSET, 16, m.mMat);
+ }
+
+ public void loadTexture(Matrix m) {
+ mTexture = m;
+ mAlloc.subData1D(TEXTURE_OFFSET, 16, m.mMat);
+ }
+
+ public void setupOrthoWindow(int w, int h) {
+ mProjection.loadOrtho(0,w, h,0, -1,1);
+ mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat);
+ }
+
+ public void setupOrthoNormalized(int w, int h) {
+ // range -1,1 in the narrow axis.
+ if(w > h) {
+ float aspect = ((float)w) / h;
+ mProjection.loadOrtho(-aspect,aspect, -1,1, -1,1);
+ } else {
+ float aspect = ((float)h) / w;
+ mProjection.loadOrtho(-1,1, -aspect,aspect, -1,1);
+ }
+ mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat);
+ }
+
+ public void setupProjectionNormalized(int w, int h) {
+ // range -1,1 in the narrow axis at z = 0.
+ Matrix m1 = new Matrix();
+ Matrix m2 = new Matrix();
+
+ if(w > h) {
+ float aspect = ((float)w) / h;
+ m1.loadFrustum(-aspect,aspect, -1,1, 1,100);
+ } else {
+ float aspect = ((float)h) / w;
+ m1.loadFrustum(-1,1, -aspect,aspect, 1,100);
+ }
+
+ m2.loadRotate(180, 0, 1, 0);
+ m1.loadMultiply(m1, m2);
+
+ m2.loadScale(-2, 2, 1);
+ m1.loadMultiply(m1, m2);
+
+ m2.loadTranslate(0, 0, 2);
+ m1.loadMultiply(m1, m2);
+
+ mProjection = m1;
+ mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat);
+ }
+
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/RSSurfaceView.java b/graphics/java/android/renderscript/RSSurfaceView.java
new file mode 100644
index 0000000..a3f1ded
--- /dev/null
+++ b/graphics/java/android/renderscript/RSSurfaceView.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.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;
+
+/**
+ * @hide
+ *
+ **/
+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(RenderScript.LOG_TAG, "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(RenderScript.LOG_TAG, "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);
+ }
+
+ /**
+ * 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(RenderScript.LOG_TAG, "surfaceCreated");
+ mSurfaceHolder = holder;
+ }
+
+ /**
+ * 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(RenderScript.LOG_TAG, "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(RenderScript.LOG_TAG, "surfaceChanged");
+ }
+
+ /**
+ * 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(RenderScript.LOG_TAG, "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(RenderScript.LOG_TAG, "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(RenderScript.LOG_TAG, "queueEvent");
+ }
+
+ /**
+ * 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();
+ }
+
+ // ----------------------------------------------------------------------
+
+ public RenderScript createRenderScript(boolean useDepth) {
+ Surface sur = null;
+ while ((sur == null) || (mSurfaceHolder == null)) {
+ sur = getHolder().getSurface();
+ }
+ RenderScript rs = new RenderScript(sur, useDepth);
+ return rs;
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
new file mode 100644
index 0000000..0f188f6
--- /dev/null
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.lang.reflect.Field;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.Config;
+import android.util.Log;
+import android.view.Surface;
+
+
+/**
+ * @hide
+ *
+ **/
+public class RenderScript {
+ static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ @SuppressWarnings({"UnusedDeclaration", "deprecation"})
+ 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.
+ */
+ @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
+ 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 int nDeviceCreate();
+ native void nDeviceDestroy(int dev);
+ native int nContextCreate(int dev, Surface sur, int ver, boolean useDepth);
+ native void nContextDestroy(int con);
+
+ //void rsContextBindSampler (uint32_t slot, RsSampler sampler);
+ //void rsContextBindRootScript (RsScript sampler);
+ native void nContextBindRootScript(int script);
+ native void nContextBindSampler(int sampler, int slot);
+ native void nContextBindProgramFragmentStore(int pfs);
+ native void nContextBindProgramFragment(int pf);
+ native void nContextBindProgramVertex(int pf);
+ native void nContextAddDefineI32(String name, int value);
+ native void nContextAddDefineF(String name, float value);
+
+ native void nAssignName(int obj, byte[] name);
+ native void nObjDestroy(int id);
+ native void nObjDestroyOOB(int id);
+ native int nFileOpen(byte[] name);
+
+ native void nElementBegin();
+ native void nElementAddPredefined(int predef);
+ native void nElementAdd(int kind, int type, int norm, int bits, String s);
+ native int nElementCreate();
+ native int nElementGetPredefined(int predef);
+
+ native void nTypeBegin(int elementID);
+ native void nTypeAdd(int dim, int val);
+ native int nTypeCreate();
+ native void nTypeFinalDestroy(Type t);
+ native void nTypeSetupFields(Type t, int[] types, int[] bits, Field[] IDs);
+
+ native int nAllocationCreateTyped(int type);
+ native int nAllocationCreatePredefSized(int predef, int count);
+ native int nAllocationCreateSized(int elem, int count);
+ native int nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp);
+ native int nAllocationCreateFromBitmapBoxed(int dstFmt, boolean genMips, Bitmap bmp);
+ native int nAllocationCreateFromAssetStream(int dstFmt, boolean genMips, int assetStream);
+
+ native void nAllocationUploadToTexture(int alloc, int baseMioLevel);
+ native void nAllocationUploadToBufferObject(int alloc);
+ native void nAllocationData(int id, int[] d, int sizeBytes);
+ native void nAllocationData(int id, float[] d, int sizeBytes);
+ native void nAllocationSubData1D(int id, int off, int count, int[] d, int sizeBytes);
+ native void nAllocationSubData1D(int id, int off, int count, float[] d, int sizeBytes);
+ native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, int[] d, int sizeBytes);
+ native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, float[] d, int sizeBytes);
+ native void nAllocationRead(int id, int[] d);
+ native void nAllocationRead(int id, float[] d);
+ native void nAllocationDataFromObject(int id, Type t, Object o);
+
+ native void nTriangleMeshBegin(int vertex, int index);
+ native void nTriangleMeshAddVertex_XY (float x, float y);
+ native void nTriangleMeshAddVertex_XYZ (float x, float y, float z);
+ native void nTriangleMeshAddVertex_XY_ST (float x, float y, float s, float t);
+ native void nTriangleMeshAddVertex_XYZ_ST (float x, float y, float z, float s, float t);
+ native void nTriangleMeshAddVertex_XYZ_ST_NORM (float x, float y, float z, float s, float t, float nx, float ny, float nz);
+ native void nTriangleMeshAddTriangle(int i1, int i2, int i3);
+ native int nTriangleMeshCreate();
+
+ native void nAdapter1DBindAllocation(int ad, int alloc);
+ native void nAdapter1DSetConstraint(int ad, int dim, int value);
+ native void nAdapter1DData(int ad, int[] d);
+ native void nAdapter1DData(int ad, float[] d);
+ native void nAdapter1DSubData(int ad, int off, int count, int[] d);
+ native void nAdapter1DSubData(int ad, int off, int count, float[] d);
+ native int nAdapter1DCreate();
+
+ native void nAdapter2DBindAllocation(int ad, int alloc);
+ native void nAdapter2DSetConstraint(int ad, int dim, int value);
+ native void nAdapter2DData(int ad, int[] d);
+ native void nAdapter2DData(int ad, float[] d);
+ native void nAdapter2DSubData(int ad, int xoff, int yoff, int w, int h, int[] d);
+ native void nAdapter2DSubData(int ad, int xoff, int yoff, int w, int h, float[] d);
+ native int nAdapter2DCreate();
+
+ native void nScriptBindAllocation(int script, int alloc, int slot);
+ native void nScriptSetClearColor(int script, float r, float g, float b, float a);
+ native void nScriptSetClearDepth(int script, float depth);
+ native void nScriptSetClearStencil(int script, int stencil);
+ native void nScriptSetTimeZone(int script, byte[] timeZone);
+ native void nScriptSetType(int type, boolean writable, String name, int slot);
+ native void nScriptSetRoot(boolean isRoot);
+
+ native void nScriptCBegin();
+ native void nScriptCSetScript(byte[] script, int offset, int length);
+ native int nScriptCCreate();
+ native void nScriptCAddDefineI32(String name, int value);
+ native void nScriptCAddDefineF(String name, float value);
+
+ native void nSamplerBegin();
+ native void nSamplerSet(int param, int value);
+ native int nSamplerCreate();
+
+ native void nProgramFragmentStoreBegin(int in, int out);
+ native void nProgramFragmentStoreDepthFunc(int func);
+ native void nProgramFragmentStoreDepthMask(boolean enable);
+ native void nProgramFragmentStoreColorMask(boolean r, boolean g, boolean b, boolean a);
+ native void nProgramFragmentStoreBlendFunc(int src, int dst);
+ native void nProgramFragmentStoreDither(boolean enable);
+ native int nProgramFragmentStoreCreate();
+
+ native void nProgramFragmentBegin(int in, int out, boolean pointSpriteEnable);
+ native void nProgramFragmentBindTexture(int vpf, int slot, int a);
+ native void nProgramFragmentBindSampler(int vpf, int slot, int s);
+ native void nProgramFragmentSetSlot(int slot, boolean enable, int env, int vt);
+ native int nProgramFragmentCreate();
+
+ native void nProgramVertexBindAllocation(int pv, int mID);
+ native void nProgramVertexBegin(int inID, int outID);
+ native void nProgramVertexSetTextureMatrixEnable(boolean enable);
+ native void nProgramVertexAddLight(int id);
+ native int nProgramVertexCreate();
+
+ native void nLightBegin();
+ native void nLightSetIsMono(boolean isMono);
+ native void nLightSetIsLocal(boolean isLocal);
+ native int nLightCreate();
+ native void nLightSetColor(int l, float r, float g, float b);
+ native void nLightSetPosition(int l, float x, float y, float z);
+
+ native int nSimpleMeshCreate(int batchID, int idxID, int[] vtxID, int prim);
+ native void nSimpleMeshBindVertex(int id, int alloc, int slot);
+ native void nSimpleMeshBindIndex(int id, int alloc);
+
+ native void nAnimationBegin(int attribCount, int keyframeCount);
+ native void nAnimationAdd(float time, float[] attribs);
+ native int nAnimationCreate();
+
+ private int mDev;
+ private int mContext;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private Surface mSurface;
+
+ private static boolean mElementsInitialized = false;
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ //
+
+ public RenderScript(Surface sur, boolean useDepth) {
+ mSurface = sur;
+ mDev = nDeviceCreate();
+ mContext = nContextCreate(mDev, mSurface, 0, useDepth);
+
+ // TODO: This should be protected by a lock
+ if(!mElementsInitialized) {
+ Element.init(this);
+ mElementsInitialized = true;
+ }
+ }
+
+ public void destroy() {
+ nContextDestroy(mContext);
+ mContext = 0;
+
+ nDeviceDestroy(mDev);
+ mDev = 0;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // Triangle Mesh
+
+ public class TriangleMesh extends BaseObj {
+ TriangleMesh(int id) {
+ super(RenderScript.this);
+ mID = id;
+ }
+ }
+
+ public void triangleMeshBegin(Element vertex, Element index) {
+ Log.e("rs", "vtx " + vertex.toString() + " " + vertex.mID + " " + vertex.mPredefinedID);
+ 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 triangleMeshAddVertex_XYZ_ST_NORM(float x, float y, float z, float s, float t, float nx, float ny, float nz) {
+ nTriangleMeshAddVertex_XYZ_ST_NORM(x, y, z, s, t, nx, ny, nz);
+ }
+
+ public void triangleMeshAddTriangle(int i1, int i2, int i3) {
+ nTriangleMeshAddTriangle(i1, i2, i3);
+ }
+
+ public TriangleMesh triangleMeshCreate() {
+ int id = nTriangleMeshCreate();
+ return new TriangleMesh(id);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // File
+
+ public class File extends BaseObj {
+ File(int id) {
+ super(RenderScript.this);
+ mID = id;
+ }
+ }
+
+ public File fileOpen(String s) throws IllegalStateException, IllegalArgumentException
+ {
+ if(s.length() < 1) {
+ throw new IllegalArgumentException("fileOpen does not accept a zero length string.");
+ }
+
+ try {
+ byte[] bytes = s.getBytes("UTF-8");
+ int id = nFileOpen(bytes);
+ return new File(id);
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////
+ // Root state
+
+ public void contextBindRootScript(Script s) {
+ int id = 0;
+ if(s != null) {
+ id = s.mID;
+ }
+ nContextBindRootScript(id);
+ }
+
+ //public void contextBindSampler(Sampler s, int slot) {
+ //nContextBindSampler(s.mID);
+ //}
+
+ public void contextBindProgramFragmentStore(ProgramStore pfs) {
+ nContextBindProgramFragmentStore(pfs.mID);
+ }
+
+ public void contextBindProgramFragment(ProgramFragment pf) {
+ nContextBindProgramFragment(pf.mID);
+ }
+
+ public void contextBindProgramVertex(ProgramVertex pf) {
+ nContextBindProgramVertex(pf.mID);
+ }
+
+}
+
+
diff --git a/graphics/java/android/renderscript/Sampler.java b/graphics/java/android/renderscript/Sampler.java
new file mode 100644
index 0000000..5e0b110
--- /dev/null
+++ b/graphics/java/android/renderscript/Sampler.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.Config;
+import android.util.Log;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+/**
+ * @hide
+ *
+ **/
+public class Sampler extends BaseObj {
+ public enum Value {
+ NEAREST (0),
+ LINEAR (1),
+ LINEAR_MIP_LINEAR (2),
+ WRAP (3),
+ CLAMP (4);
+
+ int mID;
+ Value(int id) {
+ mID = id;
+ }
+ }
+
+ Sampler(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public static class Builder {
+ RenderScript mRS;
+ Value mMin;
+ Value mMag;
+ Value mWrapS;
+ Value mWrapT;
+ Value mWrapR;
+
+ public Builder(RenderScript rs) {
+ mRS = rs;
+ mMin = Value.NEAREST;
+ mMag = Value.NEAREST;
+ mWrapS = Value.WRAP;
+ mWrapT = Value.WRAP;
+ mWrapR = Value.WRAP;
+ }
+
+ public void setMin(Value v) {
+ mMin = v;
+ }
+
+ public void setMag(Value v) {
+ mMag = v;
+ }
+
+ public void setWrapS(Value v) {
+ mWrapS = v;
+ }
+
+ public void setWrapT(Value v) {
+ mWrapT = v;
+ }
+
+ public void setWrapR(Value v) {
+ mWrapR = v;
+ }
+
+ static synchronized Sampler internalCreate(RenderScript rs, Builder b) {
+ rs.nSamplerBegin();
+ rs.nSamplerSet(0, b.mMin.mID);
+ rs.nSamplerSet(1, b.mMag.mID);
+ rs.nSamplerSet(2, b.mWrapS.mID);
+ rs.nSamplerSet(3, b.mWrapT.mID);
+ rs.nSamplerSet(4, b.mWrapR.mID);
+ int id = rs.nSamplerCreate();
+ return new Sampler(id, rs);
+ }
+
+ public Sampler create() {
+ return internalCreate(mRS, this);
+ }
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
new file mode 100644
index 0000000..a402471
--- /dev/null
+++ b/graphics/java/android/renderscript/Script.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+/**
+ * @hide
+ **/
+public class Script extends BaseObj {
+ public static final int MAX_SLOT = 16;
+
+ boolean mIsRoot;
+ Type[] mTypes;
+ boolean[] mWritable;
+
+ Script(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void bindAllocation(Allocation va, int slot) {
+ mRS.nScriptBindAllocation(mID, va.mID, slot);
+ }
+
+ public void setClearColor(float r, float g, float b, float a) {
+ mRS.nScriptSetClearColor(mID, r, g, b, a);
+ }
+
+ public void setClearDepth(float d) {
+ mRS.nScriptSetClearDepth(mID, d);
+ }
+
+ public void setClearStencil(int stencil) {
+ mRS.nScriptSetClearStencil(mID, stencil);
+ }
+
+ public void setTimeZone(String timeZone) {
+ try {
+ mRS.nScriptSetTimeZone(mID, timeZone.getBytes("UTF-8"));
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static class Builder {
+ RenderScript mRS;
+ boolean mIsRoot = false;
+ Type[] mTypes;
+ String[] mNames;
+ boolean[] mWritable;
+
+ Builder(RenderScript rs) {
+ mRS = rs;
+ mTypes = new Type[MAX_SLOT];
+ mNames = new String[MAX_SLOT];
+ mWritable = new boolean[MAX_SLOT];
+ }
+
+ public void setType(Type t, int slot) {
+ mTypes[slot] = t;
+ mNames[slot] = null;
+ }
+
+ public void setType(Type t, String name, int slot) {
+ mTypes[slot] = t;
+ mNames[slot] = name;
+ }
+
+ public void setType(boolean writable, int slot) {
+ mWritable[slot] = writable;
+ }
+
+ void transferCreate() {
+ mRS.nScriptSetRoot(mIsRoot);
+ for(int ct=0; ct < mTypes.length; ct++) {
+ if(mTypes[ct] != null) {
+ mRS.nScriptSetType(mTypes[ct].mID, mWritable[ct], mNames[ct], ct);
+ }
+ }
+ }
+
+ void transferObject(Script s) {
+ s.mIsRoot = mIsRoot;
+ s.mTypes = mTypes;
+ }
+
+ public void setRoot(boolean r) {
+ mIsRoot = r;
+ }
+
+ }
+
+}
+
diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java
new file mode 100644
index 0000000..bb99e23
--- /dev/null
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map.Entry;
+import java.util.HashMap;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * @hide
+ **/
+public class ScriptC extends Script {
+ private static final String TAG = "ScriptC";
+
+ ScriptC(int id, RenderScript rs) {
+ super(id, rs);
+ }
+
+ public static class Builder extends Script.Builder {
+ byte[] mProgram;
+ int mProgramLength;
+ HashMap<String,Integer> mIntDefines = new HashMap();
+ HashMap<String,Float> mFloatDefines = new HashMap();
+
+ public Builder(RenderScript rs) {
+ super(rs);
+ }
+
+ public void setScript(String s) {
+ try {
+ mProgram = s.getBytes("UTF-8");
+ mProgramLength = mProgram.length;
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setScript(Resources resources, int id) {
+ InputStream is = resources.openRawResource(id);
+ try {
+ try {
+ setScript(is);
+ } finally {
+ is.close();
+ }
+ } catch(IOException e) {
+ throw new Resources.NotFoundException();
+ }
+ }
+
+ public void setScript(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;
+ }
+ mProgram = buf;
+ mProgramLength = currentPos;
+ }
+
+ static synchronized ScriptC internalCreate(Builder b) {
+ b.mRS.nScriptCBegin();
+ b.transferCreate();
+
+ for (Entry<String,Integer> e: b.mIntDefines.entrySet()) {
+ b.mRS.nScriptCAddDefineI32(e.getKey(), e.getValue().intValue());
+ }
+ for (Entry<String,Float> e: b.mFloatDefines.entrySet()) {
+ b.mRS.nScriptCAddDefineF(e.getKey(), e.getValue().floatValue());
+ }
+
+ b.mRS.nScriptCSetScript(b.mProgram, 0, b.mProgramLength);
+
+ int id = b.mRS.nScriptCCreate();
+ ScriptC obj = new ScriptC(id, b.mRS);
+ b.transferObject(obj);
+
+ return obj;
+ }
+
+ public void addDefine(String name, int value) {
+ mIntDefines.put(name, value);
+ }
+
+ public void addDefine(String name, float value) {
+ mFloatDefines.put(name, value);
+ }
+
+ /**
+ * Takes the all public static final fields for a class, and adds defines
+ * for them, using the name of the field as the name of the define.
+ */
+ public void addDefines(Class cl) {
+ addDefines(cl.getFields(), (Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC), null);
+ }
+
+ /**
+ * Takes the all public fields for an object, and adds defines
+ * for them, using the name of the field as the name of the define.
+ */
+ public void addDefines(Object o) {
+ addDefines(o.getClass().getFields(), Modifier.PUBLIC, o);
+ }
+
+ void addDefines(Field[] fields, int mask, Object o) {
+ for (Field f: fields) {
+ try {
+ if ((f.getModifiers() & mask) == mask) {
+ Class t = f.getType();
+ if (t == int.class) {
+ mIntDefines.put(f.getName(), f.getInt(o));
+ }
+ else if (t == float.class) {
+ mFloatDefines.put(f.getName(), f.getFloat(o));
+ }
+ }
+ } catch (IllegalAccessException ex) {
+ // TODO: Do we want this log?
+ Log.d(TAG, "addDefines skipping field " + f.getName());
+ }
+ }
+ }
+
+ public ScriptC create() {
+ return internalCreate(this);
+ }
+ }
+}
+
diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java
new file mode 100644
index 0000000..e66fb8a
--- /dev/null
+++ b/graphics/java/android/renderscript/SimpleMesh.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+public class SimpleMesh extends BaseObj {
+ Type[] mVertexTypes;
+ Type mIndexType;
+ //Type mBatcheType;
+ Primitive mPrimitive;
+
+ SimpleMesh(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ }
+
+ public void bindVertexAllocation(Allocation a, int slot) {
+ mRS.nSimpleMeshBindVertex(mID, a.mID, slot);
+ }
+
+ public void bindIndexAllocation(Allocation a) {
+ mRS.nSimpleMeshBindIndex(mID, a.mID);
+ }
+
+ public Allocation createVertexAllocation(int slot) {
+ return Allocation.createTyped(mRS, mVertexTypes[slot]);
+ }
+
+ public Allocation createIndexAllocation() {
+ return Allocation.createTyped(mRS, mIndexType);
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+
+ class Entry {
+ Type t;
+ Element e;
+ int size;
+ }
+
+ int mVertexTypeCount;
+ Entry[] mVertexTypes;
+ Entry mIndexType;
+ //Entry mBatchType;
+ Primitive mPrimitive;
+
+
+ public Builder(RenderScript rs) {
+ mRS = rs;
+ mVertexTypeCount = 0;
+ mVertexTypes = new Entry[16];
+ mIndexType = new Entry();
+ }
+
+ public int addVertexType(Type t) throws IllegalStateException {
+ if(mVertexTypeCount >= mVertexTypes.length) {
+ throw new IllegalStateException("Max vertex types exceeded.");
+ }
+
+ int addedIndex = mVertexTypeCount;
+ mVertexTypes[mVertexTypeCount] = new Entry();
+ mVertexTypes[mVertexTypeCount].t = t;
+ mVertexTypeCount++;
+ return addedIndex;
+ }
+
+ public int addVertexType(Element e, int size) throws IllegalStateException {
+ if(mVertexTypeCount >= mVertexTypes.length) {
+ throw new IllegalStateException("Max vertex types exceeded.");
+ }
+
+ int addedIndex = mVertexTypeCount;
+ mVertexTypes[mVertexTypeCount] = new Entry();
+ mVertexTypes[mVertexTypeCount].e = e;
+ mVertexTypes[mVertexTypeCount].size = size;
+ mVertexTypeCount++;
+ return addedIndex;
+ }
+
+ public void setIndexType(Type t) {
+ mIndexType.t = t;
+ mIndexType.e = null;
+ mIndexType.size = 0;
+ }
+
+ public void setIndexType(Element e, int size) {
+ mIndexType.t = null;
+ mIndexType.e = e;
+ mIndexType.size = size;
+ }
+
+ public void setPrimitive(Primitive p) {
+ mPrimitive = p;
+ }
+
+
+ Type newType(Element e, int size) {
+ Type.Builder tb = new Type.Builder(mRS, e);
+ tb.add(Dimension.X, size);
+ return tb.create();
+ }
+
+ static synchronized SimpleMesh internalCreate(RenderScript rs, Builder b) {
+ Type[] toDestroy = new Type[18];
+ int toDestroyCount = 0;
+
+ int indexID = 0;
+ if(b.mIndexType.t != null) {
+ indexID = b.mIndexType.t.mID;
+ } else if(b.mIndexType.size != 0) {
+ b.mIndexType.t = b.newType(b.mIndexType.e, b.mIndexType.size);
+ indexID = b.mIndexType.t.mID;
+ toDestroy[toDestroyCount++] = b.mIndexType.t;
+ }
+
+ int[] IDs = new int[b.mVertexTypeCount];
+ for(int ct=0; ct < b.mVertexTypeCount; ct++) {
+ if(b.mVertexTypes[ct].t != null) {
+ IDs[ct] = b.mVertexTypes[ct].t.mID;
+ } else {
+ b.mVertexTypes[ct].t = b.newType(b.mVertexTypes[ct].e, b.mVertexTypes[ct].size);
+ IDs[ct] = b.mVertexTypes[ct].t.mID;
+ toDestroy[toDestroyCount++] = b.mVertexTypes[ct].t;
+ }
+ }
+
+ int id = rs.nSimpleMeshCreate(0, indexID, IDs, b.mPrimitive.mID);
+ for(int ct=0; ct < toDestroyCount; ct++) {
+ toDestroy[ct].destroy();
+ }
+
+ return new SimpleMesh(id, rs);
+ }
+
+ public SimpleMesh create() {
+ Log.e("rs", "SimpleMesh create");
+ SimpleMesh sm = internalCreate(mRS, this);
+ sm.mVertexTypes = new Type[mVertexTypeCount];
+ for(int ct=0; ct < mVertexTypeCount; ct++) {
+ sm.mVertexTypes[ct] = mVertexTypes[ct].t;
+ }
+ sm.mIndexType = mIndexType.t;
+ sm.mPrimitive = mPrimitive;
+ return sm;
+ }
+ }
+
+ public static class TriangleMeshBuilder {
+ float mVtxData[];
+ int mVtxCount;
+ int mIndexData[];
+ int mIndexCount;
+ RenderScript mRS;
+ Element mElement;
+
+ int mVtxSize;
+ boolean mNorm;
+ boolean mTex;
+
+ public TriangleMeshBuilder(RenderScript rs, int vtxSize, boolean norm, boolean tex) {
+ mRS = rs;
+ mVtxCount = 0;
+ mIndexCount = 0;
+ mVtxData = new float[128];
+ mIndexData = new int[128];
+ mVtxSize = vtxSize;
+ mNorm = norm;
+ mTex = tex;
+
+ if(vtxSize < 2 || vtxSize > 3) {
+ throw new IllegalArgumentException("Vertex size out of range.");
+ }
+ }
+
+ private void makeSpace(int count) {
+ if((mVtxCount + count) >= mVtxData.length) {
+ float t[] = new float[mVtxData.length * 2];
+ System.arraycopy(mVtxData, 0, t, 0, mVtxData.length);
+ mVtxData = t;
+ }
+ }
+
+ public void add_XY(float x, float y) {
+ if((mVtxSize != 2) || mNorm || mTex) {
+ throw new IllegalStateException("add mistmatch with declaired components.");
+ }
+ makeSpace(2);
+ mVtxData[mVtxCount++] = x;
+ mVtxData[mVtxCount++] = y;
+ }
+
+ public void add_XYZ(float x, float y, float z) {
+ if((mVtxSize != 3) || mNorm || mTex) {
+ throw new IllegalStateException("add mistmatch with declaired components.");
+ }
+ makeSpace(3);
+ mVtxData[mVtxCount++] = x;
+ mVtxData[mVtxCount++] = y;
+ mVtxData[mVtxCount++] = z;
+ }
+
+ public void add_XY_ST(float x, float y, float s, float t) {
+ if((mVtxSize != 2) || mNorm || !mTex) {
+ throw new IllegalStateException("add mistmatch with declaired components.");
+ }
+ makeSpace(4);
+ mVtxData[mVtxCount++] = x;
+ mVtxData[mVtxCount++] = y;
+ mVtxData[mVtxCount++] = s;
+ mVtxData[mVtxCount++] = t;
+ }
+
+ public void add_XYZ_ST(float x, float y, float z, float s, float t) {
+ if((mVtxSize != 3) || mNorm || !mTex) {
+ throw new IllegalStateException("add mistmatch with declaired components.");
+ }
+ makeSpace(5);
+ mVtxData[mVtxCount++] = x;
+ mVtxData[mVtxCount++] = y;
+ mVtxData[mVtxCount++] = z;
+ mVtxData[mVtxCount++] = s;
+ mVtxData[mVtxCount++] = t;
+ }
+
+ public void add_XYZ_ST_NORM(float x, float y, float z, float s, float t, float nx, float ny, float nz) {
+ if((mVtxSize != 3) || !mNorm || !mTex) {
+ throw new IllegalStateException("add mistmatch with declaired components.");
+ }
+ makeSpace(8);
+ mVtxData[mVtxCount++] = x;
+ mVtxData[mVtxCount++] = y;
+ mVtxData[mVtxCount++] = z;
+ mVtxData[mVtxCount++] = s;
+ mVtxData[mVtxCount++] = t;
+ mVtxData[mVtxCount++] = nx;
+ mVtxData[mVtxCount++] = ny;
+ mVtxData[mVtxCount++] = nz;
+ }
+
+ public void addTriangle(int idx1, int idx2, int idx3) {
+ if((mIndexCount + 3) >= mIndexData.length) {
+ int t[] = new int[mIndexData.length * 2];
+ System.arraycopy(mIndexData, 0, t, 0, mIndexData.length);
+ mIndexData = t;
+ }
+ mIndexData[mIndexCount++] = idx1;
+ mIndexData[mIndexCount++] = idx2;
+ mIndexData[mIndexCount++] = idx3;
+ }
+
+ public SimpleMesh create() {
+ Element.Builder b = new Element.Builder(mRS);
+ int floatCount = mVtxSize;
+ if(mVtxSize == 2) {
+ b.addFloatXY();
+ } else {
+ b.addFloatXYZ();
+ }
+ if(mTex) {
+ floatCount += 2;
+ b.addFloatST();
+ }
+ if(mNorm) {
+ floatCount += 3;
+ b.addFloatNorm();
+ }
+ mElement = b.create();
+
+ Builder smb = new Builder(mRS);
+ smb.addVertexType(mElement, mVtxCount / floatCount);
+ smb.setIndexType(Element.INDEX_16, mIndexCount);
+ smb.setPrimitive(Primitive.TRIANGLE);
+ SimpleMesh sm = smb.create();
+
+ Allocation vertexAlloc = sm.createVertexAllocation(0);
+ Allocation indexAlloc = sm.createIndexAllocation();
+ sm.bindVertexAllocation(vertexAlloc, 0);
+ sm.bindIndexAllocation(indexAlloc);
+
+ vertexAlloc.data(mVtxData);
+ vertexAlloc.uploadToBufferObject();
+
+ // This is safe because length is a pow2
+ for(int ct=0; ct < (mIndexCount+1); ct += 2) {
+ mIndexData[ct >> 1] = mIndexData[ct] | (mIndexData[ct+1] << 16);
+ }
+ indexAlloc.data(mIndexData);
+ indexAlloc.uploadToBufferObject();
+
+ return sm;
+ }
+ }
+}
+
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
new file mode 100644
index 0000000..b6b7adf
--- /dev/null
+++ b/graphics/java/android/renderscript/Type.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.lang.reflect.Field;
+
+/**
+ * @hide
+ *
+ **/
+public class Type extends BaseObj {
+ Dimension[] mDimensions;
+ int[] mValues;
+ Element mElement;
+ private int mNativeCache;
+ Class mJavaClass;
+
+
+ Type(int id, RenderScript rs) {
+ super(rs);
+ mID = id;
+ mNativeCache = 0;
+ }
+
+ protected void finalize() throws Throwable {
+ if(mNativeCache != 0) {
+ mRS.nTypeFinalDestroy(this);
+ mNativeCache = 0;
+ }
+ super.finalize();
+ }
+
+ public static Type createFromClass(RenderScript rs, Class c, int size) {
+ Element e = Element.createFromClass(rs, c);
+ Builder b = new Builder(rs, e);
+ b.add(Dimension.X, size);
+ Type t = b.create();
+ e.destroy();
+
+ // native fields
+ {
+ Field[] fields = c.getFields();
+ int[] arTypes = new int[fields.length];
+ int[] arBits = new int[fields.length];
+
+ for(int ct=0; ct < fields.length; ct++) {
+ Field f = fields[ct];
+ Class fc = f.getType();
+ if(fc == int.class) {
+ arTypes[ct] = Element.DataType.SIGNED.mID;
+ arBits[ct] = 32;
+ } else if(fc == short.class) {
+ arTypes[ct] = Element.DataType.SIGNED.mID;
+ arBits[ct] = 16;
+ } else if(fc == byte.class) {
+ arTypes[ct] = Element.DataType.SIGNED.mID;
+ arBits[ct] = 8;
+ } else if(fc == float.class) {
+ arTypes[ct] = Element.DataType.FLOAT.mID;
+ arBits[ct] = 32;
+ } else {
+ throw new IllegalArgumentException("Unkown field type");
+ }
+ }
+ rs.nTypeSetupFields(t, arTypes, arBits, fields);
+ }
+ t.mJavaClass = c;
+ return t;
+ }
+
+ public static Type createFromClass(RenderScript rs, Class c, int size, String scriptName) {
+ Type t = createFromClass(rs, c, size);
+ t.setName(scriptName);
+ return t;
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Entry[] mEntries;
+ int mEntryCount;
+ Element mElement;
+
+ class Entry {
+ Dimension mDim;
+ int mValue;
+ }
+
+ public Builder(RenderScript rs, Element e) {
+ mRS = rs;
+ mEntries = new Entry[4];
+ mElement = e;
+ }
+
+ public void add(Dimension d, int value) {
+ if(mEntries.length >= mEntryCount) {
+ Entry[] en = new Entry[mEntryCount + 8];
+ System.arraycopy(mEntries, 0, en, 0, mEntries.length);
+ mEntries = en;
+ }
+ mEntries[mEntryCount] = new Entry();
+ mEntries[mEntryCount].mDim = d;
+ mEntries[mEntryCount].mValue = value;
+ mEntryCount++;
+ }
+
+ static synchronized Type internalCreate(RenderScript rs, Builder b) {
+ rs.nTypeBegin(b.mElement.mID);
+ for (int ct=0; ct < b.mEntryCount; ct++) {
+ Entry en = b.mEntries[ct];
+ rs.nTypeAdd(en.mDim.mID, en.mValue);
+ }
+ int id = rs.nTypeCreate();
+ return new Type(id, rs);
+ }
+
+ public Type create() {
+ Type t = internalCreate(mRS, this);
+ t.mElement = mElement;
+ t.mDimensions = new Dimension[mEntryCount];
+ t.mValues = new int[mEntryCount];
+ for(int ct=0; ct < mEntryCount; ct++) {
+ t.mDimensions[ct] = mEntries[ct].mDim;
+ t.mValues[ct] = mEntries[ct].mValue;
+ }
+ return t;
+ }
+ }
+
+}
diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk
new file mode 100644
index 0000000..799fcbb
--- /dev/null
+++ b/graphics/jni/Android.mk
@@ -0,0 +1,45 @@
+
+# libRS needs libacc, which isn't 64-bit clean, and so can't be built
+# for the simulator on gHardy, and therefore libRS needs to be excluded
+# from the simulator as well, and so in turn librs_jni needs to be
+# excluded.
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ android_renderscript_RenderScript.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libandroid_runtime \
+ libacc \
+ libnativehelper \
+ libRS \
+ libcutils \
+ libskia \
+ libutils \
+ libui
+
+LOCAL_STATIC_LIBRARIES :=
+
+rs_generated_include_dir := $(call intermediates-dir-for,SHARED_LIBRARIES,libRS,,)
+
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE) \
+ $(LOCAL_PATH)/../../libs/rs \
+ $(rs_generated_include_dir) \
+ $(call include-path-for, corecg graphics)
+
+LOCAL_CFLAGS +=
+
+LOCAL_LDLIBS := -lpthread
+LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
+LOCAL_MODULE:= librs_jni
+LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
+LOCAL_MODULE_TAGS := optional
+LOCAL_REQUIRED_MODULES := libRS
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif #simulator
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
new file mode 100644
index 0000000..558146d
--- /dev/null
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -0,0 +1,1397 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libRS_jni"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <math.h>
+#include <utils/misc.h>
+
+#include <ui/Surface.h>
+
+#include <core/SkBitmap.h>
+#include <core/SkPixelRef.h>
+#include <core/SkStream.h>
+#include <core/SkTemplates.h>
+#include <images/SkImageDecoder.h>
+
+#include <utils/Asset.h>
+#include <utils/ResourceTypes.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 jfieldID gTypeNativeCache = 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");
+
+ jclass typeClass = _env->FindClass("android/renderscript/Type");
+ gTypeNativeCache = _env->GetFieldID(typeClass, "mNativeCache", "I");
+}
+
+
+// ---------------------------------------------------------------------------
+
+static void
+nAssignName(JNIEnv *_env, jobject _this, jint obj, jbyteArray str)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAssignName, con(%p), obj(%p)", con, (void *)obj);
+
+ jint len = _env->GetArrayLength(str);
+ jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0);
+ rsAssignName(con, (void *)obj, (const char *)cptr, len);
+ _env->ReleasePrimitiveArrayCritical(str, cptr, JNI_ABORT);
+}
+
+static void
+nObjDestroy(JNIEnv *_env, jobject _this, jint obj)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nObjDestroy, con(%p) obj(%p)", con, (void *)obj);
+ rsObjDestroy(con, (void *)obj);
+}
+
+static void
+nObjDestroyOOB(JNIEnv *_env, jobject _this, jint obj)
+{
+ // This function only differs from nObjDestroy in that it calls the
+ // special Out Of Band version of ObjDestroy which is thread safe.
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nObjDestroyOOB, con(%p) obj(%p)", con, (void *)obj);
+ rsObjDestroyOOB(con, (void *)obj);
+}
+
+static jint
+nFileOpen(JNIEnv *_env, jobject _this, jbyteArray str)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nFileOpen, con(%p)", con);
+
+ jint len = _env->GetArrayLength(str);
+ jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0);
+ jint ret = (jint)rsFileOpen(con, (const char *)cptr, len);
+ _env->ReleasePrimitiveArrayCritical(str, cptr, JNI_ABORT);
+ return ret;
+}
+
+// ---------------------------------------------------------------------------
+
+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, jboolean useDepth)
+{
+ 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;
+
+ return (jint)rsContextCreate((RsDevice)dev, window, ver, useDepth);
+}
+
+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(con);
+}
+
+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(con, (RsElementPredefined)predef);
+}
+
+static void
+nElementAdd(JNIEnv *_env, jobject _this, jint kind, jint type, jint norm, jint bits, jstring name)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ const char* n = NULL;
+ if (name) {
+ n = _env->GetStringUTFChars(name, NULL);
+ }
+ LOG_API("nElementAdd, con(%p), kind(%i), type(%i), norm(%i), bits(%i)", con, kind, type, norm, bits);
+ rsElementAdd(con, (RsDataKind)kind, (RsDataType)type, norm != 0, (size_t)bits, n);
+ if (n) {
+ _env->ReleaseStringUTFChars(name, n);
+ }
+}
+
+static jint
+nElementCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nElementCreate, con(%p)", con);
+ return (jint)rsElementCreate(con);
+}
+
+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(con, (RsElementPredefined)predef);
+}
+
+// -----------------------------------
+
+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(con, (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(con, (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(con);
+}
+
+static void * SF_LoadInt(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+ ((int32_t *)buffer)[0] = _env->GetIntField(_obj, _field);
+ return ((uint8_t *)buffer) + 4;
+}
+
+static void * SF_LoadShort(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+ ((int16_t *)buffer)[0] = _env->GetShortField(_obj, _field);
+ return ((uint8_t *)buffer) + 2;
+}
+
+static void * SF_LoadByte(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+ ((int8_t *)buffer)[0] = _env->GetByteField(_obj, _field);
+ return ((uint8_t *)buffer) + 1;
+}
+
+static void * SF_LoadFloat(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
+{
+ ((float *)buffer)[0] = _env->GetFloatField(_obj, _field);
+ return ((uint8_t *)buffer) + 4;
+}
+
+struct TypeFieldCache {
+ jfieldID field;
+ int bits;
+ void * (*ptr)(JNIEnv *, jobject, jfieldID, void *buffer);
+};
+
+struct TypeCache {
+ int fieldCount;
+ int size;
+ TypeFieldCache fields[1];
+};
+
+//{"nTypeFinalDestroy", "(Landroid/renderscript/Type;)V", (void*)nTypeFinalDestroy },
+static void
+nTypeFinalDestroy(JNIEnv *_env, jobject _this, jobject _type)
+{
+ TypeCache *tc = (TypeCache *)_env->GetIntField(_type, gTypeNativeCache);
+ free(tc);
+}
+
+// native void nTypeSetupFields(Type t, int[] types, int[] bits, Field[] IDs);
+static void
+nTypeSetupFields(JNIEnv *_env, jobject _this, jobject _type, jintArray _types, jintArray _bits, jobjectArray _IDs)
+{
+ int fieldCount = _env->GetArrayLength(_types);
+ size_t structSize = sizeof(TypeCache) + (sizeof(TypeFieldCache) * (fieldCount-1));
+ TypeCache *tc = (TypeCache *)malloc(structSize);
+ memset(tc, 0, structSize);
+
+ TypeFieldCache *tfc = &tc->fields[0];
+ tc->fieldCount = fieldCount;
+ _env->SetIntField(_type, gTypeNativeCache, (jint)tc);
+
+ jint *fType = _env->GetIntArrayElements(_types, NULL);
+ jint *fBits = _env->GetIntArrayElements(_bits, NULL);
+ for (int ct=0; ct < fieldCount; ct++) {
+ jobject field = _env->GetObjectArrayElement(_IDs, ct);
+ tfc[ct].field = _env->FromReflectedField(field);
+ tfc[ct].bits = fBits[ct];
+
+ switch(fType[ct]) {
+ case RS_TYPE_FLOAT:
+ tfc[ct].ptr = SF_LoadFloat;
+ break;
+ case RS_TYPE_UNSIGNED:
+ case RS_TYPE_SIGNED:
+ switch(tfc[ct].bits) {
+ case 32: tfc[ct].ptr = SF_LoadInt; break;
+ case 16: tfc[ct].ptr = SF_LoadShort; break;
+ case 8: tfc[ct].ptr = SF_LoadByte; break;
+ }
+ break;
+ }
+ tc->size += 4;
+ }
+
+ _env->ReleaseIntArrayElements(_types, fType, JNI_ABORT);
+ _env->ReleaseIntArrayElements(_bits, fBits, JNI_ABORT);
+}
+
+
+// -----------------------------------
+
+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(con, (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(con, (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(con, (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(con, (RsAllocation)a, mip);
+}
+
+static void
+nAllocationUploadToBufferObject(JNIEnv *_env, jobject _this, jint a)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationUploadToBufferObject, con(%p), a(%p)", con, (RsAllocation)a);
+ rsAllocationUploadToBufferObject(con, (RsAllocation)a);
+}
+
+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(con, w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+ bitmap.unlockPixels();
+ return id;
+ }
+ return 0;
+}
+
+static int
+nAllocationCreateFromAssetStream(JNIEnv *_env, jobject _this, jint dstFmt, jboolean genMips, jint native_asset)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+
+ Asset* asset = reinterpret_cast<Asset*>(native_asset);
+ SkBitmap bitmap;
+ SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
+ &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
+
+ 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(con, w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+ bitmap.unlockPixels();
+ return id;
+ }
+ return 0;
+}
+
+static int
+nAllocationCreateFromBitmapBoxed(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)rsAllocationCreateFromBitmapBoxed(con, w, h, (RsElementPredefined)dstFmt, e, genMips, ptr);
+ bitmap.unlockPixels();
+ return id;
+ }
+ return 0;
+}
+
+
+static void
+nAllocationData_i(JNIEnv *_env, jobject _this, jint alloc, jintArray data, int sizeBytes)
+{
+ 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(con, (RsAllocation)alloc, ptr, sizeBytes);
+ _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationData_f(JNIEnv *_env, jobject _this, jint alloc, jfloatArray data, int sizeBytes)
+{
+ 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(con, (RsAllocation)alloc, ptr, sizeBytes);
+ _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData1D_i(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jintArray data, int sizeBytes)
+{
+ 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(con, (RsAllocation)alloc, offset, count, ptr, sizeBytes);
+ _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData1D_f(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jfloatArray data, int sizeBytes)
+{
+ 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(con, (RsAllocation)alloc, offset, count, ptr, sizeBytes);
+ _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, int sizeBytes)
+{
+ 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(con, (RsAllocation)alloc, xoff, yoff, w, h, ptr, sizeBytes);
+ _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, int sizeBytes)
+{
+ 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(con, (RsAllocation)alloc, xoff, yoff, w, h, ptr, sizeBytes);
+ _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationRead_i(JNIEnv *_env, jobject _this, jint alloc, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
+ jint *ptr = _env->GetIntArrayElements(data, NULL);
+ rsAllocationRead(con, (RsAllocation)alloc, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, 0);
+}
+
+static void
+nAllocationRead_f(JNIEnv *_env, jobject _this, jint alloc, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAllocationRead_f, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
+ jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+ rsAllocationRead(con, (RsAllocation)alloc, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, 0);
+}
+
+
+//{"nAllocationDataFromObject", "(ILandroid/renderscript/Type;Ljava/lang/Object;)V", (void*)nAllocationDataFromObject },
+static void
+nAllocationDataFromObject(JNIEnv *_env, jobject _this, jint alloc, jobject _type, jobject _o)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAllocationDataFromObject con(%p), alloc(%p)", con, (RsAllocation)alloc);
+
+ const TypeCache *tc = (TypeCache *)_env->GetIntField(_type, gTypeNativeCache);
+
+ void * bufAlloc = malloc(tc->size);
+ void * buf = bufAlloc;
+ for (int ct=0; ct < tc->fieldCount; ct++) {
+ const TypeFieldCache *tfc = &tc->fields[ct];
+ buf = tfc->ptr(_env, _o, tfc->field, buf);
+ }
+ rsAllocationData(con, (RsAllocation)alloc, bufAlloc, tc->size);
+ const uint32_t * tmp = (const uint32_t *)bufAlloc;
+ free(bufAlloc);
+}
+
+// -----------------------------------
+
+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(con, (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(con, 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(con, 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(con, 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(con, v);
+}
+
+static void
+nTriangleMeshAddVertex_XYZ_ST_NORM(JNIEnv *_env, jobject _this, jfloat x, jfloat y, jfloat z, jfloat s, jfloat t, jfloat nx, jfloat ny, jfloat nz)
+{
+ float v[] = {nx, ny, nz, 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(con, 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(con, 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(con);
+}
+
+// -----------------------------------
+
+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(con, (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(con, (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(con, (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(con, (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(con, (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(con, (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(con);
+}
+
+// -----------------------------------
+
+static void
+nAdapter2DBindAllocation(JNIEnv *_env, jobject _this, jint adapter, jint alloc)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter2DBindAllocation, con(%p), adapter(%p), alloc(%p)", con, (RsAdapter2D)adapter, (RsAllocation)alloc);
+ rsAdapter2DBindAllocation(con, (RsAdapter2D)adapter, (RsAllocation)alloc);
+}
+
+static void
+nAdapter2DSetConstraint(JNIEnv *_env, jobject _this, jint adapter, jint dim, jint value)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter2DSetConstraint, con(%p), adapter(%p), dim(%i), value(%i)", con, (RsAdapter2D)adapter, dim, value);
+ rsAdapter2DSetConstraint(con, (RsAdapter2D)adapter, (RsDimension)dim, value);
+}
+
+static void
+nAdapter2DData_i(JNIEnv *_env, jobject _this, jint adapter, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAdapter2DData_i, con(%p), adapter(%p), len(%i)", con, (RsAdapter2D)adapter, len);
+ jint *ptr = _env->GetIntArrayElements(data, NULL);
+ rsAdapter2DData(con, (RsAdapter2D)adapter, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter2DData_f(JNIEnv *_env, jobject _this, jint adapter, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAdapter2DData_f, con(%p), adapter(%p), len(%i)", con, (RsAdapter2D)adapter, len);
+ jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+ rsAdapter2DData(con, (RsAdapter2D)adapter, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter2DSubData_i(JNIEnv *_env, jobject _this, jint adapter, jint xoff, jint yoff, jint w, jint h, jintArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAdapter2DSubData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)",
+ con, (RsAdapter2D)adapter, xoff, yoff, w, h, len);
+ jint *ptr = _env->GetIntArrayElements(data, NULL);
+ rsAdapter2DSubData(con, (RsAdapter2D)adapter, xoff, yoff, w, h, ptr);
+ _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static void
+nAdapter2DSubData_f(JNIEnv *_env, jobject _this, jint adapter, jint xoff, jint yoff, jint w, jint h, jfloatArray data)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(data);
+ LOG_API("nAdapter2DSubData_f, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)",
+ con, (RsAdapter2D)adapter, xoff, yoff, w, h, len);
+ jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+ rsAdapter2DSubData(con, (RsAdapter1D)adapter, xoff, yoff, w, h, ptr);
+ _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/);
+}
+
+static jint
+nAdapter2DCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nAdapter2DCreate, con(%p)", con);
+ return (jint)rsAdapter2DCreate(con);
+}
+
+// -----------------------------------
+
+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(con, (RsScript)script, (RsAllocation)alloc, slot);
+}
+
+static void
+nScriptSetClearColor(JNIEnv *_env, jobject _this, jint script, jfloat r, jfloat g, jfloat b, jfloat a)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptSetClearColor, con(%p), s(%p), r(%f), g(%f), b(%f), a(%f)", con, (void *)script, r, g, b, a);
+ rsScriptSetClearColor(con, (RsScript)script, r, g, b, a);
+}
+
+static void
+nScriptSetClearDepth(JNIEnv *_env, jobject _this, jint script, jfloat d)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetClearDepth, con(%p), s(%p), depth(%f)", con, (void *)script, d);
+ rsScriptSetClearDepth(con, (RsScript)script, d);
+}
+
+static void
+nScriptSetClearStencil(JNIEnv *_env, jobject _this, jint script, jint stencil)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetClearStencil, con(%p), s(%p), stencil(%i)", con, (void *)script, stencil);
+ rsScriptSetClearStencil(con, (RsScript)script, stencil);
+}
+
+static void
+nScriptSetTimeZone(JNIEnv *_env, jobject _this, jint script, jbyteArray timeZone)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetTimeZone, con(%p), s(%p), timeZone(%s)", con, (void *)script, (const char *)timeZone);
+
+ jint length = _env->GetArrayLength(timeZone);
+ jbyte* timeZone_ptr;
+ timeZone_ptr = (jbyte *) _env->GetPrimitiveArrayCritical(timeZone, (jboolean *)0);
+
+ rsScriptSetTimeZone(con, (RsScript)script, (const char *)timeZone_ptr, length);
+
+ if (timeZone_ptr) {
+ _env->ReleasePrimitiveArrayCritical(timeZone, timeZone_ptr, 0);
+ }
+}
+
+static void
+nScriptSetType(JNIEnv *_env, jobject _this, jint type, jboolean writable, jstring _str, jint slot)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCAddType, con(%p), type(%p), writable(%i), slot(%i)", con, (RsType)type, writable, slot);
+ const char* n = NULL;
+ if (_str) {
+ n = _env->GetStringUTFChars(_str, NULL);
+ }
+ rsScriptSetType(con, (RsType)type, slot, writable, n);
+ if (n) {
+ _env->ReleaseStringUTFChars(_str, n);
+ }
+}
+
+static void
+nScriptSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCSetRoot, con(%p), isRoot(%i)", con, isRoot);
+ rsScriptSetRoot(con, isRoot);
+}
+
+// -----------------------------------
+
+static void
+nScriptCBegin(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nScriptCBegin, con(%p)", con);
+ rsScriptCBegin(con);
+}
+
+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(con, (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(con);
+}
+
+static void
+nScriptCAddDefineI32(JNIEnv *_env, jobject _this, jstring name, jint value)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ const char* n = _env->GetStringUTFChars(name, NULL);
+ LOG_API("nScriptCAddDefineI32, con(%p) name(%s) value(%d)", con, n, value);
+ rsScriptCSetDefineI32(con, n, value);
+ _env->ReleaseStringUTFChars(name, n);
+}
+
+static void
+nScriptCAddDefineF(JNIEnv *_env, jobject _this, jstring name, jfloat value)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ const char* n = _env->GetStringUTFChars(name, NULL);
+ LOG_API("nScriptCAddDefineF, con(%p) name(%s) value(%f)", con, n, value);
+ rsScriptCSetDefineF(con, n, value);
+ _env->ReleaseStringUTFChars(name, n);
+}
+
+// ---------------------------------------------------------------------------
+
+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(con, (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(con, (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(con, 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(con, 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(con, (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(con, enable);
+}
+
+static jint
+nProgramFragmentStoreCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentStoreCreate, con(%p)", con);
+
+ return (jint)rsProgramFragmentStoreCreate(con);
+}
+
+// ---------------------------------------------------------------------------
+
+static void
+nProgramFragmentBegin(JNIEnv *_env, jobject _this, jint in, jint out, jboolean pointSpriteEnable)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentBegin, con(%p), in(%p), out(%p) PointSprite(%i)", con, (RsElement)in, (RsElement)out, pointSpriteEnable);
+ rsProgramFragmentBegin(con, (RsElement)in, (RsElement)out, pointSpriteEnable);
+}
+
+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(con, (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(con, (RsProgramFragment)vpf, slot, (RsSampler)a);
+}
+
+static void
+nProgramFragmentSetSlot(JNIEnv *_env, jobject _this, jint slot, jboolean enable, jint env, jint vt)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramFragmentSetType, con(%p), slot(%i), enable(%i), env(%i), vt(%p)", con, slot, enable, env, (RsType)vt);
+ rsProgramFragmentSetSlot(con, slot, enable, (RsTexEnvMode)env, (RsType)vt);
+}
+
+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(con);
+}
+
+// ---------------------------------------------------------------------------
+
+static void
+nProgramVertexBegin(JNIEnv *_env, jobject _this, jint in, jint out)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramVertexBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out);
+ rsProgramVertexBegin(con, (RsElement)in, (RsElement)out);
+}
+
+static void
+nProgramVertexBindAllocation(JNIEnv *_env, jobject _this, jint vpv, jint a)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramVertexBindAllocation, con(%p), vpf(%p), a(%p)", con, (RsProgramVertex)vpv, (RsAllocation)a);
+ rsProgramVertexBindAllocation(con, (RsProgramFragment)vpv, (RsAllocation)a);
+}
+
+static void
+nProgramVertexSetTextureMatrixEnable(JNIEnv *_env, jobject _this, jboolean enable)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramVertexSetTextureMatrixEnable, con(%p), enable(%i)", con, enable);
+ rsProgramVertexSetTextureMatrixEnable(con, enable);
+}
+
+static void
+nProgramVertexAddLight(JNIEnv *_env, jobject _this, jint light)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramVertexAddLight, con(%p), light(%p)", con, (RsLight)light);
+ rsProgramVertexAddLight(con, (RsLight)light);
+}
+
+static jint
+nProgramVertexCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nProgramVertexCreate, con(%p)", con);
+ return (jint)rsProgramVertexCreate(con);
+}
+
+
+
+// ---------------------------------------------------------------------------
+
+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(con, (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(con, (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(con, (RsProgramFragment)pf);
+}
+
+static void
+nContextBindProgramVertex(JNIEnv *_env, jobject _this, jint pf)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nContextBindProgramVertex, con(%p), pf(%p)", con, (RsProgramVertex)pf);
+ rsContextBindProgramVertex(con, (RsProgramVertex)pf);
+}
+
+static void
+nContextAddDefineI32(JNIEnv *_env, jobject _this, jstring name, jint value)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ const char* n = _env->GetStringUTFChars(name, NULL);
+ LOG_API("nScriptCAddDefineI32, con(%p) name(%s) value(%d)", con, n, value);
+ rsContextSetDefineI32(con, n, value);
+ _env->ReleaseStringUTFChars(name, n);
+}
+
+static void
+nContextAddDefineF(JNIEnv *_env, jobject _this, jstring name, jfloat value)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ const char* n = _env->GetStringUTFChars(name, NULL);
+ LOG_API("nScriptCAddDefineF, con(%p) name(%s) value(%f)", con, n, value);
+ rsContextSetDefineF(con, n, value);
+ _env->ReleaseStringUTFChars(name, n);
+}
+
+
+// ---------------------------------------------------------------------------
+
+static void
+nSamplerBegin(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSamplerBegin, con(%p)", con);
+ rsSamplerBegin(con);
+}
+
+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(con, (RsSamplerParam)p, (RsSamplerValue)v);
+}
+
+static jint
+nSamplerCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSamplerCreate, con(%p)", con);
+ return (jint)rsSamplerCreate(con);
+}
+
+// ---------------------------------------------------------------------------
+
+static void
+nLightBegin(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nLightBegin, con(%p)", con);
+ rsLightBegin(con);
+}
+
+static void
+nLightSetIsMono(JNIEnv *_env, jobject _this, jboolean isMono)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nLightSetIsMono, con(%p), isMono(%i)", con, isMono);
+ rsLightSetMonochromatic(con, isMono);
+}
+
+static void
+nLightSetIsLocal(JNIEnv *_env, jobject _this, jboolean isLocal)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nLightSetIsLocal, con(%p), isLocal(%i)", con, isLocal);
+ rsLightSetLocal(con, isLocal);
+}
+
+static jint
+nLightCreate(JNIEnv *_env, jobject _this)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nLightCreate, con(%p)", con);
+ return (jint)rsLightCreate(con);
+}
+
+static void
+nLightSetColor(JNIEnv *_env, jobject _this, jint light, float r, float g, float b)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nLightSetColor, con(%p), light(%p), r(%f), g(%f), b(%f)", con, (RsLight)light, r, g, b);
+ rsLightSetColor(con, (RsLight)light, r, g, b);
+}
+
+static void
+nLightSetPosition(JNIEnv *_env, jobject _this, jint light, float x, float y, float z)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nLightSetPosition, con(%p), light(%p), x(%f), y(%f), z(%f)", con, (RsLight)light, x, y, z);
+ rsLightSetPosition(con, (RsLight)light, x, y, z);
+}
+
+// ---------------------------------------------------------------------------
+
+static jint
+nSimpleMeshCreate(JNIEnv *_env, jobject _this, jint batchID, jint indexID, jintArray vtxIDs, jint primID)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ jint len = _env->GetArrayLength(vtxIDs);
+ LOG_API("nSimpleMeshCreate, con(%p), batchID(%i), indexID(%i), vtxIDs.len(%i), primID(%i)",
+ con, batchID, indexID, len, primID);
+ jint *ptr = _env->GetIntArrayElements(vtxIDs, NULL);
+ int id = (int)rsSimpleMeshCreate(con, (void *)batchID, (void *)indexID, (void **)ptr, len, primID);
+ _env->ReleaseIntArrayElements(vtxIDs, ptr, 0/*JNI_ABORT*/);
+ return id;
+}
+
+static void
+nSimpleMeshBindVertex(JNIEnv *_env, jobject _this, jint s, jint alloc, jint slot)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSimpleMeshBindVertex, con(%p), SimpleMesh(%p), Alloc(%p), slot(%i)", con, (RsSimpleMesh)s, (RsAllocation)alloc, slot);
+ rsSimpleMeshBindVertex(con, (RsSimpleMesh)s, (RsAllocation)alloc, slot);
+}
+
+static void
+nSimpleMeshBindIndex(JNIEnv *_env, jobject _this, jint s, jint alloc)
+{
+ RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+ LOG_API("nSimpleMeshBindIndex, con(%p), SimpleMesh(%p), Alloc(%p)", con, (RsSimpleMesh)s, (RsAllocation)alloc);
+ rsSimpleMeshBindIndex(con, (RsSimpleMesh)s, (RsAllocation)alloc);
+}
+
+// ---------------------------------------------------------------------------
+
+
+static const char *classPathName = "android/renderscript/RenderScript";
+
+static JNINativeMethod methods[] = {
+{"_nInit", "()V", (void*)_nInit },
+{"nDeviceCreate", "()I", (void*)nDeviceCreate },
+{"nDeviceDestroy", "(I)V", (void*)nDeviceDestroy },
+{"nContextCreate", "(ILandroid/view/Surface;IZ)I", (void*)nContextCreate },
+{"nContextDestroy", "(I)V", (void*)nContextDestroy },
+{"nAssignName", "(I[B)V", (void*)nAssignName },
+{"nObjDestroy", "(I)V", (void*)nObjDestroy },
+{"nObjDestroyOOB", "(I)V", (void*)nObjDestroyOOB },
+
+{"nFileOpen", "([B)I", (void*)nFileOpen },
+
+{"nElementBegin", "()V", (void*)nElementBegin },
+{"nElementAddPredefined", "(I)V", (void*)nElementAddPredefined },
+{"nElementAdd", "(IIIILjava/lang/String;)V", (void*)nElementAdd },
+{"nElementCreate", "()I", (void*)nElementCreate },
+{"nElementGetPredefined", "(I)I", (void*)nElementGetPredefined },
+
+{"nTypeBegin", "(I)V", (void*)nTypeBegin },
+{"nTypeAdd", "(II)V", (void*)nTypeAdd },
+{"nTypeCreate", "()I", (void*)nTypeCreate },
+{"nTypeFinalDestroy", "(Landroid/renderscript/Type;)V", (void*)nTypeFinalDestroy },
+{"nTypeSetupFields", "(Landroid/renderscript/Type;[I[I[Ljava/lang/reflect/Field;)V", (void*)nTypeSetupFields },
+
+{"nAllocationCreateTyped", "(I)I", (void*)nAllocationCreateTyped },
+{"nAllocationCreatePredefSized", "(II)I", (void*)nAllocationCreatePredefSized },
+{"nAllocationCreateSized", "(II)I", (void*)nAllocationCreateSized },
+{"nAllocationCreateFromBitmap", "(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmap },
+{"nAllocationCreateFromBitmapBoxed","(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmapBoxed },
+{"nAllocationCreateFromAssetStream","(IZI)I", (void*)nAllocationCreateFromAssetStream },
+{"nAllocationUploadToTexture", "(II)V", (void*)nAllocationUploadToTexture },
+{"nAllocationUploadToBufferObject","(I)V", (void*)nAllocationUploadToBufferObject },
+{"nAllocationData", "(I[II)V", (void*)nAllocationData_i },
+{"nAllocationData", "(I[FI)V", (void*)nAllocationData_f },
+{"nAllocationSubData1D", "(III[II)V", (void*)nAllocationSubData1D_i },
+{"nAllocationSubData1D", "(III[FI)V", (void*)nAllocationSubData1D_f },
+{"nAllocationSubData2D", "(IIIII[II)V", (void*)nAllocationSubData2D_i },
+{"nAllocationSubData2D", "(IIIII[FI)V", (void*)nAllocationSubData2D_f },
+{"nAllocationRead", "(I[I)V", (void*)nAllocationRead_i },
+{"nAllocationRead", "(I[F)V", (void*)nAllocationRead_f },
+{"nAllocationDataFromObject", "(ILandroid/renderscript/Type;Ljava/lang/Object;)V", (void*)nAllocationDataFromObject },
+
+{"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 },
+{"nTriangleMeshAddVertex_XYZ_ST_NORM", "(FFFFFFFF)V", (void*)nTriangleMeshAddVertex_XYZ_ST_NORM },
+{"nTriangleMeshAddTriangle", "(III)V", (void*)nTriangleMeshAddTriangle },
+{"nTriangleMeshCreate", "()I", (void*)nTriangleMeshCreate },
+
+{"nAdapter1DBindAllocation", "(II)V", (void*)nAdapter1DBindAllocation },
+{"nAdapter1DSetConstraint", "(III)V", (void*)nAdapter1DSetConstraint },
+{"nAdapter1DData", "(I[I)V", (void*)nAdapter1DData_i },
+{"nAdapter1DData", "(I[F)V", (void*)nAdapter1DData_f },
+{"nAdapter1DSubData", "(III[I)V", (void*)nAdapter1DSubData_i },
+{"nAdapter1DSubData", "(III[F)V", (void*)nAdapter1DSubData_f },
+{"nAdapter1DCreate", "()I", (void*)nAdapter1DCreate },
+
+{"nAdapter2DBindAllocation", "(II)V", (void*)nAdapter2DBindAllocation },
+{"nAdapter2DSetConstraint", "(III)V", (void*)nAdapter2DSetConstraint },
+{"nAdapter2DData", "(I[I)V", (void*)nAdapter2DData_i },
+{"nAdapter2DData", "(I[F)V", (void*)nAdapter2DData_f },
+{"nAdapter2DSubData", "(IIIII[I)V", (void*)nAdapter2DSubData_i },
+{"nAdapter2DSubData", "(IIIII[F)V", (void*)nAdapter2DSubData_f },
+{"nAdapter2DCreate", "()I", (void*)nAdapter2DCreate },
+
+{"nScriptBindAllocation", "(III)V", (void*)nScriptBindAllocation },
+{"nScriptSetClearColor", "(IFFFF)V", (void*)nScriptSetClearColor },
+{"nScriptSetClearDepth", "(IF)V", (void*)nScriptSetClearDepth },
+{"nScriptSetClearStencil", "(II)V", (void*)nScriptSetClearStencil },
+{"nScriptSetTimeZone", "(I[B)V", (void*)nScriptSetTimeZone },
+{"nScriptSetType", "(IZLjava/lang/String;I)V", (void*)nScriptSetType },
+{"nScriptSetRoot", "(Z)V", (void*)nScriptSetRoot },
+
+{"nScriptCBegin", "()V", (void*)nScriptCBegin },
+{"nScriptCSetScript", "([BII)V", (void*)nScriptCSetScript },
+{"nScriptCCreate", "()I", (void*)nScriptCCreate },
+{"nScriptCAddDefineI32", "(Ljava/lang/String;I)V", (void*)nScriptCAddDefineI32 },
+{"nScriptCAddDefineF", "(Ljava/lang/String;F)V", (void*)nScriptCAddDefineF },
+
+{"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", "(IIZ)V", (void*)nProgramFragmentBegin },
+{"nProgramFragmentBindTexture", "(III)V", (void*)nProgramFragmentBindTexture },
+{"nProgramFragmentBindSampler", "(III)V", (void*)nProgramFragmentBindSampler },
+{"nProgramFragmentSetSlot", "(IZII)V", (void*)nProgramFragmentSetSlot },
+{"nProgramFragmentCreate", "()I", (void*)nProgramFragmentCreate },
+
+{"nProgramVertexBindAllocation", "(II)V", (void*)nProgramVertexBindAllocation },
+{"nProgramVertexBegin", "(II)V", (void*)nProgramVertexBegin },
+{"nProgramVertexSetTextureMatrixEnable", "(Z)V", (void*)nProgramVertexSetTextureMatrixEnable },
+{"nProgramVertexAddLight", "(I)V", (void*)nProgramVertexAddLight },
+{"nProgramVertexCreate", "()I", (void*)nProgramVertexCreate },
+
+{"nLightBegin", "()V", (void*)nLightBegin },
+{"nLightSetIsMono", "(Z)V", (void*)nLightSetIsMono },
+{"nLightSetIsLocal", "(Z)V", (void*)nLightSetIsLocal },
+{"nLightCreate", "()I", (void*)nLightCreate },
+{"nLightSetColor", "(IFFF)V", (void*)nLightSetColor },
+{"nLightSetPosition", "(IFFF)V", (void*)nLightSetPosition },
+
+{"nContextBindRootScript", "(I)V", (void*)nContextBindRootScript },
+{"nContextBindProgramFragmentStore","(I)V", (void*)nContextBindProgramFragmentStore },
+{"nContextBindProgramFragment", "(I)V", (void*)nContextBindProgramFragment },
+{"nContextBindProgramVertex", "(I)V", (void*)nContextBindProgramVertex },
+
+{"nSamplerBegin", "()V", (void*)nSamplerBegin },
+{"nSamplerSet", "(II)V", (void*)nSamplerSet },
+{"nSamplerCreate", "()I", (void*)nSamplerCreate },
+
+{"nSimpleMeshCreate", "(II[II)I", (void*)nSimpleMeshCreate },
+{"nSimpleMeshBindVertex", "(III)V", (void*)nSimpleMeshBindVertex },
+{"nSimpleMeshBindIndex", "(II)V", (void*)nSimpleMeshBindIndex },
+
+};
+
+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;
+
+ 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/im/java/android/im/BrandingResourceIDs.java b/im/java/android/im/BrandingResourceIDs.java
deleted file mode 100644
index 9960722..0000000
--- a/im/java/android/im/BrandingResourceIDs.java
+++ /dev/null
@@ -1,52 +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.im;
-
-/**
- * @hide
- * Defines the IDs of branding resources.
- */
-public interface BrandingResourceIDs {
- /**
- * The logo icon of the provider which is displayed in the landing page.
- */
- public static final int DRAWABLE_LOGO = 100;
- /**
- * The icon of online presence status.
- */
- public static final int DRAWABLE_PRESENCE_ONLINE = 102;
- /**
- * The icon of busy presence status.
- */
- public static final int DRAWABLE_PRESENCE_BUSY = 103;
- /**
- * The icon of away presence status.
- */
- public static final int DRAWABLE_PRESENCE_AWAY = 104;
- /**
- * The icon of invisible presence status.
- */
- public static final int DRAWABLE_PRESENCE_INVISIBLE = 105;
- /**
- * The icon of offline presence status.
- */
- public static final int DRAWABLE_PRESENCE_OFFLINE = 106;
- /**
- * The label of the menu to go to the contact list screen.
- */
- public static final int STRING_MENU_CONTACT_LIST = 107;
-
-}
diff --git a/im/java/android/im/IImPlugin.aidl b/im/java/android/im/IImPlugin.aidl
deleted file mode 100644
index 229cd0e..0000000
--- a/im/java/android/im/IImPlugin.aidl
+++ /dev/null
@@ -1,69 +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.im;
-
-/**
- * @hide
- */
-interface IImPlugin {
- /**
- * Notify the plugin the front door activity is created. This gives the plugin a chance to
- * start its own servics, etc.
- */
- void onStart();
-
- /**
- * Notify the plugin the front door activity is stopping.
- */
- void onStop();
-
- /**
- * Sign in to the service for the account passed in.
- *
- * @param account the account id for the accont to be signed into.
- */
- void signIn(long account);
-
- /**
- * Sign out of the service for the account passed in.
- *
- * @param account the account id for the accont to be signed out of.
- */
- void signOut(long account);
-
- /**
- * Returns the package name used to load the resources for the given provider name.
- *
- * @return The package name to load the resourcs for the given provider.
- */
- String getResourcePackageNameForProvider(String providerName);
-
- /**
- * Returns a map of branding resources for the given provider. The keys are defined
- * in {@link android.im.BrandingResourceIDs}. The values are the resource identifiers generated
- * by the aapt tool.
- *
- * @return The map of branding resources for the given provider.
- */
- Map getResourceMapForProvider(String providerName);
-
- /*
- * Returns a list of supported IM providers.
- *
- * @return a List of supported providers.
- */
- List getSupportedProviders();
-}
diff --git a/im/java/android/im/ImPluginConsts.java b/im/java/android/im/ImPluginConsts.java
deleted file mode 100644
index 416493ff..0000000
--- a/im/java/android/im/ImPluginConsts.java
+++ /dev/null
@@ -1,27 +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.im;
-
-/**
- * @hide
- */
-public class ImPluginConsts {
- /**
- * The intent action name for the plugin service.
- */
- public static final String PLUGIN_ACTION_NAME = "android.im.plugin";
-} \ No newline at end of file
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/binder/Binder.h b/include/binder/Binder.h
new file mode 100644
index 0000000..47b2bb9
--- /dev/null
+++ b/include/binder/Binder.h
@@ -0,0 +1,104 @@
+/*
+ * 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 ANDROID_BINDER_H
+#define ANDROID_BINDER_H
+
+#include <binder/IBinder.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BBinder : public IBinder
+{
+public:
+ BBinder();
+
+ virtual const String16& getInterfaceDescriptor() const;
+ virtual bool isBinderAlive() const;
+ virtual status_t pingBinder();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ virtual status_t transact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+ virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0);
+
+ virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0,
+ wp<DeathRecipient>* outRecipient = NULL);
+
+ virtual void attachObject( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ object_cleanup_func func);
+ virtual void* findObject(const void* objectID) const;
+ virtual void detachObject(const void* objectID);
+
+ virtual BBinder* localBinder();
+
+protected:
+ virtual ~BBinder();
+
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+private:
+ BBinder(const BBinder& o);
+ BBinder& operator=(const BBinder& o);
+
+ class Extras;
+
+ Extras* mExtras;
+ void* mReserved0;
+ static String16 sEmptyDescriptor;
+};
+
+// ---------------------------------------------------------------------------
+
+class BpRefBase : public virtual RefBase
+{
+protected:
+ BpRefBase(const sp<IBinder>& o);
+ virtual ~BpRefBase();
+ virtual void onFirstRef();
+ virtual void onLastStrongRef(const void* id);
+ virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
+
+ inline IBinder* remote() { return mRemote; }
+ inline IBinder* remote() const { return mRemote; }
+
+private:
+ BpRefBase(const BpRefBase& o);
+ BpRefBase& operator=(const BpRefBase& o);
+
+ IBinder* const mRemote;
+ RefBase::weakref_type* mRefs;
+ volatile int32_t mState;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BINDER_H
diff --git a/include/binder/BpBinder.h b/include/binder/BpBinder.h
new file mode 100644
index 0000000..7ef93aa
--- /dev/null
+++ b/include/binder/BpBinder.h
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_BPBINDER_H
+#define ANDROID_BPBINDER_H
+
+#include <binder/IBinder.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BpBinder : public IBinder
+{
+public:
+ BpBinder(int32_t handle);
+
+ inline int32_t handle() const { return mHandle; }
+
+ virtual const String16& getInterfaceDescriptor() const;
+ virtual bool isBinderAlive() const;
+ virtual status_t pingBinder();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ virtual status_t transact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+ virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0);
+ virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0,
+ wp<DeathRecipient>* outRecipient = NULL);
+
+ virtual void attachObject( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ object_cleanup_func func);
+ virtual void* findObject(const void* objectID) const;
+ virtual void detachObject(const void* objectID);
+
+ virtual BpBinder* remoteBinder();
+
+ status_t setConstantData(const void* data, size_t size);
+ void sendObituary();
+
+ class ObjectManager
+ {
+ public:
+ ObjectManager();
+ ~ObjectManager();
+
+ void attach( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ IBinder::object_cleanup_func func);
+ void* find(const void* objectID) const;
+ void detach(const void* objectID);
+
+ void kill();
+
+ private:
+ ObjectManager(const ObjectManager&);
+ ObjectManager& operator=(const ObjectManager&);
+
+ struct entry_t
+ {
+ void* object;
+ void* cleanupCookie;
+ IBinder::object_cleanup_func func;
+ };
+
+ KeyedVector<const void*, entry_t> mObjects;
+ };
+
+protected:
+ virtual ~BpBinder();
+ virtual void onFirstRef();
+ virtual void onLastStrongRef(const void* id);
+ virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
+
+private:
+ const int32_t mHandle;
+
+ struct Obituary {
+ wp<DeathRecipient> recipient;
+ void* cookie;
+ uint32_t flags;
+ };
+
+ void reportOneDeath(const Obituary& obit);
+ bool isDescriptorCached() const;
+
+ mutable Mutex mLock;
+ volatile int32_t mAlive;
+ volatile int32_t mObitsSent;
+ Vector<Obituary>* mObituaries;
+ ObjectManager mObjects;
+ Parcel* mConstantData;
+ mutable String16 mDescriptorCache;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_BPBINDER_H
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h
new file mode 100644
index 0000000..884b5c1
--- /dev/null
+++ b/include/binder/IBinder.h
@@ -0,0 +1,159 @@
+/*
+ * 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 ANDROID_IBINDER_H
+#define ANDROID_IBINDER_H
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+
+#define B_PACK_CHARS(c1, c2, c3, c4) \
+ ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class BBinder;
+class BpBinder;
+class IInterface;
+class Parcel;
+
+/**
+ * Base class and low-level protocol for a remotable object.
+ * You can derive from this class to create an object for which other
+ * processes can hold references to it. Communication between processes
+ * (method calls, property get and set) is down through a low-level
+ * protocol implemented on top of the transact() API.
+ */
+class IBinder : public virtual RefBase
+{
+public:
+ enum {
+ FIRST_CALL_TRANSACTION = 0x00000001,
+ LAST_CALL_TRANSACTION = 0x00ffffff,
+
+ PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'),
+ DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'),
+ INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
+
+ // Corresponds to tfOneWay -- an asynchronous call.
+ FLAG_ONEWAY = 0x00000001
+ };
+
+ IBinder();
+
+ /**
+ * Check if this IBinder implements the interface named by
+ * @a descriptor. If it does, the base pointer to it is returned,
+ * which you can safely static_cast<> to the concrete C++ interface.
+ */
+ virtual sp<IInterface> queryLocalInterface(const String16& descriptor);
+
+ /**
+ * Return the canonical name of the interface provided by this IBinder
+ * object.
+ */
+ virtual const String16& getInterfaceDescriptor() const = 0;
+
+ virtual bool isBinderAlive() const = 0;
+ virtual status_t pingBinder() = 0;
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+ virtual status_t transact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0) = 0;
+
+ /**
+ * This method allows you to add data that is transported through
+ * IPC along with your IBinder pointer. When implementing a Binder
+ * object, override it to write your desired data in to @a outData.
+ * You can then call getConstantData() on your IBinder to retrieve
+ * that data, from any process. You MUST return the number of bytes
+ * written in to the parcel (including padding).
+ */
+ class DeathRecipient : public virtual RefBase
+ {
+ public:
+ virtual void binderDied(const wp<IBinder>& who) = 0;
+ };
+
+ /**
+ * Register the @a recipient for a notification if this binder
+ * goes away. If this binder object unexpectedly goes away
+ * (typically because its hosting process has been killed),
+ * then DeathRecipient::binderDied() will be called with a referene
+ * to this.
+ *
+ * The @a cookie is optional -- if non-NULL, it should be a
+ * memory address that you own (that is, you know it is unique).
+ *
+ * @note You will only receive death notifications for remote binders,
+ * as local binders by definition can't die without you dying as well.
+ * Trying to use this function on a local binder will result in an
+ * INVALID_OPERATION code being returned and nothing happening.
+ *
+ * @note This link always holds a weak reference to its recipient.
+ *
+ * @note You will only receive a weak reference to the dead
+ * binder. You should not try to promote this to a strong reference.
+ * (Nor should you need to, as there is nothing useful you can
+ * directly do with it now that it has passed on.)
+ */
+ virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0) = 0;
+
+ /**
+ * Remove a previously registered death notification.
+ * The @a recipient will no longer be called if this object
+ * dies. The @a cookie is optional. If non-NULL, you can
+ * supply a NULL @a recipient, and the recipient previously
+ * added with that cookie will be unlinked.
+ */
+ virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
+ void* cookie = NULL,
+ uint32_t flags = 0,
+ wp<DeathRecipient>* outRecipient = NULL) = 0;
+
+ virtual bool checkSubclass(const void* subclassID) const;
+
+ typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
+
+ virtual void attachObject( const void* objectID,
+ void* object,
+ void* cleanupCookie,
+ object_cleanup_func func) = 0;
+ virtual void* findObject(const void* objectID) const = 0;
+ virtual void detachObject(const void* objectID) = 0;
+
+ virtual BBinder* localBinder();
+ virtual BpBinder* remoteBinder();
+
+protected:
+ virtual ~IBinder();
+
+private:
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IBINDER_H
diff --git a/include/binder/IInterface.h b/include/binder/IInterface.h
new file mode 100644
index 0000000..273d922
--- /dev/null
+++ b/include/binder/IInterface.h
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+//
+#ifndef ANDROID_IINTERFACE_H
+#define ANDROID_IINTERFACE_H
+
+#include <binder/Binder.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IInterface : public virtual RefBase
+{
+public:
+ IInterface();
+ sp<IBinder> asBinder();
+ sp<const IBinder> asBinder() const;
+
+protected:
+ virtual ~IInterface();
+ virtual IBinder* onAsBinder() = 0;
+};
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
+{
+ return INTERFACE::asInterface(obj);
+}
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+class BnInterface : public INTERFACE, public BBinder
+{
+public:
+ virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
+ virtual const String16& getInterfaceDescriptor() const;
+
+protected:
+ virtual IBinder* onAsBinder();
+};
+
+// ----------------------------------------------------------------------
+
+template<typename INTERFACE>
+class BpInterface : public INTERFACE, public BpRefBase
+{
+public:
+ BpInterface(const sp<IBinder>& remote);
+
+protected:
+ virtual IBinder* onAsBinder();
+};
+
+// ----------------------------------------------------------------------
+
+#define DECLARE_META_INTERFACE(INTERFACE) \
+ static const String16 descriptor; \
+ static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj); \
+ virtual const String16& getInterfaceDescriptor() const; \
+ I##INTERFACE(); \
+ virtual ~I##INTERFACE(); \
+
+
+#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
+ const String16 I##INTERFACE::descriptor(NAME); \
+ const String16& I##INTERFACE::getInterfaceDescriptor() const { \
+ return I##INTERFACE::descriptor; \
+ } \
+ sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj) \
+ { \
+ sp<I##INTERFACE> intr; \
+ if (obj != NULL) { \
+ intr = static_cast<I##INTERFACE*>( \
+ obj->queryLocalInterface( \
+ I##INTERFACE::descriptor).get()); \
+ if (intr == NULL) { \
+ intr = new Bp##INTERFACE(obj); \
+ } \
+ } \
+ 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-serviceable parts after this...
+
+template<typename INTERFACE>
+inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
+ const String16& _descriptor)
+{
+ if (_descriptor == INTERFACE::descriptor) return this;
+ return NULL;
+}
+
+template<typename INTERFACE>
+inline const String16& BnInterface<INTERFACE>::getInterfaceDescriptor() const
+{
+ return INTERFACE::getInterfaceDescriptor();
+}
+
+template<typename INTERFACE>
+IBinder* BnInterface<INTERFACE>::onAsBinder()
+{
+ return this;
+}
+
+template<typename INTERFACE>
+inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
+ : BpRefBase(remote)
+{
+}
+
+template<typename INTERFACE>
+inline IBinder* BpInterface<INTERFACE>::onAsBinder()
+{
+ return remote();
+}
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IINTERFACE_H
diff --git a/include/binder/IMemory.h b/include/binder/IMemory.h
new file mode 100644
index 0000000..ae042cb
--- /dev/null
+++ b/include/binder/IMemory.h
@@ -0,0 +1,102 @@
+/*
+ * 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_IMEMORY_H
+#define ANDROID_IMEMORY_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IMemoryHeap : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MemoryHeap);
+
+ // flags returned by getFlags()
+ enum {
+ READ_ONLY = 0x00000001,
+ MAP_ONCE = 0x00000002
+ };
+
+ virtual int getHeapID() const = 0;
+ virtual void* getBase() const = 0;
+ virtual size_t getSize() const = 0;
+ virtual uint32_t getFlags() const = 0;
+
+ // these are there just for backward source compatibility
+ int32_t heapID() const { return getHeapID(); }
+ void* base() const { return getBase(); }
+ size_t virtualSize() const { return getSize(); }
+};
+
+class BnMemoryHeap : public BnInterface<IMemoryHeap>
+{
+public:
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+ BnMemoryHeap();
+protected:
+ virtual ~BnMemoryHeap();
+};
+
+// ----------------------------------------------------------------------------
+
+class IMemory : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(Memory);
+
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
+
+ // helpers
+ void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
+ void* pointer() const;
+ size_t size() const;
+ ssize_t offset() const;
+};
+
+class BnMemory : public BnInterface<IMemory>
+{
+public:
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+
+ BnMemory();
+protected:
+ virtual ~BnMemory();
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IMEMORY_H
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
new file mode 100644
index 0000000..78306b2
--- /dev/null
+++ b/include/binder/IPCThreadState.h
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IPC_THREAD_STATE_H
+#define ANDROID_IPC_THREAD_STATE_H
+
+#include <utils/Errors.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <utils/Vector.h>
+
+#ifdef HAVE_WIN32_PROC
+typedef int uid_t;
+#endif
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IPCThreadState
+{
+public:
+ static IPCThreadState* self();
+
+ sp<ProcessState> process();
+
+ status_t clearLastError();
+
+ int getCallingPid();
+ int getCallingUid();
+
+ int64_t clearCallingIdentity();
+ void restoreCallingIdentity(int64_t token);
+
+ void flushCommands();
+
+ void joinThreadPool(bool isMain = true);
+
+ // Stop the local process.
+ void stopProcess(bool immediate = true);
+
+ status_t transact(int32_t handle,
+ uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+
+ void incStrongHandle(int32_t handle);
+ void decStrongHandle(int32_t handle);
+ void incWeakHandle(int32_t handle);
+ void decWeakHandle(int32_t handle);
+ status_t attemptIncStrongHandle(int32_t handle);
+ static void expungeHandle(int32_t handle, IBinder* binder);
+ status_t requestDeathNotification( int32_t handle,
+ BpBinder* proxy);
+ status_t clearDeathNotification( int32_t handle,
+ BpBinder* proxy);
+
+ static void shutdown();
+
+private:
+ IPCThreadState();
+ ~IPCThreadState();
+
+ status_t sendReply(const Parcel& reply, uint32_t flags);
+ status_t waitForResponse(Parcel *reply,
+ status_t *acquireResult=NULL);
+ status_t talkWithDriver(bool doReceive=true);
+ status_t writeTransactionData(int32_t cmd,
+ uint32_t binderFlags,
+ int32_t handle,
+ uint32_t code,
+ const Parcel& data,
+ status_t* statusBuffer);
+ status_t executeCommand(int32_t command);
+
+ void clearCaller();
+
+ static void threadDestructor(void *st);
+ static void freeBuffer(Parcel* parcel,
+ const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsSize,
+ void* cookie);
+
+ const sp<ProcessState> mProcess;
+ Vector<BBinder*> mPendingStrongDerefs;
+ Vector<RefBase::weakref_type*> mPendingWeakDerefs;
+
+ Parcel mIn;
+ Parcel mOut;
+ status_t mLastError;
+ pid_t mCallingPid;
+ uid_t mCallingUid;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IPC_THREAD_STATE_H
diff --git a/include/binder/IPermissionController.h b/include/binder/IPermissionController.h
new file mode 100644
index 0000000..f9d371b
--- /dev/null
+++ b/include/binder/IPermissionController.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+//
+#ifndef ANDROID_IPERMISSION_CONTROLLER_H
+#define ANDROID_IPERMISSION_CONTROLLER_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IPermissionController : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(PermissionController);
+
+ virtual bool checkPermission(const String16& permission,
+ int32_t pid, int32_t uid) = 0;
+
+ enum {
+ CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+ };
+};
+
+// ----------------------------------------------------------------------
+
+class BnPermissionController : public BnInterface<IPermissionController>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IPERMISSION_CONTROLLER_H
+
diff --git a/include/binder/IServiceManager.h b/include/binder/IServiceManager.h
new file mode 100644
index 0000000..24e9e99
--- /dev/null
+++ b/include/binder/IServiceManager.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+//
+#ifndef ANDROID_ISERVICE_MANAGER_H
+#define ANDROID_ISERVICE_MANAGER_H
+
+#include <binder/IInterface.h>
+#include <binder/IPermissionController.h>
+#include <utils/Vector.h>
+#include <utils/String16.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IServiceManager : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(ServiceManager);
+
+ /**
+ * Retrieve an existing service, blocking for a few seconds
+ * if it doesn't yet exist.
+ */
+ virtual sp<IBinder> getService( const String16& name) const = 0;
+
+ /**
+ * Retrieve an existing service, non-blocking.
+ */
+ virtual sp<IBinder> checkService( const String16& name) const = 0;
+
+ /**
+ * Register a service.
+ */
+ virtual status_t addService( const String16& name,
+ const sp<IBinder>& service) = 0;
+
+ /**
+ * Return list of all existing services.
+ */
+ virtual Vector<String16> listServices() = 0;
+
+ enum {
+ GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ CHECK_SERVICE_TRANSACTION,
+ ADD_SERVICE_TRANSACTION,
+ LIST_SERVICES_TRANSACTION,
+ };
+};
+
+sp<IServiceManager> defaultServiceManager();
+
+template<typename INTERFACE>
+status_t getService(const String16& name, sp<INTERFACE>* outService)
+{
+ const sp<IServiceManager> sm = defaultServiceManager();
+ if (sm != NULL) {
+ *outService = interface_cast<INTERFACE>(sm->getService(name));
+ if ((*outService) != NULL) return NO_ERROR;
+ }
+ return NAME_NOT_FOUND;
+}
+
+bool checkCallingPermission(const String16& permission);
+bool checkCallingPermission(const String16& permission,
+ int32_t* outPid, int32_t* outUid);
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
+
+
+// ----------------------------------------------------------------------
+
+class BnServiceManager : public BnInterface<IServiceManager>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ISERVICE_MANAGER_H
+
diff --git a/include/binder/MemoryBase.h b/include/binder/MemoryBase.h
new file mode 100644
index 0000000..463e26d
--- /dev/null
+++ b/include/binder/MemoryBase.h
@@ -0,0 +1,51 @@
+/*
+ * 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 ANDROID_MEMORY_BASE_H
+#define ANDROID_MEMORY_BASE_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <binder/IMemory.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryBase : public BnMemory
+{
+public:
+ MemoryBase(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
+ virtual ~MemoryBase();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+
+protected:
+ size_t getSize() const { return mSize; }
+ ssize_t getOffset() const { return mOffset; }
+ const sp<IMemoryHeap>& getHeap() const { return mHeap; }
+
+private:
+ size_t mSize;
+ ssize_t mOffset;
+ sp<IMemoryHeap> mHeap;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_BASE_H
diff --git a/include/binder/MemoryDealer.h b/include/binder/MemoryDealer.h
new file mode 100644
index 0000000..03ac70a
--- /dev/null
+++ b/include/binder/MemoryDealer.h
@@ -0,0 +1,257 @@
+/*
+ * 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_MEMORY_DEALER_H
+#define ANDROID_MEMORY_DEALER_H
+
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/IMemory.h>
+#include <utils/threads.h>
+#include <binder/MemoryHeapBase.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+class String8;
+
+/*
+ * interface for implementing a "heap". A heap basically provides
+ * the IMemoryHeap interface for cross-process sharing and the
+ * ability to map/unmap pages within the heap.
+ */
+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();
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * interface for implementing an allocator. An allocator provides
+ * methods for allocating and freeing memory blocks and dumping
+ * its state.
+ */
+class AllocatorInterface : public RefBase
+{
+public:
+ enum {
+ PAGE_ALIGNED = 0x00000001
+ };
+
+ virtual size_t allocate(size_t size, uint32_t flags = 0) = 0;
+ virtual status_t deallocate(size_t offset) = 0;
+ virtual size_t size() const = 0;
+ 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();
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * concrete implementation of HeapInterface on top of mmap()
+ */
+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);
+};
+
+// ----------------------------------------------------------------------------
+
+/*
+ * A simple templatized doubly linked-list implementation
+ */
+
+template <typename NODE>
+class LinkedList
+{
+ NODE* mFirst;
+ NODE* mLast;
+
+public:
+ LinkedList() : mFirst(0), mLast(0) { }
+ bool isEmpty() const { return mFirst == 0; }
+ NODE const* head() const { return mFirst; }
+ NODE* head() { return mFirst; }
+ NODE const* tail() const { return mLast; }
+ NODE* tail() { return mLast; }
+
+ void insertAfter(NODE* node, NODE* newNode) {
+ newNode->prev = node;
+ newNode->next = node->next;
+ if (node->next == 0) mLast = newNode;
+ else node->next->prev = newNode;
+ node->next = newNode;
+ }
+
+ void insertBefore(NODE* node, NODE* newNode) {
+ newNode->prev = node->prev;
+ newNode->next = node;
+ if (node->prev == 0) mFirst = newNode;
+ else node->prev->next = newNode;
+ node->prev = newNode;
+ }
+
+ void insertHead(NODE* newNode) {
+ if (mFirst == 0) {
+ mFirst = mLast = newNode;
+ newNode->prev = newNode->next = 0;
+ } else {
+ newNode->prev = 0;
+ newNode->next = mFirst;
+ mFirst->prev = newNode;
+ mFirst = newNode;
+ }
+ }
+
+ void insertTail(NODE* newNode) {
+ if (mLast == 0) {
+ insertHead(newNode);
+ } else {
+ newNode->prev = mLast;
+ newNode->next = 0;
+ mLast->next = newNode;
+ mLast = newNode;
+ }
+ }
+
+ NODE* remove(NODE* node) {
+ if (node->prev == 0) mFirst = node->next;
+ else node->prev->next = node->next;
+ if (node->next == 0) mLast = node->prev;
+ else node->next->prev = node->prev;
+ return node;
+ }
+};
+
+
+/*
+ * concrete implementation of AllocatorInterface using a simple
+ * best-fit allocation scheme
+ */
+class SimpleBestFitAllocator : public AllocatorInterface
+{
+public:
+
+ SimpleBestFitAllocator(size_t size);
+ virtual ~SimpleBestFitAllocator();
+
+ virtual size_t allocate(size_t size, uint32_t flags = 0);
+ virtual status_t deallocate(size_t offset);
+ virtual size_t size() const;
+ virtual void dump(const char* what, uint32_t flags = 0) const;
+ virtual void dump(String8& res,
+ const char* what, uint32_t flags = 0) const;
+
+private:
+
+ struct chunk_t {
+ chunk_t(size_t start, size_t size)
+ : start(start), size(size), free(1), prev(0), next(0) {
+ }
+ size_t start;
+ size_t size : 28;
+ int free : 4;
+ mutable chunk_t* prev;
+ mutable chunk_t* next;
+ };
+
+ ssize_t alloc(size_t size, uint32_t flags);
+ chunk_t* dealloc(size_t start);
+ void dump_l(const char* what, uint32_t flags = 0) const;
+ void dump_l(String8& res, const char* what, uint32_t flags = 0) const;
+
+ static const int kMemoryAlign;
+ mutable Mutex mLock;
+ LinkedList<chunk_t> mList;
+ size_t mHeapSize;
+};
+
+// ----------------------------------------------------------------------------
+
+class MemoryDealer : public RefBase
+{
+public:
+
+ enum {
+ READ_ONLY = MemoryHeapBase::READ_ONLY,
+ PAGE_ALIGNED = AllocatorInterface::PAGE_ALIGNED
+ };
+
+ // creates a memory dealer with the SharedHeap and SimpleBestFitAllocator
+ MemoryDealer(size_t size, uint32_t flags = 0, const char* name = 0);
+
+ // provide a custom heap but use the SimpleBestFitAllocator
+ MemoryDealer(const sp<HeapInterface>& heap);
+
+ // provide both custom heap and allocotar
+ MemoryDealer(
+ const sp<HeapInterface>& heap,
+ const sp<AllocatorInterface>& allocator);
+
+ virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0);
+ virtual void deallocate(size_t offset);
+ virtual void dump(const char* what, uint32_t flags = 0) const;
+
+
+ sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
+ sp<AllocatorInterface> getAllocator() const { return allocator(); }
+
+protected:
+ virtual ~MemoryDealer();
+
+private:
+ const sp<HeapInterface>& heap() const;
+ const sp<AllocatorInterface>& allocator() const;
+
+ class Allocation : public BnMemory {
+ public:
+ Allocation(const sp<MemoryDealer>& dealer,
+ ssize_t offset, size_t size, const sp<IMemory>& memory);
+ virtual ~Allocation();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+ private:
+ sp<MemoryDealer> mDealer;
+ ssize_t mOffset;
+ size_t mSize;
+ sp<IMemory> mMemory;
+ };
+
+ sp<HeapInterface> mHeap;
+ sp<AllocatorInterface> mAllocator;
+};
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_DEALER_H
diff --git a/include/binder/MemoryHeapBase.h b/include/binder/MemoryHeapBase.h
new file mode 100644
index 0000000..435540e
--- /dev/null
+++ b/include/binder/MemoryHeapBase.h
@@ -0,0 +1,98 @@
+/*
+ * 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 ANDROID_MEMORY_HEAP_BASE_H
+#define ANDROID_MEMORY_HEAP_BASE_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <binder/IMemory.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MemoryHeapBase : public virtual BnMemoryHeap
+{
+public:
+ enum {
+ READ_ONLY = IMemoryHeap::READ_ONLY,
+ MAP_ONCE = IMemoryHeap::MAP_ONCE,
+ // memory won't be mapped locally, but will be mapped in the remote
+ // process.
+ DONT_MAP_LOCALLY = 0x00000100
+ };
+
+ /*
+ * maps the memory referenced by fd. but DOESN'T take ownership
+ * of the filedescriptor (it makes a copy with dup()
+ */
+ MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0);
+
+ /*
+ * maps memory from the given device
+ */
+ MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0);
+
+ /*
+ * maps memory from ashmem, with the given name for debugging
+ */
+ MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL);
+
+ virtual ~MemoryHeapBase();
+
+ /* implement IMemoryHeap interface */
+ virtual int getHeapID() const;
+ virtual void* getBase() const;
+ virtual size_t getSize() const;
+ virtual uint32_t getFlags() const;
+
+ const char* getDevice() const;
+
+ /* this closes this heap -- use carefully */
+ void dispose();
+
+ /* this is only needed as a workaround, use only if you know
+ * what you are doing */
+ status_t setDevice(const char* device) {
+ if (mDevice == 0)
+ mDevice = device;
+ return mDevice ? NO_ERROR : ALREADY_EXISTS;
+ }
+
+protected:
+ MemoryHeapBase();
+ // init() takes ownership of fd
+ status_t init(int fd, void *base, int size,
+ int flags = 0, const char* device = NULL);
+
+private:
+ status_t mapfd(int fd, size_t size, uint32_t offset = 0);
+
+ int mFD;
+ size_t mSize;
+ void* mBase;
+ uint32_t mFlags;
+ const char* mDevice;
+ bool mNeedUnmap;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_HEAP_BASE_H
diff --git a/include/binder/MemoryHeapPmem.h b/include/binder/MemoryHeapPmem.h
new file mode 100644
index 0000000..dbf26ff
--- /dev/null
+++ b/include/binder/MemoryHeapPmem.h
@@ -0,0 +1,80 @@
+/*
+ * 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 ANDROID_MEMORY_HEAP_PMEM_H
+#define ANDROID_MEMORY_HEAP_PMEM_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <binder/MemoryDealer.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/IMemory.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+
+class MemoryHeapBase;
+
+// ---------------------------------------------------------------------------
+
+class MemoryHeapPmem : public HeapInterface, public MemoryHeapBase
+{
+public:
+ class MemoryPmem : public BnMemory {
+ public:
+ MemoryPmem(const sp<MemoryHeapPmem>& heap);
+ ~MemoryPmem();
+ protected:
+ const sp<MemoryHeapPmem>& getHeap() const { return mClientHeap; }
+ private:
+ friend class MemoryHeapPmem;
+ virtual void revoke() = 0;
+ sp<MemoryHeapPmem> mClientHeap;
+ };
+
+ MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
+ uint32_t flags = IMemoryHeap::MAP_ONCE);
+ ~MemoryHeapPmem();
+
+ /* HeapInterface additions */
+ virtual sp<IMemory> mapMemory(size_t offset, size_t size);
+
+ /* make the whole heap visible (you know who you are) */
+ virtual status_t slap();
+
+ /* hide (revoke) the whole heap (the client will see the garbage page) */
+ virtual status_t unslap();
+
+ /* revoke all allocations made by this heap */
+ virtual void revoke();
+
+private:
+ /* use this to create your own IMemory for mapMemory */
+ virtual sp<MemoryPmem> createMemory(size_t offset, size_t size);
+ void remove(const wp<MemoryPmem>& memory);
+
+private:
+ sp<MemoryHeapBase> mParentHeap;
+ mutable Mutex mLock;
+ SortedVector< wp<MemoryPmem> > mAllocations;
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_MEMORY_HEAP_PMEM_H
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
new file mode 100644
index 0000000..ba6c711
--- /dev/null
+++ b/include/binder/Parcel.h
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_PARCEL_H
+#define ANDROID_PARCEL_H
+
+#include <cutils/native_handle.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IBinder;
+class ProcessState;
+class String8;
+class TextOutput;
+
+struct flat_binder_object; // defined in support_p/binder_module.h
+
+class Parcel
+{
+public:
+ Parcel();
+ ~Parcel();
+
+ const uint8_t* data() const;
+ size_t dataSize() const;
+ size_t dataAvail() const;
+ size_t dataPosition() const;
+ size_t dataCapacity() const;
+
+ status_t setDataSize(size_t size);
+ void setDataPosition(size_t pos) const;
+ status_t setDataCapacity(size_t size);
+
+ status_t setData(const uint8_t* buffer, size_t len);
+
+ status_t appendFrom(Parcel *parcel, size_t start, size_t len);
+
+ bool hasFileDescriptors() const;
+
+ status_t writeInterfaceToken(const String16& interface);
+ bool enforceInterface(const String16& interface) const;
+ bool checkInterface(IBinder*) const;
+
+ void freeData();
+
+ const size_t* objects() const;
+ size_t objectsCount() const;
+
+ status_t errorCheck() const;
+ void setError(status_t err);
+
+ status_t write(const void* data, size_t len);
+ void* writeInplace(size_t len);
+ status_t writeUnpadded(const void* data, size_t len);
+ status_t writeInt32(int32_t val);
+ status_t writeInt64(int64_t val);
+ status_t writeFloat(float val);
+ status_t writeDouble(double val);
+ status_t writeIntPtr(intptr_t val);
+ status_t writeCString(const char* str);
+ status_t writeString8(const String8& str);
+ status_t writeString16(const String16& str);
+ status_t writeString16(const char16_t* str, size_t len);
+ status_t writeStrongBinder(const sp<IBinder>& val);
+ status_t writeWeakBinder(const wp<IBinder>& val);
+
+ // Place a native_handle into the parcel (the native_handle's file-
+ // descriptors are dup'ed, so it is safe to delete the native_handle
+ // when this function returns).
+ // Doesn't take ownership of the native_handle.
+ status_t writeNativeHandle(const native_handle* handle);
+
+ // Place a file descriptor into the parcel. The given fd must remain
+ // valid for the lifetime of the parcel.
+ status_t writeFileDescriptor(int fd);
+
+ // Place a file descriptor into the parcel. A dup of the fd is made, which
+ // will be closed once the parcel is destroyed.
+ status_t writeDupFileDescriptor(int fd);
+
+ status_t writeObject(const flat_binder_object& val, bool nullMetaData);
+
+ void remove(size_t start, size_t amt);
+
+ status_t read(void* outData, size_t len) const;
+ const void* readInplace(size_t len) const;
+ int32_t readInt32() const;
+ status_t readInt32(int32_t *pArg) const;
+ int64_t readInt64() const;
+ status_t readInt64(int64_t *pArg) const;
+ float readFloat() const;
+ status_t readFloat(float *pArg) const;
+ double readDouble() const;
+ status_t readDouble(double *pArg) const;
+ intptr_t readIntPtr() const;
+ status_t readIntPtr(intptr_t *pArg) const;
+
+ const char* readCString() const;
+ String8 readString8() const;
+ String16 readString16() const;
+ const char16_t* readString16Inplace(size_t* outLen) const;
+ sp<IBinder> readStrongBinder() const;
+ wp<IBinder> readWeakBinder() const;
+
+
+ // Retrieve native_handle from the parcel. This returns a copy of the
+ // parcel's native_handle (the caller takes ownership). The caller
+ // must free the native_handle with native_handle_close() and
+ // native_handle_delete().
+ native_handle* readNativeHandle() const;
+
+
+ // Retrieve a file descriptor from the parcel. This returns the raw fd
+ // in the parcel, which you do not own -- use dup() to get your own copy.
+ int readFileDescriptor() const;
+
+ const flat_binder_object* readObject(bool nullMetaData) const;
+
+ // Explicitly close all file descriptors in the parcel.
+ void closeFileDescriptors();
+
+ typedef void (*release_func)(Parcel* parcel,
+ const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsSize,
+ void* cookie);
+
+ const uint8_t* ipcData() const;
+ size_t ipcDataSize() const;
+ const size_t* ipcObjects() const;
+ size_t ipcObjectsCount() const;
+ void ipcSetDataReference(const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsCount,
+ release_func relFunc, void* relCookie);
+
+ void print(TextOutput& to, uint32_t flags = 0) const;
+
+private:
+ Parcel(const Parcel& o);
+ Parcel& operator=(const Parcel& o);
+
+ status_t finishWrite(size_t len);
+ void releaseObjects();
+ void acquireObjects();
+ status_t growData(size_t len);
+ status_t restartWrite(size_t desired);
+ status_t continueWrite(size_t desired);
+ void freeDataNoInit();
+ void initState();
+ void scanForFds() const;
+
+ template<class T>
+ status_t readAligned(T *pArg) const;
+
+ template<class T> T readAligned() const;
+
+ template<class T>
+ status_t writeAligned(T val);
+
+ status_t mError;
+ uint8_t* mData;
+ size_t mDataSize;
+ size_t mDataCapacity;
+ mutable size_t mDataPos;
+ size_t* mObjects;
+ size_t mObjectsSize;
+ size_t mObjectsCapacity;
+ mutable size_t mNextObjectHint;
+
+ mutable bool mFdsKnown;
+ mutable bool mHasFds;
+
+ release_func mOwner;
+ void* mOwnerCookie;
+};
+
+// ---------------------------------------------------------------------------
+
+inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
+{
+ parcel.print(to);
+ return to;
+}
+
+// ---------------------------------------------------------------------------
+
+// Generic acquire and release of objects.
+void acquire_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who);
+void release_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who);
+
+void flatten_binder(const sp<ProcessState>& proc,
+ const sp<IBinder>& binder, flat_binder_object* out);
+void flatten_binder(const sp<ProcessState>& proc,
+ const wp<IBinder>& binder, flat_binder_object* out);
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const flat_binder_object& flat, sp<IBinder>* out);
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const flat_binder_object& flat, wp<IBinder>* out);
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PARCEL_H
diff --git a/include/binder/Permission.h b/include/binder/Permission.h
new file mode 100644
index 0000000..9542d50
--- /dev/null
+++ b/include/binder/Permission.h
@@ -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.
+ */
+
+#ifndef BINDER_PERMISSION_H
+#define BINDER_PERMISSION_H
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <utils/SortedVector.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+/*
+ * Permission caches the result of the permission check for the given
+ * permission name and the provided uid/pid. It also handles a few
+ * known cases efficiently (caller is in the same process or is root).
+ * The package manager does something similar but lives in dalvik world
+ * and is therefore extremely slow to access.
+ */
+
+class Permission
+{
+public:
+ Permission(char const* name);
+ Permission(const String16& name);
+ Permission(const Permission& rhs);
+ virtual ~Permission();
+
+ bool operator < (const Permission& rhs) const;
+
+ // checks the current binder call's caller has access to this permission
+ bool checkCalling() const;
+
+ // checks the specified pid/uid has access to this permission
+ bool check(pid_t pid, uid_t uid) const;
+
+protected:
+ virtual bool doCheckPermission(pid_t pid, uid_t uid) const;
+
+private:
+ Permission& operator = (const Permission& rhs) const;
+ const String16 mPermissionName;
+ mutable SortedVector<uid_t> mGranted;
+ const pid_t mPid;
+ mutable Mutex mLock;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif /* BINDER_PERMISSION_H */
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
new file mode 100644
index 0000000..feeb3c3
--- /dev/null
+++ b/include/binder/ProcessState.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_PROCESS_STATE_H
+#define ANDROID_PROCESS_STATE_H
+
+#include <binder/IBinder.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+// Global variables
+extern int mArgC;
+extern const char* const* mArgV;
+extern int mArgLen;
+
+class IPCThreadState;
+
+class ProcessState : public virtual RefBase
+{
+public:
+ static sp<ProcessState> self();
+
+ static void setSingleProcess(bool singleProcess);
+
+ void setContextObject(const sp<IBinder>& object);
+ sp<IBinder> getContextObject(const sp<IBinder>& caller);
+
+ void setContextObject(const sp<IBinder>& object,
+ const String16& name);
+ sp<IBinder> getContextObject(const String16& name,
+ const sp<IBinder>& caller);
+
+ bool supportsProcesses() const;
+
+ void startThreadPool();
+
+ typedef bool (*context_check_func)(const String16& name,
+ const sp<IBinder>& caller,
+ void* userData);
+
+ bool isContextManager(void) const;
+ bool becomeContextManager(
+ context_check_func checkFunc,
+ void* userData);
+
+ sp<IBinder> getStrongProxyForHandle(int32_t handle);
+ wp<IBinder> getWeakProxyForHandle(int32_t handle);
+ void expungeHandle(int32_t handle, IBinder* binder);
+
+ void setArgs(int argc, const char* const argv[]);
+ int getArgC() const;
+ const char* const* getArgV() const;
+
+ void setArgV0(const char* txt);
+
+ void spawnPooledThread(bool isMain);
+
+private:
+ friend class IPCThreadState;
+
+ ProcessState();
+ ~ProcessState();
+
+ ProcessState(const ProcessState& o);
+ ProcessState& operator=(const ProcessState& o);
+
+ struct handle_entry {
+ IBinder* binder;
+ RefBase::weakref_type* refs;
+ };
+
+ handle_entry* lookupHandleLocked(int32_t handle);
+
+ int mDriverFD;
+ void* mVMStart;
+
+ mutable Mutex mLock; // protects everything below.
+
+ Vector<handle_entry>mHandleToObject;
+
+ bool mManagesContexts;
+ context_check_func mBinderContextCheckFunc;
+ void* mBinderContextUserData;
+
+ KeyedVector<String16, sp<IBinder> >
+ mContexts;
+
+
+ String8 mRootDir;
+ bool mThreadPoolStarted;
+ volatile int32_t mThreadPoolSeq;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PROCESS_STATE_H
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 13e51ee..503cb31 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>
@@ -39,21 +39,10 @@ class AudioRecord
{
public:
- // input sources values must always be defined in the range
- // [AudioRecord::DEFAULT_INPUT, AudioRecord::NUM_INPUT_SOURCES[
- enum input_source {
- DEFAULT_INPUT =-1,
- MIC_INPUT = 0,
- VOICE_UPLINK_INPUT = 1,
- VOICE_DOWNLINK_INPUT = 2,
- VOICE_CALL_INPUT = 3,
- NUM_INPUT_SOURCES
- };
-
static const int DEFAULT_SAMPLE_RATE = 8000;
/* Events used by AudioRecord callback function (callback_t).
- *
+ *
* to keep in sync with frameworks/base/media/java/android/media/AudioRecord.java
*/
enum event_type {
@@ -61,7 +50,7 @@ public:
EVENT_OVERRUN = 1, // PCM buffer overrun occured.
EVENT_MARKER = 2, // Record head is at the specified marker position
// (See setMarkerPosition()).
- EVENT_NEW_POS = 3, // Record head is at a new position
+ EVENT_NEW_POS = 3, // Record head is at a new position
// (See setPositionUpdatePeriod()).
};
@@ -123,11 +112,11 @@ public:
*
* Parameters:
*
- * inputSource: Select the audio input to record to (e.g. AudioRecord::MIC_INPUT).
+ * inputSource: Select the audio input to record to (e.g. AUDIO_SOURCE_DEFAULT).
* sampleRate: Track sampling rate in Hz.
- * format: PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
+ * format: Audio format (e.g AudioSystem::PCM_16_BIT for signed
* 16 bits per sample).
- * channelCount: Number of PCM channels (e.g 2 for stereo).
+ * channels: Channel mask: see AudioSystem::audio_channels.
* frameCount: Total size of track PCM buffer in frames. This defines the
* latency of the track.
* flags: A bitmask of acoustic values from enum record_flags. It enables
@@ -148,7 +137,7 @@ public:
AudioRecord(int inputSource,
uint32_t sampleRate = 0,
int format = 0,
- int channelCount = 0,
+ uint32_t channels = AudioSystem::CHANNEL_IN_MONO,
int frameCount = 0,
uint32_t flags = 0,
callback_t cbf = 0,
@@ -166,14 +155,14 @@ public:
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful intialization
* - INVALID_OPERATION: AudioRecord is already intitialized or record device is already in use
- * - BAD_VALUE: invalid parameter (channelCount, format, sampleRate...)
+ * - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
* - NO_INIT: audio server or audio hardware not initialized
* - PERMISSION_DENIED: recording is not allowed for the requesting process
* */
status_t set(int inputSource = 0,
uint32_t sampleRate = 0,
int format = 0,
- int channelCount = 0,
+ uint32_t channels = AudioSystem::CHANNEL_IN_MONO,
int frameCount = 0,
uint32_t flags = 0,
callback_t cbf = 0,
@@ -199,6 +188,7 @@ public:
int format() const;
int channelCount() const;
+ int channels() const;
uint32_t frameCount() const;
int frameSize() const;
int inputSource() const;
@@ -222,8 +212,8 @@ public:
/* Sets marker position. When record reaches the number of frames specified,
* a callback with event type EVENT_MARKER is called. Calling setMarkerPosition
- * with marker == 0 cancels marker notification callback.
- * If the AudioRecord has been opened with no callback function associated,
+ * with marker == 0 cancels marker notification callback.
+ * If the AudioRecord has been opened with no callback function associated,
* the operation will fail.
*
* Parameters:
@@ -238,10 +228,10 @@ public:
status_t getMarkerPosition(uint32_t *marker);
- /* Sets position update period. Every time the number of frames specified has been recorded,
- * a callback with event type EVENT_NEW_POS is called.
- * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
- * callback.
+ /* Sets position update period. Every time the number of frames specified has been recorded,
+ * a callback with event type EVENT_NEW_POS is called.
+ * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
+ * callback.
* If the AudioRecord has been opened with no callback function associated,
* the operation will fail.
*
@@ -257,8 +247,8 @@ public:
status_t getPositionUpdatePeriod(uint32_t *updatePeriod);
- /* Gets record head position. The position is the total number of frames
- * recorded since record start.
+ /* Gets record head position. The position is the total number of frames
+ * recorded since record start.
*
* Parameters:
*
@@ -270,8 +260,16 @@ public:
*/
status_t getPosition(uint32_t *position);
-
-
+ /* returns a handle on the audio input used by this AudioRecord.
+ *
+ * Parameters:
+ * none.
+ *
+ * Returned value:
+ * handle on audio hardware input
+ */
+ audio_io_handle_t getInput() { return mInput; }
+
/* obtains a buffer of "frameCount" frames. The buffer must be
* filled entirely. If the track is stopped, obtainBuffer() returns
* STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -342,6 +340,7 @@ private:
bool mMarkerReached;
uint32_t mNewPosition;
uint32_t mUpdatePeriod;
+ audio_io_handle_t mInput;
};
}; // namespace android
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 3a3a714..57f8102 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -24,36 +24,130 @@
namespace android {
typedef void (*audio_error_callback)(status_t err);
+typedef int audio_io_handle_t;
+
+class IAudioPolicyService;
+class String8;
class AudioSystem
{
public:
enum stream_type {
- DEFAULT =-1,
- VOICE_CALL = 0,
- SYSTEM = 1,
- RING = 2,
- MUSIC = 3,
- ALARM = 4,
- NOTIFICATION = 5,
- BLUETOOTH_SCO = 6,
+ DEFAULT =-1,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker
+ DTMF = 8,
+ TTS = 9,
NUM_STREAM_TYPES
};
- enum audio_output_type {
- AUDIO_OUTPUT_DEFAULT =-1,
- AUDIO_OUTPUT_HARDWARE = 0,
- AUDIO_OUTPUT_A2DP = 1,
- NUM_AUDIO_OUTPUT_TYPES
+ // Audio sub formats (see AudioSystem::audio_format).
+ enum pcm_sub_format {
+ PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility
+ PCM_SUB_8_BIT = 0x2, // must be 2 for backward compatibility
+ };
+
+ // MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to specify
+ // bit rate, stereo mode, version...
+ enum mp3_sub_format {
+ //TODO
+ };
+
+ // AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient or octet aligned,
+ // encoding mode for recording...
+ enum amr_sub_format {
+ //TODO
+ };
+
+ // AAC sub format field definition: specify profile or bitrate for recording...
+ enum aac_sub_format {
+ //TODO
};
+ // VORBIS sub format field definition: specify quality for recording...
+ enum vorbis_sub_format {
+ //TODO
+ };
+
+ // Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24 bits).
+ // The main format indicates the main codec type. The sub format field indicates options and parameters
+ // for each format. The sub format is mainly used for record to indicate for instance the requested bitrate
+ // or profile. It can also be used for certain formats to give informations not present in the encoded
+ // audio stream (e.g. octet alignement for AMR).
enum audio_format {
- FORMAT_DEFAULT = 0,
- PCM_16_BIT,
- PCM_8_BIT,
- INVALID_FORMAT
+ INVALID_FORMAT = -1,
+ FORMAT_DEFAULT = 0,
+ PCM = 0x00000000, // must be 0 for backward compatibility
+ MP3 = 0x01000000,
+ AMR_NB = 0x02000000,
+ AMR_WB = 0x03000000,
+ AAC = 0x04000000,
+ HE_AAC_V1 = 0x05000000,
+ HE_AAC_V2 = 0x06000000,
+ VORBIS = 0x07000000,
+ MAIN_FORMAT_MASK = 0xFF000000,
+ SUB_FORMAT_MASK = 0x00FFFFFF,
+ // Aliases
+ PCM_16_BIT = (PCM|PCM_SUB_16_BIT),
+ PCM_8_BIT = (PCM|PCM_SUB_8_BIT)
+ };
+
+
+ // Channel mask definitions must be kept in sync with JAVA values in /media/java/android/media/AudioFormat.java
+ enum audio_channels {
+ // output channels
+ CHANNEL_OUT_FRONT_LEFT = 0x4,
+ CHANNEL_OUT_FRONT_RIGHT = 0x8,
+ CHANNEL_OUT_FRONT_CENTER = 0x10,
+ CHANNEL_OUT_LOW_FREQUENCY = 0x20,
+ CHANNEL_OUT_BACK_LEFT = 0x40,
+ CHANNEL_OUT_BACK_RIGHT = 0x80,
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100,
+ CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,
+ CHANNEL_OUT_BACK_CENTER = 0x400,
+ CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
+ CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT),
+ CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+ CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER),
+ CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+ CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
+ CHANNEL_OUT_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER),
+
+ // input channels
+ CHANNEL_IN_LEFT = 0x4,
+ CHANNEL_IN_RIGHT = 0x8,
+ CHANNEL_IN_FRONT = 0x10,
+ CHANNEL_IN_BACK = 0x20,
+ CHANNEL_IN_LEFT_PROCESSED = 0x40,
+ CHANNEL_IN_RIGHT_PROCESSED = 0x80,
+ CHANNEL_IN_FRONT_PROCESSED = 0x100,
+ CHANNEL_IN_BACK_PROCESSED = 0x200,
+ CHANNEL_IN_PRESSURE = 0x400,
+ CHANNEL_IN_X_AXIS = 0x800,
+ CHANNEL_IN_Y_AXIS = 0x1000,
+ CHANNEL_IN_Z_AXIS = 0x2000,
+ CHANNEL_IN_VOICE_UPLINK = 0x4000,
+ CHANNEL_IN_VOICE_DNLINK = 0x8000,
+ CHANNEL_IN_MONO = CHANNEL_IN_FRONT,
+ CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT),
+ CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK|
+ CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED | CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED|
+ CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS | CHANNEL_IN_Z_AXIS |
+ CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK)
};
enum audio_mode {
@@ -65,15 +159,6 @@ public:
NUM_MODES // not a valid entry, denotes end-of-list
};
- enum audio_routes {
- ROUTE_EARPIECE = (1 << 0),
- ROUTE_SPEAKER = (1 << 1),
- ROUTE_BLUETOOTH_SCO = (1 << 2),
- ROUTE_HEADSET = (1 << 3),
- ROUTE_BLUETOOTH_A2DP = (1 << 4),
- ROUTE_ALL = -1UL,
- };
-
enum audio_in_acoustics {
AGC_ENABLE = 0x0001,
AGC_DISABLE = 0,
@@ -87,36 +172,37 @@ public:
* only privileged processes can have access to them
*/
- // routing helper functions
- static status_t speakerphone(bool state);
- static status_t isSpeakerphoneOn(bool* state);
- static status_t bluetoothSco(bool state);
- static status_t isBluetoothScoOn(bool* state);
+ // mute/unmute microphone
static status_t muteMicrophone(bool state);
static status_t isMicrophoneMuted(bool *state);
+ // set/get master volume
static status_t setMasterVolume(float value);
- static status_t setMasterMute(bool mute);
static status_t getMasterVolume(float* volume);
+ // mute/unmute audio outputs
+ static status_t setMasterMute(bool mute);
static status_t getMasterMute(bool* mute);
- static status_t setStreamVolume(int stream, float value);
+ // set/get stream volume on specified output
+ static status_t setStreamVolume(int stream, float value, int output);
+ static status_t getStreamVolume(int stream, float* volume, int output);
+
+ // mute/unmute stream
static status_t setStreamMute(int stream, bool mute);
- static status_t getStreamVolume(int stream, float* volume);
static status_t getStreamMute(int stream, bool* mute);
+ // set audio mode in audio hardware (see AudioSystem::audio_mode)
static status_t setMode(int mode);
- static status_t getMode(int* mode);
-
- static status_t setRouting(int mode, uint32_t routes, uint32_t mask);
- static status_t getRouting(int mode, uint32_t* routes);
+ // returns true if tracks are active on AudioSystem::MUSIC stream
static status_t isMusicActive(bool *state);
- // Temporary interface, do not use
- // TODO: Replace with a more generic key:value get/set mechanism
- static status_t setParameter(const char* key, const char* value);
-
+ // set/get audio hardware parameters. The function accepts a list of parameters
+ // key value pairs in the form: key1=value1;key2=value2;...
+ // Some keys are reserved for standard parameters (See AudioParameter class).
+ static status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
+ static String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
+
static void setErrorCallback(audio_error_callback cb);
// helper function to obtain AudioFlinger service handle
@@ -130,47 +216,248 @@ public:
static status_t getOutputLatency(uint32_t* latency, int stream = DEFAULT);
static bool routedToA2dpOutput(int streamType);
-
- static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
+
+ static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
size_t* buffSize);
+
+ //
+ // AudioPolicyService interface
+ //
+
+ enum audio_devices {
+ // output devices
+ DEVICE_OUT_EARPIECE = 0x1,
+ DEVICE_OUT_SPEAKER = 0x2,
+ DEVICE_OUT_WIRED_HEADSET = 0x4,
+ DEVICE_OUT_WIRED_HEADPHONE = 0x8,
+ DEVICE_OUT_BLUETOOTH_SCO = 0x10,
+ DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
+ DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
+ DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
+ DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
+ DEVICE_OUT_AUX_DIGITAL = 0x400,
+ DEVICE_OUT_FM_HEADPHONE = 0x800,
+ DEVICE_OUT_FM_SPEAKER = 0x1000,
+ DEVICE_OUT_TTY = 0x2000,
+ DEVICE_OUT_DEFAULT = 0x8000,
+ DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
+ DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_FM_HEADPHONE |
+ DEVICE_OUT_FM_SPEAKER | DEVICE_OUT_TTY | DEVICE_OUT_DEFAULT),
+
+ // input devices
+ DEVICE_IN_COMMUNICATION = 0x10000,
+ DEVICE_IN_AMBIENT = 0x20000,
+ DEVICE_IN_BUILTIN_MIC = 0x40000,
+ DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
+ DEVICE_IN_WIRED_HEADSET = 0x100000,
+ DEVICE_IN_AUX_DIGITAL = 0x200000,
+ DEVICE_IN_VOICE_CALL = 0x400000,
+ DEVICE_IN_DEFAULT = 0x80000000,
+
+ DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC |
+ DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL |
+ DEVICE_IN_VOICE_CALL| DEVICE_IN_DEFAULT)
+ };
+
+ // device connection states used for setDeviceConnectionState()
+ enum device_connection_state {
+ DEVICE_STATE_UNAVAILABLE,
+ DEVICE_STATE_AVAILABLE,
+ NUM_DEVICE_STATES
+ };
+
+ // request to open a direct output with getOutput() (by opposition to sharing an output with other AudioTracks)
+ enum output_flags {
+ OUTPUT_FLAG_INDIRECT = 0x0,
+ OUTPUT_FLAG_DIRECT = 0x1
+ };
+
+ // device categories used for setForceUse()
+ enum forced_config {
+ FORCE_NONE,
+ FORCE_SPEAKER,
+ FORCE_HEADPHONES,
+ FORCE_BT_SCO,
+ FORCE_BT_A2DP,
+ FORCE_WIRED_ACCESSORY,
+ NUM_FORCE_CONFIG,
+ FORCE_DEFAULT = FORCE_NONE
+ };
+
+ // usages used for setForceUse()
+ enum force_use {
+ FOR_COMMUNICATION,
+ FOR_MEDIA,
+ FOR_RECORD,
+ NUM_FORCE_USE
+ };
+
+ // types of io configuration change events received with ioConfigChanged()
+ enum io_config_event {
+ OUTPUT_OPENED,
+ OUTPUT_CLOSED,
+ OUTPUT_CONFIG_CHANGED,
+ INPUT_OPENED,
+ INPUT_CLOSED,
+ INPUT_CONFIG_CHANGED,
+ STREAM_CONFIG_CHANGED,
+ NUM_CONFIG_EVENTS
+ };
+
+ // audio output descritor used to cache output configurations in client process to avoid frequent calls
+ // through IAudioFlinger
+ class OutputDescriptor {
+ public:
+ OutputDescriptor()
+ : samplingRate(0), format(0), channels(0), frameCount(0), latency(0) {}
+
+ uint32_t samplingRate;
+ int32_t format;
+ int32_t channels;
+ size_t frameCount;
+ uint32_t latency;
+ };
+
+ //
+ // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
+ //
+ static status_t setDeviceConnectionState(audio_devices device, device_connection_state state, const char *device_address);
+ static device_connection_state getDeviceConnectionState(audio_devices device, const char *device_address);
+ static status_t setPhoneState(int state);
+ static status_t setRingerMode(uint32_t mode, uint32_t mask);
+ static status_t setForceUse(force_use usage, forced_config config);
+ static forced_config getForceUse(force_use usage);
+ static audio_io_handle_t getOutput(stream_type stream,
+ uint32_t samplingRate = 0,
+ uint32_t format = FORMAT_DEFAULT,
+ uint32_t channels = CHANNEL_OUT_STEREO,
+ output_flags flags = OUTPUT_FLAG_INDIRECT);
+ static status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ static status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ static void releaseOutput(audio_io_handle_t output);
+ static audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate = 0,
+ uint32_t format = FORMAT_DEFAULT,
+ uint32_t channels = CHANNEL_IN_MONO,
+ audio_in_acoustics acoustics = (audio_in_acoustics)0);
+ static status_t startInput(audio_io_handle_t input);
+ static status_t stopInput(audio_io_handle_t input);
+ static void releaseInput(audio_io_handle_t input);
+ static status_t initStreamVolume(stream_type stream,
+ int indexMin,
+ int indexMax);
+ static status_t setStreamVolumeIndex(stream_type stream, int index);
+ static status_t getStreamVolumeIndex(stream_type stream, int *index);
+
+ static const sp<IAudioPolicyService>& get_audio_policy_service();
+
// ----------------------------------------------------------------------------
+ static uint32_t popCount(uint32_t u);
+ static bool isOutputDevice(audio_devices device);
+ static bool isInputDevice(audio_devices device);
+ static bool isA2dpDevice(audio_devices device);
+ static bool isBluetoothScoDevice(audio_devices device);
+ static bool isLowVisibility(stream_type stream);
+ static bool isOutputChannel(uint32_t channel);
+ static bool isInputChannel(uint32_t channel);
+ static bool isValidFormat(uint32_t format);
+ static bool isLinearPCM(uint32_t format);
+
private:
class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient
{
public:
- AudioFlingerClient() {
+ AudioFlingerClient() {
}
-
+
// DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
-
+
// IAudioFlingerClient
- virtual void a2dpEnabledChanged(bool enabled);
-
+
+ // indicate a change in the configuration of an output or input: keeps the cached
+ // values for output/input parameters upto date in client process
+ virtual void ioConfigChanged(int event, int ioHandle, void *param2);
};
- static int getOutput(int streamType);
- static sp<AudioFlingerClient> gAudioFlingerClient;
+ class AudioPolicyServiceClient: public IBinder::DeathRecipient
+ {
+ public:
+ AudioPolicyServiceClient() {
+ }
+ // DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+ };
+
+ static sp<AudioFlingerClient> gAudioFlingerClient;
+ static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient;
friend class AudioFlingerClient;
+ friend class AudioPolicyServiceClient;
static Mutex gLock;
static sp<IAudioFlinger> gAudioFlinger;
static audio_error_callback gAudioErrorCallback;
- static int gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
- static int gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
- static uint32_t gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
- static bool gA2dpEnabled;
-
+
static size_t gInBuffSize;
// previous parameters for recording buffer size queries
static uint32_t gPrevInSamplingRate;
static int gPrevInFormat;
static int gPrevInChannelCount;
+ static sp<IAudioPolicyService> gAudioPolicyService;
+
+ // mapping between stream types and outputs
+ static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap;
+ // list of output descritor containing cached parameters (sampling rate, framecount, channel count...)
+ static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
+};
+
+class AudioParameter {
+
+public:
+ AudioParameter() {}
+ AudioParameter(const String8& keyValuePairs);
+ virtual ~AudioParameter();
+
+ // reserved parameter keys for changeing standard parameters with setParameters() function.
+ // Using these keys is mandatory for AudioFlinger to properly monitor audio output/input
+ // configuration changes and act accordingly.
+ // keyRouting: to change audio routing, value is an int in AudioSystem::audio_devices
+ // keySamplingRate: to change sampling rate routing, value is an int
+ // keyFormat: to change audio format, value is an int in AudioSystem::audio_format
+ // keyChannels: to change audio channel configuration, value is an int in AudioSystem::audio_channels
+ // keyFrameCount: to change audio output frame count, value is an int
+ static const char *keyRouting;
+ static const char *keySamplingRate;
+ static const char *keyFormat;
+ static const char *keyChannels;
+ static const char *keyFrameCount;
+
+ String8 toString();
+
+ status_t add(const String8& key, const String8& value);
+ status_t addInt(const String8& key, const int value);
+ status_t addFloat(const String8& key, const float value);
+
+ status_t remove(const String8& key);
+
+ status_t get(const String8& key, String8& value);
+ status_t getInt(const String8& key, int& value);
+ status_t getFloat(const String8& key, float& value);
+ status_t getAt(size_t index, String8& key, String8& value);
+
+ size_t size() { return mParameters.size(); }
+
+private:
+ String8 mKeyValuePairs;
+ KeyedVector <String8, String8> mParameters;
};
}; // namespace android
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 7c86a65..981c2f6 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>
@@ -117,9 +117,9 @@ public:
* streamType: Select the type of audio stream this track is attached to
* (e.g. AudioSystem::MUSIC).
* sampleRate: Track sampling rate in Hz.
- * format: PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
+ * format: Audio format (e.g AudioSystem::PCM_16_BIT for signed
* 16 bits per sample).
- * channelCount: Number of PCM channels (e.g 2 for stereo).
+ * channels: Channel mask: see AudioSystem::audio_channels.
* frameCount: Total size of track PCM buffer in frames. This defines the
* latency of the track.
* flags: Reserved for future use.
@@ -133,7 +133,7 @@ public:
AudioTrack( int streamType,
uint32_t sampleRate = 0,
int format = 0,
- int channelCount = 0,
+ int channels = 0,
int frameCount = 0,
uint32_t flags = 0,
callback_t cbf = 0,
@@ -152,7 +152,7 @@ public:
AudioTrack( int streamType,
uint32_t sampleRate = 0,
int format = 0,
- int channelCount = 0,
+ int channels = 0,
const sp<IMemory>& sharedBuffer = 0,
uint32_t flags = 0,
callback_t cbf = 0,
@@ -169,13 +169,13 @@ public:
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful intialization
* - INVALID_OPERATION: AudioTrack is already intitialized
- * - BAD_VALUE: invalid parameter (channelCount, format, sampleRate...)
+ * - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
* - NO_INIT: audio server or audio hardware not initialized
* */
status_t set(int streamType =-1,
uint32_t sampleRate = 0,
int format = 0,
- int channelCount = 0,
+ int channels = 0,
int frameCount = 0,
uint32_t flags = 0,
callback_t cbf = 0,
@@ -330,6 +330,16 @@ public:
*/
status_t reload();
+ /* returns a handle on the audio output used by this AudioTrack.
+ *
+ * Parameters:
+ * none.
+ *
+ * Returned value:
+ * handle on audio hardware output
+ */
+ audio_io_handle_t getOutput();
+
/* obtains a buffer of "frameCount" frames. The buffer must be
* filled entirely. If the track is stopped, obtainBuffer() returns
* STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -387,7 +397,6 @@ private:
sp<AudioTrackThread> mAudioTrackThread;
float mVolume[2];
- uint32_t mSampleRate;
uint32_t mFrameCount;
audio_track_cblk_t* mCblk;
@@ -395,6 +404,7 @@ private:
uint8_t mFormat;
uint8_t mChannelCount;
uint8_t mMuted;
+ uint32_t mChannels;
status_t mStatus;
uint32_t mLatency;
@@ -410,6 +420,7 @@ private:
bool mMarkerReached;
uint32_t mNewPosition;
uint32_t mUpdatePeriod;
+ uint32_t mFlags;
};
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 3e59d85..8018568 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -23,11 +23,11 @@
#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>
-
+#include <utils/String8.h>
namespace android {
@@ -50,11 +50,12 @@ public:
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ int output,
status_t *status) = 0;
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int inputSource,
+ int input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -83,19 +84,14 @@ public:
/* set/get stream type state. This will probably be used by
* the preference panel, mostly.
*/
- virtual status_t setStreamVolume(int stream, float value) = 0;
+ virtual status_t setStreamVolume(int stream, float value, int output) = 0;
virtual status_t setStreamMute(int stream, bool muted) = 0;
- virtual float streamVolume(int stream) const = 0;
+ virtual float streamVolume(int stream, int output) const = 0;
virtual bool streamMute(int stream) const = 0;
- // set/get audio routing
- virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask) = 0;
- virtual uint32_t getRouting(int mode) const = 0;
-
- // set/get audio mode
+ // set audio mode
virtual status_t setMode(int mode) = 0;
- virtual int getMode() const = 0;
// mic mute/state
virtual status_t setMicMute(bool state) = 0;
@@ -104,22 +100,34 @@ public:
// is a music stream active?
virtual bool isMusicActive() const = 0;
- // pass a generic configuration parameter to libaudio
- // Temporary interface, do not use
- // TODO: Replace with a more generic key:value get/set mechanism
- virtual status_t setParameter(const char* key, const char* value) = 0;
+ virtual status_t setParameters(int ioHandle, const String8& keyValuePairs) = 0;
+ virtual String8 getParameters(int ioHandle, const String8& keys) = 0;
// register a current process for audio output change notifications
virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
// retrieve the audio recording buffer size
virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
-
- // force AudioFlinger thread out of standby
- virtual void wakeUp() = 0;
- // is A2DP output enabled
- virtual bool isA2dpEnabled() const = 0;
+ virtual int openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags) = 0;
+ virtual int openDuplicateOutput(int output1, int output2) = 0;
+ virtual status_t closeOutput(int output) = 0;
+ virtual status_t suspendOutput(int output) = 0;
+ virtual status_t restoreOutput(int output) = 0;
+
+ virtual int openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics) = 0;
+ virtual status_t closeInput(int input) = 0;
+
+ virtual status_t setStreamOutput(uint32_t stream, int output) = 0;
};
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
index c3deb0b..aa0cdcf 100644
--- a/include/media/IAudioFlingerClient.h
+++ b/include/media/IAudioFlingerClient.h
@@ -19,8 +19,8 @@
#include <utils/RefBase.h>
-#include <utils/IInterface.h>
-
+#include <binder/IInterface.h>
+#include <utils/KeyedVector.h>
namespace android {
@@ -31,8 +31,8 @@ class IAudioFlingerClient : public IInterface
public:
DECLARE_META_INTERFACE(AudioFlingerClient);
- // Notifies a change of audio output from/to hardware to/from A2DP.
- virtual void a2dpEnabledChanged(bool enabled) = 0;
+ // Notifies a change of audio input/output configuration.
+ virtual void ioConfigChanged(int event, int ioHandle, void *param2) = 0;
};
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
new file mode 100644
index 0000000..4804bbd
--- /dev/null
+++ b/include/media/IAudioPolicyService.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_IAUDIOPOLICYSERVICE_H
+#define ANDROID_IAUDIOPOLICYSERVICE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <media/AudioSystem.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IAudioPolicyService : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(AudioPolicyService);
+
+ //
+ // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
+ //
+ virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address) = 0;
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address) = 0;
+ virtual status_t setPhoneState(int state) = 0;
+ virtual status_t setRingerMode(uint32_t mode, uint32_t mask) = 0;
+ virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) = 0;
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage) = 0;
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate = 0,
+ uint32_t format = AudioSystem::FORMAT_DEFAULT,
+ uint32_t channels = 0,
+ AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT) = 0;
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0;
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0;
+ virtual void releaseOutput(audio_io_handle_t output) = 0;
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate = 0,
+ uint32_t format = AudioSystem::FORMAT_DEFAULT,
+ uint32_t channels = 0,
+ AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0) = 0;
+ virtual status_t startInput(audio_io_handle_t input) = 0;
+ virtual status_t stopInput(audio_io_handle_t input) = 0;
+ virtual void releaseInput(audio_io_handle_t input) = 0;
+ virtual status_t initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax) = 0;
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index) = 0;
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index) = 0;
+};
+
+
+// ----------------------------------------------------------------------------
+
+class BnAudioPolicyService : public BnInterface<IAudioPolicyService>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAUDIOPOLICYSERVICE_H
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..b6f654f 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -18,11 +18,12 @@
#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 {
+class Parcel;
class ISurface;
class IMediaPlayer: public IInterface
@@ -45,6 +46,36 @@ public:
virtual status_t setAudioStreamType(int type) = 0;
virtual status_t setLooping(int loop) = 0;
virtual status_t setVolume(float leftVolume, float rightVolume) = 0;
+
+ // Invoke a generic method on the player by using opaque parcels
+ // for the request and reply.
+ // @param request Parcel that must start with the media player
+ // interface token.
+ // @param[out] reply Parcel to hold the reply data. Cannot be null.
+ // @return OK if the invocation was made successfully.
+ virtual status_t invoke(const Parcel& request, Parcel *reply) = 0;
+
+ // Set a new metadata filter.
+ // @param filter A set of allow and drop rules serialized in a Parcel.
+ // @return OK if the invocation was made successfully.
+ virtual status_t setMetadataFilter(const Parcel& filter) = 0;
+
+ // Retrieve a set of metadata.
+ // @param update_only Include only the metadata that have changed
+ // since the last invocation of getMetadata.
+ // The set is built using the unfiltered
+ // notifications the native player sent to the
+ // MediaPlayerService during that period of
+ // time. If false, all the metadatas are considered.
+ // @param apply_filter If true, once the metadata set has been built based
+ // on the value update_only, the current filter is
+ // applied.
+ // @param[out] metadata On exit contains a set (possibly empty) of metadata.
+ // Valid only if the call returned OK.
+ // @return OK if the invocation was made successfully.
+ virtual status_t getMetadata(bool update_only,
+ bool apply_filter,
+ Parcel *metadata) = 0;
};
// ----------------------------------------------------------------------------
@@ -61,4 +92,3 @@ public:
}; // namespace android
#endif // ANDROID_IMEDIAPLAYER_H
-
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 d1d96b1..39b5e57 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -17,9 +17,10 @@
#ifndef ANDROID_IMEDIAPLAYERSERVICE_H
#define ANDROID_IMEDIAPLAYERSERVICE_H
+#include <utils/Errors.h> // for status_t
#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>
@@ -28,6 +29,7 @@
namespace android {
class IMediaRecorder;
+class IOMX;
class IMediaPlayerService: public IInterface
{
@@ -36,11 +38,11 @@ public:
virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid) = 0;
virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
-
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
+ virtual sp<IOMX> createOMX() = 0;
};
// ----------------------------------------------------------------------------
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/IOMX.h b/include/media/IOMX.h
new file mode 100644
index 0000000..0014d5c
--- /dev/null
+++ b/include/media/IOMX.h
@@ -0,0 +1,191 @@
+/*
+ * 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_IOMX_H_
+
+#define ANDROID_IOMX_H_
+
+#include <binder/IInterface.h>
+#include <utils/List.h>
+#include <utils/String8.h>
+
+#include <OMX_Core.h>
+#include <OMX_Video.h>
+
+namespace android {
+
+class IMemory;
+class IOMXObserver;
+class IOMXRenderer;
+class ISurface;
+class Surface;
+
+class IOMX : public IInterface {
+public:
+ DECLARE_META_INTERFACE(OMX);
+
+ typedef void *buffer_id;
+ typedef void *node_id;
+
+ virtual status_t list_nodes(List<String8> *list) = 0;
+
+ virtual status_t allocate_node(const char *name, node_id *node) = 0;
+ virtual status_t free_node(node_id node) = 0;
+
+ virtual status_t send_command(
+ node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) = 0;
+
+ virtual status_t get_parameter(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) = 0;
+
+ virtual status_t set_parameter(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) = 0;
+
+ virtual status_t get_config(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) = 0;
+
+ virtual status_t set_config(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) = 0;
+
+ virtual status_t use_buffer(
+ node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+ buffer_id *buffer) = 0;
+
+ virtual status_t allocate_buffer(
+ node_id node, OMX_U32 port_index, size_t size,
+ buffer_id *buffer) = 0;
+
+ virtual status_t allocate_buffer_with_backup(
+ node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+ buffer_id *buffer) = 0;
+
+ virtual status_t free_buffer(
+ node_id node, OMX_U32 port_index, buffer_id buffer) = 0;
+
+ virtual status_t observe_node(
+ node_id node, const sp<IOMXObserver> &observer) = 0;
+
+ virtual void fill_buffer(node_id node, buffer_id buffer) = 0;
+
+ virtual void empty_buffer(
+ node_id node,
+ buffer_id buffer,
+ OMX_U32 range_offset, OMX_U32 range_length,
+ OMX_U32 flags, OMX_TICKS timestamp) = 0;
+
+ virtual status_t get_extension_index(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index) = 0;
+
+ virtual sp<IOMXRenderer> createRenderer(
+ const sp<ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight) = 0;
+
+ // Note: This method is _not_ virtual, it exists as a wrapper around
+ // the virtual "createRenderer" method above facilitating extraction
+ // of the ISurface from a regular Surface.
+ sp<IOMXRenderer> createRenderer(
+ const sp<Surface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight);
+};
+
+struct omx_message {
+ enum {
+ EVENT,
+ EMPTY_BUFFER_DONE,
+ FILL_BUFFER_DONE,
+
+ } type;
+
+ IOMX::node_id node;
+
+ union {
+ // if type == EVENT
+ struct {
+ OMX_EVENTTYPE event;
+ OMX_U32 data1;
+ OMX_U32 data2;
+ } event_data;
+
+ // if type == EMPTY_BUFFER_DONE
+ struct {
+ IOMX::buffer_id buffer;
+ } buffer_data;
+
+ // if type == FILL_BUFFER_DONE
+ struct {
+ IOMX::buffer_id buffer;
+ OMX_U32 range_offset;
+ OMX_U32 range_length;
+ OMX_U32 flags;
+ OMX_TICKS timestamp;
+ OMX_PTR platform_private;
+ } extended_buffer_data;
+
+ } u;
+};
+
+class IOMXObserver : public IInterface {
+public:
+ DECLARE_META_INTERFACE(OMXObserver);
+
+ virtual void on_message(const omx_message &msg) = 0;
+};
+
+class IOMXRenderer : public IInterface {
+public:
+ DECLARE_META_INTERFACE(OMXRenderer);
+
+ virtual void render(IOMX::buffer_id buffer) = 0;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BnOMX : public BnInterface<IOMX> {
+public:
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+class BnOMXObserver : public BnInterface<IOMXObserver> {
+public:
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+class BnOMXRenderer : public BnInterface<IOMXRenderer> {
+public:
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // ANDROID_IOMX_H_
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 7bf555a..f723cfd 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -19,20 +19,32 @@
#ifdef __cplusplus
+#include <sys/types.h>
#include <ui/ISurface.h>
#include <utils/RefBase.h>
+#include <utils/Errors.h>
#include <media/mediaplayer.h>
#include <media/AudioSystem.h>
+#include <media/Metadata.h>
namespace android {
+class Parcel;
+template<typename T> class SortedVector;
+
enum player_type {
PV_PLAYER = 1,
SONIVOX_PLAYER = 2,
- VORBIS_PLAYER = 3
+ VORBIS_PLAYER = 3,
+ STAGEFRIGHT_PLAYER = 4,
+ // Test players are available only in the 'test' and 'eng' builds.
+ // The shared library with the test player is passed passed as an
+ // argument to the 'test:' url in the setDataSource call.
+ TEST_PLAYER = 5,
};
+
#define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
#define DEFAULT_AUDIOSINK_SAMPLERATE 44100
@@ -45,10 +57,12 @@ typedef void (*notify_callback_f)(void* cookie, int msg, int ext1, int ext2);
class MediaPlayerBase : public RefBase
{
public:
-
// AudioSink: abstraction layer for audio output
class AudioSink : public RefBase {
public:
+ typedef void (*AudioCallback)(
+ AudioSink *audioSink, void *buffer, size_t size, void *cookie);
+
virtual ~AudioSink() {}
virtual bool ready() const = 0; // audio output is open and ready
virtual bool realtime() const = 0; // audio output is real-time output
@@ -58,7 +72,17 @@ public:
virtual ssize_t frameSize() const = 0;
virtual uint32_t latency() const = 0;
virtual float msecsPerFrame() const = 0;
- virtual status_t open(uint32_t sampleRate, int channelCount, int format=AudioSystem::PCM_16_BIT, int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT) = 0;
+
+ // If no callback is specified, use the "write" API below to submit
+ // audio data. Otherwise return a full buffer of audio data on each
+ // callback.
+ virtual status_t open(
+ uint32_t sampleRate, int channelCount,
+ int format=AudioSystem::PCM_16_BIT,
+ int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ AudioCallback cb = NULL,
+ void *cookie = NULL) = 0;
+
virtual void start() = 0;
virtual ssize_t write(const void* buffer, size_t size) = 0;
virtual void stop() = 0;
@@ -88,6 +112,26 @@ public:
virtual player_type playerType() = 0;
virtual void setNotifyCallback(void* cookie, notify_callback_f notifyFunc) {
mCookie = cookie; mNotify = notifyFunc; }
+ // Invoke a generic method on the player by using opaque parcels
+ // for the request and reply.
+ //
+ // @param request Parcel that is positioned at the start of the
+ // data sent by the java layer.
+ // @param[out] reply Parcel to hold the reply data. Cannot be null.
+ // @return OK if the call was successful.
+ virtual status_t invoke(const Parcel& request, Parcel *reply) = 0;
+
+ // The Client in the MetadataPlayerService calls this method on
+ // the native player to retrieve all or a subset of metadata.
+ //
+ // @param ids SortedList of metadata ID to be fetch. If empty, all
+ // the known metadata should be returned.
+ // @param[inout] records Parcel where the player appends its metadata.
+ // @return OK if the call was successful.
+ virtual status_t getMetadata(const media::Metadata::Filter& ids,
+ Parcel *records) {
+ return INVALID_OPERATION;
+ };
protected:
virtual void sendEvent(int msg, int ext1=0, int ext2=0) { if (mNotify) mNotify(mCookie, msg, ext1, ext2); }
diff --git a/include/media/Metadata.h b/include/media/Metadata.h
new file mode 100644
index 0000000..241868a
--- /dev/null
+++ b/include/media/Metadata.h
@@ -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.
+ */
+
+#ifndef ANDROID_MEDIA_METADATA_H__
+#define ANDROID_MEDIA_METADATA_H__
+
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+class Parcel;
+
+namespace media {
+
+// Metadata is a class to build/serialize a set of metadata in a Parcel.
+//
+// This class should be kept in sync with android/media/Metadata.java.
+// It provides all the metadata ids available and methods to build the
+// header, add records and adjust the set size header field.
+//
+// Typical Usage:
+// ==============
+// Parcel p;
+// media::Metadata data(&p);
+//
+// data.appendHeader();
+// data.appendBool(Metadata::kPauseAvailable, true);
+// ... more append ...
+// data.updateLength();
+//
+
+class Metadata {
+ public:
+ typedef int32_t Type;
+ typedef SortedVector<Type> Filter;
+
+ static const Type kAny = 0;
+
+ // Keep in sync with android/media/Metadata.java
+ static const Type kTitle = 1; // String
+ static const Type kComment = 2; // String
+ static const Type kCopyright = 3; // String
+ static const Type kAlbum = 4; // String
+ static const Type kArtist = 5; // String
+ static const Type kAuthor = 6; // String
+ static const Type kComposer = 7; // String
+ static const Type kGenre = 8; // String
+ static const Type kDate = 9; // Date
+ static const Type kDuration = 10; // Integer(millisec)
+ static const Type kCdTrackNum = 11; // Integer 1-based
+ static const Type kCdTrackMax = 12; // Integer
+ static const Type kRating = 13; // String
+ static const Type kAlbumArt = 14; // byte[]
+ static const Type kVideoFrame = 15; // Bitmap
+ static const Type kCaption = 16; // TimedText
+
+ static const Type kBitRate = 17; // Integer, Aggregate rate of
+ // all the streams in bps.
+
+ static const Type kAudioBitRate = 18; // Integer, bps
+ static const Type kVideoBitRate = 19; // Integer, bps
+ static const Type kAudioSampleRate = 20; // Integer, Hz
+ static const Type kVideoframeRate = 21; // Integer, Hz
+
+ // See RFC2046 and RFC4281.
+ static const Type kMimeType = 22; // String
+ static const Type kAudioCodec = 23; // String
+ static const Type kVideoCodec = 24; // String
+
+ static const Type kVideoHeight = 25; // Integer
+ static const Type kVideoWidth = 26; // Integer
+ static const Type kNumTracks = 27; // Integer
+ static const Type kDrmCrippled = 28; // Boolean
+
+ // Playback capabilities.
+ static const Type kPauseAvailable = 29; // Boolean
+ static const Type kSeekBackwardAvailable = 30; // Boolean
+ static const Type kSeekForwardAvailable = 31; // Boolean
+
+ // @param p[inout] The parcel to append the metadata records
+ // to. The global metadata header should have been set already.
+ explicit Metadata(Parcel *p);
+ ~Metadata();
+
+ // Rewind the underlying parcel, undoing all the changes.
+ void resetParcel();
+
+ // Append the size and 'META' marker.
+ bool appendHeader();
+
+ // Once all the records have been added, call this to update the
+ // lenght field in the header.
+ void updateLength();
+
+ // append* are methods to append metadata.
+ // @param key Is the metadata Id.
+ // @param val Is the value of the metadata.
+ // @return true if successful, false otherwise.
+ // TODO: add more as needed to handle other types.
+ bool appendBool(Type key, bool val);
+ bool appendInt32(Type key, int32_t val);
+
+ private:
+ Metadata(const Metadata&);
+ Metadata& operator=(const Metadata&);
+
+
+ // Checks the key is valid and not already present.
+ bool checkKey(Type key);
+
+ Parcel *mData;
+ size_t mBegin;
+};
+
+} // namespace android::media
+} // namespace android
+
+#endif // ANDROID_MEDIA_METADATA_H__
diff --git a/include/media/PVPlayer.h b/include/media/PVPlayer.h
index 8122df6..8a66152 100644
--- a/include/media/PVPlayer.h
+++ b/include/media/PVPlayer.h
@@ -19,6 +19,7 @@
#include <utils/Errors.h>
#include <media/MediaPlayerInterface.h>
+#include <media/Metadata.h>
#define MAX_OPENCORE_INSTANCES 25
@@ -52,6 +53,10 @@ public:
virtual status_t reset();
virtual status_t setLooping(int loop);
virtual player_type playerType() { return PV_PLAYER; }
+ virtual status_t invoke(const Parcel& request, Parcel *reply);
+ virtual status_t getMetadata(
+ const SortedVector<media::Metadata::Type>& ids,
+ Parcel *records);
// make available to PlayerDriver
void sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); }
@@ -62,6 +67,7 @@ private:
static void run_set_video_surface(status_t s, void *cookie, bool cancelled);
static void run_set_audio_output(status_t s, void *cookie, bool cancelled);
static void run_prepare(status_t s, void *cookie, bool cancelled);
+ static void check_for_live_streaming(status_t s, void *cookie, bool cancelled);
PlayerDriver* mPlayerDriver;
char * mDataSourcePath;
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index f2719d3..9ea2775 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 {
@@ -52,6 +52,7 @@ enum {
METADATA_KEY_VIDEO_FORMAT = 18,
METADATA_KEY_VIDEO_HEIGHT = 19,
METADATA_KEY_VIDEO_WIDTH = 20,
+ METADATA_KEY_WRITER = 21,
// Add more here...
};
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 513ffe1..26b054bd 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>
@@ -97,6 +97,8 @@ enum media_info_type {
MEDIA_INFO_BAD_INTERLEAVING = 800,
// The media is not seekable (e.g live stream).
MEDIA_INFO_NOT_SEEKABLE = 801,
+ // New media metadata is available.
+ MEDIA_INFO_METADATA_UPDATE = 802,
};
@@ -151,7 +153,9 @@ public:
void notify(int msg, int ext1, int ext2);
static sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
static sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
-
+ status_t invoke(const Parcel& request, Parcel *reply);
+ status_t setMetadataFilter(const Parcel& filter);
+ status_t getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
private:
void clear_l();
status_t seekTo_l(int msec);
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 9b54ca9..13316a9 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 {
@@ -90,10 +93,6 @@ enum video_encoder {
VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type
};
-
-// Maximum frames per second is 24
-#define MEDIA_RECORDER_MAX_FRAME_RATE 24
-
/*
* The state machine of the media_recorder uses a set of different state names.
* The mapping between the media_recorder and the pvauthorengine is shown below:
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/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
new file mode 100644
index 0000000..960eda3
--- /dev/null
+++ b/include/media/stagefright/AudioPlayer.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 AUDIO_PLAYER_H_
+
+#define AUDIO_PLAYER_H_
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/TimeSource.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MediaSource;
+class AudioTrack;
+
+class AudioPlayer : public TimeSource {
+public:
+ AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink);
+ virtual ~AudioPlayer();
+
+ // Caller retains ownership of "source".
+ void setSource(const sp<MediaSource> &source);
+
+ // Return time in us.
+ virtual int64_t getRealTimeUs();
+
+ void start();
+
+ void pause();
+ void resume();
+
+ void stop();
+
+ // Returns the timestamp of the last buffer played (in us).
+ int64_t getMediaTimeUs();
+
+ // Returns true iff a mapping is established, i.e. the AudioPlayer
+ // has played at least one frame of audio.
+ bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us);
+
+ status_t seekTo(int64_t time_us);
+
+private:
+ sp<MediaSource> mSource;
+ AudioTrack *mAudioTrack;
+
+ MediaBuffer *mInputBuffer;
+
+ int mSampleRate;
+ int64_t mLatencyUs;
+ size_t mFrameSize;
+
+ Mutex mLock;
+ int64_t mNumFramesPlayed;
+
+ int64_t mPositionTimeMediaUs;
+ int64_t mPositionTimeRealUs;
+
+ bool mSeeking;
+ int64_t mSeekTimeUs;
+
+ bool mStarted;
+
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+
+ static void AudioCallback(int event, void *user, void *info);
+ void AudioCallback(int event, void *info);
+
+ static void AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *data, size_t size, void *me);
+
+ void fillBuffer(void *data, size_t size);
+
+ int64_t getRealTimeUsLocked() const;
+
+ AudioPlayer(const AudioPlayer &);
+ AudioPlayer &operator=(const AudioPlayer &);
+};
+
+} // namespace android
+
+#endif // AUDIO_PLAYER_H_
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
new file mode 100644
index 0000000..e129958
--- /dev/null
+++ b/include/media/stagefright/AudioSource.h
@@ -0,0 +1,51 @@
+/*
+ * 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 AUDIO_SOURCE_H_
+
+#define AUDIO_SOURCE_H_
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+class AudioRecord;
+
+class AudioSource {
+public:
+ AudioSource(int inputSource);
+ virtual ~AudioSource();
+
+ status_t initCheck() const;
+
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+private:
+ AudioRecord *mRecord;
+ status_t mInitCheck;
+
+ AudioSource(const AudioSource &);
+ AudioSource &operator=(const AudioSource &);
+};
+
+} // namespace android
+
+#endif // AUDIO_SOURCE_H_
diff --git a/include/media/stagefright/CachingDataSource.h b/include/media/stagefright/CachingDataSource.h
new file mode 100644
index 0000000..e35e19e
--- /dev/null
+++ b/include/media/stagefright/CachingDataSource.h
@@ -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.
+ */
+
+#ifndef CACHING_DATASOURCE_H_
+
+#define CACHING_DATASOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class CachingDataSource : public DataSource {
+public:
+ CachingDataSource(
+ const sp<DataSource> &source, size_t pageSize, int numPages);
+
+ status_t InitCheck() const;
+
+ virtual ssize_t read_at(off_t offset, void *data, size_t size);
+
+protected:
+ virtual ~CachingDataSource();
+
+private:
+ struct Page {
+ Page *mPrev, *mNext;
+ off_t mOffset;
+ size_t mLength;
+ void *mData;
+ };
+
+ sp<DataSource> mSource;
+ void *mData;
+ size_t mPageSize;
+ Page *mFirst, *mLast;
+
+ Page *allocate_page();
+
+ Mutex mLock;
+
+ CachingDataSource(const CachingDataSource &);
+ CachingDataSource &operator=(const CachingDataSource &);
+};
+
+} // namespace android
+
+#endif // CACHING_DATASOURCE_H_
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
new file mode 100644
index 0000000..7042e1a
--- /dev/null
+++ b/include/media/stagefright/CameraSource.h
@@ -0,0 +1,72 @@
+/*
+ * 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 CAMERA_SOURCE_H_
+
+#define CAMERA_SOURCE_H_
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class ICamera;
+class ICameraClient;
+class IMemory;
+
+class CameraSource : public MediaSource,
+ public MediaBufferObserver {
+public:
+ static CameraSource *Create();
+
+ virtual ~CameraSource();
+
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+ virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
+ virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
+
+ virtual void signalBufferReturned(MediaBuffer *buffer);
+
+private:
+ CameraSource(const sp<ICamera> &camera, const sp<ICameraClient> &client);
+
+ sp<ICamera> mCamera;
+ sp<ICameraClient> mCameraClient;
+
+ Mutex mLock;
+ Condition mFrameAvailableCondition;
+ List<sp<IMemory> > mFrames;
+
+ int mNumFrames;
+ bool mStarted;
+
+ CameraSource(const CameraSource &);
+ CameraSource &operator=(const CameraSource &);
+};
+
+} // namespace android
+
+#endif // CAMERA_SOURCE_H_
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
new file mode 100644
index 0000000..f46f0af
--- /dev/null
+++ b/include/media/stagefright/DataSource.h
@@ -0,0 +1,67 @@
+/*
+ * 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 DATA_SOURCE_H_
+
+#define DATA_SOURCE_H_
+
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class String8;
+
+class DataSource : public RefBase {
+public:
+ DataSource() {}
+
+ virtual ssize_t read_at(off_t offset, void *data, size_t size) = 0;
+
+ // Convenience methods:
+ bool getUInt16(off_t offset, uint16_t *x);
+
+ // May return ERROR_UNSUPPORTED.
+ virtual status_t getSize(off_t *size);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ bool sniff(String8 *mimeType, float *confidence);
+
+ typedef bool (*SnifferFunc)(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+ static void RegisterSniffer(SnifferFunc func);
+ static void RegisterDefaultSniffers();
+
+protected:
+ virtual ~DataSource() {}
+
+private:
+ static Mutex gSnifferMutex;
+ static List<SnifferFunc> gSniffers;
+
+ DataSource(const DataSource &);
+ DataSource &operator=(const DataSource &);
+};
+
+} // namespace android
+
+#endif // DATA_SOURCE_H_
diff --git a/include/media/stagefright/ESDS.h b/include/media/stagefright/ESDS.h
new file mode 100644
index 0000000..01bcd18
--- /dev/null
+++ b/include/media/stagefright/ESDS.h
@@ -0,0 +1,64 @@
+/*
+ * 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 ESDS_H_
+
+#define ESDS_H_
+
+#include <stdint.h>
+
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+class ESDS {
+public:
+ ESDS(const void *data, size_t size);
+ ~ESDS();
+
+ status_t InitCheck() const;
+
+ status_t getCodecSpecificInfo(const void **data, size_t *size) const;
+
+private:
+ enum {
+ kTag_ESDescriptor = 0x03,
+ kTag_DecoderConfigDescriptor = 0x04,
+ kTag_DecoderSpecificInfo = 0x05
+ };
+
+ uint8_t *mData;
+ size_t mSize;
+
+ status_t mInitCheck;
+
+ size_t mDecoderSpecificOffset;
+ size_t mDecoderSpecificLength;
+
+ status_t skipDescriptorHeader(
+ size_t offset, size_t size,
+ uint8_t *tag, size_t *data_offset, size_t *data_size) const;
+
+ status_t parse();
+ status_t parseESDescriptor(size_t offset, size_t size);
+ status_t parseDecoderConfigDescriptor(size_t offset, size_t size);
+
+ ESDS(const ESDS &);
+ ESDS &operator=(const ESDS &);
+};
+
+} // namespace android
+#endif // ESDS_H_
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
new file mode 100644
index 0000000..ccbe0ef
--- /dev/null
+++ b/include/media/stagefright/FileSource.h
@@ -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.
+ */
+
+#ifndef FILE_SOURCE_H_
+
+#define FILE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class FileSource : public DataSource {
+public:
+ FileSource(const char *filename);
+ virtual ~FileSource();
+
+ status_t InitCheck() const;
+
+ virtual ssize_t read_at(off_t offset, void *data, size_t size);
+
+private:
+ FILE *mFile;
+ Mutex mLock;
+
+ FileSource(const FileSource &);
+ FileSource &operator=(const FileSource &);
+};
+
+} // namespace android
+
+#endif // FILE_SOURCE_H_
+
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
new file mode 100644
index 0000000..0587c7c
--- /dev/null
+++ b/include/media/stagefright/HTTPDataSource.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 HTTP_DATASOURCE_H_
+
+#define HTTP_DATASOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/HTTPStream.h>
+
+namespace android {
+
+class HTTPDataSource : public DataSource {
+public:
+ HTTPDataSource(const char *host, int port, const char *path);
+ HTTPDataSource(const char *uri);
+
+ virtual ~HTTPDataSource();
+
+ // XXXandih
+ status_t InitCheck() const { return OK; }
+
+ virtual ssize_t read_at(off_t offset, void *data, size_t size);
+
+private:
+ enum {
+ kBufferSize = 64 * 1024
+ };
+
+ HTTPStream mHttp;
+ char *mHost;
+ int mPort;
+ char *mPath;
+
+ void *mBuffer;
+ size_t mBufferLength;
+ off_t mBufferOffset;
+
+ HTTPDataSource(const HTTPDataSource &);
+ HTTPDataSource &operator=(const HTTPDataSource &);
+};
+
+} // namespace android
+
+#endif // HTTP_DATASOURCE_H_
+
diff --git a/include/media/stagefright/HTTPStream.h b/include/media/stagefright/HTTPStream.h
new file mode 100644
index 0000000..3d0d67a
--- /dev/null
+++ b/include/media/stagefright/HTTPStream.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 HTTP_STREAM_H_
+
+#define HTTP_STREAM_H_
+
+#include <sys/types.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/string.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+class HTTPStream {
+public:
+ HTTPStream();
+ ~HTTPStream();
+
+ status_t connect(const char *server, int port = 80);
+ status_t disconnect();
+
+ status_t send(const char *data, size_t size);
+
+ // Assumes data is a '\0' terminated string.
+ status_t send(const char *data);
+
+ // Receive up to "size" bytes of data.
+ ssize_t receive(void *data, size_t size);
+
+ status_t receive_header(int *http_status);
+
+ // The header key used to retrieve the status line.
+ static const char *kStatusKey;
+
+ bool find_header_value(
+ const string &key, string *value) const;
+
+private:
+ enum State {
+ READY,
+ CONNECTED
+ };
+
+ State mState;
+ int mSocket;
+
+ KeyedVector<string, string> mHeaders;
+
+ // Receive a line of data terminated by CRLF, line will be '\0' terminated
+ // _excluding_ the termianting CRLF.
+ status_t receive_line(char *line, size_t size);
+
+ HTTPStream(const HTTPStream &);
+ HTTPStream &operator=(const HTTPStream &);
+};
+
+} // namespace android
+
+#endif // HTTP_STREAM_H_
diff --git a/include/media/stagefright/MP3Extractor.h b/include/media/stagefright/MP3Extractor.h
new file mode 100644
index 0000000..4e1f3c3
--- /dev/null
+++ b/include/media/stagefright/MP3Extractor.h
@@ -0,0 +1,55 @@
+/*
+ * 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 MP3_EXTRACTOR_H_
+
+#define MP3_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+class String8;
+
+class MP3Extractor : public MediaExtractor {
+public:
+ // Extractor assumes ownership of "source".
+ MP3Extractor(const sp<DataSource> &source);
+
+ size_t countTracks();
+ sp<MediaSource> getTrack(size_t index);
+ sp<MetaData> getTrackMetaData(size_t index);
+
+protected:
+ virtual ~MP3Extractor();
+
+private:
+ sp<DataSource> mDataSource;
+ off_t mFirstFramePos;
+ sp<MetaData> mMeta;
+ uint32_t mFixedHeader;
+
+ MP3Extractor(const MP3Extractor &);
+ MP3Extractor &operator=(const MP3Extractor &);
+};
+
+bool SniffMP3(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+} // namespace android
+
+#endif // MP3_EXTRACTOR_H_
diff --git a/include/media/stagefright/MPEG4Extractor.h b/include/media/stagefright/MPEG4Extractor.h
new file mode 100644
index 0000000..932e30f
--- /dev/null
+++ b/include/media/stagefright/MPEG4Extractor.h
@@ -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.
+ */
+
+#ifndef MPEG4_EXTRACTOR_H_
+
+#define MPEG4_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+class SampleTable;
+class String8;
+
+class MPEG4Extractor : public MediaExtractor {
+public:
+ // Extractor assumes ownership of "source".
+ MPEG4Extractor(const sp<DataSource> &source);
+
+ size_t countTracks();
+ sp<MediaSource> getTrack(size_t index);
+ sp<MetaData> getTrackMetaData(size_t index);
+
+protected:
+ virtual ~MPEG4Extractor();
+
+private:
+ struct Track {
+ Track *next;
+ sp<MetaData> meta;
+ uint32_t timescale;
+ sp<SampleTable> sampleTable;
+ };
+
+ sp<DataSource> mDataSource;
+ bool mHaveMetadata;
+
+ Track *mFirstTrack, *mLastTrack;
+
+ uint32_t mHandlerType;
+
+ status_t readMetaData();
+ status_t parseChunk(off_t *offset, int depth);
+
+ MPEG4Extractor(const MPEG4Extractor &);
+ MPEG4Extractor &operator=(const MPEG4Extractor &);
+};
+
+bool SniffMPEG4(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+} // namespace android
+
+#endif // MPEG4_EXTRACTOR_H_
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
new file mode 100644
index 0000000..5147de9
--- /dev/null
+++ b/include/media/stagefright/MPEG4Writer.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 MPEG4_WRITER_H_
+
+#define MPEG4_WRITER_H_
+
+#include <stdio.h>
+
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MediaBuffer;
+class MediaSource;
+class MetaData;
+
+class MPEG4Writer : public RefBase {
+public:
+ MPEG4Writer(const char *filename);
+
+ // Caller retains ownership of both meta and source.
+ void addSource(const sp<MetaData> &meta, const sp<MediaSource> &source);
+ void start();
+ void stop();
+
+ void beginBox(const char *fourcc);
+ void writeInt8(int8_t x);
+ void writeInt16(int16_t x);
+ void writeInt32(int32_t x);
+ void writeInt64(int64_t x);
+ void writeCString(const char *s);
+ void writeFourcc(const char *fourcc);
+ void write(const void *data, size_t size);
+ void endBox();
+
+protected:
+ virtual ~MPEG4Writer();
+
+private:
+ class Track;
+
+ FILE *mFile;
+ off_t mOffset;
+ off_t mMdatOffset;
+ Mutex mLock;
+
+ List<Track *> mTracks;
+
+ List<off_t> mBoxes;
+
+ off_t addSample(MediaBuffer *buffer);
+
+ MPEG4Writer(const MPEG4Writer &);
+ MPEG4Writer &operator=(const MPEG4Writer &);
+};
+
+} // namespace android
+
+#endif // MPEG4_WRITER_H_
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
new file mode 100644
index 0000000..339e6fb
--- /dev/null
+++ b/include/media/stagefright/MediaBuffer.h
@@ -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.
+ */
+
+#ifndef MEDIA_BUFFER_H_
+
+#define MEDIA_BUFFER_H_
+
+#include <pthread.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class MediaBuffer;
+class MediaBufferObserver;
+class MetaData;
+
+class MediaBufferObserver {
+public:
+ MediaBufferObserver() {}
+ virtual ~MediaBufferObserver() {}
+
+ virtual void signalBufferReturned(MediaBuffer *buffer) = 0;
+
+private:
+ MediaBufferObserver(const MediaBufferObserver &);
+ MediaBufferObserver &operator=(const MediaBufferObserver &);
+};
+
+class MediaBuffer {
+public:
+ // The underlying data remains the responsibility of the caller!
+ MediaBuffer(void *data, size_t size);
+
+ MediaBuffer(size_t size);
+
+ // Decrements the reference count and returns the buffer to its
+ // associated MediaBufferGroup if the reference count drops to 0.
+ void release();
+
+ // Increments the reference count.
+ void add_ref();
+
+ void *data() const;
+ size_t size() const;
+
+ size_t range_offset() const;
+ size_t range_length() const;
+
+ void set_range(size_t offset, size_t length);
+
+ sp<MetaData> meta_data();
+
+ // Clears meta data and resets the range to the full extent.
+ void reset();
+
+ void setObserver(MediaBufferObserver *group);
+
+ // Returns a clone of this MediaBuffer increasing its reference count.
+ // The clone references the same data but has its own range and
+ // MetaData.
+ MediaBuffer *clone();
+
+ int refcount() const;
+
+protected:
+ virtual ~MediaBuffer();
+
+private:
+ friend class MediaBufferGroup;
+ friend class OMXDecoder;
+
+ // For use by OMXDecoder, reference count must be 1, drop reference
+ // count to 0 without signalling the observer.
+ void claim();
+
+ MediaBufferObserver *mObserver;
+ MediaBuffer *mNextBuffer;
+ int mRefCount;
+
+ void *mData;
+ size_t mSize, mRangeOffset, mRangeLength;
+
+ bool mOwnsData;
+
+ sp<MetaData> mMetaData;
+
+ MediaBuffer *mOriginal;
+
+ void setNextBuffer(MediaBuffer *buffer);
+ MediaBuffer *nextBuffer();
+
+ MediaBuffer(const MediaBuffer &);
+ MediaBuffer &operator=(const MediaBuffer &);
+};
+
+} // namespace android
+
+#endif // MEDIA_BUFFER_H_
diff --git a/include/media/stagefright/MediaBufferGroup.h b/include/media/stagefright/MediaBufferGroup.h
new file mode 100644
index 0000000..0488292
--- /dev/null
+++ b/include/media/stagefright/MediaBufferGroup.h
@@ -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.
+ */
+
+#ifndef MEDIA_BUFFER_GROUP_H_
+
+#define MEDIA_BUFFER_GROUP_H_
+
+#include <media/stagefright/MediaBuffer.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MediaBuffer;
+class MetaData;
+
+class MediaBufferGroup : public MediaBufferObserver {
+public:
+ MediaBufferGroup();
+ ~MediaBufferGroup();
+
+ void add_buffer(MediaBuffer *buffer);
+
+ // Blocks until a buffer is available and returns it to the caller,
+ // the returned buffer will have a reference count of 1.
+ status_t acquire_buffer(MediaBuffer **buffer);
+
+protected:
+ virtual void signalBufferReturned(MediaBuffer *buffer);
+
+private:
+ friend class MediaBuffer;
+
+ Mutex mLock;
+ Condition mCondition;
+
+ MediaBuffer *mFirstBuffer, *mLastBuffer;
+
+ MediaBufferGroup(const MediaBufferGroup &);
+ MediaBufferGroup &operator=(const MediaBufferGroup &);
+};
+
+} // namespace android
+
+#endif // MEDIA_BUFFER_GROUP_H_
diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h
new file mode 100644
index 0000000..c8a8f00
--- /dev/null
+++ b/include/media/stagefright/MediaDebug.h
@@ -0,0 +1,20 @@
+#ifndef MEDIA_DEBUG_H_
+
+#define MEDIA_DEBUG_H_
+
+#include <cutils/log.h>
+
+#define LITERAL_TO_STRING_INTERNAL(x) #x
+#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
+
+#define CHECK_EQ(x,y) \
+ LOG_ALWAYS_FATAL_IF( \
+ (x) != (y), \
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y)
+
+#define CHECK(x) \
+ LOG_ALWAYS_FATAL_IF( \
+ !(x), \
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x)
+
+#endif // MEDIA_DEBUG_H_
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
new file mode 100644
index 0000000..2bb0ed6
--- /dev/null
+++ b/include/media/stagefright/MediaErrors.h
@@ -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.
+ */
+
+#ifndef MEDIA_ERRORS_H_
+
+#define MEDIA_ERRORS_H_
+
+#include <utils/Errors.h>
+
+namespace android {
+
+enum {
+ MEDIA_ERROR_BASE = -1000,
+
+ ERROR_ALREADY_CONNECTED = MEDIA_ERROR_BASE,
+ ERROR_NOT_CONNECTED = MEDIA_ERROR_BASE - 1,
+ ERROR_UNKNOWN_HOST = MEDIA_ERROR_BASE - 2,
+ ERROR_CANNOT_CONNECT = MEDIA_ERROR_BASE - 3,
+ ERROR_IO = MEDIA_ERROR_BASE - 4,
+ ERROR_CONNECTION_LOST = MEDIA_ERROR_BASE - 5,
+ ERROR_MALFORMED = MEDIA_ERROR_BASE - 7,
+ ERROR_OUT_OF_RANGE = MEDIA_ERROR_BASE - 8,
+ ERROR_BUFFER_TOO_SMALL = MEDIA_ERROR_BASE - 9,
+ ERROR_UNSUPPORTED = MEDIA_ERROR_BASE - 10,
+ ERROR_END_OF_STREAM = MEDIA_ERROR_BASE - 11,
+};
+
+} // namespace android
+
+#endif // MEDIA_ERRORS_H_
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
new file mode 100644
index 0000000..67e45bd
--- /dev/null
+++ b/include/media/stagefright/MediaExtractor.h
@@ -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.
+ */
+
+#ifndef MEDIA_EXTRACTOR_H_
+
+#define MEDIA_EXTRACTOR_H_
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class DataSource;
+class MediaSource;
+class MetaData;
+
+class MediaExtractor : public RefBase {
+public:
+ static sp<MediaExtractor> Create(
+ const sp<DataSource> &source, const char *mime = NULL);
+
+ virtual size_t countTracks() = 0;
+ virtual sp<MediaSource> getTrack(size_t index) = 0;
+ virtual sp<MetaData> getTrackMetaData(size_t index) = 0;
+
+protected:
+ MediaExtractor() {}
+ virtual ~MediaExtractor() {}
+
+private:
+ MediaExtractor(const MediaExtractor &);
+ MediaExtractor &operator=(const MediaExtractor &);
+};
+
+} // namespace android
+
+#endif // MEDIA_EXTRACTOR_H_
diff --git a/include/media/stagefright/MediaPlayerImpl.h b/include/media/stagefright/MediaPlayerImpl.h
new file mode 100644
index 0000000..53a2088
--- /dev/null
+++ b/include/media/stagefright/MediaPlayerImpl.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_PLAYER_IMPL_H_
+
+#define MEDIA_PLAYER_IMPL_H_
+
+#include <pthread.h>
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/OMXClient.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class AudioPlayer;
+class IOMXRenderer;
+class ISurface;
+class MediaExtractor;
+class MediaBuffer;
+class MediaSource;
+class MemoryHeapPmem;
+class MetaData;
+class Surface;
+class TimeSource;
+
+class MediaPlayerImpl {
+public:
+ MediaPlayerImpl(const char *uri);
+
+ status_t initCheck() const;
+
+ // Assumes ownership of "fd".
+ MediaPlayerImpl(int fd, int64_t offset, int64_t length);
+
+ ~MediaPlayerImpl();
+
+ void play();
+ void pause();
+ bool isPlaying() const;
+
+ void setSurface(const sp<Surface> &surface);
+ void setISurface(const sp<ISurface> &isurface);
+
+ void setAudioSink(const sp<MediaPlayerBase::AudioSink> &audioSink);
+
+ int32_t getWidth() const { return mVideoWidth; }
+ int32_t getHeight() const { return mVideoHeight; }
+
+ int64_t getDuration();
+ int64_t getPosition();
+ status_t seekTo(int64_t time);
+
+private:
+ status_t mInitCheck;
+
+ OMXClient mClient;
+
+ sp<MediaExtractor> mExtractor;
+
+ TimeSource *mTimeSource;
+
+ sp<MediaSource> mAudioSource;
+ sp<MediaSource> mAudioDecoder;
+ AudioPlayer *mAudioPlayer;
+
+ sp<MediaSource> mVideoSource;
+ sp<MediaSource> mVideoDecoder;
+ int32_t mVideoWidth, mVideoHeight;
+ int64_t mVideoPosition;
+
+ int64_t mDuration;
+
+ bool mPlaying;
+ bool mPaused;
+
+ int64_t mTimeSourceDeltaUs;
+
+ sp<Surface> mSurface;
+ sp<ISurface> mISurface;
+ sp<IOMXRenderer> mVideoRenderer;
+
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+
+ Mutex mLock;
+ pthread_t mVideoThread;
+
+ bool mSeeking;
+ int64_t mSeekTimeUs;
+
+ void init();
+
+ static void *VideoWrapper(void *me);
+ void videoEntry();
+
+ void setAudioSource(const sp<MediaSource> &source);
+ void setVideoSource(const sp<MediaSource> &source);
+
+ MediaSource *makeShoutcastSource(const char *path);
+
+ void displayOrDiscardFrame(MediaBuffer *buffer, int64_t pts_us);
+ void populateISurface();
+ void depopulateISurface();
+ void sendFrameToISurface(MediaBuffer *buffer);
+
+ void stop();
+
+ MediaPlayerImpl(const MediaPlayerImpl &);
+ MediaPlayerImpl &operator=(const MediaPlayerImpl &);
+};
+
+} // namespace android
+
+#endif // MEDIA_PLAYER_IMPL_H_
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
new file mode 100644
index 0000000..d1fa114
--- /dev/null
+++ b/include/media/stagefright/MediaSource.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_SOURCE_H_
+
+#define MEDIA_SOURCE_H_
+
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class MediaBuffer;
+class MetaData;
+
+struct MediaSource : public RefBase {
+ MediaSource();
+
+ // To be called before any other methods on this object, except
+ // getFormat().
+ virtual status_t start(MetaData *params = NULL) = 0;
+
+ // Any blocking read call returns immediately with a result of NO_INIT.
+ // It is an error to call any methods other than start after this call
+ // returns. Any buffers the object may be holding onto at the time of
+ // the stop() call are released.
+ // Also, it is imperative that any buffers output by this object and
+ // held onto by callers be released before a call to stop() !!!
+ virtual status_t stop() = 0;
+
+ // Returns the format of the data output by this media source.
+ virtual sp<MetaData> getFormat() = 0;
+
+ struct ReadOptions;
+
+ // Returns a new buffer of data. Call blocks until a
+ // buffer is available, an error is encountered of the end of the stream
+ // is reached.
+ // End of stream is signalled by a result of ERROR_END_OF_STREAM.
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+
+ // Options that modify read() behaviour. The default is to
+ // a) not request a seek
+ // b) not be late, i.e. lateness_us = 0
+ struct ReadOptions {
+ ReadOptions();
+
+ // Reset everything back to defaults.
+ void reset();
+
+ void setSeekTo(int64_t time_us);
+ void clearSeekTo();
+ bool getSeekTo(int64_t *time_us) const;
+
+ void setLateBy(int64_t lateness_us);
+ int64_t getLateBy() const;
+
+ private:
+ enum Options {
+ kSeekTo_Option = 1,
+ };
+
+ uint32_t mOptions;
+ int64_t mSeekTimeUs;
+ int64_t mLatenessUs;
+ };
+
+protected:
+ virtual ~MediaSource();
+
+private:
+ MediaSource(const MediaSource &);
+ MediaSource &operator=(const MediaSource &);
+};
+
+} // namespace android
+
+#endif // MEDIA_SOURCE_H_
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
new file mode 100644
index 0000000..be60565
--- /dev/null
+++ b/include/media/stagefright/MetaData.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 META_DATA_H_
+
+#define META_DATA_H_
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+enum {
+ kKeyMIMEType = 'mime',
+ kKeyWidth = 'widt',
+ kKeyHeight = 'heig',
+ kKeyChannelCount = '#chn',
+ kKeySampleRate = 'srte',
+ kKeyBitRate = 'brte',
+ kKeyESDS = 'esds',
+ kKeyAVCC = 'avcc',
+ kKeyTimeUnits = '#tim',
+ kKeyTimeScale = 'scal',
+ kKeyWantsNALFragments = 'NALf',
+ kKeyIsSyncFrame = 'sync',
+ kKeyDuration = 'dura',
+ kKeyColorFormat = 'colf',
+ kKeyPlatformPrivate = 'priv',
+ kKeyDecoderComponent = 'decC',
+ kKeyBufferID = 'bfID',
+ kKeyCompressedSize = 'cmpS',
+};
+
+enum {
+ kTypeESDS = 'esds',
+ kTypeAVCC = 'avcc',
+};
+
+class MetaData : public RefBase {
+public:
+ MetaData();
+ MetaData(const MetaData &from);
+
+ enum Type {
+ TYPE_NONE = 'none',
+ TYPE_C_STRING = 'cstr',
+ TYPE_INT32 = 'in32',
+ TYPE_FLOAT = 'floa',
+ TYPE_POINTER = 'ptr ',
+ };
+
+ void clear();
+ bool remove(uint32_t key);
+
+ bool setCString(uint32_t key, const char *value);
+ bool setInt32(uint32_t key, int32_t value);
+ bool setFloat(uint32_t key, float value);
+ bool setPointer(uint32_t key, void *value);
+
+ bool findCString(uint32_t key, const char **value);
+ bool findInt32(uint32_t key, int32_t *value);
+ bool findFloat(uint32_t key, float *value);
+ bool findPointer(uint32_t key, void **value);
+
+ bool setData(uint32_t key, uint32_t type, const void *data, size_t size);
+
+ bool findData(uint32_t key, uint32_t *type,
+ const void **data, size_t *size) const;
+
+protected:
+ virtual ~MetaData();
+
+private:
+ struct typed_data {
+ typed_data();
+ ~typed_data();
+
+ typed_data(const MetaData::typed_data &);
+ typed_data &operator=(const MetaData::typed_data &);
+
+ void clear();
+ void setData(uint32_t type, const void *data, size_t size);
+ void getData(uint32_t *type, const void **data, size_t *size) const;
+
+ private:
+ uint32_t mType;
+ size_t mSize;
+
+ union {
+ void *ext_data;
+ float reservoir;
+ } u;
+
+ bool usesReservoir() const {
+ return mSize <= sizeof(u.reservoir);
+ }
+
+ void allocateStorage(size_t size);
+ void freeStorage();
+
+ void *storage() {
+ return usesReservoir() ? &u.reservoir : u.ext_data;
+ }
+
+ const void *storage() const {
+ return usesReservoir() ? &u.reservoir : u.ext_data;
+ }
+ };
+
+ KeyedVector<uint32_t, typed_data> mItems;
+
+ // MetaData &operator=(const MetaData &);
+};
+
+} // namespace android
+
+#endif // META_DATA_H_
diff --git a/include/media/stagefright/MmapSource.h b/include/media/stagefright/MmapSource.h
new file mode 100644
index 0000000..a8bd57f
--- /dev/null
+++ b/include/media/stagefright/MmapSource.h
@@ -0,0 +1,52 @@
+/*
+ * 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 MMAP_SOURCE_H_
+
+#define MMAP_SOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+class MmapSource : public DataSource {
+public:
+ MmapSource(const char *filename);
+
+ // Assumes ownership of "fd".
+ MmapSource(int fd, int64_t offset, int64_t length);
+
+ virtual ~MmapSource();
+
+ status_t InitCheck() const;
+
+ virtual ssize_t read_at(off_t offset, void *data, size_t size);
+ virtual status_t getSize(off_t *size);
+
+private:
+ int mFd;
+ void *mBase;
+ size_t mSize;
+
+ MmapSource(const MmapSource &);
+ MmapSource &operator=(const MmapSource &);
+};
+
+} // namespace android
+
+#endif // MMAP_SOURCE_H_
+
diff --git a/include/media/stagefright/OMXClient.h b/include/media/stagefright/OMXClient.h
new file mode 100644
index 0000000..2f14d06
--- /dev/null
+++ b/include/media/stagefright/OMXClient.h
@@ -0,0 +1,45 @@
+/*
+ * 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 OMX_CLIENT_H_
+
+#define OMX_CLIENT_H_
+
+#include <media/IOMX.h>
+
+namespace android {
+
+class OMXClient {
+public:
+ OMXClient();
+
+ status_t connect();
+ void disconnect();
+
+ sp<IOMX> interface() {
+ return mOMX;
+ }
+
+private:
+ sp<IOMX> mOMX;
+
+ OMXClient(const OMXClient &);
+ OMXClient &operator=(const OMXClient &);
+};
+
+} // namespace android
+
+#endif // OMX_CLIENT_H_
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
new file mode 100644
index 0000000..29cdf21
--- /dev/null
+++ b/include/media/stagefright/OMXCodec.h
@@ -0,0 +1,203 @@
+/*
+ * 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 OMX_CODEC_H_
+
+#define OMX_CODEC_H_
+
+#include <media/IOMX.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MemoryDealer;
+struct OMXCodecObserver;
+
+struct OMXCodec : public MediaSource,
+ public MediaBufferObserver {
+ static sp<OMXCodec> Create(
+ const sp<IOMX> &omx,
+ const sp<MetaData> &meta, bool createEncoder,
+ const sp<MediaSource> &source);
+
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+ void on_message(const omx_message &msg);
+
+ // from MediaBufferObserver
+ virtual void signalBufferReturned(MediaBuffer *buffer);
+
+protected:
+ virtual ~OMXCodec();
+
+private:
+ enum State {
+ DEAD,
+ LOADED,
+ LOADED_TO_IDLE,
+ IDLE_TO_EXECUTING,
+ EXECUTING,
+ EXECUTING_TO_IDLE,
+ IDLE_TO_LOADED,
+ RECONFIGURING,
+ ERROR
+ };
+
+ enum {
+ kPortIndexInput = 0,
+ kPortIndexOutput = 1
+ };
+
+ enum PortStatus {
+ ENABLED,
+ DISABLING,
+ DISABLED,
+ ENABLING,
+ SHUTTING_DOWN,
+ };
+
+ enum Quirks {
+ kNeedsFlushBeforeDisable = 1,
+ kWantsNALFragments = 2,
+ kRequiresLoadedToIdleAfterAllocation = 4,
+ kRequiresAllocateBufferOnInputPorts = 8,
+ kRequiresFlushCompleteEmulation = 16,
+ kRequiresAllocateBufferOnOutputPorts = 32,
+ kRequiresFlushBeforeShutdown = 64,
+ };
+
+ struct BufferInfo {
+ IOMX::buffer_id mBuffer;
+ bool mOwnedByComponent;
+ sp<IMemory> mMem;
+ MediaBuffer *mMediaBuffer;
+ };
+
+ struct CodecSpecificData {
+ size_t mSize;
+ uint8_t mData[1];
+ };
+
+ sp<IOMX> mOMX;
+ IOMX::node_id mNode;
+ sp<OMXCodecObserver> mObserver;
+ uint32_t mQuirks;
+ bool mIsEncoder;
+ char *mMIME;
+ char *mComponentName;
+ sp<MetaData> mOutputFormat;
+ sp<MediaSource> mSource;
+ Vector<CodecSpecificData *> mCodecSpecificData;
+ size_t mCodecSpecificDataIndex;
+
+ sp<MemoryDealer> mDealer[2];
+
+ State mState;
+ Vector<BufferInfo> mPortBuffers[2];
+ PortStatus mPortStatus[2];
+ bool mInitialBufferSubmit;
+ bool mSignalledEOS;
+ bool mNoMoreOutputData;
+ int64_t mSeekTimeUs;
+
+ Mutex mLock;
+ Condition mAsyncCompletion;
+
+ // A list of indices into mPortStatus[kPortIndexOutput] filled with data.
+ List<size_t> mFilledBuffers;
+ Condition mBufferFilled;
+
+ OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
+ bool isEncoder, const char *mime, const char *componentName,
+ const sp<MediaSource> &source);
+
+ void addCodecSpecificData(const void *data, size_t size);
+ void clearCodecSpecificData();
+
+ void setAMRFormat();
+ void setAACFormat();
+
+ status_t setVideoPortFormatType(
+ OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat,
+ OMX_COLOR_FORMATTYPE colorFormat);
+
+ void setVideoInputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height);
+
+ void setVideoOutputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height);
+
+ void setImageOutputFormat(
+ OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height);
+
+ void setJPEGInputFormat(
+ OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize);
+
+ status_t allocateBuffers();
+ status_t allocateBuffersOnPort(OMX_U32 portIndex);
+
+ status_t freeBuffersOnPort(
+ OMX_U32 portIndex, bool onlyThoseWeOwn = false);
+
+ void drainInputBuffer(IOMX::buffer_id buffer);
+ void fillOutputBuffer(IOMX::buffer_id buffer);
+ void drainInputBuffer(BufferInfo *info);
+ void fillOutputBuffer(BufferInfo *info);
+
+ void drainInputBuffers();
+ void fillOutputBuffers();
+
+ // Returns true iff a flush was initiated and a completion event is
+ // upcoming, false otherwise (A flush was not necessary as we own all
+ // the buffers on that port).
+ // This method will ONLY ever return false for a component with quirk
+ // "kRequiresFlushCompleteEmulation".
+ bool flushPortAsync(OMX_U32 portIndex);
+
+ void disablePortAsync(OMX_U32 portIndex);
+ void enablePortAsync(OMX_U32 portIndex);
+
+ static size_t countBuffersWeOwn(const Vector<BufferInfo> &buffers);
+ static bool isIntermediateState(State state);
+
+ void onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
+ void onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data);
+ void onStateChange(OMX_STATETYPE newState);
+ void onPortSettingsChanged(OMX_U32 portIndex);
+
+ void setState(State newState);
+
+ status_t init();
+ void initOutputFormat(const sp<MetaData> &inputFormat);
+
+ void dumpPortStatus(OMX_U32 portIndex);
+
+ OMXCodec(const OMXCodec &);
+ OMXCodec &operator=(const OMXCodec &);
+};
+
+} // namespace android
+
+#endif // OMX_CODEC_H_
diff --git a/include/media/stagefright/QComHardwareRenderer.h b/include/media/stagefright/QComHardwareRenderer.h
new file mode 100644
index 0000000..8292dd5
--- /dev/null
+++ b/include/media/stagefright/QComHardwareRenderer.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 QCOM_HARDWARE_RENDERER_H_
+
+#define QCOM_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class ISurface;
+class MemoryHeapPmem;
+
+class QComHardwareRenderer : public VideoRenderer {
+public:
+ QComHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~QComHardwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<MemoryHeapPmem> mMemoryHeap;
+
+ bool getOffset(void *platformPrivate, size_t *offset);
+ void publishBuffers(uint32_t pmem_fd);
+
+ QComHardwareRenderer(const QComHardwareRenderer &);
+ QComHardwareRenderer &operator=(const QComHardwareRenderer &);
+};
+
+} // namespace android
+
+#endif // QCOM_HARDWARE_RENDERER_H_
diff --git a/include/media/stagefright/SampleTable.h b/include/media/stagefright/SampleTable.h
new file mode 100644
index 0000000..808d142
--- /dev/null
+++ b/include/media/stagefright/SampleTable.h
@@ -0,0 +1,109 @@
+/*
+ * 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 SAMPLE_TABLE_H_
+
+#define SAMPLE_TABLE_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class DataSource;
+
+class SampleTable : public RefBase {
+public:
+ SampleTable(const sp<DataSource> &source);
+
+ // type can be 'stco' or 'co64'.
+ status_t setChunkOffsetParams(
+ uint32_t type, off_t data_offset, off_t data_size);
+
+ status_t setSampleToChunkParams(off_t data_offset, off_t data_size);
+
+ // type can be 'stsz' or 'stz2'.
+ status_t setSampleSizeParams(
+ uint32_t type, off_t data_offset, off_t data_size);
+
+ status_t setTimeToSampleParams(off_t data_offset, off_t data_size);
+
+ status_t setSyncSampleParams(off_t data_offset, off_t data_size);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ uint32_t countChunkOffsets() const;
+ status_t getChunkOffset(uint32_t chunk_index, off_t *offset);
+
+ status_t getChunkForSample(
+ uint32_t sample_index, uint32_t *chunk_index,
+ uint32_t *chunk_relative_sample_index, uint32_t *desc_index);
+
+ uint32_t countSamples() const;
+ status_t getSampleSize(uint32_t sample_index, size_t *sample_size);
+
+ status_t getSampleOffsetAndSize(
+ uint32_t sample_index, off_t *offset, size_t *size);
+
+ status_t getMaxSampleSize(size_t *size);
+
+ status_t getDecodingTime(uint32_t sample_index, uint32_t *time);
+
+ enum {
+ kSyncSample_Flag = 1
+ };
+ status_t findClosestSample(
+ uint32_t req_time, uint32_t *sample_index, uint32_t flags);
+
+ status_t findClosestSyncSample(
+ uint32_t start_sample_index, uint32_t *sample_index);
+
+protected:
+ ~SampleTable();
+
+private:
+ sp<DataSource> mDataSource;
+ Mutex mLock;
+
+ off_t mChunkOffsetOffset;
+ uint32_t mChunkOffsetType;
+ uint32_t mNumChunkOffsets;
+
+ off_t mSampleToChunkOffset;
+ uint32_t mNumSampleToChunkOffsets;
+
+ off_t mSampleSizeOffset;
+ uint32_t mSampleSizeFieldSize;
+ uint32_t mDefaultSampleSize;
+ uint32_t mNumSampleSizes;
+
+ uint32_t mTimeToSampleCount;
+ uint32_t *mTimeToSample;
+
+ off_t mSyncSampleOffset;
+ uint32_t mNumSyncSamples;
+
+ SampleTable(const SampleTable &);
+ SampleTable &operator=(const SampleTable &);
+};
+
+} // namespace android
+
+#endif // SAMPLE_TABLE_H_
diff --git a/include/media/stagefright/ShoutcastSource.h b/include/media/stagefright/ShoutcastSource.h
new file mode 100644
index 0000000..352857a
--- /dev/null
+++ b/include/media/stagefright/ShoutcastSource.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 SHOUTCAST_SOURCE_H_
+
+#define SHOUTCAST_SOURCE_H_
+
+#include <sys/types.h>
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+class HTTPStream;
+class MediaBufferGroup;
+
+class ShoutcastSource : public MediaSource {
+public:
+ // Assumes ownership of "http".
+ ShoutcastSource(HTTPStream *http);
+ virtual ~ShoutcastSource();
+
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+private:
+ HTTPStream *mHttp;
+ size_t mMetaDataOffset;
+ size_t mBytesUntilMetaData;
+
+ MediaBufferGroup *mGroup;
+ bool mStarted;
+
+ ShoutcastSource(const ShoutcastSource &);
+ ShoutcastSource &operator= (const ShoutcastSource &);
+};
+
+} // namespace android
+
+#endif // SHOUTCAST_SOURCE_H_
+
diff --git a/include/media/stagefright/SoftwareRenderer.h b/include/media/stagefright/SoftwareRenderer.h
new file mode 100644
index 0000000..705b914
--- /dev/null
+++ b/include/media/stagefright/SoftwareRenderer.h
@@ -0,0 +1,55 @@
+/*
+ * 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 SOFTWARE_RENDERER_H_
+
+#define SOFTWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class ISurface;
+class MemoryHeapBase;
+
+class SoftwareRenderer : public VideoRenderer {
+public:
+ SoftwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~SoftwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<MemoryHeapBase> mMemoryHeap;
+ int mIndex;
+
+ SoftwareRenderer(const SoftwareRenderer &);
+ SoftwareRenderer &operator=(const SoftwareRenderer &);
+};
+
+} // namespace android
+
+#endif // SOFTWARE_RENDERER_H_
diff --git a/include/media/stagefright/TIHardwareRenderer.h b/include/media/stagefright/TIHardwareRenderer.h
new file mode 100644
index 0000000..ef42648
--- /dev/null
+++ b/include/media/stagefright/TIHardwareRenderer.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 TI_HARDWARE_RENDERER_H_
+
+#define TI_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ISurface;
+class Overlay;
+
+class TIHardwareRenderer : public VideoRenderer {
+public:
+ TIHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~TIHardwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<Overlay> mOverlay;
+ Vector<void *> mOverlayAddresses;
+ bool mIsFirstFrame;
+ size_t mIndex;
+
+ TIHardwareRenderer(const TIHardwareRenderer &);
+ TIHardwareRenderer &operator=(const TIHardwareRenderer &);
+};
+
+} // namespace android
+
+#endif // TI_HARDWARE_RENDERER_H_
+
diff --git a/include/media/stagefright/TimeSource.h b/include/media/stagefright/TimeSource.h
new file mode 100644
index 0000000..443673d
--- /dev/null
+++ b/include/media/stagefright/TimeSource.h
@@ -0,0 +1,51 @@
+/*
+ * 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 TIME_SOURCE_H_
+
+#define TIME_SOURCE_H_
+
+#include <stdint.h>
+
+namespace android {
+
+class TimeSource {
+public:
+ TimeSource() {}
+ virtual ~TimeSource() {}
+
+ virtual int64_t getRealTimeUs() = 0;
+
+private:
+ TimeSource(const TimeSource &);
+ TimeSource &operator=(const TimeSource &);
+};
+
+class SystemTimeSource : public TimeSource {
+public:
+ SystemTimeSource();
+
+ virtual int64_t getRealTimeUs();
+
+private:
+ static int64_t GetSystemTimeUs();
+
+ int64_t mStartTimeUs;
+};
+
+} // namespace android
+
+#endif // TIME_SOURCE_H_
diff --git a/include/media/stagefright/TimedEventQueue.h b/include/media/stagefright/TimedEventQueue.h
new file mode 100644
index 0000000..a264421
--- /dev/null
+++ b/include/media/stagefright/TimedEventQueue.h
@@ -0,0 +1,106 @@
+/*
+ * 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 TIMED_EVENT_QUEUE_H_
+
+#define TIMED_EVENT_QUEUE_H_
+
+#include <pthread.h>
+
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct TimedEventQueue {
+
+ struct Event : public RefBase {
+ Event() {}
+ virtual ~Event() {}
+
+ protected:
+ virtual void fire(TimedEventQueue *queue, int64_t now_us) = 0;
+
+ private:
+ friend class TimedEventQueue;
+
+ Event(const Event &);
+ Event &operator=(const Event &);
+ };
+
+ TimedEventQueue();
+ ~TimedEventQueue();
+
+ // Start executing the event loop.
+ void start();
+
+ // Stop executing the event loop, if flush is false, any pending
+ // events are discarded, otherwise the queue will stop (and this call
+ // return) once all pending events have been handled.
+ void stop(bool flush = false);
+
+ // Posts an event to the front of the queue (after all events that
+ // have previously been posted to the front but before timed events).
+ void postEvent(const sp<Event> &event);
+
+ void postEventToBack(const sp<Event> &event);
+
+ // It is an error to post an event with a negative delay.
+ void postEventWithDelay(const sp<Event> &event, int64_t delay_us);
+
+ // If the event is to be posted at a time that has already passed,
+ // it will fire as soon as possible.
+ void postTimedEvent(const sp<Event> &event, int64_t realtime_us);
+
+ // Returns true iff event is currently in the queue and has been
+ // successfully cancelled. In this case the event will have been
+ // removed from the queue and won't fire.
+ bool cancelEvent(const sp<Event> &event);
+
+ static int64_t getRealTimeUs();
+
+private:
+ struct QueueItem {
+ sp<Event> event;
+ int64_t realtime_us;
+ };
+
+ struct StopEvent : public TimedEventQueue::Event {
+ virtual void fire(TimedEventQueue *queue, int64_t now_us) {
+ queue->mStopped = true;
+ }
+ };
+
+ pthread_t mThread;
+ List<QueueItem> mQueue;
+ Mutex mLock;
+ Condition mQueueNotEmptyCondition;
+ Condition mQueueHeadChangedCondition;
+
+ bool mRunning;
+ bool mStopped;
+
+ static void *ThreadWrapper(void *me);
+ void threadEntry();
+
+ TimedEventQueue(const TimedEventQueue &);
+ TimedEventQueue &operator=(const TimedEventQueue &);
+};
+
+} // namespace android
+
+#endif // TIMED_EVENT_QUEUE_H_
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
new file mode 100644
index 0000000..30c7f11
--- /dev/null
+++ b/include/media/stagefright/Utils.h
@@ -0,0 +1,37 @@
+/*
+ * 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 UTILS_H_
+
+#define UTILS_H_
+
+#include <stdint.h>
+
+namespace android {
+
+#define FOURCC(c1, c2, c3, c4) \
+ (c1 << 24 | c2 << 16 | c3 << 8 | c4)
+
+uint16_t U16_AT(const uint8_t *ptr);
+uint32_t U32_AT(const uint8_t *ptr);
+uint64_t U64_AT(const uint8_t *ptr);
+
+uint64_t ntoh64(uint64_t x);
+uint64_t hton64(uint64_t x);
+
+} // namespace android
+
+#endif // UTILS_H_
diff --git a/include/media/stagefright/VideoRenderer.h b/include/media/stagefright/VideoRenderer.h
new file mode 100644
index 0000000..f80b277
--- /dev/null
+++ b/include/media/stagefright/VideoRenderer.h
@@ -0,0 +1,41 @@
+/*
+ * 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 VIDEO_RENDERER_H_
+
+#define VIDEO_RENDERER_H_
+
+#include <sys/types.h>
+
+namespace android {
+
+class VideoRenderer {
+public:
+ virtual ~VideoRenderer() {}
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate) = 0;
+
+protected:
+ VideoRenderer() {}
+
+ VideoRenderer(const VideoRenderer &);
+ VideoRenderer &operator=(const VideoRenderer &);
+};
+
+} // namespace android
+
+#endif // VIDEO_RENDERER_H_
diff --git a/include/media/stagefright/string.h b/include/media/stagefright/string.h
new file mode 100644
index 0000000..5dc7116
--- /dev/null
+++ b/include/media/stagefright/string.h
@@ -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.
+ */
+
+#ifndef STRING_H_
+
+#define STRING_H_
+
+#include <utils/String8.h>
+
+namespace android {
+
+class string {
+public:
+ typedef size_t size_type;
+ static size_type npos;
+
+ string();
+ string(const char *s);
+ string(const char *s, size_t length);
+ string(const string &from, size_type start, size_type length = npos);
+
+ const char *c_str() const;
+ size_type size() const;
+
+ void clear();
+ void erase(size_type from, size_type length);
+
+ size_type find(char c) const;
+
+ bool operator<(const string &other) const;
+ bool operator==(const string &other) const;
+
+ string &operator+=(char c);
+
+private:
+ String8 mString;
+};
+
+} // namespace android
+
+#endif // STRING_H_
diff --git a/include/private/binder/Static.h b/include/private/binder/Static.h
new file mode 100644
index 0000000..5b0f9fc
--- /dev/null
+++ b/include/private/binder/Static.h
@@ -0,0 +1,39 @@
+/*
+ * 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 <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/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 496a739..8e2db20 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -55,17 +55,18 @@ struct audio_track_cblk_t
uint32_t volumeLR;
};
uint32_t sampleRate;
+ // NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for
+ // 8 bit PCM data: in this case, mCblk->frameSize is based on a sample size of
+ // 16 bit because data is converted to 16 bit before being stored in buffer
+ uint32_t frameSize;
uint8_t channels;
uint8_t flowControlFlag; // underrun (out) or overrrun (in) indication
uint8_t out; // out equals 1 for AudioTrack and 0 for AudioRecord
- uint8_t forceReady;
+ uint8_t forceReady;
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
uint16_t waitTimeMs; // Cumulated wait time
- // Padding ensuring that data buffer starts on a cache line boundary (32 bytes).
- // See AudioFlinger::TrackBase constructor
- int32_t Padding[1];
- // Cache line boundary
-
+ // Cache line boundary (32 bytes)
+
audio_track_cblk_t();
uint32_t stepUser(uint32_t frameCount);
bool stepServer(uint32_t frameCount);
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index a85f275..67c2dd8 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -26,6 +26,8 @@
#endif
#include <private/pixelflinger/ggl_context.h>
+#include <hardware/copybit.h>
+#include <hardware/gralloc.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
@@ -39,7 +41,7 @@ class EGLSurfaceManager;
class EGLBufferObjectManager;
namespace gl {
-
+
struct ogles_context_t;
struct matrixx_t;
struct transform_t;
@@ -96,7 +98,7 @@ struct vec4_t {
struct vertex_t {
enum {
- // these constant matter for our clipping
+ // these constant matter for our clipping
CLIP_L = 0x0001, // clipping flags
CLIP_R = 0x0002,
CLIP_B = 0x0004,
@@ -106,7 +108,7 @@ struct vertex_t {
EYE = 0x0040,
RESERVED = 0x0080,
-
+
USER_CLIP_0 = 0x0100, // user clipping flags
USER_CLIP_1 = 0x0200,
USER_CLIP_2 = 0x0400,
@@ -121,7 +123,7 @@ struct vertex_t {
USER_CLIP_ALL = 0x3F00,
CLIP_ALL = 0x3F3F,
};
-
+
// the fields below are arranged to minimize d-cache usage
// we group together, by cache-line, the fields most likely to be used
@@ -130,7 +132,7 @@ struct vertex_t {
vec4_t eye;
};
vec4_t clip;
-
+
uint32_t flags;
size_t index; // cache tag, and vertex index
GLfixed fog;
@@ -142,7 +144,7 @@ struct vertex_t {
vec4_t color;
vec4_t texture[GGL_TEXTURE_UNIT_COUNT];
uint32_t reserved1[4];
-
+
inline void clear() {
flags = index = locked = mru = 0;
}
@@ -199,7 +201,7 @@ struct array_machine_t {
GLenum indicesType;
buffer_t const* array_buffer;
buffer_t const* element_array_buffer;
-
+
void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei);
void (*compileElement)(ogles_context_t*, vertex_t*, GLint);
@@ -285,6 +287,7 @@ struct light_t {
vec4_t normalizedObjPosition;
vec4_t spotDir;
vec4_t normalizedSpotDir;
+ vec4_t objViewer;
GLfixed spotExp;
GLfixed spotCutoff;
GLfixed spotCutoffCosine;
@@ -410,7 +413,7 @@ struct transform_t {
matrixx_t matrix;
uint32_t flags;
uint32_t ops;
-
+
union {
struct {
void (*point2)(transform_t const* t, vec4_t*, vec4_t const*);
@@ -509,17 +512,17 @@ struct viewport_t {
GLint x;
GLint y;
GLsizei w;
- GLsizei h;
+ GLsizei h;
struct {
GLint x;
GLint y;
- } surfaceport;
+ } surfaceport;
struct {
GLint x;
GLint y;
GLsizei w;
- GLsizei h;
- } scissor;
+ GLsizei h;
+ } scissor;
};
// ----------------------------------------------------------------------------
@@ -594,6 +597,14 @@ struct prims_t {
void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
};
+struct copybits_context_t {
+ // A handle to the blit engine, if it exists, else NULL.
+ copybit_device_t* blitEngine;
+ int32_t minScale;
+ int32_t maxScale;
+ buffer_handle_t drawSurfaceBuffer;
+};
+
struct ogles_context_t {
context_t rasterizer;
array_machine_t arrays __attribute__((aligned(32)));
@@ -617,6 +628,14 @@ struct ogles_context_t {
uint32_t transformTextures : 1;
EGLSurfaceManager* surfaceManager;
EGLBufferObjectManager* bufferObjectManager;
+
+ // copybits is only used if LIBAGL_USE_GRALLOC_COPYBITS is
+ // defined, but it is always present because ogles_context_t is a public
+ // struct that is used by clients of libagl. We want the size and offsets
+ // to stay the same, whether or not LIBAGL_USE_GRALLOC_COPYBITS is defined.
+
+ copybits_context_t copybits;
+
GLenum error;
static inline ogles_context_t* get() {
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
new file mode 100644
index 0000000..926fddb
--- /dev/null
+++ b/include/private/ui/RegionHelper.h
@@ -0,0 +1,281 @@
+/*
+ * 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_UI_PRIVATE_REGION_HELPER_H
+#define ANDROID_UI_PRIVATE_REGION_HELPER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+template<typename RECT>
+class region_operator
+{
+ typedef typename RECT::value_type TYPE;
+ static const TYPE max_value = 0x7FFFFFF;
+
+public:
+ /*
+ * Common boolean operations:
+ * value is computed as 0b101 op 0b110
+ * other boolean operation are possible, simply compute
+ * their corresponding value with the above formulae and use
+ * it when instantiating a region_operator.
+ */
+ static const uint32_t LHS = 0x5; // 0b101
+ static const uint32_t RHS = 0x6; // 0b110
+ enum {
+ op_nand = LHS & ~RHS,
+ op_and = LHS & RHS,
+ op_or = LHS | RHS,
+ op_xor = LHS ^ RHS
+ };
+
+ struct region {
+ RECT const* rects;
+ size_t count;
+ TYPE dx;
+ TYPE dy;
+ inline region(const region& rhs)
+ : rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { }
+ inline region(RECT const* r, size_t c)
+ : rects(r), count(c), dx(), dy() { }
+ inline region(RECT const* r, size_t c, TYPE dx, TYPE dy)
+ : rects(r), count(c), dx(dx), dy(dy) { }
+ };
+
+ class region_rasterizer {
+ friend class region_operator;
+ virtual void operator()(const RECT& rect) = 0;
+ public:
+ virtual ~region_rasterizer() { };
+ };
+
+ inline region_operator(int op, const region& lhs, const region& rhs)
+ : op_mask(op), spanner(lhs, rhs)
+ {
+ }
+
+ void operator()(region_rasterizer& rasterizer) {
+ RECT current;
+ do {
+ SpannerInner spannerInner(spanner.lhs, spanner.rhs);
+ int inside = spanner.next(current.top, current.bottom);
+ spannerInner.prepare(inside);
+ do {
+ TYPE left, right;
+ int inside = spannerInner.next(current.left, current.right);
+ if ((op_mask >> inside) & 1) {
+ if (current.left < current.right &&
+ current.top < current.bottom) {
+ rasterizer(current);
+ }
+ }
+ } while(!spannerInner.isDone());
+ } while(!spanner.isDone());
+ }
+
+private:
+ uint32_t op_mask;
+
+ class SpannerBase
+ {
+ public:
+ enum {
+ lhs_before_rhs = 0,
+ lhs_after_rhs = 1,
+ lhs_coincide_rhs = 2
+ };
+
+ protected:
+ TYPE lhs_head;
+ TYPE lhs_tail;
+ TYPE rhs_head;
+ TYPE rhs_tail;
+
+ inline int next(TYPE& head, TYPE& tail,
+ bool& more_lhs, bool& more_rhs)
+ {
+ int inside;
+ more_lhs = false;
+ more_rhs = false;
+ if (lhs_head < rhs_head) {
+ inside = lhs_before_rhs;
+ head = lhs_head;
+ if (lhs_tail <= rhs_head) {
+ tail = lhs_tail;
+ more_lhs = true;
+ } else {
+ lhs_head = rhs_head;
+ tail = rhs_head;
+ }
+ } else if (rhs_head < lhs_head) {
+ inside = lhs_after_rhs;
+ head = rhs_head;
+ if (rhs_tail <= lhs_head) {
+ tail = rhs_tail;
+ more_rhs = true;
+ } else {
+ rhs_head = lhs_head;
+ tail = lhs_head;
+ }
+ } else {
+ inside = lhs_coincide_rhs;
+ head = lhs_head;
+ if (lhs_tail <= rhs_tail) {
+ tail = rhs_head = lhs_tail;
+ more_lhs = true;
+ }
+ if (rhs_tail <= lhs_tail) {
+ tail = lhs_head = rhs_tail;
+ more_rhs = true;
+ }
+ }
+ return inside;
+ }
+ };
+
+ class Spanner : protected SpannerBase
+ {
+ friend class region_operator;
+ region lhs;
+ region rhs;
+
+ public:
+ inline Spanner(const region& lhs, const region& rhs)
+ : lhs(lhs), rhs(rhs)
+ {
+ SpannerBase::lhs_head = lhs.rects->top + lhs.dy;
+ SpannerBase::lhs_tail = lhs.rects->bottom + lhs.dy;
+ SpannerBase::rhs_head = rhs.rects->top + rhs.dy;
+ SpannerBase::rhs_tail = rhs.rects->bottom + rhs.dy;
+ }
+
+ inline bool isDone() const {
+ return !rhs.count && !lhs.count;
+ }
+
+ inline int next(TYPE& top, TYPE& bottom)
+ {
+ bool more_lhs = false;
+ bool more_rhs = false;
+ int inside = SpannerBase::next(top, bottom, more_lhs, more_rhs);
+ if (more_lhs) {
+ advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
+ }
+ if (more_rhs) {
+ advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
+ }
+ return inside;
+ }
+
+ private:
+ static inline
+ void advance(region& reg, TYPE& aTop, TYPE& aBottom) {
+ // got to next span
+ size_t count = reg.count;
+ RECT const * rects = reg.rects;
+ RECT const * const end = rects + count;
+ const int top = rects->top;
+ while (rects != end && rects->top == top) {
+ rects++;
+ count--;
+ }
+ if (rects != end) {
+ aTop = rects->top + reg.dy;
+ aBottom = rects->bottom + reg.dy;
+ } else {
+ aTop = max_value;
+ aBottom = max_value;
+ }
+ reg.rects = rects;
+ reg.count = count;
+ }
+ };
+
+ class SpannerInner : protected SpannerBase
+ {
+ region lhs;
+ region rhs;
+
+ public:
+ inline SpannerInner(const region& lhs, const region& rhs)
+ : lhs(lhs), rhs(rhs)
+ {
+ }
+
+ inline void prepare(int inside) {
+ SpannerBase::lhs_head = lhs.rects->left + lhs.dx;
+ SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
+ SpannerBase::rhs_head = rhs.rects->left + rhs.dx;
+ SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
+ if (inside == SpannerBase::lhs_before_rhs) {
+ SpannerBase::rhs_head = max_value;
+ SpannerBase::rhs_tail = max_value;
+ } else if (inside == SpannerBase::lhs_after_rhs) {
+ SpannerBase::lhs_head = max_value;
+ SpannerBase::lhs_tail = max_value;
+ } else {
+ // use both spans
+ }
+ }
+
+ inline bool isDone() const {
+ return SpannerBase::lhs_head == max_value &&
+ SpannerBase::rhs_head == max_value;
+ }
+
+ inline int next(TYPE& left, TYPE& right)
+ {
+ bool more_lhs = false;
+ bool more_rhs = false;
+ int inside = SpannerBase::next(left, right, more_lhs, more_rhs);
+ if (more_lhs) {
+ advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
+ }
+ if (more_rhs) {
+ advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
+ }
+ return inside;
+ }
+
+ private:
+ static inline
+ void advance(region& reg, TYPE& left, TYPE& right) {
+ if (reg.rects && reg.count) {
+ const int cur_span_top = reg.rects->top;
+ reg.rects++;
+ reg.count--;
+ if (!reg.count || reg.rects->top != cur_span_top) {
+ left = max_value;
+ right = max_value;
+ } else {
+ left = reg.rects->left + reg.dx;
+ right = reg.rects->right + reg.dx;
+ }
+ }
+ }
+ };
+
+ Spanner spanner;
+};
+
+// ----------------------------------------------------------------------------
+};
+
+#endif /* ANDROID_UI_PRIVATE_REGION_HELPER_H */
diff --git a/include/private/ui/SharedState.h b/include/private/ui/SharedState.h
index 546d0ad..c9f6b5e 100644
--- a/include/private/ui/SharedState.h
+++ b/include/private/ui/SharedState.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <utils/Debug.h>
#include <utils/threads.h>
namespace android {
@@ -32,16 +33,12 @@ namespace android {
struct surface_info_t { // 4 longs, 16 bytes
enum {
- eBufferDirty = 0x01
+ eBufferDirty = 0x01,
+ eNeedNewBuffer = 0x02
};
- uint16_t w;
- uint16_t h;
- uint16_t stride;
- uint16_t bpr;
- uint16_t reserved;
- uint8_t format;
+ uint8_t reserved[11];
uint8_t flags;
- ssize_t bits_offset;
+ status_t status;
};
// ---------------------------------------------------------------------------
@@ -101,6 +98,8 @@ struct layer_cblk_t // (128 bytes)
struct per_client_cblk_t // 4KB max
{
+ per_client_cblk_t() : lock(Mutex::SHARED) { }
+
Mutex lock;
Condition cv;
layer_cblk_t layers[NUM_LAYERS_MAX] __attribute__((aligned(32)));
@@ -110,8 +109,6 @@ struct per_client_cblk_t // 4KB max
INSPECT = 0x00000002
};
- per_client_cblk_t();
-
// these functions are used by the clients
status_t validate(size_t i) const;
int32_t lock_layer(size_t i, uint32_t flags);
@@ -138,30 +135,19 @@ struct display_cblk_t
struct surface_flinger_cblk_t // 4KB max
{
- surface_flinger_cblk_t();
-
uint8_t connected;
uint8_t reserved[3];
uint32_t pad[7];
-
display_cblk_t displays[NUM_DISPLAY_MAX];
};
// ---------------------------------------------------------------------------
-template<bool> struct CTA;
-template<> struct CTA<true> { };
-
-// compile-time assertions. just to avoid catastrophes.
-inline void compile_time_asserts() {
- CTA<sizeof(layer_cblk_t) == 128> sizeof__layer_cblk_t__eq_128;
- (void)sizeof__layer_cblk_t__eq_128; // we don't want a warning
- CTA<sizeof(per_client_cblk_t) <= 4096> sizeof__per_client_cblk_t__le_4096;
- (void)sizeof__per_client_cblk_t__le_4096; // we don't want a warning
- CTA<sizeof(surface_flinger_cblk_t) <= 4096> sizeof__surface_flinger_cblk_t__le_4096;
- (void)sizeof__surface_flinger_cblk_t__le_4096; // we don't want a warning
-}
+COMPILE_TIME_ASSERT(sizeof(layer_cblk_t) == 128)
+COMPILE_TIME_ASSERT(sizeof(per_client_cblk_t) <= 4096)
+COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
+// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_UI_SHARED_STATE_H
diff --git a/include/private/ui/SurfaceBuffer.h b/include/private/ui/SurfaceBuffer.h
new file mode 100644
index 0000000..bf68406
--- /dev/null
+++ b/include/private/ui/SurfaceBuffer.h
@@ -0,0 +1,77 @@
+/*
+ * 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_UI_PRIVATE_SURFACE_BUFFER_H
+#define ANDROID_UI_PRIVATE_SURFACE_BUFFER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+
+#include <private/ui/android_natives_priv.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class BufferMapper;
+class Parcel;
+class Rect;
+class Surface;
+class SurfaceBuffer;
+
+// ---------------------------------------------------------------------------
+
+class SurfaceBuffer
+ : public EGLNativeBase<
+ android_native_buffer_t,
+ SurfaceBuffer,
+ LightRefBase<SurfaceBuffer> >
+{
+public:
+ status_t lock(uint32_t usage, void** vaddr);
+ status_t lock(uint32_t usage, const Rect& rect, void** vaddr);
+ status_t unlock();
+
+protected:
+ SurfaceBuffer();
+ SurfaceBuffer(const Parcel& reply);
+ virtual ~SurfaceBuffer();
+ bool mOwner;
+
+ inline const BufferMapper& getBufferMapper() const { return mBufferMapper; }
+ inline BufferMapper& getBufferMapper() { return mBufferMapper; }
+
+private:
+ friend class Surface;
+ friend class BpSurface;
+ friend class BnSurface;
+ friend class LightRefBase<SurfaceBuffer>;
+
+ SurfaceBuffer& operator = (const SurfaceBuffer& rhs);
+ const SurfaceBuffer& operator = (const SurfaceBuffer& rhs) const;
+
+ static status_t writeToParcel(Parcel* reply,
+ android_native_buffer_t const* buffer);
+
+ BufferMapper& mBufferMapper;
+};
+
+}; // namespace android
+
+#endif // ANDROID_UI_PRIVATE_SURFACE_BUFFER_H
+
diff --git a/include/private/ui/SurfaceFlingerSynchro.h b/include/private/ui/SurfaceFlingerSynchro.h
index ff91b61..7386d33 100644
--- a/include/private/ui/SurfaceFlingerSynchro.h
+++ b/include/private/ui/SurfaceFlingerSynchro.h
@@ -21,7 +21,6 @@
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/threads.h>
#include <ui/ISurfaceComposer.h>
namespace android {
@@ -31,7 +30,6 @@ class SurfaceFlinger;
class SurfaceFlingerSynchro
{
public:
-
// client constructor
SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger);
~SurfaceFlingerSynchro();
@@ -40,34 +38,8 @@ public:
status_t signal();
private:
- class Barrier {
- public:
- Barrier();
- ~Barrier();
- void open();
- void close();
- void waitAndClose();
- status_t waitAndClose(nsecs_t timeout);
- private:
- enum { OPENED, CLOSED };
- mutable Mutex lock;
- mutable Condition cv;
- volatile int state;
- };
-
friend class SurfaceFlinger;
-
- // server constructor
- SurfaceFlingerSynchro();
-
- void open();
-
- // wait until there is some work to do
- status_t wait();
- status_t wait(nsecs_t timeout);
-
sp<ISurfaceComposer> mSurfaceComposer;
- Barrier mBarrier;
};
}; // namespace android
diff --git a/include/private/ui/android_natives_priv.h b/include/private/ui/android_natives_priv.h
new file mode 100644
index 0000000..9c92af8
--- /dev/null
+++ b/include/private/ui/android_natives_priv.h
@@ -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.
+ */
+
+#ifndef ANDROID_ANDROID_NATIVES_PRIV_H
+#define ANDROID_ANDROID_NATIVES_PRIV_H
+
+#include <ui/egl/android_natives.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+typedef struct android_native_buffer_t
+{
+#ifdef __cplusplus
+ android_native_buffer_t() {
+ common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+ common.version = sizeof(android_native_buffer_t);
+ memset(common.reserved, 0, sizeof(common.reserved));
+ }
+#endif
+
+ struct android_native_base_t common;
+
+ int width;
+ int height;
+ int stride;
+ int format;
+ int usage;
+
+ void* reserved[2];
+
+ buffer_handle_t handle;
+
+ void* reserved_proc[8];
+} android_native_buffer_t;
+
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+/*****************************************************************************/
+
+#endif /* ANDROID_ANDROID_NATIVES_PRIV_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/private/utils/futex_synchro.h b/include/private/utils/futex_synchro.h
deleted file mode 100644
index ac2ab19..0000000
--- a/include/private/utils/futex_synchro.h
+++ /dev/null
@@ -1,60 +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 _FUTEX_SYNCHRO_H
-#define _FUTEX_SYNCHRO_H
-
-#ifndef HAVE_FUTEX
-#error "HAVE_FUTEX not defined"
-#endif
-
-#define FUTEX_WAIT_INFINITE (0)
-
-typedef struct futex_mutex_t futex_mutex_t;
-
-struct futex_mutex_t
-{
- volatile int value;
-};
-
-typedef struct futex_cond_t futex_cond_t;
-
-struct futex_cond_t
-{
- volatile int value;
-};
-
-
-#if __cplusplus
-extern "C" {
-#endif
-
-void futex_mutex_init(futex_mutex_t *m);
-int futex_mutex_lock(futex_mutex_t *m, unsigned msec);
-void futex_mutex_unlock(futex_mutex_t *m);
-int futex_mutex_trylock(futex_mutex_t *m);
-
-void futex_cond_init(futex_cond_t *c);
-int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec);
-void futex_cond_signal(futex_cond_t *c);
-void futex_cond_broadcast(futex_cond_t *c);
-
-#if __cplusplus
-} // extern "C"
-#endif
-
-#endif // _FUTEX_SYNCHRO_H
-
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
index 21cb73b..28b0d2f 100644
--- a/include/tts/TtsEngine.h
+++ b/include/tts/TtsEngine.h
@@ -43,7 +43,7 @@ enum tts_callback_status {
// @param [inout] void *& - The userdata pointer set in the original
// synth call
// @param [in] uint32_t - Track sampling rate in Hz
-// @param [in] audio_format - The AudioSystem::audio_format enum
+// @param [in] uint32_t - The audio format
// @param [in] int - The number of channels
// @param [inout] int8_t *& - A buffer of audio data only valid during the
// execution of the callback
@@ -54,7 +54,7 @@ enum tts_callback_status {
// TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if
// there is more data to produce.
typedef tts_callback_status (synthDoneCB_t)(void *&, uint32_t,
- AudioSystem::audio_format, int, int8_t *&, size_t&, tts_synth_status);
+ uint32_t, int, int8_t *&, size_t&, tts_synth_status);
class TtsEngine;
extern "C" TtsEngine* getTtsEngine();
@@ -80,6 +80,8 @@ enum tts_support_result {
class TtsEngine
{
public:
+ virtual ~TtsEngine() {}
+
// Initialize the TTS engine and returns whether initialization succeeded.
// @param synthDoneCBPtr synthesis callback function pointer
// @return TTS_SUCCESS, or TTS_FAILURE
diff --git a/include/ui/BufferMapper.h b/include/ui/BufferMapper.h
new file mode 100644
index 0000000..5f084be
--- /dev/null
+++ b/include/ui/BufferMapper.h
@@ -0,0 +1,64 @@
+/*
+ * 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_UI_BUFFER_MAPPER_H
+#define ANDROID_UI_BUFFER_MAPPER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Singleton.h>
+
+#include <hardware/gralloc.h>
+
+
+struct gralloc_module_t;
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class Rect;
+
+class BufferMapper : public Singleton<BufferMapper>
+{
+public:
+ static inline BufferMapper& get() { return getInstance(); }
+
+ status_t registerBuffer(buffer_handle_t handle);
+
+ status_t unregisterBuffer(buffer_handle_t handle);
+
+ status_t lock(buffer_handle_t handle,
+ int usage, const Rect& bounds, void** vaddr);
+
+ status_t unlock(buffer_handle_t handle);
+
+ // dumps information about the mapping of this handle
+ void dump(buffer_handle_t handle);
+
+private:
+ friend class Singleton<BufferMapper>;
+ BufferMapper();
+ gralloc_module_t const *mAllocMod;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_UI_BUFFER_MAPPER_H
+
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index afb07b5..ae6e255 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -66,15 +66,16 @@ namespace android {
// msgType in notifyCallback and dataCallback functions
enum {
- CAMERA_MSG_ERROR = 0,
- CAMERA_MSG_SHUTTER,
- CAMERA_MSG_FOCUS,
- CAMERA_MSG_ZOOM,
- CAMERA_MSG_PREVIEW_FRAME,
- CAMERA_MSG_VIDEO_FRAME,
- CAMERA_MSG_POSTVIEW_FRAME,
- CAMERA_MSG_RAW_IMAGE,
- CAMERA_MSG_COMPRESSED_IMAGE
+ CAMERA_MSG_ERROR = 0x001,
+ CAMERA_MSG_SHUTTER = 0x002,
+ CAMERA_MSG_FOCUS = 0x004,
+ CAMERA_MSG_ZOOM = 0x008,
+ CAMERA_MSG_PREVIEW_FRAME = 0x010,
+ CAMERA_MSG_VIDEO_FRAME = 0x020,
+ CAMERA_MSG_POSTVIEW_FRAME = 0x040,
+ CAMERA_MSG_RAW_IMAGE = 0x080,
+ CAMERA_MSG_COMPRESSED_IMAGE = 0x100,
+ CAMERA_MSG_ALL_MSGS = 0x1FF
};
// camera fatal errors
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
index 822b4a8..535f70e 100644
--- a/include/ui/CameraHardwareInterface.h
+++ b/include/ui/CameraHardwareInterface.h
@@ -17,30 +17,28 @@
#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/ISurface.h>
+#include <ui/Camera.h>
#include <ui/CameraParameters.h>
#include <ui/Overlay.h>
namespace android {
-/** Callback for startPreview() */
-typedef void (*preview_callback)(const sp<IMemory>& mem, void* user);
+typedef void (*notify_callback)(int32_t msgType,
+ int32_t ext1,
+ int32_t ext2,
+ void* user);
-/** Callback for startRecord() */
-typedef void (*recording_callback)(nsecs_t timestamp, const sp<IMemory>& mem, void* user);
+typedef void (*data_callback)(int32_t msgType,
+ const sp<IMemory>& dataPtr,
+ void* user);
-/** Callback for takePicture() */
-typedef void (*shutter_callback)(void* user);
-
-/** Callback for takePicture() */
-typedef void (*raw_callback)(const sp<IMemory>& mem, void* user);
-
-/** Callback for takePicture() */
-typedef void (*jpeg_callback)(const sp<IMemory>& mem, void* user);
-
-/** Callback for autoFocus() */
-typedef void (*autofocus_callback)(bool focused, void* user);
+typedef void (*data_callback_timestamp)(nsecs_t timestamp,
+ int32_t msgType,
+ const sp<IMemory>& dataPtr,
+ void* user);
/**
* CameraHardwareInterface.h defines the interface to the
@@ -57,28 +55,21 @@ typedef void (*autofocus_callback)(bool focused, void* user);
* CameraService calls getPreviewHeap() to establish access to the
* preview heap so it can be registered with SurfaceFlinger for
* efficient display updating while in preview mode.
- * -# startPreview() is called, which is passed a preview_callback()
- * function and a user parameter. The camera instance then periodically
- * calls preview_callback() each time a new preview frame is available.
- * The callback routine has two parameters: the first is a pointer to
- * the IMemory containing the frame and the second a user parameter. If
- * the preview_callback code needs to use this memory after returning,
- * it must copy the data.
+ * -# startPreview() is called. The camera instance then periodically
+ * sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
+ * a new preview frame is available. If data callback code needs to use
+ * this memory after returning, it must copy the data.
*
- * Prior to taking a picture, CameraService calls autofocus() with
- * autofocus_callback() and a user parameter. When auto focusing has
- * completed, the camera instance calls autofocus_callback(), which informs
- * the application whether focusing was successful. The camera instance
- * only calls autofocus_callback() once and it is up to the application to
- * call autoFocus() again if refocusing is desired.
+ * Prior to taking a picture, CameraService calls autofocus(). When auto
+ * focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
+ * which informs the application whether focusing was successful. The camera instance
+ * only sends this message once and it is up to the application to call autoFocus()
+ * again if refocusing is desired.
*
* CameraService calls takePicture() to request the camera instance take a
- * picture. This method has two callbacks: raw_callback() and jpeg_callback().
- * When the raw image is available, raw_callback() is called with a pointer
- * to the IMemory containing the raw image. When the jpeg image is available,
- * jpeg_callback() is called with a pointer to the IMemory containing the
- * jpeg image. As with preview_callback(), the memory must be copied if it's
- * needed after returning.
+ * picture. At this point, if a shutter, postview, raw, and/or compressed callback
+ * is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
+ * any memory provided in a data callback must be copied if it's needed after returning.
*/
class CameraHardwareInterface : public virtual RefBase {
public:
@@ -90,17 +81,45 @@ public:
/** Return the IMemoryHeap for the raw image heap */
virtual sp<IMemoryHeap> getRawHeap() const = 0;
+ /** Set the notification and data callbacks */
+ virtual void setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user) = 0;
+
/**
- * Start preview mode. When a preview image is available
- * preview_callback is called with the user parameter. The
- * call back parameter may be null.
+ * The following three functions all take a msgtype,
+ * which is a bitmask of the messages defined in
+ * include/ui/Camera.h
*/
- virtual status_t startPreview(preview_callback cb, void* user) = 0;
+
+ /**
+ * Enable a message, or set of messages.
+ */
+ virtual void enableMsgType(int32_t msgType) = 0;
+
+ /**
+ * Disable a message, or a set of messages.
+ */
+ virtual void disableMsgType(int32_t msgType) = 0;
+
+ /**
+ * Query whether a message, or a set of messages, is enabled.
+ * Note that this is operates as an AND, if any of the messages
+ * queried are off, this will return false.
+ */
+ virtual bool msgTypeEnabled(int32_t msgType) = 0;
+
+ /**
+ * Start preview mode.
+ */
+ virtual status_t startPreview() = 0;
+
/**
* Only used if overlays are used for camera preview.
*/
- virtual bool useOverlay() {return false;}
- virtual status_t setOverlay(const sp<Overlay> &overlay) {return BAD_VALUE;}
+ virtual bool useOverlay() {return false;}
+ virtual status_t setOverlay(const sp<Overlay> &overlay) {return BAD_VALUE;}
/**
* Stop a previously started preview.
@@ -113,11 +132,11 @@ public:
virtual bool previewEnabled() = 0;
/**
- * Start record mode. When a record image is available recording_callback()
- * is called with the user parameter. Every record frame must be released
+ * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
+ * message is sent with the corresponding frame. Every record frame must be released
* by calling releaseRecordingFrame().
*/
- virtual status_t startRecording(recording_callback cb, void* user) = 0;
+ virtual status_t startRecording() = 0;
/**
* Stop a previously started recording.
@@ -130,39 +149,27 @@ public:
virtual bool recordingEnabled() = 0;
/**
- * Release a record frame previously returned by the recording_callback()
- * passed to startRecord().
+ * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
*/
virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
/**
- * Start auto focus, the callback routine is called
- * once when focusing is complete. autoFocus() will
- * be called again if another auto focus is needed.
+ * Start auto focus, the notification callback routine is called
+ * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
+ * will be called again if another auto focus is needed.
*/
- virtual status_t autoFocus(autofocus_callback,
- void* user) = 0;
+ virtual status_t autoFocus() = 0;
/**
- * Take a picture. The raw_callback is called when
- * the uncompressed image is available. The jpeg_callback
- * is called when the compressed image is available. These
- * call backs may be null. The user parameter is passed
- * to each of the call back routines.
+ * Take a picture.
*/
- virtual status_t takePicture(shutter_callback,
- raw_callback,
- jpeg_callback,
- void* user) = 0;
+ virtual status_t takePicture() = 0;
/**
- * Cancel a picture that was started with takePicture. You may cancel any
- * of the shutter, raw, or jpeg callbacks. Calling this method when no
- * picture is being taken is a no-op.
+ * Cancel a picture that was started with takePicture. Calling this
+ * method when no picture is being taken is a no-op.
*/
- virtual status_t cancelPicture(bool cancel_shutter,
- bool cancel_raw,
- bool cancel_jpeg) = 0;
+ virtual status_t cancelPicture() = 0;
/** Set the camera parameters. */
virtual status_t setParameters(const CameraParameters& params) = 0;
diff --git a/include/ui/EGLDisplaySurface.h b/include/ui/EGLDisplaySurface.h
deleted file mode 100644
index a8b5853..0000000
--- a/include/ui/EGLDisplaySurface.h
+++ /dev/null
@@ -1,86 +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_EGL_DISPLAY_SURFACE_H
-#define ANDROID_EGL_DISPLAY_SURFACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Timers.h>
-
-#include <ui/EGLNativeSurface.h>
-
-#include <pixelflinger/pixelflinger.h>
-#include <linux/fb.h>
-
-#include <EGL/egl.h>
-
-struct copybit_device_t;
-struct copybit_image_t;
-
-// ---------------------------------------------------------------------------
-namespace android {
-// ---------------------------------------------------------------------------
-
-class Region;
-class Rect;
-
-class EGLDisplaySurface : public EGLNativeSurface<EGLDisplaySurface>
-{
-public:
- EGLDisplaySurface();
- ~EGLDisplaySurface();
-
- int32_t getPageFlipCount() const;
- void copyFrontToBack(const Region& copyback);
- void copyFrontToImage(const copybit_image_t& dst);
- void copyBackToImage(const copybit_image_t& dst);
-
- void setSwapRectangle(int l, int t, int w, int h);
-
-private:
- static void hook_incRef(NativeWindowType window);
- static void hook_decRef(NativeWindowType window);
- static uint32_t hook_swapBuffers(NativeWindowType window);
-
- uint32_t swapBuffers();
-
- status_t mapFrameBuffer();
-
- enum {
- PAGE_FLIP = 0x00000001
- };
- GGLSurface mFb[2];
- int mIndex;
- uint32_t mFlags;
- size_t mSize;
- fb_var_screeninfo mInfo;
- fb_fix_screeninfo mFinfo;
- int32_t mPageFlipCount;
- nsecs_t mTime;
- int32_t mSwapCount;
- nsecs_t mSleep;
- uint32_t mFeatureFlags;
- copybit_device_t* mBlitEngine;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_EGL_DISPLAY_SURFACE_H
-
diff --git a/include/ui/EGLNativeWindowSurface.h b/include/ui/EGLNativeWindowSurface.h
deleted file mode 100644
index 3494234..0000000
--- a/include/ui/EGLNativeWindowSurface.h
+++ /dev/null
@@ -1,59 +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_EGL_NATIVE_WINDOW_SURFACE_H
-#define ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <ui/EGLNativeSurface.h>
-#include <EGL/egl.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-// ---------------------------------------------------------------------------
-
-class Surface;
-
-class EGLNativeWindowSurface : public EGLNativeSurface<EGLNativeWindowSurface>
-{
-public:
- EGLNativeWindowSurface(const sp<Surface>& surface);
- ~EGLNativeWindowSurface();
-
- void setSwapRectangle(int l, int t, int w, int h);
-
-private:
- static void hook_incRef(NativeWindowType window);
- static void hook_decRef(NativeWindowType window);
- static uint32_t hook_swapBuffers(NativeWindowType window);
- static void hook_connect(NativeWindowType window);
- static void hook_disconnect(NativeWindowType window);
-
- uint32_t swapBuffers();
- void connect();
- void disconnect();
-
- sp<Surface> mSurface;
- bool mConnected;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_EGL_NATIVE_WINDOW_SURFACE_H
-
diff --git a/include/ui/EGLUtils.h b/include/ui/EGLUtils.h
new file mode 100644
index 0000000..a5bff81
--- /dev/null
+++ b/include/ui/EGLUtils.h
@@ -0,0 +1,53 @@
+/*
+ * 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_UI_EGLUTILS_H
+#define ANDROID_UI_EGLUTILS_H
+
+#include <utils/Errors.h>
+#include <ui/PixelFormat.h>
+#include <EGL/egl.h>
+
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class EGLUtils
+{
+public:
+
+ static const char *strerror(EGLint err);
+
+ static status_t selectConfigForPixelFormat(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ PixelFormat format,
+ EGLConfig* outConfig);
+
+ static status_t selectConfigForNativeWindow(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ EGLNativeWindowType window,
+ EGLConfig* outConfig);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_UI_EGLUTILS_H */
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 3848d8c..3b18c77 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>
@@ -52,7 +55,9 @@ public:
CLASS_KEYBOARD = 0x00000001,
CLASS_ALPHAKEY = 0x00000002,
CLASS_TOUCHSCREEN = 0x00000004,
- CLASS_TRACKBALL = 0x00000008
+ CLASS_TRACKBALL = 0x00000008,
+ CLASS_TOUCHSCREEN_MT= 0x00000010,
+ CLASS_DPAD = 0x00000020
};
uint32_t getDeviceClasses(int32_t deviceId) const;
@@ -70,6 +75,13 @@ public:
int getKeycodeState(int key) const;
int getKeycodeState(int32_t deviceId, int key) const;
+ status_t scancodeToKeycode(int32_t deviceId, int scancode,
+ int32_t* outKeycode, uint32_t* outFlags) const;
+
+ // exclude a particular device from opening
+ // this can be used to ignore input devices for sensors
+ void addExcludedDevice(const char* deviceName);
+
// special type codes when devices are added/removed.
enum {
DEVICE_ADDED = 0x10000000,
@@ -82,10 +94,9 @@ public:
virtual bool getEvent(int32_t* outDeviceId, int32_t* outType,
int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
int32_t* outValue, nsecs_t* outWhen);
-
+
protected:
virtual ~EventHub();
- virtual void onFirstRef();
private:
bool openPlatformInput(void);
@@ -108,17 +119,18 @@ private:
String8 keylayoutFilename;
device_t* next;
- device_t(int32_t _id, const char* _path);
+ device_t(int32_t _id, const char* _path, const char* name);
~device_t();
};
device_t* getDevice(int32_t deviceId) const;
+ bool hasKeycode(device_t* device, int keycode) const;
// Protect all internal state.
mutable Mutex mLock;
bool mHaveFirstKeyboard;
- int32_t mFirstKeyboardId; // the API is that the build in keyboard is id 0, so map it
+ int32_t mFirstKeyboardId; // the API is that the built-in keyboard is id 0, so map it
struct device_ent {
device_t* device;
@@ -133,7 +145,10 @@ private:
device_t **mDevices;
struct pollfd *mFDs;
int mFDCount;
-
+
+ bool mOpened;
+ List<String8> mExcludedDevices;
+
// device ids that report particular switches.
#ifdef EV_SW
int32_t mSwitches[SW_MAX+1];
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
new file mode 100644
index 0000000..68144b5
--- /dev/null
+++ b/include/ui/FramebufferNativeWindow.h
@@ -0,0 +1,87 @@
+/*
+ * 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_FRAMEBUFFER_NATIVE_WINDOW_H
+#define ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+
+#include <utils/threads.h>
+#include <ui/Rect.h>
+
+#include <pixelflinger/pixelflinger.h>
+
+#include <ui/egl/android_natives.h>
+
+
+extern "C" EGLNativeWindowType android_createDisplaySurface(void);
+
+// ---------------------------------------------------------------------------
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Surface;
+class NativeBuffer;
+
+// ---------------------------------------------------------------------------
+
+class FramebufferNativeWindow
+ : public EGLNativeBase<
+ android_native_window_t,
+ FramebufferNativeWindow,
+ LightRefBase<FramebufferNativeWindow> >
+{
+public:
+ FramebufferNativeWindow();
+
+ framebuffer_device_t const * getDevice() const { return fbDev; }
+
+ bool isUpdateOnDemand() const { return mUpdateOnDemand; }
+ status_t setUpdateRectangle(const Rect& updateRect);
+
+private:
+ friend class LightRefBase<FramebufferNativeWindow>;
+ ~FramebufferNativeWindow(); // this class cannot be overloaded
+ static int setSwapInterval(android_native_window_t* window, int interval);
+ static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
+ static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int query(android_native_window_t* window, int what, int* value);
+ static int perform(android_native_window_t* window, int operation, ...);
+
+ framebuffer_device_t* fbDev;
+ alloc_device_t* grDev;
+
+ sp<NativeBuffer> buffers[2];
+ sp<NativeBuffer> front;
+
+ mutable Mutex mutex;
+ Condition mCondition;
+ int32_t mNumBuffers;
+ int32_t mNumFreeBuffers;
+ int32_t mBufferHead;
+ bool mUpdateOnDemand;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_FRAMEBUFFER_NATIVE_WINDOW_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 1001c71..236d0f6 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>
#include <utils/Timers.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..7909c2f 100644
--- a/include/ui/ISurface.h
+++ b/include/ui/ISurface.h
@@ -21,11 +21,12 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/IInterface.h>
+#include <binder/IInterface.h>
#include <utils/RefBase.h>
#include <ui/PixelFormat.h>
#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
namespace android {
@@ -33,6 +34,7 @@ typedef int32_t SurfaceID;
class IMemoryHeap;
class OverlayRef;
+class SurfaceBuffer;
class ISurface : public IInterface
{
@@ -42,11 +44,13 @@ protected:
UNREGISTER_BUFFERS,
POST_BUFFER, // one-way transaction
CREATE_OVERLAY,
+ GET_BUFFER,
};
public:
DECLARE_META_INTERFACE(Surface);
+ virtual sp<SurfaceBuffer> getBuffer(int usage) = 0;
class BufferHeap {
public:
@@ -78,9 +82,7 @@ public:
};
virtual status_t registerBuffers(const BufferHeap& buffers) = 0;
-
virtual void postBuffer(ssize_t offset) = 0; // one-way
-
virtual void unregisterBuffers() = 0;
virtual sp<OverlayRef> createOverlay(
diff --git a/include/ui/ISurfaceComposer.h b/include/ui/ISurfaceComposer.h
index 5c64b22..25d954c 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>
@@ -32,7 +32,6 @@ namespace android {
// ----------------------------------------------------------------------------
class DisplayInfo;
-class IGPUCallback;
class ISurfaceComposer : public IInterface
{
@@ -41,8 +40,6 @@ public:
enum { // (keep in sync with Surface.java)
eHidden = 0x00000004,
- eGPU = 0x00000008,
- eHardware = 0x00000010,
eDestroyBackbuffer = 0x00000020,
eSecure = 0x00000080,
eNonPremultiplied = 0x00000100,
@@ -63,7 +60,6 @@ public:
eTransparentRegionChanged = 0x00000020,
eVisibilityChanged = 0x00000040,
eFreezeTintChanged = 0x00000080,
- eDestroyed = 0x00000100
};
enum {
@@ -94,7 +90,7 @@ public:
virtual sp<ISurfaceFlingerClient> createConnection() = 0;
/* retrieve the control block */
- virtual sp<IMemory> getCblk() const = 0;
+ virtual sp<IMemoryHeap> getCblk() const = 0;
/* open/close transactions. recquires ACCESS_SURFACE_FLINGER permission */
virtual void openGlobalTransaction() = 0;
@@ -112,37 +108,12 @@ public:
*/
virtual void bootFinished() = 0;
- /* get access to the GPU. Access is relinquished when releasing regs */
- struct gpu_info_t {
- struct gpu_region_t {
- sp<IMemory> region;
- size_t reserved;
- };
- sp<IMemory> regs;
- size_t count;
- gpu_region_t regions[2];
- };
- virtual status_t requestGPU(
- const sp<IGPUCallback>& callback,
- gpu_info_t* gpu) = 0;
-
- /* take the gpu back from any apps using it. They'll get a
- * EGL_CONTEXT_LOST error */
- virtual status_t revokeGPU() = 0;
-
/* Signal surfaceflinger that there might be some work to do
* This is an ASYNCHRONOUS call.
*/
virtual void signal() const = 0;
};
-class IGPUCallback : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(GPUCallback);
- virtual void gpuLost() = 0; //one-way
-};
-
// ----------------------------------------------------------------------------
class BnSurfaceComposer : public BnInterface<ISurfaceComposer>
@@ -159,8 +130,6 @@ public:
SET_ORIENTATION,
FREEZE_DISPLAY,
UNFREEZE_DISPLAY,
- REQUEST_GPU,
- REVOKE_GPU,
SIGNAL
};
@@ -170,15 +139,6 @@ public:
uint32_t flags = 0);
};
-class BnGPUCallback : public BnInterface<IGPUCallback>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/include/ui/ISurfaceFlingerClient.h b/include/ui/ISurfaceFlingerClient.h
index 5b9361d..5d231e6 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>
@@ -52,12 +52,14 @@ public:
struct surface_data_t {
int32_t token;
int32_t identity;
- sp<IMemoryHeap> heap[2];
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
status_t readFromParcel(const Parcel& parcel);
status_t writeToParcel(Parcel* parcel) const;
};
- virtual void getControlBlocks(sp<IMemory>* ctl) const = 0;
+ virtual sp<IMemoryHeap> getControlBlock() const = 0;
virtual sp<ISurface> createSurface( surface_data_t* data,
int pid,
diff --git a/include/ui/Overlay.h b/include/ui/Overlay.h
index 66514b4..a9ae1c4 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>
@@ -82,6 +82,16 @@ public:
/* release the overlay buffer and post it */
status_t queueBuffer(overlay_buffer_t buffer);
+ /* change the width and height of the overlay */
+ status_t resizeInput(uint32_t width, uint32_t height);
+
+ status_t setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) ;
+
+ status_t getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) ;
+
+ /* set the buffer attributes */
+ status_t setParameter(int param, int value);
+
/* returns the address of a given buffer if supported, NULL otherwise. */
void* getBufferAddress(overlay_buffer_t buffer);
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index 14af823..6d87321 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -84,6 +84,13 @@ typedef int32_t PixelFormat;
struct PixelFormatInfo
{
+ enum {
+ INDEX_ALPHA = 0,
+ INDEX_RED = 1,
+ INDEX_GREEN = 2,
+ INDEX_BLUE = 3
+ };
+
enum { // components
ALPHA = 1,
RGB = 2,
@@ -95,20 +102,33 @@ struct PixelFormatInfo
Y_CB_CR_I = 8,
};
+ struct szinfo {
+ uint8_t h;
+ uint8_t l;
+ };
+
inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
size_t getScanlineSize(unsigned int width) const;
+ size_t getSize(size_t ci) const {
+ return (ci <= 3) ? (cinfo[ci].h - cinfo[ci].l) : 0;
+ }
size_t version;
PixelFormat format;
size_t bytesPerPixel;
size_t bitsPerPixel;
- uint8_t h_alpha;
- uint8_t l_alpha;
- uint8_t h_red;
- uint8_t l_red;
- uint8_t h_green;
- uint8_t l_green;
- uint8_t h_blue;
- uint8_t l_blue;
+ union {
+ szinfo cinfo[4];
+ struct {
+ uint8_t h_alpha;
+ uint8_t l_alpha;
+ uint8_t h_red;
+ uint8_t l_red;
+ uint8_t h_green;
+ uint8_t l_green;
+ uint8_t h_blue;
+ uint8_t l_blue;
+ };
+ };
uint8_t components;
uint8_t reserved0[3];
uint32_t reserved1;
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index da72944..a213c09 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -30,6 +30,8 @@ public:
int right;
int bottom;
+ typedef int value_type;
+
// we don't provide copy-ctor and operator= on purpose
// because we want the compiler generated versions
@@ -46,7 +48,11 @@ public:
}
void makeInvalid();
-
+
+ inline void clear() {
+ left = top = right = bottom = 0;
+ }
+
// a valid rectangle has a non negative width and height
inline bool isValid() const {
return (width()>=0) && (height()>=0);
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 7689673..2bcad5b 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -21,14 +21,12 @@
#include <sys/types.h>
#include <utils/Vector.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <ui/Rect.h>
#include <hardware/copybit.h>
-#include <core/SkRegion.h>
-
namespace android {
// ---------------------------------------------------------------------------
@@ -40,7 +38,6 @@ class Region
public:
Region();
Region(const Region& rhs);
- explicit Region(const SkRegion& rhs);
explicit Region(const Rect& rhs);
explicit Region(const Parcel& parcel);
explicit Region(const void* buffer);
@@ -48,65 +45,78 @@ public:
Region& operator = (const Region& rhs);
- inline bool isEmpty() const { return mRegion.isEmpty(); }
- inline bool isRect() const { return mRegion.isRect(); }
-
- Rect bounds() const;
+ inline bool isEmpty() const { return mBounds.isEmpty(); }
+ inline bool isRect() const { return mStorage.isEmpty(); }
- const SkRegion& toSkRegion() const;
+ inline Rect getBounds() const { return mBounds; }
+ inline Rect bounds() const { return getBounds(); }
+ // the region becomes its bounds
+ Region& makeBoundsSelf();
+
void clear();
void set(const Rect& r);
+ void set(uint32_t w, uint32_t h);
Region& orSelf(const Rect& rhs);
Region& andSelf(const Rect& rhs);
+ Region& subtractSelf(const Rect& rhs);
// boolean operators, applied on this
Region& orSelf(const Region& rhs);
Region& andSelf(const Region& rhs);
Region& subtractSelf(const Region& rhs);
+ // boolean operators
+ const Region merge(const Rect& rhs) const;
+ const Region intersect(const Rect& rhs) const;
+ const Region subtract(const Rect& rhs) const;
+
+ // boolean operators
+ const Region merge(const Region& rhs) const;
+ const Region intersect(const Region& rhs) const;
+ const Region subtract(const Region& rhs) const;
+
// these translate rhs first
Region& translateSelf(int dx, int dy);
Region& orSelf(const Region& rhs, int dx, int dy);
Region& andSelf(const Region& rhs, int dx, int dy);
Region& subtractSelf(const Region& rhs, int dx, int dy);
- // boolean operators
- Region merge(const Region& rhs) const;
- Region intersect(const Region& rhs) const;
- Region subtract(const Region& rhs) const;
-
// these translate rhs first
- Region translate(int dx, int dy) const;
- Region merge(const Region& rhs, int dx, int dy) const;
- Region intersect(const Region& rhs, int dx, int dy) const;
- Region subtract(const Region& rhs, int dx, int dy) const;
+ const Region translate(int dx, int dy) const;
+ const Region merge(const Region& rhs, int dx, int dy) const;
+ const Region intersect(const Region& rhs, int dx, int dy) const;
+ const Region subtract(const Region& rhs, int dx, int dy) const;
// convenience operators overloads
- inline Region operator | (const Region& rhs) const;
- inline Region operator & (const Region& rhs) const;
- inline Region operator - (const Region& rhs) const;
- inline Region operator + (const Point& pt) const;
+ inline const Region operator | (const Region& rhs) const;
+ inline const Region operator & (const Region& rhs) const;
+ inline const Region operator - (const Region& rhs) const;
+ inline const Region operator + (const Point& pt) const;
inline Region& operator |= (const Region& rhs);
inline Region& operator &= (const Region& rhs);
inline Region& operator -= (const Region& rhs);
inline Region& operator += (const Point& pt);
- class iterator {
- SkRegion::Iterator mIt;
- public:
- iterator(const Region& r);
- inline operator bool () const { return !done(); }
- int iterate(Rect* rect);
- private:
- inline bool done() const {
- return const_cast<SkRegion::Iterator&>(mIt).done();
- }
- };
+
+ /* various ways to access the rectangle list */
+
+ typedef Rect const* const_iterator;
+
+ const_iterator begin() const;
+ const_iterator end() const;
- size_t rects(Vector<Rect>& rectList) const;
+ /* no user serviceable parts here... */
+
+ size_t getRects(Vector<Rect>& rectList) const;
+ Rect const* getArray(size_t* count) const;
+
+
+ // add a rectangle to the internal list. This rectangle must
+ // be sorted in Y and X and must not make the region invalid.
+ void addRectUnchecked(int l, int t, int r, int b);
// flatten/unflatten a region to/from a Parcel
status_t write(Parcel& parcel) const;
@@ -123,20 +133,46 @@ public:
void dump(const char* what, uint32_t flags=0) const;
private:
- SkRegion mRegion;
+ class rasterizer;
+ friend class rasterizer;
+
+ Region& operationSelf(const Rect& r, int op);
+ Region& operationSelf(const Region& r, int op);
+ Region& operationSelf(const Region& r, int dx, int dy, int op);
+ const Region operation(const Rect& rhs, int op) const;
+ const Region operation(const Region& rhs, int op) const;
+ const Region operation(const Region& rhs, int dx, int dy, int op) const;
+
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Region& rhs, int dx, int dy);
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Rect& rhs, int dx, int dy);
+
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Region& rhs);
+ static void boolean_operation(int op, Region& dst,
+ const Region& lhs, const Rect& rhs);
+
+ static void translate(Region& reg, int dx, int dy);
+ static void translate(Region& dst, const Region& reg, int dx, int dy);
+
+ static bool validate(const Region& reg, const char* name);
+
+ Rect mBounds;
+ Vector<Rect> mStorage;
};
-Region Region::operator | (const Region& rhs) const {
+const Region Region::operator | (const Region& rhs) const {
return merge(rhs);
}
-Region Region::operator & (const Region& rhs) const {
+const Region Region::operator & (const Region& rhs) const {
return intersect(rhs);
}
-Region Region::operator - (const Region& rhs) const {
+const Region Region::operator - (const Region& rhs) const {
return subtract(rhs);
}
-Region Region::operator + (const Point& pt) const {
+const Region Region::operator + (const Point& pt) const {
return translate(pt.x, pt.y);
}
@@ -157,16 +193,23 @@ Region& Region::operator += (const Point& pt) {
// ---------------------------------------------------------------------------
struct region_iterator : public copybit_region_t {
- region_iterator(const Region& region) : i(region) {
+ region_iterator(const Region& region)
+ : b(region.begin()), e(region.end()) {
this->next = iterate;
}
private:
static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
- return static_cast<const region_iterator*>(self)
- ->i.iterate(reinterpret_cast<Rect*>(rect));
+ region_iterator const* me = static_cast<region_iterator const*>(self);
+ if (me->b != me->e) {
+ *reinterpret_cast<Rect*>(rect) = *me->b++;
+ return 1;
+ }
+ return 0;
}
- mutable Region::iterator i;
+ mutable Region::const_iterator b;
+ Region::const_iterator const e;
};
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/include/ui/Surface.h b/include/ui/Surface.h
index 33953a9..30ab82f 100644
--- a/include/ui/Surface.h
+++ b/include/ui/Surface.h
@@ -28,48 +28,41 @@
#include <ui/Region.h>
#include <ui/ISurfaceFlingerClient.h>
+#include <ui/egl/android_natives.h>
+
namespace android {
// ---------------------------------------------------------------------------
+class BufferMapper;
+class IOMX;
class Rect;
+class Surface;
class SurfaceComposerClient;
+struct per_client_cblk_t;
+struct layer_cblk_t;
-class Surface : public RefBase
-{
+// ---------------------------------------------------------------------------
+class SurfaceControl : public RefBase
+{
public:
- struct SurfaceInfo {
- uint32_t w;
- uint32_t h;
- uint32_t bpr;
- PixelFormat format;
- void* bits;
- void* base;
- uint32_t reserved[2];
- };
-
- bool isValid() const { return this && mToken>=0 && mClient!=0; }
+ static bool isValid(const sp<SurfaceControl>& surface) {
+ return (surface != 0) && surface->isValid();
+ }
+ bool isValid() {
+ return mToken>=0 && mClient!=0;
+ }
+ static bool isSameSurface(
+ const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
+
SurfaceID ID() const { return mToken; }
-
- status_t lock(SurfaceInfo* info, bool blocking = true);
- status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
- status_t unlockAndPost();
- status_t unlock();
-
- void* heapBase(int i) const;
uint32_t getFlags() const { return mFlags; }
+ uint32_t getIdentity() const { return mIdentity; }
- // setSwapRectangle() is mainly used by EGL
- void setSwapRectangle(const Rect& r);
- const Rect& swapRectangle() const;
- status_t nextBuffer(SurfaceInfo* info);
-
- sp<Surface> dup() const;
- static sp<Surface> readFromParcel(Parcel* parcel);
- static status_t writeToParcel(const sp<Surface>& surface, Parcel* parcel);
- static bool isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs);
-
+ // release surface data from java
+ void clear();
+
status_t setLayer(int32_t layer);
status_t setPosition(int32_t x, int32_t y);
status_t setSize(uint32_t w, uint32_t h);
@@ -83,8 +76,17 @@ public:
status_t setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
status_t setFreezeTint(uint32_t tint);
- uint32_t getIdentity() const { return mIdentity; }
+ static status_t writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel);
+
+ sp<Surface> getSurface() const;
+
private:
+ // can't be copied
+ SurfaceControl& operator = (SurfaceControl& rhs);
+ SurfaceControl(const SurfaceControl& rhs);
+
+
friend class SurfaceComposerClient;
// camera and camcorder need access to the ISurface binder interface for preview
@@ -92,42 +94,157 @@ private:
friend class MediaRecorder;
// mediaplayer needs access to ISurface for display
friend class MediaPlayer;
+ // for testing
friend class Test;
const sp<ISurface>& getISurface() const { return mSurface; }
+
- // can't be copied
- Surface& operator = (Surface& rhs);
- Surface(const Surface& rhs);
+ friend class Surface;
- Surface(const sp<SurfaceComposerClient>& client,
+ SurfaceControl(
+ const sp<SurfaceComposerClient>& client,
const sp<ISurface>& surface,
const ISurfaceFlingerClient::surface_data_t& data,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- bool owner = true);
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
- Surface(Surface const* rhs);
+ ~SurfaceControl();
- ~Surface();
+ status_t validate(per_client_cblk_t const* cblk) const;
+ void destroy();
+
+ sp<SurfaceComposerClient> mClient;
+ sp<ISurface> mSurface;
+ SurfaceID mToken;
+ uint32_t mIdentity;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ PixelFormat mFormat;
+ uint32_t mFlags;
+ mutable Mutex mLock;
+
+ mutable sp<Surface> mSurfaceData;
+};
+
+// ---------------------------------------------------------------------------
- Region dirtyRegion() const;
- void setDirtyRegion(const Region& region) const;
+class Surface
+ : public EGLNativeBase<android_native_window_t, Surface, RefBase>
+{
+public:
+ struct SurfaceInfo {
+ uint32_t w;
+ uint32_t h;
+ uint32_t s;
+ uint32_t usage;
+ PixelFormat format;
+ void* bits;
+ uint32_t reserved[2];
+ };
+
+ Surface(const Parcel& data);
+
+ static bool isValid(const sp<Surface>& surface) {
+ return (surface != 0) && surface->isValid();
+ }
+
+ static bool isSameSurface(
+ const sp<Surface>& lhs, const sp<Surface>& rhs);
+
+ bool isValid();
+ SurfaceID ID() const { return mToken; }
+ uint32_t getFlags() const { return mFlags; }
+ uint32_t getIdentity() const { return mIdentity; }
+
+ // the lock/unlock APIs must be used from the same thread
+ status_t lock(SurfaceInfo* info, bool blocking = true);
+ status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
+ status_t unlockAndPost();
- // this locks protects calls to lockSurface() / unlockSurface()
- // and is called by SurfaceComposerClient.
- Mutex& getLock() const { return mSurfaceLock; }
+ // setSwapRectangle() is intended to be used by GL ES clients
+ void setSwapRectangle(const Rect& r);
+
+private:
+ // can't be copied
+ Surface& operator = (Surface& rhs);
+ Surface(const Surface& rhs);
+
+ Surface(const sp<SurfaceControl>& control);
+ void init();
+ ~Surface();
+
+ friend class SurfaceComposerClient;
+ friend class SurfaceControl;
+
+
+ // camera and camcorder need access to the ISurface binder interface for preview
+ friend class Camera;
+ friend class MediaRecorder;
+ // mediaplayer needs access to ISurface for display
+ friend class MediaPlayer;
+ friend class IOMX;
+ // this is just to be able to write some unit tests
+ friend class Test;
+ sp<SurfaceComposerClient> getClient() const;
+ sp<ISurface> getISurface() const;
+
+ status_t getBufferLocked(int index, int usage);
+
+ status_t validate(per_client_cblk_t const* cblk) const;
+ static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty);
+
+ inline const BufferMapper& getBufferMapper() const { return mBufferMapper; }
+ inline BufferMapper& getBufferMapper() { return mBufferMapper; }
+
+ static int setSwapInterval(android_native_window_t* window, int interval);
+ static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
+ static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+ static int query(android_native_window_t* window, int what, int* value);
+ static int perform(android_native_window_t* window, int operation, ...);
+
+ int dequeueBuffer(android_native_buffer_t** buffer);
+ int lockBuffer(android_native_buffer_t* buffer);
+ int queueBuffer(android_native_buffer_t* buffer);
+ int query(int what, int* value);
+ int perform(int operation, va_list args);
+
+ status_t dequeueBuffer(sp<SurfaceBuffer>* buffer);
+ status_t lockBuffer(const sp<SurfaceBuffer>& buffer);
+ status_t queueBuffer(const sp<SurfaceBuffer>& buffer);
+
+
+ void setUsage(uint32_t reqUsage);
+
+ // constants
sp<SurfaceComposerClient> mClient;
sp<ISurface> mSurface;
- sp<IMemoryHeap> mHeap[2];
SurfaceID mToken;
uint32_t mIdentity;
PixelFormat mFormat;
uint32_t mFlags;
- const bool mOwner;
- mutable void* mSurfaceHeapBase[2];
+ BufferMapper& mBufferMapper;
+
+ // protected by mSurfaceLock
+ Rect mSwapRectangle;
+ uint32_t mUsage;
+ bool mUsageChanged;
+
+ // protected by mSurfaceLock. These are also used from lock/unlock
+ // but in that case, they must be called form the same thread.
+ sp<SurfaceBuffer> mBuffers[2];
mutable Region mDirtyRegion;
- mutable Rect mSwapRectangle;
mutable uint8_t mBackbufferIndex;
+
+ // must be used from the lock/unlock thread
+ sp<SurfaceBuffer> mLockedBuffer;
+ mutable Region mOldDirtyRegion;
+
+ // query() must be called from dequeueBuffer() thread
+ uint32_t mWidth;
+ uint32_t mHeight;
+
+ // Inherently thread-safe
mutable Mutex mSurfaceLock;
};
diff --git a/include/ui/SurfaceComposerClient.h b/include/ui/SurfaceComposerClient.h
index 76a3b55..286f885 100644
--- a/include/ui/SurfaceComposerClient.h
+++ b/include/ui/SurfaceComposerClient.h
@@ -62,7 +62,7 @@ public:
// surface creation / destruction
//! Create a surface
- sp<Surface> createSurface(
+ sp<SurfaceControl> createSurface(
int pid, //!< pid of the process the surfacec is for
DisplayID display, //!< Display to create this surface on
uint32_t w, //!< width in pixel
@@ -111,51 +111,35 @@ public:
private:
friend class Surface;
+ friend class SurfaceControl;
SurfaceComposerClient(const sp<ISurfaceComposer>& sm,
const sp<IBinder>& conn);
- status_t hide(Surface* surface);
- status_t show(Surface* surface, int32_t layer = -1);
- status_t freeze(Surface* surface);
- status_t unfreeze(Surface* surface);
- status_t setFlags(Surface* surface, uint32_t flags, uint32_t mask);
- status_t setTransparentRegionHint(Surface* surface, const Region& transparent);
- status_t setLayer(Surface* surface, int32_t layer);
- status_t setAlpha(Surface* surface, float alpha=1.0f);
- status_t setFreezeTint(Surface* surface, uint32_t tint);
- status_t setMatrix(Surface* surface, float dsdx, float dtdx, float dsdy, float dtdy);
- status_t setPosition(Surface* surface, int32_t x, int32_t y);
- status_t setSize(Surface* surface, uint32_t w, uint32_t h);
+ status_t hide(SurfaceID id);
+ status_t show(SurfaceID id, int32_t layer = -1);
+ status_t freeze(SurfaceID id);
+ status_t unfreeze(SurfaceID id);
+ status_t setFlags(SurfaceID id, uint32_t flags, uint32_t mask);
+ status_t setTransparentRegionHint(SurfaceID id, const Region& transparent);
+ status_t setLayer(SurfaceID id, int32_t layer);
+ status_t setAlpha(SurfaceID id, float alpha=1.0f);
+ status_t setFreezeTint(SurfaceID id, uint32_t tint);
+ status_t setMatrix(SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy);
+ status_t setPosition(SurfaceID id, int32_t x, int32_t y);
+ status_t setSize(SurfaceID id, uint32_t w, uint32_t h);
- //! Unlock the surface, and specify the dirty region if any
- status_t unlockAndPostSurface(Surface* surface);
- status_t unlockSurface(Surface* surface);
-
- status_t lockSurface(Surface* surface,
- Surface::SurfaceInfo* info,
- Region* dirty,
- bool blocking = true);
-
- status_t nextBuffer(Surface* surface,
- Surface::SurfaceInfo* info);
+ void signalServer();
status_t destroySurface(SurfaceID sid);
void _init(const sp<ISurfaceComposer>& sm,
const sp<ISurfaceFlingerClient>& conn);
- void _signal_server();
- static void _send_dirty_region(layer_cblk_t* lcblk, const Region& dirty);
- inline layer_state_t* _get_state_l(const sp<Surface>& surface);
- layer_state_t* _lockLayerState(const sp<Surface>& surface);
+ inline layer_state_t* _get_state_l(SurfaceID id);
+ layer_state_t* _lockLayerState(SurfaceID id);
inline void _unlockLayerState();
- status_t validateSurface(
- per_client_cblk_t const* cblk, Surface const * surface);
-
- void pinHeap(const sp<IMemoryHeap>& heap);
-
mutable Mutex mLock;
layer_state_t* mPrebuiltLayerState;
SortedVector<layer_state_t> mStates;
@@ -165,11 +149,8 @@ private:
// after assignment
status_t mStatus;
per_client_cblk_t* mControl;
- sp<IMemory> mControlMemory;
+ sp<IMemoryHeap> mControlMemory;
sp<ISurfaceFlingerClient> mClient;
- sp<IMemoryHeap> mSurfaceHeap;
- uint8_t* mSurfaceHeapBase;
- void* mGL;
SurfaceFlingerSynchro* mSignalServer;
};
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
new file mode 100644
index 0000000..3740db5
--- /dev/null
+++ b/include/ui/egl/android_natives.h
@@ -0,0 +1,263 @@
+/*
+ * 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_ANDROID_NATIVES_H
+#define ANDROID_ANDROID_NATIVES_H
+
+#include <sys/types.h>
+#include <string.h>
+
+#include <hardware/gralloc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
+ (((unsigned)(a)<<24)|((unsigned)(b)<<16)|((unsigned)(c)<<8)|(unsigned)(d))
+
+#define ANDROID_NATIVE_WINDOW_MAGIC \
+ ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
+
+#define ANDROID_NATIVE_BUFFER_MAGIC \
+ ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
+
+// ---------------------------------------------------------------------------
+
+struct android_native_buffer_t;
+
+// ---------------------------------------------------------------------------
+
+typedef struct android_native_base_t
+{
+ /* a magic value defined by the actual EGL native type */
+ int magic;
+
+ /* the sizeof() of the actual EGL native type */
+ int version;
+
+ void* reserved[4];
+
+ /* reference-counting interface */
+ void (*incRef)(struct android_native_base_t* base);
+ void (*decRef)(struct android_native_base_t* base);
+} android_native_base_t;
+
+// ---------------------------------------------------------------------------
+
+/* attributes queriable with query() */
+enum {
+ NATIVE_WINDOW_WIDTH = 0,
+ NATIVE_WINDOW_HEIGHT = 1,
+ NATIVE_WINDOW_FORMAT = 2,
+};
+
+/* valid operations for the (*perform)() hook */
+enum {
+ NATIVE_WINDOW_SET_USAGE = 0
+};
+
+typedef struct android_native_window_t
+{
+#ifdef __cplusplus
+ android_native_window_t()
+ : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
+ {
+ common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
+ common.version = sizeof(android_native_window_t);
+ memset(common.reserved, 0, sizeof(common.reserved));
+ }
+#endif
+
+ struct android_native_base_t common;
+
+ /* flags describing some attributes of this surface or its updater */
+ const uint32_t flags;
+
+ /* min swap interval supported by this updated */
+ const int minSwapInterval;
+
+ /* max swap interval supported by this updated */
+ const int maxSwapInterval;
+
+ /* horizontal and vertical resolution in DPI */
+ const float xdpi;
+ const float ydpi;
+
+ /* Some storage reserved for the OEM's driver. */
+ intptr_t oem[4];
+
+
+ /*
+ * Set the swap interval for this surface.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*setSwapInterval)(struct android_native_window_t* window,
+ int interval);
+
+ /*
+ * hook called by EGL to acquire a buffer. After this call, the buffer
+ * is not locked, so its content cannot be modified.
+ * this call may block if no buffers are available.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*dequeueBuffer)(struct android_native_window_t* window,
+ struct android_native_buffer_t** buffer);
+
+ /*
+ * hook called by EGL to lock a buffer. This MUST be called before modifying
+ * the content of a buffer. The buffer must have been acquired with
+ * dequeueBuffer first.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*lockBuffer)(struct android_native_window_t* window,
+ struct android_native_buffer_t* buffer);
+ /*
+ * hook called by EGL when modifications to the render buffer are done.
+ * This unlocks and post the buffer.
+ *
+ * Buffers MUST be queued in the same order than they were dequeued.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*queueBuffer)(struct android_native_window_t* window,
+ struct android_native_buffer_t* buffer);
+
+ /*
+ * hook used to retrieve information about the native window.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*query)(struct android_native_window_t* window,
+ int what, int* value);
+
+ /*
+ * hook used to perform various operations on the surface.
+ * (*perform)() is a generic mechanism to add functionality to
+ * android_native_window_t while keeping backward binary compatibility.
+ *
+ * This hook should not be called directly, instead use the helper functions
+ * defined below.
+ *
+ * The valid operations are:
+ * NATIVE_WINDOW_SET_USAGE
+ *
+ */
+
+ int (*perform)(struct android_native_window_t* window,
+ int operation, ... );
+
+ void* reserved_proc[3];
+} android_native_window_t;
+
+
+/*
+ * native_window_set_usage() sets the intended usage flags for the next
+ * buffers acquired with (*lockBuffer)() and on.
+ * By default (if this function is never called), a usage of
+ * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
+ * is assumed.
+ * Calling this function will usually cause following buffers to be
+ * reallocated.
+ */
+
+static inline int native_window_set_usage(
+ android_native_window_t* window, int usage)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
+}
+
+
+// ---------------------------------------------------------------------------
+
+/* FIXME: this is legacy for pixmaps */
+typedef struct egl_native_pixmap_t
+{
+ int32_t version; /* must be 32 */
+ int32_t width;
+ int32_t height;
+ int32_t stride;
+ uint8_t* data;
+ uint8_t format;
+ uint8_t rfu[3];
+ union {
+ uint32_t compressedFormat;
+ int32_t vstride;
+ };
+ int32_t reserved;
+} egl_native_pixmap_t;
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+/*
+ * This helper class turns an EGL android_native_xxx type into a C++
+ * reference-counted object; with proper type conversions.
+ */
+template <typename NATIVE_TYPE, typename TYPE, typename REF>
+class EGLNativeBase : public NATIVE_TYPE, public REF
+{
+protected:
+ typedef EGLNativeBase<NATIVE_TYPE, TYPE, REF> BASE;
+ EGLNativeBase() : NATIVE_TYPE(), REF() {
+ NATIVE_TYPE::common.incRef = incRef;
+ NATIVE_TYPE::common.decRef = decRef;
+ }
+ static inline TYPE* getSelf(NATIVE_TYPE* self) {
+ return static_cast<TYPE*>(self);
+ }
+ static inline TYPE const* getSelf(NATIVE_TYPE const* self) {
+ return static_cast<TYPE const *>(self);
+ }
+ static inline TYPE* getSelf(android_native_base_t* base) {
+ return getSelf(reinterpret_cast<NATIVE_TYPE*>(base));
+ }
+ static inline TYPE const * getSelf(android_native_base_t const* base) {
+ return getSelf(reinterpret_cast<NATIVE_TYPE const*>(base));
+ }
+ static void incRef(android_native_base_t* base) {
+ EGLNativeBase* self = getSelf(base);
+ self->incStrong(self);
+ }
+ static void decRef(android_native_base_t* base) {
+ EGLNativeBase* self = getSelf(base);
+ self->decStrong(self);
+ }
+};
+
+} // namespace android
+#endif // __cplusplus
+
+/*****************************************************************************/
+
+#endif /* ANDROID_ANDROID_NATIVES_H */
diff --git a/include/utils.h b/include/utils.h
deleted file mode 100644
index 30648b1..0000000
--- a/include/utils.h
+++ /dev/null
@@ -1,33 +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.
- */
-
-//
-// 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
-
-#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
diff --git a/include/utils/Binder.h b/include/utils/Binder.h
deleted file mode 100644
index b5b8d98..0000000
--- a/include/utils/Binder.h
+++ /dev/null
@@ -1,103 +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 ANDROID_BINDER_H
-#define ANDROID_BINDER_H
-
-#include <utils/IBinder.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class BBinder : public IBinder
-{
-public:
- BBinder();
-
- virtual String16 getInterfaceDescriptor() const;
- virtual bool isBinderAlive() const;
- virtual status_t pingBinder();
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- virtual status_t transact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-
- virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0);
-
- virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0,
- wp<DeathRecipient>* outRecipient = NULL);
-
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func);
- virtual void* findObject(const void* objectID) const;
- virtual void detachObject(const void* objectID);
-
- virtual BBinder* localBinder();
-
-protected:
- virtual ~BBinder();
-
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-
-private:
- BBinder(const BBinder& o);
- BBinder& operator=(const BBinder& o);
-
- class Extras;
-
- Extras* mExtras;
- void* mReserved0;
-};
-
-// ---------------------------------------------------------------------------
-
-class BpRefBase : public virtual RefBase
-{
-protected:
- BpRefBase(const sp<IBinder>& o);
- virtual ~BpRefBase();
- virtual void onFirstRef();
- virtual void onLastStrongRef(const void* id);
- virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
-
- inline IBinder* remote() { return mRemote; }
- inline IBinder* remote() const { return mRemote; }
-
-private:
- BpRefBase(const BpRefBase& o);
- BpRefBase& operator=(const BpRefBase& o);
-
- IBinder* const mRemote;
- RefBase::weakref_type* mRefs;
- volatile int32_t mState;
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_BINDER_H
diff --git a/include/utils/BpBinder.h b/include/utils/BpBinder.h
deleted file mode 100644
index 7b96e29..0000000
--- a/include/utils/BpBinder.h
+++ /dev/null
@@ -1,122 +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.
- */
-
-#ifndef ANDROID_BPBINDER_H
-#define ANDROID_BPBINDER_H
-
-#include <utils/IBinder.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class BpBinder : public IBinder
-{
-public:
- BpBinder(int32_t handle);
-
- inline int32_t handle() const { return mHandle; }
-
- virtual String16 getInterfaceDescriptor() const;
- virtual bool isBinderAlive() const;
- virtual status_t pingBinder();
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- virtual status_t transact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-
- virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0);
- virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0,
- wp<DeathRecipient>* outRecipient = NULL);
-
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func);
- virtual void* findObject(const void* objectID) const;
- virtual void detachObject(const void* objectID);
-
- virtual BpBinder* remoteBinder();
-
- status_t setConstantData(const void* data, size_t size);
- void sendObituary();
-
- class ObjectManager
- {
- public:
- ObjectManager();
- ~ObjectManager();
-
- void attach( const void* objectID,
- void* object,
- void* cleanupCookie,
- IBinder::object_cleanup_func func);
- void* find(const void* objectID) const;
- void detach(const void* objectID);
-
- void kill();
-
- private:
- ObjectManager(const ObjectManager&);
- ObjectManager& operator=(const ObjectManager&);
-
- struct entry_t
- {
- void* object;
- void* cleanupCookie;
- IBinder::object_cleanup_func func;
- };
-
- KeyedVector<const void*, entry_t> mObjects;
- };
-
-protected:
- virtual ~BpBinder();
- virtual void onFirstRef();
- virtual void onLastStrongRef(const void* id);
- virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
-
-private:
- const int32_t mHandle;
-
- struct Obituary {
- wp<DeathRecipient> recipient;
- void* cookie;
- uint32_t flags;
- };
-
- void reportOneDeath(const Obituary& obit);
-
- mutable Mutex mLock;
- volatile int32_t mAlive;
- volatile int32_t mObitsSent;
- Vector<Obituary>* mObituaries;
- ObjectManager mObjects;
- Parcel* mConstantData;
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_BPBINDER_H
diff --git a/include/utils/Debug.h b/include/utils/Debug.h
index a662b9c..d9ed32d 100644
--- a/include/utils/Debug.h
+++ b/include/utils/Debug.h
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-//
-// Debugging tools. These should be able to be stripped
-// in release builds.
-//
#ifndef ANDROID_DEBUG_H
#define ANDROID_DEBUG_H
@@ -25,9 +21,32 @@
#include <sys/types.h>
namespace android {
+// ---------------------------------------------------------------------------
+#ifdef __cplusplus
template<bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true> {};
+#define COMPILE_TIME_ASSERT(_exp) \
+ template class CompileTimeAssert< (_exp) >;
+#endif
+#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE(_exp) \
+ CompileTimeAssert<( _exp )>();
+
+// ---------------------------------------------------------------------------
+
+#ifdef __cplusplus
+template<bool C, typename LSH, typename RHS> struct CompileTimeIfElse;
+template<typename LHS, typename RHS>
+struct CompileTimeIfElse<true, LHS, RHS> { typedef LHS TYPE; };
+template<typename LHS, typename RHS>
+struct CompileTimeIfElse<false, LHS, RHS> { typedef RHS TYPE; };
+#endif
+
+// ---------------------------------------------------------------------------
+
+#ifdef __cplusplus
+extern "C" {
+#endif
const char* stringForIndent(int32_t indentLevel);
@@ -35,11 +54,17 @@ typedef void (*debugPrintFunc)(void* cookie, const char* txt);
void printTypeCode(uint32_t typeCode,
debugPrintFunc func = 0, void* cookie = 0);
+
void printHexData(int32_t indent, const void *buf, size_t length,
size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16,
size_t alignment=0, bool cArrayStyle=false,
debugPrintFunc func = 0, void* cookie = 0);
+#ifdef __cplusplus
+}
+#endif
+
+// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_DEBUG_H
diff --git a/include/utils/IBinder.h b/include/utils/IBinder.h
deleted file mode 100644
index 7370330..0000000
--- a/include/utils/IBinder.h
+++ /dev/null
@@ -1,159 +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 ANDROID_IBINDER_H
-#define ANDROID_IBINDER_H
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-
-#define B_PACK_CHARS(c1, c2, c3, c4) \
- ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class BBinder;
-class BpBinder;
-class IInterface;
-class Parcel;
-
-/**
- * Base class and low-level protocol for a remotable object.
- * You can derive from this class to create an object for which other
- * processes can hold references to it. Communication between processes
- * (method calls, property get and set) is down through a low-level
- * protocol implemented on top of the transact() API.
- */
-class IBinder : public virtual RefBase
-{
-public:
- enum {
- FIRST_CALL_TRANSACTION = 0x00000001,
- LAST_CALL_TRANSACTION = 0x00ffffff,
-
- PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'),
- DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'),
- INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
-
- // Corresponds to tfOneWay -- an asynchronous call.
- FLAG_ONEWAY = 0x00000001
- };
-
- inline IBinder() { }
-
- /**
- * Check if this IBinder implements the interface named by
- * @a descriptor. If it does, the base pointer to it is returned,
- * which you can safely static_cast<> to the concrete C++ interface.
- */
- virtual sp<IInterface> queryLocalInterface(const String16& descriptor);
-
- /**
- * Return the canonical name of the interface provided by this IBinder
- * object.
- */
- virtual String16 getInterfaceDescriptor() const = 0;
-
- virtual bool isBinderAlive() const = 0;
- virtual status_t pingBinder() = 0;
- virtual status_t dump(int fd, const Vector<String16>& args) = 0;
-
- virtual status_t transact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0) = 0;
-
- /**
- * This method allows you to add data that is transported through
- * IPC along with your IBinder pointer. When implementing a Binder
- * object, override it to write your desired data in to @a outData.
- * You can then call getConstantData() on your IBinder to retrieve
- * that data, from any process. You MUST return the number of bytes
- * written in to the parcel (including padding).
- */
- class DeathRecipient : public virtual RefBase
- {
- public:
- virtual void binderDied(const wp<IBinder>& who) = 0;
- };
-
- /**
- * Register the @a recipient for a notification if this binder
- * goes away. If this binder object unexpectedly goes away
- * (typically because its hosting process has been killed),
- * then DeathRecipient::binderDied() will be called with a referene
- * to this.
- *
- * The @a cookie is optional -- if non-NULL, it should be a
- * memory address that you own (that is, you know it is unique).
- *
- * @note You will only receive death notifications for remote binders,
- * as local binders by definition can't die without you dying as well.
- * Trying to use this function on a local binder will result in an
- * INVALID_OPERATION code being returned and nothing happening.
- *
- * @note This link always holds a weak reference to its recipient.
- *
- * @note You will only receive a weak reference to the dead
- * binder. You should not try to promote this to a strong reference.
- * (Nor should you need to, as there is nothing useful you can
- * directly do with it now that it has passed on.)
- */
- virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0) = 0;
-
- /**
- * Remove a previously registered death notification.
- * The @a recipient will no longer be called if this object
- * dies. The @a cookie is optional. If non-NULL, you can
- * supply a NULL @a recipient, and the recipient previously
- * added with that cookie will be unlinked.
- */
- virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
- void* cookie = NULL,
- uint32_t flags = 0,
- wp<DeathRecipient>* outRecipient = NULL) = 0;
-
- virtual bool checkSubclass(const void* subclassID) const;
-
- typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
-
- virtual void attachObject( const void* objectID,
- void* object,
- void* cleanupCookie,
- object_cleanup_func func) = 0;
- virtual void* findObject(const void* objectID) const = 0;
- virtual void detachObject(const void* objectID) = 0;
-
- virtual BBinder* localBinder();
- virtual BpBinder* remoteBinder();
-
-protected:
- inline virtual ~IBinder() { }
-
-private:
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_IBINDER_H
diff --git a/include/utils/IInterface.h b/include/utils/IInterface.h
deleted file mode 100644
index 959722a..0000000
--- a/include/utils/IInterface.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.
- */
-
-//
-#ifndef ANDROID_IINTERFACE_H
-#define ANDROID_IINTERFACE_H
-
-#include <utils/Binder.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IInterface : public virtual RefBase
-{
-public:
- sp<IBinder> asBinder();
- sp<const IBinder> asBinder() const;
-
-protected:
- virtual IBinder* onAsBinder() = 0;
-};
-
-// ----------------------------------------------------------------------
-
-template<typename INTERFACE>
-inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
-{
- return INTERFACE::asInterface(obj);
-}
-
-// ----------------------------------------------------------------------
-
-template<typename INTERFACE>
-class BnInterface : public INTERFACE, public BBinder
-{
-public:
- virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
- virtual String16 getInterfaceDescriptor() const;
-
-protected:
- virtual IBinder* onAsBinder();
-};
-
-// ----------------------------------------------------------------------
-
-template<typename INTERFACE>
-class BpInterface : public INTERFACE, public BpRefBase
-{
-public:
- BpInterface(const sp<IBinder>& remote);
-
-protected:
- virtual IBinder* onAsBinder();
-};
-
-// ----------------------------------------------------------------------
-
-#define DECLARE_META_INTERFACE(INTERFACE) \
- static const String16 descriptor; \
- static sp<I##INTERFACE> asInterface(const sp<IBinder>& obj); \
- virtual String16 getInterfaceDescriptor() const; \
-
-#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
- const String16 I##INTERFACE::descriptor(NAME); \
- String16 I##INTERFACE::getInterfaceDescriptor() const { \
- return I##INTERFACE::descriptor; \
- } \
- sp<I##INTERFACE> I##INTERFACE::asInterface(const sp<IBinder>& obj) \
- { \
- sp<I##INTERFACE> intr; \
- if (obj != NULL) { \
- intr = static_cast<I##INTERFACE*>( \
- obj->queryLocalInterface( \
- I##INTERFACE::descriptor).get()); \
- if (intr == NULL) { \
- intr = new Bp##INTERFACE(obj); \
- } \
- } \
- return intr; \
- } \
-
-// ----------------------------------------------------------------------
-// No user-servicable parts after this...
-
-template<typename INTERFACE>
-inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
- const String16& _descriptor)
-{
- if (_descriptor == INTERFACE::descriptor) return this;
- return NULL;
-}
-
-template<typename INTERFACE>
-inline String16 BnInterface<INTERFACE>::getInterfaceDescriptor() const
-{
- return INTERFACE::getInterfaceDescriptor();
-}
-
-template<typename INTERFACE>
-IBinder* BnInterface<INTERFACE>::onAsBinder()
-{
- return this;
-}
-
-template<typename INTERFACE>
-inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
- : BpRefBase(remote)
-{
-}
-
-template<typename INTERFACE>
-inline IBinder* BpInterface<INTERFACE>::onAsBinder()
-{
- return remote();
-}
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IINTERFACE_H
diff --git a/include/utils/IMemory.h b/include/utils/IMemory.h
deleted file mode 100644
index 35a3fd7..0000000
--- a/include/utils/IMemory.h
+++ /dev/null
@@ -1,94 +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_IMEMORY_H
-#define ANDROID_IMEMORY_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <utils/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IMemoryHeap : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(MemoryHeap);
-
- // flags returned by getFlags()
- enum {
- READ_ONLY = 0x00000001,
- MAP_ONCE = 0x00000002
- };
-
- virtual int getHeapID() const = 0;
- virtual void* getBase() const = 0;
- virtual size_t getSize() const = 0;
- virtual uint32_t getFlags() const = 0;
-
- // these are there just for backward source compatibility
- int32_t heapID() const { return getHeapID(); }
- void* base() const { return getBase(); }
- size_t virtualSize() const { return getSize(); }
-};
-
-class BnMemoryHeap : public BnInterface<IMemoryHeap>
-{
-public:
- virtual status_t onTransact(
- uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-class IMemory : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(Memory);
-
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
-
- // helpers
- void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
- void* pointer() const;
- size_t size() const;
- ssize_t offset() const;
-};
-
-class BnMemory : public BnInterface<IMemory>
-{
-public:
- virtual status_t onTransact(
- uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IMEMORY_H
diff --git a/include/utils/IPCThreadState.h b/include/utils/IPCThreadState.h
deleted file mode 100644
index 0490fd3..0000000
--- a/include/utils/IPCThreadState.h
+++ /dev/null
@@ -1,110 +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.
- */
-
-#ifndef ANDROID_IPC_THREAD_STATE_H
-#define ANDROID_IPC_THREAD_STATE_H
-
-#include <utils/Errors.h>
-#include <utils/Parcel.h>
-#include <utils/ProcessState.h>
-#include <utils/Vector.h>
-
-#ifdef HAVE_WIN32_PROC
-typedef int uid_t;
-#endif
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class IPCThreadState
-{
-public:
- static IPCThreadState* self();
-
- sp<ProcessState> process();
-
- status_t clearLastError();
-
- int getCallingPid();
- int getCallingUid();
-
- int64_t clearCallingIdentity();
- void restoreCallingIdentity(int64_t token);
-
- void flushCommands();
-
- void joinThreadPool(bool isMain = true);
-
- // Stop the local process.
- void stopProcess(bool immediate = true);
-
- status_t transact(int32_t handle,
- uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
-
- void incStrongHandle(int32_t handle);
- void decStrongHandle(int32_t handle);
- void incWeakHandle(int32_t handle);
- void decWeakHandle(int32_t handle);
- status_t attemptIncStrongHandle(int32_t handle);
- static void expungeHandle(int32_t handle, IBinder* binder);
- status_t requestDeathNotification( int32_t handle,
- BpBinder* proxy);
- status_t clearDeathNotification( int32_t handle,
- BpBinder* proxy);
-
- static void shutdown();
-
-private:
- IPCThreadState();
- ~IPCThreadState();
-
- status_t sendReply(const Parcel& reply, uint32_t flags);
- status_t waitForResponse(Parcel *reply,
- status_t *acquireResult=NULL);
- status_t talkWithDriver(bool doReceive=true);
- status_t writeTransactionData(int32_t cmd,
- uint32_t binderFlags,
- int32_t handle,
- uint32_t code,
- const Parcel& data,
- status_t* statusBuffer);
- status_t executeCommand(int32_t command);
-
- void clearCaller();
-
- static void threadDestructor(void *st);
- static void freeBuffer(Parcel* parcel,
- const uint8_t* data, size_t dataSize,
- const size_t* objects, size_t objectsSize,
- void* cookie);
-
- const sp<ProcessState> mProcess;
- Vector<BBinder*> mPendingStrongDerefs;
- Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-
- Parcel mIn;
- Parcel mOut;
- status_t mLastError;
- pid_t mCallingPid;
- uid_t mCallingUid;
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_IPC_THREAD_STATE_H
diff --git a/include/utils/IPermissionController.h b/include/utils/IPermissionController.h
deleted file mode 100644
index cb1dd34..0000000
--- a/include/utils/IPermissionController.h
+++ /dev/null
@@ -1,56 +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.
- */
-
-//
-#ifndef ANDROID_IPERMISSION_CONTROLLER_H
-#define ANDROID_IPERMISSION_CONTROLLER_H
-
-#include <utils/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IPermissionController : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(PermissionController);
-
- virtual bool checkPermission(const String16& permission,
- int32_t pid, int32_t uid) = 0;
-
- enum {
- CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
- };
-};
-
-// ----------------------------------------------------------------------
-
-class BnPermissionController : public BnInterface<IPermissionController>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IPERMISSION_CONTROLLER_H
-
diff --git a/include/utils/IServiceManager.h b/include/utils/IServiceManager.h
deleted file mode 100644
index e3d99fe..0000000
--- a/include/utils/IServiceManager.h
+++ /dev/null
@@ -1,98 +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.
- */
-
-//
-#ifndef ANDROID_ISERVICE_MANAGER_H
-#define ANDROID_ISERVICE_MANAGER_H
-
-#include <utils/IInterface.h>
-#include <utils/IPermissionController.h>
-#include <utils/Vector.h>
-#include <utils/String16.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IServiceManager : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(ServiceManager);
-
- /**
- * Retrieve an existing service, blocking for a few seconds
- * if it doesn't yet exist.
- */
- virtual sp<IBinder> getService( const String16& name) const = 0;
-
- /**
- * Retrieve an existing service, non-blocking.
- */
- virtual sp<IBinder> checkService( const String16& name) const = 0;
-
- /**
- * Register a service.
- */
- virtual status_t addService( const String16& name,
- const sp<IBinder>& service) = 0;
-
- /**
- * Return list of all existing services.
- */
- virtual Vector<String16> listServices() = 0;
-
- enum {
- GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
- CHECK_SERVICE_TRANSACTION,
- ADD_SERVICE_TRANSACTION,
- LIST_SERVICES_TRANSACTION,
- };
-};
-
-sp<IServiceManager> defaultServiceManager();
-
-template<typename INTERFACE>
-status_t getService(const String16& name, sp<INTERFACE>* outService)
-{
- const sp<IServiceManager> sm = defaultServiceManager();
- if (sm != NULL) {
- *outService = interface_cast<INTERFACE>(sm->getService(name));
- if ((*outService) != NULL) return NO_ERROR;
- }
- return NAME_NOT_FOUND;
-}
-
-bool checkCallingPermission(const String16& permission);
-bool checkCallingPermission(const String16& permission,
- int32_t* outPid, int32_t* outUid);
-
-// ----------------------------------------------------------------------
-
-class BnServiceManager : public BnInterface<IServiceManager>
-{
-public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_ISERVICE_MANAGER_H
-
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index f4513ee..6bcdea4 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -164,7 +164,7 @@ ssize_t KeyedVector<KEY,VALUE>::replaceValueFor(const KEY& key, const VALUE& val
template<typename KEY, typename VALUE> inline
ssize_t KeyedVector<KEY,VALUE>::replaceValueAt(size_t index, const VALUE& item) {
if (index<size()) {
- mVector.editValueAt(index).value = item;
+ mVector.editItemAt(index).value = item;
return index;
}
return BAD_INDEX;
diff --git a/include/utils/List.h b/include/utils/List.h
index 1a6be9a..403cd7f 100644
--- a/include/utils/List.h
+++ b/include/utils/List.h
@@ -22,147 +22,200 @@
// construction, so if the compiler's auto-generated versions won't work for
// you, define your own.
//
-// The only class you want to use from here is "List". Do not use classes
-// starting with "_" directly.
+// The only class you want to use from here is "List".
//
#ifndef _LIBS_UTILS_LIST_H
#define _LIBS_UTILS_LIST_H
-namespace android {
-
-/*
- * One element in the list.
- */
-template<class T> class _ListNode {
-public:
- typedef _ListNode<T> _Node;
-
- _ListNode(const T& val) : mVal(val) {}
- ~_ListNode(void) {}
-
- T& getRef(void) { return mVal; }
- void setVal(const T& val) { mVal = val; }
+#include <stddef.h>
+#include <stdint.h>
- _Node* getPrev(void) const { return mpPrev; }
- void setPrev(_Node* ptr) { mpPrev = ptr; }
- _Node* getNext(void) const { return mpNext; }
- void setNext(_Node* ptr) { mpNext = ptr; }
-
-private:
- T mVal;
- _Node* mpPrev;
- _Node* mpNext;
-};
+namespace android {
/*
- * Iterator for walking through the list.
+ * Doubly-linked list. Instantiate with "List<MyClass> myList".
+ *
+ * Objects added to the list are copied using the assignment operator,
+ * so this must be defined.
*/
-template<class T, class Tref> class _ListIterator {
-public:
- typedef _ListIterator<T,Tref> _Iter;
- typedef _ListNode<T> _Node;
-
- _ListIterator(void) {}
- _ListIterator(_Node* ptr) : mpNode(ptr) {}
- ~_ListIterator(void) {}
-
- /*
- * Dereference operator. Used to get at the juicy insides.
- */
- Tref operator*() const { return mpNode->getRef(); }
-
+template<typename T>
+class List
+{
+protected:
/*
- * Iterator comparison.
+ * One element in the list.
*/
- bool operator==(const _Iter& right) const { return mpNode == right.mpNode; }
- bool operator!=(const _Iter& right) const { return mpNode != right.mpNode; }
+ class _Node {
+ public:
+ explicit _Node(const T& val) : mVal(val) {}
+ ~_Node() {}
+ inline T& getRef() { return mVal; }
+ inline const T& getRef() const { return mVal; }
+ inline _Node* getPrev() const { return mpPrev; }
+ inline _Node* getNext() const { return mpNext; }
+ inline void setVal(const T& val) { mVal = val; }
+ inline void setPrev(_Node* ptr) { mpPrev = ptr; }
+ inline void setNext(_Node* ptr) { mpNext = ptr; }
+ private:
+ friend class List;
+ friend class _ListIterator;
+ T mVal;
+ _Node* mpPrev;
+ _Node* mpNext;
+ };
/*
- * Incr/decr, used to move through the list.
+ * Iterator for walking through the list.
*/
- _Iter& operator++(void) { // pre-increment
- mpNode = mpNode->getNext();
- return *this;
- }
- _Iter operator++(int) { // post-increment
- _Iter tmp = *this;
- ++*this;
- return tmp;
- }
- _Iter& operator--(void) { // pre-increment
- mpNode = mpNode->getPrev();
- return *this;
- }
- _Iter operator--(int) { // post-increment
- _Iter tmp = *this;
- --*this;
- return tmp;
- }
+
+ template <typename TYPE>
+ struct CONST_ITERATOR {
+ typedef _Node const * NodePtr;
+ typedef const TYPE Type;
+ };
+
+ template <typename TYPE>
+ struct NON_CONST_ITERATOR {
+ typedef _Node* NodePtr;
+ typedef TYPE Type;
+ };
+
+ template<
+ typename U,
+ template <class> class Constness
+ >
+ class _ListIterator {
+ typedef _ListIterator<U, Constness> _Iter;
+ typedef typename Constness<U>::NodePtr _NodePtr;
+ typedef typename Constness<U>::Type _Type;
+
+ explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
+
+ public:
+ _ListIterator() {}
+ _ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {}
+ ~_ListIterator() {}
+
+ // this will handle conversions from iterator to const_iterator
+ // (and also all convertible iterators)
+ // Here, in this implementation, the iterators can be converted
+ // if the nodes can be converted
+ template<typename V> explicit
+ _ListIterator(const V& rhs) : mpNode(rhs.mpNode) {}
+
+
+ /*
+ * Dereference operator. Used to get at the juicy insides.
+ */
+ _Type& operator*() const { return mpNode->getRef(); }
+ _Type* operator->() const { return &(mpNode->getRef()); }
+
+ /*
+ * Iterator comparison.
+ */
+ inline bool operator==(const _Iter& right) const {
+ return mpNode == right.mpNode; }
+
+ inline bool operator!=(const _Iter& right) const {
+ return mpNode != right.mpNode; }
+
+ /*
+ * handle comparisons between iterator and const_iterator
+ */
+ template<typename OTHER>
+ inline bool operator==(const OTHER& right) const {
+ return mpNode == right.mpNode; }
+
+ template<typename OTHER>
+ inline bool operator!=(const OTHER& right) const {
+ return mpNode != right.mpNode; }
+
+ /*
+ * Incr/decr, used to move through the list.
+ */
+ inline _Iter& operator++() { // pre-increment
+ mpNode = mpNode->getNext();
+ return *this;
+ }
+ const _Iter operator++(int) { // post-increment
+ _Iter tmp(*this);
+ mpNode = mpNode->getNext();
+ return tmp;
+ }
+ inline _Iter& operator--() { // pre-increment
+ mpNode = mpNode->getPrev();
+ return *this;
+ }
+ const _Iter operator--(int) { // post-increment
+ _Iter tmp(*this);
+ mpNode = mpNode->getPrev();
+ return tmp;
+ }
- _Node* getNode(void) const { return mpNode; }
+ inline _NodePtr getNode() const { return mpNode; }
-private:
- _Node* mpNode;
-};
+ _NodePtr mpNode; /* should be private, but older gcc fails */
+ private:
+ friend class List;
+ };
-
-/*
- * Doubly-linked list. Instantiate with "List<MyClass> myList".
- *
- * Objects added to the list are copied using the assignment operator,
- * so this must be defined.
- */
-template<class T> class List {
public:
- typedef _ListNode<T> _Node;
-
- List(void) {
+ List() {
prep();
}
List(const List<T>& src) { // copy-constructor
prep();
insert(begin(), src.begin(), src.end());
}
- virtual ~List(void) {
+ virtual ~List() {
clear();
delete[] (unsigned char*) mpMiddle;
}
- typedef _ListIterator<T,T&> iterator;
- typedef _ListIterator<T, const T&> const_iterator;
+ typedef _ListIterator<T, NON_CONST_ITERATOR> iterator;
+ typedef _ListIterator<T, CONST_ITERATOR> const_iterator;
List<T>& operator=(const List<T>& right);
/* returns true if the list is empty */
- bool empty(void) const { return mpMiddle->getNext() == mpMiddle; }
+ inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
/* return #of elements in list */
- unsigned int size(void) const {
- return distance(begin(), end());
+ size_t size() const {
+ return size_t(distance(begin(), end()));
}
/*
* Return the first element or one past the last element. The
- * _ListNode* we're returning is converted to an "iterator" by a
+ * _Node* we're returning is converted to an "iterator" by a
* constructor in _ListIterator.
*/
- iterator begin() { return mpMiddle->getNext(); }
- const_iterator begin() const { return mpMiddle->getNext(); }
- iterator end() { return mpMiddle; }
- const_iterator end() const { return mpMiddle; }
+ inline iterator begin() {
+ return iterator(mpMiddle->getNext());
+ }
+ inline const_iterator begin() const {
+ return const_iterator(const_cast<_Node const*>(mpMiddle->getNext()));
+ }
+ inline iterator end() {
+ return iterator(mpMiddle);
+ }
+ inline const_iterator end() const {
+ return const_iterator(const_cast<_Node const*>(mpMiddle));
+ }
/* add the object to the head or tail of the list */
void push_front(const T& val) { insert(begin(), val); }
void push_back(const T& val) { insert(end(), val); }
/* insert before the current node; returns iterator at new node */
- iterator insert(iterator posn, const T& val) {
+ iterator insert(iterator posn, const T& val)
+ {
_Node* newNode = new _Node(val); // alloc & copy-construct
newNode->setNext(posn.getNode());
newNode->setPrev(posn.getNode()->getPrev());
posn.getNode()->getPrev()->setNext(newNode);
posn.getNode()->setPrev(newNode);
- return newNode;
+ return iterator(newNode);
}
/* insert a range of elements before the current node */
@@ -178,18 +231,18 @@ public:
pPrev->setNext(pNext);
pNext->setPrev(pPrev);
delete posn.getNode();
- return pNext;
+ return iterator(pNext);
}
/* remove a range of elements */
iterator erase(iterator first, iterator last) {
while (first != last)
erase(first++); // don't erase than incr later!
- return last;
+ return iterator(last);
}
/* remove all contents of the list */
- void clear(void) {
+ void clear() {
_Node* pCurrent = mpMiddle->getNext();
_Node* pNext;
@@ -207,21 +260,20 @@ public:
* will be equal to "last". The iterators must refer to the same
* list.
*
- * (This is actually a generic iterator function. It should be part
- * of some other class, possibly an iterator base class. It needs to
- * know the difference between a list, which has to march through,
- * and a vector, which can just do pointer math.)
+ * FIXME: This is actually a generic iterator function. It should be a
+ * template function at the top-level with specializations for things like
+ * vector<>, which can just do pointer math). Here we limit it to
+ * _ListIterator of the same type but different constness.
*/
- unsigned int distance(iterator first, iterator last) {
- unsigned int count = 0;
- while (first != last) {
- ++first;
- ++count;
- }
- return count;
- }
- unsigned int distance(const_iterator first, const_iterator last) const {
- unsigned int count = 0;
+ template<
+ typename U,
+ template <class> class CL,
+ template <class> class CR
+ >
+ ptrdiff_t distance(
+ _ListIterator<U, CL> first, _ListIterator<U, CR> last) const
+ {
+ ptrdiff_t count = 0;
while (first != last) {
++first;
++count;
@@ -231,12 +283,12 @@ public:
private:
/*
- * I want a _ListNode but don't need it to hold valid data. More
+ * I want a _Node but don't need it to hold valid data. More
* to the point, I don't want T's constructor to fire, since it
* might have side-effects or require arguments. So, we do this
* slightly uncouth storage alloc.
*/
- void prep(void) {
+ void prep() {
mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
mpMiddle->setPrev(mpMiddle);
mpMiddle->setNext(mpMiddle);
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/MemoryBase.h b/include/utils/MemoryBase.h
deleted file mode 100644
index eb5a9d2..0000000
--- a/include/utils/MemoryBase.h
+++ /dev/null
@@ -1,51 +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 ANDROID_MEMORY_BASE_H
-#define ANDROID_MEMORY_BASE_H
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <utils/IMemory.h>
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class MemoryBase : public BnMemory
-{
-public:
- MemoryBase(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
- virtual ~MemoryBase();
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
-
-protected:
- size_t getSize() const { return mSize; }
- ssize_t getOffset() const { return mOffset; }
- const sp<IMemoryHeap>& getHeap() const { return mHeap; }
-
-private:
- size_t mSize;
- ssize_t mOffset;
- sp<IMemoryHeap> mHeap;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_MEMORY_BASE_H
diff --git a/include/utils/MemoryDealer.h b/include/utils/MemoryDealer.h
deleted file mode 100644
index 454b627..0000000
--- a/include/utils/MemoryDealer.h
+++ /dev/null
@@ -1,238 +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_MEMORY_DEALER_H
-#define ANDROID_MEMORY_DEALER_H
-
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/IMemory.h>
-#include <utils/threads.h>
-#include <utils/MemoryHeapBase.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-class String8;
-
-/*
- * interface for implementing a "heap". A heap basically provides
- * the IMemoryHeap interface for cross-process sharing and the
- * ability to map/unmap pages within the heap.
- */
-class HeapInterface : public virtual BnMemoryHeap
-{
-public:
- // all values must be page-aligned
- virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-/*
- * interface for implementing an allocator. An allocator provides
- * methods for allocating and freeing memory blocks and dumping
- * its state.
- */
-class AllocatorInterface : public RefBase
-{
-public:
- enum {
- PAGE_ALIGNED = 0x00000001
- };
-
- virtual size_t allocate(size_t size, uint32_t flags = 0) = 0;
- virtual status_t deallocate(size_t offset) = 0;
- virtual size_t size() const = 0;
- 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;
-};
-
-// ----------------------------------------------------------------------------
-
-/*
- * concrete implementation of HeapInterface on top of mmap()
- */
-class SharedHeap : public HeapInterface, public MemoryHeapBase
-{
-public:
- SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL);
- virtual ~SharedHeap();
- virtual sp<IMemory> mapMemory(size_t offset, size_t size);
-};
-
-// ----------------------------------------------------------------------------
-
-/*
- * A simple templatized doubly linked-list implementation
- */
-
-template <typename NODE>
-class LinkedList
-{
- NODE* mFirst;
- NODE* mLast;
-
-public:
- LinkedList() : mFirst(0), mLast(0) { }
- bool isEmpty() const { return mFirst == 0; }
- NODE const* head() const { return mFirst; }
- NODE* head() { return mFirst; }
- NODE const* tail() const { return mLast; }
- NODE* tail() { return mLast; }
-
- void insertAfter(NODE* node, NODE* newNode) {
- newNode->prev = node;
- newNode->next = node->next;
- if (node->next == 0) mLast = newNode;
- else node->next->prev = newNode;
- node->next = newNode;
- }
-
- void insertBefore(NODE* node, NODE* newNode) {
- newNode->prev = node->prev;
- newNode->next = node;
- if (node->prev == 0) mFirst = newNode;
- else node->prev->next = newNode;
- node->prev = newNode;
- }
-
- void insertHead(NODE* newNode) {
- if (mFirst == 0) {
- mFirst = mLast = newNode;
- newNode->prev = newNode->next = 0;
- } else {
- insertBefore(mFirst, newNode);
- }
- }
-
- void insertTail(NODE* newNode) {
- if (mLast == 0) insertBeginning(newNode);
- else insertAfter(mLast, newNode);
- }
-
- NODE* remove(NODE* node) {
- if (node->prev == 0) mFirst = node->next;
- else node->prev->next = node->next;
- if (node->next == 0) mLast = node->prev;
- else node->next->prev = node->prev;
- return node;
- }
-};
-
-
-/*
- * concrete implementation of AllocatorInterface using a simple
- * best-fit allocation scheme
- */
-class SimpleBestFitAllocator : public AllocatorInterface
-{
-public:
-
- SimpleBestFitAllocator(size_t size);
- virtual ~SimpleBestFitAllocator();
-
- virtual size_t allocate(size_t size, uint32_t flags = 0);
- virtual status_t deallocate(size_t offset);
- virtual size_t size() const;
- virtual void dump(const char* what, uint32_t flags = 0) const;
- virtual void dump(String8& res,
- const char* what, uint32_t flags = 0) const;
-
-private:
-
- struct chunk_t {
- chunk_t(size_t start, size_t size)
- : start(start), size(size), free(1), prev(0), next(0) {
- }
- size_t start;
- size_t size : 28;
- int free : 4;
- mutable chunk_t* prev;
- mutable chunk_t* next;
- };
-
- ssize_t alloc(size_t size, uint32_t flags);
- chunk_t* dealloc(size_t start);
- void dump_l(const char* what, uint32_t flags = 0) const;
- void dump_l(String8& res, const char* what, uint32_t flags = 0) const;
-
- static const int kMemoryAlign;
- mutable Mutex mLock;
- LinkedList<chunk_t> mList;
- size_t mHeapSize;
-};
-
-// ----------------------------------------------------------------------------
-
-class MemoryDealer : public RefBase
-{
-public:
-
- enum {
- READ_ONLY = MemoryHeapBase::READ_ONLY,
- PAGE_ALIGNED = AllocatorInterface::PAGE_ALIGNED
- };
-
- // creates a memory dealer with the SharedHeap and SimpleBestFitAllocator
- MemoryDealer(size_t size, uint32_t flags = 0, const char* name = 0);
-
- // provide a custom heap but use the SimpleBestFitAllocator
- MemoryDealer(const sp<HeapInterface>& heap);
-
- // provide both custom heap and allocotar
- MemoryDealer(
- const sp<HeapInterface>& heap,
- const sp<AllocatorInterface>& allocator);
-
- virtual ~MemoryDealer();
-
- virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0);
- virtual void deallocate(size_t offset);
- virtual void dump(const char* what, uint32_t flags = 0) const;
-
-
- sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
- sp<AllocatorInterface> getAllocator() const { return allocator(); }
-
-private:
- const sp<HeapInterface>& heap() const;
- const sp<AllocatorInterface>& allocator() const;
-
- class Allocation : public BnMemory {
- public:
- Allocation(const sp<MemoryDealer>& dealer,
- ssize_t offset, size_t size, const sp<IMemory>& memory);
- virtual ~Allocation();
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
- private:
- sp<MemoryDealer> mDealer;
- ssize_t mOffset;
- size_t mSize;
- sp<IMemory> mMemory;
- };
-
- sp<HeapInterface> mHeap;
- sp<AllocatorInterface> mAllocator;
-};
-
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_MEMORY_DEALER_H
diff --git a/include/utils/MemoryHeapBase.h b/include/utils/MemoryHeapBase.h
deleted file mode 100644
index 574acf4..0000000
--- a/include/utils/MemoryHeapBase.h
+++ /dev/null
@@ -1,98 +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 ANDROID_MEMORY_HEAP_BASE_H
-#define ANDROID_MEMORY_HEAP_BASE_H
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <utils/IMemory.h>
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class MemoryHeapBase : public virtual BnMemoryHeap
-{
-public:
- enum {
- READ_ONLY = IMemoryHeap::READ_ONLY,
- MAP_ONCE = IMemoryHeap::MAP_ONCE,
- // memory won't be mapped locally, but will be mapped in the remote
- // process.
- DONT_MAP_LOCALLY = 0x00000100
- };
-
- /*
- * maps the memory referenced by fd. but DOESN'T take ownership
- * of the filedescriptor (it makes a copy with dup()
- */
- MemoryHeapBase(int fd, size_t size, uint32_t flags = 0);
-
- /*
- * maps memory from the given device
- */
- MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0);
-
- /*
- * maps memory from ashmem, with the given name for debugging
- */
- MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL);
-
- virtual ~MemoryHeapBase();
-
- /* implement IMemoryHeap interface */
- virtual int getHeapID() const;
- virtual void* getBase() const;
- virtual size_t getSize() const;
- virtual uint32_t getFlags() const;
-
- const char* getDevice() const;
-
- /* this closes this heap -- use carefully */
- void dispose();
-
- /* this is only needed as a workaround, use only if you know
- * what you are doing */
- status_t setDevice(const char* device) {
- if (mDevice == 0)
- mDevice = device;
- return mDevice ? NO_ERROR : ALREADY_EXISTS;
- }
-
-protected:
- MemoryHeapBase();
- // init() takes ownership of fd
- status_t init(int fd, void *base, int size,
- int flags = 0, const char* device = NULL);
-
-private:
- status_t mapfd(int fd, size_t size);
-
- int mFD;
- size_t mSize;
- void* mBase;
- uint32_t mFlags;
- const char* mDevice;
- bool mNeedUnmap;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_MEMORY_HEAP_BASE_H
diff --git a/include/utils/MemoryHeapPmem.h b/include/utils/MemoryHeapPmem.h
deleted file mode 100644
index 60335ad..0000000
--- a/include/utils/MemoryHeapPmem.h
+++ /dev/null
@@ -1,80 +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 ANDROID_MEMORY_HEAP_PMEM_H
-#define ANDROID_MEMORY_HEAP_PMEM_H
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <utils/MemoryDealer.h>
-#include <utils/MemoryHeapBase.h>
-#include <utils/IMemory.h>
-#include <utils/SortedVector.h>
-
-namespace android {
-
-class MemoryHeapBase;
-
-// ---------------------------------------------------------------------------
-
-class MemoryHeapPmem : public HeapInterface, public MemoryHeapBase
-{
-public:
- class MemoryPmem : public BnMemory {
- public:
- MemoryPmem(const sp<MemoryHeapPmem>& heap);
- ~MemoryPmem();
- protected:
- const sp<MemoryHeapPmem>& getHeap() const { return mClientHeap; }
- private:
- friend class MemoryHeapPmem;
- virtual void revoke() = 0;
- sp<MemoryHeapPmem> mClientHeap;
- };
-
- MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
- uint32_t flags = IMemoryHeap::MAP_ONCE);
- ~MemoryHeapPmem();
-
- /* HeapInterface additions */
- virtual sp<IMemory> mapMemory(size_t offset, size_t size);
-
- /* make the whole heap visible (you know who you are) */
- virtual status_t slap();
-
- /* hide (revoke) the whole heap (the client will see the garbage page) */
- virtual status_t unslap();
-
- /* revoke all allocations made by this heap */
- virtual void revoke();
-
-private:
- /* use this to create your own IMemory for mapMemory */
- virtual sp<MemoryPmem> createMemory(size_t offset, size_t size);
- void remove(const wp<MemoryPmem>& memory);
-
-private:
- sp<MemoryHeapBase> mParentHeap;
- mutable Mutex mLock;
- SortedVector< wp<MemoryPmem> > mAllocations;
-};
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_MEMORY_HEAP_PMEM_H
diff --git a/include/utils/Parcel.h b/include/utils/Parcel.h
deleted file mode 100644
index af1490a..0000000
--- a/include/utils/Parcel.h
+++ /dev/null
@@ -1,211 +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.
- */
-
-#ifndef ANDROID_PARCEL_H
-#define ANDROID_PARCEL_H
-
-#include <cutils/native_handle.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-class IBinder;
-class ProcessState;
-class String8;
-class TextOutput;
-
-struct flat_binder_object; // defined in support_p/binder_module.h
-
-class Parcel
-{
-public:
- Parcel();
- ~Parcel();
-
- const uint8_t* data() const;
- size_t dataSize() const;
- size_t dataAvail() const;
- size_t dataPosition() const;
- size_t dataCapacity() const;
-
- status_t setDataSize(size_t size);
- void setDataPosition(size_t pos) const;
- status_t setDataCapacity(size_t size);
-
- status_t setData(const uint8_t* buffer, size_t len);
-
- status_t appendFrom(Parcel *parcel, size_t start, size_t len);
-
- bool hasFileDescriptors() const;
-
- status_t writeInterfaceToken(const String16& interface);
- bool enforceInterface(const String16& interface) const;
-
- void freeData();
-
- const size_t* objects() const;
- size_t objectsCount() const;
-
- status_t errorCheck() const;
- void setError(status_t err);
-
- status_t write(const void* data, size_t len);
- void* writeInplace(size_t len);
- status_t writeUnpadded(const void* data, size_t len);
- status_t writeInt32(int32_t val);
- status_t writeInt64(int64_t val);
- status_t writeFloat(float val);
- status_t writeDouble(double val);
- status_t writeCString(const char* str);
- status_t writeString8(const String8& str);
- status_t writeString16(const String16& str);
- status_t writeString16(const char16_t* str, size_t len);
- status_t writeStrongBinder(const sp<IBinder>& val);
- status_t writeWeakBinder(const wp<IBinder>& val);
-
- // Place a native_handle into the parcel (the native_handle's file-
- // descriptors are dup'ed, so it is safe to delete the native_handle
- // when this function returns).
- // Doesn't take ownership of the native_handle.
- status_t writeNativeHandle(const native_handle* handle);
-
- // Place a file descriptor into the parcel. The given fd must remain
- // valid for the lifetime of the parcel.
- status_t writeFileDescriptor(int fd);
-
- // Place a file descriptor into the parcel. A dup of the fd is made, which
- // will be closed once the parcel is destroyed.
- status_t writeDupFileDescriptor(int fd);
-
- status_t writeObject(const flat_binder_object& val, bool nullMetaData);
-
- void remove(size_t start, size_t amt);
-
- status_t read(void* outData, size_t len) const;
- const void* readInplace(size_t len) const;
- int32_t readInt32() const;
- status_t readInt32(int32_t *pArg) const;
- int64_t readInt64() const;
- status_t readInt64(int64_t *pArg) const;
- float readFloat() const;
- status_t readFloat(float *pArg) const;
- double readDouble() const;
- status_t readDouble(double *pArg) const;
-
- const char* readCString() const;
- String8 readString8() const;
- String16 readString16() const;
- const char16_t* readString16Inplace(size_t* outLen) const;
- sp<IBinder> readStrongBinder() const;
- wp<IBinder> readWeakBinder() const;
-
-
- // Retrieve native_handle from the parcel. This returns a copy of the
- // parcel's native_handle (the caller takes ownership). The caller
- // must free the native_handle with native_handle_close() and
- // native_handle_delete().
- native_handle* readNativeHandle() const;
-
-
- // Retrieve a file descriptor from the parcel. This returns the raw fd
- // in the parcel, which you do not own -- use dup() to get your own copy.
- int readFileDescriptor() const;
-
- const flat_binder_object* readObject(bool nullMetaData) const;
-
- // Explicitly close all file descriptors in the parcel.
- void closeFileDescriptors();
-
- typedef void (*release_func)(Parcel* parcel,
- const uint8_t* data, size_t dataSize,
- const size_t* objects, size_t objectsSize,
- void* cookie);
-
- const uint8_t* ipcData() const;
- size_t ipcDataSize() const;
- const size_t* ipcObjects() const;
- size_t ipcObjectsCount() const;
- void ipcSetDataReference(const uint8_t* data, size_t dataSize,
- const size_t* objects, size_t objectsCount,
- release_func relFunc, void* relCookie);
-
- void print(TextOutput& to, uint32_t flags = 0) const;
-
-private:
- Parcel(const Parcel& o);
- Parcel& operator=(const Parcel& o);
-
- status_t finishWrite(size_t len);
- void releaseObjects();
- void acquireObjects();
- status_t growData(size_t len);
- status_t restartWrite(size_t desired);
- status_t continueWrite(size_t desired);
- void freeDataNoInit();
- void initState();
- void scanForFds() const;
-
- status_t mError;
- uint8_t* mData;
- size_t mDataSize;
- size_t mDataCapacity;
- mutable size_t mDataPos;
- size_t* mObjects;
- size_t mObjectsSize;
- size_t mObjectsCapacity;
- mutable size_t mNextObjectHint;
-
- mutable bool mFdsKnown;
- mutable bool mHasFds;
-
- release_func mOwner;
- void* mOwnerCookie;
-};
-
-// ---------------------------------------------------------------------------
-
-inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
-{
- parcel.print(to);
- return to;
-}
-
-// ---------------------------------------------------------------------------
-
-// Generic acquire and release of objects.
-void acquire_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who);
-void release_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who);
-
-void flatten_binder(const sp<ProcessState>& proc,
- const sp<IBinder>& binder, flat_binder_object* out);
-void flatten_binder(const sp<ProcessState>& proc,
- const wp<IBinder>& binder, flat_binder_object* out);
-status_t unflatten_binder(const sp<ProcessState>& proc,
- const flat_binder_object& flat, sp<IBinder>* out);
-status_t unflatten_binder(const sp<ProcessState>& proc,
- const flat_binder_object& flat, wp<IBinder>* out);
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PARCEL_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/ProcessState.h b/include/utils/ProcessState.h
deleted file mode 100644
index 39584f4..0000000
--- a/include/utils/ProcessState.h
+++ /dev/null
@@ -1,117 +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.
- */
-
-#ifndef ANDROID_PROCESS_STATE_H
-#define ANDROID_PROCESS_STATE_H
-
-#include <utils/IBinder.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-
-#include <utils/threads.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-
-// Global variables
-extern int mArgC;
-extern const char* const* mArgV;
-extern int mArgLen;
-
-class IPCThreadState;
-
-class ProcessState : public virtual RefBase
-{
-public:
- static sp<ProcessState> self();
-
- static void setSingleProcess(bool singleProcess);
-
- void setContextObject(const sp<IBinder>& object);
- sp<IBinder> getContextObject(const sp<IBinder>& caller);
-
- void setContextObject(const sp<IBinder>& object,
- const String16& name);
- sp<IBinder> getContextObject(const String16& name,
- const sp<IBinder>& caller);
-
- bool supportsProcesses() const;
-
- void startThreadPool();
-
- typedef bool (*context_check_func)(const String16& name,
- const sp<IBinder>& caller,
- void* userData);
-
- bool isContextManager(void) const;
- bool becomeContextManager(
- context_check_func checkFunc,
- void* userData);
-
- sp<IBinder> getStrongProxyForHandle(int32_t handle);
- wp<IBinder> getWeakProxyForHandle(int32_t handle);
- void expungeHandle(int32_t handle, IBinder* binder);
-
- void setArgs(int argc, const char* const argv[]);
- int getArgC() const;
- const char* const* getArgV() const;
-
- void setArgV0(const char* txt);
-
- void spawnPooledThread(bool isMain);
-
-private:
- friend class IPCThreadState;
-
- ProcessState();
- ~ProcessState();
-
- ProcessState(const ProcessState& o);
- ProcessState& operator=(const ProcessState& o);
-
- struct handle_entry {
- IBinder* binder;
- RefBase::weakref_type* refs;
- };
-
- handle_entry* lookupHandleLocked(int32_t handle);
-
- int mDriverFD;
- void* mVMStart;
-
- mutable Mutex mLock; // protects everything below.
-
- Vector<handle_entry>mHandleToObject;
-
- bool mManagesContexts;
- context_check_func mBinderContextCheckFunc;
- void* mBinderContextUserData;
-
- KeyedVector<String16, sp<IBinder> >
- mContexts;
-
-
- String8 mRootDir;
- bool mThreadPoolStarted;
- volatile int32_t mThreadPoolSeq;
-};
-
-}; // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PROCESS_STATE_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index cbda0fd..bd7f28c 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -156,6 +156,10 @@ public:
delete static_cast<const T*>(this);
}
}
+ //! DEBUGGING ONLY: Get current strong ref count.
+ inline int32_t getStrongCount() const {
+ return mCount;
+ }
protected:
inline ~LightRefBase() { }
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
new file mode 100644
index 0000000..bc7626a8
--- /dev/null
+++ b/include/utils/Singleton.h
@@ -0,0 +1,69 @@
+/*
+ * 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_UTILS_SINGLETON_H
+#define ANDROID_UTILS_SINGLETON_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+template <typename TYPE>
+class Singleton
+{
+public:
+ static TYPE& getInstance() {
+ Mutex::Autolock _l(sLock);
+ TYPE* instance = sInstance;
+ if (instance == 0) {
+ instance = new TYPE();
+ sInstance = instance;
+ }
+ return *instance;
+ }
+
+protected:
+ ~Singleton() { };
+ Singleton() { };
+
+private:
+ Singleton(const Singleton&);
+ Singleton& operator = (const Singleton&);
+ static Mutex sLock;
+ static TYPE* sInstance;
+};
+
+/*
+ * use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file
+ * (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes,
+ * and avoid to have a copy of them in each compilation units Singleton<TYPE>
+ * is used.
+ */
+
+#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \
+ template class Singleton< TYPE >; \
+ template< class TYPE > Mutex Singleton< TYPE >::sLock; \
+ template<> TYPE* Singleton< TYPE >::sInstance(0);
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_UTILS_SINGLETON_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/SortedVector.h b/include/utils/SortedVector.h
index c8a6153..8beec57 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -141,8 +141,7 @@ SortedVector<TYPE>::SortedVector()
: SortedVectorImpl(sizeof(TYPE),
((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
|(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
- |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
- |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+ |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0))
)
{
}
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/TypeHelpers.h b/include/utils/TypeHelpers.h
index c04c37f..2ff2749 100644
--- a/include/utils/TypeHelpers.h
+++ b/include/utils/TypeHelpers.h
@@ -29,35 +29,39 @@ namespace android {
/*
* Types traits
*/
-
-template <typename T> struct trait_trivial_ctor { enum { value = false }; };
-template <typename T> struct trait_trivial_dtor { enum { value = false }; };
-template <typename T> struct trait_trivial_copy { enum { value = false }; };
-template <typename T> struct trait_trivial_assign{ enum { value = false }; };
-
-template <typename T> struct trait_pointer { enum { value = false }; };
-template <typename T> struct trait_pointer<T*> { enum { value = true }; };
-
-#define ANDROID_BASIC_TYPES_TRAITS( T ) \
- template<> struct trait_trivial_ctor< T > { enum { value = true }; }; \
- template<> struct trait_trivial_dtor< T > { enum { value = true }; }; \
- template<> struct trait_trivial_copy< T > { enum { value = true }; }; \
- template<> struct trait_trivial_assign< T >{ enum { value = true }; };
-
-#define ANDROID_TYPE_TRAITS( T, ctor, dtor, copy, assign ) \
- template<> struct trait_trivial_ctor< T > { enum { value = ctor }; }; \
- template<> struct trait_trivial_dtor< T > { enum { value = dtor }; }; \
- template<> struct trait_trivial_copy< T > { enum { value = copy }; }; \
- template<> struct trait_trivial_assign< T >{ enum { value = assign }; };
+
+template <typename T> struct trait_trivial_ctor { enum { value = false }; };
+template <typename T> struct trait_trivial_dtor { enum { value = false }; };
+template <typename T> struct trait_trivial_copy { enum { value = false }; };
+template <typename T> struct trait_trivial_move { enum { value = false }; };
+template <typename T> struct trait_pointer { enum { value = false }; };
+template <typename T> struct trait_pointer<T*> { enum { value = true }; };
+
+// sp<> can be trivially moved
+template <typename T> class sp;
+template <typename T> struct trait_trivial_move< sp<T> >{
+ enum { value = true };
+};
+
+// wp<> can be trivially moved
+template <typename T> class wp;
+template <typename T> struct trait_trivial_move< wp<T> >{
+ enum { value = true };
+};
template <typename TYPE>
struct traits {
enum {
+ // whether this type is a pointer
is_pointer = trait_pointer<TYPE>::value,
+ // whether this type's constructor is a no-op
has_trivial_ctor = is_pointer || trait_trivial_ctor<TYPE>::value,
+ // whether this type's destructor is a no-op
has_trivial_dtor = is_pointer || trait_trivial_dtor<TYPE>::value,
+ // whether this type type can be copy-constructed with memcpy
has_trivial_copy = is_pointer || trait_trivial_copy<TYPE>::value,
- has_trivial_assign = is_pointer || trait_trivial_assign<TYPE>::value
+ // whether this type can be moved with memmove
+ has_trivial_move = is_pointer || trait_trivial_move<TYPE>::value
};
};
@@ -65,37 +69,47 @@ template <typename T, typename U>
struct aggregate_traits {
enum {
is_pointer = false,
- has_trivial_ctor = traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
- has_trivial_dtor = traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
- has_trivial_copy = traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
- has_trivial_assign = traits<T>::has_trivial_assign && traits<U>::has_trivial_assign
+ has_trivial_ctor =
+ traits<T>::has_trivial_ctor && traits<U>::has_trivial_ctor,
+ has_trivial_dtor =
+ traits<T>::has_trivial_dtor && traits<U>::has_trivial_dtor,
+ has_trivial_copy =
+ traits<T>::has_trivial_copy && traits<U>::has_trivial_copy,
+ has_trivial_move =
+ traits<T>::has_trivial_move && traits<U>::has_trivial_move
};
};
+#define ANDROID_BASIC_TYPES_TRAITS( T ) \
+ template<> struct trait_trivial_ctor< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_dtor< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_copy< T > { enum { value = true }; }; \
+ template<> struct trait_trivial_move< T > { enum { value = true }; };
+
// ---------------------------------------------------------------------------
/*
* basic types traits
*/
-
-ANDROID_BASIC_TYPES_TRAITS( void );
-ANDROID_BASIC_TYPES_TRAITS( bool );
-ANDROID_BASIC_TYPES_TRAITS( char );
-ANDROID_BASIC_TYPES_TRAITS( unsigned char );
-ANDROID_BASIC_TYPES_TRAITS( short );
-ANDROID_BASIC_TYPES_TRAITS( unsigned short );
-ANDROID_BASIC_TYPES_TRAITS( int );
-ANDROID_BASIC_TYPES_TRAITS( unsigned int );
-ANDROID_BASIC_TYPES_TRAITS( long );
-ANDROID_BASIC_TYPES_TRAITS( unsigned long );
-ANDROID_BASIC_TYPES_TRAITS( long long );
-ANDROID_BASIC_TYPES_TRAITS( unsigned long long );
-ANDROID_BASIC_TYPES_TRAITS( float );
-ANDROID_BASIC_TYPES_TRAITS( double );
+
+ANDROID_BASIC_TYPES_TRAITS( void )
+ANDROID_BASIC_TYPES_TRAITS( bool )
+ANDROID_BASIC_TYPES_TRAITS( char )
+ANDROID_BASIC_TYPES_TRAITS( unsigned char )
+ANDROID_BASIC_TYPES_TRAITS( short )
+ANDROID_BASIC_TYPES_TRAITS( unsigned short )
+ANDROID_BASIC_TYPES_TRAITS( int )
+ANDROID_BASIC_TYPES_TRAITS( unsigned int )
+ANDROID_BASIC_TYPES_TRAITS( long )
+ANDROID_BASIC_TYPES_TRAITS( unsigned long )
+ANDROID_BASIC_TYPES_TRAITS( long long )
+ANDROID_BASIC_TYPES_TRAITS( unsigned long long )
+ANDROID_BASIC_TYPES_TRAITS( float )
+ANDROID_BASIC_TYPES_TRAITS( double )
// ---------------------------------------------------------------------------
-
+
/*
* compare and order types
*/
@@ -111,9 +125,9 @@ int compare_type(const TYPE& lhs, const TYPE& rhs) {
}
/*
- * create, destroy, copy and assign types...
+ * create, destroy, copy and move types...
*/
-
+
template<typename TYPE> inline
void construct_type(TYPE* p, size_t n) {
if (!traits<TYPE>::has_trivial_ctor) {
@@ -146,17 +160,6 @@ void copy_type(TYPE* d, const TYPE* s, size_t n) {
}
template<typename TYPE> inline
-void assign_type(TYPE* d, const TYPE* s, size_t n) {
- if (!traits<TYPE>::has_trivial_assign) {
- while (n--) {
- *d++ = *s++;
- }
- } else {
- memcpy(d,s,n*sizeof(TYPE));
- }
-}
-
-template<typename TYPE> inline
void splat_type(TYPE* where, const TYPE* what, size_t n) {
if (!traits<TYPE>::has_trivial_copy) {
while (n--) {
@@ -164,15 +167,19 @@ void splat_type(TYPE* where, const TYPE* what, size_t n) {
where++;
}
} else {
- while (n--) {
- *where++ = *what;
+ while (n--) {
+ *where++ = *what;
}
}
}
template<typename TYPE> inline
void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
- if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
+ if ((traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy)
+ || traits<TYPE>::has_trivial_move)
+ {
+ memmove(d,s,n*sizeof(TYPE));
+ } else {
d += n;
s += n;
while (n--) {
@@ -180,35 +187,37 @@ void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
if (!traits<TYPE>::has_trivial_copy) {
new(d) TYPE(*s);
} else {
- *d = *s;
+ *d = *s;
}
if (!traits<TYPE>::has_trivial_dtor) {
s->~TYPE();
}
}
- } else {
- memmove(d,s,n*sizeof(TYPE));
}
}
template<typename TYPE> inline
void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
- if (!traits<TYPE>::has_trivial_copy || !traits<TYPE>::has_trivial_dtor) {
+ if ((traits<TYPE>::has_trivial_dtor && traits<TYPE>::has_trivial_copy)
+ || traits<TYPE>::has_trivial_move)
+ {
+ memmove(d,s,n*sizeof(TYPE));
+ } else {
while (n--) {
if (!traits<TYPE>::has_trivial_copy) {
new(d) TYPE(*s);
} else {
- *d = *s;
+ *d = *s;
}
if (!traits<TYPE>::has_trivial_dtor) {
s->~TYPE();
}
d++, s++;
}
- } else {
- memmove(d,s,n*sizeof(TYPE));
}
}
+
+
// ---------------------------------------------------------------------------
/*
@@ -242,8 +251,8 @@ struct trait_trivial_copy< key_value_pair_t<K, V> >
{ enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
template<>
template <typename K, typename V>
-struct trait_trivial_assign< key_value_pair_t<K, V> >
-{ enum { value = aggregate_traits<K,V>::has_trivial_assign};};
+struct trait_trivial_move< key_value_pair_t<K, V> >
+{ enum { value = aggregate_traits<K,V>::has_trivial_move }; };
// ---------------------------------------------------------------------------
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index be365d8..ad59fd6 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -175,8 +175,7 @@ Vector<TYPE>::Vector()
: VectorImpl(sizeof(TYPE),
((traits<TYPE>::has_trivial_ctor ? HAS_TRIVIAL_CTOR : 0)
|(traits<TYPE>::has_trivial_dtor ? HAS_TRIVIAL_DTOR : 0)
- |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0)
- |(traits<TYPE>::has_trivial_assign ? HAS_TRIVIAL_ASSIGN : 0))
+ |(traits<TYPE>::has_trivial_copy ? HAS_TRIVIAL_COPY : 0))
)
{
}
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
index 2525229..49b03f1 100644
--- a/include/utils/VectorImpl.h
+++ b/include/utils/VectorImpl.h
@@ -44,7 +44,6 @@ public:
HAS_TRIVIAL_CTOR = 0x00000001,
HAS_TRIVIAL_DTOR = 0x00000002,
HAS_TRIVIAL_COPY = 0x00000004,
- HAS_TRIVIAL_ASSIGN = 0x00000008
};
VectorImpl(size_t itemSize, uint32_t flags);
diff --git a/include/utils/ZipEntry.h b/include/utils/ZipEntry.h
deleted file mode 100644
index e4698df..0000000
--- a/include/utils/ZipEntry.h
+++ /dev/null
@@ -1,345 +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.
- */
-
-//
-// Zip archive entries.
-//
-// The ZipEntry class is tightly meshed with the ZipFile class.
-//
-#ifndef __LIBS_ZIPENTRY_H
-#define __LIBS_ZIPENTRY_H
-
-#include "Errors.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-
-namespace android {
-
-class ZipFile;
-
-/*
- * ZipEntry objects represent a single entry in a Zip archive.
- *
- * You can use one of these to get or set information about an entry, but
- * there are no functions here for accessing the data itself. (We could
- * tuck a pointer to the ZipFile in here for convenience, but that raises
- * the likelihood of using ZipEntry objects after discarding the ZipFile.)
- *
- * File information is stored in two places: next to the file data (the Local
- * File Header, and possibly a Data Descriptor), and at the end of the file
- * (the Central Directory Entry). The two must be kept in sync.
- */
-class ZipEntry {
-public:
- friend class ZipFile;
-
- ZipEntry(void)
- : mDeleted(false), mMarked(false)
- {}
- ~ZipEntry(void) {}
-
- /*
- * Returns "true" if the data is compressed.
- */
- bool isCompressed(void) const {
- return mCDE.mCompressionMethod != kCompressStored;
- }
- int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
-
- /*
- * Return the uncompressed length.
- */
- off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
-
- /*
- * Return the compressed length. For uncompressed data, this returns
- * the same thing as getUncompresesdLen().
- */
- off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
-
- /*
- * Return the absolute file offset of the start of the compressed or
- * uncompressed data.
- */
- off_t getFileOffset(void) const {
- return mCDE.mLocalHeaderRelOffset +
- LocalFileHeader::kLFHLen +
- mLFH.mFileNameLength +
- mLFH.mExtraFieldLength;
- }
-
- /*
- * Return the data CRC.
- */
- unsigned long getCRC32(void) const { return mCDE.mCRC32; }
-
- /*
- * Return file modification time in UNIX seconds-since-epoch.
- */
- time_t getModWhen(void) const;
-
- /*
- * Return the archived file name.
- */
- const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
-
- /*
- * Application-defined "mark". Can be useful when synchronizing the
- * contents of an archive with contents on disk.
- */
- bool getMarked(void) const { return mMarked; }
- void setMarked(bool val) { mMarked = val; }
-
- /*
- * Some basic functions for raw data manipulation. "LE" means
- * Little Endian.
- */
- static inline unsigned short getShortLE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8);
- }
- static inline unsigned long getLongLE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
- }
- static inline void putShortLE(unsigned char* buf, short val) {
- buf[0] = (unsigned char) val;
- buf[1] = (unsigned char) (val >> 8);
- }
- static inline void putLongLE(unsigned char* buf, long val) {
- buf[0] = (unsigned char) val;
- buf[1] = (unsigned char) (val >> 8);
- buf[2] = (unsigned char) (val >> 16);
- buf[3] = (unsigned char) (val >> 24);
- }
-
- /* defined for Zip archives */
- enum {
- kCompressStored = 0, // no compression
- // shrunk = 1,
- // reduced 1 = 2,
- // reduced 2 = 3,
- // reduced 3 = 4,
- // reduced 4 = 5,
- // imploded = 6,
- // tokenized = 7,
- kCompressDeflated = 8, // standard deflate
- // Deflate64 = 9,
- // lib imploded = 10,
- // reserved = 11,
- // bzip2 = 12,
- };
-
- /*
- * Deletion flag. If set, the entry will be removed on the next
- * call to "flush".
- */
- bool getDeleted(void) const { return mDeleted; }
-
-protected:
- /*
- * Initialize the structure from the file, which is pointing at
- * our Central Directory entry.
- */
- status_t initFromCDE(FILE* fp);
-
- /*
- * Initialize the structure for a new file. We need the filename
- * and comment so that we can properly size the LFH area. The
- * filename is mandatory, the comment is optional.
- */
- void initNew(const char* fileName, const char* comment);
-
- /*
- * Initialize the structure with the contents of a ZipEntry from
- * another file.
- */
- status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
-
- /*
- * Add some pad bytes to the LFH. We do this by adding or resizing
- * the "extra" field.
- */
- status_t addPadding(int padding);
-
- /*
- * Set information about the data for this entry.
- */
- void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
- int compressionMethod);
-
- /*
- * Set the modification date.
- */
- void setModWhen(time_t when);
-
- /*
- * Return the offset of the local file header.
- */
- off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
-
- /*
- * Set the offset of the local file header, relative to the start of
- * the current file.
- */
- void setLFHOffset(off_t offset) {
- mCDE.mLocalHeaderRelOffset = (long) offset;
- }
-
- /* mark for deletion; used by ZipFile::remove() */
- void setDeleted(void) { mDeleted = true; }
-
-private:
- /* these are private and not defined */
- ZipEntry(const ZipEntry& src);
- ZipEntry& operator=(const ZipEntry& src);
-
- /* returns "true" if the CDE and the LFH agree */
- bool compareHeaders(void) const;
- void copyCDEtoLFH(void);
-
- bool mDeleted; // set if entry is pending deletion
- bool mMarked; // app-defined marker
-
- /*
- * Every entry in the Zip archive starts off with one of these.
- */
- class LocalFileHeader {
- public:
- LocalFileHeader(void) :
- mVersionToExtract(0),
- mGPBitFlag(0),
- mCompressionMethod(0),
- mLastModFileTime(0),
- mLastModFileDate(0),
- mCRC32(0),
- mCompressedSize(0),
- mUncompressedSize(0),
- mFileNameLength(0),
- mExtraFieldLength(0),
- mFileName(NULL),
- mExtraField(NULL)
- {}
- virtual ~LocalFileHeader(void) {
- delete[] mFileName;
- delete[] mExtraField;
- }
-
- status_t read(FILE* fp);
- status_t write(FILE* fp);
-
- // unsigned long mSignature;
- unsigned short mVersionToExtract;
- unsigned short mGPBitFlag;
- unsigned short mCompressionMethod;
- unsigned short mLastModFileTime;
- unsigned short mLastModFileDate;
- unsigned long mCRC32;
- unsigned long mCompressedSize;
- unsigned long mUncompressedSize;
- unsigned short mFileNameLength;
- unsigned short mExtraFieldLength;
- unsigned char* mFileName;
- unsigned char* mExtraField;
-
- enum {
- kSignature = 0x04034b50,
- kLFHLen = 30, // LocalFileHdr len, excl. var fields
- };
-
- void dump(void) const;
- };
-
- /*
- * Every entry in the Zip archive has one of these in the "central
- * directory" at the end of the file.
- */
- class CentralDirEntry {
- public:
- CentralDirEntry(void) :
- mVersionMadeBy(0),
- mVersionToExtract(0),
- mGPBitFlag(0),
- mCompressionMethod(0),
- mLastModFileTime(0),
- mLastModFileDate(0),
- mCRC32(0),
- mCompressedSize(0),
- mUncompressedSize(0),
- mFileNameLength(0),
- mExtraFieldLength(0),
- mFileCommentLength(0),
- mDiskNumberStart(0),
- mInternalAttrs(0),
- mExternalAttrs(0),
- mLocalHeaderRelOffset(0),
- mFileName(NULL),
- mExtraField(NULL),
- mFileComment(NULL)
- {}
- virtual ~CentralDirEntry(void) {
- delete[] mFileName;
- delete[] mExtraField;
- delete[] mFileComment;
- }
-
- status_t read(FILE* fp);
- status_t write(FILE* fp);
-
- // unsigned long mSignature;
- unsigned short mVersionMadeBy;
- unsigned short mVersionToExtract;
- unsigned short mGPBitFlag;
- unsigned short mCompressionMethod;
- unsigned short mLastModFileTime;
- unsigned short mLastModFileDate;
- unsigned long mCRC32;
- unsigned long mCompressedSize;
- unsigned long mUncompressedSize;
- unsigned short mFileNameLength;
- unsigned short mExtraFieldLength;
- unsigned short mFileCommentLength;
- unsigned short mDiskNumberStart;
- unsigned short mInternalAttrs;
- unsigned long mExternalAttrs;
- unsigned long mLocalHeaderRelOffset;
- unsigned char* mFileName;
- unsigned char* mExtraField;
- unsigned char* mFileComment;
-
- void dump(void) const;
-
- enum {
- kSignature = 0x02014b50,
- kCDELen = 46, // CentralDirEnt len, excl. var fields
- };
- };
-
- enum {
- //kDataDescriptorSignature = 0x08074b50, // currently unused
- kDataDescriptorLen = 16, // four 32-bit fields
-
- kDefaultVersion = 20, // need deflate, nothing much else
- kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
- kUsesDataDescr = 0x0008, // GPBitFlag bit 3
- };
-
- LocalFileHeader mLFH;
- CentralDirEntry mCDE;
-};
-
-}; // namespace android
-
-#endif // __LIBS_ZIPENTRY_H
diff --git a/include/utils/ZipFile.h b/include/utils/ZipFile.h
deleted file mode 100644
index 44df5bb..0000000
--- a/include/utils/ZipFile.h
+++ /dev/null
@@ -1,269 +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.
- */
-
-//
-// General-purpose Zip archive access. This class allows both reading and
-// writing to Zip archives, including deletion of existing entries.
-//
-#ifndef __LIBS_ZIPFILE_H
-#define __LIBS_ZIPFILE_H
-
-#include "ZipEntry.h"
-#include "Vector.h"
-#include "Errors.h"
-#include <stdio.h>
-
-namespace android {
-
-/*
- * Manipulate a Zip archive.
- *
- * Some changes will not be visible in the until until "flush" is called.
- *
- * The correct way to update a file archive is to make all changes to a
- * copy of the archive in a temporary file, and then unlink/rename over
- * the original after everything completes. Because we're only interested
- * in using this for packaging, we don't worry about such things. Crashing
- * after making changes and before flush() completes could leave us with
- * an unusable Zip archive.
- */
-class ZipFile {
-public:
- ZipFile(void)
- : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
- {}
- ~ZipFile(void) {
- if (!mReadOnly)
- flush();
- if (mZipFp != NULL)
- fclose(mZipFp);
- discardEntries();
- }
-
- /*
- * Open a new or existing archive.
- */
- typedef enum {
- kOpenReadOnly = 0x01,
- kOpenReadWrite = 0x02,
- kOpenCreate = 0x04, // create if it doesn't exist
- kOpenTruncate = 0x08, // if it exists, empty it
- };
- status_t open(const char* zipFileName, int flags);
-
- /*
- * Add a file to the end of the archive. Specify whether you want the
- * library to try to store it compressed.
- *
- * If "storageName" is specified, the archive will use that instead
- * of "fileName".
- *
- * If there is already an entry with the same name, the call fails.
- * Existing entries with the same name must be removed first.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t add(const char* fileName, int compressionMethod,
- ZipEntry** ppEntry)
- {
- return add(fileName, fileName, compressionMethod, ppEntry);
- }
- status_t add(const char* fileName, const char* storageName,
- int compressionMethod, ZipEntry** ppEntry)
- {
- return addCommon(fileName, NULL, 0, storageName,
- ZipEntry::kCompressStored,
- compressionMethod, ppEntry);
- }
-
- /*
- * Add a file that is already compressed with gzip.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t addGzip(const char* fileName, const char* storageName,
- ZipEntry** ppEntry)
- {
- return addCommon(fileName, NULL, 0, storageName,
- ZipEntry::kCompressDeflated,
- ZipEntry::kCompressDeflated, ppEntry);
- }
-
- /*
- * Add a file from an in-memory data buffer.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t add(const void* data, size_t size, const char* storageName,
- int compressionMethod, ZipEntry** ppEntry)
- {
- return addCommon(NULL, data, size, storageName,
- ZipEntry::kCompressStored,
- compressionMethod, ppEntry);
- }
-
- /*
- * Add an entry by copying it from another zip file. If "padding" is
- * nonzero, the specified number of bytes will be added to the "extra"
- * field in the header.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
- status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
- int padding, ZipEntry** ppEntry);
-
- /*
- * Mark an entry as having been removed. It is not actually deleted
- * from the archive or our internal data structures until flush() is
- * called.
- */
- status_t remove(ZipEntry* pEntry);
-
- /*
- * Flush changes. If mNeedCDRewrite is set, this writes the central dir.
- */
- status_t flush(void);
-
- /*
- * Expand the data into the buffer provided. The buffer must hold
- * at least <uncompressed len> bytes. Variation expands directly
- * to a file.
- *
- * Returns "false" if an error was encountered in the compressed data.
- */
- //bool uncompress(const ZipEntry* pEntry, void* buf) const;
- //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
- void* uncompress(const ZipEntry* pEntry);
-
- /*
- * Get an entry, by name. Returns NULL if not found.
- *
- * Does not return entries pending deletion.
- */
- ZipEntry* getEntryByName(const char* fileName) const;
-
- /*
- * Get the Nth entry in the archive.
- *
- * This will return an entry that is pending deletion.
- */
- int getNumEntries(void) const { return mEntries.size(); }
- ZipEntry* getEntryByIndex(int idx) const;
-
-private:
- /* these are private and not defined */
- ZipFile(const ZipFile& src);
- ZipFile& operator=(const ZipFile& src);
-
- class EndOfCentralDir {
- public:
- EndOfCentralDir(void) :
- mDiskNumber(0),
- mDiskWithCentralDir(0),
- mNumEntries(0),
- mTotalNumEntries(0),
- mCentralDirSize(0),
- mCentralDirOffset(0),
- mCommentLen(0),
- mComment(NULL)
- {}
- virtual ~EndOfCentralDir(void) {
- delete[] mComment;
- }
-
- status_t readBuf(const unsigned char* buf, int len);
- status_t write(FILE* fp);
-
- //unsigned long mSignature;
- unsigned short mDiskNumber;
- unsigned short mDiskWithCentralDir;
- unsigned short mNumEntries;
- unsigned short mTotalNumEntries;
- unsigned long mCentralDirSize;
- unsigned long mCentralDirOffset; // offset from first disk
- unsigned short mCommentLen;
- unsigned char* mComment;
-
- enum {
- kSignature = 0x06054b50,
- kEOCDLen = 22, // EndOfCentralDir len, excl. comment
-
- kMaxCommentLen = 65535, // longest possible in ushort
- kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
-
- };
-
- void dump(void) const;
- };
-
-
- /* read all entries in the central dir */
- status_t readCentralDir(void);
-
- /* crunch deleted entries out */
- status_t crunchArchive(void);
-
- /* clean up mEntries */
- void discardEntries(void);
-
- /* common handler for all "add" functions */
- status_t addCommon(const char* fileName, const void* data, size_t size,
- const char* storageName, int sourceType, int compressionMethod,
- ZipEntry** ppEntry);
-
- /* copy all of "srcFp" into "dstFp" */
- status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
- /* copy all of "data" into "dstFp" */
- status_t copyDataToFp(FILE* dstFp,
- const void* data, size_t size, unsigned long* pCRC32);
- /* copy some of "srcFp" into "dstFp" */
- status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
- unsigned long* pCRC32);
- /* like memmove(), but on parts of a single file */
- status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
- /* compress all of "srcFp" into "dstFp", using Deflate */
- status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
- const void* data, size_t size, unsigned long* pCRC32);
-
- /* get modification date from a file descriptor */
- time_t getModTime(int fd);
-
- /*
- * We use stdio FILE*, which gives us buffering but makes dealing
- * with files >2GB awkward. Until we support Zip64, we're fine.
- */
- FILE* mZipFp; // Zip file pointer
-
- /* one of these per file */
- EndOfCentralDir mEOCD;
-
- /* did we open this read-only? */
- bool mReadOnly;
-
- /* set this when we trash the central dir */
- bool mNeedCDRewrite;
-
- /*
- * One ZipEntry per entry in the zip file. I'm using pointers instead
- * of objects because it's easier than making operator= work for the
- * classes and sub-classes.
- */
- Vector<ZipEntry*> mEntries;
-};
-
-}; // namespace android
-
-#endif // __LIBS_ZIPFILE_H
diff --git a/include/utils/executablepath.h b/include/utils/executablepath.h
deleted file mode 100644
index c979432..0000000
--- a/include/utils/executablepath.h
+++ /dev/null
@@ -1,28 +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 _UTILS_EXECUTABLEPATH_H
-#define _UTILS_EXECUTABLEPATH_H
-
-#include <limits.h>
-
-// returns the path to this executable
-#if __cplusplus
-extern "C"
-#endif
-void executablepath(char s[PATH_MAX]);
-
-#endif // _UTILS_EXECUTABLEPATH_H
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..e9b0788 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -21,6 +21,10 @@
#include <sys/types.h>
#include <time.h>
+#if defined(HAVE_PTHREADS)
+# include <pthread.h>
+#endif
+
// ------------------------------------------------------------------
// C API
@@ -176,6 +180,8 @@ inline thread_id_t getThreadId() {
return androidGetThreadId();
}
+/*****************************************************************************/
+
/*
* Simple mutex class. The implementation is system-dependent.
*
@@ -184,8 +190,14 @@ inline thread_id_t getThreadId() {
*/
class Mutex {
public:
+ enum {
+ NORMAL = 0,
+ SHARED = 1
+ };
+
Mutex();
Mutex(const char* name);
+ Mutex(int type, const char* name = NULL);
~Mutex();
// lock or unlock the mutex
@@ -199,11 +211,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:
@@ -212,11 +224,49 @@ private:
// A mutex cannot be copied
Mutex(const Mutex&);
Mutex& operator = (const Mutex&);
- void _init();
+#if defined(HAVE_PTHREADS)
+ pthread_mutex_t mMutex;
+#else
+ void _init();
void* mState;
+#endif
};
+#if defined(HAVE_PTHREADS)
+
+inline Mutex::Mutex() {
+ pthread_mutex_init(&mMutex, NULL);
+}
+inline Mutex::Mutex(const char* name) {
+ pthread_mutex_init(&mMutex, NULL);
+}
+inline Mutex::Mutex(int type, const char* name) {
+ if (type == SHARED) {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+ pthread_mutex_init(&mMutex, &attr);
+ pthread_mutexattr_destroy(&attr);
+ } else {
+ pthread_mutex_init(&mMutex, NULL);
+ }
+}
+inline Mutex::~Mutex() {
+ pthread_mutex_destroy(&mMutex);
+}
+inline status_t Mutex::lock() {
+ return -pthread_mutex_lock(&mMutex);
+}
+inline void Mutex::unlock() {
+ pthread_mutex_unlock(&mMutex);
+}
+inline status_t Mutex::tryLock() {
+ return -pthread_mutex_trylock(&mMutex);
+}
+
+#endif // HAVE_PTHREADS
+
/*
* Automatic mutex. Declare one of these at the top of a function.
* When the function returns, it will go out of scope, and release the
@@ -225,6 +275,7 @@ private:
typedef Mutex::Autolock AutoMutex;
+/*****************************************************************************/
/*
* Condition variable class. The implementation is system-dependent.
@@ -240,9 +291,6 @@ public:
~Condition();
// Wait on the condition variable. Lock the mutex before calling.
status_t wait(Mutex& mutex);
- // Wait on the condition variable until the given time. Lock the mutex
- // before calling.
- status_t wait(Mutex& mutex, nsecs_t abstime);
// same with relative timeout
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
// Signal the condition variable, allowing one thread to continue.
@@ -251,9 +299,60 @@ public:
void broadcast();
private:
+#if defined(HAVE_PTHREADS)
+ pthread_cond_t mCond;
+#else
void* mState;
+#endif
};
+#if defined(HAVE_PTHREADS)
+
+inline Condition::Condition() {
+ pthread_cond_init(&mCond, NULL);
+}
+inline Condition::~Condition() {
+ pthread_cond_destroy(&mCond);
+}
+inline status_t Condition::wait(Mutex& mutex) {
+ return -pthread_cond_wait(&mCond, &mutex.mMutex);
+}
+inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
+#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
+ struct timespec ts;
+ ts.tv_sec = reltime/1000000000;
+ ts.tv_nsec = reltime%1000000000;
+ return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
+#else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
+ struct timespec ts;
+#if defined(HAVE_POSIX_CLOCKS)
+ clock_gettime(CLOCK_REALTIME, &ts);
+#else // HAVE_POSIX_CLOCKS
+ // we don't support the clocks here.
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ ts.tv_sec = t.tv_sec;
+ ts.tv_nsec= t.tv_usec*1000;
+#endif // HAVE_POSIX_CLOCKS
+ ts.tv_sec += reltime/1000000000;
+ ts.tv_nsec+= reltime%1000000000;
+ if (ts.tv_nsec >= 1000000000) {
+ ts.tv_nsec -= 1000000000;
+ ts.tv_sec += 1;
+ }
+ return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
+#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
+}
+inline void Condition::signal() {
+ pthread_cond_signal(&mCond);
+}
+inline void Condition::broadcast() {
+ pthread_cond_broadcast(&mCond);
+}
+
+#endif // HAVE_PTHREADS
+
+/*****************************************************************************/
/*
* This is our spiffy thread object!
@@ -291,7 +390,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/keystore/java/android/security/CertTool.java b/keystore/java/android/security/CertTool.java
index 989432a..d1174ad 100644
--- a/keystore/java/android/security/CertTool.java
+++ b/keystore/java/android/security/CertTool.java
@@ -42,6 +42,15 @@ public class CertTool {
System.loadLibrary("certtool_jni");
}
+ /** Keystore namespace for CA certificates. */
+ public static final String CA_CERTIFICATE = "CACERT";
+
+ /** Keystore namespace for user certificates. */
+ public static final String USER_CERTIFICATE = "USRCERT";
+
+ /** Keystore namespace for user private keys. */
+ public static final String USER_KEY = "USRKEY";
+
public static final String ACTION_ADD_CREDENTIAL =
"android.security.ADD_CREDENTIAL";
public static final String KEY_TYPE_NAME = "typeName";
@@ -60,10 +69,6 @@ public class CertTool {
private static final String ISSUER_NAME = "Issuer Name:";
private static final String DISTINCT_NAME = "Distinct Name:";
- private static final String CA_CERTIFICATE = "CACERT";
- private static final String USER_CERTIFICATE = "USRCERT";
- private static final String USER_KEY = "USRKEY";
-
private static final String KEYNAME_DELIMITER = "_";
private static final Keystore sKeystore = Keystore.getInstance();
diff --git a/keystore/java/android/security/ServiceCommand.java b/keystore/java/android/security/ServiceCommand.java
index dddf654..cefae40 100644
--- a/keystore/java/android/security/ServiceCommand.java
+++ b/keystore/java/android/security/ServiceCommand.java
@@ -121,15 +121,16 @@ public class ServiceCommand {
Reply reply = new Reply();
if (!readBytes(buf, 4)) return null;
- reply.len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8) |
- ((((int) buf[2]) & 0xff) << 16) |
- ((((int) buf[3]) & 0xff) << 24);
+ reply.len = ((((int) buf[0]) & 0xff) << 24) |
+ ((((int) buf[1]) & 0xff) << 16) |
+ ((((int) buf[2]) & 0xff) << 8) |
+ (((int) buf[3]) & 0xff);
if (!readBytes(buf, 4)) return null;
- reply.returnCode = (((int) buf[0]) & 0xff) |
- ((((int) buf[1]) & 0xff) << 8) |
- ((((int) buf[2]) & 0xff) << 16) |
- ((((int) buf[3]) & 0xff) << 24);
+ reply.returnCode = ((((int) buf[0]) & 0xff) << 24) |
+ ((((int) buf[1]) & 0xff) << 16) |
+ ((((int) buf[2]) & 0xff) << 8) |
+ (((int) buf[3]) & 0xff);
if (reply.len > BUFFER_LENGTH) {
Log.e(mTag,"invalid reply length (" + reply.len + ")");
@@ -145,15 +146,15 @@ public class ServiceCommand {
byte[] data = (_data == null) ? new byte[0] : _data.getBytes();
int len = data.length;
// the length of data
- buf[0] = (byte) (len & 0xff);
- buf[1] = (byte) ((len >> 8) & 0xff);
- buf[2] = (byte) ((len >> 16) & 0xff);
- buf[3] = (byte) ((len >> 24) & 0xff);
+ buf[0] = (byte) ((len >> 24) & 0xff);
+ buf[1] = (byte) ((len >> 16) & 0xff);
+ buf[2] = (byte) ((len >> 8) & 0xff);
+ buf[3] = (byte) (len & 0xff);
// the opcode of the command
- buf[4] = (byte) (cmd & 0xff);
- buf[5] = (byte) ((cmd >> 8) & 0xff);
- buf[6] = (byte) ((cmd >> 16) & 0xff);
- buf[7] = (byte) ((cmd >> 24) & 0xff);
+ buf[4] = (byte) ((cmd >> 24) & 0xff);
+ buf[5] = (byte) ((cmd >> 16) & 0xff);
+ buf[6] = (byte) ((cmd >> 8) & 0xff);
+ buf[7] = (byte) (cmd & 0xff);
try {
mOut.write(buf, 0, 8);
mOut.write(data, 0, len);
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index 16a4f2d..57a29f2 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -29,25 +29,41 @@ namespace android {
// ----------------------------------------------------------------------------
-A2dpAudioInterface::A2dpAudioInterface() :
- mOutput(0)
+//AudioHardwareInterface* A2dpAudioInterface::createA2dpInterface()
+//{
+// AudioHardwareInterface* hw = 0;
+//
+// hw = AudioHardwareInterface::create();
+// LOGD("new A2dpAudioInterface(hw: %p)", hw);
+// hw = new A2dpAudioInterface(hw);
+// return hw;
+//}
+
+A2dpAudioInterface::A2dpAudioInterface(AudioHardwareInterface* hw) :
+ mOutput(0), mHardwareInterface(hw), mBluetoothEnabled(true)
{
}
A2dpAudioInterface::~A2dpAudioInterface()
{
- delete mOutput;
+ closeOutputStream((AudioStreamOut *)mOutput);
+ delete mHardwareInterface;
}
status_t A2dpAudioInterface::initCheck()
{
- return 0;
+ if (mHardwareInterface == 0) return NO_INIT;
+ return mHardwareInterface->initCheck();
}
AudioStreamOut* A2dpAudioInterface::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
- LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
+ if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {
+ LOGV("A2dpAudioInterface::openOutputStream() open HW device: %x", devices);
+ return mHardwareInterface->openOutputStream(devices, format, channels, sampleRate, status);
+ }
+
status_t err = 0;
// only one output stream allowed
@@ -59,71 +75,127 @@ AudioStreamOut* A2dpAudioInterface::openOutputStream(
// create new output stream
A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
- if ((err = out->set(format, channelCount, sampleRate)) == NO_ERROR) {
+ if ((err = out->set(devices, format, channels, sampleRate)) == NO_ERROR) {
mOutput = out;
+ mOutput->setBluetoothEnabled(mBluetoothEnabled);
} else {
delete out;
}
-
+
if (status)
*status = err;
return mOutput;
}
+void A2dpAudioInterface::closeOutputStream(AudioStreamOut* out) {
+ if (mOutput == 0 || mOutput != out) {
+ mHardwareInterface->closeOutputStream(out);
+ }
+ else {
+ delete mOutput;
+ mOutput = 0;
+ }
+}
+
+
AudioStreamIn* A2dpAudioInterface::openInputStream(
- int inputSource, int format, int channelCount, uint32_t sampleRate,
- status_t *status, AudioSystem::audio_in_acoustics acoustics)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
{
- if (status)
- *status = -1;
- return NULL;
+ return mHardwareInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+}
+
+void A2dpAudioInterface::closeInputStream(AudioStreamIn* in)
+{
+ return mHardwareInterface->closeInputStream(in);
+}
+
+status_t A2dpAudioInterface::setMode(int mode)
+{
+ return mHardwareInterface->setMode(mode);
}
status_t A2dpAudioInterface::setMicMute(bool state)
{
- return 0;
+ return mHardwareInterface->setMicMute(state);
}
status_t A2dpAudioInterface::getMicMute(bool* state)
{
- return 0;
+ return mHardwareInterface->getMicMute(state);
}
-status_t A2dpAudioInterface::setParameter(const char *key, const char *value)
+status_t A2dpAudioInterface::setParameters(const String8& keyValuePairs)
{
- LOGD("setParameter %s,%s\n", key, value);
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ String8 key;
+ status_t status = NO_ERROR;
+
+ LOGV("setParameters() %s", keyValuePairs.string());
+
+ key = "bluetooth_enabled";
+ if (param.get(key, value) == NO_ERROR) {
+ mBluetoothEnabled = (value == "true");
+ if (mOutput) {
+ mOutput->setBluetoothEnabled(mBluetoothEnabled);
+ }
+ param.remove(key);
+ }
- if (!key || !value)
- return -EINVAL;
+ if (param.size()) {
+ status_t hwStatus = mHardwareInterface->setParameters(param.toString());
+ if (status == NO_ERROR) {
+ status = hwStatus;
+ }
+ }
- if (strcmp(key, "a2dp_sink_address") == 0) {
- return mOutput->setAddress(value);
+ return status;
+}
+
+String8 A2dpAudioInterface::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ AudioParameter a2dpParam = AudioParameter();
+ String8 value;
+ String8 key;
+
+ key = "bluetooth_enabled";
+ if (param.get(key, value) == NO_ERROR) {
+ value = mBluetoothEnabled ? "true" : "false";
+ a2dpParam.add(key, value);
+ param.remove(key);
}
- if (strcmp(key, "bluetooth_enabled") == 0) {
- mOutput->setBluetoothEnabled(strcmp(value, "true") == 0);
+
+ String8 keyValuePairs = a2dpParam.toString();
+
+ if (param.size()) {
+ keyValuePairs += ";";
+ keyValuePairs += mHardwareInterface->getParameters(param.toString());
}
- return 0;
+ LOGV("getParameters() %s", keyValuePairs.string());
+ return keyValuePairs;
}
-status_t A2dpAudioInterface::setVoiceVolume(float v)
+size_t A2dpAudioInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
{
- return 0;
+ return mHardwareInterface->getInputBufferSize(sampleRate, format, channelCount);
}
-status_t A2dpAudioInterface::setMasterVolume(float v)
+status_t A2dpAudioInterface::setVoiceVolume(float v)
{
- return 0;
+ return mHardwareInterface->setVoiceVolume(v);
}
-status_t A2dpAudioInterface::doRouting()
+status_t A2dpAudioInterface::setMasterVolume(float v)
{
- return 0;
+ return mHardwareInterface->setMasterVolume(v);
}
status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
{
- return 0;
+ return mHardwareInterface->dumpState(fd, args);
}
// ----------------------------------------------------------------------------
@@ -132,7 +204,7 @@ A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
// assume BT enabled to start, this is safe because its only the
// enabled->disabled transition we are worried about
- mBluetoothEnabled(true)
+ mBluetoothEnabled(true), mDevice(0), mClosing(false)
{
// use any address by default
strcpy(mA2dpAddress, "00:00:00:00:00:00");
@@ -140,27 +212,43 @@ A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
}
status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
- int format, int channels, uint32_t rate)
+ uint32_t device, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
{
- LOGD("A2dpAudioStreamOut::set %d, %d, %d\n", format, channels, rate);
+ int lFormat = pFormat ? *pFormat : 0;
+ uint32_t lChannels = pChannels ? *pChannels : 0;
+ uint32_t lRate = pRate ? *pRate : 0;
+
+ LOGD("A2dpAudioStreamOut::set %x, %d, %d, %d\n", device, lFormat, lChannels, lRate);
// fix up defaults
- if (format == 0) format = AudioSystem::PCM_16_BIT;
- if (channels == 0) channels = channelCount();
- if (rate == 0) rate = sampleRate();
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
// check values
- if ((format != AudioSystem::PCM_16_BIT) ||
- (channels != channelCount()) ||
- (rate != sampleRate()))
+ if ((lFormat != format()) ||
+ (lChannels != channels()) ||
+ (lRate != sampleRate())){
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
return BAD_VALUE;
+ }
+
+ if (pFormat) *pFormat = lFormat;
+ if (pChannels) *pChannels = lChannels;
+ if (pRate) *pRate = lRate;
+ mDevice = device;
return NO_ERROR;
}
A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
{
+ LOGV("A2dpAudioStreamOut destructor");
+ standby();
close();
+ LOGV("A2dpAudioStreamOut destructor returning from close()");
}
ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
@@ -170,7 +258,7 @@ ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t
size_t remaining = bytes;
status_t status = -1;
- if (!mBluetoothEnabled) {
+ if (!mBluetoothEnabled || mClosing) {
LOGW("A2dpAudioStreamOut::write(), but bluetooth disabled");
goto Error;
}
@@ -219,6 +307,11 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
{
int result = 0;
+ if (mClosing) {
+ LOGV("Ignore standby, closing");
+ return result;
+ }
+
Mutex::Autolock lock(mLock);
if (!mStandby) {
@@ -230,6 +323,64 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
return result;
}
+status_t A2dpAudioInterface::A2dpAudioStreamOut::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ String8 key = String8("a2dp_sink_address");
+ status_t status = NO_ERROR;
+ int device;
+ LOGV("A2dpAudioStreamOut::setParameters() %s", keyValuePairs.string());
+
+ if (param.get(key, value) == NO_ERROR) {
+ if (value.length() != strlen("00:00:00:00:00:00")) {
+ status = BAD_VALUE;
+ } else {
+ setAddress(value.string());
+ }
+ param.remove(key);
+ }
+ key = String8("closing");
+ if (param.get(key, value) == NO_ERROR) {
+ mClosing = (value == "true");
+ param.remove(key);
+ }
+ key = AudioParameter::keyRouting;
+ if (param.getInt(key, device) == NO_ERROR) {
+ if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device)) {
+ mDevice = device;
+ status = NO_ERROR;
+ } else {
+ status = BAD_VALUE;
+ }
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 A2dpAudioInterface::A2dpAudioStreamOut::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8("a2dp_sink_address");
+
+ if (param.get(key, value) == NO_ERROR) {
+ value = mA2dpAddress;
+ param.add(key, value);
+ }
+ key = AudioParameter::keyRouting;
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ LOGV("A2dpAudioStreamOut::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
{
Mutex::Autolock lock(mLock);
@@ -260,12 +411,14 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::setBluetoothEnabled(bool enable
status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
{
Mutex::Autolock lock(mLock);
+ LOGV("A2dpAudioStreamOut::close() calling close_l()");
return close_l();
}
status_t A2dpAudioInterface::A2dpAudioStreamOut::close_l()
{
if (mData) {
+ LOGV("A2dpAudioStreamOut::close_l() calling a2dp_cleanup(mData)");
a2dp_cleanup(mData);
mData = NULL;
}
@@ -277,5 +430,4 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<Strin
return NO_ERROR;
}
-
}; // namespace android
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index 091e775..35a6e11 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -32,38 +32,44 @@ class A2dpAudioInterface : public AudioHardwareBase
class A2dpAudioStreamOut;
public:
- A2dpAudioInterface();
+ A2dpAudioInterface(AudioHardwareInterface* hw);
virtual ~A2dpAudioInterface();
virtual status_t initCheck();
virtual status_t setVoiceVolume(float volume);
virtual status_t setMasterVolume(float volume);
+ virtual status_t setMode(int mode);
+
// mic mute
virtual status_t setMicMute(bool state);
virtual status_t getMicMute(bool* state);
- // Temporary interface, do not use
- // TODO: Replace with a more generic key:value get/set mechanism
- virtual status_t setParameter(const char *key, const char *value);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
// create I/O streams
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
virtual AudioStreamIn* openInputStream(
- int inputSource,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
status_t *status,
AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
+// static AudioHardwareInterface* createA2dpInterface();
protected:
- virtual status_t doRouting();
virtual status_t dump(int fd, const Vector<String16>& args);
private:
@@ -71,19 +77,22 @@ private:
public:
A2dpAudioStreamOut();
virtual ~A2dpAudioStreamOut();
- status_t set(int format,
- int channelCount,
- uint32_t sampleRate);
+ status_t set(uint32_t device,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
virtual uint32_t sampleRate() const { return 44100; }
// SBC codec wants a multiple of 512
virtual size_t bufferSize() const { return 512 * 20; }
- virtual int channelCount() const { return 2; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual uint32_t latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
- virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
status_t standby();
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
private:
friend class A2dpAudioInterface;
@@ -102,11 +111,19 @@ private:
void* mData;
Mutex mLock;
bool mBluetoothEnabled;
+ uint32_t mDevice;
+ bool mClosing;
};
+ friend class A2dpAudioStreamOut;
+
A2dpAudioStreamOut* mOutput;
+ AudioHardwareInterface *mHardwareInterface;
+ char mA2dpAddress[20];
+ bool mBluetoothEnabled;
};
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index 50d516b..f5c03bb 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -1,16 +1,30 @@
LOCAL_PATH:= $(call my-dir)
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
include $(CLEAR_VARS)
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ ENABLE_AUDIO_DUMP := true
+endif
+
+
LOCAL_SRC_FILES:= \
AudioHardwareGeneric.cpp \
AudioHardwareStub.cpp \
- AudioDumpInterface.cpp \
AudioHardwareInterface.cpp
+ifeq ($(ENABLE_AUDIO_DUMP),true)
+ LOCAL_SRC_FILES += AudioDumpInterface.cpp
+ LOCAL_CFLAGS += -DENABLE_AUDIO_DUMP
+endif
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libmedia \
libhardware_legacy
@@ -20,8 +34,44 @@ endif
LOCAL_MODULE:= libaudiointerface
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_SRC_FILES += A2dpAudioInterface.cpp
+ LOCAL_SHARED_LIBRARIES += liba2dp
+ LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
+ LOCAL_C_INCLUDES += $(call include-path-for, bluez)
+endif
+
include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ AudioPolicyManagerGeneric.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_MODULE:= libaudiopolicygeneric
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -29,28 +79,45 @@ LOCAL_SRC_FILES:= \
AudioMixer.cpp.arm \
AudioResampler.cpp.arm \
AudioResamplerSinc.cpp.arm \
- AudioResamplerCubic.cpp.arm
+ AudioResamplerCubic.cpp.arm \
+ AudioPolicyService.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
+ libbinder \
libmedia \
- libhardware_legacy
+ libhardware_legacy \
+ libaudiopolicygeneric
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
LOCAL_STATIC_LIBRARIES += libaudiointerface
+ LOCAL_CFLAGS += -DGENERIC_AUDIO
+else
+ LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy
+endif
+
+ifeq ($(TARGET_SIMULATOR),true)
+ LOCAL_LDLIBS += -ldl
else
- LOCAL_SHARED_LIBRARIES += libaudio
+ LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_MODULE:= libaudioflinger
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
- LOCAL_SRC_FILES += A2dpAudioInterface.cpp
- LOCAL_SHARED_LIBRARIES += liba2dp
LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
- LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs)
- LOCAL_C_INCLUDES += $(call include-path-for, bluez-utils)
+ LOCAL_SHARED_LIBRARIES += liba2dp
+endif
+
+ifeq ($(AUDIO_POLICY_TEST),true)
+ LOCAL_CFLAGS += -DAUDIO_POLICY_TEST
+endif
+
+ifeq ($(TARGET_SIMULATOR),true)
+ ifeq ($(HOST_OS),linux)
+ LOCAL_LDLIBS += -lrt -lpthread
+ endif
endif
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
index b4940cb..858e5aa 100644
--- a/libs/audioflinger/AudioDumpInterface.cpp
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -16,6 +16,7 @@
*/
#define LOG_TAG "AudioFlingerDump"
+//#define LOG_NDEBUG 0
#include <stdint.h>
#include <sys/types.h>
@@ -28,68 +29,240 @@
namespace android {
-bool gFirst = true; // true if first write after a standby
-
// ----------------------------------------------------------------------------
AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
+ : mFirstHwOutput(true), mPolicyCommands(String8("")), mFileName(String8(""))
{
if(hw == 0) {
LOGE("Dump construct hw = 0");
}
mFinalInterface = hw;
- mStreamOut = 0;
+ LOGV("Constructor %p, mFinalInterface %p", this, mFinalInterface);
}
AudioDumpInterface::~AudioDumpInterface()
{
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ closeOutputStream((AudioStreamOut *)mOutputs[i]);
+ }
if(mFinalInterface) delete mFinalInterface;
- if(mStreamOut) delete mStreamOut;
}
AudioStreamOut* AudioDumpInterface::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
+{
+ AudioStreamOut* outFinal = NULL;
+ int lFormat = AudioSystem::PCM_16_BIT;
+ uint32_t lChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ uint32_t lRate = 44100;
+
+
+ if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices) || mFirstHwOutput) {
+ outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status);
+ if (outFinal != 0) {
+ lFormat = outFinal->format();
+ lChannels = outFinal->channels();
+ lRate = outFinal->sampleRate();
+ if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) {
+ mFirstHwOutput = false;
+ }
+ }
+ } else {
+ if (format != 0 && *format != 0) {
+ lFormat = *format;
+ } else {
+ lFormat = AudioSystem::PCM_16_BIT;
+ }
+ if (channels != 0 && *channels != 0) {
+ lChannels = *channels;
+ } else {
+ lChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ }
+ if (sampleRate != 0 && *sampleRate != 0) {
+ lRate = *sampleRate;
+ } else {
+ lRate = 44100;
+ }
+ if (status) *status = NO_ERROR;
+ }
+ LOGV("openOutputStream(), outFinal %p", outFinal);
+
+ AudioStreamOutDump *dumOutput = new AudioStreamOutDump(this, mOutputs.size(), outFinal,
+ devices, lFormat, lChannels, lRate);
+ mOutputs.add(dumOutput);
+
+ return dumOutput;
+}
+
+void AudioDumpInterface::closeOutputStream(AudioStreamOut* out)
+{
+ AudioStreamOutDump *dumpOut = (AudioStreamOutDump *)out;
+
+ if (mOutputs.indexOf(dumpOut) < 0) {
+ LOGW("Attempt to close invalid output stream");
+ return;
+ }
+
+ LOGV("closeOutputStream() output %p", out);
+
+ dumpOut->standby();
+ if (dumpOut->finalStream() != NULL) {
+ mFinalInterface->closeOutputStream(dumpOut->finalStream());
+ mFirstHwOutput = true;
+ }
+
+ mOutputs.remove(dumpOut);
+ delete dumpOut;
+}
+
+AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
- AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate, status);
+ AudioStreamIn* inFinal = NULL;
+ int lFormat = AudioSystem::PCM_16_BIT;
+ uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO;
+ uint32_t lRate = 8000;
- if(outFinal) {
- mStreamOut = new AudioStreamOutDump(outFinal);
- return mStreamOut;
+
+ if (mInputs.size() == 0) {
+ inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics);
+ if (inFinal == 0) return 0;
+
+ lFormat = inFinal->format();
+ lChannels = inFinal->channels();
+ lRate = inFinal->sampleRate();
} else {
- LOGE("Dump outFinal=0");
- return 0;
+ if (format != 0 && *format != 0) lFormat = *format;
+ if (channels != 0 && *channels != 0) lChannels = *channels;
+ if (sampleRate != 0 && *sampleRate != 0) lRate = *sampleRate;
+ if (status) *status = NO_ERROR;
}
+ LOGV("openInputStream(), inFinal %p", inFinal);
+
+ AudioStreamInDump *dumInput = new AudioStreamInDump(this, mInputs.size(), inFinal,
+ devices, lFormat, lChannels, lRate);
+ mInputs.add(dumInput);
+
+ return dumInput;
}
+void AudioDumpInterface::closeInputStream(AudioStreamIn* in)
+{
+ AudioStreamInDump *dumpIn = (AudioStreamInDump *)in;
+
+ if (mInputs.indexOf(dumpIn) < 0) {
+ LOGW("Attempt to close invalid input stream");
+ return;
+ }
+ dumpIn->standby();
+ if (dumpIn->finalStream() != NULL) {
+ mFinalInterface->closeInputStream(dumpIn->finalStream());
+ }
+
+ mInputs.remove(dumpIn);
+ delete dumpIn;
+}
+
+
+status_t AudioDumpInterface::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ int valueInt;
+ LOGV("setParameters %s", keyValuePairs.string());
+
+ if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+ mFileName = value;
+ param.remove(String8("test_cmd_file_name"));
+ }
+ if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+ Mutex::Autolock _l(mLock);
+ param.remove(String8("test_cmd_policy"));
+ mPolicyCommands = param.toString();
+ LOGV("test_cmd_policy command %s written", mPolicyCommands.string());
+ return NO_ERROR;
+ }
+
+ if (mFinalInterface != 0 ) return mFinalInterface->setParameters(keyValuePairs);
+ return NO_ERROR;
+}
+
+String8 AudioDumpInterface::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ AudioParameter response;
+ String8 value;
+
+// LOGV("getParameters %s", keys.string());
+ if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) {
+ Mutex::Autolock _l(mLock);
+ if (mPolicyCommands.length() != 0) {
+ response = AudioParameter(mPolicyCommands);
+ response.addInt(String8("test_cmd_policy"), 1);
+ } else {
+ response.addInt(String8("test_cmd_policy"), 0);
+ }
+ param.remove(String8("test_cmd_policy"));
+// LOGV("test_cmd_policy command %s read", mPolicyCommands.string());
+ }
+
+ if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) {
+ response.add(String8("test_cmd_file_name"), mFileName);
+ param.remove(String8("test_cmd_file_name"));
+ }
+
+ String8 keyValuePairs = response.toString();
+
+ if (param.size() && mFinalInterface != 0 ) {
+ keyValuePairs += ";";
+ keyValuePairs += mFinalInterface->getParameters(param.toString());
+ }
+
+ return keyValuePairs;
+}
+
// ----------------------------------------------------------------------------
-AudioStreamOutDump::AudioStreamOutDump( AudioStreamOut* finalStream)
+AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamOut* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate)
+ : mInterface(interface), mId(id),
+ mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices),
+ mBufferSize(1024), mFinalStream(finalStream), mOutFile(0), mFileCount(0)
{
- mFinalStream = finalStream;
- mOutFile = 0;
+ LOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
}
AudioStreamOutDump::~AudioStreamOutDump()
{
+ LOGV("AudioStreamOutDump destructor");
Close();
- delete mFinalStream;
}
ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
{
ssize_t ret;
- ret = mFinalStream->write(buffer, bytes);
- if(!mOutFile && gFirst) {
- gFirst = false;
- // check if dump file exist
- mOutFile = fopen(FLINGER_DUMP_NAME, "r");
- if(mOutFile) {
- fclose(mOutFile);
- mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+ if (mFinalStream) {
+ ret = mFinalStream->write(buffer, bytes);
+ } else {
+ usleep((bytes * 1000000) / frameSize() / sampleRate());
+ ret = bytes;
+ }
+ if(!mOutFile) {
+ if (mInterface->fileName() != "") {
+ char name[255];
+ sprintf(name, "%s_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount);
+ mOutFile = fopen(name, "wb");
+ LOGV("Opening dump file %s, fh %p", name, mOutFile);
}
}
if (mOutFile) {
@@ -100,13 +273,105 @@ ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
status_t AudioStreamOutDump::standby()
{
+ LOGV("AudioStreamOutDump standby(), mOutFile %p, mFinalStream %p", mOutFile, mFinalStream);
+
Close();
- gFirst = true;
- return mFinalStream->standby();
+ if (mFinalStream != 0 ) return mFinalStream->standby();
+ return NO_ERROR;
+}
+
+uint32_t AudioStreamOutDump::sampleRate() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+ return mSampleRate;
+}
+
+size_t AudioStreamOutDump::bufferSize() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+ return mBufferSize;
+}
+
+uint32_t AudioStreamOutDump::channels() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->channels();
+ return mChannels;
+}
+int AudioStreamOutDump::format() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->format();
+ return mFormat;
+}
+uint32_t AudioStreamOutDump::latency() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->latency();
+ return 0;
+}
+status_t AudioStreamOutDump::setVolume(float left, float right)
+{
+ if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right);
+ return NO_ERROR;
+}
+status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs)
+{
+ LOGV("AudioStreamOutDump::setParameters %s", keyValuePairs.string());
+
+ if (mFinalStream != 0 ) {
+ return mFinalStream->setParameters(keyValuePairs);
+ }
+
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ int valueInt;
+ status_t status = NO_ERROR;
+
+ if (param.getInt(String8("set_id"), valueInt) == NO_ERROR) {
+ mId = valueInt;
+ }
+
+ if (param.getInt(String8("format"), valueInt) == NO_ERROR) {
+ if (mOutFile == 0) {
+ mFormat = valueInt;
+ } else {
+ status = INVALID_OPERATION;
+ }
+ }
+ if (param.getInt(String8("channels"), valueInt) == NO_ERROR) {
+ if (valueInt == AudioSystem::CHANNEL_OUT_STEREO || valueInt == AudioSystem::CHANNEL_OUT_MONO) {
+ mChannels = valueInt;
+ } else {
+ status = BAD_VALUE;
+ }
+ }
+ if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) {
+ if (valueInt > 0 && valueInt <= 48000) {
+ if (mOutFile == 0) {
+ mSampleRate = valueInt;
+ } else {
+ status = INVALID_OPERATION;
+ }
+ } else {
+ status = BAD_VALUE;
+ }
+ }
+ return status;
}
+String8 AudioStreamOutDump::getParameters(const String8& keys)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
-void AudioStreamOutDump::Close(void)
+status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
+
+void AudioStreamOutDump::Close()
{
if(mOutFile) {
fclose(mOutFile);
@@ -114,4 +379,141 @@ void AudioStreamOutDump::Close(void)
}
}
+// ----------------------------------------------------------------------------
+
+AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamIn* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate)
+ : mInterface(interface), mId(id),
+ mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices),
+ mBufferSize(1024), mFinalStream(finalStream), mInFile(0)
+{
+ LOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream);
+}
+
+
+AudioStreamInDump::~AudioStreamInDump()
+{
+ Close();
+}
+
+ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes)
+{
+ if (mFinalStream) {
+ return mFinalStream->read(buffer, bytes);
+ }
+
+ usleep((bytes * 1000000) / frameSize() / sampleRate());
+
+ if(!mInFile) {
+ char name[255];
+ strcpy(name, "/sdcard/music/sine440");
+ if (channels() == AudioSystem::CHANNEL_IN_MONO) {
+ strcat(name, "_mo");
+ } else {
+ strcat(name, "_st");
+ }
+ if (format() == AudioSystem::PCM_16_BIT) {
+ strcat(name, "_16b");
+ } else {
+ strcat(name, "_8b");
+ }
+ if (sampleRate() < 16000) {
+ strcat(name, "_8k");
+ } else if (sampleRate() < 32000) {
+ strcat(name, "_22k");
+ } else if (sampleRate() < 48000) {
+ strcat(name, "_44k");
+ } else {
+ strcat(name, "_48k");
+ }
+ strcat(name, ".wav");
+ mInFile = fopen(name, "rb");
+ LOGV("Opening dump file %s, fh %p", name, mInFile);
+ if (mInFile) {
+ fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+ }
+
+ }
+ if (mInFile) {
+ ssize_t bytesRead = fread(buffer, bytes, 1, mInFile);
+ if (bytesRead != bytes) {
+ fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET);
+ fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mInFile);
+ }
+ }
+ return bytes;
+}
+
+status_t AudioStreamInDump::standby()
+{
+ LOGV("AudioStreamInDump standby(), mInFile %p, mFinalStream %p", mInFile, mFinalStream);
+
+ Close();
+ if (mFinalStream != 0 ) return mFinalStream->standby();
+ return NO_ERROR;
+}
+
+status_t AudioStreamInDump::setGain(float gain)
+{
+ if (mFinalStream != 0 ) return mFinalStream->setGain(gain);
+ return NO_ERROR;
+}
+
+uint32_t AudioStreamInDump::sampleRate() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->sampleRate();
+ return mSampleRate;
+}
+
+size_t AudioStreamInDump::bufferSize() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->bufferSize();
+ return mBufferSize;
+}
+
+uint32_t AudioStreamInDump::channels() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->channels();
+ return mChannels;
+}
+
+int AudioStreamInDump::format() const
+{
+ if (mFinalStream != 0 ) return mFinalStream->format();
+ return mFormat;
+}
+
+status_t AudioStreamInDump::setParameters(const String8& keyValuePairs)
+{
+ LOGV("AudioStreamInDump::setParameters()");
+ if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs);
+ return NO_ERROR;
+}
+
+String8 AudioStreamInDump::getParameters(const String8& keys)
+{
+ if (mFinalStream != 0 ) return mFinalStream->getParameters(keys);
+
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
+status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args)
+{
+ if (mFinalStream != 0 ) return mFinalStream->dump(fd, args);
+ return NO_ERROR;
+}
+
+void AudioStreamInDump::Close()
+{
+ if(mInFile) {
+ fclose(mInFile);
+ mInFile = 0;
+ }
+}
}; // namespace android
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index b72c94e..1136ce1 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -20,35 +20,95 @@
#include <stdint.h>
#include <sys/types.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
#include <hardware_legacy/AudioHardwareBase.h>
namespace android {
-#define FLINGER_DUMP_NAME "/data/FlingerOut.pcm" // name of file used for dump
+#define AUDIO_DUMP_WAVE_HDR_SIZE 44
+
+class AudioDumpInterface;
class AudioStreamOutDump : public AudioStreamOut {
public:
- AudioStreamOutDump( AudioStreamOut* FinalStream);
+ AudioStreamOutDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamOut* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate);
~AudioStreamOutDump();
- virtual ssize_t write(const void* buffer, size_t bytes);
-
- virtual uint32_t sampleRate() const { return mFinalStream->sampleRate(); }
- virtual size_t bufferSize() const { return mFinalStream->bufferSize(); }
- virtual int channelCount() const { return mFinalStream->channelCount(); }
- virtual int format() const { return mFinalStream->format(); }
- virtual uint32_t latency() const { return mFinalStream->latency(); }
- virtual status_t setVolume(float volume)
- { return mFinalStream->setVolume(volume); }
+
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual uint32_t sampleRate() const;
+ virtual size_t bufferSize() const;
+ virtual uint32_t channels() const;
+ virtual int format() const;
+ virtual uint32_t latency() const;
+ virtual status_t setVolume(float left, float right);
virtual status_t standby();
- virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalStream->dump(fd, args); }
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t dump(int fd, const Vector<String16>& args);
void Close(void);
+ AudioStreamOut* finalStream() { return mFinalStream; }
+ uint32_t device() { return mDevice; }
+ int getId() { return mId; }
private:
+ AudioDumpInterface *mInterface;
+ int mId;
+ uint32_t mSampleRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mLatency; //
+ uint32_t mDevice; // current device this output is routed to
+ size_t mBufferSize;
AudioStreamOut *mFinalStream;
- FILE *mOutFile; // output file
+ FILE *mOutFile; // output file
+ int mFileCount;
};
+class AudioStreamInDump : public AudioStreamIn {
+public:
+ AudioStreamInDump(AudioDumpInterface *interface,
+ int id,
+ AudioStreamIn* finalStream,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t sampleRate);
+ ~AudioStreamInDump();
+
+ virtual uint32_t sampleRate() const;
+ virtual size_t bufferSize() const;
+ virtual uint32_t channels() const;
+ virtual int format() const;
+
+ virtual status_t setGain(float gain);
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ void Close(void);
+ AudioStreamIn* finalStream() { return mFinalStream; }
+ uint32_t device() { return mDevice; }
+
+private:
+ AudioDumpInterface *mInterface;
+ int mId;
+ uint32_t mSampleRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mDevice; // current device this output is routed to
+ size_t mBufferSize;
+ AudioStreamIn *mFinalStream;
+ FILE *mInFile; // output file
+};
class AudioDumpInterface : public AudioHardwareBase
{
@@ -56,10 +116,13 @@ class AudioDumpInterface : public AudioHardwareBase
public:
AudioDumpInterface(AudioHardwareInterface* hw);
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
+
virtual ~AudioDumpInterface();
virtual status_t initCheck()
@@ -75,21 +138,25 @@ public:
virtual status_t getMicMute(bool* state)
{return mFinalInterface->getMicMute(state);}
- virtual status_t setParameter(const char* key, const char* value)
- {return mFinalInterface->setParameter(key, value);}
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
- virtual AudioStreamIn* openInputStream(int inputSource, int format, int channelCount,
- uint32_t sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics)
- { return mFinalInterface->openInputStream(inputSource, format, channelCount, sampleRate, status, acoustics); }
+ virtual AudioStreamIn* openInputStream(uint32_t devices, int *format, uint32_t *channels,
+ uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
+ String8 fileName() const { return mFileName; }
protected:
- virtual status_t doRouting() {return mFinalInterface->setRouting(mMode, mRoutes[mMode]);}
-
- AudioHardwareInterface *mFinalInterface;
- AudioStreamOutDump *mStreamOut;
+ AudioHardwareInterface *mFinalInterface;
+ SortedVector<AudioStreamOutDump *> mOutputs;
+ bool mFirstHwOutput;
+ SortedVector<AudioStreamInDump *> mInputs;
+ Mutex mLock;
+ String8 mPolicyCommands;
+ String8 mFileName;
};
}; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index da7cc8a..3a419b5 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>
@@ -71,15 +71,9 @@ static const float MAX_GAIN = 4096.0f;
static const int8_t kMaxTrackRetries = 50;
static const int8_t kMaxTrackStartupRetries = 50;
-static const int kStartSleepTime = 30000;
-static const int kStopSleepTime = 30000;
-
static const int kDumpLockRetries = 50;
static const int kDumpLockSleep = 20000;
-// Maximum number of pending buffers allocated by OutputTrack::write()
-static const uint8_t kMaxOutputTrackBuffers = 5;
-
#define AUDIOFLINGER_SECURITY_ENABLED 1
@@ -121,132 +115,41 @@ static bool settingsAllowed() {
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
- mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false),
- mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0),
- mRouteRestoreTime(0), mMusicMuteSaved(false)
+ mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)
{
mHardwareStatus = AUDIO_HW_IDLE;
+
mAudioHardware = AudioHardwareInterface::create();
+
mHardwareStatus = AUDIO_HW_INIT;
if (mAudioHardware->initCheck() == NO_ERROR) {
// open 16-bit output stream for s/w mixer
- mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
- status_t status;
- AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
- mHardwareStatus = AUDIO_HW_IDLE;
- if (hwOutput) {
- mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
- } else {
- LOGE("Failed to initialize hardware output stream, status: %d", status);
- }
-
-#ifdef WITH_A2DP
- // Create A2DP interface
- mA2dpAudioInterface = new A2dpAudioInterface();
- AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
- if (a2dpOutput) {
- mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
- if (hwOutput) {
- uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
- MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
- hwOutput->sampleRate(),
- AudioSystem::PCM_16_BIT,
- hwOutput->channelCount(),
- frameCount);
- mHardwareMixerThread->setOuputTrack(a2dpOutTrack);
- }
- } else {
- LOGE("Failed to initialize A2DP output stream, status: %d", status);
- }
-#endif
-
- // FIXME - this should come from settings
- setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+
setMode(AudioSystem::MODE_NORMAL);
setMasterVolume(1.0f);
setMasterMute(false);
-
- // Start record thread
- mAudioRecordThread = new AudioRecordThread(mAudioHardware, this);
- if (mAudioRecordThread != 0) {
- mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
- }
- } else {
+ } else {
LOGE("Couldn't even initialize the stubbed audio hardware!");
}
}
AudioFlinger::~AudioFlinger()
{
- if (mAudioRecordThread != 0) {
- mAudioRecordThread->exit();
- mAudioRecordThread.clear();
+ while (!mRecordThreads.isEmpty()) {
+ // closeInput() will remove first entry from mRecordThreads
+ closeInput(mRecordThreads.keyAt(0));
}
- mHardwareMixerThread.clear();
- delete mAudioHardware;
- // deleting mA2dpAudioInterface also deletes mA2dpOutput;
-#ifdef WITH_A2DP
- mA2dpMixerThread.clear();
- delete mA2dpAudioInterface;
-#endif
-}
-
-
-#ifdef WITH_A2DP
-// setA2dpEnabled_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::setA2dpEnabled_l(bool enable)
-{
- SortedVector < sp<MixerThread::Track> > tracks;
- SortedVector < wp<MixerThread::Track> > activeTracks;
-
- LOGD_IF(enable, "set output to A2DP\n");
- LOGD_IF(!enable, "set output to hardware audio\n");
-
- // Transfer tracks playing on MUSIC stream from one mixer to the other
- if (enable) {
- mHardwareMixerThread->getTracks_l(tracks, activeTracks);
- mA2dpMixerThread->putTracks_l(tracks, activeTracks);
- } else {
- mA2dpMixerThread->getTracks_l(tracks, activeTracks);
- mHardwareMixerThread->putTracks_l(tracks, activeTracks);
- mA2dpMixerThread->mOutput->standby();
+ while (!mPlaybackThreads.isEmpty()) {
+ // closeOutput() will remove first entry from mPlaybackThreads
+ closeOutput(mPlaybackThreads.keyAt(0));
}
- mA2dpEnabled = enable;
- mNotifyA2dpChange = true;
- mWaitWorkCV.broadcast();
-}
-
-// checkA2dpEnabledChange_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::checkA2dpEnabledChange_l()
-{
- if (mNotifyA2dpChange) {
- // Notify AudioSystem of the A2DP activation/deactivation
- size_t size = mNotificationClients.size();
- for (size_t i = 0; i < size; i++) {
- sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
- if (binder != NULL) {
- LOGV("Notifying output change to client %p", binder.get());
- sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
- client->a2dpEnabledChanged(mA2dpEnabled);
- }
- }
- mNotifyA2dpChange = false;
+ if (mAudioHardware) {
+ delete mAudioHardware;
}
}
-#endif // WITH_A2DP
-bool AudioFlinger::streamForcedToSpeaker(int streamType)
-{
- // NOTE that streams listed here must not be routed to A2DP by default:
- // AudioSystem::routedToA2dpOutput(streamType) == false
- return (streamType == AudioSystem::RING ||
- streamType == AudioSystem::ALARM ||
- streamType == AudioSystem::NOTIFICATION ||
- streamType == AudioSystem::ENFORCED_AUDIBLE);
-}
+
status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
{
@@ -276,10 +179,7 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
char buffer[SIZE];
String8 result;
int hardwareStatus = mHardwareStatus;
-
- if (hardwareStatus == AUDIO_HW_IDLE && mHardwareMixerThread->mStandby) {
- hardwareStatus = AUDIO_HW_STANDBY;
- }
+
snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
result.append(buffer);
write(fd, result.string(), result.size());
@@ -337,13 +237,16 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
dumpClients(fd, args);
dumpInternals(fd, args);
- mHardwareMixerThread->dump(fd, args);
-#ifdef WITH_A2DP
- mA2dpMixerThread->dump(fd, args);
-#endif
- // dump record client
- if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args);
+ // dump playback threads
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ mPlaybackThreads.valueAt(i)->dump(fd, args);
+ }
+
+ // dump record threads
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads.valueAt(i)->dump(fd, args);
+ }
if (mAudioHardware) {
mAudioHardware->dumpState(fd, args);
@@ -353,6 +256,7 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
+
// IAudioFlinger interface
@@ -365,9 +269,10 @@ sp<IAudioTrack> AudioFlinger::createTrack(
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ int output,
status_t *status)
{
- sp<MixerThread::Track> track;
+ sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
wp<Client> wclient;
@@ -381,6 +286,12 @@ sp<IAudioTrack> AudioFlinger::createTrack(
{
Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGE("unknown output thread");
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
wclient = mClients.valueFor(pid);
@@ -390,16 +301,8 @@ sp<IAudioTrack> AudioFlinger::createTrack(
client = new Client(this, pid);
mClients.add(pid, client);
}
-#ifdef WITH_A2DP
- if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) {
- track = mA2dpMixerThread->createTrack_l(client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer, &lStatus);
- } else
-#endif
- {
- track = mHardwareMixerThread->createTrack_l(client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer, &lStatus);
- }
+ track = thread->createTrack_l(client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer, &lStatus);
}
if (lStatus == NO_ERROR) {
trackHandle = new TrackHandle(track);
@@ -416,52 +319,57 @@ Exit:
uint32_t AudioFlinger::sampleRate(int output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->sampleRate();
- }
-#endif
- return mHardwareMixerThread->sampleRate();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("sampleRate() unknown thread %d", output);
+ return 0;
+ }
+ return thread->sampleRate();
}
int AudioFlinger::channelCount(int output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->channelCount();
- }
-#endif
- return mHardwareMixerThread->channelCount();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("channelCount() unknown thread %d", output);
+ return 0;
+ }
+ return thread->channelCount();
}
int AudioFlinger::format(int output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->format();
- }
-#endif
- return mHardwareMixerThread->format();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("format() unknown thread %d", output);
+ return 0;
+ }
+ return thread->format();
}
size_t AudioFlinger::frameCount(int output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->frameCount();
- }
-#endif
- return mHardwareMixerThread->frameCount();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("frameCount() unknown thread %d", output);
+ return 0;
+ }
+ return thread->frameCount();
}
uint32_t AudioFlinger::latency(int output) const
{
-#ifdef WITH_A2DP
- if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
- return mA2dpMixerThread->latency();
- }
-#endif
- return mHardwareMixerThread->latency();
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ LOGW("latency() unknown thread %d", output);
+ return 0;
+ }
+ return thread->latency();
}
status_t AudioFlinger::setMasterVolume(float value)
@@ -478,94 +386,12 @@ status_t AudioFlinger::setMasterVolume(float value)
value = 1.0f;
}
mHardwareStatus = AUDIO_HW_IDLE;
- mHardwareMixerThread->setMasterVolume(value);
-#ifdef WITH_A2DP
- mA2dpMixerThread->setMasterVolume(value);
-#endif
-
- return NO_ERROR;
-}
-
-status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
-{
- status_t err = NO_ERROR;
-
- // check calling permissions
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
- if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) {
- LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask);
- return BAD_VALUE;
- }
-
-#ifdef WITH_A2DP
- LOGV("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(),
- IPCThreadState::self()->getCallingPid());
- if (mode == AudioSystem::MODE_NORMAL &&
- (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
- AutoMutex lock(&mLock);
-
- bool enableA2dp = false;
- if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
- enableA2dp = true;
- }
- if (mA2dpDisableCount > 0) {
- mA2dpSuppressed = enableA2dp;
- } else {
- setA2dpEnabled_l(enableA2dp);
- }
- LOGV("setOutput done\n");
- }
- // setRouting() is always called at least for mode == AudioSystem::MODE_IN_CALL when
- // SCO is enabled, whatever current mode is so we can safely handle A2DP disabling only
- // in this case to avoid doing it several times.
- if (mode == AudioSystem::MODE_IN_CALL &&
- (mask & AudioSystem::ROUTE_BLUETOOTH_SCO)) {
- AutoMutex lock(&mLock);
- handleRouteDisablesA2dp_l(routes);
- }
-#endif
- // do nothing if only A2DP routing is affected
- mask &= ~AudioSystem::ROUTE_BLUETOOTH_A2DP;
- if (mask) {
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_HW_GET_ROUTING;
- uint32_t r;
- err = mAudioHardware->getRouting(mode, &r);
- if (err == NO_ERROR) {
- r = (r & ~mask) | (routes & mask);
- if (mode == AudioSystem::MODE_NORMAL ||
- (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
- mSavedRoute = r;
- r |= mForcedRoute;
- LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute);
- }
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- err = mAudioHardware->setRouting(mode, r);
- }
- mHardwareStatus = AUDIO_HW_IDLE;
- }
- return err;
-}
+ mMasterVolume = value;
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads.valueAt(i)->setMasterVolume(value);
-uint32_t AudioFlinger::getRouting(int mode) const
-{
- uint32_t routes = 0;
- if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
- if (mode == AudioSystem::MODE_NORMAL ||
- (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
- routes = mSavedRoute;
- } else {
- mHardwareStatus = AUDIO_HW_GET_ROUTING;
- mAudioHardware->getRouting(mode, &routes);
- mHardwareStatus = AUDIO_HW_IDLE;
- }
- } else {
- LOGW("Illegal value: getRouting(%d)", mode);
- }
- return routes;
+ return NO_ERROR;
}
status_t AudioFlinger::setMode(int mode)
@@ -586,15 +412,6 @@ status_t AudioFlinger::setMode(int mode)
return ret;
}
-int AudioFlinger::getMode() const
-{
- int mode = AudioSystem::MODE_INVALID;
- mHardwareStatus = AUDIO_HW_SET_MODE;
- mAudioHardware->getMode(&mode);
- mHardwareStatus = AUDIO_HW_IDLE;
- return mode;
-}
-
status_t AudioFlinger::setMicMute(bool state)
{
// check calling permissions
@@ -624,36 +441,46 @@ status_t AudioFlinger::setMasterMute(bool muted)
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
- mHardwareMixerThread->setMasterMute(muted);
-#ifdef WITH_A2DP
- mA2dpMixerThread->setMasterMute(muted);
-#endif
+
+ mMasterMute = muted;
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads.valueAt(i)->setMasterMute(muted);
+
return NO_ERROR;
}
float AudioFlinger::masterVolume() const
{
- return mHardwareMixerThread->masterVolume();
+ return mMasterVolume;
}
bool AudioFlinger::masterMute() const
{
- return mHardwareMixerThread->masterMute();
+ return mMasterMute;
}
-status_t AudioFlinger::setStreamVolume(int stream, float value)
+status_t AudioFlinger::setStreamVolume(int stream, float value, int output)
{
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES ||
- uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) {
+ if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return BAD_VALUE;
}
+ AutoMutex lock(mLock);
+ PlaybackThread *thread = NULL;
+ if (output) {
+ thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+ }
+
status_t ret = NO_ERROR;
+
if (stream == AudioSystem::VOICE_CALL ||
stream == AudioSystem::BLUETOOTH_SCO) {
float hwValue;
@@ -670,12 +497,18 @@ 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
+ mStreamTypes[stream].volume = value;
+
+ if (thread == NULL) {
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
+
+ } else {
+ thread->setStreamVolume(stream, value);
+ }
return ret;
}
@@ -687,82 +520,116 @@ status_t AudioFlinger::setStreamMute(int stream, bool muted)
return PERMISSION_DENIED;
}
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES ||
+ if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES ||
uint32_t(stream) == AudioSystem::ENFORCED_AUDIBLE) {
return BAD_VALUE;
}
-#ifdef WITH_A2DP
- mA2dpMixerThread->setStreamMute(stream, muted);
-#endif
- if (stream == AudioSystem::MUSIC)
- {
- AutoMutex lock(&mHardwareLock);
- if (mForcedRoute != 0)
- mMusicMuteSaved = muted;
- else
- mHardwareMixerThread->setStreamMute(stream, muted);
- } else {
- mHardwareMixerThread->setStreamMute(stream, muted);
- }
+ mStreamTypes[stream].mute = muted;
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ mPlaybackThreads.valueAt(i)->setStreamMute(stream, muted);
return NO_ERROR;
}
-float AudioFlinger::streamVolume(int stream) const
+float AudioFlinger::streamVolume(int stream, int output) const
{
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+ if (stream < 0 || uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
return 0.0f;
}
-
- float volume = mHardwareMixerThread->streamVolume(stream);
+
+ AutoMutex lock(mLock);
+ float volume;
+ if (output) {
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return 0.0f;
+ }
+ volume = thread->streamVolume(stream);
+ } else {
+ volume = mStreamTypes[stream].volume;
+ }
+
// remove correction applied by setStreamVolume()
if (stream == AudioSystem::VOICE_CALL) {
volume = (volume - 0.01) / 0.99 ;
}
-
+
return volume;
}
bool AudioFlinger::streamMute(int stream) const
{
- if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+ if (stream < 0 || stream >= (int)AudioSystem::NUM_STREAM_TYPES) {
return true;
}
-
- if (stream == AudioSystem::MUSIC && mForcedRoute != 0)
- {
- return mMusicMuteSaved;
- }
- return mHardwareMixerThread->streamMute(stream);
+
+ return mStreamTypes[stream].mute;
}
bool AudioFlinger::isMusicActive() const
{
Mutex::Autolock _l(mLock);
- #ifdef WITH_A2DP
- if (isA2dpEnabled()) {
- return mA2dpMixerThread->isMusicActive_l();
- }
- #endif
- return mHardwareMixerThread->isMusicActive_l();
+ for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i)->isMusicActive()) {
+ return true;
+ }
+ }
+ return false;
}
-status_t AudioFlinger::setParameter(const char* key, const char* value)
+status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)
{
- status_t result, result2;
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_SET_PARAMETER;
-
- LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid());
- result = mAudioHardware->setParameter(key, value);
- if (mA2dpAudioInterface) {
- result2 = mA2dpAudioInterface->setParameter(key, value);
- if (result2)
- result = result2;
+ status_t result;
+
+ LOGV("setParameters(): io %d, keyvalue %s, tid %d, calling tid %d",
+ ioHandle, keyValuePairs.string(), gettid(), IPCThreadState::self()->getCallingPid());
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
}
- mHardwareStatus = AUDIO_HW_IDLE;
- return result;
+
+ // ioHandle == 0 means the parameters are global to the audio hardware interface
+ if (ioHandle == 0) {
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_SET_PARAMETER;
+ result = mAudioHardware->setParameters(keyValuePairs);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return result;
+ }
+
+ // Check if parameters are for an output
+ PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
+ if (playbackThread != NULL) {
+ return playbackThread->setParameters(keyValuePairs);
+ }
+
+ // Check if parameters are for an input
+ RecordThread *recordThread = checkRecordThread_l(ioHandle);
+ if (recordThread != NULL) {
+ return recordThread->setParameters(keyValuePairs);
+ }
+
+ return BAD_VALUE;
+}
+
+String8 AudioFlinger::getParameters(int ioHandle, const String8& keys)
+{
+// LOGV("getParameters() io %d, keys %s, tid %d, calling tid %d",
+// ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
+
+ if (ioHandle == 0) {
+ return mAudioHardware->getParameters(keys);
+ }
+ PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
+ if (playbackThread != NULL) {
+ return playbackThread->getParameters(keys);
+ }
+ RecordThread *recordThread = checkRecordThread_l(ioHandle);
+ if (recordThread != NULL) {
+ return recordThread->getParameters(keys);
+ }
+ return String8("");
}
size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
@@ -772,7 +639,7 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int cha
void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
{
-
+
LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
Mutex::Autolock _l(mLock);
@@ -781,12 +648,21 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
LOGV("Adding notification client %p", binder.get());
binder->linkToDeath(this);
mNotificationClients.add(binder);
- client->a2dpEnabledChanged(isA2dpEnabled());
+ }
+
+ // the config change is always sent from playback or record threads to avoid deadlock
+ // with AudioSystem::gLock
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED);
+ }
+
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED);
}
}
void AudioFlinger::binderDied(const wp<IBinder>& who) {
-
+
LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
Mutex::Autolock _l(mLock);
@@ -801,6 +677,36 @@ void AudioFlinger::binderDied(const wp<IBinder>& who) {
}
}
+void AudioFlinger::audioConfigChanged(int event, const sp<ThreadBase>& thread, void *param2) {
+ Mutex::Autolock _l(mLock);
+ int ioHandle = 0;
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i) == thread) {
+ ioHandle = mPlaybackThreads.keyAt(i);
+ break;
+ }
+ }
+ if (ioHandle == 0) {
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ if (mRecordThreads.valueAt(i) == thread) {
+ ioHandle = mRecordThreads.keyAt(i);
+ break;
+ }
+ }
+ }
+
+ if (ioHandle != 0) {
+ size_t size = mNotificationClients.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<IBinder> binder = mNotificationClients.itemAt(i);
+ LOGV("audioConfigChanged() Notifying change to client %p", binder.get());
+ sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+ client->ioConfigChanged(event, ioHandle, param2);
+ }
+ }
+}
+
void AudioFlinger::removeClient(pid_t pid)
{
LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
@@ -808,147 +714,146 @@ void AudioFlinger::removeClient(pid_t pid)
mClients.removeItem(pid);
}
-bool AudioFlinger::isA2dpEnabled() const
+// ----------------------------------------------------------------------------
+
+AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger)
+ : Thread(false),
+ mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
+ mFormat(0), mFrameSize(1), mStandby(false)
{
- return mA2dpEnabled;
}
-void AudioFlinger::handleForcedSpeakerRoute(int command)
+AudioFlinger::ThreadBase::~ThreadBase()
{
- switch(command) {
- case ACTIVE_TRACK_ADDED:
- {
- AutoMutex lock(mHardwareLock);
- if (mForcedSpeakerCount++ == 0) {
- if (mForcedRoute == 0) {
- mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
- LOGV("++mForcedSpeakerCount == 0, mMusicMuteSaved = %d, mRouteRestoreTime = %d", mMusicMuteSaved, mRouteRestoreTime);
- if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
- LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
- mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
- usleep(mHardwareMixerThread->latency()*1000);
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
- mHardwareStatus = AUDIO_HW_IDLE;
- // delay track start so that audio hardware has time to siwtch routes
- usleep(kStartSleepTime);
- }
- }
- mForcedRoute = AudioSystem::ROUTE_SPEAKER;
- mRouteRestoreTime = 0;
- }
- LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
- }
- break;
- case ACTIVE_TRACK_REMOVED:
- {
- AutoMutex lock(mHardwareLock);
- if (mForcedSpeakerCount > 0){
- if (--mForcedSpeakerCount == 0) {
- mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
- }
- LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);
- } else {
- LOGE("mForcedSpeakerCount is already zero");
- }
- }
- break;
- case CHECK_ROUTE_RESTORE_TIME:
- case FORCE_ROUTE_RESTORE:
- if (mRouteRestoreTime) {
- AutoMutex lock(mHardwareLock);
- if (mRouteRestoreTime &&
- (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) {
- mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved);
- mForcedRoute = 0;
- if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute);
- mHardwareStatus = AUDIO_HW_IDLE;
- LOGV("Route forced to Speaker OFF %08x", mSavedRoute);
- }
- mRouteRestoreTime = 0;
- }
- }
- break;
- }
+ mParamCond.broadcast();
+ mNewParameters.clear();
}
-#ifdef WITH_A2DP
-// handleRouteDisablesA2dp_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::handleRouteDisablesA2dp_l(int routes)
-{
- if (routes & AudioSystem::ROUTE_BLUETOOTH_SCO) {
- if (mA2dpDisableCount++ == 0) {
- if (mA2dpEnabled) {
- setA2dpEnabled_l(false);
- mA2dpSuppressed = true;
- }
- }
- LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount);
- } else {
- if (mA2dpDisableCount > 0) {
- if (--mA2dpDisableCount == 0) {
- if (mA2dpSuppressed) {
- setA2dpEnabled_l(true);
- mA2dpSuppressed = false;
- }
- }
- LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount);
- } else {
- LOGV("mA2dpDisableCount is already zero");
- }
+void AudioFlinger::ThreadBase::exit()
+{
+ // keep a strong ref on ourself so that we want get
+ // destroyed in the middle of requestExitAndWait()
+ sp <ThreadBase> strongMe = this;
+
+ LOGV("ThreadBase::exit");
+ {
+ AutoMutex lock(&mLock);
+ requestExit();
+ mWaitWorkCV.signal();
}
+ requestExitAndWait();
}
-#endif
-// ----------------------------------------------------------------------------
+uint32_t AudioFlinger::ThreadBase::sampleRate() const
+{
+ return mSampleRate;
+}
-AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType)
- : Thread(false),
- mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType),
- mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
- mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
- mInWrite(false)
+int AudioFlinger::ThreadBase::channelCount() const
{
- mSampleRate = output->sampleRate();
- mChannelCount = output->channelCount();
+ return mChannelCount;
+}
- // FIXME - Current mixer implementation only supports stereo output
- if (mChannelCount == 1) {
- LOGE("Invalid audio hardware channel count");
+int AudioFlinger::ThreadBase::format() const
+{
+ return mFormat;
+}
+
+size_t AudioFlinger::ThreadBase::frameCount() const
+{
+ return mFrameCount;
+}
+
+status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs)
+{
+ status_t status;
+
+ LOGV("ThreadBase::setParameters() %s", keyValuePairs.string());
+ Mutex::Autolock _l(mLock);
+
+ mNewParameters.add(keyValuePairs);
+ mWaitWorkCV.signal();
+ mParamCond.wait(mLock);
+ status = mParamStatus;
+ mWaitWorkCV.signal();
+ return status;
+}
+
+void AudioFlinger::ThreadBase::sendConfigEvent(int event, int param)
+{
+ Mutex::Autolock _l(mLock);
+ sendConfigEvent_l(event, param);
+}
+
+// sendConfigEvent_l() must be called with ThreadBase::mLock held
+void AudioFlinger::ThreadBase::sendConfigEvent_l(int event, int param)
+{
+ ConfigEvent *configEvent = new ConfigEvent();
+ configEvent->mEvent = event;
+ configEvent->mParam = param;
+ mConfigEvents.add(configEvent);
+ LOGV("sendConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event, param);
+ mWaitWorkCV.signal();
+}
+
+void AudioFlinger::ThreadBase::processConfigEvents()
+{
+ mLock.lock();
+ while(!mConfigEvents.isEmpty()) {
+ LOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
+ ConfigEvent *configEvent = mConfigEvents[0];
+ mConfigEvents.removeAt(0);
+ // release mLock because audioConfigChanged() will call
+ // Audioflinger::audioConfigChanged() which locks AudioFlinger mLock thus creating
+ // potential cross deadlock between AudioFlinger::mLock and mLock
+ mLock.unlock();
+ audioConfigChanged(configEvent->mEvent, configEvent->mParam);
+ delete configEvent;
+ mLock.lock();
}
+ mLock.unlock();
+}
- mFormat = output->format();
- mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t);
- mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate());
- // FIXME - Current mixer implementation only supports stereo output: Always
- // Allocate a stereo buffer even if HW output is mono.
- mMixBuffer = new int16_t[mFrameCount * 2];
- memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+// ----------------------------------------------------------------------------
+
+AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : ThreadBase(audioFlinger),
+ mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
+ mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
+{
+ readOutputParameters();
+
+ mMasterVolume = mAudioFlinger->masterVolume();
+ mMasterMute = mAudioFlinger->masterMute();
+
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream);
+ mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream);
+ }
+ // notify client processes that a new input has been opened
+ sendConfigEvent(AudioSystem::OUTPUT_OPENED);
}
-AudioFlinger::MixerThread::~MixerThread()
+AudioFlinger::PlaybackThread::~PlaybackThread()
{
delete [] mMixBuffer;
- delete mAudioMixer;
}
-status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args)
+status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
{
dumpInternals(fd, args);
dumpTracks(fd, args);
return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args)
+status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType);
+ snprintf(buffer, SIZE, "Output thread %p tracks\n", this);
result.append(buffer);
result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
for (size_t i = 0; i < mTracks.size(); ++i) {
@@ -959,7 +864,7 @@ status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& a
}
}
- snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType);
+ snprintf(buffer, SIZE, "Output thread %p active tracks\n", this);
result.append(buffer);
result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
for (size_t i = 0; i < mActiveTracks.size(); ++i) {
@@ -976,15 +881,13 @@ status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& a
return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType);
- result.append(buffer);
- snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+ snprintf(buffer, SIZE, "Output thread %p internals\n", this);
result.append(buffer);
snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
result.append(buffer);
@@ -1001,238 +904,354 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>
}
// Thread virtuals
+status_t AudioFlinger::PlaybackThread::readyToRun()
+{
+ if (mSampleRate == 0) {
+ LOGE("No working audio driver found.");
+ return NO_INIT;
+ }
+ LOGI("AudioFlinger's thread %p ready to run", this);
+ return NO_ERROR;
+}
+
+void AudioFlinger::PlaybackThread::onFirstRef()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "Playback Thread %p", this);
+
+ run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+// PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
+ const sp<AudioFlinger::Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ const sp<IMemory>& sharedBuffer,
+ status_t *status)
+{
+ sp<Track> track;
+ status_t lStatus;
+
+ if (mType == DIRECT) {
+ if (sampleRate != mSampleRate || format != mFormat || channelCount != mChannelCount) {
+ LOGE("createTrack_l() Bad parameter: sampleRate %d format %d, channelCount %d for output %p",
+ sampleRate, format, channelCount, mOutput);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ } else {
+ // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+ if (sampleRate > mSampleRate*2) {
+ LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ }
+
+ if (mOutput == 0) {
+ LOGE("Audio driver not initialized.");
+ lStatus = NO_INIT;
+ goto Exit;
+ }
+
+ { // scope for mLock
+ Mutex::Autolock _l(mLock);
+ track = new Track(this, client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer);
+ if (track->getCblk() == NULL) {
+ lStatus = NO_MEMORY;
+ goto Exit;
+ }
+ mTracks.add(track);
+ }
+ lStatus = NO_ERROR;
+
+Exit:
+ if(status) {
+ *status = lStatus;
+ }
+ return track;
+}
+
+uint32_t AudioFlinger::PlaybackThread::latency() const
+{
+ if (mOutput) {
+ return mOutput->latency();
+ }
+ else {
+ return 0;
+ }
+}
+
+status_t AudioFlinger::PlaybackThread::setMasterVolume(float value)
+{
+ mMasterVolume = value;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted)
+{
+ mMasterMute = muted;
+ return NO_ERROR;
+}
+
+float AudioFlinger::PlaybackThread::masterVolume() const
+{
+ return mMasterVolume;
+}
+
+bool AudioFlinger::PlaybackThread::masterMute() const
+{
+ return mMasterMute;
+}
+
+status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value)
+{
+ mStreamTypes[stream].volume = value;
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::PlaybackThread::setStreamMute(int stream, bool muted)
+{
+ mStreamTypes[stream].mute = muted;
+ return NO_ERROR;
+}
+
+float AudioFlinger::PlaybackThread::streamVolume(int stream) const
+{
+ return mStreamTypes[stream].volume;
+}
+
+bool AudioFlinger::PlaybackThread::streamMute(int stream) const
+{
+ return mStreamTypes[stream].mute;
+}
+
+bool AudioFlinger::PlaybackThread::isMusicActive() const
+{
+ Mutex::Autolock _l(mLock);
+ size_t count = mActiveTracks.size();
+ for (size_t i = 0 ; i < count ; ++i) {
+ sp<Track> t = mActiveTracks[i].promote();
+ if (t == 0) continue;
+ Track* const track = t.get();
+ if (t->type() == AudioSystem::MUSIC)
+ return true;
+ }
+ return false;
+}
+
+// addTrack_l() must be called with ThreadBase::mLock held
+status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
+{
+ status_t status = ALREADY_EXISTS;
+
+ // here the track could be either new, or restarted
+ // in both cases "unstop" the track
+ if (track->isPaused()) {
+ track->mState = TrackBase::RESUMING;
+ LOGV("PAUSED => RESUMING (%d)", track->name());
+ } else {
+ track->mState = TrackBase::ACTIVE;
+ LOGV("? => ACTIVE (%d)", track->name());
+ }
+ // set retry count for buffer fill
+ track->mRetryCount = kMaxTrackStartupRetries;
+ if (mActiveTracks.indexOf(track) < 0) {
+ // the track is newly added, make sure it fills up all its
+ // buffers before playing. This is to ensure the client will
+ // effectively get the latency it requested.
+ track->mFillingUpStatus = Track::FS_FILLING;
+ track->mResetDone = false;
+ mActiveTracks.add(track);
+ status = NO_ERROR;
+ }
+
+ LOGV("mWaitWorkCV.broadcast");
+ mWaitWorkCV.broadcast();
+
+ return status;
+}
+
+// destroyTrack_l() must be called with ThreadBase::mLock held
+void AudioFlinger::PlaybackThread::destroyTrack_l(const sp<Track>& track)
+{
+ track->mState = TrackBase::TERMINATED;
+ if (mActiveTracks.indexOf(track) < 0) {
+ LOGV("remove track (%d) and delete from mixer", track->name());
+ mTracks.remove(track);
+ deleteTrackName_l(track->name());
+ }
+}
+
+String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)
+{
+ return mOutput->getParameters(keys);
+}
+
+void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) {
+ AudioSystem::OutputDescriptor desc;
+ void *param2 = 0;
+
+ LOGV("PlaybackThread::audioConfigChanged, thread %p, event %d, param %d", this, event, param);
+
+ switch (event) {
+ case AudioSystem::OUTPUT_OPENED:
+ case AudioSystem::OUTPUT_CONFIG_CHANGED:
+ desc.channels = mChannelCount;
+ desc.samplingRate = mSampleRate;
+ desc.format = mFormat;
+ desc.frameCount = mFrameCount;
+ desc.latency = latency();
+ param2 = &desc;
+ break;
+
+ case AudioSystem::STREAM_CONFIG_CHANGED:
+ param2 = &param;
+ case AudioSystem::OUTPUT_CLOSED:
+ default:
+ break;
+ }
+ mAudioFlinger->audioConfigChanged(event, this, param2);
+}
+
+void AudioFlinger::PlaybackThread::readOutputParameters()
+{
+ mSampleRate = mOutput->sampleRate();
+ mChannelCount = AudioSystem::popCount(mOutput->channels());
+
+ mFormat = mOutput->format();
+ mFrameSize = mOutput->frameSize();
+ mFrameCount = mOutput->bufferSize() / mFrameSize;
+
+ mMinBytesToWrite = (mOutput->latency() * mSampleRate * mFrameSize) / 1000;
+ // FIXME - Current mixer implementation only supports stereo output: Always
+ // Allocate a stereo buffer even if HW output is mono.
+ if (mMixBuffer != NULL) delete mMixBuffer;
+ mMixBuffer = new int16_t[mFrameCount * 2];
+ memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : PlaybackThread(audioFlinger, output),
+ mAudioMixer(0)
+{
+ mType = PlaybackThread::MIXER;
+ mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+
+ // FIXME - Current mixer implementation only supports stereo output
+ if (mChannelCount == 1) {
+ LOGE("Invalid audio hardware channel count");
+ }
+}
+
+AudioFlinger::MixerThread::~MixerThread()
+{
+ delete mAudioMixer;
+}
+
bool AudioFlinger::MixerThread::threadLoop()
{
unsigned long sleepTime = kBufferRecoveryInUsecs;
int16_t* curBuf = mMixBuffer;
Vector< sp<Track> > tracksToRemove;
size_t enabledTracks = 0;
- nsecs_t standbyTime = systemTime();
- size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
+ nsecs_t standbyTime = systemTime();
+ size_t mixBufferSize = mFrameCount * mFrameSize;
nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
-#ifdef WITH_A2DP
- bool outputTrackActive = false;
-#endif
+ while (!exitPending())
+ {
+ processConfigEvents();
- do {
enabledTracks = 0;
- { // scope for the AudioFlinger::mLock
-
- Mutex::Autolock _l(mAudioFlinger->mLock);
+ { // scope for mLock
-#ifdef WITH_A2DP
- if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) {
- if (outputTrackActive) {
- mAudioFlinger->mLock.unlock();
- mOutputTrack->stop();
- mAudioFlinger->mLock.lock();
- outputTrackActive = false;
- }
+ Mutex::Autolock _l(mLock);
+
+ if (checkForNewParameters_l()) {
+ mixBufferSize = mFrameCount * mFrameSize;
+ maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
}
- mAudioFlinger->checkA2dpEnabledChange_l();
-#endif
const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
// put audio hardware into standby after short delay
- if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
- // wait until we have something to do...
- LOGV("Audio hardware entering standby, output %d\n", mOutputType);
+ if UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
+ mSuspended) {
if (!mStandby) {
+ LOGV("Audio hardware entering standby, mixer %p, mSuspended %d\n", this, mSuspended);
mOutput->standby();
mStandby = true;
+ mBytesWritten = 0;
}
-
-#ifdef WITH_A2DP
- if (outputTrackActive) {
- mAudioFlinger->mLock.unlock();
- mOutputTrack->stop();
- mAudioFlinger->mLock.lock();
- outputTrackActive = false;
- }
-#endif
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE);
- }
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- mAudioFlinger->mWaitWorkCV.wait(mAudioFlinger->mLock);
- LOGV("Audio hardware exiting standby, output %d\n", mOutputType);
-
- if (mMasterMute == false) {
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.audio.silent", value, "0");
- if (atoi(value)) {
- LOGD("Silence is golden");
- setMasterMute(true);
- }
- }
-
- standbyTime = systemTime() + kStandbyTimeInNsecs;
- continue;
- }
-
- // Forced route to speaker is handled by hardware mixer thread
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME);
- }
-
- // find out which tracks need to be processed
- size_t count = activeTracks.size();
- for (size_t i=0 ; i<count ; i++) {
- sp<Track> t = activeTracks[i].promote();
- if (t == 0) continue;
- Track* const track = t.get();
- audio_track_cblk_t* cblk = track->cblk();
-
- // The first time a track is added we wait
- // for all its buffers to be filled before processing it
- mAudioMixer->setActiveTrack(track->name());
- if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
- !track->isPaused())
- {
- //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+ if (!activeTracks.size() && mConfigEvents.isEmpty()) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
- // compute volume for this track
- int16_t left, right;
- if (track->isMuted() || mMasterMute || track->isPausing()) {
- left = right = 0;
- if (track->isPausing()) {
- LOGV("paused(%d)", track->name());
- track->setPaused();
- }
- } else {
- float typeVolume = mStreamTypes[track->type()].volume;
- float v = mMasterVolume * typeVolume;
- float v_clamped = v * cblk->volume[0];
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- left = int16_t(v_clamped);
- v_clamped = v * cblk->volume[1];
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- right = int16_t(v_clamped);
- }
+ if (exitPending()) break;
- // XXX: these things DON'T need to be done each time
- mAudioMixer->setBufferProvider(track);
- mAudioMixer->enable(AudioMixer::MIXING);
+ // wait until we have something to do...
+ LOGV("MixerThread %p TID %d going to sleep\n", this, gettid());
+ mWaitWorkCV.wait(mLock);
+ LOGV("MixerThread %p TID %d waking up\n", this, gettid());
- int param;
- if ( track->mFillingUpStatus == Track::FS_FILLED) {
- // no ramp for the first volume setting
- track->mFillingUpStatus = Track::FS_ACTIVE;
- if (track->mState == TrackBase::RESUMING) {
- track->mState = TrackBase::ACTIVE;
- param = AudioMixer::RAMP_VOLUME;
- } else {
- param = AudioMixer::VOLUME;
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
}
- } else {
- param = AudioMixer::RAMP_VOLUME;
}
- mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
- mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
- mAudioMixer->setParameter(
- AudioMixer::TRACK,
- AudioMixer::FORMAT, track->format());
- mAudioMixer->setParameter(
- AudioMixer::TRACK,
- AudioMixer::CHANNEL_COUNT, track->channelCount());
- mAudioMixer->setParameter(
- AudioMixer::RESAMPLE,
- AudioMixer::SAMPLE_RATE,
- int(cblk->sampleRate));
- // reset retry count
- track->mRetryCount = kMaxTrackRetries;
- enabledTracks++;
- } else {
- //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
- if (track->isStopped()) {
- track->reset();
- }
- if (track->isTerminated() || track->isStopped() || track->isPaused()) {
- // We have consumed all the buffers of this track.
- // Remove it from the list of active tracks.
- LOGV("remove(%d) from active list", track->name());
- tracksToRemove.add(track);
- } else {
- // No buffers for this track. Give it a few chances to
- // fill a buffer, then remove it from active list.
- if (--(track->mRetryCount) <= 0) {
- LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
- tracksToRemove.add(track);
- }
- }
- // LOGV("disable(%d)", track->name());
- mAudioMixer->disable(AudioMixer::MIXING);
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ continue;
}
}
- // remove all the tracks that need to be...
- count = tracksToRemove.size();
- if (UNLIKELY(count)) {
- for (size_t i=0 ; i<count ; i++) {
- const sp<Track>& track = tracksToRemove[i];
- removeActiveTrack_l(track);
- if (track->isTerminated()) {
- mTracks.remove(track);
- deleteTrackName_l(track->mName);
- }
- }
- }
+ enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
}
-
+
if (LIKELY(enabledTracks)) {
// mix buffers...
mAudioMixer->process(curBuf);
-#ifdef WITH_A2DP
- if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
- if (!outputTrackActive) {
- LOGV("starting output track in mixer for output %d", mOutputType);
- mOutputTrack->start();
- outputTrackActive = true;
- }
- mOutputTrack->write(curBuf, mFrameCount);
- }
-#endif
-
// output audio to hardware
- mLastWriteTime = systemTime();
- mInWrite = true;
- mOutput->write(curBuf, mixBufferSize);
- mNumWrites++;
- mInWrite = false;
- mStandby = false;
- nsecs_t temp = systemTime();
- standbyTime = temp + kStandbyTimeInNsecs;
- nsecs_t delta = temp - mLastWriteTime;
- if (delta > maxPeriod) {
- LOGW("write blocked for %llu msecs", ns2ms(delta));
- mNumDelayedWrites++;
- }
- sleepTime = kBufferRecoveryInUsecs;
- } else {
-#ifdef WITH_A2DP
- if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
- if (outputTrackActive) {
- mOutputTrack->write(curBuf, 0);
- if (mOutputTrack->bufferQueueEmpty()) {
- mOutputTrack->stop();
- outputTrackActive = false;
- } else {
- standbyTime = systemTime() + kStandbyTimeInNsecs;
- }
+ if (mSuspended) {
+ usleep(kMaxBufferRecoveryInUsecs);
+ } else {
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);
+ if (bytesWritten > 0) mBytesWritten += bytesWritten;
+ mNumWrites++;
+ mInWrite = false;
+ mStandby = false;
+ nsecs_t temp = systemTime();
+ standbyTime = temp + kStandbyTimeInNsecs;
+ nsecs_t delta = temp - mLastWriteTime;
+ if (delta > maxPeriod) {
+ LOGW("write blocked for %llu msecs", ns2ms(delta));
+ mNumDelayedWrites++;
}
+ sleepTime = kBufferRecoveryInUsecs;
}
-#endif
+ } else {
// There was nothing to mix this round, which means all
// active tracks were late. Sleep a little bit to give
// them another chance. If we're too late, the audio
// hardware will zero-fill for us.
- //LOGV("no buffers - usleep(%lu)", sleepTime);
+ // LOGV("thread %p no buffers - usleep(%lu)", this, sleepTime);
usleep(sleepTime);
if (sleepTime < kMaxBufferRecoveryInUsecs) {
sleepTime += kBufferRecoveryInUsecs;
@@ -1243,101 +1262,165 @@ bool AudioFlinger::MixerThread::threadLoop()
// since we can't guarantee the destructors won't acquire that
// same lock.
tracksToRemove.clear();
- } while (true);
-
- return false;
-}
+ }
-status_t AudioFlinger::MixerThread::readyToRun()
-{
- if (mSampleRate == 0) {
- LOGE("No working audio driver found.");
- return NO_INIT;
+ if (!mStandby) {
+ mOutput->standby();
}
- LOGI("AudioFlinger's thread ready to run for output %d", mOutputType);
- return NO_ERROR;
+ sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
+ processConfigEvents();
+
+ LOGV("MixerThread %p exiting", this);
+ return false;
}
-void AudioFlinger::MixerThread::onFirstRef()
+// prepareTracks_l() must be called with ThreadBase::mLock held
+size_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType);
- run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
-}
+ size_t enabledTracks = 0;
+ // find out which tracks need to be processed
+ size_t count = activeTracks.size();
+ for (size_t i=0 ; i<count ; i++) {
+ sp<Track> t = activeTracks[i].promote();
+ if (t == 0) continue;
-// MixerThread::createTrack_l() must be called with AudioFlinger::mLock held
-sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l(
- const sp<AudioFlinger::Client>& client,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount,
- const sp<IMemory>& sharedBuffer,
- status_t *status)
-{
- sp<Track> track;
- status_t lStatus;
-
- // Resampler implementation limits input sampling rate to 2 x output sampling rate.
- if (sampleRate > mSampleRate*2) {
- LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
- lStatus = BAD_VALUE;
- goto Exit;
- }
+ Track* const track = t.get();
+ audio_track_cblk_t* cblk = track->cblk();
+ // The first time a track is added we wait
+ // for all its buffers to be filled before processing it
+ mAudioMixer->setActiveTrack(track->name());
+ if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+ !track->isPaused())
+ {
+ //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+ // compute volume for this track
+ int16_t left, right;
+ if (track->isMuted() || mMasterMute || track->isPausing() ||
+ mStreamTypes[track->type()].mute) {
+ left = right = 0;
+ if (track->isPausing()) {
+ track->setPaused();
+ }
+ } else {
+ float typeVolume = mStreamTypes[track->type()].volume;
+ float v = mMasterVolume * typeVolume;
+ float v_clamped = v * cblk->volume[0];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ left = int16_t(v_clamped);
+ v_clamped = v * cblk->volume[1];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ right = int16_t(v_clamped);
+ }
- if (mSampleRate == 0) {
- LOGE("Audio driver not initialized.");
- lStatus = NO_INIT;
- goto Exit;
+ // XXX: these things DON'T need to be done each time
+ mAudioMixer->setBufferProvider(track);
+ mAudioMixer->enable(AudioMixer::MIXING);
+
+ int param;
+ if ( track->mFillingUpStatus == Track::FS_FILLED) {
+ // no ramp for the first volume setting
+ track->mFillingUpStatus = Track::FS_ACTIVE;
+ if (track->mState == TrackBase::RESUMING) {
+ track->mState = TrackBase::ACTIVE;
+ param = AudioMixer::RAMP_VOLUME;
+ } else {
+ param = AudioMixer::VOLUME;
+ }
+ } else {
+ param = AudioMixer::RAMP_VOLUME;
+ }
+ mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
+ mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
+ mAudioMixer->setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::FORMAT, track->format());
+ mAudioMixer->setParameter(
+ AudioMixer::TRACK,
+ AudioMixer::CHANNEL_COUNT, track->channelCount());
+ mAudioMixer->setParameter(
+ AudioMixer::RESAMPLE,
+ AudioMixer::SAMPLE_RATE,
+ int(cblk->sampleRate));
+
+ // reset retry count
+ track->mRetryCount = kMaxTrackRetries;
+ enabledTracks++;
+ } else {
+ //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+ if (track->isStopped()) {
+ track->reset();
+ }
+ if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+ // We have consumed all the buffers of this track.
+ // Remove it from the list of active tracks.
+ tracksToRemove->add(track);
+ mAudioMixer->disable(AudioMixer::MIXING);
+ } else {
+ // No buffers for this track. Give it a few chances to
+ // fill a buffer, then remove it from active list.
+ if (--(track->mRetryCount) <= 0) {
+ LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ tracksToRemove->add(track);
+ }
+ // For tracks using static shared memry buffer, make sure that we have
+ // written enough data to audio hardware before disabling the track
+ // NOTE: this condition with arrive before track->mRetryCount <= 0 so we
+ // don't care about code removing track from active list above.
+ if ((track->mSharedBuffer == 0) || (mBytesWritten >= mMinBytesToWrite)) {
+ mAudioMixer->disable(AudioMixer::MIXING);
+ } else {
+ enabledTracks++;
+ }
+ }
+ }
}
- track = new Track(this, client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer);
- if (track->getCblk() == NULL) {
- lStatus = NO_MEMORY;
- goto Exit;
+ // remove all the tracks that need to be...
+ count = tracksToRemove->size();
+ if (UNLIKELY(count)) {
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Track>& track = tracksToRemove->itemAt(i);
+ mActiveTracks.remove(track);
+ if (track->isTerminated()) {
+ mTracks.remove(track);
+ deleteTrackName_l(track->mName);
+ }
+ }
}
- mTracks.add(track);
- lStatus = NO_ERROR;
-Exit:
- if(status) {
- *status = lStatus;
- }
- return track;
+ return enabledTracks;
}
-// getTracks_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::getTracks_l(
+void AudioFlinger::MixerThread::getTracks(
SortedVector < sp<Track> >& tracks,
- SortedVector < wp<Track> >& activeTracks)
+ SortedVector < wp<Track> >& activeTracks,
+ int streamType)
{
+ LOGV ("MixerThread::getTracks() mixer %p, mTracks.size %d, mActiveTracks.size %d", this, mTracks.size(), mActiveTracks.size());
+ Mutex::Autolock _l(mLock);
size_t size = mTracks.size();
- LOGV ("MixerThread::getTracks_l() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType, mTracks.size(), mActiveTracks.size());
for (size_t i = 0; i < size; i++) {
sp<Track> t = mTracks[i];
- if (AudioSystem::routedToA2dpOutput(t->mStreamType)) {
+ if (t->type() == streamType) {
tracks.add(t);
int j = mActiveTracks.indexOf(t);
if (j >= 0) {
t = mActiveTracks[j].promote();
if (t != NULL) {
- activeTracks.add(t);
- }
+ activeTracks.add(t);
+ }
}
}
}
size = activeTracks.size();
for (size_t i = 0; i < size; i++) {
- removeActiveTrack_l(activeTracks[i]);
+ mActiveTracks.remove(activeTracks[i]);
}
-
+
size = tracks.size();
for (size_t i = 0; i < size; i++) {
sp<Track> t = tracks[i];
@@ -1346,219 +1429,570 @@ void AudioFlinger::MixerThread::getTracks_l(
}
}
-// putTracks_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::putTracks_l(
+void AudioFlinger::MixerThread::putTracks(
SortedVector < sp<Track> >& tracks,
SortedVector < wp<Track> >& activeTracks)
{
-
- LOGV ("MixerThread::putTracks_l() for output %d, tracks.size %d, activeTracks.size %d", mOutputType, tracks.size(), activeTracks.size());
-
+ LOGV ("MixerThread::putTracks() mixer %p, tracks.size %d, activeTracks.size %d", this, tracks.size(), activeTracks.size());
+ Mutex::Autolock _l(mLock);
size_t size = tracks.size();
for (size_t i = 0; i < size ; i++) {
sp<Track> t = tracks[i];
int name = getTrackName_l();
if (name < 0) return;
-
+
t->mName = name;
- t->mMixerThread = this;
+ t->mThread = this;
mTracks.add(t);
int j = activeTracks.indexOf(t);
if (j >= 0) {
- addActiveTrack_l(t);
- }
+ mActiveTracks.add(t);
+ }
}
}
-uint32_t AudioFlinger::MixerThread::sampleRate() const
+// getTrackName_l() must be called with ThreadBase::mLock held
+int AudioFlinger::MixerThread::getTrackName_l()
{
- return mSampleRate;
+ return mAudioMixer->getTrackName();
}
-int AudioFlinger::MixerThread::channelCount() const
+// deleteTrackName_l() must be called with ThreadBase::mLock held
+void AudioFlinger::MixerThread::deleteTrackName_l(int name)
{
- return mChannelCount;
+ mAudioMixer->deleteTrackName(name);
}
-int AudioFlinger::MixerThread::format() const
+// checkForNewParameters_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::MixerThread::checkForNewParameters_l()
{
- return mFormat;
-}
+ bool reconfig = false;
-size_t AudioFlinger::MixerThread::frameCount() const
-{
- return mFrameCount;
-}
+ while (!mNewParameters.isEmpty()) {
+ status_t status = NO_ERROR;
+ String8 keyValuePair = mNewParameters[0];
+ AudioParameter param = AudioParameter(keyValuePair);
+ int value;
-uint32_t AudioFlinger::MixerThread::latency() const
-{
- if (mOutput) {
- return mOutput->latency();
- }
- else {
- return 0;
+ mNewParameters.removeAt(0);
+
+ if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
+ if (value != AudioSystem::PCM_16_BIT) {
+ status = BAD_VALUE;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+ if (value != AudioSystem::CHANNEL_OUT_STEREO) {
+ status = BAD_VALUE;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be garantied
+ // if frame count is changed after track creation
+ if (!mTracks.isEmpty()) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (status == NO_ERROR) {
+ status = mOutput->setParameters(keyValuePair);
+ if (!mStandby && status == INVALID_OPERATION) {
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ status = mOutput->setParameters(keyValuePair);
+ }
+ if (status == NO_ERROR && reconfig) {
+ delete mAudioMixer;
+ readOutputParameters();
+ mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+ for (size_t i = 0; i < mTracks.size() ; i++) {
+ int name = getTrackName_l();
+ if (name < 0) break;
+ mTracks[i]->mName = name;
+ // limit track sample rate to 2 x new output sample rate
+ if (mTracks[i]->mCblk->sampleRate > 2 * sampleRate()) {
+ mTracks[i]->mCblk->sampleRate = 2 * sampleRate();
+ }
+ }
+ sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
+ }
+ }
+ mParamStatus = status;
+ mParamCond.signal();
+ mWaitWorkCV.wait(mLock);
}
+ return reconfig;
}
-status_t AudioFlinger::MixerThread::setMasterVolume(float value)
+status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
{
- mMasterVolume = value;
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ PlaybackThread::dumpInternals(fd, args);
+
+ snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
return NO_ERROR;
}
-status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
+// ----------------------------------------------------------------------------
+AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
+ : PlaybackThread(audioFlinger, output),
+ mLeftVolume (1.0), mRightVolume(1.0)
{
- mMasterMute = muted;
- return NO_ERROR;
+ mType = PlaybackThread::DIRECT;
}
-float AudioFlinger::MixerThread::masterVolume() const
+AudioFlinger::DirectOutputThread::~DirectOutputThread()
{
- return mMasterVolume;
}
-bool AudioFlinger::MixerThread::masterMute() const
+
+bool AudioFlinger::DirectOutputThread::threadLoop()
{
- return mMasterMute;
+ unsigned long sleepTime = kBufferRecoveryInUsecs;
+ sp<Track> trackToRemove;
+ sp<Track> activeTrack;
+ nsecs_t standbyTime = systemTime();
+ int8_t *curBuf;
+ size_t mixBufferSize = mFrameCount*mFrameSize;
+
+ while (!exitPending())
+ {
+ processConfigEvents();
+
+ { // scope for the mLock
+
+ Mutex::Autolock _l(mLock);
+
+ if (checkForNewParameters_l()) {
+ mixBufferSize = mFrameCount*mFrameSize;
+ }
+
+ // put audio hardware into standby after short delay
+ if UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
+ mSuspended) {
+ // wait until we have something to do...
+ if (!mStandby) {
+ LOGV("Audio hardware entering standby, mixer %p\n", this);
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ }
+
+ if (!mActiveTracks.size() && mConfigEvents.isEmpty()) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+
+ if (exitPending()) break;
+
+ LOGV("DirectOutputThread %p TID %d going to sleep\n", this, gettid());
+ mWaitWorkCV.wait(mLock);
+ LOGV("DirectOutputThread %p TID %d waking up in active mode\n", this, gettid());
+
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
+ }
+ }
+
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ continue;
+ }
+ }
+
+ // find out which tracks need to be processed
+ if (mActiveTracks.size() != 0) {
+ sp<Track> t = mActiveTracks[0].promote();
+ if (t == 0) continue;
+
+ Track* const track = t.get();
+ audio_track_cblk_t* cblk = track->cblk();
+
+ // The first time a track is added we wait
+ // for all its buffers to be filled before processing it
+ if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+ !track->isPaused())
+ {
+ //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+ // compute volume for this track
+ float left, right;
+ if (track->isMuted() || mMasterMute || track->isPausing() ||
+ mStreamTypes[track->type()].mute) {
+ left = right = 0;
+ if (track->isPausing()) {
+ track->setPaused();
+ }
+ } else {
+ float typeVolume = mStreamTypes[track->type()].volume;
+ float v = mMasterVolume * typeVolume;
+ float v_clamped = v * cblk->volume[0];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ left = v_clamped/MAX_GAIN;
+ v_clamped = v * cblk->volume[1];
+ if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+ right = v_clamped/MAX_GAIN;
+ }
+
+ if (left != mLeftVolume || right != mRightVolume) {
+ mOutput->setVolume(left, right);
+ left = mLeftVolume;
+ right = mRightVolume;
+ }
+
+ if (track->mFillingUpStatus == Track::FS_FILLED) {
+ track->mFillingUpStatus = Track::FS_ACTIVE;
+ if (track->mState == TrackBase::RESUMING) {
+ track->mState = TrackBase::ACTIVE;
+ }
+ }
+
+ // reset retry count
+ track->mRetryCount = kMaxTrackRetries;
+ activeTrack = t;
+ } else {
+ //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+ if (track->isStopped()) {
+ track->reset();
+ }
+ if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+ // We have consumed all the buffers of this track.
+ // Remove it from the list of active tracks.
+ trackToRemove = track;
+ } else {
+ // No buffers for this track. Give it a few chances to
+ // fill a buffer, then remove it from active list.
+ if (--(track->mRetryCount) <= 0) {
+ LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+ trackToRemove = track;
+ }
+
+ // For tracks using static shared memry buffer, make sure that we have
+ // written enough data to audio hardware before disabling the track
+ // NOTE: this condition with arrive before track->mRetryCount <= 0 so we
+ // don't care about code removing track from active list above.
+ if ((track->mSharedBuffer != 0) && (mBytesWritten < mMinBytesToWrite)) {
+ activeTrack = t;
+ }
+ }
+ }
+ }
+
+ // remove all the tracks that need to be...
+ if (UNLIKELY(trackToRemove != 0)) {
+ mActiveTracks.remove(trackToRemove);
+ if (trackToRemove->isTerminated()) {
+ mTracks.remove(trackToRemove);
+ deleteTrackName_l(trackToRemove->mName);
+ }
+ }
+ }
+
+ if (activeTrack != 0) {
+ AudioBufferProvider::Buffer buffer;
+ size_t frameCount = mFrameCount;
+ curBuf = (int8_t *)mMixBuffer;
+ // output audio to hardware
+ mLastWriteTime = systemTime();
+ mInWrite = true;
+ while(frameCount) {
+ buffer.frameCount = frameCount;
+ activeTrack->getNextBuffer(&buffer);
+ if (UNLIKELY(buffer.raw == 0)) {
+ memset(curBuf, 0, frameCount * mFrameSize);
+ break;
+ }
+ memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
+ frameCount -= buffer.frameCount;
+ curBuf += buffer.frameCount * mFrameSize;
+ activeTrack->releaseBuffer(&buffer);
+ }
+ if (mSuspended) {
+ usleep(kMaxBufferRecoveryInUsecs);
+ } else {
+ int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
+ if (bytesWritten) mBytesWritten += bytesWritten;
+ mNumWrites++;
+ mInWrite = false;
+ mStandby = false;
+ nsecs_t temp = systemTime();
+ standbyTime = temp + kStandbyTimeInNsecs;
+ sleepTime = kBufferRecoveryInUsecs;
+ }
+ } else {
+ // There was nothing to mix this round, which means all
+ // active tracks were late. Sleep a little bit to give
+ // them another chance. If we're too late, the audio
+ // hardware will zero-fill for us.
+ //LOGV("no buffers - usleep(%lu)", sleepTime);
+ usleep(sleepTime);
+ if (sleepTime < kMaxBufferRecoveryInUsecs) {
+ sleepTime += kBufferRecoveryInUsecs;
+ }
+ }
+
+ // finally let go of removed track, without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+ trackToRemove.clear();
+ activeTrack.clear();
+ }
+
+ if (!mStandby) {
+ mOutput->standby();
+ }
+ sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
+ processConfigEvents();
+
+ LOGV("DirectOutputThread %p exiting", this);
+ return false;
}
-status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
+// getTrackName_l() must be called with ThreadBase::mLock held
+int AudioFlinger::DirectOutputThread::getTrackName_l()
{
- mStreamTypes[stream].volume = value;
- return NO_ERROR;
+ return 0;
}
-status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
+// deleteTrackName_l() must be called with ThreadBase::mLock held
+void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name)
{
- mStreamTypes[stream].mute = muted;
- return NO_ERROR;
}
-float AudioFlinger::MixerThread::streamVolume(int stream) const
+// checkForNewParameters_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::DirectOutputThread::checkForNewParameters_l()
{
- return mStreamTypes[stream].volume;
+ bool reconfig = false;
+
+ while (!mNewParameters.isEmpty()) {
+ status_t status = NO_ERROR;
+ String8 keyValuePair = mNewParameters[0];
+ AudioParameter param = AudioParameter(keyValuePair);
+ int value;
+
+ mNewParameters.removeAt(0);
+
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be garantied
+ // if frame count is changed after track creation
+ if (!mTracks.isEmpty()) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (status == NO_ERROR) {
+ status = mOutput->setParameters(keyValuePair);
+ if (!mStandby && status == INVALID_OPERATION) {
+ mOutput->standby();
+ mStandby = true;
+ mBytesWritten = 0;
+ status = mOutput->setParameters(keyValuePair);
+ }
+ if (status == NO_ERROR && reconfig) {
+ readOutputParameters();
+ sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
+ }
+ }
+ mParamStatus = status;
+ mParamCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ return reconfig;
}
-bool AudioFlinger::MixerThread::streamMute(int stream) const
+// ----------------------------------------------------------------------------
+
+AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread)
+ : MixerThread(audioFlinger, mainThread->getOutput())
{
- return mStreamTypes[stream].mute;
+ mType = PlaybackThread::DUPLICATING;
+ addOutputTrack(mainThread);
}
-// isMusicActive_l() must be called with AudioFlinger::mLock held
-bool AudioFlinger::MixerThread::isMusicActive_l() const
+AudioFlinger::DuplicatingThread::~DuplicatingThread()
{
- size_t count = mActiveTracks.size();
- for (size_t i = 0 ; i < count ; ++i) {
- sp<Track> t = mActiveTracks[i].promote();
- if (t == 0) continue;
- Track* const track = t.get();
- if (t->mStreamType == AudioSystem::MUSIC)
- return true;
- }
- return false;
+ mOutputTracks.clear();
}
-// addTrack_l() must be called with AudioFlinger::mLock held
-status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track)
+bool AudioFlinger::DuplicatingThread::threadLoop()
{
- status_t status = ALREADY_EXISTS;
+ unsigned long sleepTime = kBufferRecoveryInUsecs;
+ int16_t* curBuf = mMixBuffer;
+ Vector< sp<Track> > tracksToRemove;
+ size_t enabledTracks = 0;
+ nsecs_t standbyTime = systemTime();
+ size_t mixBufferSize = mFrameCount*mFrameSize;
+ SortedVector< sp<OutputTrack> > outputTracks;
- // here the track could be either new, or restarted
- // in both cases "unstop" the track
- if (track->isPaused()) {
- track->mState = TrackBase::RESUMING;
- LOGV("PAUSED => RESUMING (%d)", track->name());
- } else {
- track->mState = TrackBase::ACTIVE;
- LOGV("? => ACTIVE (%d)", track->name());
- }
- // set retry count for buffer fill
- track->mRetryCount = kMaxTrackStartupRetries;
- if (mActiveTracks.indexOf(track) < 0) {
- // the track is newly added, make sure it fills up all its
- // buffers before playing. This is to ensure the client will
- // effectively get the latency it requested.
- track->mFillingUpStatus = Track::FS_FILLING;
- track->mResetDone = false;
- addActiveTrack_l(track);
- status = NO_ERROR;
- }
-
- LOGV("mWaitWorkCV.broadcast");
- mAudioFlinger->mWaitWorkCV.broadcast();
+ while (!exitPending())
+ {
+ processConfigEvents();
- return status;
-}
+ enabledTracks = 0;
+ { // scope for the mLock
-// destroyTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::destroyTrack_l(const sp<Track>& track)
-{
- track->mState = TrackBase::TERMINATED;
- if (mActiveTracks.indexOf(track) < 0) {
- LOGV("remove track (%d) and delete from mixer", track->name());
- mTracks.remove(track);
- deleteTrackName_l(track->name());
- }
-}
+ Mutex::Autolock _l(mLock);
-// addActiveTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::addActiveTrack_l(const wp<Track>& t)
-{
- mActiveTracks.add(t);
+ if (checkForNewParameters_l()) {
+ mixBufferSize = mFrameCount*mFrameSize;
+ }
- // Force routing to speaker for certain stream types
- // The forced routing to speaker is managed by hardware mixer
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- sp<Track> track = t.promote();
- if (track == NULL) return;
-
- if (streamForcedToSpeaker(track->type())) {
- mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
- }
- }
-}
+ const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
-// removeActiveTrack_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::removeActiveTrack_l(const wp<Track>& t)
-{
- mActiveTracks.remove(t);
+ for (size_t i = 0; i < mOutputTracks.size(); i++) {
+ outputTracks.add(mOutputTracks[i]);
+ }
+
+ // put audio hardware into standby after short delay
+ if UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
+ mSuspended) {
+ if (!mStandby) {
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ outputTracks[i]->stop();
+ }
+ mStandby = true;
+ mBytesWritten = 0;
+ }
+
+ if (!activeTracks.size() && mConfigEvents.isEmpty()) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ outputTracks.clear();
+
+ if (exitPending()) break;
+
+ LOGV("DuplicatingThread %p TID %d going to sleep\n", this, gettid());
+ mWaitWorkCV.wait(mLock);
+ LOGV("DuplicatingThread %p TID %d waking up\n", this, gettid());
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
+ }
+ }
+
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ sleepTime = kBufferRecoveryInUsecs;
+ continue;
+ }
+ }
+
+ enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
+ }
+
+ bool mustSleep = true;
+ if (LIKELY(enabledTracks)) {
+ // mix buffers...
+ mAudioMixer->process(curBuf);
+ if (!mSuspended) {
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ outputTracks[i]->write(curBuf, mFrameCount);
+ mustSleep = false;
+ }
+ mStandby = false;
+ mBytesWritten += mixBufferSize;
+ }
+ } else {
+ // flush remaining overflow buffers in output tracks
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ if (outputTracks[i]->isActive()) {
+ outputTracks[i]->write(curBuf, 0);
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ mustSleep = false;
+ }
+ }
+ }
+ if (mustSleep) {
+// LOGV("threadLoop() sleeping %d", sleepTime);
+ usleep(sleepTime);
+ if (sleepTime < kMaxBufferRecoveryInUsecs) {
+ sleepTime += kBufferRecoveryInUsecs;
+ }
+ } else {
+ sleepTime = kBufferRecoveryInUsecs;
+ }
+
+ // finally let go of all our tracks, without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+ tracksToRemove.clear();
+ outputTracks.clear();
+ }
- // Force routing to speaker for certain stream types
- // The forced routing to speaker is managed by hardware mixer
- if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
- sp<Track> track = t.promote();
- if (track == NULL) return;
+ { // scope for the mLock
- if (streamForcedToSpeaker(track->type())) {
- mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+ Mutex::Autolock _l(mLock);
+ if (!mStandby) {
+ LOGV("DuplicatingThread() exiting out of standby");
+ for (size_t i = 0; i < mOutputTracks.size(); i++) {
+ mOutputTracks[i]->destroy();
+ }
}
}
-}
-// getTrackName_l() must be called with AudioFlinger::mLock held
-int AudioFlinger::MixerThread::getTrackName_l()
-{
- return mAudioMixer->getTrackName();
+ sendConfigEvent(AudioSystem::OUTPUT_CLOSED);
+ processConfigEvents();
+
+ return false;
}
-// deleteTrackName_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::MixerThread::deleteTrackName_l(int name)
+void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
{
- mAudioMixer->deleteTrackName(name);
+ int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate();
+ OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread,
+ mSampleRate,
+ mFormat,
+ mChannelCount,
+ frameCount);
+ if (outputTrack->cblk() != NULL) {
+ thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f);
+ mOutputTracks.add(outputTrack);
+ LOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
+ }
}
-size_t AudioFlinger::MixerThread::getOutputFrameCount()
+void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread)
{
- return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mOutputTracks.size(); i++) {
+ if (mOutputTracks[i]->thread() == (ThreadBase *)thread) {
+ mOutputTracks[i]->destroy();
+ mOutputTracks.removeAt(i);
+ return;
+ }
+ }
+ LOGV("removeOutputTrack(): unkonwn thread: %p", thread);
}
+
// ----------------------------------------------------------------------------
// TrackBase constructor must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread::TrackBase::TrackBase(
- const sp<MixerThread>& mixerThread,
+AudioFlinger::ThreadBase::TrackBase::TrackBase(
+ const wp<ThreadBase>& thread,
const sp<Client>& client,
uint32_t sampleRate,
int format,
@@ -1567,7 +2001,7 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
uint32_t flags,
const sp<IMemory>& sharedBuffer)
: RefBase(),
- mMixerThread(mixerThread),
+ mThread(thread),
mClient(client),
mFrameCount(0),
mState(IDLE),
@@ -1575,13 +2009,6 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
mFormat(format),
mFlags(flags & ~SYSTEM_FLAGS_MASK)
{
- mName = mixerThread->getTrackName_l();
- LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
- if (mName < 0) {
- LOGE("no more track names availlable");
- return;
- }
-
LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
// LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
@@ -1635,16 +2062,19 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
}
}
-AudioFlinger::MixerThread::TrackBase::~TrackBase()
+AudioFlinger::PlaybackThread::TrackBase::~TrackBase()
{
if (mCblk) {
- mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ if (mClient == NULL) {
+ delete mCblk;
+ }
}
mCblkMemory.clear(); // and free the shared memory
mClient.clear();
}
-void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::PlaybackThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
{
buffer->raw = 0;
mFrameCount = buffer->frameCount;
@@ -1652,7 +2082,7 @@ void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Bu
buffer->frameCount = 0;
}
-bool AudioFlinger::MixerThread::TrackBase::step() {
+bool AudioFlinger::PlaybackThread::TrackBase::step() {
bool result;
audio_track_cblk_t* cblk = this->cblk();
@@ -1664,7 +2094,7 @@ bool AudioFlinger::MixerThread::TrackBase::step() {
return result;
}
-void AudioFlinger::MixerThread::TrackBase::reset() {
+void AudioFlinger::PlaybackThread::TrackBase::reset() {
audio_track_cblk_t* cblk = this->cblk();
cblk->user = 0;
@@ -1675,27 +2105,27 @@ void AudioFlinger::MixerThread::TrackBase::reset() {
LOGV("TrackBase::reset");
}
-sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
+sp<IMemory> AudioFlinger::PlaybackThread::TrackBase::getCblk() const
{
return mCblkMemory;
}
-int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
+int AudioFlinger::PlaybackThread::TrackBase::sampleRate() const {
return (int)mCblk->sampleRate;
}
-int AudioFlinger::MixerThread::TrackBase::channelCount() const {
+int AudioFlinger::PlaybackThread::TrackBase::channelCount() const {
return (int)mCblk->channels;
}
-void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+void* AudioFlinger::PlaybackThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
audio_track_cblk_t* cblk = this->cblk();
- int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
- int16_t *bufferEnd = bufferStart + frames * cblk->channels;
+ int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize;
+ int8_t *bufferEnd = bufferStart + frames * cblk->frameSize;
// Check validity of returned pointer in case the track control block would have been corrupted.
- if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||
- (cblk->channels == 2 && ((unsigned long)bufferStart & 3))) {
+ if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||
+ ((unsigned long)bufferStart & (unsigned long)(cblk->frameSize - 1))) {
LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \
server %d, serverBase %d, user %d, userBase %d, channels %d",
bufferStart, bufferEnd, mBuffer, mBufferEnd,
@@ -1708,9 +2138,9 @@ void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t
// ----------------------------------------------------------------------------
-// Track constructor must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread::Track::Track(
- const sp<MixerThread>& mixerThread,
+// Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
+AudioFlinger::PlaybackThread::Track::Track(
+ const wp<ThreadBase>& thread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
@@ -1718,40 +2148,58 @@ AudioFlinger::MixerThread::Track::Track(
int channelCount,
int frameCount,
const sp<IMemory>& sharedBuffer)
- : TrackBase(mixerThread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
+ : TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer),
+ mMute(false), mSharedBuffer(sharedBuffer), mName(-1)
{
+ sp<ThreadBase> baseThread = thread.promote();
+ if (baseThread != 0) {
+ PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get();
+ mName = playbackThread->getTrackName_l();
+ }
+ LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ if (mName < 0) {
+ LOGE("no more track names available");
+ }
mVolume[0] = 1.0f;
mVolume[1] = 1.0f;
- mMute = false;
- mSharedBuffer = sharedBuffer;
mStreamType = streamType;
+ // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of
+ // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
+ mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t);
}
-AudioFlinger::MixerThread::Track::~Track()
+AudioFlinger::PlaybackThread::Track::~Track()
{
- wp<Track> weak(this); // never create a strong ref from the dtor
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mState = TERMINATED;
+ LOGV("PlaybackThread::Track destructor");
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ mState = TERMINATED;
+ }
}
-void AudioFlinger::MixerThread::Track::destroy()
+void AudioFlinger::PlaybackThread::Track::destroy()
{
- // NOTE: destroyTrack_l() can remove a strong reference to this Track
+ // NOTE: destroyTrack_l() can remove a strong reference to this Track
// by removing it from mTracks vector, so there is a risk that this Tracks's
- // desctructor is called. As the destructor needs to lock AudioFlinger::mLock,
- // we must acquire a strong reference on this Track before locking AudioFlinger::mLock
+ // desctructor is called. As the destructor needs to lock mLock,
+ // we must acquire a strong reference on this Track before locking mLock
// here so that the destructor is called only when exiting this function.
- // On the other hand, as long as Track::destroy() is only called by
- // TrackHandle destructor, the TrackHandle still holds a strong ref on
+ // On the other hand, as long as Track::destroy() is only called by
+ // TrackHandle destructor, the TrackHandle still holds a strong ref on
// this Track with its member mTrack.
sp<Track> keep(this);
- { // scope for AudioFlinger::mLock
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mMixerThread->destroyTrack_l(this);
+ { // scope for mLock
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ playbackThread->destroyTrack_l(this);
+ }
}
}
-void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
+void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
{
snprintf(buffer, size, " %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
mName - AudioMixer::TRACK0,
@@ -1770,7 +2218,7 @@ void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
mCblk->user);
}
-status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesReady;
@@ -1807,76 +2255,90 @@ status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Bu
getNextBuffer_exit:
buffer->raw = 0;
buffer->frameCount = 0;
+ LOGV("getNextBuffer() no more data");
return NOT_ENOUGH_DATA;
}
-bool AudioFlinger::MixerThread::Track::isReady() const {
+bool AudioFlinger::PlaybackThread::Track::isReady() const {
if (mFillingUpStatus != FS_FILLING) return true;
if (mCblk->framesReady() >= mCblk->frameCount ||
mCblk->forceReady) {
mFillingUpStatus = FS_FILLED;
mCblk->forceReady = 0;
- LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType);
return true;
}
return false;
}
-status_t AudioFlinger::MixerThread::Track::start()
+status_t AudioFlinger::PlaybackThread::Track::start()
{
- LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mMixerThread->addTrack_l(this);
+ LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ playbackThread->addTrack_l(this);
+ }
return NO_ERROR;
}
-void AudioFlinger::MixerThread::Track::stop()
+void AudioFlinger::PlaybackThread::Track::stop()
{
- LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- if (mState > STOPPED) {
- mState = STOPPED;
- // If the track is not active (PAUSED and buffers full), flush buffers
- if (mMixerThread->mActiveTracks.indexOf(this) < 0) {
- reset();
+ LOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ if (mState > STOPPED) {
+ mState = STOPPED;
+ // If the track is not active (PAUSED and buffers full), flush buffers
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ if (playbackThread->mActiveTracks.indexOf(this) < 0) {
+ reset();
+ }
+ LOGV("(> STOPPED) => STOPPED (%d)", mName);
}
- LOGV("(> STOPPED) => STOPPED (%d)", mName);
}
}
-void AudioFlinger::MixerThread::Track::pause()
+void AudioFlinger::PlaybackThread::Track::pause()
{
LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- if (mState == ACTIVE || mState == RESUMING) {
- mState = PAUSING;
- LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ if (mState == ACTIVE || mState == RESUMING) {
+ mState = PAUSING;
+ LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
+ }
}
}
-void AudioFlinger::MixerThread::Track::flush()
+void AudioFlinger::PlaybackThread::Track::flush()
{
LOGV("flush(%d)", mName);
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
- return;
- }
- // No point remaining in PAUSED state after a flush => go to
- // STOPPED state
- mState = STOPPED;
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ Mutex::Autolock _l(thread->mLock);
+ if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
+ return;
+ }
+ // No point remaining in PAUSED state after a flush => go to
+ // STOPPED state
+ mState = STOPPED;
- mCblk->lock.lock();
- // NOTE: reset() will reset cblk->user and cblk->server with
- // the risk that at the same time, the AudioMixer is trying to read
- // data. In this case, getNextBuffer() would return a NULL pointer
- // as audio buffer => the AudioMixer code MUST always test that pointer
- // returned by getNextBuffer() is not NULL!
- reset();
- mCblk->lock.unlock();
+ mCblk->lock.lock();
+ // NOTE: reset() will reset cblk->user and cblk->server with
+ // the risk that at the same time, the AudioMixer is trying to read
+ // data. In this case, getNextBuffer() would return a NULL pointer
+ // as audio buffer => the AudioMixer code MUST always test that pointer
+ // returned by getNextBuffer() is not NULL!
+ reset();
+ mCblk->lock.unlock();
+ }
}
-void AudioFlinger::MixerThread::Track::reset()
+void AudioFlinger::PlaybackThread::Track::reset()
{
// Do not reset twice to avoid discarding data written just after a flush and before
// the audioflinger thread detects the track is stopped.
@@ -1886,17 +2348,17 @@ void AudioFlinger::MixerThread::Track::reset()
// written to buffer
mCblk->flowControlFlag = 1;
mCblk->forceReady = 0;
- mFillingUpStatus = FS_FILLING;
+ mFillingUpStatus = FS_FILLING;
mResetDone = true;
}
}
-void AudioFlinger::MixerThread::Track::mute(bool muted)
+void AudioFlinger::PlaybackThread::Track::mute(bool muted)
{
mMute = muted;
}
-void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
+void AudioFlinger::PlaybackThread::Track::setVolume(float left, float right)
{
mVolume[0] = left;
mVolume[1] = right;
@@ -1905,28 +2367,33 @@ void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
// ----------------------------------------------------------------------------
// RecordTrack constructor must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread::RecordTrack::RecordTrack(
- const sp<MixerThread>& mixerThread,
+AudioFlinger::RecordThread::RecordTrack::RecordTrack(
+ const wp<ThreadBase>& thread,
const sp<Client>& client,
- int inputSource,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
uint32_t flags)
- : TrackBase(mixerThread, client, sampleRate, format,
+ : TrackBase(thread, client, sampleRate, format,
channelCount, frameCount, flags, 0),
- mOverflow(false), mInputSource(inputSource)
+ mOverflow(false)
{
+ LOGV("RecordTrack constructor, size %d", (int)mBufferEnd - (int)mBuffer);
+ if (format == AudioSystem::PCM_16_BIT) {
+ mCblk->frameSize = channelCount * sizeof(int16_t);
+ } else if (format == AudioSystem::PCM_8_BIT) {
+ mCblk->frameSize = channelCount * sizeof(int8_t);
+ } else {
+ mCblk->frameSize = sizeof(int8_t);
+ }
}
-AudioFlinger::MixerThread::RecordTrack::~RecordTrack()
+AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
{
- Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
- mMixerThread->deleteTrackName_l(mName);
}
-status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesAvail;
@@ -1965,180 +2432,234 @@ getNextBuffer_exit:
return NOT_ENOUGH_DATA;
}
-status_t AudioFlinger::MixerThread::RecordTrack::start()
+status_t AudioFlinger::RecordThread::RecordTrack::start()
{
- return mMixerThread->mAudioFlinger->startRecord(this);
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ RecordThread *recordThread = (RecordThread *)thread.get();
+ return recordThread->start(this);
+ }
+ return NO_INIT;
}
-void AudioFlinger::MixerThread::RecordTrack::stop()
+void AudioFlinger::RecordThread::RecordTrack::stop()
{
- mMixerThread->mAudioFlinger->stopRecord(this);
- TrackBase::reset();
- // Force overerrun condition to avoid false overrun callback until first data is
- // read from buffer
- mCblk->flowControlFlag = 1;
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ RecordThread *recordThread = (RecordThread *)thread.get();
+ recordThread->stop(this);
+ TrackBase::reset();
+ // Force overerrun condition to avoid false overrun callback until first data is
+ // read from buffer
+ mCblk->flowControlFlag = 1;
+ }
}
// ----------------------------------------------------------------------------
-AudioFlinger::MixerThread::OutputTrack::OutputTrack(
- const sp<MixerThread>& mixerThread,
+AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
+ const wp<ThreadBase>& thread,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount)
- : Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL),
- mOutputMixerThread(mixerThread)
+ : Track(thread, NULL, AudioSystem::NUM_STREAM_TYPES, sampleRate, format, channelCount, frameCount, NULL),
+ mActive(false)
{
-
- mCblk->out = 1;
- mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
- mCblk->volume[0] = mCblk->volume[1] = 0x1000;
- mOutBuffer.frameCount = 0;
- mCblk->bufferTimeoutMs = 10;
-
- LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p",
- mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
-
+
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();
+ if (mCblk != NULL) {
+ mCblk->out = 1;
+ mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+ mOutBuffer.frameCount = 0;
+ mWaitTimeMs = (playbackThread->frameCount() * 2 * 1000) / playbackThread->sampleRate();
+ playbackThread->mTracks.add(this);
+ LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p mWaitTimeMs %d",
+ mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd, mWaitTimeMs);
+ } else {
+ LOGW("Error creating output track on thread %p", playbackThread);
+ }
}
-AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
+AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack()
{
- stop();
+ clearBufferQueue();
}
-status_t AudioFlinger::MixerThread::OutputTrack::start()
+status_t AudioFlinger::PlaybackThread::OutputTrack::start()
{
status_t status = Track::start();
-
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ mActive = true;
mRetryCount = 127;
return status;
}
-void AudioFlinger::MixerThread::OutputTrack::stop()
+void AudioFlinger::PlaybackThread::OutputTrack::stop()
{
Track::stop();
clearBufferQueue();
mOutBuffer.frameCount = 0;
+ mActive = false;
}
-void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames)
+bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames)
{
Buffer *pInBuffer;
Buffer inBuffer;
uint32_t channels = mCblk->channels;
-
+ bool outputBufferFull = false;
inBuffer.frameCount = frames;
inBuffer.i16 = data;
-
- if (mCblk->user == 0) {
- mOutputMixerThread->mAudioFlinger->mLock.lock();
- bool isMusicActive = mOutputMixerThread->isMusicActive_l();
- mOutputMixerThread->mAudioFlinger->mLock.unlock();
- if (isMusicActive) {
- mCblk->forceReady = 1;
- LOGV("OutputTrack::start() force ready");
- } else if (mCblk->frameCount > frames){
- if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
- uint32_t startFrames = (mCblk->frameCount - frames);
- LOGV("OutputTrack::start() write %d frames", startFrames);
- pInBuffer = new Buffer;
- pInBuffer->mBuffer = new int16_t[startFrames * channels];
- pInBuffer->frameCount = startFrames;
- pInBuffer->i16 = pInBuffer->mBuffer;
- memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
- mBufferQueue.add(pInBuffer);
- } else {
- LOGW ("OutputTrack::write() no more buffers");
+
+ uint32_t waitTimeLeftMs = mWaitTimeMs;
+
+ if (!mActive) {
+ start();
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ MixerThread *mixerThread = (MixerThread *)thread.get();
+ if (mCblk->frameCount > frames){
+ if (mBufferQueue.size() < kMaxOverFlowBuffers) {
+ uint32_t startFrames = (mCblk->frameCount - frames);
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[startFrames * channels];
+ pInBuffer->frameCount = startFrames;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ } else {
+ LOGW ("OutputTrack::write() %p no more buffers in queue", this);
+ }
}
- }
+ }
}
- while (1) {
+ while (waitTimeLeftMs) {
// First write pending buffers, then new data
if (mBufferQueue.size()) {
pInBuffer = mBufferQueue.itemAt(0);
} else {
pInBuffer = &inBuffer;
}
-
+
if (pInBuffer->frameCount == 0) {
break;
}
-
+
if (mOutBuffer.frameCount == 0) {
mOutBuffer.frameCount = pInBuffer->frameCount;
- if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+ nsecs_t startTime = systemTime();
+ if (obtainBuffer(&mOutBuffer, waitTimeLeftMs) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+ LOGV ("OutputTrack::write() %p no more output buffers", this);
+ outputBufferFull = true;
break;
}
+ uint32_t waitTimeMs = (uint32_t)ns2ms(systemTime() - startTime);
+// LOGV("OutputTrack::write() waitTimeMs %d waitTimeLeftMs %d", waitTimeMs, waitTimeLeftMs)
+ if (waitTimeLeftMs >= waitTimeMs) {
+ waitTimeLeftMs -= waitTimeMs;
+ } else {
+ waitTimeLeftMs = 0;
+ }
}
-
+
uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
mCblk->stepUser(outFrames);
pInBuffer->frameCount -= outFrames;
pInBuffer->i16 += outFrames * channels;
mOutBuffer.frameCount -= outFrames;
- mOutBuffer.i16 += outFrames * channels;
-
+ mOutBuffer.i16 += outFrames * channels;
+
if (pInBuffer->frameCount == 0) {
if (mBufferQueue.size()) {
mBufferQueue.removeAt(0);
delete [] pInBuffer->mBuffer;
delete pInBuffer;
+ LOGV("OutputTrack::write() %p released overflow buffer %d", this, mBufferQueue.size());
} else {
break;
}
}
}
-
+
// If we could not write all frames, allocate a buffer and queue it for next time.
if (inBuffer.frameCount) {
- if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+ if (mBufferQueue.size() < kMaxOverFlowBuffers) {
pInBuffer = new Buffer;
pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
pInBuffer->frameCount = inBuffer.frameCount;
pInBuffer->i16 = pInBuffer->mBuffer;
memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
mBufferQueue.add(pInBuffer);
+ LOGV("OutputTrack::write() %p adding overflow buffer %d", this, mBufferQueue.size());
} else {
- LOGW("OutputTrack::write() no more buffers");
+ LOGW("OutputTrack::write() %p no more overflow buffers", this);
}
}
-
+
// Calling write() with a 0 length buffer, means that no more data will be written:
- // If no more buffers are pending, fill output track buffer to make sure it is started
+ // If no more buffers are pending, fill output track buffer to make sure it is started
// by output mixer.
- if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) {
- frames = mCblk->frameCount - mCblk->user;
- pInBuffer = new Buffer;
- pInBuffer->mBuffer = new int16_t[frames * channels];
- pInBuffer->frameCount = frames;
- pInBuffer->i16 = pInBuffer->mBuffer;
- memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
- mBufferQueue.add(pInBuffer);
+ if (frames == 0 && mBufferQueue.size() == 0) {
+ if (mCblk->user < mCblk->frameCount) {
+ frames = mCblk->frameCount - mCblk->user;
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[frames * channels];
+ pInBuffer->frameCount = frames;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ } else {
+ stop();
+ }
}
+ return outputBufferFull;
}
-status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs)
{
int active;
- int timeout = 0;
status_t result;
audio_track_cblk_t* cblk = mCblk;
uint32_t framesReq = buffer->frameCount;
- LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
+// LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
buffer->frameCount = 0;
-
+
uint32_t framesAvail = cblk->framesAvailable();
+
if (framesAvail == 0) {
- return AudioTrack::NO_MORE_BUFFERS;
+ Mutex::Autolock _l(cblk->lock);
+ goto start_loop_here;
+ while (framesAvail == 0) {
+ active = mActive;
+ if (UNLIKELY(!active)) {
+ LOGV("Not active and NO_MORE_BUFFERS");
+ return AudioTrack::NO_MORE_BUFFERS;
+ }
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
+ if (result != NO_ERROR) {
+ return AudioTrack::NO_MORE_BUFFERS;
+ }
+ // read the server count again
+ start_loop_here:
+ framesAvail = cblk->framesAvailable_l();
+ }
}
+// if (framesAvail < framesReq) {
+// return AudioTrack::NO_MORE_BUFFERS;
+// }
+
if (framesReq > framesAvail) {
framesReq = framesAvail;
}
@@ -2156,11 +2677,11 @@ status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvide
}
-void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue()
+void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue()
{
size_t size = mBufferQueue.size();
Buffer *pBuffer;
-
+
for (size_t i = 0; i < size; i++) {
pBuffer = mBufferQueue.itemAt(i);
delete [] pBuffer->mBuffer;
@@ -2192,7 +2713,7 @@ const sp<MemoryDealer>& AudioFlinger::Client::heap() const
// ----------------------------------------------------------------------------
-AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track)
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::PlaybackThread::Track>& track)
: BnAudioTrack(),
mTrack(track)
{
@@ -2244,7 +2765,7 @@ status_t AudioFlinger::TrackHandle::onTransact(
sp<IAudioRecord> AudioFlinger::openRecord(
pid_t pid,
- int inputSource,
+ int input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -2252,14 +2773,13 @@ sp<IAudioRecord> AudioFlinger::openRecord(
uint32_t flags,
status_t *status)
{
- sp<MixerThread::RecordTrack> recordTrack;
+ sp<RecordThread::RecordTrack> recordTrack;
sp<RecordHandle> recordHandle;
sp<Client> client;
wp<Client> wclient;
- AudioStreamIn* input = 0;
- int inFrameCount;
- size_t inputBufferSize;
status_t lStatus;
+ RecordThread *thread;
+ size_t inFrameCount;
// check calling permissions
if (!recordingAllowed()) {
@@ -2267,30 +2787,15 @@ sp<IAudioRecord> AudioFlinger::openRecord(
goto Exit;
}
- if (uint32_t(inputSource) >= AudioRecord::NUM_INPUT_SOURCES) {
- LOGE("invalid stream type");
- lStatus = BAD_VALUE;
- goto Exit;
- }
-
- if (mAudioRecordThread == 0) {
- LOGE("Audio record thread not started");
- lStatus = NO_INIT;
- goto Exit;
- }
-
-
- // Check that audio input stream accepts requested audio parameters
- inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
- if (inputBufferSize == 0) {
- lStatus = BAD_VALUE;
- LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d", sampleRate, format, channelCount);
- goto Exit;
- }
-
// add client to list
{ // scope for mLock
Mutex::Autolock _l(mLock);
+ thread = checkRecordThread_l(input);
+ if (thread == NULL) {
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
wclient = mClients.valueFor(pid);
if (wclient != NULL) {
client = wclient.promote();
@@ -2299,12 +2804,8 @@ sp<IAudioRecord> AudioFlinger::openRecord(
mClients.add(pid, client);
}
- // frameCount must be a multiple of input buffer size
- inFrameCount = inputBufferSize/channelCount/sizeof(short);
- frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
-
// create new record track. The record track uses one track in mHardwareMixerThread by convention.
- recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, inputSource, sampleRate,
+ recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate,
format, channelCount, frameCount, flags);
}
if (recordTrack->getCblk() == NULL) {
@@ -2324,22 +2825,9 @@ Exit:
return recordHandle;
}
-status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) {
- if (mAudioRecordThread != 0) {
- return mAudioRecordThread->start(recordTrack);
- }
- return NO_INIT;
-}
-
-void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) {
- if (mAudioRecordThread != 0) {
- mAudioRecordThread->stop(recordTrack);
- }
-}
-
// ----------------------------------------------------------------------------
-AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack)
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordThread::RecordTrack>& recordTrack)
: BnAudioRecord(),
mRecordTrack(recordTrack)
{
@@ -2371,86 +2859,164 @@ status_t AudioFlinger::RecordHandle::onTransact(
// ----------------------------------------------------------------------------
-AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware,
- const sp<AudioFlinger>& audioFlinger) :
- mAudioHardware(audioHardware),
- mAudioFlinger(audioFlinger),
- mActive(false)
+AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels) :
+ ThreadBase(audioFlinger),
+ mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
{
+ mReqChannelCount = AudioSystem::popCount(channels);
+ mReqSampleRate = sampleRate;
+ readInputParameters();
+ sendConfigEvent(AudioSystem::INPUT_OPENED);
}
-AudioFlinger::AudioRecordThread::~AudioRecordThread()
+
+AudioFlinger::RecordThread::~RecordThread()
{
+ delete[] mRsmpInBuffer;
+ if (mResampler != 0) {
+ delete mResampler;
+ delete[] mRsmpOutBuffer;
+ }
}
-bool AudioFlinger::AudioRecordThread::threadLoop()
+void AudioFlinger::RecordThread::onFirstRef()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "Record Thread %p", this);
+
+ run(buffer, PRIORITY_URGENT_AUDIO);
+}
+bool AudioFlinger::RecordThread::threadLoop()
{
- LOGV("AudioRecordThread: start record loop");
AudioBufferProvider::Buffer buffer;
- int inBufferSize = 0;
- int inFrameCount = 0;
- AudioStreamIn* input = 0;
+ sp<RecordTrack> activeTrack;
- mActive = 0;
-
// start recording
while (!exitPending()) {
- if (!mActive) {
- mLock.lock();
- if (!mActive && !exitPending()) {
- LOGV("AudioRecordThread: loop stopping");
- if (input) {
- delete input;
- input = 0;
+
+ processConfigEvents();
+
+ { // scope for mLock
+ Mutex::Autolock _l(mLock);
+ checkForNewParameters_l();
+ if (mActiveTrack == 0 && mConfigEvents.isEmpty()) {
+ if (!mStandby) {
+ mInput->standby();
+ mStandby = true;
}
- mRecordTrack.clear();
- mStopped.signal();
+ if (exitPending()) break;
+
+ LOGV("RecordThread: loop stopping");
+ // go to sleep
mWaitWorkCV.wait(mLock);
-
- LOGV("AudioRecordThread: loop starting");
- if (mRecordTrack != 0) {
- input = mAudioHardware->openInputStream(
- mRecordTrack->inputSource(),
- mRecordTrack->format(),
- mRecordTrack->channelCount(),
- mRecordTrack->sampleRate(),
- &mStartStatus,
- (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16));
- if (input != 0) {
- inBufferSize = input->bufferSize();
- inFrameCount = inBufferSize/input->frameSize();
+ LOGV("RecordThread: loop starting");
+ continue;
+ }
+ if (mActiveTrack != 0) {
+ if (mActiveTrack->mState == TrackBase::PAUSING) {
+ mActiveTrack.clear();
+ mStartStopCond.broadcast();
+ } else if (mActiveTrack->mState == TrackBase::RESUMING) {
+ mRsmpInIndex = mFrameCount;
+ if (mReqChannelCount != mActiveTrack->channelCount()) {
+ mActiveTrack.clear();
+ } else {
+ mActiveTrack->mState = TrackBase::ACTIVE;
}
- } else {
- mStartStatus = NO_INIT;
- }
- if (mStartStatus !=NO_ERROR) {
- LOGW("record start failed, status %d", mStartStatus);
- mActive = false;
- mRecordTrack.clear();
+ mStartStopCond.broadcast();
}
- mWaitWorkCV.signal();
+ mStandby = false;
}
- mLock.unlock();
- } else if (mRecordTrack != 0) {
-
- buffer.frameCount = inFrameCount;
- if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR &&
- (int)buffer.frameCount == inFrameCount)) {
- LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
- ssize_t bytesRead = input->read(buffer.raw, inBufferSize);
- if (bytesRead < 0) {
- LOGE("Error reading audio input");
- sleep(1);
+ }
+
+ if (mActiveTrack != 0) {
+ buffer.frameCount = mFrameCount;
+ if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+ size_t framesOut = buffer.frameCount;
+ if (mResampler == 0) {
+ // no resampling
+ while (framesOut) {
+ size_t framesIn = mFrameCount - mRsmpInIndex;
+ if (framesIn) {
+ int8_t *src = (int8_t *)mRsmpInBuffer + mRsmpInIndex * mFrameSize;
+ int8_t *dst = buffer.i8 + (buffer.frameCount - framesOut) * mActiveTrack->mCblk->frameSize;
+ if (framesIn > framesOut)
+ framesIn = framesOut;
+ mRsmpInIndex += framesIn;
+ framesOut -= framesIn;
+ if (mChannelCount == mReqChannelCount ||
+ mFormat != AudioSystem::PCM_16_BIT) {
+ memcpy(dst, src, framesIn * mFrameSize);
+ } else {
+ int16_t *src16 = (int16_t *)src;
+ int16_t *dst16 = (int16_t *)dst;
+ if (mChannelCount == 1) {
+ while (framesIn--) {
+ *dst16++ = *src16;
+ *dst16++ = *src16++;
+ }
+ } else {
+ while (framesIn--) {
+ *dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1);
+ src16 += 2;
+ }
+ }
+ }
+ }
+ if (framesOut && mFrameCount == mRsmpInIndex) {
+ ssize_t bytesRead;
+ if (framesOut == mFrameCount &&
+ (mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) {
+ bytesRead = mInput->read(buffer.raw, mInputBytes);
+ framesOut = 0;
+ } else {
+ bytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
+ mRsmpInIndex = 0;
+ }
+ if (bytesRead < 0) {
+ LOGE("Error reading audio input");
+ sleep(1);
+ mRsmpInIndex = mFrameCount;
+ framesOut = 0;
+ buffer.frameCount = 0;
+ }
+ }
+ }
+ } else {
+ // resampling
+
+ memset(mRsmpOutBuffer, 0, framesOut * 2 * sizeof(int32_t));
+ // alter output frame count as if we were expecting stereo samples
+ if (mChannelCount == 1 && mReqChannelCount == 1) {
+ framesOut >>= 1;
+ }
+ mResampler->resample(mRsmpOutBuffer, framesOut, this);
+ // ditherAndClamp() works as long as all buffers returned by mActiveTrack->getNextBuffer()
+ // are 32 bit aligned which should be always true.
+ if (mChannelCount == 2 && mReqChannelCount == 1) {
+ AudioMixer::ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
+ // the resampler always outputs stereo samples: do post stereo to mono conversion
+ int16_t *src = (int16_t *)mRsmpOutBuffer;
+ int16_t *dst = buffer.i16;
+ while (framesOut--) {
+ *dst++ = (int16_t)(((int32_t)*src + (int32_t)*(src + 1)) >> 1);
+ src += 2;
+ }
+ } else {
+ AudioMixer::ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
+ }
+
}
- mRecordTrack->releaseBuffer(&buffer);
- mRecordTrack->overflow();
+ mActiveTrack->releaseBuffer(&buffer);
+ mActiveTrack->overflow();
}
-
// client isn't retrieving buffers fast enough
else {
- if (!mRecordTrack->setOverflow())
- LOGW("AudioRecordThread: buffer overflow");
+ if (!mActiveTrack->setOverflow())
+ LOGW("RecordThread: buffer overflow");
// Release the processor for a while before asking for a new buffer.
// This will give the application more chance to read from the buffer and
// clear the overflow.
@@ -2459,65 +3025,64 @@ bool AudioFlinger::AudioRecordThread::threadLoop()
}
}
-
- if (input) {
- delete input;
+ if (!mStandby) {
+ mInput->standby();
}
- mRecordTrack.clear();
-
+ mActiveTrack.clear();
+
+ sendConfigEvent(AudioSystem::INPUT_CLOSED);
+ processConfigEvents();
+
+ LOGV("RecordThread %p exiting", this);
return false;
}
-status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack)
+status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
{
- LOGV("AudioRecordThread::start");
+ LOGV("RecordThread::start");
AutoMutex lock(&mLock);
- mActive = true;
- // If starting the active track, just reset mActive in case a stop
- // was pending and exit
- if (recordTrack == mRecordTrack.get()) return NO_ERROR;
- if (mRecordTrack != 0) return -EBUSY;
+ if (mActiveTrack != 0) {
+ if (recordTrack != mActiveTrack.get()) return -EBUSY;
- mRecordTrack = recordTrack;
+ if (mActiveTrack->mState == TrackBase::PAUSING) mActiveTrack->mState = TrackBase::RESUMING;
+ return NO_ERROR;
+ }
+
+ mActiveTrack = recordTrack;
+ mActiveTrack->mState = TrackBase::RESUMING;
// signal thread to start
LOGV("Signal record thread");
mWaitWorkCV.signal();
- mWaitWorkCV.wait(mLock);
- LOGV("Record started, status %d", mStartStatus);
- return mStartStatus;
-}
-
-void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) {
- LOGV("AudioRecordThread::stop");
- AutoMutex lock(&mLock);
- if (mActive && (recordTrack == mRecordTrack.get())) {
- mActive = false;
- mStopped.wait(mLock);
+ mStartStopCond.wait(mLock);
+ if (mActiveTrack != 0) {
+ LOGV("Record started OK");
+ return NO_ERROR;
+ } else {
+ LOGV("Record failed to start");
+ return BAD_VALUE;
}
}
-void AudioFlinger::AudioRecordThread::exit()
-{
- LOGV("AudioRecordThread::exit");
- {
- AutoMutex lock(&mLock);
- requestExit();
- mWaitWorkCV.signal();
+void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
+ LOGV("RecordThread::stop");
+ AutoMutex lock(&mLock);
+ if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
+ mActiveTrack->mState = TrackBase::PAUSING;
+ mStartStopCond.wait(mLock);
}
- requestExitAndWait();
}
-status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args)
+status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
pid_t pid = 0;
- if (mRecordTrack != 0 && mRecordTrack->mClient != 0) {
- snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid());
+ if (mActiveTrack != 0 && mActiveTrack->mClient != 0) {
+ snprintf(buffer, SIZE, "Record client pid: %d\n", mActiveTrack->mClient->pid());
result.append(buffer);
} else {
result.append("No record client\n");
@@ -2526,6 +3091,468 @@ status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& a
return NO_ERROR;
}
+status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ size_t framesReq = buffer->frameCount;
+ size_t framesReady = mFrameCount - mRsmpInIndex;
+ int channelCount;
+
+ if (framesReady == 0) {
+ ssize_t bytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
+ if (bytesRead < 0) {
+ LOGE("RecordThread::getNextBuffer() Error reading audio input");
+ sleep(1);
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
+ }
+ mRsmpInIndex = 0;
+ framesReady = mFrameCount;
+ }
+
+ if (framesReq > framesReady) {
+ framesReq = framesReady;
+ }
+
+ if (mChannelCount == 1 && mReqChannelCount == 2) {
+ channelCount = 1;
+ } else {
+ channelCount = 2;
+ }
+ buffer->raw = mRsmpInBuffer + mRsmpInIndex * channelCount;
+ buffer->frameCount = framesReq;
+ return NO_ERROR;
+}
+
+void AudioFlinger::RecordThread::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ mRsmpInIndex += buffer->frameCount;
+ buffer->frameCount = 0;
+}
+
+bool AudioFlinger::RecordThread::checkForNewParameters_l()
+{
+ bool reconfig = false;
+
+ while (!mNewParameters.isEmpty()) {
+ status_t status = NO_ERROR;
+ String8 keyValuePair = mNewParameters[0];
+ AudioParameter param = AudioParameter(keyValuePair);
+ int value;
+ int reqFormat = mFormat;
+ int reqSamplingRate = mReqSampleRate;
+ int reqChannelCount = mReqChannelCount;
+
+ mNewParameters.removeAt(0);
+
+ if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+ reqSamplingRate = value;
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
+ reqFormat = value;
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+ reqChannelCount = AudioSystem::popCount(value);
+ reconfig = true;
+ }
+ if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+ // do not accept frame count changes if tracks are open as the track buffer
+ // size depends on frame count and correct behavior would not be garantied
+ // if frame count is changed after track creation
+ if (mActiveTrack != 0) {
+ status = INVALID_OPERATION;
+ } else {
+ reconfig = true;
+ }
+ }
+ if (status == NO_ERROR) {
+ status = mInput->setParameters(keyValuePair);
+ if (status == INVALID_OPERATION) {
+ mInput->standby();
+ status = mInput->setParameters(keyValuePair);
+ }
+ if (reconfig) {
+ if (status == BAD_VALUE &&
+ reqFormat == mInput->format() && reqFormat == AudioSystem::PCM_16_BIT &&
+ ((int)mInput->sampleRate() <= 2 * reqSamplingRate) &&
+ (AudioSystem::popCount(mInput->channels()) < 3) && (reqChannelCount < 3)) {
+ status = NO_ERROR;
+ }
+ if (status == NO_ERROR) {
+ readInputParameters();
+ sendConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
+ }
+ }
+ }
+ mParamStatus = status;
+ mParamCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ return reconfig;
+}
+
+String8 AudioFlinger::RecordThread::getParameters(const String8& keys)
+{
+ return mInput->getParameters(keys);
+}
+
+void AudioFlinger::RecordThread::audioConfigChanged(int event, int param) {
+ AudioSystem::OutputDescriptor desc;
+ void *param2 = 0;
+
+ switch (event) {
+ case AudioSystem::INPUT_OPENED:
+ case AudioSystem::INPUT_CONFIG_CHANGED:
+ desc.channels = mChannelCount;
+ desc.samplingRate = mSampleRate;
+ desc.format = mFormat;
+ desc.frameCount = mFrameCount;
+ desc.latency = 0;
+ param2 = &desc;
+ break;
+
+ case AudioSystem::INPUT_CLOSED:
+ default:
+ break;
+ }
+ mAudioFlinger->audioConfigChanged(event, this, param2);
+}
+
+void AudioFlinger::RecordThread::readInputParameters()
+{
+ if (mRsmpInBuffer) delete mRsmpInBuffer;
+ if (mRsmpOutBuffer) delete mRsmpOutBuffer;
+ if (mResampler) delete mResampler;
+ mResampler = 0;
+
+ mSampleRate = mInput->sampleRate();
+ mChannelCount = AudioSystem::popCount(mInput->channels());
+ mFormat = mInput->format();
+ mFrameSize = mInput->frameSize();
+ mInputBytes = mInput->bufferSize();
+ mFrameCount = mInputBytes / mFrameSize;
+ mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount];
+
+ if (mSampleRate != mReqSampleRate && mChannelCount < 3 && mReqChannelCount < 3)
+ {
+ int channelCount;
+ // optmization: if mono to mono, use the resampler in stereo to stereo mode to avoid
+ // stereo to mono post process as the resampler always outputs stereo.
+ if (mChannelCount == 1 && mReqChannelCount == 2) {
+ channelCount = 1;
+ } else {
+ channelCount = 2;
+ }
+ mResampler = AudioResampler::create(16, channelCount, mReqSampleRate);
+ mResampler->setSampleRate(mSampleRate);
+ mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN);
+ mRsmpOutBuffer = new int32_t[mFrameCount * 2];
+
+ // optmization: if mono to mono, alter input frame count as if we were inputing stereo samples
+ if (mChannelCount == 1 && mReqChannelCount == 1) {
+ mFrameCount >>= 1;
+ }
+
+ }
+ mRsmpInIndex = mFrameCount;
+}
+
+// ----------------------------------------------------------------------------
+
+int AudioFlinger::openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags)
+{
+ status_t status;
+ PlaybackThread *thread = NULL;
+ mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
+ uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+ uint32_t format = pFormat ? *pFormat : 0;
+ uint32_t channels = pChannels ? *pChannels : 0;
+ uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
+
+ LOGV("openOutput(), Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
+ pDevices ? *pDevices : 0,
+ samplingRate,
+ format,
+ channels,
+ flags);
+
+ if (pDevices == NULL || *pDevices == 0) {
+ return 0;
+ }
+ Mutex::Autolock _l(mLock);
+
+ AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices,
+ (int *)&format,
+ &channels,
+ &samplingRate,
+ &status);
+ LOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d",
+ output,
+ samplingRate,
+ format,
+ channels,
+ status);
+
+ mHardwareStatus = AUDIO_HW_IDLE;
+ if (output != 0) {
+ if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
+ (format != AudioSystem::PCM_16_BIT) ||
+ (channels != AudioSystem::CHANNEL_OUT_STEREO)) {
+ thread = new DirectOutputThread(this, output);
+ LOGV("openOutput() created direct output: ID %d thread %p", (mNextThreadId + 1), thread);
+ } else {
+ thread = new MixerThread(this, output);
+ LOGV("openOutput() created mixer output: ID %d thread %p", (mNextThreadId + 1), thread);
+ }
+ mPlaybackThreads.add(++mNextThreadId, thread);
+
+ if (pSamplingRate) *pSamplingRate = samplingRate;
+ if (pFormat) *pFormat = format;
+ if (pChannels) *pChannels = channels;
+ if (pLatencyMs) *pLatencyMs = thread->latency();
+ }
+
+ return mNextThreadId;
+}
+
+int AudioFlinger::openDuplicateOutput(int output1, int output2)
+{
+ Mutex::Autolock _l(mLock);
+ MixerThread *thread1 = checkMixerThread_l(output1);
+ MixerThread *thread2 = checkMixerThread_l(output2);
+
+ if (thread1 == NULL || thread2 == NULL) {
+ LOGW("openDuplicateOutput() wrong output mixer type for output %d or %d", output1, output2);
+ return 0;
+ }
+
+
+ DuplicatingThread *thread = new DuplicatingThread(this, thread1);
+ thread->addOutputTrack(thread2);
+ mPlaybackThreads.add(++mNextThreadId, thread);
+ return mNextThreadId;
+}
+
+status_t AudioFlinger::closeOutput(int output)
+{
+ // keep strong reference on the playback thread so that
+ // it is not destroyed while exit() is executed
+ sp <PlaybackThread> thread;
+ {
+ Mutex::Autolock _l(mLock);
+ thread = checkPlaybackThread_l(output);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("closeOutput() %d", output);
+
+ if (thread->type() == PlaybackThread::MIXER) {
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i)->type() == PlaybackThread::DUPLICATING) {
+ DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
+ dupThread->removeOutputTrack((MixerThread *)thread.get());
+ }
+ }
+ }
+ mPlaybackThreads.removeItem(output);
+ }
+ thread->exit();
+
+ if (thread->type() != PlaybackThread::DUPLICATING) {
+ mAudioHardware->closeOutputStream(thread->getOutput());
+ }
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::suspendOutput(int output)
+{
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("suspendOutput() %d", output);
+ thread->suspend();
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::restoreOutput(int output)
+{
+ Mutex::Autolock _l(mLock);
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("restoreOutput() %d", output);
+
+ thread->restore();
+
+ return NO_ERROR;
+}
+
+int AudioFlinger::openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics)
+{
+ status_t status;
+ RecordThread *thread = NULL;
+ uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+ uint32_t format = pFormat ? *pFormat : 0;
+ uint32_t channels = pChannels ? *pChannels : 0;
+ uint32_t reqSamplingRate = samplingRate;
+ uint32_t reqFormat = format;
+ uint32_t reqChannels = channels;
+
+ if (pDevices == NULL || *pDevices == 0) {
+ return 0;
+ }
+ Mutex::Autolock _l(mLock);
+
+ AudioStreamIn *input = mAudioHardware->openInputStream(*pDevices,
+ (int *)&format,
+ &channels,
+ &samplingRate,
+ &status,
+ (AudioSystem::audio_in_acoustics)acoustics);
+ LOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d",
+ input,
+ samplingRate,
+ format,
+ channels,
+ acoustics,
+ status);
+
+ // If the input could not be opened with the requested parameters and we can handle the conversion internally,
+ // try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo
+ // or stereo to mono conversions on 16 bit PCM inputs.
+ if (input == 0 && status == BAD_VALUE &&
+ reqFormat == format && format == AudioSystem::PCM_16_BIT &&
+ (samplingRate <= 2 * reqSamplingRate) &&
+ (AudioSystem::popCount(channels) < 3) && (AudioSystem::popCount(reqChannels) < 3)) {
+ LOGV("openInput() reopening with proposed sampling rate and channels");
+ input = mAudioHardware->openInputStream(*pDevices,
+ (int *)&format,
+ &channels,
+ &samplingRate,
+ &status,
+ (AudioSystem::audio_in_acoustics)acoustics);
+ }
+
+ if (input != 0) {
+ // Start record thread
+ thread = new RecordThread(this, input, reqSamplingRate, reqChannels);
+ mRecordThreads.add(++mNextThreadId, thread);
+ LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread);
+ if (pSamplingRate) *pSamplingRate = reqSamplingRate;
+ if (pFormat) *pFormat = format;
+ if (pChannels) *pChannels = reqChannels;
+
+ input->standby();
+ }
+
+ return mNextThreadId;
+}
+
+status_t AudioFlinger::closeInput(int input)
+{
+ // keep strong reference on the record thread so that
+ // it is not destroyed while exit() is executed
+ sp <RecordThread> thread;
+ {
+ Mutex::Autolock _l(mLock);
+ thread = checkRecordThread_l(input);
+ if (thread == NULL) {
+ return BAD_VALUE;
+ }
+
+ LOGV("closeInput() %d", input);
+ mRecordThreads.removeItem(input);
+ }
+ thread->exit();
+
+ mAudioHardware->closeInputStream(thread->getInput());
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::setStreamOutput(uint32_t stream, int output)
+{
+ Mutex::Autolock _l(mLock);
+ MixerThread *dstThread = checkMixerThread_l(output);
+ if (dstThread == NULL) {
+ LOGW("setStreamOutput() bad output id %d", output);
+ return BAD_VALUE;
+ }
+
+ LOGV("setStreamOutput() stream %d to output %d", stream, output);
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
+ if (thread != dstThread &&
+ thread->type() != PlaybackThread::DIRECT) {
+ MixerThread *srcThread = (MixerThread *)thread;
+ SortedVector < sp<MixerThread::Track> > tracks;
+ SortedVector < wp<MixerThread::Track> > activeTracks;
+ srcThread->getTracks(tracks, activeTracks, stream);
+ if (tracks.size()) {
+ dstThread->putTracks(tracks, activeTracks);
+ }
+ dstThread->sendConfigEvent(AudioSystem::STREAM_CONFIG_CHANGED, stream);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+// checkPlaybackThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
+{
+ PlaybackThread *thread = NULL;
+ if (mPlaybackThreads.indexOfKey(output) >= 0) {
+ thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();
+ }
+ return thread;
+}
+
+// checkMixerThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(int output) const
+{
+ PlaybackThread *thread = checkPlaybackThread_l(output);
+ if (thread != NULL) {
+ if (thread->type() == PlaybackThread::DIRECT) {
+ thread = NULL;
+ }
+ }
+ return (MixerThread *)thread;
+}
+
+// checkRecordThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(int input) const
+{
+ RecordThread *thread = NULL;
+ if (mRecordThreads.indexOfKey(input) >= 0) {
+ thread = (RecordThread *)mRecordThreads.valueFor(input).get();
+ }
+ return thread;
+}
+
+// ----------------------------------------------------------------------------
+
status_t AudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -2533,6 +3560,7 @@ status_t AudioFlinger::onTransact(
}
// ----------------------------------------------------------------------------
+
void AudioFlinger::instantiate() {
defaultServiceManager()->addService(
String16("media.audio_flinger"), new AudioFlinger());
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 634934e..65c148e 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -30,8 +30,7 @@
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/threads.h>
-#include <utils/MemoryDealer.h>
-#include <utils/KeyedVector.h>
+#include <binder/MemoryDealer.h>
#include <utils/SortedVector.h>
#include <utils/Vector.h>
@@ -44,6 +43,7 @@ namespace android {
class audio_track_cblk_t;
class AudioMixer;
class AudioBuffer;
+class AudioResampler;
// ----------------------------------------------------------------------------
@@ -56,7 +56,7 @@ class AudioBuffer;
static const nsecs_t kStandbyTimeInNsecs = seconds(3);
-class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient
+class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient
{
public:
static void instantiate();
@@ -73,6 +73,7 @@ public:
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ int output,
status_t *status);
virtual uint32_t sampleRate(int output) const;
@@ -87,33 +88,51 @@ public:
virtual float masterVolume() const;
virtual bool masterMute() const;
- virtual status_t setStreamVolume(int stream, float value);
+ virtual status_t setStreamVolume(int stream, float value, int output);
virtual status_t setStreamMute(int stream, bool muted);
- virtual float streamVolume(int stream) const;
+ virtual float streamVolume(int stream, int output) const;
virtual bool streamMute(int stream) const;
- virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask);
- virtual uint32_t getRouting(int mode) const;
-
virtual status_t setMode(int mode);
- virtual int getMode() const;
virtual status_t setMicMute(bool state);
virtual bool getMicMute() const;
virtual bool isMusicActive() const;
- virtual bool isA2dpEnabled() const;
-
- virtual status_t setParameter(const char* key, const char* value);
+ virtual status_t setParameters(int ioHandle, const String8& keyValuePairs);
+ virtual String8 getParameters(int ioHandle, const String8& keys);
virtual void registerClient(const sp<IAudioFlingerClient>& client);
-
+
virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
-
- virtual void wakeUp() { mWaitWorkCV.broadcast(); }
-
+
+ virtual int openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags);
+
+ virtual int openDuplicateOutput(int output1, int output2);
+
+ virtual status_t closeOutput(int output);
+
+ virtual status_t suspendOutput(int output);
+
+ virtual status_t restoreOutput(int output);
+
+ virtual int openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics);
+
+ virtual status_t closeInput(int input);
+
+ virtual status_t setStreamOutput(uint32_t stream, int output);
+
// IBinder::DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
@@ -139,7 +158,7 @@ public:
// record interface
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int inputSource,
+ int input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -156,27 +175,7 @@ public:
private:
AudioFlinger();
virtual ~AudioFlinger();
-
- void setOutput(int outputType);
- void doSetOutput(int outputType);
-
-#ifdef WITH_A2DP
- void setA2dpEnabled_l(bool enable);
- void checkA2dpEnabledChange_l();
-#endif
- static bool streamForcedToSpeaker(int streamType);
-
- // Management of forced route to speaker for certain track types.
- enum force_speaker_command {
- ACTIVE_TRACK_ADDED = 0,
- ACTIVE_TRACK_REMOVED,
- CHECK_ROUTE_RESTORE_TIME,
- FORCE_ROUTE_RESTORE
- };
- void handleForcedSpeakerRoute(int command);
-#ifdef WITH_A2DP
- void handleRouteDisablesA2dp_l(int routes);
-#endif
+
// Internal dump utilites.
status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
@@ -201,14 +200,17 @@ private:
class TrackHandle;
class RecordHandle;
- class AudioRecordThread;
-
-
- // --- MixerThread ---
- class MixerThread : public Thread {
+ class RecordThread;
+ class PlaybackThread;
+ class MixerThread;
+ class DirectOutputThread;
+ class Track;
+ class RecordTrack;
+
+ class ThreadBase : public Thread {
public:
-
- // --- Track ---
+ ThreadBase (const sp<AudioFlinger>& audioFlinger);
+ virtual ~ThreadBase();
// base for record and playback
class TrackBase : public AudioBufferProvider, public RefBase {
@@ -230,7 +232,7 @@ private:
// The upper 16 bits are used for track-specific flags.
};
- TrackBase(const sp<MixerThread>& mixerThread,
+ TrackBase(const wp<ThreadBase>& thread,
const sp<Client>& client,
uint32_t sampleRate,
int format,
@@ -243,11 +245,15 @@ private:
virtual status_t start() = 0;
virtual void stop() = 0;
sp<IMemory> getCblk() const;
+ audio_track_cblk_t* cblk() const { return mCblk; }
protected:
- friend class MixerThread;
+ friend class ThreadBase;
friend class RecordHandle;
- friend class AudioRecordThread;
+ friend class PlaybackThread;
+ friend class RecordThread;
+ friend class MixerThread;
+ friend class DirectOutputThread;
TrackBase(const TrackBase&);
TrackBase& operator = (const TrackBase&);
@@ -255,10 +261,6 @@ private:
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
- audio_track_cblk_t* cblk() const {
- return mCblk;
- }
-
int format() const {
return mFormat;
}
@@ -269,10 +271,6 @@ private:
void* getBuffer(uint32_t offset, uint32_t frames) const;
- int name() const {
- return mName;
- }
-
bool isStopped() const {
return mState == STOPPED;
}
@@ -284,14 +282,13 @@ private:
bool step();
void reset();
- sp<MixerThread> mMixerThread;
+ wp<ThreadBase> mThread;
sp<Client> mClient;
sp<IMemory> mCblkMemory;
audio_track_cblk_t* mCblk;
void* mBuffer;
void* mBufferEnd;
uint32_t mFrameCount;
- int mName;
// we don't really need a lock for these
int mState;
int mClientTid;
@@ -299,10 +296,69 @@ private:
uint32_t mFlags;
};
+ class ConfigEvent {
+ public:
+ ConfigEvent() : mEvent(0), mParam(0) {}
+
+ int mEvent;
+ int mParam;
+ };
+
+ uint32_t sampleRate() const;
+ int channelCount() const;
+ int format() const;
+ size_t frameCount() const;
+ void wakeUp() { mWaitWorkCV.broadcast(); }
+ void exit();
+ virtual bool checkForNewParameters_l() = 0;
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys) = 0;
+ virtual void audioConfigChanged(int event, int param = 0) = 0;
+ void sendConfigEvent(int event, int param = 0);
+ void sendConfigEvent_l(int event, int param = 0);
+ void processConfigEvents();
+
+ mutable Mutex mLock;
+
+ protected:
+
+ friend class Track;
+ friend class TrackBase;
+ friend class PlaybackThread;
+ friend class MixerThread;
+ friend class DirectOutputThread;
+ friend class DuplicatingThread;
+ friend class RecordThread;
+ friend class RecordTrack;
+
+ Condition mWaitWorkCV;
+ sp<AudioFlinger> mAudioFlinger;
+ uint32_t mSampleRate;
+ size_t mFrameCount;
+ int mChannelCount;
+ int mFormat;
+ uint32_t mFrameSize;
+ Condition mParamCond;
+ Vector<String8> mNewParameters;
+ status_t mParamStatus;
+ Vector<ConfigEvent *> mConfigEvents;
+ bool mStandby;
+ };
+
+ // --- PlaybackThread ---
+ class PlaybackThread : public ThreadBase {
+ public:
+
+ enum type {
+ MIXER,
+ DIRECT,
+ DUPLICATING
+ };
+
// playback track
class Track : public TrackBase {
public:
- Track( const sp<MixerThread>& mixerThread,
+ Track( const wp<ThreadBase>& thread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
@@ -321,6 +377,9 @@ private:
void destroy();
void mute(bool);
void setVolume(float left, float right);
+ int name() const {
+ return mName;
+ }
int type() const {
return mStreamType;
@@ -328,29 +387,25 @@ private:
protected:
- friend class MixerThread;
+ friend class ThreadBase;
friend class AudioFlinger;
- friend class AudioFlinger::TrackHandle;
+ friend class TrackHandle;
+ friend class PlaybackThread;
+ friend class MixerThread;
+ friend class DirectOutputThread;
Track(const Track&);
Track& operator = (const Track&);
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
- bool isMuted() const {
- return (mMute || mMixerThread->mStreamTypes[mStreamType].mute);
- }
-
+ bool isMuted() { return mMute; }
bool isPausing() const {
return mState == PAUSING;
}
-
bool isPaused() const {
return mState == PAUSED;
}
-
bool isReady() const;
-
void setPaused() { mState = PAUSED; }
void reset();
@@ -364,54 +419,20 @@ private:
sp<IMemory> mSharedBuffer;
bool mResetDone;
int mStreamType;
+ int mName;
}; // end of Track
- // record track
- class RecordTrack : public TrackBase {
- public:
- RecordTrack(const sp<MixerThread>& mixerThread,
- const sp<Client>& client,
- int inputSource,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount,
- uint32_t flags);
- ~RecordTrack();
-
- virtual status_t start();
- virtual void stop();
-
- bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
- bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
-
- int inputSource() const { return mInputSource; }
-
- private:
- friend class AudioFlinger;
- friend class AudioFlinger::RecordHandle;
- friend class AudioFlinger::AudioRecordThread;
- friend class MixerThread;
-
- RecordTrack(const Track&);
- RecordTrack& operator = (const Track&);
-
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
- bool mOverflow;
- int mInputSource;
- };
// playback track
class OutputTrack : public Track {
public:
-
+
class Buffer: public AudioBufferProvider::Buffer {
public:
int16_t *mBuffer;
};
-
- OutputTrack( const sp<MixerThread>& mixerThread,
+
+ OutputTrack( const wp<ThreadBase>& thread,
uint32_t sampleRate,
int format,
int channelCount,
@@ -420,35 +441,35 @@ private:
virtual status_t start();
virtual void stop();
- void write(int16_t* data, uint32_t frames);
+ bool write(int16_t* data, uint32_t frames);
bool bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
+ bool isActive() { return mActive; }
+ wp<ThreadBase>& thread() { return mThread; }
private:
- status_t obtainBuffer(AudioBufferProvider::Buffer* buffer);
+ status_t obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs);
void clearBufferQueue();
-
- sp<MixerThread> mOutputMixerThread;
+
+ // Maximum number of pending buffers allocated by OutputTrack::write()
+ static const uint8_t kMaxOverFlowBuffers = 3;
+
Vector < Buffer* > mBufferQueue;
AudioBufferProvider::Buffer mOutBuffer;
- uint32_t mFramesWritten;
-
- }; // end of OutputTrack
+ uint32_t mWaitTimeMs;
+ bool mActive;
- MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType);
- virtual ~MixerThread();
+ }; // end of OutputTrack
+
+ PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+ virtual ~PlaybackThread();
virtual status_t dump(int fd, const Vector<String16>& args);
// Thread virtuals
- virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
- virtual uint32_t sampleRate() const;
- virtual int channelCount() const;
- virtual int format() const;
- virtual size_t frameCount() const;
virtual uint32_t latency() const;
virtual status_t setMasterVolume(float value);
@@ -463,9 +484,8 @@ private:
virtual float streamVolume(int stream) const;
virtual bool streamMute(int stream) const;
- bool isMusicActive_l() const;
-
-
+ bool isMusicActive() const;
+
sp<Track> createTrack_l(
const sp<AudioFlinger::Client>& client,
int streamType,
@@ -475,13 +495,15 @@ private:
int frameCount,
const sp<IMemory>& sharedBuffer,
status_t *status);
-
- void getTracks_l(SortedVector < sp<Track> >& tracks,
- SortedVector < wp<Track> >& activeTracks);
- void putTracks_l(SortedVector < sp<Track> >& tracks,
- SortedVector < wp<Track> >& activeTracks);
- void setOuputTrack(OutputTrack *track) { mOutputTrack = track; }
-
+
+ AudioStreamOut* getOutput() { return mOutput; }
+
+ virtual int type() const { return mType; }
+ void suspend() { mSuspended++; }
+ void restore() { if (mSuspended) mSuspended--; }
+ virtual String8 getParameters(const String8& keys);
+ virtual void audioConfigChanged(int event, int param = 0);
+
struct stream_type_t {
stream_type_t()
: volume(1.0f),
@@ -492,56 +514,115 @@ private:
bool mute;
};
- private:
+ protected:
+ int mType;
+ int16_t* mMixBuffer;
+ int mSuspended;
+ int mBytesWritten;
+ bool mMasterMute;
+ SortedVector< wp<Track> > mActiveTracks;
+ private:
friend class AudioFlinger;
+ friend class OutputTrack;
friend class Track;
friend class TrackBase;
- friend class RecordTrack;
-
- MixerThread(const Client&);
- MixerThread& operator = (const MixerThread&);
-
+ friend class MixerThread;
+ friend class DirectOutputThread;
+ friend class DuplicatingThread;
+
+ PlaybackThread(const Client&);
+ PlaybackThread& operator = (const PlaybackThread&);
+
status_t addTrack_l(const sp<Track>& track);
void destroyTrack_l(const sp<Track>& track);
- int getTrackName_l();
- void deleteTrackName_l(int name);
- void addActiveTrack_l(const wp<Track>& t);
- void removeActiveTrack_l(const wp<Track>& t);
- size_t getOutputFrameCount();
+ virtual int getTrackName_l() = 0;
+ virtual void deleteTrackName_l(int name) = 0;
+ void readOutputParameters();
- status_t dumpInternals(int fd, const Vector<String16>& args);
+ virtual status_t dumpInternals(int fd, const Vector<String16>& args);
status_t dumpTracks(int fd, const Vector<String16>& args);
-
- sp<AudioFlinger> mAudioFlinger;
- SortedVector< wp<Track> > mActiveTracks;
+
SortedVector< sp<Track> > mTracks;
- stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
- AudioMixer* mAudioMixer;
+ // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread
+ stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES + 1];
AudioStreamOut* mOutput;
- int mOutputType;
- uint32_t mSampleRate;
- size_t mFrameCount;
- int mChannelCount;
- int mFormat;
- int16_t* mMixBuffer;
float mMasterVolume;
- bool mMasterMute;
nsecs_t mLastWriteTime;
int mNumWrites;
int mNumDelayedWrites;
- bool mStandby;
bool mInWrite;
- sp <OutputTrack> mOutputTrack;
+ int mMinBytesToWrite;
+ };
+
+ class MixerThread : public PlaybackThread {
+ public:
+ MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+ virtual ~MixerThread();
+
+ // Thread virtuals
+ virtual bool threadLoop();
+
+ void getTracks(SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks,
+ int streamType);
+ void putTracks(SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks);
+ virtual int getTrackName_l();
+ virtual void deleteTrackName_l(int name);
+ virtual bool checkForNewParameters_l();
+ virtual status_t dumpInternals(int fd, const Vector<String16>& args);
+
+ protected:
+ size_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove);
+
+ AudioMixer* mAudioMixer;
+ };
+
+ class DirectOutputThread : public PlaybackThread {
+ public:
+
+ DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+ ~DirectOutputThread();
+
+ // Thread virtuals
+ virtual bool threadLoop();
+
+ virtual int getTrackName_l();
+ virtual void deleteTrackName_l(int name);
+ virtual bool checkForNewParameters_l();
+
+ private:
+ float mLeftVolume;
+ float mRightVolume;
};
-
+ class DuplicatingThread : public MixerThread {
+ public:
+ DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread);
+ ~DuplicatingThread();
+
+ // Thread virtuals
+ virtual bool threadLoop();
+ void addOutputTrack(MixerThread* thread);
+ void removeOutputTrack(MixerThread* thread);
+
+ private:
+ SortedVector < sp<OutputTrack> > mOutputTracks;
+ };
+
+ PlaybackThread *checkPlaybackThread_l(int output) const;
+ MixerThread *checkMixerThread_l(int output) const;
+ RecordThread *checkRecordThread_l(int input) const;
+ float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
+ void audioConfigChanged(int event, const sp<ThreadBase>& thread, void *param2);
+
friend class AudioBuffer;
class TrackHandle : public android::BnAudioTrack {
public:
- TrackHandle(const sp<MixerThread::Track>& track);
+ TrackHandle(const sp<PlaybackThread::Track>& track);
virtual ~TrackHandle();
virtual status_t start();
virtual void stop();
@@ -553,20 +634,91 @@ private:
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<MixerThread::Track> mTrack;
+ sp<PlaybackThread::Track> mTrack;
};
friend class Client;
- friend class MixerThread::Track;
+ friend class PlaybackThread::Track;
void removeClient(pid_t pid);
+ // record thread
+ class RecordThread : public ThreadBase, public AudioBufferProvider
+ {
+ public:
+
+ // record track
+ class RecordTrack : public TrackBase {
+ public:
+ RecordTrack(const wp<ThreadBase>& thread,
+ const sp<Client>& client,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags);
+ ~RecordTrack();
+
+ virtual status_t start();
+ virtual void stop();
+
+ bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+ bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+ private:
+ friend class AudioFlinger;
+ friend class RecordThread;
+
+ RecordTrack(const RecordTrack&);
+ RecordTrack& operator = (const RecordTrack&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool mOverflow;
+ };
+
+
+ RecordThread(const sp<AudioFlinger>& audioFlinger,
+ AudioStreamIn *input,
+ uint32_t sampleRate,
+ uint32_t channels);
+ ~RecordThread();
+
+ virtual bool threadLoop();
+ virtual status_t readyToRun() { return NO_ERROR; }
+ virtual void onFirstRef();
+
+ status_t start(RecordTrack* recordTrack);
+ void stop(RecordTrack* recordTrack);
+ status_t dump(int fd, const Vector<String16>& args);
+ AudioStreamIn* getInput() { return mInput; }
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+ virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+ virtual bool checkForNewParameters_l();
+ virtual String8 getParameters(const String8& keys);
+ virtual void audioConfigChanged(int event, int param = 0);
+ void readInputParameters();
+
+ private:
+ RecordThread();
+ AudioStreamIn *mInput;
+ sp<RecordTrack> mActiveTrack;
+ Condition mStartStopCond;
+ AudioResampler *mResampler;
+ int32_t *mRsmpOutBuffer;
+ int16_t *mRsmpInBuffer;
+ size_t mRsmpInIndex;
+ size_t mInputBytes;
+ int mReqChannelCount;
+ uint32_t mReqSampleRate;
+ };
class RecordHandle : public android::BnAudioRecord {
public:
- RecordHandle(const sp<MixerThread::RecordTrack>& recordTrack);
+ RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
virtual status_t start();
virtual void stop();
@@ -574,66 +726,31 @@ private:
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<MixerThread::RecordTrack> mRecordTrack;
+ sp<RecordThread::RecordTrack> mRecordTrack;
};
- // record thread
- class AudioRecordThread : public Thread
- {
- public:
- AudioRecordThread(AudioHardwareInterface* audioHardware, const sp<AudioFlinger>& audioFlinger);
- virtual ~AudioRecordThread();
- virtual bool threadLoop();
- virtual status_t readyToRun() { return NO_ERROR; }
- virtual void onFirstRef() {}
-
- status_t start(MixerThread::RecordTrack* recordTrack);
- void stop(MixerThread::RecordTrack* recordTrack);
- void exit();
- status_t dump(int fd, const Vector<String16>& args);
-
- private:
- AudioRecordThread();
- AudioHardwareInterface *mAudioHardware;
- sp<AudioFlinger> mAudioFlinger;
- sp<MixerThread::RecordTrack> mRecordTrack;
- Mutex mLock;
- Condition mWaitWorkCV;
- Condition mStopped;
- volatile bool mActive;
- status_t mStartStatus;
- };
+ friend class RecordThread;
+ friend class PlaybackThread;
- friend class AudioRecordThread;
- friend class MixerThread;
- status_t startRecord(MixerThread::RecordTrack* recordTrack);
- void stopRecord(MixerThread::RecordTrack* recordTrack);
-
- mutable Mutex mHardwareLock;
mutable Mutex mLock;
- mutable Condition mWaitWorkCV;
DefaultKeyedVector< pid_t, wp<Client> > mClients;
- sp<MixerThread> mA2dpMixerThread;
- sp<MixerThread> mHardwareMixerThread;
+ mutable Mutex mHardwareLock;
AudioHardwareInterface* mAudioHardware;
- AudioHardwareInterface* mA2dpAudioInterface;
- sp<AudioRecordThread> mAudioRecordThread;
- bool mA2dpEnabled;
- bool mNotifyA2dpChange;
mutable int mHardwareStatus;
- SortedVector< wp<IBinder> > mNotificationClients;
- int mForcedSpeakerCount;
- int mA2dpDisableCount;
-
- // true if A2DP should resume when mA2dpDisableCount returns to zero
- bool mA2dpSuppressed;
- uint32_t mSavedRoute;
- uint32_t mForcedRoute;
- nsecs_t mRouteRestoreTime;
- bool mMusicMuteSaved;
+
+
+ DefaultKeyedVector< int, sp<PlaybackThread> > mPlaybackThreads;
+ PlaybackThread::stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
+ float mMasterVolume;
+ bool mMasterMute;
+
+ DefaultKeyedVector< int, sp<RecordThread> > mRecordThreads;
+
+ SortedVector< sp<IBinder> > mNotificationClients;
+ int mNextThreadId;
};
// ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index 1e159b8..57874f3 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -49,8 +49,8 @@ AudioHardwareGeneric::AudioHardwareGeneric()
AudioHardwareGeneric::~AudioHardwareGeneric()
{
if (mFd >= 0) ::close(mFd);
- delete mOutput;
- delete mInput;
+ closeOutputStream((AudioStreamOut *)mOutput);
+ closeInputStream((AudioStreamIn *)mInput);
}
status_t AudioHardwareGeneric::initCheck()
@@ -63,7 +63,7 @@ status_t AudioHardwareGeneric::initCheck()
}
AudioStreamOut* AudioHardwareGeneric::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
AutoMutex lock(mLock);
@@ -77,7 +77,7 @@ AudioStreamOut* AudioHardwareGeneric::openOutputStream(
// create new output stream
AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
- status_t lStatus = out->set(this, mFd, format, channelCount, sampleRate);
+ status_t lStatus = out->set(this, mFd, devices, format, channels, sampleRate);
if (status) {
*status = lStatus;
}
@@ -89,17 +89,19 @@ AudioStreamOut* AudioHardwareGeneric::openOutputStream(
return mOutput;
}
-void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) {
- if (out == mOutput) mOutput = 0;
+void AudioHardwareGeneric::closeOutputStream(AudioStreamOut* out) {
+ if (mOutput && out == mOutput) {
+ delete mOutput;
+ mOutput = 0;
+ }
}
AudioStreamIn* AudioHardwareGeneric::openInputStream(
- int inputSource, int format, int channelCount, uint32_t sampleRate,
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
// check for valid input source
- if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
- (inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
return 0;
}
@@ -115,7 +117,7 @@ AudioStreamIn* AudioHardwareGeneric::openInputStream(
// create new output stream
AudioStreamInGeneric* in = new AudioStreamInGeneric();
- status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate, acoustics);
+ status_t lStatus = in->set(this, mFd, devices, format, channels, sampleRate, acoustics);
if (status) {
*status = lStatus;
}
@@ -127,8 +129,11 @@ AudioStreamIn* AudioHardwareGeneric::openInputStream(
return mInput;
}
-void AudioHardwareGeneric::closeInputStream(AudioStreamInGeneric* in) {
- if (in == mInput) mInput = 0;
+void AudioHardwareGeneric::closeInputStream(AudioStreamIn* in) {
+ if (mInput && in == mInput) {
+ delete mInput;
+ mInput = 0;
+ }
}
status_t AudioHardwareGeneric::setVoiceVolume(float v)
@@ -185,30 +190,42 @@ status_t AudioHardwareGeneric::dump(int fd, const Vector<String16>& args)
status_t AudioStreamOutGeneric::set(
AudioHardwareGeneric *hw,
int fd,
- int format,
- int channels,
- uint32_t rate)
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate)
{
+ int lFormat = pFormat ? *pFormat : 0;
+ uint32_t lChannels = pChannels ? *pChannels : 0;
+ uint32_t lRate = pRate ? *pRate : 0;
+
// fix up defaults
- if (format == 0) format = AudioSystem::PCM_16_BIT;
- if (channels == 0) channels = channelCount();
- if (rate == 0) rate = sampleRate();
+ if (lFormat == 0) lFormat = format();
+ if (lChannels == 0) lChannels = channels();
+ if (lRate == 0) lRate = sampleRate();
// check values
- if ((format != AudioSystem::PCM_16_BIT) ||
- (channels != channelCount()) ||
- (rate != sampleRate()))
+ if ((lFormat != format()) ||
+ (lChannels != channels()) ||
+ (lRate != sampleRate())) {
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
return BAD_VALUE;
+ }
+
+ if (pFormat) *pFormat = lFormat;
+ if (pChannels) *pChannels = lChannels;
+ if (pRate) *pRate = lRate;
mAudioHardware = hw;
mFd = fd;
+ mDevice = devices;
return NO_ERROR;
}
AudioStreamOutGeneric::~AudioStreamOutGeneric()
{
- if (mAudioHardware)
- mAudioHardware->closeOutputStream(this);
}
ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)
@@ -234,10 +251,12 @@ status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
result.append(buffer);
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
result.append(buffer);
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
+ snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
+ result.append(buffer);
snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
result.append(buffer);
snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
@@ -246,29 +265,68 @@ status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
+status_t AudioStreamOutGeneric::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ LOGV("setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevice = device;
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioStreamOutGeneric::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ LOGV("getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
// record functions
status_t AudioStreamInGeneric::set(
AudioHardwareGeneric *hw,
int fd,
- int format,
- int channels,
- uint32_t rate,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustics)
{
// FIXME: remove logging
- LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, format, channels, rate);
+ if (pFormat == 0 || pChannels == 0 || pRate == 0) return BAD_VALUE;
+ LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, *pFormat, *pChannels, *pRate);
// check values
- if ((format != AudioSystem::PCM_16_BIT) ||
- (channels != channelCount()) ||
- (rate != sampleRate())) {
+ if ((*pFormat != format()) ||
+ (*pChannels != channels()) ||
+ (*pRate != sampleRate())) {
LOGE("Error opening input channel");
+ *pFormat = format();
+ *pChannels = channels();
+ *pRate = sampleRate();
return BAD_VALUE;
}
mAudioHardware = hw;
mFd = fd;
+ mDevice = devices;
return NO_ERROR;
}
@@ -276,14 +334,12 @@ AudioStreamInGeneric::~AudioStreamInGeneric()
{
// FIXME: remove logging
LOGD("AudioStreamInGeneric destructor");
- if (mAudioHardware)
- mAudioHardware->closeInputStream(this);
}
ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
{
// FIXME: remove logging
- LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, bytes, mFd);
+ LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, (int)bytes, mFd);
AutoMutex lock(mLock);
if (mFd < 0) {
LOGE("Attempt to read from unopened device");
@@ -303,10 +359,12 @@ status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
result.append(buffer);
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
result.append(buffer);
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
+ snprintf(buffer, SIZE, "\tdevice: %d\n", mDevice);
+ result.append(buffer);
snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
result.append(buffer);
snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
@@ -315,6 +373,39 @@ status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
+status_t AudioStreamInGeneric::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ status_t status = NO_ERROR;
+ int device;
+ LOGV("setParameters() %s", keyValuePairs.string());
+
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDevice = device;
+ param.remove(key);
+ }
+
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioStreamInGeneric::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mDevice);
+ }
+
+ LOGV("getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index c89df87..42da413 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -39,24 +39,28 @@ public:
virtual status_t set(
AudioHardwareGeneric *hw,
int mFd,
- int format,
- int channelCount,
- uint32_t sampleRate);
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
virtual uint32_t sampleRate() const { return 44100; }
virtual size_t bufferSize() const { return 4096; }
- virtual int channelCount() const { return 2; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual uint32_t latency() const { return 20; }
- virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t standby();
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
private:
AudioHardwareGeneric *mAudioHardware;
Mutex mLock;
int mFd;
+ uint32_t mDevice;
};
class AudioStreamInGeneric : public AudioStreamIn {
@@ -67,24 +71,28 @@ public:
virtual status_t set(
AudioHardwareGeneric *hw,
int mFd,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustics);
- uint32_t sampleRate() const { return 8000; }
+ virtual uint32_t sampleRate() const { return 8000; }
virtual size_t bufferSize() const { return 320; }
- virtual int channelCount() const { return 1; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual status_t setGain(float gain) { return INVALID_OPERATION; }
virtual ssize_t read(void* buffer, ssize_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t standby() { return NO_ERROR; }
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
private:
AudioHardwareGeneric *mAudioHardware;
Mutex mLock;
int mFd;
+ uint32_t mDevice;
};
@@ -101,28 +109,27 @@ public:
virtual status_t setMicMute(bool state);
virtual status_t getMicMute(bool* state);
- virtual status_t setParameter(const char* key, const char* value)
- { return NO_ERROR; }
-
// create I/O streams
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
virtual AudioStreamIn* openInputStream(
- int inputSource,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
status_t *status,
AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
void closeOutputStream(AudioStreamOutGeneric* out);
void closeInputStream(AudioStreamInGeneric* in);
protected:
- virtual status_t doRouting() { return NO_ERROR; }
virtual status_t dump(int fd, const Vector<String16>& args);
private:
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
index cc1bd8f..9a4a7f9 100644
--- a/libs/audioflinger/AudioHardwareInterface.cpp
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -18,6 +18,7 @@
#include <cutils/properties.h>
#include <string.h>
#include <unistd.h>
+//#define LOG_NDEBUG 0
#define LOG_TAG "AudioHardwareInterface"
#include <utils/Log.h>
@@ -25,15 +26,17 @@
#include "AudioHardwareStub.h"
#include "AudioHardwareGeneric.h"
+#ifdef WITH_A2DP
+#include "A2dpAudioInterface.h"
+#endif
-//#define DUMP_FLINGER_OUT // if defined allows recording samples in a file
-#ifdef DUMP_FLINGER_OUT
+#ifdef ENABLE_AUDIO_DUMP
#include "AudioDumpInterface.h"
#endif
// change to 1 to log routing calls
-#define LOG_ROUTING_CALLS 0
+#define LOG_ROUTING_CALLS 1
namespace android {
@@ -48,14 +51,6 @@ static const char* routingModeStrings[] =
"IN_CALL"
};
-static const char* routeStrings[] =
-{
- "EARPIECE ",
- "SPEAKER ",
- "BLUETOOTH ",
- "HEADSET ",
- "BLUETOOTH_A2DP "
-};
static const char* routeNone = "NONE";
static const char* displayMode(int mode)
@@ -64,22 +59,6 @@ static const char* displayMode(int mode)
return routingModeStrings[0];
return routingModeStrings[mode+3];
}
-
-static const char* displayRoutes(uint32_t routes)
-{
- static char routeStr[80];
- if (routes == 0)
- return routeNone;
- routeStr[0] = 0;
- int bitMask = 1;
- for (int i = 0; i < 4; ++i, bitMask <<= 1) {
- if (routes & bitMask) {
- strcat(routeStr, routeStrings[i]);
- }
- }
- routeStr[strlen(routeStr)-1] = 0;
- return routeStr;
-}
#endif
// ----------------------------------------------------------------------------
@@ -112,13 +91,17 @@ AudioHardwareInterface* AudioHardwareInterface::create()
hw = new AudioHardwareStub();
}
-#ifdef DUMP_FLINGER_OUT
+#ifdef WITH_A2DP
+ hw = new A2dpAudioInterface(hw);
+#endif
+
+#ifdef ENABLE_AUDIO_DUMP
// This code adds a record of buffers in a file to write calls made by AudioFlinger.
// It replaces the current AudioHardwareInterface object by an intermediate one which
// will record buffers in a file (after sending them to hardware) for testing purpose.
- // This feature is enabled by defining symbol DUMP_FLINGER_OUT.
- // The output file is FLINGER_DUMP_NAME. Pause are not recorded in the file.
-
+ // This feature is enabled by defining symbol ENABLE_AUDIO_DUMP.
+ // The output file is set with setParameters("test_cmd_file_name=<name>"). Pause are not recorded in the file.
+ LOGV("opening PCM dump interface");
hw = new AudioDumpInterface(hw); // replace interface
#endif
return hw;
@@ -132,48 +115,9 @@ AudioStreamIn::~AudioStreamIn() {}
AudioHardwareBase::AudioHardwareBase()
{
- // force a routing update on initialization
- memset(&mRoutes, 0, sizeof(mRoutes));
mMode = 0;
}
-// generics for audio routing - the real work is done in doRouting
-status_t AudioHardwareBase::setRouting(int mode, uint32_t routes)
-{
-#if LOG_ROUTING_CALLS
- LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
-#endif
- if (mode == AudioSystem::MODE_CURRENT)
- mode = mMode;
- if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
- return BAD_VALUE;
- uint32_t old = mRoutes[mode];
- mRoutes[mode] = routes;
- if ((mode != mMode) || (old == routes))
- return NO_ERROR;
-#if LOG_ROUTING_CALLS
- const char* oldRouteStr = strdup(displayRoutes(old));
- LOGD("doRouting: mode=%s, old route=[%s], new route=[%s]",
- displayMode(mode), oldRouteStr, displayRoutes(routes));
- delete oldRouteStr;
-#endif
- return doRouting();
-}
-
-status_t AudioHardwareBase::getRouting(int mode, uint32_t* routes)
-{
- if (mode == AudioSystem::MODE_CURRENT)
- mode = mMode;
- if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
- return BAD_VALUE;
- *routes = mRoutes[mode];
-#if LOG_ROUTING_CALLS
- LOGD("getRouting: mode=%s, routes=[%s]",
- displayMode(mode), displayRoutes(*routes));
-#endif
- return NO_ERROR;
-}
-
status_t AudioHardwareBase::setMode(int mode)
{
#if LOG_ROUTING_CALLS
@@ -182,29 +126,24 @@ status_t AudioHardwareBase::setMode(int mode)
if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
return BAD_VALUE;
if (mMode == mode)
- return NO_ERROR;
-#if LOG_ROUTING_CALLS
- LOGD("doRouting: old mode=%s, new mode=%s route=[%s]",
- displayMode(mMode), displayMode(mode), displayRoutes(mRoutes[mode]));
-#endif
+ return ALREADY_EXISTS;
mMode = mode;
- return doRouting();
+ return NO_ERROR;
}
-status_t AudioHardwareBase::getMode(int* mode)
+// default implementation
+status_t AudioHardwareBase::setParameters(const String8& keyValuePairs)
{
- // Implement: set audio routing
- *mode = mMode;
return NO_ERROR;
}
-status_t AudioHardwareBase::setParameter(const char* key, const char* value)
+// default implementation
+String8 AudioHardwareBase::getParameters(const String8& keys)
{
- // default implementation is to ignore
- return NO_ERROR;
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
}
-
// default implementation
size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
{
@@ -233,10 +172,6 @@ status_t AudioHardwareBase::dumpState(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
result.append(buffer);
- for (int i = 0, n = AudioSystem::NUM_MODES; i < n; ++i) {
- snprintf(buffer, SIZE, "\tmRoutes[%d]: %d\n", i, mRoutes[i]);
- result.append(buffer);
- }
::write(fd, result.string(), result.size());
dump(fd, args); // Dump the state of the concrete child.
return NO_ERROR;
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index 0ab4c60..ae391ee 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -43,10 +43,10 @@ status_t AudioHardwareStub::initCheck()
}
AudioStreamOut* AudioHardwareStub::openOutputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
{
AudioStreamOutStub* out = new AudioStreamOutStub();
- status_t lStatus = out->set(format, channelCount, sampleRate);
+ status_t lStatus = out->set(format, channels, sampleRate);
if (status) {
*status = lStatus;
}
@@ -56,18 +56,22 @@ AudioStreamOut* AudioHardwareStub::openOutputStream(
return 0;
}
+void AudioHardwareStub::closeOutputStream(AudioStreamOut* out)
+{
+ delete out;
+}
+
AudioStreamIn* AudioHardwareStub::openInputStream(
- int inputSource, int format, int channelCount, uint32_t sampleRate,
+ uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate,
status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
// check for valid input source
- if ((inputSource < AudioRecord::DEFAULT_INPUT) ||
- (inputSource >= AudioRecord::NUM_INPUT_SOURCES)) {
+ if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
return 0;
}
AudioStreamInStub* in = new AudioStreamInStub();
- status_t lStatus = in->set(format, channelCount, sampleRate, acoustics);
+ status_t lStatus = in->set(format, channels, sampleRate, acoustics);
if (status) {
*status = lStatus;
}
@@ -77,6 +81,11 @@ AudioStreamIn* AudioHardwareStub::openInputStream(
return 0;
}
+void AudioHardwareStub::closeInputStream(AudioStreamIn* in)
+{
+ delete in;
+}
+
status_t AudioHardwareStub::setVoiceVolume(float volume)
{
return NO_ERROR;
@@ -107,24 +116,19 @@ status_t AudioHardwareStub::dump(int fd, const Vector<String16>& args)
// ----------------------------------------------------------------------------
-status_t AudioStreamOutStub::set(int format, int channels, uint32_t rate)
+status_t AudioStreamOutStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate)
{
- // fix up defaults
- if (format == 0) format = AudioSystem::PCM_16_BIT;
- if (channels == 0) channels = channelCount();
- if (rate == 0) rate = sampleRate();
+ if (pFormat) *pFormat = format();
+ if (pChannels) *pChannels = channels();
+ if (pRate) *pRate = sampleRate();
- if ((format == AudioSystem::PCM_16_BIT) &&
- (channels == channelCount()) &&
- (rate == sampleRate()))
- return NO_ERROR;
- return BAD_VALUE;
+ return NO_ERROR;
}
ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)
{
// fake timing for audio output
- usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+ usleep(bytes * 1000000 / sizeof(int16_t) / AudioSystem::popCount(channels()) / sampleRate());
return bytes;
}
@@ -141,29 +145,31 @@ status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n");
snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
::write(fd, result.string(), result.size());
return NO_ERROR;
}
+String8 AudioStreamOutStub::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
-status_t AudioStreamInStub::set(int format, int channels, uint32_t rate,
+status_t AudioStreamInStub::set(int *pFormat, uint32_t *pChannels, uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustics)
{
- if ((format == AudioSystem::PCM_16_BIT) &&
- (channels == channelCount()) &&
- (rate == sampleRate()))
- return NO_ERROR;
- return BAD_VALUE;
+ return NO_ERROR;
}
ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)
{
// fake timing for audio input
- usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+ usleep(bytes * 1000000 / sizeof(int16_t) / AudioSystem::popCount(channels()) / sampleRate());
memset(buffer, 0, bytes);
return bytes;
}
@@ -179,7 +185,7 @@ status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
result.append(buffer);
- snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+ snprintf(buffer, SIZE, "\tchannels: %d\n", channels());
result.append(buffer);
snprintf(buffer, SIZE, "\tformat: %d\n", format());
result.append(buffer);
@@ -187,6 +193,12 @@ status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
return NO_ERROR;
}
+String8 AudioStreamInStub::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ return param.toString();
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index bf63cc5..583f852 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -29,29 +29,33 @@ namespace android {
class AudioStreamOutStub : public AudioStreamOut {
public:
- virtual status_t set(int format, int channelCount, uint32_t sampleRate);
+ virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate);
virtual uint32_t sampleRate() const { return 44100; }
virtual size_t bufferSize() const { return 4096; }
- virtual int channelCount() const { return 2; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual uint32_t latency() const { return 0; }
- virtual status_t setVolume(float volume) { return NO_ERROR; }
+ virtual status_t setVolume(float left, float right) { return NO_ERROR; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t standby();
virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;}
+ virtual String8 getParameters(const String8& keys);
};
class AudioStreamInStub : public AudioStreamIn {
public:
- virtual status_t set(int format, int channelCount, uint32_t sampleRate, AudioSystem::audio_in_acoustics acoustics);
+ virtual status_t set(int *pFormat, uint32_t *pChannels, uint32_t *pRate, AudioSystem::audio_in_acoustics acoustics);
virtual uint32_t sampleRate() const { return 8000; }
virtual size_t bufferSize() const { return 320; }
- virtual int channelCount() const { return 1; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_IN_MONO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual status_t setGain(float gain) { return NO_ERROR; }
virtual ssize_t read(void* buffer, ssize_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t standby() { return NO_ERROR; }
+ virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR;}
+ virtual String8 getParameters(const String8& keys);
};
class AudioHardwareStub : public AudioHardwareBase
@@ -67,26 +71,25 @@ public:
virtual status_t setMicMute(bool state) { mMicMute = state; return NO_ERROR; }
virtual status_t getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
- virtual status_t setParameter(const char* key, const char* value)
- { return NO_ERROR; }
-
// create I/O streams
virtual AudioStreamOut* openOutputStream(
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
status_t *status=0);
+ virtual void closeOutputStream(AudioStreamOut* out);
virtual AudioStreamIn* openInputStream(
- int inputSource,
- int format,
- int channelCount,
- uint32_t sampleRate,
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
status_t *status,
- AudioSystem::audio_in_acoustics acoustics);
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual void closeInputStream(AudioStreamIn* in);
protected:
- virtual status_t doRouting() { return NO_ERROR; }
virtual status_t dump(int fd, const Vector<String16>& args);
bool mMicMute;
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index b02efcc..19a442a 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -610,7 +610,6 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
t->in = in;
}
-inline
void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
{
for (size_t i=0 ; i<c ; i++) {
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
index 72ca28a..15766cd 100644
--- a/libs/audioflinger/AudioMixer.h
+++ b/libs/audioflinger/AudioMixer.h
@@ -85,6 +85,8 @@ public:
uint32_t trackNames() const { return mTrackNames; }
+ static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
+
private:
enum {
@@ -176,7 +178,6 @@ private:
static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
- static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
static void process__validate(state_t* state, void* output);
static void process__nop(state_t* state, void* output);
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.cpp b/libs/audioflinger/AudioPolicyManagerGeneric.cpp
new file mode 100644
index 0000000..6323859
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyManagerGeneric.cpp
@@ -0,0 +1,826 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AudioPolicyManagerGeneric"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include "AudioPolicyManagerGeneric.h"
+#include <media/mediarecorder.h>
+
+namespace android {
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyInterface implementation
+// ----------------------------------------------------------------------------
+
+
+status_t AudioPolicyManagerGeneric::setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+
+ LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+
+ // connect/disconnect only 1 device at a time
+ if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
+
+ if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+ LOGE("setDeviceConnectionState() invalid address: %s", device_address);
+ return BAD_VALUE;
+ }
+
+ // handle output devices
+ if (AudioSystem::isOutputDevice(device)) {
+ switch (state)
+ {
+ // handle output device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+ if (mAvailableOutputDevices & device) {
+ LOGW("setDeviceConnectionState() device already connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ LOGV("setDeviceConnectionState() connecting device %x", device);
+
+ // register new device as available
+ mAvailableOutputDevices |= device;
+ break;
+ // handle output device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE:
+ if (!(mAvailableOutputDevices & device)) {
+ LOGW("setDeviceConnectionState() device not connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ LOGV("setDeviceConnectionState() disconnecting device %x", device);
+ // remove device from available output devices
+ mAvailableOutputDevices &= ~device;
+ break;
+
+ default:
+ LOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+ }
+ // handle input devices
+ if (AudioSystem::isInputDevice(device)) {
+ switch (state)
+ {
+ // handle input device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+ if (mAvailableInputDevices & device) {
+ LOGW("setDeviceConnectionState() device already connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices |= device;
+ break;
+
+ // handle input device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE:
+ if (!(mAvailableInputDevices & device)) {
+ LOGW("setDeviceConnectionState() device not connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices &= ~device;
+ break;
+
+ default:
+ LOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+ }
+
+ LOGW("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+}
+
+AudioSystem::device_connection_state AudioPolicyManagerGeneric::getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address)
+{
+ AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ String8 address = String8(device_address);
+ if (AudioSystem::isOutputDevice(device)) {
+ if (device & mAvailableOutputDevices) {
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ } else if (AudioSystem::isInputDevice(device)) {
+ if (device & mAvailableInputDevices) {
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ }
+
+ return state;
+}
+
+void AudioPolicyManagerGeneric::setPhoneState(int state)
+{
+ LOGV("setPhoneState() state %d", state);
+ uint32_t newDevice = 0;
+ if (state < 0 || state >= AudioSystem::NUM_MODES) {
+ LOGW("setPhoneState() invalid state %d", state);
+ return;
+ }
+
+ if (state == mPhoneState ) {
+ LOGW("setPhoneState() setting same state %d", state);
+ return;
+ }
+ // store previous phone state for management of sonification strategy below
+ int oldState = mPhoneState;
+ mPhoneState = state;
+
+ // if leaving or entering in call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (state == AudioSystem::MODE_IN_CALL ||
+ oldState == AudioSystem::MODE_IN_CALL) {
+ bool starting = (state == AudioSystem::MODE_IN_CALL) ? true : false;
+ LOGV("setPhoneState() in call state management: new state is %d", state);
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ handleIncallSonification(stream, starting);
+ }
+ }
+}
+
+void AudioPolicyManagerGeneric::setRingerMode(uint32_t mode, uint32_t mask)
+{
+ LOGV("setRingerMode() mode %x, mask %x", mode, mask);
+
+ mRingerMode = mode;
+}
+
+void AudioPolicyManagerGeneric::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ LOGV("setForceUse) usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+ mForceUse[usage] = config;
+}
+
+AudioSystem::forced_config AudioPolicyManagerGeneric::getForceUse(AudioSystem::force_use usage)
+{
+ return mForceUse[usage];
+}
+
+void AudioPolicyManagerGeneric::setSystemProperty(const char* property, const char* value)
+{
+ LOGV("setSystemProperty() property %s, value %s", property, value);
+ if (strcmp(property, "ro.camera.sound.forced") == 0) {
+ if (atoi(value)) {
+ LOGV("ENFORCED_AUDIBLE cannot be muted");
+ mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = false;
+ } else {
+ LOGV("ENFORCED_AUDIBLE can be muted");
+ mStreams[AudioSystem::ENFORCED_AUDIBLE].mCanBeMuted = true;
+ }
+ }
+}
+
+audio_io_handle_t AudioPolicyManagerGeneric::getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags)
+{
+ LOGV("getOutput() stream %d, samplingRate %d, format %d, channels %x, flags %x", stream, samplingRate, format, channels, flags);
+
+#ifdef AUDIO_POLICY_TEST
+ if (mCurOutput != 0) {
+ LOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channels %x, mDirectOutput %d",
+ mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
+
+ if (mTestOutputs[mCurOutput] == 0) {
+ LOGV("getOutput() opening test output");
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+ outputDesc->mDevice = mTestDevice;
+ outputDesc->mSamplingRate = mTestSamplingRate;
+ outputDesc->mFormat = mTestFormat;
+ outputDesc->mChannels = mTestChannels;
+ outputDesc->mLatency = mTestLatencyMs;
+ outputDesc->mFlags = (AudioSystem::output_flags)(mDirectOutput ? AudioSystem::OUTPUT_FLAG_DIRECT : 0);
+ outputDesc->mRefCount[stream] = 0;
+ mTestOutputs[mCurOutput] = mpClientInterface->openOutput(&outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannels,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+ if (mTestOutputs[mCurOutput]) {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"),mCurOutput);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
+ mOutputs.add(mTestOutputs[mCurOutput], outputDesc);
+ }
+ }
+ return mTestOutputs[mCurOutput];
+ }
+#endif //AUDIO_POLICY_TEST
+ if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
+ (format != 0 && !AudioSystem::isLinearPCM(format)) ||
+ (channels != 0 && channels != AudioSystem::CHANNEL_OUT_MONO && channels != AudioSystem::CHANNEL_OUT_STEREO)) {
+ return 0;
+ }
+
+ return mHardwareOutput;
+}
+
+status_t AudioPolicyManagerGeneric::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ LOGV("startOutput() output %d, stream %d", output, stream);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("startOutput() unknow output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // handle special case for sonification while in call
+ if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+ handleIncallSonification(stream, true);
+ }
+
+ // incremenent usage count for this stream on the requested output:
+ outputDesc->changeRefCount(stream, 1);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerGeneric::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ LOGV("stopOutput() output %d, stream %d", output, stream);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("stopOutput() unknow output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // handle special case for sonification while in call
+ if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+ handleIncallSonification(stream, false);
+ }
+
+ if (outputDesc->isUsedByStream(stream)) {
+ // decrement usage count of this stream on the output
+ outputDesc->changeRefCount(stream, -1);
+ return NO_ERROR;
+ } else {
+ LOGW("stopOutput() refcount is already 0 for output %d", output);
+ return INVALID_OPERATION;
+ }
+}
+
+void AudioPolicyManagerGeneric::releaseOutput(audio_io_handle_t output)
+{
+ LOGV("releaseOutput() %d", output);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("releaseOutput() releasing unknown output %d", output);
+ return;
+ }
+
+#ifdef AUDIO_POLICY_TEST
+ int testIndex = testOutputIndex(output);
+ if (testIndex != 0) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+ if (outputDesc->refCount() == 0) {
+ mpClientInterface->closeOutput(output);
+ delete mOutputs.valueAt(index);
+ mOutputs.removeItem(output);
+ mTestOutputs[testIndex] = 0;
+ }
+ }
+#endif //AUDIO_POLICY_TEST
+}
+
+audio_io_handle_t AudioPolicyManagerGeneric::getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ audio_io_handle_t input = 0;
+ uint32_t device;
+
+ LOGV("getInput() inputSource %d, samplingRate %d, format %d, channels %x, acoustics %x", inputSource, samplingRate, format, channels, acoustics);
+
+ AudioInputDescriptor *inputDesc = new AudioInputDescriptor();
+ inputDesc->mDevice = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+ inputDesc->mSamplingRate = samplingRate;
+ inputDesc->mFormat = format;
+ inputDesc->mChannels = channels;
+ inputDesc->mAcoustics = acoustics;
+ inputDesc->mRefCount = 0;
+ input = mpClientInterface->openInput(&inputDesc->mDevice,
+ &inputDesc->mSamplingRate,
+ &inputDesc->mFormat,
+ &inputDesc->mChannels,
+ inputDesc->mAcoustics);
+
+ // only accept input with the exact requested set of parameters
+ if ((samplingRate != inputDesc->mSamplingRate) ||
+ (format != inputDesc->mFormat) ||
+ (channels != inputDesc->mChannels)) {
+ LOGV("getOutput() failed opening input: samplingRate %d, format %d, channels %d",
+ samplingRate, format, channels);
+ mpClientInterface->closeInput(input);
+ delete inputDesc;
+ return 0;
+ }
+ mInputs.add(input, inputDesc);
+ return input;
+}
+
+status_t AudioPolicyManagerGeneric::startInput(audio_io_handle_t input)
+{
+ LOGV("startInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("startInput() unknow input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+#ifdef AUDIO_POLICY_TEST
+ if (mTestInput == 0)
+#endif //AUDIO_POLICY_TEST
+ {
+ // refuse 2 active AudioRecord clients at the same time
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ if (mInputs.valueAt(i)->mRefCount > 0) {
+ LOGW("startInput() input %d, other input %d already started", input, mInputs.keyAt(i));
+ return INVALID_OPERATION;
+ }
+ }
+ }
+
+ inputDesc->mRefCount = 1;
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerGeneric::stopInput(audio_io_handle_t input)
+{
+ LOGV("stopInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("stopInput() unknow input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+ if (inputDesc->mRefCount == 0) {
+ LOGW("stopInput() input %d already stopped", input);
+ return INVALID_OPERATION;
+ } else {
+ inputDesc->mRefCount = 0;
+ return NO_ERROR;
+ }
+}
+
+void AudioPolicyManagerGeneric::releaseInput(audio_io_handle_t input)
+{
+ LOGV("releaseInput() %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("releaseInput() releasing unknown input %d", input);
+ return;
+ }
+ mpClientInterface->closeInput(input);
+ delete mInputs.valueAt(index);
+ mInputs.removeItem(input);
+}
+
+
+
+void AudioPolicyManagerGeneric::initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax)
+{
+ LOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+ mStreams[stream].mIndexMin = indexMin;
+ mStreams[stream].mIndexMax = indexMax;
+}
+
+status_t AudioPolicyManagerGeneric::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
+{
+
+ if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
+ return BAD_VALUE;
+ }
+
+ LOGV("setStreamVolumeIndex() stream %d, index %d", stream, index);
+ mStreams[stream].mIndexCur = index;
+
+ // do not change actual stream volume if the stream is muted
+ if (mStreams[stream].mMuteCount != 0) {
+ return NO_ERROR;
+ }
+
+ // Do not changed in call volume if bluetooth is connected and vice versa
+ if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+ LOGV("setStreamVolumeIndex() cannot set stream %d volume with force use = %d for comm",
+ stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+ return INVALID_OPERATION;
+ }
+
+ // compute and apply stream volume on all outputs according to connected device
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+ uint32_t device = outputDesc->device();
+
+ float volume = computeVolume((int)stream, index, device);
+
+ LOGV("setStreamVolume() for output %d stream %d, volume %f", mOutputs.keyAt(i), stream, volume);
+ mpClientInterface->setStreamVolume(stream, volume, mOutputs.keyAt(i));
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManagerGeneric::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
+{
+ if (index == 0) {
+ return BAD_VALUE;
+ }
+ LOGV("getStreamVolumeIndex() stream %d", stream);
+ *index = mStreams[stream].mIndexCur;
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManagerGeneric
+// ----------------------------------------------------------------------------
+
+// --- class factory
+
+AudioPolicyManagerGeneric::AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface)
+ :
+#ifdef AUDIO_POLICY_TEST
+ Thread(false),
+#endif //AUDIO_POLICY_TEST
+ mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0)
+{
+ mpClientInterface = clientInterface;
+
+ for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
+ mForceUse[i] = AudioSystem::FORCE_NONE;
+ }
+
+ // devices available by default are speaker, ear piece and microphone
+ mAvailableOutputDevices = AudioSystem::DEVICE_OUT_SPEAKER;
+ mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+
+ // open hardware output
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+ outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
+ mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannels,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+
+ if (mHardwareOutput == 0) {
+ LOGE("Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d",
+ outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
+ } else {
+ mOutputs.add(mHardwareOutput, outputDesc);
+ }
+
+#ifdef AUDIO_POLICY_TEST
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+
+ mTestDevice = AudioSystem::DEVICE_OUT_SPEAKER;
+ mTestSamplingRate = 44100;
+ mTestFormat = AudioSystem::PCM_16_BIT;
+ mTestChannels = AudioSystem::CHANNEL_OUT_STEREO;
+ mTestLatencyMs = 0;
+ mCurOutput = 0;
+ mDirectOutput = false;
+ for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+ mTestOutputs[i] = 0;
+ }
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "AudioPolicyManagerTest");
+ run(buffer, ANDROID_PRIORITY_AUDIO);
+#endif //AUDIO_POLICY_TEST
+}
+
+AudioPolicyManagerGeneric::~AudioPolicyManagerGeneric()
+{
+#ifdef AUDIO_POLICY_TEST
+ exit();
+#endif //AUDIO_POLICY_TEST
+
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ mpClientInterface->closeOutput(mOutputs.keyAt(i));
+ delete mOutputs.valueAt(i);
+ }
+ mOutputs.clear();
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ mpClientInterface->closeInput(mInputs.keyAt(i));
+ delete mInputs.valueAt(i);
+ }
+ mInputs.clear();
+}
+
+#ifdef AUDIO_POLICY_TEST
+bool AudioPolicyManagerGeneric::threadLoop()
+{
+ LOGV("entering threadLoop()");
+ while (!exitPending())
+ {
+ String8 command;
+ int valueInt;
+ String8 value;
+
+ Mutex::Autolock _l(mLock);
+ mWaitWorkCV.waitRelative(mLock, milliseconds(50));
+
+ command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
+ AudioParameter param = AudioParameter(command);
+
+ if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR &&
+ valueInt != 0) {
+ LOGV("Test command %s received", command.string());
+ String8 target;
+ if (param.get(String8("target"), target) != NO_ERROR) {
+ target = "Manager";
+ }
+ if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_output"));
+ mCurOutput = valueInt;
+ }
+ if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_direct"));
+ if (value == "false") {
+ mDirectOutput = false;
+ } else if (value == "true") {
+ mDirectOutput = true;
+ }
+ }
+ if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_input"));
+ mTestInput = valueInt;
+ }
+
+ if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_format"));
+ int format = AudioSystem::INVALID_FORMAT;
+ if (value == "PCM 16 bits") {
+ format = AudioSystem::PCM_16_BIT;
+ } else if (value == "PCM 8 bits") {
+ format = AudioSystem::PCM_8_BIT;
+ } else if (value == "Compressed MP3") {
+ format = AudioSystem::MP3;
+ }
+ if (format != AudioSystem::INVALID_FORMAT) {
+ if (target == "Manager") {
+ mTestFormat = format;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("format"), format);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+ if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_channels"));
+ int channels = 0;
+
+ if (value == "Channels Stereo") {
+ channels = AudioSystem::CHANNEL_OUT_STEREO;
+ } else if (value == "Channels Mono") {
+ channels = AudioSystem::CHANNEL_OUT_MONO;
+ }
+ if (channels != 0) {
+ if (target == "Manager") {
+ mTestChannels = channels;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("channels"), channels);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+ if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_sampleRate"));
+ if (valueInt >= 0 && valueInt <= 96000) {
+ int samplingRate = valueInt;
+ if (target == "Manager") {
+ mTestSamplingRate = samplingRate;
+ } else if (mTestOutputs[mCurOutput] != 0) {
+ AudioParameter outputParam = AudioParameter();
+ outputParam.addInt(String8("sampling_rate"), samplingRate);
+ mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+ }
+ }
+ }
+
+ if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
+ param.remove(String8("test_cmd_policy_reopen"));
+
+ mpClientInterface->closeOutput(mHardwareOutput);
+ delete mOutputs.valueFor(mHardwareOutput);
+ mOutputs.removeItem(mHardwareOutput);
+
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+ outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
+ mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
+ &outputDesc->mSamplingRate,
+ &outputDesc->mFormat,
+ &outputDesc->mChannels,
+ &outputDesc->mLatency,
+ outputDesc->mFlags);
+ if (mHardwareOutput == 0) {
+ LOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d",
+ outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
+ } else {
+ AudioParameter outputCmd = AudioParameter();
+ outputCmd.addInt(String8("set_id"), 0);
+ mpClientInterface->setParameters(mHardwareOutput, outputCmd.toString());
+ mOutputs.add(mHardwareOutput, outputDesc);
+ }
+ }
+
+
+ mpClientInterface->setParameters(0, String8("test_cmd_policy="));
+ }
+ }
+ return false;
+}
+
+void AudioPolicyManagerGeneric::exit()
+{
+ {
+ AutoMutex _l(mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+ }
+ requestExitAndWait();
+}
+
+int AudioPolicyManagerGeneric::testOutputIndex(audio_io_handle_t output)
+{
+ for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+ if (output == mTestOutputs[i]) return i;
+ }
+ return 0;
+}
+#endif //AUDIO_POLICY_TEST
+
+// ---
+
+AudioPolicyManagerGeneric::routing_strategy AudioPolicyManagerGeneric::getStrategy(AudioSystem::stream_type stream)
+{
+ // stream to strategy mapping
+ switch (stream) {
+ case AudioSystem::VOICE_CALL:
+ case AudioSystem::BLUETOOTH_SCO:
+ return STRATEGY_PHONE;
+ case AudioSystem::RING:
+ case AudioSystem::NOTIFICATION:
+ case AudioSystem::ALARM:
+ case AudioSystem::ENFORCED_AUDIBLE:
+ return STRATEGY_SONIFICATION;
+ case AudioSystem::DTMF:
+ return STRATEGY_DTMF;
+ default:
+ LOGE("unknown stream type");
+ case AudioSystem::SYSTEM:
+ // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
+ // while key clicks are played produces a poor result
+ case AudioSystem::TTS:
+ case AudioSystem::MUSIC:
+ return STRATEGY_MEDIA;
+ }
+}
+
+
+float AudioPolicyManagerGeneric::computeVolume(int stream, int index, uint32_t device)
+{
+ float volume = 1.0;
+
+ StreamDescriptor &streamDesc = mStreams[stream];
+
+ // Force max volume if stream cannot be muted
+ if (!streamDesc.mCanBeMuted) index = streamDesc.mIndexMax;
+
+ int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin);
+ volume = AudioSystem::linearToLog(volInt);
+
+ return volume;
+}
+
+void AudioPolicyManagerGeneric::setStreamMute(int stream, bool on, audio_io_handle_t output)
+{
+ LOGV("setStreamMute() stream %d, mute %d, output %d", stream, on, output);
+
+ StreamDescriptor &streamDesc = mStreams[stream];
+
+ if (on) {
+ if (streamDesc.mMuteCount++ == 0) {
+ if (streamDesc.mCanBeMuted) {
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, 0, output);
+ }
+ }
+ } else {
+ if (streamDesc.mMuteCount == 0) {
+ LOGW("setStreamMute() unmuting non muted stream!");
+ return;
+ }
+ if (--streamDesc.mMuteCount == 0) {
+ uint32_t device = mOutputs.valueFor(output)->mDevice;
+ float volume = computeVolume(stream, streamDesc.mIndexCur, device);
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output);
+ }
+ }
+}
+
+void AudioPolicyManagerGeneric::handleIncallSonification(int stream, bool starting)
+{
+ // if the stream pertains to sonification strategy and we are in call we must
+ // mute the stream if it is low visibility. If it is high visibility, we must play a tone
+ // in the device used for phone strategy and play the tone if the selected device does not
+ // interfere with the device used for phone strategy
+ if (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) {
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mHardwareOutput);
+ LOGV("handleIncallSonification() stream %d starting %d device %x", stream, starting, outputDesc->mDevice);
+ if (outputDesc->isUsedByStream((AudioSystem::stream_type)stream)) {
+ if (AudioSystem::isLowVisibility((AudioSystem::stream_type)stream)) {
+ LOGV("handleIncallSonification() low visibility");
+ setStreamMute(stream, starting, mHardwareOutput);
+ } else {
+ if (starting) {
+ mpClientInterface->startTone(ToneGenerator::TONE_SUP_CALL_WAITING, AudioSystem::VOICE_CALL);
+ } else {
+ mpClientInterface->stopTone();
+ }
+ }
+ }
+ }
+}
+
+
+// --- AudioOutputDescriptor class implementation
+
+AudioPolicyManagerGeneric::AudioOutputDescriptor::AudioOutputDescriptor()
+ : mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0),
+ mFlags((AudioSystem::output_flags)0), mDevice(0)
+{
+ // clear usage count for all stream types
+ for (int i = 0; i < AudioSystem::NUM_STREAM_TYPES; i++) {
+ mRefCount[i] = 0;
+ }
+}
+
+uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::device()
+{
+ return mDevice;
+}
+
+void AudioPolicyManagerGeneric::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta)
+{
+ if ((delta + (int)mRefCount[stream]) < 0) {
+ LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
+ mRefCount[stream] = 0;
+ return;
+ }
+ mRefCount[stream] += delta;
+ LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+}
+
+uint32_t AudioPolicyManagerGeneric::AudioOutputDescriptor::refCount()
+{
+ uint32_t refcount = 0;
+ for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
+ refcount += mRefCount[i];
+ }
+ return refcount;
+}
+
+// --- AudioInputDescriptor class implementation
+
+AudioPolicyManagerGeneric::AudioInputDescriptor::AudioInputDescriptor()
+ : mSamplingRate(0), mFormat(0), mChannels(0),
+ mAcoustics((AudioSystem::audio_in_acoustics)0), mDevice(0), mRefCount(0)
+{
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioPolicyManagerGeneric.h b/libs/audioflinger/AudioPolicyManagerGeneric.h
new file mode 100644
index 0000000..d904520
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyManagerGeneric.h
@@ -0,0 +1,189 @@
+/*
+ * 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 <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <utils/threads.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define MAX_DEVICE_ADDRESS_LEN 20
+#define NUM_TEST_OUTPUTS 5
+
+class AudioPolicyManagerGeneric: public AudioPolicyInterface
+#ifdef AUDIO_POLICY_TEST
+ , public Thread
+#endif //AUDIO_POLICY_TEST
+{
+
+public:
+ AudioPolicyManagerGeneric(AudioPolicyClientInterface *clientInterface);
+ virtual ~AudioPolicyManagerGeneric();
+
+ // AudioPolicyInterface
+ virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address);
+ virtual void setPhoneState(int state);
+ virtual void setRingerMode(uint32_t mode, uint32_t mask);
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
+ virtual void setSystemProperty(const char* property, const char* value);
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags);
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual void releaseOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics);
+ // indicates to the audio policy manager that the input starts being used.
+ virtual status_t startInput(audio_io_handle_t input);
+ // indicates to the audio policy manager that the input stops being used.
+ virtual status_t stopInput(audio_io_handle_t input);
+ virtual void releaseInput(audio_io_handle_t input);
+ virtual void initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax);
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
+
+private:
+
+ enum routing_strategy {
+ STRATEGY_MEDIA,
+ STRATEGY_PHONE,
+ STRATEGY_SONIFICATION,
+ STRATEGY_DTMF,
+ NUM_STRATEGIES
+ };
+
+ // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
+ // and keep track of the usage of this output by each audio stream type.
+ class AudioOutputDescriptor
+ {
+ public:
+ AudioOutputDescriptor();
+
+
+ uint32_t device();
+ void changeRefCount(AudioSystem::stream_type, int delta);
+ bool isUsedByStream(AudioSystem::stream_type stream) { return mRefCount[stream] > 0 ? true : false; }
+ uint32_t refCount();
+
+ uint32_t mSamplingRate; //
+ uint32_t mFormat; //
+ uint32_t mChannels; // output configuration
+ uint32_t mLatency; //
+ AudioSystem::output_flags mFlags; //
+ uint32_t mDevice; // current device this output is routed to
+ uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES]; // number of streams of each type using this output
+ };
+
+ // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
+ // and keep track of the usage of this input.
+ class AudioInputDescriptor
+ {
+ public:
+ AudioInputDescriptor();
+
+ uint32_t mSamplingRate; //
+ uint32_t mFormat; // input configuration
+ uint32_t mChannels; //
+ AudioSystem::audio_in_acoustics mAcoustics; //
+ uint32_t mDevice; // current device this input is routed to
+ uint32_t mRefCount; // number of AudioRecord clients using this output
+ };
+
+ // stream descriptor used for volume control
+ class StreamDescriptor
+ {
+ public:
+ StreamDescriptor()
+ : mIndexMin(0), mIndexMax(1), mIndexCur(1), mMuteCount(0), mCanBeMuted(true) {}
+
+ int mIndexMin; // min volume index
+ int mIndexMax; // max volume index
+ int mIndexCur; // current volume index
+ int mMuteCount; // mute request counter
+ bool mCanBeMuted; // true is the stream can be muted
+ };
+
+ // return the strategy corresponding to a given stream type
+ static routing_strategy getStrategy(AudioSystem::stream_type stream);
+ // return the output handle of an output routed to the specified device, 0 if no output
+ // is routed to the device
+ float computeVolume(int stream, int index, uint32_t device);
+ // Mute or unmute the stream on the specified output
+ void setStreamMute(int stream, bool on, audio_io_handle_t output);
+ // handle special cases for sonification strategy while in call: mute streams or replace by
+ // a special tone in the device used for communication
+ void handleIncallSonification(int stream, bool starting);
+
+
+#ifdef AUDIO_POLICY_TEST
+ virtual bool threadLoop();
+ void exit();
+ int testOutputIndex(audio_io_handle_t output);
+#endif //AUDIO_POLICY_TEST
+
+
+ AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
+ audio_io_handle_t mHardwareOutput; // hardware output handler
+
+ KeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs; // list ot output descritors
+ KeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs; // list of input descriptors
+ uint32_t mAvailableOutputDevices; // bit field of all available output devices
+ uint32_t mAvailableInputDevices; // bit field of all available input devices
+ int mPhoneState; // current phone state
+ uint32_t mRingerMode; // current ringer mode
+ AudioSystem::forced_config mForceUse[AudioSystem::NUM_FORCE_USE]; // current forced use configuration
+
+ StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES]; // stream descriptors for volume control
+
+#ifdef AUDIO_POLICY_TEST
+ Mutex mLock;
+ Condition mWaitWorkCV;
+
+ int mCurOutput;
+ bool mDirectOutput;
+ audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
+ int mTestInput;
+ uint32_t mTestDevice;
+ uint32_t mTestSamplingRate;
+ uint32_t mTestFormat;
+ uint32_t mTestChannels;
+ uint32_t mTestLatencyMs;
+#endif //AUDIO_POLICY_TEST
+
+};
+
+};
diff --git a/libs/audioflinger/AudioPolicyService.cpp b/libs/audioflinger/AudioPolicyService.cpp
new file mode 100644
index 0000000..5c3cc8e
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyService.cpp
@@ -0,0 +1,771 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AudioPolicyService"
+//#define LOG_NDEBUG 0
+
+#undef __STRICT_ANSI__
+#define __STDINT_LIMITS
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
+#include <sys/time.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <binder/IPCThreadState.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+#include "AudioPolicyService.h"
+#include "AudioPolicyManagerGeneric.h"
+#include <cutils/properties.h>
+#include <dlfcn.h>
+
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+namespace android {
+
+static bool checkPermission() {
+#ifndef HAVE_ANDROID_OS
+ return true;
+#endif
+ if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+ bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
+ if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+ return ok;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioPolicyService::AudioPolicyService()
+ : BnAudioPolicyService() , mpPolicyManager(NULL)
+{
+ char value[PROPERTY_VALUE_MAX];
+
+ // start tone playback thread
+ mTonePlaybackThread = new AudioCommandThread();
+ // start audio commands thread
+ mAudioCommandThread = new AudioCommandThread();
+
+#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
+ mpPolicyManager = new AudioPolicyManagerGeneric(this);
+ LOGV("build for GENERIC_AUDIO - using generic audio policy");
+#else
+ // if running in emulation - use the emulator driver
+ if (property_get("ro.kernel.qemu", value, 0)) {
+ LOGV("Running in emulation - using generic audio policy");
+ mpPolicyManager = new AudioPolicyManagerGeneric(this);
+ }
+ else {
+ LOGV("Using hardware specific audio policy");
+ mpPolicyManager = createAudioPolicyManager(this);
+ }
+#endif
+
+ // load properties
+ property_get("ro.camera.sound.forced", value, "0");
+ mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);
+}
+
+AudioPolicyService::~AudioPolicyService()
+{
+ mTonePlaybackThread->exit();
+ mTonePlaybackThread.clear();
+ mAudioCommandThread->exit();
+ mAudioCommandThread.clear();
+
+ if (mpPolicyManager) {
+ delete mpPolicyManager;
+ }
+}
+
+
+status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (!AudioSystem::isOutputDevice(device) && !AudioSystem::isInputDevice(device)) {
+ return BAD_VALUE;
+ }
+ if (state != AudioSystem::DEVICE_STATE_AVAILABLE && state != AudioSystem::DEVICE_STATE_UNAVAILABLE) {
+ return BAD_VALUE;
+ }
+
+ LOGV("setDeviceConnectionState() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->setDeviceConnectionState(device, state, device_address);
+}
+
+AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address)
+{
+ if (mpPolicyManager == NULL) {
+ return AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ }
+ if (!checkPermission()) {
+ return AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ }
+ return mpPolicyManager->getDeviceConnectionState(device, device_address);
+}
+
+status_t AudioPolicyService::setPhoneState(int state)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (state < 0 || state >= AudioSystem::NUM_MODES) {
+ return BAD_VALUE;
+ }
+
+ LOGV("setPhoneState() tid %d", gettid());
+
+ // TODO: check if it is more appropriate to do it in platform specific policy manager
+ AudioSystem::setMode(state);
+
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->setPhoneState(state);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::setRingerMode(uint32_t mode, uint32_t mask)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+
+ mpPolicyManager->setRingerMode(mode, mask);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (usage < 0 || usage >= AudioSystem::NUM_FORCE_USE) {
+ return BAD_VALUE;
+ }
+ if (config < 0 || config >= AudioSystem::NUM_FORCE_CONFIG) {
+ return BAD_VALUE;
+ }
+ LOGV("setForceUse() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->setForceUse(usage, config);
+ return NO_ERROR;
+}
+
+AudioSystem::forced_config AudioPolicyService::getForceUse(AudioSystem::force_use usage)
+{
+ if (mpPolicyManager == NULL) {
+ return AudioSystem::FORCE_NONE;
+ }
+ if (!checkPermission()) {
+ return AudioSystem::FORCE_NONE;
+ }
+ if (usage < 0 || usage >= AudioSystem::NUM_FORCE_USE) {
+ return AudioSystem::FORCE_NONE;
+ }
+ return mpPolicyManager->getForceUse(usage);
+}
+
+audio_io_handle_t AudioPolicyService::getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags)
+{
+ if (mpPolicyManager == NULL) {
+ return 0;
+ }
+ LOGV("getOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->getOutput(stream, samplingRate, format, channels, flags);
+}
+
+status_t AudioPolicyService::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ LOGV("startOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->startOutput(output, stream);
+}
+
+status_t AudioPolicyService::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ LOGV("stopOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->stopOutput(output, stream);
+}
+
+void AudioPolicyService::releaseOutput(audio_io_handle_t output)
+{
+ if (mpPolicyManager == NULL) {
+ return;
+ }
+ LOGV("releaseOutput() tid %d", gettid());
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->releaseOutput(output);
+}
+
+audio_io_handle_t AudioPolicyService::getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ if (mpPolicyManager == NULL) {
+ return 0;
+ }
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->getInput(inputSource, samplingRate, format, channels, acoustics);
+}
+
+status_t AudioPolicyService::startInput(audio_io_handle_t input)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->startInput(input);
+}
+
+status_t AudioPolicyService::stopInput(audio_io_handle_t input)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mpPolicyManager->stopInput(input);
+}
+
+void AudioPolicyService::releaseInput(audio_io_handle_t input)
+{
+ if (mpPolicyManager == NULL) {
+ return;
+ }
+ Mutex::Autolock _l(mLock);
+ mpPolicyManager->releaseInput(input);
+}
+
+status_t AudioPolicyService::initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+ mpPolicyManager->initStreamVolume(stream, indexMin, indexMax);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+
+ return mpPolicyManager->setStreamVolumeIndex(stream, index);
+}
+
+status_t AudioPolicyService::getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
+{
+ if (mpPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!checkPermission()) {
+ return PERMISSION_DENIED;
+ }
+ if (stream < 0 || stream >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+ return mpPolicyManager->getStreamVolumeIndex(stream, index);
+}
+
+void AudioPolicyService::binderDied(const wp<IBinder>& who) {
+ LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
+}
+
+status_t AudioPolicyService::dump(int fd, const Vector<String16>& args)
+{
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ dumpPermissionDenial(fd, args);
+ } else {
+
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::dumpPermissionDenial(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump AudioPolicyService from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ return BnAudioPolicyService::onTransact(code, data, reply, flags);
+}
+
+
+// ----------------------------------------------------------------------------
+void AudioPolicyService::instantiate() {
+ defaultServiceManager()->addService(
+ String16("media.audio_policy"), new AudioPolicyService());
+}
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyClientInterface implementation
+// ----------------------------------------------------------------------------
+
+
+audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ AudioSystem::output_flags flags)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("openOutput() could not get AudioFlinger");
+ return 0;
+ }
+
+ return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags);
+}
+
+audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("openDuplicateOutput() could not get AudioFlinger");
+ return 0;
+ }
+ return af->openDuplicateOutput(output1, output2);
+}
+
+status_t AudioPolicyService::closeOutput(audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ return af->closeOutput(output);
+}
+
+
+status_t AudioPolicyService::suspendOutput(audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("suspendOutput() could not get AudioFlinger");
+ return PERMISSION_DENIED;
+ }
+
+ return af->suspendOutput(output);
+}
+
+status_t AudioPolicyService::restoreOutput(audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("restoreOutput() could not get AudioFlinger");
+ return PERMISSION_DENIED;
+ }
+
+ return af->restoreOutput(output);
+}
+
+audio_io_handle_t AudioPolicyService::openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ LOGW("openInput() could not get AudioFlinger");
+ return 0;
+ }
+
+ return af->openInput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, acoustics);
+}
+
+status_t AudioPolicyService::closeInput(audio_io_handle_t input)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ return af->closeInput(input);
+}
+
+status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs)
+{
+ return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs);
+}
+
+status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output)
+{
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+
+ return af->setStreamOutput(stream, output);
+}
+
+
+void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs)
+{
+ mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs, delayMs);
+}
+
+String8 AudioPolicyService::getParameters(audio_io_handle_t ioHandle, const String8& keys)
+{
+ String8 result = AudioSystem::getParameters(ioHandle, keys);
+ return result;
+}
+
+status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream)
+{
+ mTonePlaybackThread->startToneCommand(tone, stream);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::stopTone()
+{
+ mTonePlaybackThread->stopToneCommand();
+ return NO_ERROR;
+}
+
+
+// ----------- AudioPolicyService::AudioCommandThread implementation ----------
+
+AudioPolicyService::AudioCommandThread::AudioCommandThread()
+ : Thread(false)
+{
+ mpToneGenerator = NULL;
+}
+
+
+AudioPolicyService::AudioCommandThread::~AudioCommandThread()
+{
+ mAudioCommands.clear();
+ if (mpToneGenerator != NULL) delete mpToneGenerator;
+}
+
+void AudioPolicyService::AudioCommandThread::onFirstRef()
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "AudioCommandThread");
+
+ run(buffer, ANDROID_PRIORITY_AUDIO);
+}
+
+bool AudioPolicyService::AudioCommandThread::threadLoop()
+{
+ nsecs_t waitTime = INT64_MAX;
+
+ mLock.lock();
+ while (!exitPending())
+ {
+ while(!mAudioCommands.isEmpty()) {
+ nsecs_t curTime = systemTime();
+ // commands are sorted by increasing time stamp: execute them from index 0 and up
+ if (mAudioCommands[0]->mTime <= curTime) {
+ AudioCommand *command = mAudioCommands[0];
+ mAudioCommands.removeAt(0);
+ switch (command->mCommand) {
+ case START_TONE: {
+ mLock.unlock();
+ ToneData *data = (ToneData *)command->mParam;
+ LOGV("AudioCommandThread() processing start tone %d on stream %d",
+ data->mType, data->mStream);
+ if (mpToneGenerator != NULL)
+ delete mpToneGenerator;
+ mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
+ mpToneGenerator->startTone(data->mType);
+ delete data;
+ mLock.lock();
+ }break;
+ case STOP_TONE: {
+ mLock.unlock();
+ LOGV("AudioCommandThread() processing stop tone");
+ if (mpToneGenerator != NULL) {
+ mpToneGenerator->stopTone();
+ delete mpToneGenerator;
+ mpToneGenerator = NULL;
+ }
+ mLock.lock();
+ }break;
+ case SET_VOLUME: {
+ VolumeData *data = (VolumeData *)command->mParam;
+ LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %d", data->mStream, data->mVolume, data->mIO);
+ command->mStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO);
+ if (command->mWaitStatus) {
+ command->mCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ delete data;
+ }break;
+ case SET_PARAMETERS: {
+ ParametersData *data = (ParametersData *)command->mParam;
+ LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO);
+ command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
+ if (command->mWaitStatus) {
+ command->mCond.signal();
+ mWaitWorkCV.wait(mLock);
+ }
+ delete data;
+ }break;
+ default:
+ LOGW("AudioCommandThread() unknown command %d", command->mCommand);
+ }
+ delete command;
+ waitTime = INT64_MAX;
+ } else {
+ waitTime = mAudioCommands[0]->mTime - curTime;
+ break;
+ }
+ }
+ LOGV("AudioCommandThread() going to sleep");
+ mWaitWorkCV.waitRelative(mLock, waitTime);
+ LOGV("AudioCommandThread() waking up");
+ }
+ mLock.unlock();
+ return false;
+}
+
+void AudioPolicyService::AudioCommandThread::startToneCommand(int type, int stream)
+{
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = START_TONE;
+ ToneData *data = new ToneData();
+ data->mType = type;
+ data->mStream = stream;
+ command->mParam = (void *)data;
+ command->mWaitStatus = false;
+ insertCommand_l(command);
+ LOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
+ mWaitWorkCV.signal();
+}
+
+void AudioPolicyService::AudioCommandThread::stopToneCommand()
+{
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = STOP_TONE;
+ command->mParam = NULL;
+ command->mWaitStatus = false;
+ insertCommand_l(command);
+ LOGV("AudioCommandThread() adding tone stop");
+ mWaitWorkCV.signal();
+}
+
+status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output, int delayMs)
+{
+ status_t status = NO_ERROR;
+
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = SET_VOLUME;
+ VolumeData *data = new VolumeData();
+ data->mStream = stream;
+ data->mVolume = volume;
+ data->mIO = output;
+ command->mParam = data;
+ if (delayMs == 0) {
+ command->mWaitStatus = true;
+ } else {
+ command->mWaitStatus = false;
+ }
+ insertCommand_l(command, delayMs);
+ LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output);
+ mWaitWorkCV.signal();
+ if (command->mWaitStatus) {
+ command->mCond.wait(mLock);
+ status = command->mStatus;
+ mWaitWorkCV.signal();
+ }
+ return status;
+}
+
+status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs)
+{
+ status_t status = NO_ERROR;
+
+ Mutex::Autolock _l(mLock);
+ AudioCommand *command = new AudioCommand();
+ command->mCommand = SET_PARAMETERS;
+ ParametersData *data = new ParametersData();
+ data->mIO = ioHandle;
+ data->mKeyValuePairs = keyValuePairs;
+ command->mParam = data;
+ if (delayMs == 0) {
+ command->mWaitStatus = true;
+ } else {
+ command->mWaitStatus = false;
+ }
+ insertCommand_l(command, delayMs);
+ LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", keyValuePairs.string(), ioHandle, delayMs);
+ mWaitWorkCV.signal();
+ if (command->mWaitStatus) {
+ command->mCond.wait(mLock);
+ status = command->mStatus;
+ mWaitWorkCV.signal();
+ }
+ return status;
+}
+
+// insertCommand_l() must be called with mLock held
+void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
+{
+ ssize_t i;
+ Vector <AudioCommand *> removedCommands;
+
+ command->mTime = systemTime() + milliseconds(delayMs);
+
+ // check same pending commands with later time stamps and eliminate them
+ for (i = mAudioCommands.size()-1; i >= 0; i--) {
+ AudioCommand *command2 = mAudioCommands[i];
+ // commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands
+ if (command2->mTime <= command->mTime) break;
+ if (command2->mCommand != command->mCommand) continue;
+
+ switch (command->mCommand) {
+ case SET_PARAMETERS: {
+ ParametersData *data = (ParametersData *)command->mParam;
+ ParametersData *data2 = (ParametersData *)command2->mParam;
+ if (data->mIO != data2->mIO) break;
+ LOGV("Comparing parameter command %s to new command %s", data2->mKeyValuePairs.string(), data->mKeyValuePairs.string());
+ AudioParameter param = AudioParameter(data->mKeyValuePairs);
+ AudioParameter param2 = AudioParameter(data2->mKeyValuePairs);
+ for (size_t j = 0; j < param.size(); j++) {
+ String8 key;
+ String8 value;
+ param.getAt(j, key, value);
+ for (size_t k = 0; k < param2.size(); k++) {
+ String8 key2;
+ String8 value2;
+ param2.getAt(k, key2, value2);
+ if (key2 == key) {
+ param2.remove(key2);
+ LOGV("Filtering out parameter %s", key2.string());
+ break;
+ }
+ }
+ }
+ // if all keys have been filtered out, remove the command.
+ // otherwise, update the key value pairs
+ if (param2.size() == 0) {
+ removedCommands.add(command2);
+ } else {
+ data2->mKeyValuePairs = param2.toString();
+ }
+ } break;
+
+ case SET_VOLUME: {
+ VolumeData *data = (VolumeData *)command->mParam;
+ VolumeData *data2 = (VolumeData *)command2->mParam;
+ if (data->mIO != data2->mIO) break;
+ if (data->mStream != data2->mStream) break;
+ LOGV("Filtering out volume command on output %d for stream %d", data->mIO, data->mStream);
+ removedCommands.add(command2);
+ } break;
+ case START_TONE:
+ case STOP_TONE:
+ default:
+ break;
+ }
+ }
+
+ // remove filtered commands
+ for (size_t j = 0; j < removedCommands.size(); j++) {
+ // removed commands always have time stamps greater than current command
+ for (size_t k = i + 1; k < mAudioCommands.size(); k++) {
+ if (mAudioCommands[k] == removedCommands[j]) {
+ LOGV("suppressing command: %d", mAudioCommands[k]->mCommand);
+ mAudioCommands.removeAt(k);
+ break;
+ }
+ }
+ }
+ removedCommands.clear();
+
+ // insert command at the right place according to its time stamp
+ LOGV("inserting command: %d at index %ld, num commands %d", command->mCommand, i+1, mAudioCommands.size());
+ mAudioCommands.insertAt(command, i + 1);
+}
+
+void AudioPolicyService::AudioCommandThread::exit()
+{
+ LOGV("AudioCommandThread::exit");
+ {
+ AutoMutex _l(mLock);
+ requestExit();
+ mWaitWorkCV.signal();
+ }
+ requestExitAndWait();
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioPolicyService.h b/libs/audioflinger/AudioPolicyService.h
new file mode 100644
index 0000000..56a85e1
--- /dev/null
+++ b/libs/audioflinger/AudioPolicyService.h
@@ -0,0 +1,203 @@
+/*
+ * 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_AUDIOPOLICYSERVICE_H
+#define ANDROID_AUDIOPOLICYSERVICE_H
+
+#include <media/IAudioPolicyService.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <media/ToneGenerator.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class String8;
+
+// ----------------------------------------------------------------------------
+
+class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface, public IBinder::DeathRecipient
+{
+
+public:
+ static void instantiate();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ //
+ // BnAudioPolicyService (see AudioPolicyInterface for method descriptions)
+ //
+
+ virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device,
+ const char *device_address);
+ virtual status_t setPhoneState(int state);
+ virtual status_t setRingerMode(uint32_t mode, uint32_t mask);
+ virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
+ virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream,
+ uint32_t samplingRate = 0,
+ uint32_t format = AudioSystem::FORMAT_DEFAULT,
+ uint32_t channels = 0,
+ AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT);
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual void releaseOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t getInput(int inputSource,
+ uint32_t samplingRate = 0,
+ uint32_t format = AudioSystem::FORMAT_DEFAULT,
+ uint32_t channels = 0,
+ AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0);
+ virtual status_t startInput(audio_io_handle_t input);
+ virtual status_t stopInput(audio_io_handle_t input);
+ virtual void releaseInput(audio_io_handle_t input);
+ virtual status_t initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax);
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index);
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index);
+
+ virtual status_t onTransact(
+ uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags);
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
+ //
+ // AudioPolicyClientInterface
+ //
+ virtual audio_io_handle_t openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ AudioSystem::output_flags flags);
+ virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2);
+ virtual status_t closeOutput(audio_io_handle_t output);
+ virtual status_t suspendOutput(audio_io_handle_t output);
+ virtual status_t restoreOutput(audio_io_handle_t output);
+ virtual audio_io_handle_t openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics);
+ virtual status_t closeInput(audio_io_handle_t input);
+ virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs = 0);
+ virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output);
+ virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0);
+ virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
+ virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream);
+ virtual status_t stopTone();
+
+private:
+ AudioPolicyService();
+ virtual ~AudioPolicyService();
+
+ // Thread used for tone playback and to send audio config commands to audio flinger
+ // For tone playback, using a separate thread is necessary to avoid deadlock with mLock because startTone()
+ // and stopTone() are normally called with mLock locked and requesting a tone start or stop will cause
+ // calls to AudioPolicyService and an attempt to lock mLock.
+ // For audio config commands, it is necessary because audio flinger requires that the calling process (user)
+ // has permission to modify audio settings.
+ class AudioCommandThread : public Thread {
+ class AudioCommand;
+ public:
+
+ // commands for tone AudioCommand
+ enum {
+ START_TONE,
+ STOP_TONE,
+ SET_VOLUME,
+ SET_PARAMETERS
+ };
+
+ AudioCommandThread ();
+ virtual ~AudioCommandThread();
+
+ // Thread virtuals
+ virtual void onFirstRef();
+ virtual bool threadLoop();
+
+ void exit();
+ void startToneCommand(int type = 0, int stream = 0);
+ void stopToneCommand();
+ status_t volumeCommand(int stream, float volume, int output, int delayMs = 0);
+ status_t parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs = 0);
+ void insertCommand_l(AudioCommand *command, int delayMs = 0);
+
+ private:
+ // descriptor for requested tone playback event
+ class AudioCommand {
+ public:
+ int mCommand; // START_TONE, STOP_TONE ...
+ nsecs_t mTime; // time stamp
+ Condition mCond; // condition for status return
+ status_t mStatus; // command status
+ bool mWaitStatus; // true if caller is waiting for status
+ void *mParam; // command parameter (ToneData, VolumeData, ParametersData)
+ };
+
+ class ToneData {
+ public:
+ int mType; // tone type (START_TONE only)
+ int mStream; // stream type (START_TONE only)
+ };
+
+ class VolumeData {
+ public:
+ int mStream;
+ float mVolume;
+ int mIO;
+ };
+ class ParametersData {
+ public:
+ int mIO;
+ String8 mKeyValuePairs;
+ };
+
+
+ Mutex mLock;
+ Condition mWaitWorkCV;
+ Vector <AudioCommand *> mAudioCommands; // list of pending commands
+ ToneGenerator *mpToneGenerator; // the tone generator
+ };
+
+ // Internal dump utilities.
+ status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
+
+
+ Mutex mLock; // prevents concurrent access to AudioPolicy manager functions changing device
+ // connection stated our routing
+ AudioPolicyInterface* mpPolicyManager; // the platform specific policy manager
+ sp <AudioCommandThread> mAudioCommandThread; // audio commands thread
+ sp <AudioCommandThread> mTonePlaybackThread; // tone playback thread
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOPOLICYSERVICE_H
+
+
+
+
+
+
+
+
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
new file mode 100644
index 0000000..2df6775
--- /dev/null
+++ b/libs/binder/Android.mk
@@ -0,0 +1,45 @@
+# 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 \
+ Permission.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/binder/Binder.cpp b/libs/binder/Binder.cpp
new file mode 100644
index 0000000..0dd7622
--- /dev/null
+++ b/libs/binder/Binder.cpp
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ */
+
+#include <binder/Binder.h>
+
+#include <utils/Atomic.h>
+#include <binder/BpBinder.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+IBinder::IBinder()
+ : RefBase()
+{
+}
+
+IBinder::~IBinder()
+{
+}
+
+// ---------------------------------------------------------------------------
+
+sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor)
+{
+ return NULL;
+}
+
+BBinder* IBinder::localBinder()
+{
+ return NULL;
+}
+
+BpBinder* IBinder::remoteBinder()
+{
+ return NULL;
+}
+
+bool IBinder::checkSubclass(const void* /*subclassID*/) const
+{
+ return false;
+}
+
+// ---------------------------------------------------------------------------
+
+class BBinder::Extras
+{
+public:
+ Mutex mLock;
+ BpBinder::ObjectManager mObjects;
+};
+
+// ---------------------------------------------------------------------------
+
+String16 BBinder::sEmptyDescriptor;
+
+BBinder::BBinder()
+ : mExtras(NULL)
+{
+}
+
+bool BBinder::isBinderAlive() const
+{
+ return true;
+}
+
+status_t BBinder::pingBinder()
+{
+ return NO_ERROR;
+}
+
+const String16& BBinder::getInterfaceDescriptor() const
+{
+ LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
+ return sEmptyDescriptor;
+}
+
+status_t BBinder::transact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ data.setDataPosition(0);
+
+ status_t err = NO_ERROR;
+ switch (code) {
+ case PING_TRANSACTION:
+ reply->writeInt32(pingBinder());
+ break;
+ default:
+ err = onTransact(code, data, reply, flags);
+ break;
+ }
+
+ if (reply != NULL) {
+ reply->setDataPosition(0);
+ }
+
+ return err;
+}
+
+status_t BBinder::linkToDeath(
+ const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
+{
+ return INVALID_OPERATION;
+}
+
+status_t BBinder::unlinkToDeath(
+ const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+ wp<DeathRecipient>* outRecipient)
+{
+ return INVALID_OPERATION;
+}
+
+status_t BBinder::dump(int fd, const Vector<String16>& args)
+{
+ return NO_ERROR;
+}
+
+void BBinder::attachObject(
+ const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func)
+{
+ Extras* e = mExtras;
+
+ if (!e) {
+ e = new Extras;
+ if (android_atomic_cmpxchg(0, reinterpret_cast<int32_t>(e),
+ reinterpret_cast<volatile int32_t*>(&mExtras)) != 0) {
+ delete e;
+ e = mExtras;
+ }
+ if (e == 0) return; // out of memory
+ }
+
+ AutoMutex _l(e->mLock);
+ e->mObjects.attach(objectID, object, cleanupCookie, func);
+}
+
+void* BBinder::findObject(const void* objectID) const
+{
+ Extras* e = mExtras;
+ if (!e) return NULL;
+
+ AutoMutex _l(e->mLock);
+ return e->mObjects.find(objectID);
+}
+
+void BBinder::detachObject(const void* objectID)
+{
+ Extras* e = mExtras;
+ if (!e) return;
+
+ AutoMutex _l(e->mLock);
+ e->mObjects.detach(objectID);
+}
+
+BBinder* BBinder::localBinder()
+{
+ return this;
+}
+
+BBinder::~BBinder()
+{
+ if (mExtras) delete mExtras;
+}
+
+
+status_t BBinder::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case INTERFACE_TRANSACTION:
+ reply->writeString16(getInterfaceDescriptor());
+ return NO_ERROR;
+
+ case DUMP_TRANSACTION: {
+ int fd = data.readFileDescriptor();
+ int argc = data.readInt32();
+ Vector<String16> args;
+ for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+ args.add(data.readString16());
+ }
+ return dump(fd, args);
+ }
+ default:
+ return UNKNOWN_TRANSACTION;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+enum {
+ // This is used to transfer ownership of the remote binder from
+ // the BpRefBase object holding it (when it is constructed), to the
+ // owner of the BpRefBase object when it first acquires that BpRefBase.
+ kRemoteAcquired = 0x00000001
+};
+
+BpRefBase::BpRefBase(const sp<IBinder>& o)
+ : mRemote(o.get()), mRefs(NULL), mState(0)
+{
+ extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+
+ if (mRemote) {
+ mRemote->incStrong(this); // Removed on first IncStrong().
+ mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
+ }
+}
+
+BpRefBase::~BpRefBase()
+{
+ if (mRemote) {
+ if (!(mState&kRemoteAcquired)) {
+ mRemote->decStrong(this);
+ }
+ mRefs->decWeak(this);
+ }
+}
+
+void BpRefBase::onFirstRef()
+{
+ android_atomic_or(kRemoteAcquired, &mState);
+}
+
+void BpRefBase::onLastStrongRef(const void* id)
+{
+ if (mRemote) {
+ mRemote->decStrong(this);
+ }
+}
+
+bool BpRefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+ return mRemote ? mRefs->attemptIncStrong(this) : false;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
new file mode 100644
index 0000000..5de87ec
--- /dev/null
+++ b/libs/binder/BpBinder.cpp
@@ -0,0 +1,365 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BpBinder"
+//#define LOG_NDEBUG 0
+
+#include <binder/BpBinder.h>
+
+#include <binder/IPCThreadState.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+
+//#undef LOGV
+//#define LOGV(...) fprintf(stderr, __VA_ARGS__)
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+BpBinder::ObjectManager::ObjectManager()
+{
+}
+
+BpBinder::ObjectManager::~ObjectManager()
+{
+ kill();
+}
+
+void BpBinder::ObjectManager::attach(
+ const void* objectID, void* object, void* cleanupCookie,
+ IBinder::object_cleanup_func func)
+{
+ entry_t e;
+ e.object = object;
+ e.cleanupCookie = cleanupCookie;
+ e.func = func;
+
+ if (mObjects.indexOfKey(objectID) >= 0) {
+ LOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",
+ objectID, this, object);
+ return;
+ }
+
+ mObjects.add(objectID, e);
+}
+
+void* BpBinder::ObjectManager::find(const void* objectID) const
+{
+ const ssize_t i = mObjects.indexOfKey(objectID);
+ if (i < 0) return NULL;
+ return mObjects.valueAt(i).object;
+}
+
+void BpBinder::ObjectManager::detach(const void* objectID)
+{
+ mObjects.removeItem(objectID);
+}
+
+void BpBinder::ObjectManager::kill()
+{
+ const size_t N = mObjects.size();
+ LOGV("Killing %d objects in manager %p", N, this);
+ for (size_t i=0; i<N; i++) {
+ const entry_t& e = mObjects.valueAt(i);
+ if (e.func != NULL) {
+ e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
+ }
+ }
+
+ mObjects.clear();
+}
+
+// ---------------------------------------------------------------------------
+
+BpBinder::BpBinder(int32_t handle)
+ : mHandle(handle)
+ , mAlive(1)
+ , mObitsSent(0)
+ , mObituaries(NULL)
+{
+ LOGV("Creating BpBinder %p handle %d\n", this, mHandle);
+
+ extendObjectLifetime(OBJECT_LIFETIME_WEAK);
+ IPCThreadState::self()->incWeakHandle(handle);
+}
+
+bool BpBinder::isDescriptorCached() const {
+ Mutex::Autolock _l(mLock);
+ return mDescriptorCache.size() ? true : false;
+}
+
+const String16& BpBinder::getInterfaceDescriptor() const
+{
+ 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;
+ }
+ }
+
+ // 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
+{
+ return mAlive != 0;
+}
+
+status_t BpBinder::pingBinder()
+{
+ Parcel send;
+ Parcel reply;
+ status_t err = transact(PING_TRANSACTION, send, &reply);
+ if (err != NO_ERROR) return err;
+ if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA;
+ return (status_t)reply.readInt32();
+}
+
+status_t BpBinder::dump(int fd, const Vector<String16>& args)
+{
+ Parcel send;
+ Parcel reply;
+ send.writeFileDescriptor(fd);
+ const size_t numArgs = args.size();
+ send.writeInt32(numArgs);
+ for (size_t i = 0; i < numArgs; i++) {
+ send.writeString16(args[i]);
+ }
+ status_t err = transact(DUMP_TRANSACTION, send, &reply);
+ return err;
+}
+
+status_t BpBinder::transact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ // Once a binder has died, it will never come back to life.
+ if (mAlive) {
+ status_t status = IPCThreadState::self()->transact(
+ mHandle, code, data, reply, flags);
+ if (status == DEAD_OBJECT) mAlive = 0;
+ return status;
+ }
+
+ return DEAD_OBJECT;
+}
+
+status_t BpBinder::linkToDeath(
+ const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
+{
+ Obituary ob;
+ ob.recipient = recipient;
+ ob.cookie = cookie;
+ ob.flags = flags;
+
+ LOG_ALWAYS_FATAL_IF(recipient == NULL,
+ "linkToDeath(): recipient must be non-NULL");
+
+ {
+ AutoMutex _l(mLock);
+
+ if (!mObitsSent) {
+ if (!mObituaries) {
+ mObituaries = new Vector<Obituary>;
+ if (!mObituaries) {
+ return NO_MEMORY;
+ }
+ LOGV("Requesting death notification: %p handle %d\n", this, mHandle);
+ getWeakRefs()->incWeak(this);
+ IPCThreadState* self = IPCThreadState::self();
+ self->requestDeathNotification(mHandle, this);
+ self->flushCommands();
+ }
+ ssize_t res = mObituaries->add(ob);
+ return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
+ }
+ }
+
+ return DEAD_OBJECT;
+}
+
+status_t BpBinder::unlinkToDeath(
+ const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+ wp<DeathRecipient>* outRecipient)
+{
+ AutoMutex _l(mLock);
+
+ if (mObitsSent) {
+ return DEAD_OBJECT;
+ }
+
+ const size_t N = mObituaries ? mObituaries->size() : 0;
+ for (size_t i=0; i<N; i++) {
+ const Obituary& obit = mObituaries->itemAt(i);
+ if ((obit.recipient == recipient
+ || (recipient == NULL && obit.cookie == cookie))
+ && obit.flags == flags) {
+ const uint32_t allFlags = obit.flags|flags;
+ if (outRecipient != NULL) {
+ *outRecipient = mObituaries->itemAt(i).recipient;
+ }
+ mObituaries->removeAt(i);
+ if (mObituaries->size() == 0) {
+ LOGV("Clearing death notification: %p handle %d\n", this, mHandle);
+ IPCThreadState* self = IPCThreadState::self();
+ self->clearDeathNotification(mHandle, this);
+ self->flushCommands();
+ delete mObituaries;
+ mObituaries = NULL;
+ }
+ return NO_ERROR;
+ }
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+void BpBinder::sendObituary()
+{
+ LOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
+ this, mHandle, mObitsSent ? "true" : "false");
+
+ mAlive = 0;
+ if (mObitsSent) return;
+
+ mLock.lock();
+ Vector<Obituary>* obits = mObituaries;
+ if(obits != NULL) {
+ LOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
+ IPCThreadState* self = IPCThreadState::self();
+ self->clearDeathNotification(mHandle, this);
+ self->flushCommands();
+ mObituaries = NULL;
+ }
+ mObitsSent = 1;
+ mLock.unlock();
+
+ LOGV("Reporting death of proxy %p for %d recipients\n",
+ this, obits ? obits->size() : 0);
+
+ if (obits != NULL) {
+ const size_t N = obits->size();
+ for (size_t i=0; i<N; i++) {
+ reportOneDeath(obits->itemAt(i));
+ }
+
+ delete obits;
+ }
+}
+
+void BpBinder::reportOneDeath(const Obituary& obit)
+{
+ sp<DeathRecipient> recipient = obit.recipient.promote();
+ LOGV("Reporting death to recipient: %p\n", recipient.get());
+ if (recipient == NULL) return;
+
+ recipient->binderDied(this);
+}
+
+
+void BpBinder::attachObject(
+ const void* objectID, void* object, void* cleanupCookie,
+ object_cleanup_func func)
+{
+ AutoMutex _l(mLock);
+ LOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
+ mObjects.attach(objectID, object, cleanupCookie, func);
+}
+
+void* BpBinder::findObject(const void* objectID) const
+{
+ AutoMutex _l(mLock);
+ return mObjects.find(objectID);
+}
+
+void BpBinder::detachObject(const void* objectID)
+{
+ AutoMutex _l(mLock);
+ mObjects.detach(objectID);
+}
+
+BpBinder* BpBinder::remoteBinder()
+{
+ return this;
+}
+
+BpBinder::~BpBinder()
+{
+ LOGV("Destroying BpBinder %p handle %d\n", this, mHandle);
+
+ IPCThreadState* ipc = IPCThreadState::self();
+
+ mLock.lock();
+ Vector<Obituary>* obits = mObituaries;
+ if(obits != NULL) {
+ if (ipc) ipc->clearDeathNotification(mHandle, this);
+ mObituaries = NULL;
+ }
+ mLock.unlock();
+
+ if (obits != NULL) {
+ // XXX Should we tell any remaining DeathRecipient
+ // objects that the last strong ref has gone away, so they
+ // are no longer linked?
+ delete obits;
+ }
+
+ if (ipc) {
+ ipc->expungeHandle(mHandle, this);
+ ipc->decWeakHandle(mHandle);
+ }
+}
+
+void BpBinder::onFirstRef()
+{
+ LOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (ipc) ipc->incStrongHandle(mHandle);
+}
+
+void BpBinder::onLastStrongRef(const void* id)
+{
+ LOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle);
+ IF_LOGV() {
+ printRefs();
+ }
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (ipc) ipc->decStrongHandle(mHandle);
+}
+
+bool BpBinder::onIncStrongAttempted(uint32_t flags, const void* id)
+{
+ LOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle);
+ IPCThreadState* ipc = IPCThreadState::self();
+ return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp
new file mode 100644
index 0000000..29acf5d
--- /dev/null
+++ b/libs/binder/IInterface.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+IInterface::IInterface()
+ : RefBase() {
+}
+
+IInterface::~IInterface() {
+}
+
+sp<IBinder> IInterface::asBinder()
+{
+ return this ? onAsBinder() : NULL;
+}
+
+sp<const IBinder> IInterface::asBinder() const
+{
+ return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
new file mode 100644
index 0000000..6c1d225
--- /dev/null
+++ b/libs/binder/IMemory.cpp
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IMemory"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <binder/IMemory.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <binder/Parcel.h>
+#include <utils/CallStack.h>
+
+#define VERBOSE 0
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class HeapCache : public IBinder::DeathRecipient
+{
+public:
+ HeapCache();
+ virtual ~HeapCache();
+
+ virtual void binderDied(const wp<IBinder>& who);
+
+ sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);
+ void pin_heap(const sp<IBinder>& binder);
+ void free_heap(const sp<IBinder>& binder);
+ sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
+ void dump_heaps();
+
+private:
+ // For IMemory.cpp
+ struct heap_info_t {
+ sp<IMemoryHeap> heap;
+ int32_t count;
+ };
+
+ void free_heap(const wp<IBinder>& binder);
+
+ Mutex mHeapCacheLock;
+ KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
+};
+
+static sp<HeapCache> gHeapCache = new HeapCache();
+
+/******************************************************************************/
+
+enum {
+ HEAP_ID = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMemoryHeap : public BpInterface<IMemoryHeap>
+{
+public:
+ BpMemoryHeap(const sp<IBinder>& impl);
+ virtual ~BpMemoryHeap();
+
+ virtual int getHeapID() const;
+ virtual void* getBase() const;
+ virtual size_t getSize() const;
+ virtual uint32_t getFlags() const;
+
+private:
+ friend class IMemory;
+ friend class HeapCache;
+
+ // for debugging in this module
+ static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
+ return gHeapCache->find_heap(binder);
+ }
+ static inline void free_heap(const sp<IBinder>& binder) {
+ gHeapCache->free_heap(binder);
+ }
+ static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) {
+ return gHeapCache->get_heap(binder);
+ }
+ static inline void dump_heaps() {
+ gHeapCache->dump_heaps();
+ }
+ void inline pin_heap() const {
+ gHeapCache->pin_heap(const_cast<BpMemoryHeap*>(this)->asBinder());
+ }
+
+ void assertMapped() const;
+ void assertReallyMapped() const;
+ void pinHeap() const;
+
+ mutable volatile int32_t mHeapId;
+ mutable void* mBase;
+ mutable size_t mSize;
+ mutable uint32_t mFlags;
+ mutable bool mRealHeap;
+ mutable Mutex mLock;
+};
+
+// ----------------------------------------------------------------------------
+
+enum {
+ GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMemory : public BpInterface<IMemory>
+{
+public:
+ BpMemory(const sp<IBinder>& impl);
+ virtual ~BpMemory();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
+
+private:
+ mutable sp<IMemoryHeap> mHeap;
+ mutable ssize_t mOffset;
+ mutable size_t mSize;
+};
+
+/******************************************************************************/
+
+void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const
+{
+ sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder);
+ void* const base = realHeap->base();
+ if (base == MAP_FAILED)
+ return 0;
+ return static_cast<char*>(base) + offset;
+}
+
+void* IMemory::pointer() const {
+ ssize_t offset;
+ sp<IMemoryHeap> heap = getMemory(&offset);
+ void* const base = heap!=0 ? heap->base() : MAP_FAILED;
+ if (base == MAP_FAILED)
+ return 0;
+ return static_cast<char*>(base) + offset;
+}
+
+size_t IMemory::size() const {
+ size_t size;
+ getMemory(NULL, &size);
+ return size;
+}
+
+ssize_t IMemory::offset() const {
+ ssize_t offset;
+ getMemory(&offset);
+ return offset;
+}
+
+/******************************************************************************/
+
+BpMemory::BpMemory(const sp<IBinder>& impl)
+ : BpInterface<IMemory>(impl), mOffset(0), mSize(0)
+{
+}
+
+BpMemory::~BpMemory()
+{
+}
+
+sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
+{
+ if (mHeap == 0) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
+ if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
+ sp<IBinder> heap = reply.readStrongBinder();
+ ssize_t o = reply.readInt32();
+ size_t s = reply.readInt32();
+ if (heap != 0) {
+ mHeap = interface_cast<IMemoryHeap>(heap);
+ if (mHeap != 0) {
+ mOffset = o;
+ mSize = s;
+ }
+ }
+ }
+ }
+ if (offset) *offset = mOffset;
+ if (size) *size = mSize;
+ return mHeap;
+}
+
+// ---------------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
+
+BnMemory::BnMemory() {
+}
+
+BnMemory::~BnMemory() {
+}
+
+status_t BnMemory::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case GET_MEMORY: {
+ CHECK_INTERFACE(IMemory, data, reply);
+ ssize_t offset;
+ size_t size;
+ reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );
+ reply->writeInt32(offset);
+ reply->writeInt32(size);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+
+/******************************************************************************/
+
+BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
+ : BpInterface<IMemoryHeap>(impl),
+ mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
+{
+}
+
+BpMemoryHeap::~BpMemoryHeap() {
+ if (mHeapId != -1) {
+ close(mHeapId);
+ if (mRealHeap) {
+ // by construction we're the last one
+ if (mBase != MAP_FAILED) {
+ sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
+
+ if (VERBOSE) {
+ LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d",
+ binder.get(), this, mSize, mHeapId);
+ CallStack stack;
+ stack.update();
+ stack.dump("callstack");
+ }
+
+ munmap(mBase, mSize);
+ }
+ } else {
+ // remove from list only if it was mapped before
+ sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
+ free_heap(binder);
+ }
+ }
+}
+
+void BpMemoryHeap::assertMapped() const
+{
+ if (mHeapId == -1) {
+ sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());
+ sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
+ heap->assertReallyMapped();
+ if (heap->mBase != MAP_FAILED) {
+ Mutex::Autolock _l(mLock);
+ if (mHeapId == -1) {
+ mBase = heap->mBase;
+ mSize = heap->mSize;
+ android_atomic_write( dup( heap->mHeapId ), &mHeapId );
+ }
+ } else {
+ // something went wrong
+ free_heap(binder);
+ }
+ }
+}
+
+void BpMemoryHeap::assertReallyMapped() const
+{
+ if (mHeapId == -1) {
+
+ // remote call without mLock held, worse case scenario, we end up
+ // calling transact() from multiple threads, but that's not a problem,
+ // only mmap below must be in the critical section.
+
+ Parcel data, reply;
+ data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
+ status_t err = remote()->transact(HEAP_ID, data, &reply);
+ int parcel_fd = reply.readFileDescriptor();
+ ssize_t size = reply.readInt32();
+ uint32_t flags = reply.readInt32();
+
+ 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=%ld, err=%d (%s)",
+ parcel_fd, size, err, strerror(errno));
+
+ int access = PROT_READ;
+ if (!(flags & READ_ONLY)) {
+ access |= PROT_WRITE;
+ }
+
+ Mutex::Autolock _l(mLock);
+ if (mHeapId == -1) {
+ mRealHeap = true;
+ mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
+ if (mBase == MAP_FAILED) {
+ LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",
+ asBinder().get(), size, fd, strerror(errno));
+ close(fd);
+ } else {
+ if (flags & MAP_ONCE) {
+ //LOGD("pinning heap (binder=%p, size=%d, fd=%d",
+ // asBinder().get(), size, fd);
+ pin_heap();
+ }
+ mSize = size;
+ mFlags = flags;
+ android_atomic_write(fd, &mHeapId);
+ }
+ }
+ }
+}
+
+int BpMemoryHeap::getHeapID() const {
+ assertMapped();
+ return mHeapId;
+}
+
+void* BpMemoryHeap::getBase() const {
+ assertMapped();
+ return mBase;
+}
+
+size_t BpMemoryHeap::getSize() const {
+ assertMapped();
+ return mSize;
+}
+
+uint32_t BpMemoryHeap::getFlags() const {
+ assertMapped();
+ return mFlags;
+}
+
+// ---------------------------------------------------------------------------
+
+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)
+{
+ switch(code) {
+ case HEAP_ID: {
+ CHECK_INTERFACE(IMemoryHeap, data, reply);
+ reply->writeFileDescriptor(getHeapID());
+ reply->writeInt32(getSize());
+ reply->writeInt32(getFlags());
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+/*****************************************************************************/
+
+HeapCache::HeapCache()
+ : DeathRecipient()
+{
+}
+
+HeapCache::~HeapCache()
+{
+}
+
+void HeapCache::binderDied(const wp<IBinder>& binder)
+{
+ //LOGD("binderDied binder=%p", binder.unsafe_get());
+ free_heap(binder);
+}
+
+sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
+{
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) {
+ heap_info_t& info = mHeapCache.editValueAt(i);
+ LOGD_IF(VERBOSE,
+ "found binder=%p, heap=%p, size=%d, fd=%d, count=%d",
+ binder.get(), info.heap.get(),
+ static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
+ static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+ info.count);
+ android_atomic_inc(&info.count);
+ return info.heap;
+ } else {
+ heap_info_t info;
+ info.heap = interface_cast<IMemoryHeap>(binder);
+ info.count = 1;
+ //LOGD("adding binder=%p, heap=%p, count=%d",
+ // binder.get(), info.heap.get(), info.count);
+ mHeapCache.add(binder, info);
+ return info.heap;
+ }
+}
+
+void HeapCache::pin_heap(const sp<IBinder>& binder)
+{
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) {
+ heap_info_t& info(mHeapCache.editValueAt(i));
+ android_atomic_inc(&info.count);
+ binder->linkToDeath(this);
+ } else {
+ LOGE("pin_heap binder=%p not found!!!", binder.get());
+ }
+}
+
+void HeapCache::free_heap(const sp<IBinder>& binder) {
+ free_heap( wp<IBinder>(binder) );
+}
+
+void HeapCache::free_heap(const wp<IBinder>& binder)
+{
+ sp<IMemoryHeap> rel;
+ {
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) {
+ heap_info_t& info(mHeapCache.editValueAt(i));
+ int32_t c = android_atomic_dec(&info.count);
+ if (c == 1) {
+ LOGD_IF(VERBOSE,
+ "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d",
+ binder.unsafe_get(), info.heap.get(),
+ static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
+ static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+ info.count);
+ rel = mHeapCache.valueAt(i).heap;
+ mHeapCache.removeItemsAt(i);
+ }
+ } else {
+ LOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
+ }
+ }
+}
+
+sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder)
+{
+ sp<IMemoryHeap> realHeap;
+ Mutex::Autolock _l(mHeapCacheLock);
+ ssize_t i = mHeapCache.indexOfKey(binder);
+ if (i>=0) realHeap = mHeapCache.valueAt(i).heap;
+ else realHeap = interface_cast<IMemoryHeap>(binder);
+ return realHeap;
+}
+
+void HeapCache::dump_heaps()
+{
+ Mutex::Autolock _l(mHeapCacheLock);
+ int c = mHeapCache.size();
+ for (int i=0 ; i<c ; i++) {
+ const heap_info_t& info = mHeapCache.valueAt(i);
+ BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
+ LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)",
+ mHeapCache.keyAt(i).unsafe_get(),
+ info.heap.get(), info.count,
+ h->mHeapId, h->mBase, h->mSize);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
new file mode 100644
index 0000000..c371a23
--- /dev/null
+++ b/libs/binder/IPCThreadState.cpp
@@ -0,0 +1,1025 @@
+/*
+ * 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.
+ */
+
+#include <binder/IPCThreadState.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/binder/binder_module.h>
+#include <private/binder/Static.h>
+
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_WIN32_THREADS
+#include <windows.h>
+#endif
+
+
+#if LOG_NDEBUG
+
+#define IF_LOG_TRANSACTIONS() if (false)
+#define IF_LOG_COMMANDS() if (false)
+#define LOG_REMOTEREFS(...)
+#define IF_LOG_REMOTEREFS() if (false)
+#define LOG_THREADPOOL(...)
+#define LOG_ONEWAY(...)
+
+#else
+
+#define IF_LOG_TRANSACTIONS() IF_LOG(LOG_VERBOSE, "transact")
+#define IF_LOG_COMMANDS() IF_LOG(LOG_VERBOSE, "ipc")
+#define LOG_REMOTEREFS(...) LOG(LOG_DEBUG, "remoterefs", __VA_ARGS__)
+#define IF_LOG_REMOTEREFS() IF_LOG(LOG_DEBUG, "remoterefs")
+#define LOG_THREADPOOL(...) LOG(LOG_DEBUG, "threadpool", __VA_ARGS__)
+#define LOG_ONEWAY(...) LOG(LOG_DEBUG, "ipc", __VA_ARGS__)
+
+#endif
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+static const char* getReturnString(size_t idx);
+static const char* getCommandString(size_t idx);
+static const void* printReturnCommand(TextOutput& out, const void* _cmd);
+static const void* printCommand(TextOutput& out, const void* _cmd);
+
+// This will result in a missing symbol failure if the IF_LOG_COMMANDS()
+// conditionals don't get stripped... but that is probably what we want.
+#if !LOG_NDEBUG
+static const char *kReturnStrings[] = {
+#if 1 /* TODO: error update strings */
+ "unknown",
+#else
+ "BR_OK",
+ "BR_TIMEOUT",
+ "BR_WAKEUP",
+ "BR_TRANSACTION",
+ "BR_REPLY",
+ "BR_ACQUIRE_RESULT",
+ "BR_DEAD_REPLY",
+ "BR_TRANSACTION_COMPLETE",
+ "BR_INCREFS",
+ "BR_ACQUIRE",
+ "BR_RELEASE",
+ "BR_DECREFS",
+ "BR_ATTEMPT_ACQUIRE",
+ "BR_EVENT_OCCURRED",
+ "BR_NOOP",
+ "BR_SPAWN_LOOPER",
+ "BR_FINISHED",
+ "BR_DEAD_BINDER",
+ "BR_CLEAR_DEATH_NOTIFICATION_DONE"
+#endif
+};
+
+static const char *kCommandStrings[] = {
+#if 1 /* TODO: error update strings */
+ "unknown",
+#else
+ "BC_NOOP",
+ "BC_TRANSACTION",
+ "BC_REPLY",
+ "BC_ACQUIRE_RESULT",
+ "BC_FREE_BUFFER",
+ "BC_TRANSACTION_COMPLETE",
+ "BC_INCREFS",
+ "BC_ACQUIRE",
+ "BC_RELEASE",
+ "BC_DECREFS",
+ "BC_INCREFS_DONE",
+ "BC_ACQUIRE_DONE",
+ "BC_ATTEMPT_ACQUIRE",
+ "BC_RETRIEVE_ROOT_OBJECT",
+ "BC_SET_THREAD_ENTRY",
+ "BC_REGISTER_LOOPER",
+ "BC_ENTER_LOOPER",
+ "BC_EXIT_LOOPER",
+ "BC_SYNC",
+ "BC_STOP_PROCESS",
+ "BC_STOP_SELF",
+ "BC_REQUEST_DEATH_NOTIFICATION",
+ "BC_CLEAR_DEATH_NOTIFICATION",
+ "BC_DEAD_BINDER_DONE"
+#endif
+};
+
+static const char* getReturnString(size_t idx)
+{
+ if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0]))
+ return kReturnStrings[idx];
+ else
+ return "unknown";
+}
+
+static const char* getCommandString(size_t idx)
+{
+ if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[0]))
+ return kCommandStrings[idx];
+ else
+ return "unknown";
+}
+
+static const void* printBinderTransactionData(TextOutput& out, const void* data)
+{
+ const binder_transaction_data* btd =
+ (const binder_transaction_data*)data;
+ out << "target=" << btd->target.ptr << " (cookie " << btd->cookie << ")" << endl
+ << "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl
+ << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
+ << " bytes)" << endl
+ << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
+ << " bytes)" << endl;
+ return btd+1;
+}
+
+static const void* printReturnCommand(TextOutput& out, const void* _cmd)
+{
+ static const int32_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
+
+ const int32_t* cmd = (const int32_t*)_cmd;
+ int32_t code = *cmd++;
+ if (code == BR_ERROR) {
+ out << "BR_ERROR: " << (void*)(*cmd++) << endl;
+ return cmd;
+ } else if (code < 0 || code >= N) {
+ out << "Unknown reply: " << code << endl;
+ return cmd;
+ }
+
+ out << kReturnStrings[code];
+ switch (code) {
+ case BR_TRANSACTION:
+ case BR_REPLY: {
+ out << ": " << indent;
+ cmd = (const int32_t *)printBinderTransactionData(out, cmd);
+ out << dedent;
+ } break;
+
+ case BR_ACQUIRE_RESULT: {
+ const int32_t res = *cmd++;
+ out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
+ } break;
+
+ case BR_INCREFS:
+ case BR_ACQUIRE:
+ case BR_RELEASE:
+ case BR_DECREFS: {
+ const int32_t b = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
+ } break;
+
+ case BR_ATTEMPT_ACQUIRE: {
+ const int32_t p = *cmd++;
+ const int32_t b = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": target=" << (void*)b << " (cookie " << (void*)c
+ << "), pri=" << p;
+ } break;
+
+ case BR_DEAD_BINDER:
+ case BR_CLEAR_DEATH_NOTIFICATION_DONE: {
+ const int32_t c = *cmd++;
+ out << ": death cookie " << (void*)c;
+ } break;
+ }
+
+ out << endl;
+ return cmd;
+}
+
+static const void* printCommand(TextOutput& out, const void* _cmd)
+{
+ static const int32_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
+
+ const int32_t* cmd = (const int32_t*)_cmd;
+ int32_t code = *cmd++;
+ if (code < 0 || code >= N) {
+ out << "Unknown command: " << code << endl;
+ return cmd;
+ }
+
+ out << kCommandStrings[code];
+ switch (code) {
+ case BC_TRANSACTION:
+ case BC_REPLY: {
+ out << ": " << indent;
+ cmd = (const int32_t *)printBinderTransactionData(out, cmd);
+ out << dedent;
+ } break;
+
+ case BC_ACQUIRE_RESULT: {
+ const int32_t res = *cmd++;
+ out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
+ } break;
+
+ case BC_FREE_BUFFER: {
+ const int32_t buf = *cmd++;
+ out << ": buffer=" << (void*)buf;
+ } break;
+
+ case BC_INCREFS:
+ case BC_ACQUIRE:
+ case BC_RELEASE:
+ case BC_DECREFS: {
+ const int32_t d = *cmd++;
+ out << ": descriptor=" << (void*)d;
+ } break;
+
+ case BC_INCREFS_DONE:
+ case BC_ACQUIRE_DONE: {
+ const int32_t b = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
+ } break;
+
+ case BC_ATTEMPT_ACQUIRE: {
+ const int32_t p = *cmd++;
+ const int32_t d = *cmd++;
+ out << ": decriptor=" << (void*)d << ", pri=" << p;
+ } break;
+
+ case BC_REQUEST_DEATH_NOTIFICATION:
+ case BC_CLEAR_DEATH_NOTIFICATION: {
+ const int32_t h = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": handle=" << h << " (death cookie " << (void*)c << ")";
+ } break;
+
+ case BC_DEAD_BINDER_DONE: {
+ const int32_t c = *cmd++;
+ out << ": death cookie " << (void*)c;
+ } break;
+ }
+
+ out << endl;
+ return cmd;
+}
+#endif
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+static bool gShutdown = false;
+
+IPCThreadState* IPCThreadState::self()
+{
+ if (gHaveTLS) {
+restart:
+ const pthread_key_t k = gTLS;
+ IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
+ if (st) return st;
+ return new IPCThreadState;
+ }
+
+ if (gShutdown) return NULL;
+
+ pthread_mutex_lock(&gTLSMutex);
+ if (!gHaveTLS) {
+ if (pthread_key_create(&gTLS, threadDestructor) != 0) {
+ pthread_mutex_unlock(&gTLSMutex);
+ return NULL;
+ }
+ gHaveTLS = true;
+ }
+ pthread_mutex_unlock(&gTLSMutex);
+ goto restart;
+}
+
+void IPCThreadState::shutdown()
+{
+ gShutdown = true;
+
+ if (gHaveTLS) {
+ // XXX Need to wait for all thread pool threads to exit!
+ IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
+ if (st) {
+ delete st;
+ pthread_setspecific(gTLS, NULL);
+ }
+ gHaveTLS = false;
+ }
+}
+
+sp<ProcessState> IPCThreadState::process()
+{
+ return mProcess;
+}
+
+status_t IPCThreadState::clearLastError()
+{
+ const status_t err = mLastError;
+ mLastError = NO_ERROR;
+ return err;
+}
+
+int IPCThreadState::getCallingPid()
+{
+ return mCallingPid;
+}
+
+int IPCThreadState::getCallingUid()
+{
+ return mCallingUid;
+}
+
+int64_t IPCThreadState::clearCallingIdentity()
+{
+ int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
+ clearCaller();
+ return token;
+}
+
+void IPCThreadState::restoreCallingIdentity(int64_t token)
+{
+ mCallingUid = (int)(token>>32);
+ mCallingPid = (int)token;
+}
+
+void IPCThreadState::clearCaller()
+{
+ mCallingPid = getpid();
+ mCallingUid = getuid();
+}
+
+void IPCThreadState::flushCommands()
+{
+ if (mProcess->mDriverFD <= 0)
+ return;
+ talkWithDriver(false);
+}
+
+void IPCThreadState::joinThreadPool(bool isMain)
+{
+ LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
+
+ mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
+
+ status_t result;
+ do {
+ int32_t cmd;
+
+ // When we've cleared the incoming command queue, process any pending derefs
+ if (mIn.dataPosition() >= mIn.dataSize()) {
+ size_t numPending = mPendingWeakDerefs.size();
+ if (numPending > 0) {
+ for (size_t i = 0; i < numPending; i++) {
+ RefBase::weakref_type* refs = mPendingWeakDerefs[i];
+ refs->decWeak(mProcess.get());
+ }
+ mPendingWeakDerefs.clear();
+ }
+
+ numPending = mPendingStrongDerefs.size();
+ if (numPending > 0) {
+ for (size_t i = 0; i < numPending; i++) {
+ BBinder* obj = mPendingStrongDerefs[i];
+ obj->decStrong(mProcess.get());
+ }
+ mPendingStrongDerefs.clear();
+ }
+ }
+
+ // now get the next command to be processed, waiting if necessary
+ result = talkWithDriver();
+ if (result >= NO_ERROR) {
+ size_t IN = mIn.dataAvail();
+ if (IN < sizeof(int32_t)) continue;
+ cmd = mIn.readInt32();
+ IF_LOG_COMMANDS() {
+ alog << "Processing top-level Command: "
+ << getReturnString(cmd) << endl;
+ }
+ result = executeCommand(cmd);
+ }
+
+ // Let this thread exit the thread pool if it is no longer
+ // needed and it is not the main process thread.
+ if(result == TIMED_OUT && !isMain) {
+ break;
+ }
+ } while (result != -ECONNREFUSED && result != -EBADF);
+
+ LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
+ (void*)pthread_self(), getpid(), (void*)result);
+
+ mOut.writeInt32(BC_EXIT_LOOPER);
+ talkWithDriver(false);
+}
+
+void IPCThreadState::stopProcess(bool immediate)
+{
+ //LOGI("**** STOPPING PROCESS");
+ flushCommands();
+ int fd = mProcess->mDriverFD;
+ mProcess->mDriverFD = -1;
+ close(fd);
+ //kill(getpid(), SIGKILL);
+}
+
+status_t IPCThreadState::transact(int32_t handle,
+ uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags)
+{
+ status_t err = data.errorCheck();
+
+ flags |= TF_ACCEPT_FDS;
+
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
+ << handle << " / code " << TypeCode(code) << ": "
+ << indent << data << dedent << endl;
+ }
+
+ if (err == NO_ERROR) {
+ LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
+ (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
+ err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
+ }
+
+ if (err != NO_ERROR) {
+ if (reply) reply->setError(err);
+ return (mLastError = err);
+ }
+
+ if ((flags & TF_ONE_WAY) == 0) {
+ if (reply) {
+ err = waitForResponse(reply);
+ } else {
+ Parcel fakeReply;
+ err = waitForResponse(&fakeReply);
+ }
+
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
+ << handle << ": ";
+ if (reply) alog << indent << *reply << dedent << endl;
+ else alog << "(none requested)" << endl;
+ }
+ } else {
+ err = waitForResponse(NULL, NULL);
+ }
+
+ return err;
+}
+
+void IPCThreadState::incStrongHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
+ mOut.writeInt32(BC_ACQUIRE);
+ mOut.writeInt32(handle);
+}
+
+void IPCThreadState::decStrongHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle);
+ mOut.writeInt32(BC_RELEASE);
+ mOut.writeInt32(handle);
+}
+
+void IPCThreadState::incWeakHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
+ mOut.writeInt32(BC_INCREFS);
+ mOut.writeInt32(handle);
+}
+
+void IPCThreadState::decWeakHandle(int32_t handle)
+{
+ LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
+ mOut.writeInt32(BC_DECREFS);
+ mOut.writeInt32(handle);
+}
+
+status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
+{
+ mOut.writeInt32(BC_ATTEMPT_ACQUIRE);
+ mOut.writeInt32(0); // xxx was thread priority
+ mOut.writeInt32(handle);
+ status_t result = UNKNOWN_ERROR;
+
+ waitForResponse(NULL, &result);
+
+#if LOG_REFCOUNTS
+ printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
+ handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
+#endif
+
+ return result;
+}
+
+void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder)
+{
+#if LOG_REFCOUNTS
+ printf("IPCThreadState::expungeHandle(%ld)\n", handle);
+#endif
+ self()->mProcess->expungeHandle(handle, binder);
+}
+
+status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
+{
+ mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
+ mOut.writeInt32((int32_t)handle);
+ mOut.writeInt32((int32_t)proxy);
+ return NO_ERROR;
+}
+
+status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
+{
+ mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION);
+ mOut.writeInt32((int32_t)handle);
+ mOut.writeInt32((int32_t)proxy);
+ return NO_ERROR;
+}
+
+IPCThreadState::IPCThreadState()
+ : mProcess(ProcessState::self())
+{
+ pthread_setspecific(gTLS, this);
+ clearCaller();
+ mIn.setDataCapacity(256);
+ mOut.setDataCapacity(256);
+}
+
+IPCThreadState::~IPCThreadState()
+{
+}
+
+status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
+{
+ status_t err;
+ status_t statusBuffer;
+ err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
+ if (err < NO_ERROR) return err;
+
+ return waitForResponse(NULL, NULL);
+}
+
+status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
+{
+ int32_t cmd;
+ int32_t err;
+
+ while (1) {
+ if ((err=talkWithDriver()) < NO_ERROR) break;
+ err = mIn.errorCheck();
+ if (err < NO_ERROR) break;
+ if (mIn.dataAvail() == 0) continue;
+
+ cmd = mIn.readInt32();
+
+ IF_LOG_COMMANDS() {
+ alog << "Processing waitForResponse Command: "
+ << getReturnString(cmd) << endl;
+ }
+
+ switch (cmd) {
+ case BR_TRANSACTION_COMPLETE:
+ if (!reply && !acquireResult) goto finish;
+ break;
+
+ case BR_DEAD_REPLY:
+ err = DEAD_OBJECT;
+ goto finish;
+
+ case BR_FAILED_REPLY:
+ err = FAILED_TRANSACTION;
+ goto finish;
+
+ case BR_ACQUIRE_RESULT:
+ {
+ LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
+ const int32_t result = mIn.readInt32();
+ if (!acquireResult) continue;
+ *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
+ }
+ goto finish;
+
+ case BR_REPLY:
+ {
+ binder_transaction_data tr;
+ err = mIn.read(&tr, sizeof(tr));
+ LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
+ if (err != NO_ERROR) goto finish;
+
+ if (reply) {
+ if ((tr.flags & TF_STATUS_CODE) == 0) {
+ reply->ipcSetDataReference(
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t),
+ freeBuffer, this);
+ } else {
+ err = *static_cast<const status_t*>(tr.data.ptr.buffer);
+ freeBuffer(NULL,
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t), this);
+ }
+ } else {
+ freeBuffer(NULL,
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t), this);
+ continue;
+ }
+ }
+ goto finish;
+
+ default:
+ err = executeCommand(cmd);
+ if (err != NO_ERROR) goto finish;
+ break;
+ }
+ }
+
+finish:
+ if (err != NO_ERROR) {
+ if (acquireResult) *acquireResult = err;
+ if (reply) reply->setError(err);
+ mLastError = err;
+ }
+
+ return err;
+}
+
+status_t IPCThreadState::talkWithDriver(bool doReceive)
+{
+ LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
+
+ binder_write_read bwr;
+
+ // Is the read buffer empty?
+ const bool needRead = mIn.dataPosition() >= mIn.dataSize();
+
+ // We don't want to write anything if we are still reading
+ // from data left in the input buffer and the caller
+ // has requested to read the next data.
+ const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
+
+ bwr.write_size = outAvail;
+ bwr.write_buffer = (long unsigned int)mOut.data();
+
+ // This is what we'll read.
+ if (doReceive && needRead) {
+ bwr.read_size = mIn.dataCapacity();
+ bwr.read_buffer = (long unsigned int)mIn.data();
+ } else {
+ bwr.read_size = 0;
+ }
+
+ IF_LOG_COMMANDS() {
+ TextOutput::Bundle _b(alog);
+ if (outAvail != 0) {
+ alog << "Sending commands to driver: " << indent;
+ const void* cmds = (const void*)bwr.write_buffer;
+ const void* end = ((const uint8_t*)cmds)+bwr.write_size;
+ alog << HexDump(cmds, bwr.write_size) << endl;
+ while (cmds < end) cmds = printCommand(alog, cmds);
+ alog << dedent;
+ }
+ alog << "Size of receive buffer: " << bwr.read_size
+ << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
+ }
+
+ // Return immediately if there is nothing to do.
+ if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
+
+ bwr.write_consumed = 0;
+ bwr.read_consumed = 0;
+ status_t err;
+ do {
+ IF_LOG_COMMANDS() {
+ alog << "About to read/write, write size = " << mOut.dataSize() << endl;
+ }
+#if defined(HAVE_ANDROID_OS)
+ if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
+ err = NO_ERROR;
+ else
+ err = -errno;
+#else
+ err = INVALID_OPERATION;
+#endif
+ IF_LOG_COMMANDS() {
+ alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
+ }
+ } while (err == -EINTR);
+
+ IF_LOG_COMMANDS() {
+ alog << "Our err: " << (void*)err << ", write consumed: "
+ << bwr.write_consumed << " (of " << mOut.dataSize()
+ << "), read consumed: " << bwr.read_consumed << endl;
+ }
+
+ if (err >= NO_ERROR) {
+ if (bwr.write_consumed > 0) {
+ if (bwr.write_consumed < (ssize_t)mOut.dataSize())
+ mOut.remove(0, bwr.write_consumed);
+ else
+ mOut.setDataSize(0);
+ }
+ if (bwr.read_consumed > 0) {
+ mIn.setDataSize(bwr.read_consumed);
+ mIn.setDataPosition(0);
+ }
+ IF_LOG_COMMANDS() {
+ TextOutput::Bundle _b(alog);
+ alog << "Remaining data size: " << mOut.dataSize() << endl;
+ alog << "Received commands from driver: " << indent;
+ const void* cmds = mIn.data();
+ const void* end = mIn.data() + mIn.dataSize();
+ alog << HexDump(cmds, mIn.dataSize()) << endl;
+ while (cmds < end) cmds = printReturnCommand(alog, cmds);
+ alog << dedent;
+ }
+ return NO_ERROR;
+ }
+
+ return err;
+}
+
+status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
+ int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
+{
+ binder_transaction_data tr;
+
+ tr.target.handle = handle;
+ tr.code = code;
+ tr.flags = binderFlags;
+
+ const status_t err = data.errorCheck();
+ if (err == NO_ERROR) {
+ tr.data_size = data.ipcDataSize();
+ tr.data.ptr.buffer = data.ipcData();
+ tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
+ tr.data.ptr.offsets = data.ipcObjects();
+ } else if (statusBuffer) {
+ tr.flags |= TF_STATUS_CODE;
+ *statusBuffer = err;
+ tr.data_size = sizeof(status_t);
+ tr.data.ptr.buffer = statusBuffer;
+ tr.offsets_size = 0;
+ tr.data.ptr.offsets = NULL;
+ } else {
+ return (mLastError = err);
+ }
+
+ mOut.writeInt32(cmd);
+ mOut.write(&tr, sizeof(tr));
+
+ return NO_ERROR;
+}
+
+sp<BBinder> the_context_object;
+
+void setTheContextObject(sp<BBinder> obj)
+{
+ the_context_object = obj;
+}
+
+status_t IPCThreadState::executeCommand(int32_t cmd)
+{
+ BBinder* obj;
+ RefBase::weakref_type* refs;
+ status_t result = NO_ERROR;
+
+ switch (cmd) {
+ case BR_ERROR:
+ result = mIn.readInt32();
+ break;
+
+ case BR_OK:
+ break;
+
+ case BR_ACQUIRE:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ LOG_ASSERT(refs->refBase() == obj,
+ "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
+ refs, obj, refs->refBase());
+ obj->incStrong(mProcess.get());
+ IF_LOG_REMOTEREFS() {
+ LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
+ obj->printRefs();
+ }
+ mOut.writeInt32(BC_ACQUIRE_DONE);
+ mOut.writeInt32((int32_t)refs);
+ mOut.writeInt32((int32_t)obj);
+ break;
+
+ case BR_RELEASE:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ LOG_ASSERT(refs->refBase() == obj,
+ "BR_RELEASE: object %p does not match cookie %p (expected %p)",
+ refs, obj, refs->refBase());
+ IF_LOG_REMOTEREFS() {
+ LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
+ obj->printRefs();
+ }
+ mPendingStrongDerefs.push(obj);
+ break;
+
+ case BR_INCREFS:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ refs->incWeak(mProcess.get());
+ mOut.writeInt32(BC_INCREFS_DONE);
+ mOut.writeInt32((int32_t)refs);
+ mOut.writeInt32((int32_t)obj);
+ break;
+
+ case BR_DECREFS:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+ // NOTE: This assertion is not valid, because the object may no
+ // longer exist (thus the (BBinder*)cast above resulting in a different
+ // memory address).
+ //LOG_ASSERT(refs->refBase() == obj,
+ // "BR_DECREFS: object %p does not match cookie %p (expected %p)",
+ // refs, obj, refs->refBase());
+ mPendingWeakDerefs.push(refs);
+ break;
+
+ case BR_ATTEMPT_ACQUIRE:
+ refs = (RefBase::weakref_type*)mIn.readInt32();
+ obj = (BBinder*)mIn.readInt32();
+
+ {
+ const bool success = refs->attemptIncStrong(mProcess.get());
+ LOG_ASSERT(success && refs->refBase() == obj,
+ "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
+ refs, obj, refs->refBase());
+
+ mOut.writeInt32(BC_ACQUIRE_RESULT);
+ mOut.writeInt32((int32_t)success);
+ }
+ break;
+
+ case BR_TRANSACTION:
+ {
+ binder_transaction_data tr;
+ result = mIn.read(&tr, sizeof(tr));
+ LOG_ASSERT(result == NO_ERROR,
+ "Not enough command data for brTRANSACTION");
+ if (result != NO_ERROR) break;
+
+ Parcel buffer;
+ buffer.ipcSetDataReference(
+ reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+ tr.data_size,
+ reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
+ tr.offsets_size/sizeof(size_t), freeBuffer, this);
+
+ const pid_t origPid = mCallingPid;
+ const uid_t origUid = mCallingUid;
+
+ mCallingPid = tr.sender_pid;
+ mCallingUid = tr.sender_euid;
+
+ //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
+
+ Parcel reply;
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BR_TRANSACTION thr " << (void*)pthread_self()
+ << " / obj " << tr.target.ptr << " / code "
+ << TypeCode(tr.code) << ": " << indent << buffer
+ << dedent << endl
+ << "Data addr = "
+ << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
+ << ", offsets addr="
+ << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
+ }
+ if (tr.target.ptr) {
+ sp<BBinder> b((BBinder*)tr.cookie);
+ const status_t error = b->transact(tr.code, buffer, &reply, 0);
+ if (error < NO_ERROR) reply.setError(error);
+
+ } else {
+ const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);
+ if (error < NO_ERROR) reply.setError(error);
+ }
+
+ //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
+ // mCallingPid, origPid, origUid);
+
+ if ((tr.flags & TF_ONE_WAY) == 0) {
+ LOG_ONEWAY("Sending reply to %d!", mCallingPid);
+ sendReply(reply, 0);
+ } else {
+ LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
+ }
+
+ mCallingPid = origPid;
+ mCallingUid = origUid;
+
+ IF_LOG_TRANSACTIONS() {
+ TextOutput::Bundle _b(alog);
+ alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
+ << tr.target.ptr << ": " << indent << reply << dedent << endl;
+ }
+
+ }
+ break;
+
+ case BR_DEAD_BINDER:
+ {
+ BpBinder *proxy = (BpBinder*)mIn.readInt32();
+ proxy->sendObituary();
+ mOut.writeInt32(BC_DEAD_BINDER_DONE);
+ mOut.writeInt32((int32_t)proxy);
+ } break;
+
+ case BR_CLEAR_DEATH_NOTIFICATION_DONE:
+ {
+ BpBinder *proxy = (BpBinder*)mIn.readInt32();
+ proxy->getWeakRefs()->decWeak(proxy);
+ } break;
+
+ case BR_FINISHED:
+ result = TIMED_OUT;
+ break;
+
+ case BR_NOOP:
+ break;
+
+ case BR_SPAWN_LOOPER:
+ mProcess->spawnPooledThread(false);
+ break;
+
+ default:
+ printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
+ result = UNKNOWN_ERROR;
+ break;
+ }
+
+ if (result != NO_ERROR) {
+ mLastError = result;
+ }
+
+ return result;
+}
+
+void IPCThreadState::threadDestructor(void *st)
+{
+ IPCThreadState* const self = static_cast<IPCThreadState*>(st);
+ if (self) {
+ self->flushCommands();
+#if defined(HAVE_ANDROID_OS)
+ ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
+#endif
+ delete self;
+ }
+}
+
+
+void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsSize,
+ void* cookie)
+{
+ //LOGI("Freeing parcel %p", &parcel);
+ IF_LOG_COMMANDS() {
+ alog << "Writing BC_FREE_BUFFER for " << data << endl;
+ }
+ LOG_ASSERT(data != NULL, "Called with NULL data");
+ if (parcel != NULL) parcel->closeFileDescriptors();
+ IPCThreadState* state = self();
+ state->mOut.writeInt32(BC_FREE_BUFFER);
+ state->mOut.writeInt32((int32_t)data);
+}
+
+}; // namespace android
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
new file mode 100644
index 0000000..bff4c9b
--- /dev/null
+++ b/libs/binder/IPermissionController.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PermissionController"
+
+#include <binder/IPermissionController.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+
+#include <private/binder/Static.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BpPermissionController : public BpInterface<IPermissionController>
+{
+public:
+ BpPermissionController(const sp<IBinder>& impl)
+ : BpInterface<IPermissionController>(impl)
+ {
+ }
+
+ virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+ data.writeString16(permission);
+ data.writeInt32(pid);
+ data.writeInt32(uid);
+ remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readInt32() != 0) return 0;
+ return reply.readInt32() != 0;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
+
+// ----------------------------------------------------------------------
+
+status_t BnPermissionController::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ //printf("PermissionController received: "); data.print();
+ switch(code) {
+ case CHECK_PERMISSION_TRANSACTION: {
+ CHECK_INTERFACE(IPermissionController, data, reply);
+ String16 permission = data.readString16();
+ int32_t pid = data.readInt32();
+ int32_t uid = data.readInt32();
+ bool res = checkPermission(permission, pid, uid);
+ // write exception
+ reply->writeInt32(0);
+ reply->writeInt32(res ? 1 : 0);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
new file mode 100644
index 0000000..0cf4158
--- /dev/null
+++ b/libs/binder/IServiceManager.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ServiceManager"
+
+#include <binder/IServiceManager.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+#include <utils/SystemClock.h>
+
+#include <private/binder/Static.h>
+
+#include <unistd.h>
+
+namespace android {
+
+sp<IServiceManager> defaultServiceManager()
+{
+ if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
+
+ {
+ AutoMutex _l(gDefaultServiceManagerLock);
+ if (gDefaultServiceManager == NULL) {
+ gDefaultServiceManager = interface_cast<IServiceManager>(
+ ProcessState::self()->getContextObject(NULL));
+ }
+ }
+
+ return gDefaultServiceManager;
+}
+
+bool checkCallingPermission(const String16& permission)
+{
+ return checkCallingPermission(permission, NULL, NULL);
+}
+
+static String16 _permission("permission");
+
+
+bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
+{
+ IPCThreadState* ipcState = IPCThreadState::self();
+ pid_t pid = ipcState->getCallingPid();
+ uid_t uid = ipcState->getCallingUid();
+ if (outPid) *outPid = pid;
+ if (outUid) *outUid = uid;
+ return checkPermission(permission, pid, uid);
+}
+
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
+{
+ sp<IPermissionController> pc;
+ gDefaultServiceManagerLock.lock();
+ pc = gPermissionController;
+ gDefaultServiceManagerLock.unlock();
+
+ int64_t startTime = 0;
+
+ while (true) {
+ if (pc != NULL) {
+ bool res = pc->checkPermission(permission, pid, uid);
+ if (res) {
+ if (startTime != 0) {
+ LOGI("Check passed after %d seconds for %s from uid=%d pid=%d",
+ (int)((uptimeMillis()-startTime)/1000),
+ String8(permission).string(), uid, pid);
+ }
+ return res;
+ }
+
+ // Is this a permission failure, or did the controller go away?
+ if (pc->asBinder()->isBinderAlive()) {
+ LOGW("Permission failure: %s from uid=%d pid=%d",
+ String8(permission).string(), uid, pid);
+ return false;
+ }
+
+ // Object is dead!
+ gDefaultServiceManagerLock.lock();
+ if (gPermissionController == pc) {
+ gPermissionController = NULL;
+ }
+ gDefaultServiceManagerLock.unlock();
+ }
+
+ // Need to retrieve the permission controller.
+ sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
+ if (binder == NULL) {
+ // Wait for the permission controller to come back...
+ if (startTime == 0) {
+ startTime = uptimeMillis();
+ LOGI("Waiting to check permission %s from uid=%d pid=%d",
+ String8(permission).string(), uid, pid);
+ }
+ sleep(1);
+ } else {
+ pc = interface_cast<IPermissionController>(binder);
+ // Install the new permission controller, and try again.
+ gDefaultServiceManagerLock.lock();
+ gPermissionController = pc;
+ gDefaultServiceManagerLock.unlock();
+ }
+ }
+}
+
+// ----------------------------------------------------------------------
+
+class BpServiceManager : public BpInterface<IServiceManager>
+{
+public:
+ BpServiceManager(const sp<IBinder>& impl)
+ : BpInterface<IServiceManager>(impl)
+ {
+ }
+
+ virtual sp<IBinder> getService(const String16& name) const
+ {
+ unsigned n;
+ for (n = 0; n < 5; n++){
+ sp<IBinder> svc = checkService(name);
+ if (svc != NULL) return svc;
+ LOGI("Waiting for sevice %s...\n", String8(name).string());
+ sleep(1);
+ }
+ return NULL;
+ }
+
+ virtual sp<IBinder> checkService( const String16& name) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+ data.writeString16(name);
+ remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
+ return reply.readStrongBinder();
+ }
+
+ virtual status_t addService(const String16& name, const sp<IBinder>& service)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+ data.writeString16(name);
+ data.writeStrongBinder(service);
+ status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
+ return err == NO_ERROR ? reply.readInt32() : err;
+ }
+
+ virtual Vector<String16> listServices()
+ {
+ Vector<String16> res;
+ int n = 0;
+
+ for (;;) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
+ data.writeInt32(n++);
+ status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
+ if (err != NO_ERROR)
+ break;
+ res.add(reply.readString16());
+ }
+ return res;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
+
+// ----------------------------------------------------------------------
+
+status_t BnServiceManager::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ //printf("ServiceManager received: "); data.print();
+ switch(code) {
+ case GET_SERVICE_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ String16 which = data.readString16();
+ sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which);
+ reply->writeStrongBinder(b);
+ return NO_ERROR;
+ } break;
+ case CHECK_SERVICE_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ String16 which = data.readString16();
+ sp<IBinder> b = const_cast<BnServiceManager*>(this)->checkService(which);
+ reply->writeStrongBinder(b);
+ return NO_ERROR;
+ } break;
+ case ADD_SERVICE_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ String16 which = data.readString16();
+ sp<IBinder> b = data.readStrongBinder();
+ status_t err = addService(which, b);
+ reply->writeInt32(err);
+ return NO_ERROR;
+ } break;
+ case LIST_SERVICES_TRANSACTION: {
+ CHECK_INTERFACE(IServiceManager, data, reply);
+ Vector<String16> list = listServices();
+ const size_t N = list.size();
+ reply->writeInt32(N);
+ for (size_t i=0; i<N; i++) {
+ reply->writeString16(list[i]);
+ }
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/libs/binder/MemoryBase.cpp b/libs/binder/MemoryBase.cpp
new file mode 100644
index 0000000..033066b
--- /dev/null
+++ b/libs/binder/MemoryBase.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 <stdlib.h>
+#include <stdint.h>
+
+#include <binder/MemoryBase.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap,
+ ssize_t offset, size_t size)
+ : mSize(size), mOffset(offset), mHeap(heap)
+{
+}
+
+sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const
+{
+ if (offset) *offset = mOffset;
+ if (size) *size = mSize;
+ return mHeap;
+}
+
+MemoryBase::~MemoryBase()
+{
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
new file mode 100644
index 0000000..d5ffe7f
--- /dev/null
+++ b/libs/binder/MemoryDealer.cpp
@@ -0,0 +1,421 @@
+/*
+ * 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 "MemoryDealer"
+
+#include <binder/MemoryDealer.h>
+
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <binder/MemoryBase.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+HeapInterface::HeapInterface() { }
+HeapInterface::~HeapInterface() { }
+
+// ----------------------------------------------------------------------------
+
+AllocatorInterface::AllocatorInterface() { }
+AllocatorInterface::~AllocatorInterface() { }
+
+// ----------------------------------------------------------------------------
+
+class SimpleMemory : public MemoryBase {
+public:
+ SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
+ virtual ~SimpleMemory();
+};
+
+
+// ----------------------------------------------------------------------------
+
+MemoryDealer::Allocation::Allocation(
+ const sp<MemoryDealer>& dealer, ssize_t offset, size_t size,
+ const sp<IMemory>& memory)
+ : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory)
+{
+}
+
+MemoryDealer::Allocation::~Allocation()
+{
+ if (mSize) {
+ /* 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 allocator
+ * and could alias some real allocation (their offset is zero). */
+ mDealer->deallocate(mOffset);
+ }
+}
+
+sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
+ ssize_t* offset, size_t* size) const
+{
+ return mMemory->getMemory(offset, size);
+}
+
+// ----------------------------------------------------------------------------
+
+MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name)
+ : mHeap(new SharedHeap(size, flags, name)),
+ mAllocator(new SimpleBestFitAllocator(size))
+{
+}
+
+MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap)
+ : mHeap(heap),
+ mAllocator(new SimpleBestFitAllocator(heap->virtualSize()))
+{
+}
+
+MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap,
+ const sp<AllocatorInterface>& allocator)
+ : mHeap(heap), mAllocator(allocator)
+{
+}
+
+MemoryDealer::~MemoryDealer()
+{
+}
+
+sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
+{
+ sp<IMemory> memory;
+ const ssize_t offset = allocator()->allocate(size, flags);
+ if (offset >= 0) {
+ sp<IMemory> new_memory = heap()->mapMemory(offset, size);
+ if (new_memory != 0) {
+ memory = new Allocation(this, offset, size, new_memory);
+ } else {
+ 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
+ * allocator and could alias some real allocation
+ * (their offset is zero). */
+ allocator()->deallocate(offset);
+ }
+ }
+ }
+ return memory;
+}
+
+void MemoryDealer::deallocate(size_t offset)
+{
+ allocator()->deallocate(offset);
+}
+
+void MemoryDealer::dump(const char* what, uint32_t flags) const
+{
+ allocator()->dump(what, flags);
+}
+
+const sp<HeapInterface>& MemoryDealer::heap() const {
+ return mHeap;
+}
+
+const sp<AllocatorInterface>& MemoryDealer::allocator() const {
+ return mAllocator;
+}
+
+// ----------------------------------------------------------------------------
+
+// align all the memory blocks on a cache-line boundary
+const int SimpleBestFitAllocator::kMemoryAlign = 32;
+
+SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
+{
+ size_t pagesize = getpagesize();
+ mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
+
+ chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
+ mList.insertHead(node);
+}
+
+SimpleBestFitAllocator::~SimpleBestFitAllocator()
+{
+ while(!mList.isEmpty()) {
+ delete mList.remove(mList.head());
+ }
+}
+
+size_t SimpleBestFitAllocator::size() const
+{
+ return mHeapSize;
+}
+
+size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
+{
+ Mutex::Autolock _l(mLock);
+ ssize_t offset = alloc(size, flags);
+ return offset;
+}
+
+status_t SimpleBestFitAllocator::deallocate(size_t offset)
+{
+ Mutex::Autolock _l(mLock);
+ chunk_t const * const freed = dealloc(offset);
+ if (freed) {
+ return NO_ERROR;
+ }
+ return NAME_NOT_FOUND;
+}
+
+ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
+{
+ if (size == 0) {
+ return 0;
+ }
+ size = (size + kMemoryAlign-1) / kMemoryAlign;
+ chunk_t* free_chunk = 0;
+ chunk_t* cur = mList.head();
+
+ size_t pagesize = getpagesize();
+ while (cur) {
+ int extra = 0;
+ if (flags & PAGE_ALIGNED)
+ extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
+
+ // best fit
+ if (cur->free && (cur->size >= (size+extra))) {
+ if ((!free_chunk) || (cur->size < free_chunk->size)) {
+ free_chunk = cur;
+ }
+ if (cur->size == size) {
+ break;
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (free_chunk) {
+ const size_t free_size = free_chunk->size;
+ free_chunk->free = 0;
+ free_chunk->size = size;
+ if (free_size > size) {
+ int extra = 0;
+ if (flags & PAGE_ALIGNED)
+ extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
+ if (extra) {
+ chunk_t* split = new chunk_t(free_chunk->start, extra);
+ free_chunk->start += extra;
+ mList.insertBefore(free_chunk, split);
+ }
+
+ LOGE_IF((flags&PAGE_ALIGNED) &&
+ ((free_chunk->start*kMemoryAlign)&(pagesize-1)),
+ "PAGE_ALIGNED requested, but page is not aligned!!!");
+
+ const ssize_t tail_free = free_size - (size+extra);
+ if (tail_free > 0) {
+ chunk_t* split = new chunk_t(
+ free_chunk->start + free_chunk->size, tail_free);
+ mList.insertAfter(free_chunk, split);
+ }
+ }
+ return (free_chunk->start)*kMemoryAlign;
+ }
+ return NO_MEMORY;
+}
+
+SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
+{
+ start = start / kMemoryAlign;
+ chunk_t* cur = mList.head();
+ while (cur) {
+ if (cur->start == start) {
+ LOG_FATAL_IF(cur->free,
+ "block at offset 0x%08lX of size 0x%08lX already freed",
+ cur->start*kMemoryAlign, cur->size*kMemoryAlign);
+
+ // merge freed blocks together
+ chunk_t* freed = cur;
+ cur->free = 1;
+ do {
+ chunk_t* const p = cur->prev;
+ chunk_t* const n = cur->next;
+ if (p && (p->free || !cur->size)) {
+ freed = p;
+ p->size += cur->size;
+ mList.remove(cur);
+ delete cur;
+ }
+ cur = n;
+ } while (cur && cur->free);
+
+ #ifndef NDEBUG
+ if (!freed->free) {
+ dump_l("dealloc (!freed->free)");
+ }
+ #endif
+ LOG_FATAL_IF(!freed->free,
+ "freed block at offset 0x%08lX of size 0x%08lX is not free!",
+ freed->start * kMemoryAlign, freed->size * kMemoryAlign);
+
+ return freed;
+ }
+ cur = cur->next;
+ }
+ return 0;
+}
+
+void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const
+{
+ Mutex::Autolock _l(mLock);
+ dump_l(what, flags);
+}
+
+void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const
+{
+ String8 result;
+ dump_l(result, what, flags);
+ LOGD("%s", result.string());
+}
+
+void SimpleBestFitAllocator::dump(String8& result,
+ const char* what, uint32_t flags) const
+{
+ Mutex::Autolock _l(mLock);
+ dump_l(result, what, flags);
+}
+
+void SimpleBestFitAllocator::dump_l(String8& result,
+ const char* what, uint32_t flags) const
+{
+ size_t size = 0;
+ int32_t i = 0;
+ chunk_t const* cur = mList.head();
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, " %s (%p, size=%u)\n",
+ what, this, (unsigned int)mHeapSize);
+
+ result.append(buffer);
+
+ while (cur) {
+ const char* errs[] = {"", "| link bogus NP",
+ "| link bogus PN", "| link bogus NP+PN" };
+ int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0;
+ int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0;
+
+ snprintf(buffer, SIZE, " %3u: %08x | 0x%08X | 0x%08X | %s %s\n",
+ i, int(cur), int(cur->start*kMemoryAlign),
+ int(cur->size*kMemoryAlign),
+ int(cur->free) ? "F" : "A",
+ errs[np|pn]);
+
+ result.append(buffer);
+
+ if (!cur->free)
+ size += cur->size*kMemoryAlign;
+
+ i++;
+ cur = cur->next;
+ }
+ snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024));
+ result.append(buffer);
+}
+
+// ----------------------------------------------------------------------------
+
+SharedHeap::SharedHeap()
+ : HeapInterface(), MemoryHeapBase()
+{
+}
+
+SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
+ : MemoryHeapBase(size, flags, name)
+{
+}
+
+SharedHeap::~SharedHeap()
+{
+}
+
+sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size)
+{
+ return new SimpleMemory(this, offset, size);
+}
+
+
+SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap,
+ ssize_t offset, size_t size)
+ : MemoryBase(heap, offset, size)
+{
+#ifndef NDEBUG
+ void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
+ memset(start_ptr, 0xda, size);
+#endif
+}
+
+SimpleMemory::~SimpleMemory()
+{
+ size_t freedOffset = getOffset();
+ size_t freedSize = getSize();
+
+ // keep the size to unmap in excess
+ size_t pagesize = getpagesize();
+ size_t start = freedOffset;
+ size_t end = start + freedSize;
+ start &= ~(pagesize-1);
+ end = (end + pagesize-1) & ~(pagesize-1);
+
+ // give back to the kernel the pages we don't need
+ size_t free_start = freedOffset;
+ size_t free_end = free_start + freedSize;
+ if (start < free_start)
+ start = free_start;
+ if (end > free_end)
+ end = free_end;
+ start = (start + pagesize-1) & ~(pagesize-1);
+ end &= ~(pagesize-1);
+
+ if (start < end) {
+ void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
+ size_t size = end-start;
+
+#ifndef NDEBUG
+ memset(start_ptr, 0xdf, size);
+#endif
+
+ // MADV_REMOVE is not defined on Dapper based Goobuntu
+#ifdef MADV_REMOVE
+ if (size) {
+ int err = madvise(start_ptr, size, MADV_REMOVE);
+ LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
+ start_ptr, size, err<0 ? strerror(errno) : "Ok");
+ }
+#endif
+ }
+}
+
+}; // namespace android
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
new file mode 100644
index 0000000..5df078f
--- /dev/null
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MemoryHeapBase"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/ashmem.h>
+#include <cutils/atomic.h>
+
+#include <binder/MemoryHeapBase.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapBase::MemoryHeapBase()
+ : mFD(-1), mSize(0), mBase(MAP_FAILED),
+ mDevice(NULL), mNeedUnmap(false)
+{
+}
+
+MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
+ : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+ mDevice(0), mNeedUnmap(false)
+{
+ const size_t pagesize = getpagesize();
+ size = ((size + pagesize-1) & ~(pagesize-1));
+ int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
+ LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
+ if (fd >= 0) {
+ if (mapfd(fd, size) == NO_ERROR) {
+ if (flags & READ_ONLY) {
+ ashmem_set_prot_region(fd, PROT_READ);
+ }
+ }
+ }
+}
+
+MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
+ : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+ mDevice(0), mNeedUnmap(false)
+{
+ int fd = open(device, O_RDWR);
+ LOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
+ if (fd >= 0) {
+ const size_t pagesize = getpagesize();
+ size = ((size + pagesize-1) & ~(pagesize-1));
+ if (mapfd(fd, size) == NO_ERROR) {
+ mDevice = device;
+ }
+ }
+}
+
+MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset)
+ : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
+ mDevice(0), mNeedUnmap(false)
+{
+ const size_t pagesize = getpagesize();
+ size = ((size + pagesize-1) & ~(pagesize-1));
+ mapfd(dup(fd), size, offset);
+}
+
+status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
+{
+ if (mFD != -1) {
+ return INVALID_OPERATION;
+ }
+ mFD = fd;
+ mBase = base;
+ mSize = size;
+ mFlags = flags;
+ mDevice = device;
+ return NO_ERROR;
+}
+
+status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
+{
+ if (size == 0) {
+ // try to figure out the size automatically
+#if HAVE_ANDROID_OS
+ // first try the PMEM ioctl
+ pmem_region reg;
+ int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, &reg);
+ if (err == 0)
+ size = reg.len;
+#endif
+ if (size == 0) { // try fstat
+ struct stat sb;
+ if (fstat(fd, &sb) == 0)
+ size = sb.st_size;
+ }
+ // if it didn't work, let mmap() fail.
+ }
+
+ if ((mFlags & DONT_MAP_LOCALLY) == 0) {
+ void* base = (uint8_t*)mmap(0, size,
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
+ if (base == MAP_FAILED) {
+ LOGE("mmap(fd=%d, size=%u) failed (%s)",
+ fd, uint32_t(size), strerror(errno));
+ close(fd);
+ return -errno;
+ }
+ //LOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
+ mBase = base;
+ mNeedUnmap = true;
+ } else {
+ mBase = 0; // not MAP_FAILED
+ mNeedUnmap = false;
+ }
+ mFD = fd;
+ mSize = size;
+ return NO_ERROR;
+}
+
+MemoryHeapBase::~MemoryHeapBase()
+{
+ dispose();
+}
+
+void MemoryHeapBase::dispose()
+{
+ int fd = android_atomic_or(-1, &mFD);
+ if (fd >= 0) {
+ if (mNeedUnmap) {
+ //LOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
+ munmap(mBase, mSize);
+ }
+ mBase = 0;
+ mSize = 0;
+ close(fd);
+ }
+}
+
+int MemoryHeapBase::getHeapID() const {
+ return mFD;
+}
+
+void* MemoryHeapBase::getBase() const {
+ return mBase;
+}
+
+size_t MemoryHeapBase::getSize() const {
+ return mSize;
+}
+
+uint32_t MemoryHeapBase::getFlags() const {
+ return mFlags;
+}
+
+const char* MemoryHeapBase::getDevice() const {
+ return mDevice;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/binder/MemoryHeapPmem.cpp b/libs/binder/MemoryHeapPmem.cpp
new file mode 100644
index 0000000..3806a42
--- /dev/null
+++ b/libs/binder/MemoryHeapPmem.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MemoryHeapPmem"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+
+#include <binder/MemoryHeapPmem.h>
+#include <binder/MemoryHeapBase.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
+ : BnMemory(), mClientHeap(heap)
+{
+}
+
+MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
+ if (mClientHeap != NULL) {
+ mClientHeap->remove(this);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
+public:
+ SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
+ virtual ~SubRegionMemory();
+ virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+private:
+ friend class MemoryHeapPmem;
+ void revoke();
+ size_t mSize;
+ ssize_t mOffset;
+};
+
+SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
+ ssize_t offset, size_t size)
+ : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
+{
+#ifndef NDEBUG
+ void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
+ memset(start_ptr, 0xda, size);
+#endif
+
+#if HAVE_ANDROID_OS
+ if (size > 0) {
+ const size_t pagesize = getpagesize();
+ size = (size + pagesize-1) & ~(pagesize-1);
+ int our_fd = heap->heapID();
+ struct pmem_region sub = { offset, size };
+ int err = ioctl(our_fd, PMEM_MAP, &sub);
+ LOGE_IF(err<0, "PMEM_MAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+}
+#endif
+}
+
+sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
+{
+ if (offset) *offset = mOffset;
+ if (size) *size = mSize;
+ return getHeap();
+}
+
+SubRegionMemory::~SubRegionMemory()
+{
+ revoke();
+}
+
+
+void SubRegionMemory::revoke()
+{
+ // NOTE: revoke() doesn't need to be protected by a lock because it
+ // can only be called from MemoryHeapPmem::revoke(), which means
+ // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
+ // which means MemoryHeapPmem::revoke() wouldn't have been able to
+ // promote() it.
+
+#if HAVE_ANDROID_OS
+ if (mSize != 0) {
+ const sp<MemoryHeapPmem>& heap(getHeap());
+ int our_fd = heap->heapID();
+ struct pmem_region sub;
+ sub.offset = mOffset;
+ sub.len = mSize;
+ int err = ioctl(our_fd, PMEM_UNMAP, &sub);
+ LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+ mSize = 0;
+ }
+#endif
+}
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
+ uint32_t flags)
+ : HeapInterface(), MemoryHeapBase()
+{
+ char const * const device = pmemHeap->getDevice();
+#if HAVE_ANDROID_OS
+ if (device) {
+ int fd = open(device, O_RDWR);
+ LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
+ if (fd >= 0) {
+ int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
+ if (err < 0) {
+ LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
+ strerror(errno), fd, pmemHeap->heapID());
+ close(fd);
+ } else {
+ // everything went well...
+ mParentHeap = pmemHeap;
+ MemoryHeapBase::init(fd,
+ pmemHeap->getBase(),
+ pmemHeap->getSize(),
+ pmemHeap->getFlags() | flags,
+ device);
+ }
+ }
+ }
+#else
+ mParentHeap = pmemHeap;
+ MemoryHeapBase::init(
+ dup(pmemHeap->heapID()),
+ pmemHeap->getBase(),
+ pmemHeap->getSize(),
+ pmemHeap->getFlags() | flags,
+ device);
+#endif
+}
+
+MemoryHeapPmem::~MemoryHeapPmem()
+{
+}
+
+sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
+{
+ sp<MemoryPmem> memory = createMemory(offset, size);
+ if (memory != 0) {
+ Mutex::Autolock _l(mLock);
+ mAllocations.add(memory);
+ }
+ return memory;
+}
+
+sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
+ size_t offset, size_t size)
+{
+ sp<SubRegionMemory> memory;
+ if (heapID() > 0)
+ memory = new SubRegionMemory(this, offset, size);
+ return memory;
+}
+
+status_t MemoryHeapPmem::slap()
+{
+#if HAVE_ANDROID_OS
+ size_t size = getSize();
+ const size_t pagesize = getpagesize();
+ size = (size + pagesize-1) & ~(pagesize-1);
+ int our_fd = getHeapID();
+ struct pmem_region sub = { 0, size };
+ int err = ioctl(our_fd, PMEM_MAP, &sub);
+ LOGE_IF(err<0, "PMEM_MAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+ return -errno;
+#else
+ return NO_ERROR;
+#endif
+}
+
+status_t MemoryHeapPmem::unslap()
+{
+#if HAVE_ANDROID_OS
+ size_t size = getSize();
+ const size_t pagesize = getpagesize();
+ size = (size + pagesize-1) & ~(pagesize-1);
+ int our_fd = getHeapID();
+ struct pmem_region sub = { 0, size };
+ int err = ioctl(our_fd, PMEM_UNMAP, &sub);
+ LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
+ "mFD=%d, sub.offset=%lu, sub.size=%lu",
+ strerror(errno), our_fd, sub.offset, sub.len);
+ return -errno;
+#else
+ return NO_ERROR;
+#endif
+}
+
+void MemoryHeapPmem::revoke()
+{
+ SortedVector< wp<MemoryPmem> > allocations;
+
+ { // scope for lock
+ Mutex::Autolock _l(mLock);
+ allocations = mAllocations;
+ }
+
+ ssize_t count = allocations.size();
+ for (ssize_t i=0 ; i<count ; i++) {
+ sp<MemoryPmem> memory(allocations[i].promote());
+ if (memory != 0)
+ memory->revoke();
+ }
+}
+
+void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
+{
+ Mutex::Autolock _l(mLock);
+ mAllocations.remove(memory);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
new file mode 100644
index 0000000..e397bce
--- /dev/null
+++ b/libs/binder/Parcel.cpp
@@ -0,0 +1,1336 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Parcel"
+//#define LOG_NDEBUG 0
+
+#include <binder/Parcel.h>
+
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <utils/Debug.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/binder/binder_module.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#ifndef INT32_MAX
+#define INT32_MAX ((int32_t)(2147483647))
+#endif
+
+#define LOG_REFS(...)
+//#define LOG_REFS(...) LOG(LOG_DEBUG, "Parcel", __VA_ARGS__)
+
+// ---------------------------------------------------------------------------
+
+#define PAD_SIZE(s) (((s)+3)&~3)
+
+// XXX This can be made public if we want to provide
+// support for typed data.
+struct small_flat_data
+{
+ uint32_t type;
+ uint32_t data;
+};
+
+namespace android {
+
+void acquire_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who)
+{
+ switch (obj.type) {
+ case BINDER_TYPE_BINDER:
+ if (obj.binder) {
+ LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
+ static_cast<IBinder*>(obj.cookie)->incStrong(who);
+ }
+ return;
+ case BINDER_TYPE_WEAK_BINDER:
+ if (obj.binder)
+ static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);
+ return;
+ case BINDER_TYPE_HANDLE: {
+ const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
+ if (b != NULL) {
+ LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get());
+ b->incStrong(who);
+ }
+ return;
+ }
+ case BINDER_TYPE_WEAK_HANDLE: {
+ const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
+ if (b != NULL) b.get_refs()->incWeak(who);
+ return;
+ }
+ case BINDER_TYPE_FD: {
+ // intentionally blank -- nothing to do to acquire this, but we do
+ // recognize it as a legitimate object type.
+ return;
+ }
+ }
+
+ LOGD("Invalid object type 0x%08lx", obj.type);
+}
+
+void release_object(const sp<ProcessState>& proc,
+ const flat_binder_object& obj, const void* who)
+{
+ switch (obj.type) {
+ case BINDER_TYPE_BINDER:
+ if (obj.binder) {
+ LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
+ static_cast<IBinder*>(obj.cookie)->decStrong(who);
+ }
+ return;
+ case BINDER_TYPE_WEAK_BINDER:
+ if (obj.binder)
+ static_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who);
+ return;
+ case BINDER_TYPE_HANDLE: {
+ const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
+ if (b != NULL) {
+ LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get());
+ b->decStrong(who);
+ }
+ return;
+ }
+ case BINDER_TYPE_WEAK_HANDLE: {
+ const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
+ if (b != NULL) b.get_refs()->decWeak(who);
+ return;
+ }
+ case BINDER_TYPE_FD: {
+ if (obj.cookie != (void*)0) close(obj.handle);
+ return;
+ }
+ }
+
+ LOGE("Invalid object type 0x%08lx", obj.type);
+}
+
+inline static status_t finish_flatten_binder(
+ const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out)
+{
+ return out->writeObject(flat, false);
+}
+
+status_t flatten_binder(const sp<ProcessState>& proc,
+ const sp<IBinder>& binder, Parcel* out)
+{
+ flat_binder_object obj;
+
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ if (binder != NULL) {
+ IBinder *local = binder->localBinder();
+ if (!local) {
+ BpBinder *proxy = binder->remoteBinder();
+ if (proxy == NULL) {
+ LOGE("null proxy");
+ }
+ const int32_t handle = proxy ? proxy->handle() : 0;
+ obj.type = BINDER_TYPE_HANDLE;
+ obj.handle = handle;
+ obj.cookie = NULL;
+ } else {
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = local->getWeakRefs();
+ obj.cookie = local;
+ }
+ } else {
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = NULL;
+ obj.cookie = NULL;
+ }
+
+ return finish_flatten_binder(binder, obj, out);
+}
+
+status_t flatten_binder(const sp<ProcessState>& proc,
+ const wp<IBinder>& binder, Parcel* out)
+{
+ flat_binder_object obj;
+
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ if (binder != NULL) {
+ sp<IBinder> real = binder.promote();
+ if (real != NULL) {
+ IBinder *local = real->localBinder();
+ if (!local) {
+ BpBinder *proxy = real->remoteBinder();
+ if (proxy == NULL) {
+ LOGE("null proxy");
+ }
+ const int32_t handle = proxy ? proxy->handle() : 0;
+ obj.type = BINDER_TYPE_WEAK_HANDLE;
+ obj.handle = handle;
+ obj.cookie = NULL;
+ } else {
+ obj.type = BINDER_TYPE_WEAK_BINDER;
+ obj.binder = binder.get_refs();
+ obj.cookie = binder.unsafe_get();
+ }
+ return finish_flatten_binder(real, obj, out);
+ }
+
+ // XXX How to deal? In order to flatten the given binder,
+ // we need to probe it for information, which requires a primary
+ // reference... but we don't have one.
+ //
+ // The OpenBinder implementation uses a dynamic_cast<> here,
+ // but we can't do that with the different reference counting
+ // implementation we are using.
+ LOGE("Unable to unflatten Binder weak reference!");
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = NULL;
+ obj.cookie = NULL;
+ return finish_flatten_binder(NULL, obj, out);
+
+ } else {
+ obj.type = BINDER_TYPE_BINDER;
+ obj.binder = NULL;
+ obj.cookie = NULL;
+ return finish_flatten_binder(NULL, obj, out);
+ }
+}
+
+inline static status_t finish_unflatten_binder(
+ BpBinder* proxy, const flat_binder_object& flat, const Parcel& in)
+{
+ return NO_ERROR;
+}
+
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const Parcel& in, sp<IBinder>* out)
+{
+ const flat_binder_object* flat = in.readObject(false);
+
+ if (flat) {
+ switch (flat->type) {
+ case BINDER_TYPE_BINDER:
+ *out = static_cast<IBinder*>(flat->cookie);
+ return finish_unflatten_binder(NULL, *flat, in);
+ case BINDER_TYPE_HANDLE:
+ *out = proc->getStrongProxyForHandle(flat->handle);
+ return finish_unflatten_binder(
+ static_cast<BpBinder*>(out->get()), *flat, in);
+ }
+ }
+ return BAD_TYPE;
+}
+
+status_t unflatten_binder(const sp<ProcessState>& proc,
+ const Parcel& in, wp<IBinder>* out)
+{
+ const flat_binder_object* flat = in.readObject(false);
+
+ if (flat) {
+ switch (flat->type) {
+ case BINDER_TYPE_BINDER:
+ *out = static_cast<IBinder*>(flat->cookie);
+ return finish_unflatten_binder(NULL, *flat, in);
+ case BINDER_TYPE_WEAK_BINDER:
+ if (flat->binder != NULL) {
+ out->set_object_and_refs(
+ static_cast<IBinder*>(flat->cookie),
+ static_cast<RefBase::weakref_type*>(flat->binder));
+ } else {
+ *out = NULL;
+ }
+ return finish_unflatten_binder(NULL, *flat, in);
+ case BINDER_TYPE_HANDLE:
+ case BINDER_TYPE_WEAK_HANDLE:
+ *out = proc->getWeakProxyForHandle(flat->handle);
+ return finish_unflatten_binder(
+ static_cast<BpBinder*>(out->unsafe_get()), *flat, in);
+ }
+ }
+ return BAD_TYPE;
+}
+
+// ---------------------------------------------------------------------------
+
+Parcel::Parcel()
+{
+ initState();
+}
+
+Parcel::~Parcel()
+{
+ freeDataNoInit();
+}
+
+const uint8_t* Parcel::data() const
+{
+ return mData;
+}
+
+size_t Parcel::dataSize() const
+{
+ return (mDataSize > mDataPos ? mDataSize : mDataPos);
+}
+
+size_t Parcel::dataAvail() const
+{
+ // TODO: decide what to do about the possibility that this can
+ // report an available-data size that exceeds a Java int's max
+ // positive value, causing havoc. Fortunately this will only
+ // happen if someone constructs a Parcel containing more than two
+ // gigabytes of data, which on typical phone hardware is simply
+ // not possible.
+ return dataSize() - dataPosition();
+}
+
+size_t Parcel::dataPosition() const
+{
+ return mDataPos;
+}
+
+size_t Parcel::dataCapacity() const
+{
+ return mDataCapacity;
+}
+
+status_t Parcel::setDataSize(size_t size)
+{
+ status_t err;
+ err = continueWrite(size);
+ if (err == NO_ERROR) {
+ mDataSize = size;
+ LOGV("setDataSize Setting data size of %p to %d\n", this, mDataSize);
+ }
+ return err;
+}
+
+void Parcel::setDataPosition(size_t pos) const
+{
+ mDataPos = pos;
+ mNextObjectHint = 0;
+}
+
+status_t Parcel::setDataCapacity(size_t size)
+{
+ if (size > mDataSize) return continueWrite(size);
+ return NO_ERROR;
+}
+
+status_t Parcel::setData(const uint8_t* buffer, size_t len)
+{
+ status_t err = restartWrite(len);
+ if (err == NO_ERROR) {
+ memcpy(const_cast<uint8_t*>(data()), buffer, len);
+ mDataSize = len;
+ mFdsKnown = false;
+ }
+ return err;
+}
+
+status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)
+{
+ const sp<ProcessState> proc(ProcessState::self());
+ status_t err;
+ uint8_t *data = parcel->mData;
+ size_t *objects = parcel->mObjects;
+ size_t size = parcel->mObjectsSize;
+ int startPos = mDataPos;
+ int firstIndex = -1, lastIndex = -2;
+
+ if (len == 0) {
+ return NO_ERROR;
+ }
+
+ // range checks against the source parcel size
+ if ((offset > parcel->mDataSize)
+ || (len > parcel->mDataSize)
+ || (offset + len > parcel->mDataSize)) {
+ return BAD_VALUE;
+ }
+
+ // Count objects in range
+ for (int i = 0; i < (int) size; i++) {
+ size_t off = objects[i];
+ if ((off >= offset) && (off < offset + len)) {
+ if (firstIndex == -1) {
+ firstIndex = i;
+ }
+ lastIndex = i;
+ }
+ }
+ int numObjects = lastIndex - firstIndex + 1;
+
+ // grow data
+ err = growData(len);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ // append data
+ memcpy(mData + mDataPos, data + offset, len);
+ mDataPos += len;
+ mDataSize += len;
+
+ if (numObjects > 0) {
+ // grow objects
+ if (mObjectsCapacity < mObjectsSize + numObjects) {
+ int newSize = ((mObjectsSize + numObjects)*3)/2;
+ size_t *objects =
+ (size_t*)realloc(mObjects, newSize*sizeof(size_t));
+ if (objects == (size_t*)0) {
+ return NO_MEMORY;
+ }
+ mObjects = objects;
+ mObjectsCapacity = newSize;
+ }
+
+ // append and acquire objects
+ int idx = mObjectsSize;
+ for (int i = firstIndex; i <= lastIndex; i++) {
+ size_t off = objects[i] - offset + startPos;
+ mObjects[idx++] = off;
+ mObjectsSize++;
+
+ flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(mData + off);
+ acquire_object(proc, *flat, this);
+
+ if (flat->type == BINDER_TYPE_FD) {
+ // If this is a file descriptor, we need to dup it so the
+ // new Parcel now owns its own fd, and can declare that we
+ // officially know we have fds.
+ flat->handle = dup(flat->handle);
+ flat->cookie = (void*)1;
+ mHasFds = mFdsKnown = true;
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+bool Parcel::hasFileDescriptors() const
+{
+ if (!mFdsKnown) {
+ scanForFds();
+ }
+ return mHasFds;
+}
+
+status_t Parcel::writeInterfaceToken(const String16& interface)
+{
+ // currently the interface identification token is just its name as a string
+ return writeString16(interface);
+}
+
+bool Parcel::checkInterface(IBinder* binder) const
+{
+ return enforceInterface(binder->getInterfaceDescriptor());
+}
+
+bool Parcel::enforceInterface(const String16& interface) const
+{
+ const String16 str(readString16());
+ if (str == interface) {
+ return true;
+ } else {
+ LOGW("**** enforceInterface() expected '%s' but read '%s'\n",
+ String8(interface).string(), String8(str).string());
+ return false;
+ }
+}
+
+const size_t* Parcel::objects() const
+{
+ return mObjects;
+}
+
+size_t Parcel::objectsCount() const
+{
+ return mObjectsSize;
+}
+
+status_t Parcel::errorCheck() const
+{
+ return mError;
+}
+
+void Parcel::setError(status_t err)
+{
+ mError = err;
+}
+
+status_t Parcel::finishWrite(size_t len)
+{
+ //printf("Finish write of %d\n", len);
+ mDataPos += len;
+ LOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos);
+ if (mDataPos > mDataSize) {
+ mDataSize = mDataPos;
+ LOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize);
+ }
+ //printf("New pos=%d, size=%d\n", mDataPos, mDataSize);
+ return NO_ERROR;
+}
+
+status_t Parcel::writeUnpadded(const void* data, size_t len)
+{
+ size_t end = mDataPos + len;
+ if (end < mDataPos) {
+ // integer overflow
+ return BAD_VALUE;
+ }
+
+ if (end <= mDataCapacity) {
+restart_write:
+ memcpy(mData+mDataPos, data, len);
+ return finishWrite(len);
+ }
+
+ status_t err = growData(len);
+ if (err == NO_ERROR) goto restart_write;
+ return err;
+}
+
+status_t Parcel::write(const void* data, size_t len)
+{
+ void* const d = writeInplace(len);
+ if (d) {
+ memcpy(d, data, len);
+ return NO_ERROR;
+ }
+ return mError;
+}
+
+void* Parcel::writeInplace(size_t len)
+{
+ const size_t padded = PAD_SIZE(len);
+
+ // sanity check for integer overflow
+ if (mDataPos+padded < mDataPos) {
+ return NULL;
+ }
+
+ if ((mDataPos+padded) <= mDataCapacity) {
+restart_write:
+ //printf("Writing %ld bytes, padded to %ld\n", len, padded);
+ uint8_t* const data = mData+mDataPos;
+
+ // Need to pad at end?
+ if (padded != len) {
+#if BYTE_ORDER == BIG_ENDIAN
+ static const uint32_t mask[4] = {
+ 0x00000000, 0xffffff00, 0xffff0000, 0xff000000
+ };
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+ static const uint32_t mask[4] = {
+ 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff
+ };
+#endif
+ //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len],
+ // *reinterpret_cast<void**>(data+padded-4));
+ *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len];
+ }
+
+ finishWrite(padded);
+ return data;
+ }
+
+ status_t err = growData(padded);
+ if (err == NO_ERROR) goto restart_write;
+ return NULL;
+}
+
+status_t Parcel::writeInt32(int32_t val)
+{
+ return writeAligned(val);
+}
+
+status_t Parcel::writeInt64(int64_t val)
+{
+ return writeAligned(val);
+}
+
+status_t Parcel::writeFloat(float val)
+{
+ return writeAligned(val);
+}
+
+status_t Parcel::writeDouble(double val)
+{
+ return writeAligned(val);
+}
+
+status_t Parcel::writeIntPtr(intptr_t val)
+{
+ return writeAligned(val);
+}
+
+status_t Parcel::writeCString(const char* str)
+{
+ return write(str, strlen(str)+1);
+}
+
+status_t Parcel::writeString8(const String8& str)
+{
+ status_t err = writeInt32(str.bytes());
+ if (err == NO_ERROR) {
+ err = write(str.string(), str.bytes()+1);
+ }
+ return err;
+}
+
+status_t Parcel::writeString16(const String16& str)
+{
+ return writeString16(str.string(), str.size());
+}
+
+status_t Parcel::writeString16(const char16_t* str, size_t len)
+{
+ if (str == NULL) return writeInt32(-1);
+
+ status_t err = writeInt32(len);
+ if (err == NO_ERROR) {
+ len *= sizeof(char16_t);
+ uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
+ if (data) {
+ memcpy(data, str, len);
+ *reinterpret_cast<char16_t*>(data+len) = 0;
+ return NO_ERROR;
+ }
+ err = mError;
+ }
+ return err;
+}
+
+status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
+{
+ return flatten_binder(ProcessState::self(), val, this);
+}
+
+status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
+{
+ return flatten_binder(ProcessState::self(), val, this);
+}
+
+status_t Parcel::writeNativeHandle(const native_handle* handle)
+{
+ if (!handle || handle->version != sizeof(native_handle))
+ return BAD_TYPE;
+
+ status_t err;
+ err = writeInt32(handle->numFds);
+ if (err != NO_ERROR) return err;
+
+ err = writeInt32(handle->numInts);
+ if (err != NO_ERROR) return err;
+
+ for (int i=0 ; err==NO_ERROR && i<handle->numFds ; i++)
+ err = writeDupFileDescriptor(handle->data[i]);
+
+ if (err != NO_ERROR) {
+ LOGD("write native handle, write dup fd failed");
+ return err;
+ }
+ err = write(handle->data + handle->numFds, sizeof(int)*handle->numInts);
+ return err;
+}
+
+status_t Parcel::writeFileDescriptor(int fd)
+{
+ flat_binder_object obj;
+ obj.type = BINDER_TYPE_FD;
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ obj.handle = fd;
+ obj.cookie = (void*)0;
+ return writeObject(obj, true);
+}
+
+status_t Parcel::writeDupFileDescriptor(int fd)
+{
+ flat_binder_object obj;
+ obj.type = BINDER_TYPE_FD;
+ obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ obj.handle = dup(fd);
+ obj.cookie = (void*)1;
+ return writeObject(obj, true);
+}
+
+status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
+{
+ const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
+ const bool enoughObjects = mObjectsSize < mObjectsCapacity;
+ if (enoughData && enoughObjects) {
+restart_write:
+ *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
+
+ // Need to write meta-data?
+ if (nullMetaData || val.binder != NULL) {
+ mObjects[mObjectsSize] = mDataPos;
+ acquire_object(ProcessState::self(), val, this);
+ mObjectsSize++;
+ }
+
+ // remember if it's a file descriptor
+ if (val.type == BINDER_TYPE_FD) {
+ mHasFds = mFdsKnown = true;
+ }
+
+ return finishWrite(sizeof(flat_binder_object));
+ }
+
+ if (!enoughData) {
+ const status_t err = growData(sizeof(val));
+ if (err != NO_ERROR) return err;
+ }
+ if (!enoughObjects) {
+ size_t newSize = ((mObjectsSize+2)*3)/2;
+ size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));
+ if (objects == NULL) return NO_MEMORY;
+ mObjects = objects;
+ mObjectsCapacity = newSize;
+ }
+
+ goto restart_write;
+}
+
+
+void Parcel::remove(size_t start, size_t amt)
+{
+ LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
+}
+
+status_t Parcel::read(void* outData, size_t len) const
+{
+ if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
+ memcpy(outData, mData+mDataPos, len);
+ mDataPos += PAD_SIZE(len);
+ LOGV("read Setting data pos of %p to %d\n", this, mDataPos);
+ return NO_ERROR;
+ }
+ return NOT_ENOUGH_DATA;
+}
+
+const void* Parcel::readInplace(size_t len) const
+{
+ if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += PAD_SIZE(len);
+ LOGV("readInplace Setting data pos of %p to %d\n", this, mDataPos);
+ return data;
+ }
+ return NULL;
+}
+
+template<class T>
+status_t Parcel::readAligned(T *pArg) const {
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
+
+ if ((mDataPos+sizeof(T)) <= mDataSize) {
+ const void* data = mData+mDataPos;
+ mDataPos += sizeof(T);
+ *pArg = *reinterpret_cast<const T*>(data);
+ return NO_ERROR;
+ } else {
+ return NOT_ENOUGH_DATA;
+ }
+}
+
+template<class T>
+T Parcel::readAligned() const {
+ T result;
+ if (readAligned(&result) != NO_ERROR) {
+ result = 0;
+ }
+
+ return result;
+}
+
+template<class T>
+status_t Parcel::writeAligned(T val) {
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
+
+ if ((mDataPos+sizeof(val)) <= mDataCapacity) {
+restart_write:
+ *reinterpret_cast<T*>(mData+mDataPos) = val;
+ return finishWrite(sizeof(val));
+ }
+
+ status_t err = growData(sizeof(val));
+ if (err == NO_ERROR) goto restart_write;
+ return err;
+}
+
+status_t Parcel::readInt32(int32_t *pArg) const
+{
+ return readAligned(pArg);
+}
+
+int32_t Parcel::readInt32() const
+{
+ return readAligned<int32_t>();
+}
+
+
+status_t Parcel::readInt64(int64_t *pArg) const
+{
+ return readAligned(pArg);
+}
+
+
+int64_t Parcel::readInt64() const
+{
+ return readAligned<int64_t>();
+}
+
+status_t Parcel::readFloat(float *pArg) const
+{
+ return readAligned(pArg);
+}
+
+
+float Parcel::readFloat() const
+{
+ return readAligned<float>();
+}
+
+status_t Parcel::readDouble(double *pArg) const
+{
+ return readAligned(pArg);
+}
+
+
+double Parcel::readDouble() const
+{
+ return readAligned<double>();
+}
+
+status_t Parcel::readIntPtr(intptr_t *pArg) const
+{
+ return readAligned(pArg);
+}
+
+
+intptr_t Parcel::readIntPtr() const
+{
+ return readAligned<intptr_t>();
+}
+
+
+const char* Parcel::readCString() const
+{
+ const size_t avail = mDataSize-mDataPos;
+ if (avail > 0) {
+ const char* str = reinterpret_cast<const char*>(mData+mDataPos);
+ // is the string's trailing NUL within the parcel's valid bounds?
+ const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
+ if (eos) {
+ const size_t len = eos - str;
+ mDataPos += PAD_SIZE(len+1);
+ LOGV("readCString Setting data pos of %p to %d\n", this, mDataPos);
+ return str;
+ }
+ }
+ return NULL;
+}
+
+String8 Parcel::readString8() const
+{
+ int32_t size = readInt32();
+ // watch for potential int overflow adding 1 for trailing NUL
+ if (size > 0 && size < INT32_MAX) {
+ const char* str = (const char*)readInplace(size+1);
+ if (str) return String8(str, size);
+ }
+ return String8();
+}
+
+String16 Parcel::readString16() const
+{
+ size_t len;
+ const char16_t* str = readString16Inplace(&len);
+ if (str) return String16(str, len);
+ LOGE("Reading a NULL string not supported here.");
+ return String16();
+}
+
+const char16_t* Parcel::readString16Inplace(size_t* outLen) const
+{
+ int32_t size = readInt32();
+ // watch for potential int overflow from size+1
+ if (size >= 0 && size < INT32_MAX) {
+ *outLen = size;
+ const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
+ if (str != NULL) {
+ return str;
+ }
+ }
+ *outLen = 0;
+ return NULL;
+}
+
+sp<IBinder> Parcel::readStrongBinder() const
+{
+ sp<IBinder> val;
+ unflatten_binder(ProcessState::self(), *this, &val);
+ return val;
+}
+
+wp<IBinder> Parcel::readWeakBinder() const
+{
+ wp<IBinder> val;
+ unflatten_binder(ProcessState::self(), *this, &val);
+ return val;
+}
+
+
+native_handle* Parcel::readNativeHandle() const
+{
+ int numFds, numInts;
+ status_t err;
+ err = readInt32(&numFds);
+ if (err != NO_ERROR) return 0;
+ err = readInt32(&numInts);
+ if (err != NO_ERROR) return 0;
+
+ native_handle* h = native_handle_create(numFds, numInts);
+ for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
+ h->data[i] = dup(readFileDescriptor());
+ if (h->data[i] < 0) err = BAD_VALUE;
+ }
+ err = read(h->data + numFds, sizeof(int)*numInts);
+ if (err != NO_ERROR) {
+ native_handle_close(h);
+ native_handle_delete(h);
+ h = 0;
+ }
+ return h;
+}
+
+
+int Parcel::readFileDescriptor() const
+{
+ const flat_binder_object* flat = readObject(true);
+ if (flat) {
+ switch (flat->type) {
+ case BINDER_TYPE_FD:
+ //LOGI("Returning file descriptor %ld from parcel %p\n", flat->handle, this);
+ return flat->handle;
+ }
+ }
+ return BAD_TYPE;
+}
+
+const flat_binder_object* Parcel::readObject(bool nullMetaData) const
+{
+ const size_t DPOS = mDataPos;
+ if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
+ const flat_binder_object* obj
+ = reinterpret_cast<const flat_binder_object*>(mData+DPOS);
+ mDataPos = DPOS + sizeof(flat_binder_object);
+ if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) {
+ // When transferring a NULL object, we don't write it into
+ // the object list, so we don't want to check for it when
+ // reading.
+ LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+ return obj;
+ }
+
+ // Ensure that this object is valid...
+ size_t* const OBJS = mObjects;
+ const size_t N = mObjectsSize;
+ size_t opos = mNextObjectHint;
+
+ if (N > 0) {
+ LOGV("Parcel %p looking for obj at %d, hint=%d\n",
+ this, DPOS, opos);
+
+ // Start at the current hint position, looking for an object at
+ // the current data position.
+ if (opos < N) {
+ while (opos < (N-1) && OBJS[opos] < DPOS) {
+ opos++;
+ }
+ } else {
+ opos = N-1;
+ }
+ if (OBJS[opos] == DPOS) {
+ // Found it!
+ LOGV("Parcel found obj %d at index %d with forward search",
+ this, DPOS, opos);
+ mNextObjectHint = opos+1;
+ LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+ return obj;
+ }
+
+ // Look backwards for it...
+ while (opos > 0 && OBJS[opos] > DPOS) {
+ opos--;
+ }
+ if (OBJS[opos] == DPOS) {
+ // Found it!
+ LOGV("Parcel found obj %d at index %d with backward search",
+ this, DPOS, opos);
+ mNextObjectHint = opos+1;
+ LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
+ return obj;
+ }
+ }
+ LOGW("Attempt to read object from Parcel %p at offset %d that is not in the object list",
+ this, DPOS);
+ }
+ return NULL;
+}
+
+void Parcel::closeFileDescriptors()
+{
+ size_t i = mObjectsSize;
+ if (i > 0) {
+ //LOGI("Closing file descriptors for %d objects...", mObjectsSize);
+ }
+ while (i > 0) {
+ i--;
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
+ if (flat->type == BINDER_TYPE_FD) {
+ //LOGI("Closing fd: %ld\n", flat->handle);
+ close(flat->handle);
+ }
+ }
+}
+
+const uint8_t* Parcel::ipcData() const
+{
+ return mData;
+}
+
+size_t Parcel::ipcDataSize() const
+{
+ return (mDataSize > mDataPos ? mDataSize : mDataPos);
+}
+
+const size_t* Parcel::ipcObjects() const
+{
+ return mObjects;
+}
+
+size_t Parcel::ipcObjectsCount() const
+{
+ return mObjectsSize;
+}
+
+void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
+ const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)
+{
+ freeDataNoInit();
+ mError = NO_ERROR;
+ mData = const_cast<uint8_t*>(data);
+ mDataSize = mDataCapacity = dataSize;
+ //LOGI("setDataReference Setting data size of %p to %lu (pid=%d)\n", this, mDataSize, getpid());
+ mDataPos = 0;
+ LOGV("setDataReference Setting data pos of %p to %d\n", this, mDataPos);
+ mObjects = const_cast<size_t*>(objects);
+ mObjectsSize = mObjectsCapacity = objectsCount;
+ mNextObjectHint = 0;
+ mOwner = relFunc;
+ mOwnerCookie = relCookie;
+ scanForFds();
+}
+
+void Parcel::print(TextOutput& to, uint32_t flags) const
+{
+ to << "Parcel(";
+
+ if (errorCheck() != NO_ERROR) {
+ const status_t err = errorCheck();
+ to << "Error: " << (void*)err << " \"" << strerror(-err) << "\"";
+ } else if (dataSize() > 0) {
+ const uint8_t* DATA = data();
+ to << indent << HexDump(DATA, dataSize()) << dedent;
+ const size_t* OBJS = objects();
+ const size_t N = objectsCount();
+ for (size_t i=0; i<N; i++) {
+ const flat_binder_object* flat
+ = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);
+ to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
+ << TypeCode(flat->type & 0x7f7f7f00)
+ << " = " << flat->binder;
+ }
+ } else {
+ to << "NULL";
+ }
+
+ to << ")";
+}
+
+void Parcel::releaseObjects()
+{
+ const sp<ProcessState> proc(ProcessState::self());
+ size_t i = mObjectsSize;
+ uint8_t* const data = mData;
+ size_t* const objects = mObjects;
+ while (i > 0) {
+ i--;
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+ release_object(proc, *flat, this);
+ }
+}
+
+void Parcel::acquireObjects()
+{
+ const sp<ProcessState> proc(ProcessState::self());
+ size_t i = mObjectsSize;
+ uint8_t* const data = mData;
+ size_t* const objects = mObjects;
+ while (i > 0) {
+ i--;
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(data+objects[i]);
+ acquire_object(proc, *flat, this);
+ }
+}
+
+void Parcel::freeData()
+{
+ freeDataNoInit();
+ initState();
+}
+
+void Parcel::freeDataNoInit()
+{
+ if (mOwner) {
+ //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
+ mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
+ } else {
+ releaseObjects();
+ if (mData) free(mData);
+ if (mObjects) free(mObjects);
+ }
+}
+
+status_t Parcel::growData(size_t len)
+{
+ size_t newSize = ((mDataSize+len)*3)/2;
+ return (newSize <= mDataSize)
+ ? (status_t) NO_MEMORY
+ : continueWrite(newSize);
+}
+
+status_t Parcel::restartWrite(size_t desired)
+{
+ if (mOwner) {
+ freeData();
+ return continueWrite(desired);
+ }
+
+ uint8_t* data = (uint8_t*)realloc(mData, desired);
+ if (!data && desired > mDataCapacity) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+
+ releaseObjects();
+
+ if (data) {
+ mData = data;
+ mDataCapacity = desired;
+ }
+
+ mDataSize = mDataPos = 0;
+ LOGV("restartWrite Setting data size of %p to %d\n", this, mDataSize);
+ LOGV("restartWrite Setting data pos of %p to %d\n", this, mDataPos);
+
+ free(mObjects);
+ mObjects = NULL;
+ mObjectsSize = mObjectsCapacity = 0;
+ mNextObjectHint = 0;
+ mHasFds = false;
+ mFdsKnown = true;
+
+ return NO_ERROR;
+}
+
+status_t Parcel::continueWrite(size_t desired)
+{
+ // If shrinking, first adjust for any objects that appear
+ // after the new data size.
+ size_t objectsSize = mObjectsSize;
+ if (desired < mDataSize) {
+ if (desired == 0) {
+ objectsSize = 0;
+ } else {
+ while (objectsSize > 0) {
+ if (mObjects[objectsSize-1] < desired)
+ break;
+ objectsSize--;
+ }
+ }
+ }
+
+ if (mOwner) {
+ // If the size is going to zero, just release the owner's data.
+ if (desired == 0) {
+ freeData();
+ return NO_ERROR;
+ }
+
+ // If there is a different owner, we need to take
+ // posession.
+ uint8_t* data = (uint8_t*)malloc(desired);
+ if (!data) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+ size_t* objects = NULL;
+
+ if (objectsSize) {
+ objects = (size_t*)malloc(objectsSize*sizeof(size_t));
+ if (!objects) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+
+ // Little hack to only acquire references on objects
+ // we will be keeping.
+ size_t oldObjectsSize = mObjectsSize;
+ mObjectsSize = objectsSize;
+ acquireObjects();
+ mObjectsSize = oldObjectsSize;
+ }
+
+ if (mData) {
+ memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
+ }
+ if (objects && mObjects) {
+ memcpy(objects, mObjects, objectsSize*sizeof(size_t));
+ }
+ //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
+ mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
+ mOwner = NULL;
+
+ mData = data;
+ mObjects = objects;
+ mDataSize = (mDataSize < desired) ? mDataSize : desired;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ mDataCapacity = desired;
+ mObjectsSize = mObjectsCapacity = objectsSize;
+ mNextObjectHint = 0;
+
+ } else if (mData) {
+ if (objectsSize < mObjectsSize) {
+ // Need to release refs on any objects we are dropping.
+ const sp<ProcessState> proc(ProcessState::self());
+ for (size_t i=objectsSize; i<mObjectsSize; i++) {
+ const flat_binder_object* flat
+ = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
+ if (flat->type == BINDER_TYPE_FD) {
+ // will need to rescan because we may have lopped off the only FDs
+ mFdsKnown = false;
+ }
+ release_object(proc, *flat, this);
+ }
+ size_t* objects =
+ (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
+ if (objects) {
+ mObjects = objects;
+ }
+ mObjectsSize = objectsSize;
+ mNextObjectHint = 0;
+ }
+
+ // We own the data, so we can just do a realloc().
+ if (desired > mDataCapacity) {
+ uint8_t* data = (uint8_t*)realloc(mData, desired);
+ if (data) {
+ mData = data;
+ mDataCapacity = desired;
+ } else if (desired > mDataCapacity) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+ } else {
+ mDataSize = desired;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ if (mDataPos > desired) {
+ mDataPos = desired;
+ LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
+ }
+ }
+
+ } else {
+ // This is the first data. Easy!
+ uint8_t* data = (uint8_t*)malloc(desired);
+ if (!data) {
+ mError = NO_MEMORY;
+ return NO_MEMORY;
+ }
+
+ if(!(mDataCapacity == 0 && mObjects == NULL
+ && mObjectsCapacity == 0)) {
+ LOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
+ }
+
+ mData = data;
+ mDataSize = mDataPos = 0;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
+ mDataCapacity = desired;
+ }
+
+ return NO_ERROR;
+}
+
+void Parcel::initState()
+{
+ mError = NO_ERROR;
+ mData = 0;
+ mDataSize = 0;
+ mDataCapacity = 0;
+ mDataPos = 0;
+ LOGV("initState Setting data size of %p to %d\n", this, mDataSize);
+ LOGV("initState Setting data pos of %p to %d\n", this, mDataPos);
+ mObjects = NULL;
+ mObjectsSize = 0;
+ mObjectsCapacity = 0;
+ mNextObjectHint = 0;
+ mHasFds = false;
+ mFdsKnown = true;
+ mOwner = NULL;
+}
+
+void Parcel::scanForFds() const
+{
+ bool hasFds = false;
+ for (size_t i=0; i<mObjectsSize; i++) {
+ const flat_binder_object* flat
+ = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
+ if (flat->type == BINDER_TYPE_FD) {
+ hasFds = true;
+ break;
+ }
+ }
+ mHasFds = hasFds;
+ mFdsKnown = true;
+}
+
+}; // namespace android
diff --git a/libs/binder/Permission.cpp b/libs/binder/Permission.cpp
new file mode 100644
index 0000000..fd8fe69
--- /dev/null
+++ b/libs/binder/Permission.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 <stdint.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Permission.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+Permission::Permission(char const* name)
+ : mPermissionName(name), mPid(getpid())
+{
+}
+
+Permission::Permission(const String16& name)
+ : mPermissionName(name), mPid(getpid())
+{
+}
+
+Permission::Permission(const Permission& rhs)
+ : mPermissionName(rhs.mPermissionName),
+ mGranted(rhs.mGranted),
+ mPid(rhs.mPid)
+{
+}
+
+Permission::~Permission()
+{
+}
+
+bool Permission::operator < (const Permission& rhs) const
+{
+ return mPermissionName < rhs.mPermissionName;
+}
+
+bool Permission::checkCalling() const
+{
+ IPCThreadState* ipcState = IPCThreadState::self();
+ pid_t pid = ipcState->getCallingPid();
+ uid_t uid = ipcState->getCallingUid();
+ return doCheckPermission(pid, uid);
+}
+
+bool Permission::check(pid_t pid, uid_t uid) const
+{
+ return doCheckPermission(pid, uid);
+}
+
+bool Permission::doCheckPermission(pid_t pid, uid_t uid) const
+{
+ if ((uid == 0) || (pid == mPid)) {
+ // root and ourselves is always okay
+ return true;
+ } else {
+ // see if we already granted this permission for this uid
+ Mutex::Autolock _l(mLock);
+ if (mGranted.indexOf(uid) >= 0)
+ return true;
+ }
+
+ bool granted = checkPermission(mPermissionName, pid, uid);
+ if (granted) {
+ Mutex::Autolock _l(mLock);
+ // no need to check again, the old item will be replaced if it is
+ // already there.
+ mGranted.add(uid);
+ }
+ return granted;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
new file mode 100644
index 0000000..d7daf73
--- /dev/null
+++ b/libs/binder/ProcessState.cpp
@@ -0,0 +1,398 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ProcessState"
+
+#include <cutils/process_name.h>
+
+#include <binder/ProcessState.h>
+
+#include <utils/Atomic.h>
+#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <binder/IServiceManager.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include <private/binder/binder_module.h>
+#include <private/binder/Static.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#define BINDER_VM_SIZE (1*1024*1024)
+
+static bool gSingleProcess = false;
+
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+// Global variables
+int mArgC;
+const char* const* mArgV;
+int mArgLen;
+
+class PoolThread : public Thread
+{
+public:
+ PoolThread(bool isMain)
+ : mIsMain(isMain)
+ {
+ }
+
+protected:
+ virtual bool threadLoop()
+ {
+ IPCThreadState::self()->joinThreadPool(mIsMain);
+ return false;
+ }
+
+ const bool mIsMain;
+};
+
+sp<ProcessState> ProcessState::self()
+{
+ if (gProcess != NULL) return gProcess;
+
+ AutoMutex _l(gProcessMutex);
+ if (gProcess == NULL) gProcess = new ProcessState;
+ return gProcess;
+}
+
+void ProcessState::setSingleProcess(bool singleProcess)
+{
+ gSingleProcess = singleProcess;
+}
+
+
+void ProcessState::setContextObject(const sp<IBinder>& object)
+{
+ setContextObject(object, String16("default"));
+}
+
+sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
+{
+ if (supportsProcesses()) {
+ return getStrongProxyForHandle(0);
+ } else {
+ return getContextObject(String16("default"), caller);
+ }
+}
+
+void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
+{
+ AutoMutex _l(mLock);
+ mContexts.add(name, object);
+}
+
+sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller)
+{
+ mLock.lock();
+ sp<IBinder> object(
+ mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL);
+ mLock.unlock();
+
+ //printf("Getting context object %s for %p\n", String8(name).string(), caller.get());
+
+ if (object != NULL) return object;
+
+ // Don't attempt to retrieve contexts if we manage them
+ if (mManagesContexts) {
+ LOGE("getContextObject(%s) failed, but we manage the contexts!\n",
+ String8(name).string());
+ return NULL;
+ }
+
+ IPCThreadState* ipc = IPCThreadState::self();
+ {
+ Parcel data, reply;
+ // no interface token on this magic transaction
+ data.writeString16(name);
+ data.writeStrongBinder(caller);
+ status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0);
+ if (result == NO_ERROR) {
+ object = reply.readStrongBinder();
+ }
+ }
+
+ ipc->flushCommands();
+
+ if (object != NULL) setContextObject(object, name);
+ return object;
+}
+
+bool ProcessState::supportsProcesses() const
+{
+ return mDriverFD >= 0;
+}
+
+void ProcessState::startThreadPool()
+{
+ AutoMutex _l(mLock);
+ if (!mThreadPoolStarted) {
+ mThreadPoolStarted = true;
+ spawnPooledThread(true);
+ }
+}
+
+bool ProcessState::isContextManager(void) const
+{
+ return mManagesContexts;
+}
+
+bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData)
+{
+ if (!mManagesContexts) {
+ AutoMutex _l(mLock);
+ mBinderContextCheckFunc = checkFunc;
+ mBinderContextUserData = userData;
+ if (mDriverFD >= 0) {
+ int dummy = 0;
+#if defined(HAVE_ANDROID_OS)
+ status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+#else
+ status_t result = INVALID_OPERATION;
+#endif
+ if (result == 0) {
+ mManagesContexts = true;
+ } else if (result == -1) {
+ mBinderContextCheckFunc = NULL;
+ mBinderContextUserData = NULL;
+ LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
+ }
+ } else {
+ // If there is no driver, our only world is the local
+ // process so we can always become the context manager there.
+ mManagesContexts = true;
+ }
+ }
+ return mManagesContexts;
+}
+
+ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
+{
+ const size_t N=mHandleToObject.size();
+ if (N <= (size_t)handle) {
+ handle_entry e;
+ e.binder = NULL;
+ e.refs = NULL;
+ status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
+ if (err < NO_ERROR) return NULL;
+ }
+ return &mHandleToObject.editItemAt(handle);
+}
+
+sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
+{
+ sp<IBinder> result;
+
+ AutoMutex _l(mLock);
+
+ handle_entry* e = lookupHandleLocked(handle);
+
+ if (e != NULL) {
+ // We need to create a new BpBinder if there isn't currently one, OR we
+ // are unable to acquire a weak reference on this current one. See comment
+ // in getWeakProxyForHandle() for more info about this.
+ IBinder* b = e->binder;
+ if (b == NULL || !e->refs->attemptIncWeak(this)) {
+ b = new BpBinder(handle);
+ e->binder = b;
+ if (b) e->refs = b->getWeakRefs();
+ result = b;
+ } else {
+ // This little bit of nastyness is to allow us to add a primary
+ // reference to the remote proxy when this team doesn't have one
+ // but another team is sending the handle to us.
+ result.force_set(b);
+ e->refs->decWeak(this);
+ }
+ }
+
+ return result;
+}
+
+wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
+{
+ wp<IBinder> result;
+
+ AutoMutex _l(mLock);
+
+ handle_entry* e = lookupHandleLocked(handle);
+
+ if (e != NULL) {
+ // We need to create a new BpBinder if there isn't currently one, OR we
+ // are unable to acquire a weak reference on this current one. The
+ // attemptIncWeak() is safe because we know the BpBinder destructor will always
+ // call expungeHandle(), which acquires the same lock we are holding now.
+ // We need to do this because there is a race condition between someone
+ // releasing a reference on this BpBinder, and a new reference on its handle
+ // arriving from the driver.
+ IBinder* b = e->binder;
+ if (b == NULL || !e->refs->attemptIncWeak(this)) {
+ b = new BpBinder(handle);
+ result = b;
+ e->binder = b;
+ if (b) e->refs = b->getWeakRefs();
+ } else {
+ result = b;
+ e->refs->decWeak(this);
+ }
+ }
+
+ return result;
+}
+
+void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
+{
+ AutoMutex _l(mLock);
+
+ handle_entry* e = lookupHandleLocked(handle);
+
+ // This handle may have already been replaced with a new BpBinder
+ // (if someone failed the AttemptIncWeak() above); we don't want
+ // to overwrite it.
+ if (e && e->binder == binder) e->binder = NULL;
+}
+
+void ProcessState::setArgs(int argc, const char* const argv[])
+{
+ mArgC = argc;
+ mArgV = (const char **)argv;
+
+ mArgLen = 0;
+ for (int i=0; i<argc; i++) {
+ mArgLen += strlen(argv[i]) + 1;
+ }
+ mArgLen--;
+}
+
+int ProcessState::getArgC() const
+{
+ return mArgC;
+}
+
+const char* const* ProcessState::getArgV() const
+{
+ return mArgV;
+}
+
+void ProcessState::setArgV0(const char* txt)
+{
+ if (mArgV != NULL) {
+ strncpy((char*)mArgV[0], txt, mArgLen);
+ set_process_name(txt);
+ }
+}
+
+void ProcessState::spawnPooledThread(bool isMain)
+{
+ if (mThreadPoolStarted) {
+ int32_t s = android_atomic_add(1, &mThreadPoolSeq);
+ char buf[32];
+ sprintf(buf, "Binder Thread #%d", s);
+ LOGV("Spawning new pooled thread, name=%s\n", buf);
+ sp<Thread> t = new PoolThread(isMain);
+ t->run(buf);
+ }
+}
+
+static int open_driver()
+{
+ if (gSingleProcess) {
+ return -1;
+ }
+
+ int fd = open("/dev/binder", O_RDWR);
+ if (fd >= 0) {
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ int vers;
+#if defined(HAVE_ANDROID_OS)
+ status_t result = ioctl(fd, BINDER_VERSION, &vers);
+#else
+ status_t result = -1;
+ errno = EPERM;
+#endif
+ if (result == -1) {
+ LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
+ close(fd);
+ fd = -1;
+ }
+ if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
+ LOGE("Binder driver protocol does not match user space protocol!");
+ close(fd);
+ fd = -1;
+ }
+#if defined(HAVE_ANDROID_OS)
+ size_t maxThreads = 15;
+ result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
+ if (result == -1) {
+ LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
+ }
+#endif
+
+ } else {
+ LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
+ }
+ return fd;
+}
+
+ProcessState::ProcessState()
+ : mDriverFD(open_driver())
+ , mVMStart(MAP_FAILED)
+ , mManagesContexts(false)
+ , mBinderContextCheckFunc(NULL)
+ , mBinderContextUserData(NULL)
+ , mThreadPoolStarted(false)
+ , mThreadPoolSeq(1)
+{
+ if (mDriverFD >= 0) {
+ // XXX Ideally, there should be a specific define for whether we
+ // have mmap (or whether we could possibly have the kernel module
+ // availabla).
+#if !defined(HAVE_WIN32_IPC)
+ // mmap the binder, providing a chunk of virtual address space to receive transactions.
+ mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
+ if (mVMStart == MAP_FAILED) {
+ // *sigh*
+ LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
+ close(mDriverFD);
+ mDriverFD = -1;
+ }
+#else
+ mDriverFD = -1;
+#endif
+ }
+ if (mDriverFD < 0) {
+ // Need to run without the driver, starting our own thread pool.
+ }
+}
+
+ProcessState::~ProcessState()
+{
+}
+
+}; // namespace android
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..bc466be
--- /dev/null
+++ b/libs/rs/Android.mk
@@ -0,0 +1,115 @@
+
+LOCAL_PATH:=$(call my-dir)
+
+
+# Build rsg-generator ====================
+include $(CLEAR_VARS)
+
+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)
+
+LOCAL_SRC_FILES:= \
+ spec.l \
+ rsg_generator.c
+
+include $(BUILD_HOST_EXECUTABLE)
+
+# TODO: This should go into build/core/config.mk
+RSG_GENERATOR:=$(LOCAL_BUILT_MODULE)
+
+
+
+# Build render script lib ====================
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libRS
+
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+intermediates:= $(local-intermediates-dir)
+
+# Generate custom headers
+
+GEN := $(addprefix $(intermediates)/, \
+ rsgApiStructs.h \
+ rsgApiFuncDecl.h \
+ )
+
+$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(PRIVATE_PATH)/rs.spec
+$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec
+$(GEN): $(intermediates)/%.h : $(LOCAL_PATH)/%.h.rsg
+ $(transform-generated-source)
+
+# used in jni/Android.mk
+rs_generated_source += $(GEN)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+# Generate custom source files
+
+GEN := $(addprefix $(intermediates)/, \
+ rsgApi.cpp \
+ rsgApiReplay.cpp \
+ )
+
+$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
+$(GEN) : PRIVATE_CUSTOM_TOOL = $(RSG_GENERATOR) $< $@ <$(PRIVATE_PATH)/rs.spec
+$(GEN) : $(RSG_GENERATOR) $(LOCAL_PATH)/rs.spec
+$(GEN): $(intermediates)/%.cpp : $(LOCAL_PATH)/%.cpp.rsg
+ $(transform-generated-source)
+
+# used in jni/Android.mk
+rs_generated_source += $(GEN)
+
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+# libRS needs libacc, which isn't 64-bit clean, and so can't be built
+# for the simulator on gHardy, and therefore libRS needs to be excluded
+# from the simulator as well.
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_SRC_FILES:= \
+ rsAdapter.cpp \
+ rsAllocation.cpp \
+ rsComponent.cpp \
+ rsContext.cpp \
+ rsDevice.cpp \
+ rsElement.cpp \
+ rsFileA3D.cpp \
+ rsLight.cpp \
+ rsLocklessFifo.cpp \
+ rsObjectBase.cpp \
+ rsMatrix.cpp \
+ rsMesh.cpp \
+ rsNoise.cpp \
+ rsProgram.cpp \
+ rsProgramFragment.cpp \
+ rsProgramFragmentStore.cpp \
+ rsProgramVertex.cpp \
+ rsSampler.cpp \
+ rsScript.cpp \
+ rsScriptC.cpp \
+ rsScriptC_Lib.cpp \
+ rsSimpleMesh.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_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Include the subdirectories ====================
+include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk,\
+ java \
+ ))
+
+endif #simulator
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
new file mode 100644
index 0000000..1e24cd2
--- /dev/null
+++ b/libs/rs/RenderScript.h
@@ -0,0 +1,201 @@
+/*
+ * 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 * RsFile;
+typedef void * RsSampler;
+typedef void * RsScript;
+typedef void * RsScriptBasicTemp;
+typedef void * RsTriangleMesh;
+typedef void * RsSimpleMesh;
+typedef void * RsType;
+typedef void * RsLight;
+
+typedef void * RsProgramVertex;
+typedef void * RsProgramFragment;
+typedef void * RsProgramFragmentStore;
+
+RsDevice rsDeviceCreate();
+void rsDeviceDestroy(RsDevice);
+
+RsContext rsContextCreate(RsDevice, void *, uint32_t version, bool useDepth);
+void rsContextDestroy(RsContext);
+void rsObjDestroyOOB(RsContext, void *);
+
+#define RS_MAX_TEXTURE 2
+
+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,
+ RS_KIND_POINT_SIZE
+};
+
+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, // 0
+ RS_BLEND_SRC_ONE, // 1
+ RS_BLEND_SRC_DST_COLOR, // 2
+ RS_BLEND_SRC_ONE_MINUS_DST_COLOR, // 3
+ RS_BLEND_SRC_SRC_ALPHA, // 4
+ RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_SRC_DST_ALPHA, // 6
+ RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7
+ RS_BLEND_SRC_SRC_ALPHA_SATURATE // 8
+};
+
+enum RsBlendDstFunc {
+ RS_BLEND_DST_ZERO, // 0
+ RS_BLEND_DST_ONE, // 1
+ RS_BLEND_DST_SRC_COLOR, // 2
+ RS_BLEND_DST_ONE_MINUS_SRC_COLOR, // 3
+ RS_BLEND_DST_SRC_ALPHA, // 4
+ RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_DST_DST_ALPHA, // 6
+ RS_BLEND_DST_ONE_MINUS_DST_ALPHA // 7
+};
+
+enum RsTexEnvMode {
+ RS_TEX_ENV_MODE_REPLACE,
+ RS_TEX_ENV_MODE_MODULATE,
+ RS_TEX_ENV_MODE_DECAL
+};
+
+enum RsPrimitive {
+ RS_PRIMITIVE_POINT,
+ RS_PRIMITIVE_LINE,
+ RS_PRIMITIVE_LINE_STRIP,
+ RS_PRIMITIVE_TRIANGLE,
+ RS_PRIMITIVE_TRIANGLE_STRIP,
+ RS_PRIMITIVE_TRIANGLE_FAN
+};
+
+
+#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..5eb8912
--- /dev/null
+++ b/libs/rs/RenderScriptEnv.h
@@ -0,0 +1,33 @@
+#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 * RsSimpleMesh;
+typedef void * RsType;
+typedef void * RsProgramFragment;
+typedef void * RsProgramFragmentStore;
+typedef void * RsLight;
+
+
+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
+
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/Fall/Android.mk b/libs/rs/java/Fall/Android.mk
new file mode 100644
index 0000000..6366f63
--- /dev/null
+++ b/libs/rs/java/Fall/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := FallRS
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Fall/AndroidManifest.xml b/libs/rs/java/Fall/AndroidManifest.xml
new file mode 100644
index 0000000..f646d0d
--- /dev/null
+++ b/libs/rs/java/Fall/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.fall.rs">
+
+ <application android:label="FallRS">
+
+ <activity
+ android:screenOrientation="portrait"
+ android:name="Fall"
+ android:theme="@android:style/Theme.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/Fall/res/drawable-hdpi/leaves.png b/libs/rs/java/Fall/res/drawable-hdpi/leaves.png
new file mode 100644
index 0000000..9eddd66
--- /dev/null
+++ b/libs/rs/java/Fall/res/drawable-hdpi/leaves.png
Binary files differ
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg b/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
new file mode 100644
index 0000000..1698f28
--- /dev/null
+++ b/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
Binary files differ
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/sky.jpg b/libs/rs/java/Fall/res/drawable-hdpi/sky.jpg
new file mode 100644
index 0000000..565a63b
--- /dev/null
+++ b/libs/rs/java/Fall/res/drawable-hdpi/sky.jpg
Binary files differ
diff --git a/libs/rs/java/Fall/res/raw/fall.c b/libs/rs/java/Fall/res/raw/fall.c
new file mode 100644
index 0000000..f348a62
--- /dev/null
+++ b/libs/rs/java/Fall/res/raw/fall.c
@@ -0,0 +1,518 @@
+// 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.
+
+#pragma version(1)
+#pragma stateVertex(PVSky)
+#pragma stateFragment(PFBackground)
+#pragma stateFragmentStore(PFSBackground)
+
+#define RSID_STATE 0
+#define RSID_RIPPLE_MAP 1
+#define RSID_REFRACTION_MAP 2
+#define RSID_LEAVES 3
+#define RSID_DROP 4
+
+#define LEAF_STRUCT_FIELDS_COUNT 11
+#define LEAF_STRUCT_X 0
+#define LEAF_STRUCT_Y 1
+#define LEAF_STRUCT_SCALE 2
+#define LEAF_STRUCT_ANGLE 3
+#define LEAF_STRUCT_SPIN 4
+#define LEAF_STRUCT_U1 5
+#define LEAF_STRUCT_U2 6
+#define LEAF_STRUCT_ALTITUDE 7
+#define LEAF_STRUCT_RIPPLED 8
+#define LEAF_STRUCT_DELTAX 9
+#define LEAF_STRUCT_DELTAY 10
+
+#define LEAVES_TEXTURES_COUNT 4
+
+#define LEAF_SIZE 0.55f
+
+#define REFRACTION 1.333f
+#define DAMP 3
+
+#define DROP_RADIUS 2
+// The higher, the smaller the ripple
+#define RIPPLE_HEIGHT 10.0f
+
+int offset(int x, int y, int width) {
+ return x + 1 + (y + 1) * (width + 2);
+}
+
+void dropWithStrength(int x, int y, int r, int s) {
+ int width = State_meshWidth;
+ int height = State_meshHeight;
+
+ if (x < r) x = r;
+ if (y < r) y = r;
+ if (x >= width - r) x = width - r - 1;
+ if (y >= height - r) y = height - r - 1;
+
+ x = width - x;
+
+ int rippleMapSize = State_rippleMapSize;
+ int index = State_rippleIndex;
+ int origin = offset(0, 0, width);
+
+ int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+ int sqr = r * r;
+ float invs = 1.0f / s;
+
+ int h = 0;
+ for ( ; h < r; h += 1) {
+ int sqv = h * h;
+ int yn = origin + (y - h) * (width + 2);
+ int yp = origin + (y + h) * (width + 2);
+ int w = 0;
+ for ( ; w < r; w += 1) {
+ int squ = w * w;
+ if (squ + sqv < sqr) {
+ int v = -sqrtf((sqr - (squ + sqv)) << 16) * invs;
+ current[yn + x + w] = v;
+ current[yp + x + w] = v;
+ current[yn + x - w] = v;
+ current[yp + x - w] = v;
+ }
+ }
+ }
+}
+
+void drop(int x, int y, int r) {
+ dropWithStrength(x, y, r, 1);
+}
+
+void updateRipples() {
+ int rippleMapSize = State_rippleMapSize;
+ int width = State_meshWidth;
+ int height = State_meshHeight;
+ int index = State_rippleIndex;
+ int origin = offset(0, 0, width);
+
+ int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+ int* next = loadArrayI32(RSID_RIPPLE_MAP, (1 - index) * rippleMapSize + origin);
+
+ storeI32(RSID_STATE, OFFSETOF_WorldState_rippleIndex, 1 - index);
+
+ int a = 1;
+ int b = width + 2;
+ int h = height;
+ while (h) {
+ int w = width;
+ while (w) {
+ int droplet = ((current[-b] + current[b] + current[-a] + current[a]) >> 1) - *next;
+ droplet -= (droplet >> DAMP);
+ *next = droplet;
+ current += 1;
+ next += 1;
+ w -= 1;
+ }
+ current += 2;
+ next += 2;
+ h -= 1;
+ }
+}
+
+int refraction(int d, int wave, int *map) {
+ int i = d;
+ if (i < 0) i = -i;
+ if (i > 512) i = 512;
+ int w = (wave + 0x10000) >> 8;
+ w &= ~(w >> 31);
+ int r = (map[i] * w) >> 3;
+ if (d < 0) {
+ return -r;
+ }
+ return r;
+}
+
+void generateRipples() {
+ int rippleMapSize = loadI32(RSID_STATE, OFFSETOF_WorldState_rippleMapSize);
+ int width = State_meshWidth;
+ int height = State_meshHeight;
+ int index = State_rippleIndex;
+ int origin = offset(0, 0, width);
+
+ int b = width + 2;
+
+ int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
+ int *map = loadArrayI32(RSID_REFRACTION_MAP, 0);
+ float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
+
+ float fw = (float) width;
+ float fh = (float) height;
+ float fy = (1.0f / 512.0f) * (1.0f / RIPPLE_HEIGHT);
+
+ int h = height - 1;
+ while (h >= 0) {
+ int w = width - 1;
+ int wave = *current;
+ int offset = h * width;
+ while (w >= 0) {
+ int nextWave = current[1];
+ int dx = nextWave - wave;
+ int dy = current[b] - wave;
+
+ int offsetx = refraction(dx, wave, map) >> 16;
+ int u = (width - w) + offsetx;
+ u &= ~(u >> 31);
+ if (u >= width) u = width - 1;
+
+ int offsety = refraction(dy, wave, map) >> 16;
+ int v = (height - h) + offsety;
+ v &= ~(v >> 31);
+ if (v >= height) v = height - 1;
+
+ int index = (offset + w) << 3;
+ vertices[index + 3] = u / fw;
+ vertices[index + 4] = v / fh;
+
+ // Update Z coordinate of the vertex
+ vertices[index + 7] = dy * fy;
+
+ w -= 1;
+ current += 1;
+ wave = nextWave;
+ }
+ h -= 1;
+ current += 2;
+ }
+
+ // Compute the normals for lighting
+ int y = 0;
+ int w8 = width << 3;
+ for ( ; y < height; y += 1) {
+ int x = 0;
+ int yOffset = y * width;
+ for ( ; x < width; x += 1) {
+ int o = (yOffset + x) << 3;
+ int o1 = o + 8;
+ int ow = o + w8;
+ int ow1 = ow + 8;
+
+ // V1
+ float v1x = vertices[o + 5];
+ float v1y = vertices[o + 6];
+ float v1z = vertices[o + 7];
+
+ // V2
+ float v2x = vertices[o1 + 5];
+ float v2y = vertices[o1 + 6];
+ float v2z = vertices[o1 + 7];
+
+ // V3
+ float v3x = vertices[ow + 5];
+ float v3y = vertices[ow + 6];
+ float v3z = vertices[ow + 7];
+
+ // N1
+ float n1x = v2x - v1x;
+ float n1y = v2y - v1y;
+ float n1z = v2z - v1z;
+
+ // N2
+ float n2x = v3x - v1x;
+ float n2y = v3y - v1y;
+ float n2z = v3z - v1z;
+
+ // N1 x N2
+ float n3x = n1y * n2z - n1z * n2y;
+ float n3y = n1z * n2x - n1x * n2z;
+ float n3z = n1x * n2y - n1y * n2x;
+
+ // Normalize
+ float len = 1.0f / magf3(n3x, n3y, n3z);
+ n3x *= len;
+ n3y *= len;
+ n3z *= len;
+
+ // V2
+ v2x = vertices[ow1 + 5];
+ v2y = vertices[ow1 + 6];
+ v2z = vertices[ow1 + 7];
+
+ // N1
+ n1x = v2x - v1x;
+ n1y = v2y - v1y;
+ n1z = v2z - v1z;
+
+ // N2
+ n2x = v3x - v1x;
+ n2y = v3y - v1y;
+ n2z = v3z - v1z;
+
+ // Average of previous normal and N1 x N2
+ n3x = n3x * 0.5f + (n1y * n2z - n1z * n2y) * 0.5f;
+ n3y = n3y * 0.5f + (n1z * n2x - n1x * n2z) * 0.5f;
+ n3z = n3z * 0.5f + (n1x * n2y - n1y * n2x) * 0.5f;
+
+ // Normalize
+ len = 1.0f / magf3(n3x, n3y, n3z);
+ n3x *= len;
+ n3y *= len;
+ n3z *= len;
+
+ vertices[o + 0] = n3x;
+ vertices[o + 1] = n3y;
+ vertices[o + 2] = -n3z;
+
+ // reset Z
+ //vertices[(yOffset + x) << 3 + 7] = 0.0f;
+ }
+ }
+}
+
+float averageZ(float x1, float x2, float y1, float y2, float* vertices,
+ int meshWidth, int meshHeight, float glWidth, float glHeight) {
+
+ x1 = ((x1 + glWidth * 0.5f) / glWidth) * meshWidth;
+ x2 = ((x2 + glWidth * 0.5f) / glWidth) * meshWidth;
+ y1 = ((y1 + glHeight * 0.5f) / glHeight) * meshHeight;
+ y2 = ((y2 + glHeight * 0.5f) / glHeight) * meshHeight;
+
+ int quadX1 = clamp(x1, 0, meshWidth);
+ int quadX2 = clamp(x2, 0, meshWidth);
+ int quadY1 = clamp(y1, 0, meshHeight);
+ int quadY2 = clamp(y2, 0, meshHeight);
+
+ float z = 0.0f;
+ int vertexCount = 0;
+
+ int y = quadY1;
+ for ( ; y < quadY2; y += 1) {
+ int x = quadX1;
+ int yOffset = y * meshWidth;
+ for ( ; x < quadX2; x += 1) {
+ z += vertices[(yOffset + x) << 3 + 7];
+ vertexCount += 1;
+ }
+ }
+
+ return 55.0f * z / vertexCount;
+}
+
+void drawLeaf(int index, float* vertices, int meshWidth, int meshHeight,
+ float glWidth, float glHeight) {
+
+ float *leafStruct = loadArrayF(RSID_LEAVES, index);
+
+ float x = leafStruct[LEAF_STRUCT_X];
+ float x1 = x - LEAF_SIZE;
+ float x2 = x + LEAF_SIZE;
+
+ float y = leafStruct[LEAF_STRUCT_Y];
+ float y1 = y - LEAF_SIZE;
+ float y2 = y + LEAF_SIZE;
+
+ float u1 = leafStruct[LEAF_STRUCT_U1];
+ float u2 = leafStruct[LEAF_STRUCT_U2];
+
+ float z1 = 0.0f;
+ float z2 = 0.0f;
+ float z3 = 0.0f;
+ float z4 = 0.0f;
+
+ float a = leafStruct[LEAF_STRUCT_ALTITUDE];
+ float s = leafStruct[LEAF_STRUCT_SCALE];
+ float r = leafStruct[LEAF_STRUCT_ANGLE];
+
+ float tz = 0.0f;
+ if (a > 0.0f) {
+ tz = -a;
+ } else {
+// z1 = averageZ(x1, x, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
+// z2 = averageZ(x, x2, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
+// z3 = averageZ(x, x2, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
+// z4 = averageZ(x1, x, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
+ }
+
+ x1 -= x;
+ x2 -= x;
+ y1 -= y;
+ y2 -= y;
+
+ float matrix[16];
+ matrixLoadIdentity(matrix);
+ matrixTranslate(matrix, x, y, tz);
+ matrixScale(matrix, s, s, 1.0f);
+ matrixRotate(matrix, r, 0.0f, 0.0f, 1.0f);
+ vpLoadModelMatrix(matrix);
+
+ drawQuadTexCoords(x1, y1, z1, u1, 1.0f,
+ x2, y1, z2, u2, 1.0f,
+ x2, y2, z3, u2, 0.0f,
+ x1, y2, z4, u1, 0.0f);
+
+ float spin = leafStruct[LEAF_STRUCT_SPIN];
+ if (a <= 0.0f) {
+ float rippled = leafStruct[LEAF_STRUCT_RIPPLED];
+ if (rippled < 0.0f) {
+ drop(((x + glWidth * 0.5f) / glWidth) * meshWidth,
+ meshHeight - ((y + glHeight * 0.5f) / glHeight) * meshHeight,
+ DROP_RADIUS);
+ spin /= 4.0f;
+ leafStruct[LEAF_STRUCT_SPIN] = spin;
+ leafStruct[LEAF_STRUCT_RIPPLED] = 1.0f;
+ } else {
+// dropWithStrength(((x + glWidth / 2.0f) / glWidth) * meshWidth,
+// meshHeight - ((y + glHeight / 2.0f) / glHeight) * meshHeight,
+// 2, 5);
+ }
+ leafStruct[LEAF_STRUCT_X] = x + leafStruct[LEAF_STRUCT_DELTAX];
+ leafStruct[LEAF_STRUCT_Y] = y + leafStruct[LEAF_STRUCT_DELTAY];
+ r += spin;
+ leafStruct[LEAF_STRUCT_ANGLE] = r;
+ } else {
+ a -= 0.005f;
+ leafStruct[LEAF_STRUCT_ALTITUDE] = a;
+ r += spin * 2.0f;
+ leafStruct[LEAF_STRUCT_ANGLE] = r;
+ }
+
+ if (-LEAF_SIZE * s + x > glWidth / 2.0f || LEAF_SIZE * s + x < -glWidth / 2.0f ||
+ LEAF_SIZE * s + y < -glHeight / 2.0f) {
+
+ int sprite = randf(LEAVES_TEXTURES_COUNT);
+ leafStruct[LEAF_STRUCT_X] = randf2(-1.0f, 1.0f);
+ leafStruct[LEAF_STRUCT_Y] = glHeight / 2.0f + LEAF_SIZE * 2 * randf(1.0f);
+ leafStruct[LEAF_STRUCT_SCALE] = randf2(0.4f, 0.5f);
+ leafStruct[LEAF_STRUCT_SPIN] = degf(randf2(-0.02f, 0.02f)) / 4.0f;
+ leafStruct[LEAF_STRUCT_U1] = sprite / (float) LEAVES_TEXTURES_COUNT;
+ leafStruct[LEAF_STRUCT_U2] = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
+ leafStruct[LEAF_STRUCT_DELTAX] = randf2(-0.02f, 0.02f) / 60.0f;
+ leafStruct[LEAF_STRUCT_DELTAY] = -0.08f * randf2(0.9f, 1.1f) / 60.0f;
+ }
+}
+
+void drawLeaves() {
+ bindProgramFragment(NAMED_PFBackground);
+ bindProgramFragmentStore(NAMED_PFSLeaf);
+ bindProgramVertex(NAMED_PVSky);
+ bindTexture(NAMED_PFBackground, 0, NAMED_TLeaves);
+
+ int leavesCount = State_leavesCount;
+ int count = leavesCount * LEAF_STRUCT_FIELDS_COUNT;
+ int width = State_meshWidth;
+ int height = State_meshHeight;
+ float glWidth = State_glWidth;
+ float glHeight = State_glHeight;
+
+ float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
+
+ int i = 0;
+ for ( ; i < count; i += LEAF_STRUCT_FIELDS_COUNT) {
+ drawLeaf(i, vertices, width, height, glWidth, glHeight);
+ }
+
+ float matrix[16];
+ matrixLoadIdentity(matrix);
+ vpLoadModelMatrix(matrix);
+}
+
+void drawRiverbed() {
+ bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
+
+ drawTriangleMesh(NAMED_WaterMesh);
+}
+
+void drawSky() {
+ color(1.0f, 1.0f, 1.0f, 0.8f);
+
+ bindProgramFragment(NAMED_PFSky);
+ bindProgramFragmentStore(NAMED_PFSLeaf);
+ bindTexture(NAMED_PFSky, 0, NAMED_TSky);
+
+ float x = State_skyOffsetX + State_skySpeedX;
+ float y = State_skyOffsetY + State_skySpeedY;
+
+ if (x > 1.0f) x = 0.0f;
+ if (x < -1.0f) x = 0.0f;
+ if (y > 1.0f) y = 0.0f;
+
+ storeF(RSID_STATE, OFFSETOF_WorldState_skyOffsetX, x);
+ storeF(RSID_STATE, OFFSETOF_WorldState_skyOffsetY, y);
+
+ float matrix[16];
+ matrixLoadTranslate(matrix, x, y, 0.0f);
+ vpLoadTextureMatrix(matrix);
+
+ drawTriangleMesh(NAMED_WaterMesh);
+
+ matrixLoadIdentity(matrix);
+ vpLoadTextureMatrix(matrix);
+}
+
+void drawLighting() {
+ ambient(0.0f, 0.0f, 0.0f, 1.0f);
+ diffuse(0.0f, 0.0f, 0.0f, 1.0f);
+ specular(0.44f, 0.44f, 0.44f, 1.0f);
+ shininess(40.0f);
+
+ bindProgramFragmentStore(NAMED_PFSBackground);
+ bindProgramFragment(NAMED_PFLighting);
+ bindProgramVertex(NAMED_PVLight);
+
+ drawTriangleMesh(NAMED_WaterMesh);
+}
+
+void drawNormals() {
+ int width = State_meshWidth;
+ int height = State_meshHeight;
+
+ float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
+
+ bindProgramVertex(NAMED_PVSky);
+ bindProgramFragment(NAMED_PFLighting);
+
+ color(1.0f, 0.0f, 0.0f, 1.0f);
+
+ float scale = 1.0f / 10.0f;
+ int y = 0;
+ for ( ; y < height; y += 1) {
+ int yOffset = y * width;
+ int x = 0;
+ for ( ; x < width; x += 1) {
+ int offset = (yOffset + x) << 3;
+ float vx = vertices[offset + 5];
+ float vy = vertices[offset + 6];
+ float vz = vertices[offset + 7];
+ float nx = vertices[offset + 0];
+ float ny = vertices[offset + 1];
+ float nz = vertices[offset + 2];
+ drawLine(vx, vy, vz, vx + nx * scale, vy + ny * scale, vz + nz * scale);
+ }
+ }
+}
+
+int main(int index) {
+ int dropX = Drop_dropX;
+ if (dropX != -1) {
+ int dropY = Drop_dropY;
+ drop(dropX, dropY, DROP_RADIUS);
+ storeI32(RSID_DROP, OFFSETOF_DropState_dropX, -1);
+ storeI32(RSID_DROP, OFFSETOF_DropState_dropY, -1);
+ }
+
+ updateRipples();
+ generateRipples();
+ updateTriangleMesh(NAMED_WaterMesh);
+
+ drawRiverbed();
+ drawSky();
+ drawLighting();
+ drawLeaves();
+ //drawNormals();
+
+ return 1;
+}
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/Fall.java b/libs/rs/java/Fall/src/com/android/fall/rs/Fall.java
new file mode 100644
index 0000000..b1d9b1d
--- /dev/null
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/Fall.java
@@ -0,0 +1,47 @@
+/*
+ * 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.fall.rs;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Fall extends Activity {
+ private FallView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mView = new FallView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mView.onPause();
+
+ Runtime.getRuntime().exit(0);
+ }
+}
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
new file mode 100644
index 0000000..8a33d66
--- /dev/null
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
@@ -0,0 +1,423 @@
+/*
+ * 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.fall.rs;
+
+import android.content.res.Resources;
+import android.renderscript.RenderScript;
+import android.renderscript.ScriptC;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Allocation;
+import android.renderscript.Sampler;
+import android.renderscript.Element;
+import android.renderscript.Light;
+import android.renderscript.Type;
+import static android.renderscript.Sampler.Value.LINEAR;
+import static android.renderscript.Sampler.Value.WRAP;
+import static android.renderscript.ProgramStore.DepthFunc.*;
+import static android.renderscript.ProgramStore.BlendDstFunc;
+import static android.renderscript.ProgramStore.BlendSrcFunc;
+import static android.renderscript.ProgramFragment.EnvMode.*;
+import static android.renderscript.Element.*;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import static android.util.MathUtils.*;
+
+import java.util.TimeZone;
+
+class FallRS {
+ private static final int MESH_RESOLUTION = 48;
+
+ private static final int RSID_STATE = 0;
+
+ private static final int TEXTURES_COUNT = 3;
+ private static final int LEAVES_TEXTURES_COUNT = 4;
+ private static final int RSID_TEXTURE_RIVERBED = 0;
+ private static final int RSID_TEXTURE_LEAVES = 1;
+ private static final int RSID_TEXTURE_SKY = 2;
+
+ private static final int RSID_RIPPLE_MAP = 1;
+
+ private static final int RSID_REFRACTION_MAP = 2;
+
+ private static final int RSID_LEAVES = 3;
+ private static final int LEAVES_COUNT = 14;
+ private static final int LEAF_STRUCT_FIELDS_COUNT = 11;
+ private static final int LEAF_STRUCT_X = 0;
+ private static final int LEAF_STRUCT_Y = 1;
+ private static final int LEAF_STRUCT_SCALE = 2;
+ private static final int LEAF_STRUCT_ANGLE = 3;
+ private static final int LEAF_STRUCT_SPIN = 4;
+ private static final int LEAF_STRUCT_U1 = 5;
+ private static final int LEAF_STRUCT_U2 = 6;
+ private static final int LEAF_STRUCT_ALTITUDE = 7;
+ private static final int LEAF_STRUCT_RIPPLED = 8;
+ private static final int LEAF_STRUCT_DELTAX = 9;
+ private static final int LEAF_STRUCT_DELTAY = 10;
+
+ private static final int RSID_DROP = 4;
+
+ private Resources mResources;
+ private RenderScript mRS;
+
+ private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
+
+ private final int mWidth;
+ private final int mHeight;
+
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private ProgramFragment mPfBackground;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private ProgramFragment mPfLighting;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private ProgramFragment mPfSky;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private ProgramStore mPfsBackground;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private ProgramStore mPfsLeaf;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private ProgramVertex mPvLight;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private ProgramVertex mPvSky;
+
+ private Allocation mState;
+ private Allocation mDropState;
+ private DropState mDrop;
+ private Type mStateType;
+ private Type mDropType;
+ private int mMeshWidth;
+
+ private int mMeshHeight;
+ @SuppressWarnings({"FieldCanBeLocal"})
+ private RenderScript.TriangleMesh mMesh;
+
+ private Allocation mRippleMap;
+ private Allocation mRefractionMap;
+
+ private Allocation mLeaves;
+ private float mGlHeight;
+
+ public FallRS(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ mOptionsARGB.inScaled = false;
+ mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ }
+
+ public void init(RenderScript rs, Resources res) {
+ mRS = rs;
+ mResources = res;
+ initRS();
+ }
+
+ private void initRS() {
+ createProgramVertex();
+ createProgramFragmentStore();
+ createProgramFragment();
+ createMesh();
+ createScriptStructures();
+ loadTextures();
+
+ ScriptC.Builder sb = new ScriptC.Builder(mRS);
+ sb.setType(mStateType, "State", RSID_STATE);
+ sb.setType(mDropType, "Drop", RSID_DROP);
+ sb.setScript(mResources, R.raw.fall);
+ sb.setRoot(true);
+
+ ScriptC script = sb.create();
+ script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ script.setTimeZone(TimeZone.getDefault().getID());
+
+ script.bindAllocation(mState, RSID_STATE);
+ script.bindAllocation(mRippleMap, RSID_RIPPLE_MAP);
+ script.bindAllocation(mRefractionMap, RSID_REFRACTION_MAP);
+ script.bindAllocation(mLeaves, RSID_LEAVES);
+ script.bindAllocation(mDropState, RSID_DROP);
+
+ mRS.contextBindRootScript(script);
+ }
+
+ private void createMesh() {
+ final RenderScript rs = mRS;
+ rs.triangleMeshBegin(Element.NORM_ST_XYZ_F32, Element.INDEX_16);
+
+ int wResolution;
+ int hResolution;
+
+ final int width = mWidth;
+ final int height = mHeight;
+
+ if (width < height) {
+ wResolution = MESH_RESOLUTION;
+ hResolution = (int) (MESH_RESOLUTION * height / (float) width);
+ } else {
+ wResolution = (int) (MESH_RESOLUTION * width / (float) height);
+ hResolution = MESH_RESOLUTION;
+ }
+
+ mGlHeight = 2.0f * height / (float) width;
+ final float glHeight = mGlHeight;
+
+ float quadWidth = 2.0f / (float) wResolution;
+ float quadHeight = glHeight / (float) hResolution;
+
+ wResolution += 2;
+ hResolution += 2;
+
+ for (int y = 0; y <= hResolution; y++) {
+ final boolean shift = (y & 0x1) == 0;
+ final float yOffset = y * quadHeight - glHeight / 2.0f - quadHeight;
+ final float t = 1.0f - y / (float) hResolution;
+ for (int x = 0; x <= wResolution; x++) {
+ if (shift) {
+ rs.triangleMeshAddVertex_XYZ_ST_NORM(
+ -1.0f + x * quadWidth - quadWidth, yOffset, 0.0f,
+ x / (float) wResolution, t,
+ 0.0f, 0.0f, -1.0f);
+ } else {
+ rs.triangleMeshAddVertex_XYZ_ST_NORM(
+ -1.0f + x * quadWidth - quadWidth * 0.5f, yOffset, 0.0f,
+ x / (float) wResolution, t,
+ 0.0f, 0.0f, -1.0f);
+ }
+ }
+ }
+
+ for (int y = 0; y < hResolution; y++) {
+ final boolean shift = (y & 0x1) == 0;
+ final int yOffset = y * (wResolution + 1);
+ for (int x = 0; x < wResolution; x++) {
+ final int index = yOffset + x;
+ final int iWR1 = index + wResolution + 1;
+ if (shift) {
+ rs.triangleMeshAddTriangle(index, index + 1, iWR1);
+ rs.triangleMeshAddTriangle(index + 1, iWR1 + 1, iWR1);
+ } else {
+ rs.triangleMeshAddTriangle(index, iWR1 + 1, iWR1);
+ rs.triangleMeshAddTriangle(index, index + 1, iWR1 + 1);
+ }
+ }
+ }
+
+ mMesh = rs.triangleMeshCreate();
+ mMesh.setName("WaterMesh");
+
+ mMeshWidth = wResolution + 1;
+ mMeshHeight = hResolution + 1;
+ }
+
+ private void createScriptStructures() {
+ final int rippleMapSize = (mMeshWidth + 2) * (mMeshHeight + 2);
+
+ createState(rippleMapSize);
+ createRippleMap(rippleMapSize);
+ createRefractionMap();
+ createLeaves();
+ }
+
+ private void createLeaves() {
+ final float[] leaves = new float[LEAVES_COUNT * LEAF_STRUCT_FIELDS_COUNT];
+ mLeaves = Allocation.createSized(mRS, USER_FLOAT, leaves.length);
+ for (int i = 0; i < leaves.length; i += LEAF_STRUCT_FIELDS_COUNT) {
+ createLeaf(leaves, i);
+ }
+ mLeaves.data(leaves);
+ }
+
+ private void createRefractionMap() {
+ final int[] refractionMap = new int[513];
+ float ir = 1.0f / 1.333f;
+ for (int i = 0; i < refractionMap.length; i++) {
+ float d = (float) Math.tan(Math.asin(Math.sin(Math.atan(i * (1.0f / 256.0f))) * ir));
+ refractionMap[i] = (int) Math.floor(d * (1 << 16) + 0.5f);
+ }
+ mRefractionMap = Allocation.createSized(mRS, USER_I32, refractionMap.length);
+ mRefractionMap.data(refractionMap);
+ }
+
+ private void createRippleMap(int rippleMapSize) {
+ final int[] rippleMap = new int[rippleMapSize * 2];
+ mRippleMap = Allocation.createSized(mRS, USER_I32, rippleMap.length);
+ mRippleMap.data(rippleMap);
+ }
+
+ static class WorldState {
+ public int frameCount;
+ public int width;
+ public int height;
+ public int meshWidth;
+ public int meshHeight;
+ public int rippleMapSize;
+ public int rippleIndex;
+ public int leavesCount;
+ public float glWidth;
+ public float glHeight;
+ public float skyOffsetX;
+ public float skyOffsetY;
+ public float skySpeedX;
+ public float skySpeedY;
+ }
+
+ static class DropState {
+ public int dropX;
+ public int dropY;
+ }
+
+ private void createState(int rippleMapSize) {
+ WorldState worldState = new WorldState();
+ worldState.width = mWidth;
+ worldState.height = mHeight;
+ worldState.meshWidth = mMeshWidth;
+ worldState.meshHeight = mMeshHeight;
+ worldState.rippleMapSize = rippleMapSize;
+ worldState.rippleIndex = 0;
+ worldState.leavesCount = LEAVES_COUNT;
+ worldState.glWidth = 2.0f;
+ worldState.glHeight = mGlHeight;
+ worldState.skySpeedX = random(-0.001f, 0.001f);
+ worldState.skySpeedY = random(0.00008f, 0.0002f);
+
+ mStateType = Type.createFromClass(mRS, WorldState.class, 1, "WorldState");
+ mState = Allocation.createTyped(mRS, mStateType);
+ mState.data(worldState);
+
+ mDrop = new DropState();
+ mDrop.dropX = -1;
+ mDrop.dropY = -1;
+
+ mDropType = Type.createFromClass(mRS, DropState.class, 1, "DropState");
+ mDropState = Allocation.createTyped(mRS, mDropType);
+ mDropState.data(mDrop);
+ }
+
+ private void createLeaf(float[] leaves, int index) {
+ int sprite = random(LEAVES_TEXTURES_COUNT);
+ //noinspection PointlessArithmeticExpression
+ leaves[index + LEAF_STRUCT_X] = random(-1.0f, 1.0f);
+ leaves[index + LEAF_STRUCT_Y] = random(-mGlHeight / 2.0f, mGlHeight / 2.0f);
+ leaves[index + LEAF_STRUCT_SCALE] = random(0.4f, 0.5f);
+ leaves[index + LEAF_STRUCT_ANGLE] = random(0.0f, 360.0f);
+ leaves[index + LEAF_STRUCT_SPIN] = degrees(random(-0.02f, 0.02f)) / 4.0f;
+ leaves[index + LEAF_STRUCT_U1] = sprite / (float) LEAVES_TEXTURES_COUNT;
+ leaves[index + LEAF_STRUCT_U2] = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
+ leaves[index + LEAF_STRUCT_ALTITUDE] = -1.0f;
+ leaves[index + LEAF_STRUCT_RIPPLED] = 1.0f;
+ leaves[index + LEAF_STRUCT_DELTAX] = random(-0.02f, 0.02f) / 60.0f;
+ leaves[index + LEAF_STRUCT_DELTAY] = -0.08f * random(0.9f, 1.1f) / 60.0f;
+ }
+
+ private void loadTextures() {
+ final Allocation[] textures = new Allocation[TEXTURES_COUNT];
+ textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.riverbed, "TRiverbed");
+ textures[RSID_TEXTURE_LEAVES] = loadTextureARGB(R.drawable.leaves, "TLeaves");
+ textures[RSID_TEXTURE_SKY] = loadTextureARGB(R.drawable.sky, "TSky");
+
+ final int count = textures.length;
+ for (int i = 0; i < count; i++) {
+ final Allocation texture = textures[i];
+ texture.uploadToTexture(0);
+ }
+ }
+
+ private Allocation loadTexture(int id, String name) {
+ final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources,
+ id, RGB_565, false);
+ allocation.setName(name);
+ return allocation;
+ }
+
+ private Allocation loadTextureARGB(int id, String name) {
+ Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
+ final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888, false);
+ allocation.setName(name);
+ return allocation;
+ }
+
+ private void createProgramFragment() {
+ Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
+ sampleBuilder.setMin(LINEAR);
+ sampleBuilder.setMag(LINEAR);
+ sampleBuilder.setWrapS(WRAP);
+ sampleBuilder.setWrapT(WRAP);
+ Sampler sampler = sampleBuilder.create();
+
+ ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
+ builder.setTexEnable(true, 0);
+ builder.setTexEnvMode(REPLACE, 0);
+ mPfBackground = builder.create();
+ mPfBackground.setName("PFBackground");
+ mPfBackground.bindSampler(sampler, 0);
+
+ builder = new ProgramFragment.Builder(mRS, null, null);
+ builder.setTexEnable(false, 0);
+ mPfLighting = builder.create();
+ mPfLighting.setName("PFLighting");
+ mPfLighting.bindSampler(sampler, 0);
+
+ builder = new ProgramFragment.Builder(mRS, null, null);
+ builder.setTexEnable(true, 0);
+ builder.setTexEnvMode(MODULATE, 0);
+ mPfSky = builder.create();
+ mPfSky.setName("PFSky");
+ mPfSky.bindSampler(sampler, 0);
+ }
+
+ private void createProgramFragmentStore() {
+ ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
+ builder.setDepthFunc(ALWAYS);
+ builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
+ builder.setDitherEnable(false);
+ builder.setDepthMask(true);
+ mPfsBackground = builder.create();
+ mPfsBackground.setName("PFSBackground");
+
+ builder = new ProgramStore.Builder(mRS, null, null);
+ builder.setDepthFunc(ALWAYS);
+ builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+ builder.setDitherEnable(false);
+ builder.setDepthMask(true);
+ mPfsLeaf = builder.create();
+ mPfsLeaf.setName("PFSLeaf");
+ }
+
+ private void createProgramVertex() {
+ ProgramVertex.MatrixAllocation pvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
+ pvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
+
+ Light light = new Light.Builder(mRS).create();
+ light.setPosition(0.0f, 2.0f, -8.0f);
+
+ ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
+ builder.addLight(light);
+ mPvLight = builder.create();
+ mPvLight.bindAllocation(pvOrthoAlloc);
+ mPvLight.setName("PVLight");
+
+ builder = new ProgramVertex.Builder(mRS, null, null);
+ builder.setTextureMatrixEnable(true);
+ mPvSky = builder.create();
+ mPvSky.bindAllocation(pvOrthoAlloc);
+ mPvSky.setName("PVSky");
+ }
+
+ void addDrop(float x, float y) {
+ mDrop.dropX = (int) ((x / mWidth) * mMeshWidth);
+ mDrop.dropY = (int) ((y / mHeight) * mMeshHeight);
+ mDropState.data(mDrop);
+ }
+}
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
new file mode 100644
index 0000000..7468d2b
--- /dev/null
+++ b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
@@ -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.
+ */
+
+
+package com.android.fall.rs;
+
+import android.content.Context;
+import android.view.SurfaceHolder;
+import android.view.MotionEvent;
+import android.view.KeyEvent;
+import android.renderscript.RenderScript;
+import android.renderscript.RSSurfaceView;
+
+class FallView extends RSSurfaceView {
+ private FallRS mRender;
+
+ public FallView(Context context) {
+ super(context);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ RenderScript RS = createRenderScript(false);
+ mRender = new FallRS(w, h);
+ mRender.init(RS, getResources());
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ mRender.addDrop(event.getX(), event.getY());
+ try {
+ Thread.sleep(16);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ break;
+ }
+ return true;
+ }
+}
diff --git a/libs/rs/java/Film/Android.mk b/libs/rs/java/Film/Android.mk
new file mode 100644
index 0000000..b7f98fc
--- /dev/null
+++ b/libs/rs/java/Film/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := Film
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Film/AndroidManifest.xml b/libs/rs/java/Film/AndroidManifest.xml
new file mode 100644
index 0000000..a5ce8a1
--- /dev/null
+++ b/libs/rs/java/Film/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.film">
+ <application android:label="Film">
+ <activity android:name="Film"
+ android:screenOrientation="portrait"
+ 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/Film/res/drawable/p01.png b/libs/rs/java/Film/res/drawable/p01.png
new file mode 100644
index 0000000..a9b9bdb
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p01.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p02.png b/libs/rs/java/Film/res/drawable/p02.png
new file mode 100644
index 0000000..8162c82
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p02.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p03.png b/libs/rs/java/Film/res/drawable/p03.png
new file mode 100644
index 0000000..e3e26c0
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p03.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p04.png b/libs/rs/java/Film/res/drawable/p04.png
new file mode 100644
index 0000000..daee603
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p04.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p05.png b/libs/rs/java/Film/res/drawable/p05.png
new file mode 100644
index 0000000..fac5248
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p05.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p06.png b/libs/rs/java/Film/res/drawable/p06.png
new file mode 100644
index 0000000..3b51261
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p06.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p07.png b/libs/rs/java/Film/res/drawable/p07.png
new file mode 100644
index 0000000..d8bd938
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p07.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p08.png b/libs/rs/java/Film/res/drawable/p08.png
new file mode 100644
index 0000000..ef175e8
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p08.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p09.png b/libs/rs/java/Film/res/drawable/p09.png
new file mode 100644
index 0000000..7bf3874
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p09.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p10.png b/libs/rs/java/Film/res/drawable/p10.png
new file mode 100644
index 0000000..908827d
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p10.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p11.png b/libs/rs/java/Film/res/drawable/p11.png
new file mode 100644
index 0000000..1289f71
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p11.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p12.png b/libs/rs/java/Film/res/drawable/p12.png
new file mode 100644
index 0000000..e1af16a
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p12.png
Binary files differ
diff --git a/libs/rs/java/Film/res/drawable/p13.png b/libs/rs/java/Film/res/drawable/p13.png
new file mode 100644
index 0000000..d08bcbe
--- /dev/null
+++ b/libs/rs/java/Film/res/drawable/p13.png
Binary files differ
diff --git a/libs/rs/java/Film/res/raw/filmimage.c b/libs/rs/java/Film/res/raw/filmimage.c
new file mode 100644
index 0000000..3bd9496
--- /dev/null
+++ b/libs/rs/java/Film/res/raw/filmimage.c
@@ -0,0 +1,110 @@
+// Fountain test script
+
+#pragma version(1)
+#pragma stateVertex(orthoWindow)
+#pragma stateRaster(flat)
+#pragma stateFragment(PgmFragBackground)
+#pragma stateFragmentStore(MyBlend)
+
+
+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 ++;
+ }
+ }
+
+ drawRect(con, 0, 256, 0, 512);
+ contextBindProgramFragment(con, NAMED_PgmFragParts);
+
+ 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, NAMED_PartBuffer, drawCount);
+ return 1;
+}
diff --git a/libs/rs/java/Film/res/raw/filmstrip.c b/libs/rs/java/Film/res/raw/filmstrip.c
new file mode 100644
index 0000000..8f3d930
--- /dev/null
+++ b/libs/rs/java/Film/res/raw/filmstrip.c
@@ -0,0 +1,96 @@
+// Fountain test script
+
+#pragma version(1)
+#pragma stateVertex(PVBackground)
+#pragma stateFragment(PFBackground)
+#pragma stateFragmentStore(PSBackground)
+
+#define POS_TRANSLATE 0
+#define POS_ROTATE 1
+#define POS_FOCUS 2
+
+#define STATE_TRIANGLE_OFFSET_COUNT 0
+#define STATE_LAST_FOCUS 1
+
+
+// The script enviroment has 3 env allocations.
+// bank0: (r) The enviroment structure
+// bank1: (r) The position information
+// bank2: (rw) The temporary texture state
+
+int main(int index)
+{
+ float mat1[16];
+
+ float trans = Pos_translate;
+ float rot = Pos_rotate;
+
+ matrixLoadScale(mat1, 2.f, 2.f, 2.f);
+ matrixTranslate(mat1, 0.f, 0.f, trans);
+ matrixRotate(mat1, 90.f, 0.f, 0.f, 1.f);
+ matrixRotate(mat1, rot, 1.f, 0.f, 0.f);
+ vpLoadModelMatrix(mat1);
+
+ // Draw the lighting effect in the strip and fill the Z buffer.
+ drawSimpleMesh(NAMED_mesh);
+
+ // Start of images.
+ bindProgramFragmentStore(NAMED_PSImages);
+ bindProgramFragment(NAMED_PFImages);
+ bindProgramVertex(NAMED_PVImages);
+
+ float focusPos = Pos_focus;
+ int focusID = 0;
+ int lastFocusID = loadI32(2, STATE_LAST_FOCUS);
+ int imgCount = 13;
+
+ if (trans > (-.3f)) {
+ focusID = -1.0f - focusPos;
+ if (focusID >= imgCount) {
+ focusID = -1;
+ }
+ } else {
+ focusID = -1;
+ }
+
+ /*
+ if (focusID != lastFocusID) {
+ if (lastFocusID >= 0) {
+ uploadToTexture(con, env->tex[lastFocusID], 1);
+ }
+ if (focusID >= 0) {
+ uploadToTexture(con, env->tex[focusID], 0);
+ }
+ }
+ */
+ storeI32(2, STATE_LAST_FOCUS, focusID);
+
+ int triangleOffsetsCount = Pos_triangleOffsetCount;
+
+ int imgId = 0;
+ for (imgId=1; imgId <= imgCount; imgId++) {
+ float pos = focusPos + imgId + 0.4f;
+ int offset = (int)floorf(pos * 2.f);
+ pos = pos - 0.75f;
+
+ offset = offset + triangleOffsetsCount / 2;
+ if (!((offset < 0) || (offset >= triangleOffsetsCount))) {
+ int start = offset -2;
+ int end = offset + 2;
+
+ if (start < 0) {
+ start = 0;
+ }
+ if (end >= triangleOffsetsCount) {
+ end = triangleOffsetsCount-1;
+ }
+
+ bindTexture(NAMED_PFImages, 0, loadI32(0, imgId - 1));
+ matrixLoadTranslate(mat1, -pos - loadF(5, triangleOffsetsCount / 2), 0, 0);
+ vpLoadTextureMatrix(mat1);
+ drawSimpleMeshRange(NAMED_mesh, loadI32(4, start), (loadI32(4, end) - loadI32(4, start)));
+ }
+ }
+ return 0;
+}
+
diff --git a/libs/rs/java/Film/src/com/android/film/Film.java b/libs/rs/java/Film/src/com/android/film/Film.java
new file mode 100644
index 0000000..6e99816
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/Film.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.film;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+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 Film 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 FilmView 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 FilmView(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/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java
new file mode 100644
index 0000000..cee827b
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -0,0 +1,256 @@
+/*
+ * 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.film;
+
+import java.io.Writer;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.util.Log;
+
+import android.renderscript.*;
+
+public class FilmRS {
+ class StripPosition {
+ public float translate;
+ public float rotate;
+ public float focus;
+ public int triangleOffsetCount;
+ }
+ StripPosition mPos = new StripPosition();
+
+
+ private final int STATE_LAST_FOCUS = 1;
+
+ public FilmRS() {
+ }
+
+ public void init(RenderScript rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ initRS();
+ }
+
+ public void setFilmStripPosition(int x, int y)
+ {
+ if (x < 50) {
+ x = 50;
+ }
+ if (x > 270) {
+ x = 270;
+ }
+
+ float anim = ((float)x-50) / 270.f;
+ mPos.translate = 2f * anim + 0.5f; // translation
+ mPos.rotate = (anim * 40); // rotation
+ mPos.focus = ((float)y) / 16.f - 10.f; // focusPos
+ mPos.triangleOffsetCount = mFSM.mTriangleOffsetsCount;
+ mAllocPos.data(mPos);
+ }
+
+
+ private Resources mRes;
+ private RenderScript mRS;
+ private Script mScriptStrip;
+ private Script mScriptImage;
+ private Sampler mSampler;
+ private ProgramStore mPSBackground;
+ private ProgramStore mPSImages;
+ private ProgramFragment mPFBackground;
+ private ProgramFragment mPFImages;
+ private ProgramVertex mPVBackground;
+ private ProgramVertex mPVImages;
+ private ProgramVertex.MatrixAllocation mPVA;
+ private Type mStripPositionType;
+
+ private Allocation mImages[];
+ private Allocation mAllocIDs;
+ private Allocation mAllocPos;
+ private Allocation mAllocState;
+ private Allocation mAllocPV;
+ private Allocation mAllocOffsetsTex;
+ private Allocation mAllocOffsets;
+
+ private SimpleMesh mMesh;
+ private Light mLight;
+
+ private FilmStripMesh mFSM;
+
+ private int[] mBufferIDs;
+ private float[] mBufferPos = new float[3];
+ private int[] mBufferState;
+
+ private void initPFS() {
+ ProgramStore.Builder b = new ProgramStore.Builder(mRS, null, null);
+
+ b.setDepthFunc(ProgramStore.DepthFunc.LESS);
+ b.setDitherEnable(true);
+ b.setDepthMask(true);
+ mPSBackground = b.create();
+ mPSBackground.setName("PSBackground");
+
+ b.setDepthFunc(ProgramStore.DepthFunc.EQUAL);
+ b.setDitherEnable(false);
+ b.setDepthMask(false);
+ b.setBlendFunc(ProgramStore.BlendSrcFunc.ONE,
+ ProgramStore.BlendDstFunc.ONE);
+ mPSImages = b.create();
+ mPSImages.setName("PSImages");
+ }
+
+ private void initPF() {
+ Sampler.Builder bs = new Sampler.Builder(mRS);
+ bs.setMin(Sampler.Value.LINEAR);//_MIP_LINEAR);
+ bs.setMag(Sampler.Value.LINEAR);
+ bs.setWrapS(Sampler.Value.CLAMP);
+ bs.setWrapT(Sampler.Value.WRAP);
+ mSampler = bs.create();
+
+ ProgramFragment.Builder b = new ProgramFragment.Builder(mRS, null, null);
+
+ mPFBackground = b.create();
+ mPFBackground.setName("PFBackground");
+
+ b.setTexEnable(true, 0);
+ b.setTexEnvMode(ProgramFragment.EnvMode.REPLACE, 0);
+ mPFImages = b.create();
+ mPFImages.bindSampler(mSampler, 0);
+ mPFImages.setName("PFImages");
+ }
+
+ private void initPV() {
+ mLight = (new Light.Builder(mRS)).create();
+ mLight.setPosition(0, -0.5f, -1.0f);
+
+ ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
+ pvb.addLight(mLight);
+ mPVBackground = pvb.create();
+ mPVBackground.setName("PVBackground");
+
+ pvb = new ProgramVertex.Builder(mRS, null, null);
+ pvb.setTextureMatrixEnable(true);
+ mPVImages = pvb.create();
+ mPVImages.setName("PVImages");
+ }
+
+ private void loadImages() {
+ mBufferIDs = new int[13];
+ mImages = new Allocation[13];
+ mAllocIDs = Allocation.createSized(mRS,
+ Element.USER_FLOAT, mBufferIDs.length);
+
+ Element ie = Element.RGB_565;
+ mImages[0] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p01, ie, true);
+ mImages[1] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p02, ie, true);
+ mImages[2] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p03, ie, true);
+ mImages[3] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p04, ie, true);
+ mImages[4] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p05, ie, true);
+ mImages[5] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p06, ie, true);
+ mImages[6] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p07, ie, true);
+ mImages[7] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p08, ie, true);
+ mImages[8] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p09, ie, true);
+ mImages[9] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p10, ie, true);
+ mImages[10] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p11, ie, true);
+ mImages[11] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p12, ie, true);
+ mImages[12] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p13, ie, true);
+
+ int black[] = new int[1024];
+ for(int ct=0; ct < mImages.length; ct++) {
+ Allocation.Adapter2D a = mImages[ct].createAdapter2D();
+
+ int size = 512;
+ int mip = 0;
+ while(size >= 2) {
+ a.subData(0, 0, 2, size, black);
+ a.subData(size-2, 0, 2, size, black);
+ a.subData(0, 0, size, 2, black);
+ a.subData(0, size-2, size, 2, black);
+ size >>= 1;
+ mip++;
+ a.setConstraint(Dimension.LOD, mip);
+ }
+
+ mImages[ct].uploadToTexture(1);
+ mBufferIDs[ct] = mImages[ct].getID();
+ }
+ mAllocIDs.data(mBufferIDs);
+ }
+
+ private void initState()
+ {
+ mBufferState = new int[10];
+ mAllocState = Allocation.createSized(mRS,
+ Element.USER_FLOAT, mBufferState.length);
+ mBufferState[STATE_LAST_FOCUS] = -1;
+ mAllocState.data(mBufferState);
+ }
+
+ private void initRS() {
+ mFSM = new FilmStripMesh();
+ mMesh = mFSM.init(mRS);
+ mMesh.setName("mesh");
+
+ initPFS();
+ initPF();
+ initPV();
+
+ Log.e("rs", "Done loading named");
+
+ mStripPositionType = Type.createFromClass(mRS, StripPosition.class, 1);
+
+ ScriptC.Builder sb = new ScriptC.Builder(mRS);
+ sb.setScript(mRes, R.raw.filmstrip);
+ sb.setRoot(true);
+ sb.setType(mStripPositionType, "Pos", 1);
+ mScriptStrip = sb.create();
+ mScriptStrip.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+ mAllocPos = Allocation.createTyped(mRS, mStripPositionType);
+
+ loadImages();
+ initState();
+
+ mPVA = new ProgramVertex.MatrixAllocation(mRS);
+ mPVBackground.bindAllocation(mPVA);
+ mPVImages.bindAllocation(mPVA);
+ mPVA.setupProjectionNormalized(320, 480);
+
+
+ mScriptStrip.bindAllocation(mAllocIDs, 0);
+ mScriptStrip.bindAllocation(mAllocPos, 1);
+ mScriptStrip.bindAllocation(mAllocState, 2);
+ mScriptStrip.bindAllocation(mPVA.mAlloc, 3);
+
+
+ mAllocOffsets = Allocation.createSized(mRS,
+ Element.USER_I32, mFSM.mTriangleOffsets.length);
+ mAllocOffsets.data(mFSM.mTriangleOffsets);
+ mScriptStrip.bindAllocation(mAllocOffsets, 4);
+
+ mAllocOffsetsTex = Allocation.createSized(mRS,
+ Element.USER_FLOAT, mFSM.mTriangleOffsetsTex.length);
+ mAllocOffsetsTex.data(mFSM.mTriangleOffsetsTex);
+ mScriptStrip.bindAllocation(mAllocOffsetsTex, 5);
+
+ setFilmStripPosition(0, 0);
+ mRS.contextBindRootScript(mScriptStrip);
+ }
+}
+
+
+
diff --git a/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java b/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java
new file mode 100644
index 0000000..64aac26
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/FilmStripMesh.java
@@ -0,0 +1,254 @@
+/*
+ * 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.film;
+
+import java.io.Writer;
+import java.lang.Math;
+import android.util.Log;
+
+import android.renderscript.RenderScript;
+import android.renderscript.SimpleMesh;
+
+
+class FilmStripMesh {
+
+ class Vertex {
+ float nx;
+ float ny;
+ float nz;
+ float s;
+ float t;
+ float x;
+ float y;
+ float z;
+
+ Vertex() {
+ nx = 0;
+ ny = 0;
+ nz = 0;
+ s = 0;
+ t = 0;
+ x = 0;
+ y = 0;
+ z = 0;
+ }
+
+ void xyz(float _x, float _y, float _z) {
+ x = _x;
+ y = _y;
+ z = _z;
+ }
+
+ void nxyz(float _x, float _y, float _z) {
+ nx = _x;
+ ny = _y;
+ nz = _z;
+ }
+
+ void st(float _s, float _t) {
+ s = _s;
+ t = _t;
+ }
+
+ void computeNorm(Vertex v1, Vertex v2) {
+ float dx = v1.x - v2.x;
+ float dy = v1.y - v2.y;
+ float dz = v1.z - v2.z;
+ float len = (float)java.lang.Math.sqrt(dx*dx + dy*dy + dz*dz);
+ dx /= len;
+ dy /= len;
+ dz /= len;
+
+ nx = dx * dz;
+ ny = dy * dz;
+ nz = (float)java.lang.Math.sqrt(dx*dx + dy*dy);
+
+ len = (float)java.lang.Math.sqrt(nx*nx + ny*ny + nz*nz);
+ nx /= len;
+ ny /= len;
+ nz /= len;
+ }
+ }
+
+ int[] mTriangleOffsets;
+ float[] mTriangleOffsetsTex;
+ int mTriangleOffsetsCount;
+
+ SimpleMesh init(RenderScript rs)
+ {
+ float vtx[] = new float[] {
+ 60.431003f, 124.482050f,
+ 60.862074f, 120.872604f,
+ 61.705303f, 117.336662f,
+ 62.949505f, 113.921127f,
+ 64.578177f, 110.671304f,
+ 66.569716f, 107.630302f,
+ 68.897703f, 104.838457f,
+ 71.531259f, 102.332803f,
+ 74.435452f, 100.146577f,
+ 77.571757f, 98.308777f,
+ 80.898574f, 96.843781f,
+ 84.371773f, 95.771023f,
+ 87.945283f, 95.104731f,
+ 98.958994f, 95.267098f,
+ 109.489523f, 98.497596f,
+ 118.699582f, 104.539366f,
+ 125.856872f, 112.912022f,
+ 130.392311f, 122.949849f,
+ 131.945283f, 133.854731f,
+ 130.392311f, 144.759613f,
+ 125.856872f, 154.797439f,
+ 118.699582f, 163.170096f,
+ 109.489523f, 169.211866f,
+ 98.958994f, 172.442364f,
+ 87.945283f, 172.604731f,
+ 72.507313f, 172.672927f,
+ 57.678920f, 168.377071f,
+ 44.668135f, 160.067134f,
+ 34.534908f, 148.420104f,
+ 28.104767f, 134.384831f,
+ 25.901557f, 119.104731f,
+ 28.104767f, 103.824631f,
+ 34.534908f, 89.789358f,
+ 44.668135f, 78.142327f,
+ 57.678920f, 69.832390f,
+ 72.507313f, 65.536534f,
+ 87.945283f, 65.604731f,
+ 106.918117f, 65.688542f,
+ 125.141795f, 60.409056f,
+ 141.131686f, 50.196376f,
+ 153.585137f, 35.882502f,
+ 161.487600f, 18.633545f,
+ 164.195283f, -0.145269f,
+ 161.487600f, -18.924084f,
+ 153.585137f, -36.173040f,
+ 141.131686f, -50.486914f,
+ 125.141795f, -60.699594f,
+ 106.918117f, -65.979081f,
+ 87.945283f, -65.895269f,
+ 80f, -65.895269f,
+ 60f, -65.895269f,
+ 40f, -65.895269f,
+ 20f, -65.895269f,
+ 0f, -65.895269f,
+ -20f, -65.895269f,
+ -40f, -65.895269f,
+ -60f, -65.895269f,
+ -80f, -65.895269f,
+ -87.945283f, -65.895269f,
+ -106.918117f, -65.979081f,
+ -125.141795f, -60.699594f,
+ -141.131686f, -50.486914f,
+ -153.585137f, -36.173040f,
+ -161.487600f, -18.924084f,
+ -164.195283f, -0.145269f,
+ -161.487600f, 18.633545f,
+ -153.585137f, 35.882502f,
+ -141.131686f, 50.196376f,
+ -125.141795f, 60.409056f,
+ -106.918117f, 65.688542f,
+ -87.945283f, 65.604731f,
+ -72.507313f, 65.536534f,
+ -57.678920f, 69.832390f,
+ -44.668135f, 78.142327f,
+ -34.534908f, 89.789358f,
+ -28.104767f, 103.824631f,
+ -25.901557f, 119.104731f,
+ -28.104767f, 134.384831f,
+ -34.534908f, 148.420104f,
+ -44.668135f, 160.067134f,
+ -57.678920f, 168.377071f,
+ -72.507313f, 172.672927f,
+ -87.945283f, 172.604731f,
+ -98.958994f, 172.442364f,
+ -109.489523f, 169.211866f,
+ -118.699582f, 163.170096f,
+ -125.856872f, 154.797439f,
+ -130.392311f, 144.759613f,
+ -131.945283f, 133.854731f,
+ -130.392311f, 122.949849f,
+ -125.856872f, 112.912022f,
+ -118.699582f, 104.539366f,
+ -109.489523f, 98.497596f,
+ -98.958994f, 95.267098f,
+ -87.945283f, 95.104731f,
+ -84.371773f, 95.771023f,
+ -80.898574f, 96.843781f,
+ -77.571757f, 98.308777f,
+ -74.435452f, 100.146577f,
+ -71.531259f, 102.332803f,
+ -68.897703f, 104.838457f,
+ -66.569716f, 107.630302f,
+ -64.578177f, 110.671304f,
+ -62.949505f, 113.921127f,
+ -61.705303f, 117.336662f,
+ -60.862074f, 120.872604f,
+ -60.431003f, 124.482050f
+ };
+
+
+ mTriangleOffsets = new int[64];
+ mTriangleOffsetsTex = new float[64];
+
+ mTriangleOffsets[0] = 0;
+ mTriangleOffsetsCount = 1;
+
+ Vertex t = new Vertex();
+ t.nxyz(1, 0, 0);
+ int count = vtx.length / 2;
+
+ SimpleMesh.TriangleMeshBuilder tm = new SimpleMesh.TriangleMeshBuilder(rs, 3, true, true);
+
+ float runningS = 0;
+ for (int ct=0; ct < (count-1); ct++) {
+ t.x = -vtx[ct*2] / 100.f;
+ t.z = vtx[ct*2+1] / 100.f;
+ t.s = runningS;
+ t.nx = (vtx[ct*2+3] - vtx[ct*2 +1]);
+ t.ny = (vtx[ct*2+2] - vtx[ct*2 ]);
+ float len = (float)java.lang.Math.sqrt(t.nx * t.nx + t.ny * t.ny);
+ runningS += len / 100;
+ t.nx /= len;
+ t.ny /= len;
+ t.y = -0.5f;
+ t.t = 0;
+ tm.add_XYZ_ST_NORM(t.x, t.y, t.z, t.s, t.t, t.nx, t.ny, t.nz);
+ //android.util.Log.e("rs", "vtx x="+t.x+" y="+t.y+" z="+t.z+" s="+t.s+" t="+t.t);
+ t.y = .5f;
+ t.t = 1;
+ tm.add_XYZ_ST_NORM(t.x, t.y, t.z, t.s, t.t, t.nx, t.ny, t.nz);
+ //android.util.Log.e("rs", "vtx x="+t.x+" y="+t.y+" z="+t.z+" s="+t.s+" t="+t.t);
+
+ if((runningS*2) > mTriangleOffsetsCount) {
+ mTriangleOffsets[mTriangleOffsetsCount] = ct*2 * 3;
+ mTriangleOffsetsTex[mTriangleOffsetsCount] = t.s;
+ mTriangleOffsetsCount ++;
+ }
+ }
+
+ count = (count * 2 - 2);
+ for (int ct=0; ct < (count-2); ct+= 2) {
+ tm.addTriangle(ct, ct+1, ct+2);
+ tm.addTriangle(ct+1, ct+3, ct+2);
+ }
+ return tm.create();
+ }
+
+
+}
+
diff --git a/libs/rs/java/Film/src/com/android/film/FilmView.java b/libs/rs/java/Film/src/com/android/film/FilmView.java
new file mode 100644
index 0000000..1c5b2bc
--- /dev/null
+++ b/libs/rs/java/Film/src/com/android/film/FilmView.java
@@ -0,0 +1,82 @@
+/*
+ * 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.film;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+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 FilmView extends RSSurfaceView {
+
+ public FilmView(Context context) {
+ super(context);
+
+ //setFocusable(true);
+ }
+
+ private RenderScript mRS;
+ private FilmRS mRender;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ mRS = createRenderScript(true);
+ mRender = new FilmRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ // break point at here
+ // this method doesn't work when 'extends View' include 'extends ScrollView'.
+ return super.onKeyDown(keyCode, event);
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ boolean ret = true;
+ int act = ev.getAction();
+ if (act == ev.ACTION_UP) {
+ ret = false;
+ }
+ mRender.setFilmStripPosition((int)ev.getX(), (int)ev.getY() / 5);
+ return ret;
+ }
+}
+
+
diff --git a/libs/rs/java/Fountain/Android.mk b/libs/rs/java/Fountain/Android.mk
new file mode 100644
index 0000000..b6a9f10
--- /dev/null
+++ b/libs/rs/java/Fountain/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := Fountain
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Fountain/AndroidManifest.xml b/libs/rs/java/Fountain/AndroidManifest.xml
new file mode 100644
index 0000000..dd0e428
--- /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.Translucent">
+ <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..8c1cad4
--- /dev/null
+++ b/libs/rs/java/Fountain/res/raw/fountain.c
@@ -0,0 +1,51 @@
+// Fountain test script
+#pragma version(1)
+#pragma stateVertex(default)
+#pragma stateFragment(default)
+#pragma stateFragmentStore(default)
+
+int main(int launchID) {
+ int ct;
+ int count = Control_count - 1;
+ int rate = Control_rate;
+ float *dataF = loadArrayF(1, 0);
+ float height = getHeight();
+
+ if (rate) {
+ int *dataI = loadArrayI32(1, 0);
+ float rMax = ((float)rate) * 0.005f;
+ int x = Control_x;
+ int y = Control_y;
+ int newPart = loadI32(1, count * 5);
+ int c = colorFloatRGBAtoUNorm8(Control_r, Control_g, Control_b, 0.99f);
+
+ while (rate--) {
+ int idx = newPart * 5;
+ vec2Rand(dataF + idx, rMax);
+ dataF[idx + 2] = x;
+ dataF[idx + 3] = y;
+ dataI[idx + 4] = c;
+ newPart++;
+ if (newPart >= count) {
+ newPart = 0;
+ }
+ }
+ storeI32(1, count * 5, newPart);
+ }
+
+ for (ct=0; ct < count; ct++) {
+ float dy = dataF[1] + 0.15f;
+ float posy = dataF[3] + dy;
+ if ((posy > height) && (dy > 0)) {
+ dy *= -0.3f;
+ }
+ dataF[1] = dy;
+ dataF[2] += dataF[0];
+ dataF[3] = posy;
+ dataF += 5;
+ }
+
+ uploadToBufferObject(NAMED_PartBuffer);
+ drawSimpleMeshRange(NAMED_PartMesh, 0, count);
+ 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..58c78fa
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/Fountain.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.fountain;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+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/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
new file mode 100644
index 0000000..6d400c5
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -0,0 +1,115 @@
+/*
+ * 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.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+
+public class FountainRS {
+ public static final int PART_COUNT = 20000;
+
+ static class SomeData {
+ public int x;
+ public int y;
+ public int rate;
+ public int count;
+ public float r;
+ public float g;
+ public float b;
+ }
+
+ public FountainRS() {
+ }
+
+ public void init(RenderScript rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ initRS();
+ }
+
+ public void newTouchPosition(int x, int y, int rate) {
+ if (mSD.rate == 0) {
+ mSD.r = ((x & 0x1) != 0) ? 0.f : 1.f;
+ mSD.g = ((x & 0x2) != 0) ? 0.f : 1.f;
+ mSD.b = ((x & 0x4) != 0) ? 0.f : 1.f;
+ if ((mSD.r + mSD.g + mSD.b) < 0.9f) {
+ mSD.r = 0.8f;
+ mSD.g = 0.5f;
+ mSD.b = 1.f;
+ }
+ }
+ mSD.rate = rate;
+ mSD.x = x;
+ mSD.y = y;
+ mIntAlloc.data(mSD);
+ }
+
+
+ /////////////////////////////////////////
+
+ private Resources mRes;
+
+ private RenderScript mRS;
+ private Allocation mIntAlloc;
+ private SimpleMesh mSM;
+ private SomeData mSD;
+ private Type mSDType;
+
+ private void initRS() {
+ mSD = new SomeData();
+ mSDType = Type.createFromClass(mRS, SomeData.class, 1, "SomeData");
+ mIntAlloc = Allocation.createTyped(mRS, mSDType);
+ mSD.count = PART_COUNT;
+ mIntAlloc.data(mSD);
+
+ Element.Builder eb = new Element.Builder(mRS);
+ eb.addFloat(Element.DataKind.USER); //dx
+ eb.addFloat(Element.DataKind.USER); //dy
+ eb.addFloatXY();
+ eb.addUNorm8RGBA();
+ Element primElement = eb.create();
+
+
+ SimpleMesh.Builder smb = new SimpleMesh.Builder(mRS);
+ int vtxSlot = smb.addVertexType(primElement, PART_COUNT);
+ smb.setPrimitive(Primitive.POINT);
+ mSM = smb.create();
+ mSM.setName("PartMesh");
+
+ Allocation partAlloc = mSM.createVertexAllocation(vtxSlot);
+ partAlloc.setName("PartBuffer");
+ mSM.bindVertexAllocation(partAlloc, 0);
+
+ // All setup of named objects should be done by this point
+ // because we are about to compile the script.
+ ScriptC.Builder sb = new ScriptC.Builder(mRS);
+ sb.setScript(mRes, R.raw.fountain);
+ sb.setRoot(true);
+ sb.setType(mSDType, "Control", 0);
+ Script script = sb.create();
+ script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+ script.bindAllocation(mIntAlloc, 0);
+ script.bindAllocation(partAlloc, 1);
+ mRS.contextBindRootScript(script);
+ }
+
+}
+
+
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..7826161
--- /dev/null
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
@@ -0,0 +1,79 @@
+/*
+ * 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.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+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 FountainRS mRender;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ mRS = createRenderScript(false);
+ mRender = new FountainRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ int act = ev.getAction();
+ if (act == ev.ACTION_UP) {
+ mRender.newTouchPosition(0, 0, 0);
+ return false;
+ }
+ float rate = (ev.getPressure() * 50.f);
+ rate *= rate;
+ if(rate > 2000.f) {
+ rate = 2000.f;
+ }
+ mRender.newTouchPosition((int)ev.getX(), (int)ev.getY(), (int)rate);
+ return true;
+ }
+}
+
+
diff --git a/libs/rs/java/Rollo/Android.mk b/libs/rs/java/Rollo/Android.mk
new file mode 100644
index 0000000..5a4957c
--- /dev/null
+++ b/libs/rs/java/Rollo/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := Rollo
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Rollo/AndroidManifest.xml b/libs/rs/java/Rollo/AndroidManifest.xml
new file mode 100644
index 0000000..127a140
--- /dev/null
+++ b/libs/rs/java/Rollo/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.rollo">
+ <application android:label="Rollo">
+ <activity android:name="Rollo"
+ android:theme="@android:style/Theme.Translucent">
+ <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/Rollo/res/raw/browser.png b/libs/rs/java/Rollo/res/raw/browser.png
new file mode 100644
index 0000000..513f0be
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/browser.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/calendar.png b/libs/rs/java/Rollo/res/raw/calendar.png
new file mode 100644
index 0000000..030ae73
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/calendar.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/g1155.png b/libs/rs/java/Rollo/res/raw/g1155.png
new file mode 100644
index 0000000..68e1843
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/g1155.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/g2140.png b/libs/rs/java/Rollo/res/raw/g2140.png
new file mode 100644
index 0000000..8c4e853
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/g2140.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/maps.png b/libs/rs/java/Rollo/res/raw/maps.png
new file mode 100644
index 0000000..fd5fc39
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/maps.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/market.png b/libs/rs/java/Rollo/res/raw/market.png
new file mode 100644
index 0000000..83b6910
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/market.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path1920.png b/libs/rs/java/Rollo/res/raw/path1920.png
new file mode 100644
index 0000000..3510665
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path1920.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path1927.png b/libs/rs/java/Rollo/res/raw/path1927.png
new file mode 100644
index 0000000..fccc846
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path1927.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path3099.png b/libs/rs/java/Rollo/res/raw/path3099.png
new file mode 100644
index 0000000..527ebf6
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path3099.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path3950.png b/libs/rs/java/Rollo/res/raw/path3950.png
new file mode 100644
index 0000000..59a646a
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path3950.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path431.png b/libs/rs/java/Rollo/res/raw/path431.png
new file mode 100644
index 0000000..5d2ed75
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path431.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path4481.png b/libs/rs/java/Rollo/res/raw/path4481.png
new file mode 100644
index 0000000..78be0fc
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path4481.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path5168.png b/libs/rs/java/Rollo/res/raw/path5168.png
new file mode 100644
index 0000000..a7c3a19
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path5168.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path676.png b/libs/rs/java/Rollo/res/raw/path676.png
new file mode 100644
index 0000000..2099690
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path676.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path754.png b/libs/rs/java/Rollo/res/raw/path754.png
new file mode 100644
index 0000000..88aed5b
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path754.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/path815.png b/libs/rs/java/Rollo/res/raw/path815.png
new file mode 100644
index 0000000..407570f
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/path815.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/photos.png b/libs/rs/java/Rollo/res/raw/photos.png
new file mode 100644
index 0000000..1ed8f1e
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/photos.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/polygon2408.png b/libs/rs/java/Rollo/res/raw/polygon2408.png
new file mode 100644
index 0000000..4413954
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/polygon2408.png
Binary files differ
diff --git a/libs/rs/java/Rollo/res/raw/rollo.c b/libs/rs/java/Rollo/res/raw/rollo.c
new file mode 100644
index 0000000..6376715
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/rollo.c
@@ -0,0 +1,184 @@
+#pragma version(1)
+#pragma stateVertex(PV)
+#pragma stateFragment(PF)
+#pragma stateFragmentStore(PFS)
+
+// Scratch buffer layout
+#define SCRATCH_FADE 0
+#define SCRATCH_ZOOM 1
+#define SCRATCH_ROT 2
+
+//#define STATE_POS_X 0
+#define STATE_DONE 1
+//#define STATE_PRESSURE 2
+#define STATE_ZOOM 3
+//#define STATE_WARP 4
+#define STATE_ORIENTATION 5
+#define STATE_SELECTION 6
+#define STATE_FIRST_VISIBLE 7
+#define STATE_COUNT 8
+#define STATE_TOUCH 9
+
+
+float filter(float val, float target, float str)
+{
+ float delta = (target - val);
+ return val + delta * str;
+}
+
+int main(void* con, int ft, int launchID)
+{
+ int rowCount;
+ int row;
+ int col;
+ int imageID;
+ int done = loadI32(0, STATE_DONE);
+ int selectedID = loadI32(0, STATE_SELECTION);
+
+ float f = loadF(2, 0);
+
+ pfClearColor(0.0f, 0.0f, 0.0f, f);
+ if (done) {
+ if (f > 0.02f) {
+ //f = f - 0.02f;
+ //storeF(2, 0, f);
+ }
+ } else {
+ if (f < 0.8f) {
+ f = f + 0.02f;
+ storeF(2, 0, f);
+ }
+ }
+
+ float touchCut = 1.f;
+ if (loadI32(0, STATE_TOUCH)) {
+ touchCut = 4.f;
+ }
+
+
+ float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
+ float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
+ storeF(2, SCRATCH_ZOOM, zoom);
+
+ float targetRot = loadI32(0, STATE_FIRST_VISIBLE) / 180.0f * 3.14f;
+ targetRot = targetRot * 0.80f - .12f;
+ float drawRot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
+ storeF(2, SCRATCH_ROT, drawRot);
+
+ float diam = 8.f;
+ float scale = 1.0f / zoom;
+
+ // Bug makes 1.0f alpha fail.
+ color(1.0f, 1.0f, 1.0f, 0.99f);
+
+ float rot = drawRot * scale;
+ float rotStep = 16.0f / 180.0f * 3.14f * scale;
+ rowCount = 4;
+ int index = 0;
+ int iconCount = loadI32(0, STATE_COUNT);
+ while (iconCount) {
+ float tmpSin = sinf(rot);
+ float tmpCos = cosf(rot);
+ //debugF("rot", rot);
+
+ float tx1 = tmpSin * diam - (tmpCos * scale * 0.9f);
+ float tx2 = tx1 + (tmpCos * scale * 1.8f);
+ float tz1 = tmpCos * diam + (tmpSin * scale * 0.9f);
+ float tz2 = tz1 - (tmpSin * scale * 1.8f);
+
+ int y;
+ for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+ float ty1 = ((y * 3.1f) - 5.f) * scale;
+ float ty2 = ty1 + scale * 1.8f;
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz2,
+ tx2, ty2, tz2,
+ tx1, ty2, tz1);
+
+ iconCount--;
+ index++;
+ }
+ rot = rot + rotStep;
+ }
+
+ if ((zoom < 1.1f) && (zoom > 0.9f)) {
+ bindProgramVertex(NAMED_PVOrtho);
+ bindProgramFragment(NAMED_PFText);
+ bindProgramFragmentStore(NAMED_PFSText);
+
+ rot = drawRot * scale;
+ index = 0;
+ iconCount = loadI32(0, STATE_COUNT);
+ while (iconCount) {
+ int y;
+
+ float tx = 240.f + floorf(sinf(rot) * 430.f) - 64.f + 16.f;
+
+ float alpha = 2.4f - (fabsf(tx - 240.f + 48.f) / 76.f);
+ if (alpha > 0.99f) {
+ alpha = 0.99f;
+ }
+ alpha = alpha * (1.f - (fabsf(zoom - 1.f) * 10.f));
+
+ tx = tx + 0.25f;
+
+ for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+
+ if (alpha > 0) {
+ color(1.0f, 1.0f, 1.0f, alpha);
+
+ float ty = 605.f - y * 150.f;
+
+ ty = ty + 0.25f;
+
+ bindTexture(NAMED_PFText, 0, loadI32(3, index));
+ drawRect(tx, ty, tx + 128.f, ty + 32.f, 0.5f);
+ }
+ iconCount--;
+ index++;
+ }
+ rot = rot + rotStep;
+ }
+
+
+ bindProgramVertex(NAMED_PV);
+ bindProgramFragment(NAMED_PF);
+ bindProgramFragmentStore(NAMED_PFS);
+ }
+
+ // Draw the selected icon
+ color(1.0f, 1.0f, 1.0f, 0.9f);
+ rot = drawRot * scale;
+ index = 0;
+ iconCount = loadI32(0, STATE_COUNT);
+ while (iconCount) {
+ int y;
+ for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+ if (index == selectedID) {
+
+ float tmpSin = sinf(rot) * scale;
+ float tmpCos = cosf(rot) * scale;
+ float tx1 = tmpSin * diam * 0.9f - tmpCos * 2.f;
+ float tx2 = tx1 + (tmpCos * 4.f);
+ float tz1 = tmpCos * diam * 0.9f + tmpSin * 2.f;
+ float tz2 = tz1 - (tmpSin * 4.f);
+
+ float ty1 = ((y * 3.1f) - 4.5f) * scale;
+ float ty2 = ty1 + scale * 4.f;
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz2,
+ tx2, ty2, tz2,
+ tx1, ty2, tz1);
+ }
+ iconCount--;
+ index++;
+ }
+ rot = rot + rotStep;
+ }
+
+ return 1;
+}
+
+
diff --git a/libs/rs/java/Rollo/res/raw/rollo2.c b/libs/rs/java/Rollo/res/raw/rollo2.c
new file mode 100644
index 0000000..256fa3c
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/rollo2.c
@@ -0,0 +1,155 @@
+#pragma version(1)
+#pragma stateVertex(PV)
+#pragma stateFragment(PF)
+#pragma stateFragmentStore(PFS)
+
+// Scratch buffer layout
+#define SCRATCH_FADE 0
+#define SCRATCH_ZOOM 1
+#define SCRATCH_ROT 2
+
+//#define STATE_POS_X 0
+#define STATE_DONE 1
+//#define STATE_PRESSURE 2
+#define STATE_ZOOM 3
+//#define STATE_WARP 4
+#define STATE_ORIENTATION 5
+#define STATE_SELECTION 6
+#define STATE_FIRST_VISIBLE 7
+#define STATE_COUNT 8
+#define STATE_TOUCH 9
+
+float filter(float val, float target, float str)
+{
+ float delta = (target - val);
+ return val + delta * str;
+}
+
+
+int main(void* con, int ft, int launchID)
+{
+ int rowCount;
+ int imageID;
+ int done = loadI32(0, STATE_DONE);
+ int selectedID = loadI32(0, STATE_SELECTION);
+ int iconCount = loadI32(0, STATE_COUNT);
+
+ float f = loadF(2, 0);
+
+ float iconSize = 1.f;
+ float iconSpacing = 0.2f;
+ float z = 4.f;
+
+ pfClearColor(0.0f, 0.0f, 0.0f, f);
+ if (done) {
+ } else {
+ if (f < 0.8f) {
+ f = f + 0.02f;
+ storeF(2, 0, f);
+ }
+ }
+
+ float touchCut = 1.f;
+ if (loadI32(0, STATE_TOUCH)) {
+ touchCut = 5.f;
+ }
+
+
+ float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
+ float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
+ storeF(2, SCRATCH_ZOOM, zoom);
+
+ float targetPos = loadI32(0, STATE_FIRST_VISIBLE) / (-20.0f);
+ float pos = filter(loadF(2, SCRATCH_ROT), targetPos, 0.1f * touchCut);
+ storeF(2, SCRATCH_ROT, pos);
+ pos = pos - 1.f;
+
+ color(1.0f, 1.0f, 1.0f, 1.0f);
+
+
+ // Draw flat icons first
+ int index = ((int)pos) * 4;
+ int row;
+ int col;
+ float xoffset = -0.3f;
+ float gridSize = iconSize * 4.f + iconSpacing * 3.f;
+ float yoffset = (pos - ((int)pos));
+ for (row = 0; row < 4; row ++) {
+ float ty1 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing) - iconSize;
+ float ty2 = ty1 + iconSize;
+
+ for (col = 0; (col < 4) && (index < iconCount); col ++) {
+ if (index >= 0) {
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ float fcol = col;
+ float tx1 = xoffset + (-gridSize / 2.f) + (fcol * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ drawQuad(tx1, ty1, z,
+ tx2, ty1, z,
+ tx2, ty2, z,
+ tx1, ty2, z);
+ }
+ index++;
+ }
+ }
+
+ // bottom roller
+ {
+ float roll = (1.f - yoffset) * 0.5f * 3.14f;
+ float tmpSin = sinf(roll);
+ float tmpCos = cosf(roll);
+
+ for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
+ float ty2 = (gridSize / 2.f) - ((float)row - yoffset) * (iconSize + iconSpacing);
+ float ty1 = ty2 - tmpCos * iconSize;
+
+ float tz1 = z + tmpSin * iconSize;
+ float tz2 = z;
+
+ float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz1,
+ tx2, ty2, tz2,
+ tx1, ty2, tz2);
+ index++;
+ }
+ }
+
+ // Top roller
+ {
+ index = (((int)pos) * 4) - 4;
+ float roll = yoffset * 0.5f * 3.14f;
+ float tmpSin = sinf(roll);
+ float tmpCos = cosf(roll);
+
+ for (col = 0; (col < 4) && (index < iconCount) && (index >= 0); col ++) {
+ float ty1 = (gridSize / 2.f) - ((float)-1.f - yoffset) * (iconSize + iconSpacing) - iconSize;
+ float ty2 = ty1 + tmpCos * iconSize;
+
+ float tz1 = z;
+ float tz2 = z + tmpSin * iconSize;
+
+ float tx1 = xoffset + (-gridSize / 2.f) + ((float)col * (iconSize + iconSpacing));
+ float tx2 = tx1 + iconSize;
+
+ bindTexture(NAMED_PF, 0, loadI32(1, index));
+ drawQuad(tx1, ty1, tz1,
+ tx2, ty1, tz1,
+ tx2, ty2, tz2,
+ tx1, ty2, tz2);
+ index++;
+ }
+ }
+
+
+
+
+ return 1;
+}
+
+
+
diff --git a/libs/rs/java/Rollo/res/raw/settings.png b/libs/rs/java/Rollo/res/raw/settings.png
new file mode 100644
index 0000000..dd2cd95
--- /dev/null
+++ b/libs/rs/java/Rollo/res/raw/settings.png
Binary files differ
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/Rollo.java b/libs/rs/java/Rollo/src/com/android/rollo/Rollo.java
new file mode 100644
index 0000000..400d801
--- /dev/null
+++ b/libs/rs/java/Rollo/src/com/android/rollo/Rollo.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rollo;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+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 Rollo 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 RolloView 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 RolloView(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/Rollo/src/com/android/rollo/RolloRS.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
new file mode 100644
index 0000000..ba74b58
--- /dev/null
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
@@ -0,0 +1,315 @@
+/*
+ * 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.rollo;
+
+import java.io.Writer;
+
+import android.renderscript.RenderScript;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Element;
+import android.renderscript.Allocation;
+import android.renderscript.Script;
+import android.renderscript.ScriptC;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.Sampler;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.Typeface;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+public class RolloRS {
+ //public static final int STATE_SELECTED_ID = 0;
+ public static final int STATE_DONE = 1;
+ //public static final int STATE_PRESSURE = 2;
+ public static final int STATE_ZOOM = 3;
+ //public static final int STATE_WARP = 4;
+ public static final int STATE_ORIENTATION = 5;
+ public static final int STATE_SELECTION = 6;
+ public static final int STATE_FIRST_VISIBLE = 7;
+ public static final int STATE_COUNT = 8;
+ public static final int STATE_TOUCH = 9;
+
+
+ public RolloRS() {
+ }
+
+ public void init(RenderScript rs, Resources res, int width, int height) {
+ mRS = rs;
+ mRes = res;
+ mWidth = width;
+ mHeight = height;
+ initNamed();
+ initRS();
+ }
+
+ public void setPosition(float column) {
+ mAllocStateBuf[STATE_FIRST_VISIBLE] = (int)(column * (-20));
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ public void setTouch(boolean touch) {
+ mAllocStateBuf[STATE_TOUCH] = touch ? 1 : 0;
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ public void setZoom(float z) {
+ //Log.e("rs", "zoom " + Float.toString(z));
+
+ mAllocStateBuf[STATE_ZOOM] = (int)(z * 1000.f);
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ public void setSelected(int index) {
+ //Log.e("rs", "setSelected " + Integer.toString(index));
+
+ mAllocStateBuf[STATE_SELECTION] = index;
+ mAllocStateBuf[STATE_DONE] = 1;
+ mAllocState.data(mAllocStateBuf);
+ }
+
+ private int mWidth;
+ private int mHeight;
+
+ private Resources mRes;
+ private RenderScript mRS;
+ private Script mScript;
+ private Sampler mSampler;
+ private Sampler mSamplerText;
+ private ProgramStore mPSBackground;
+ private ProgramStore mPSText;
+ private ProgramFragment mPFImages;
+ private ProgramFragment mPFText;
+ private ProgramVertex mPV;
+ private ProgramVertex.MatrixAllocation mPVAlloc;
+ private ProgramVertex mPVOrtho;
+ private ProgramVertex.MatrixAllocation mPVOrthoAlloc;
+ private Allocation[] mIcons;
+ private Allocation[] mLabels;
+
+ private int[] mAllocStateBuf;
+ private Allocation mAllocState;
+
+ private int[] mAllocIconIDBuf;
+ private Allocation mAllocIconID;
+
+ private int[] mAllocLabelIDBuf;
+ private Allocation mAllocLabelID;
+
+ private int[] mAllocScratchBuf;
+ private Allocation mAllocScratch;
+
+ private void initNamed() {
+ Sampler.Builder sb = new Sampler.Builder(mRS);
+ sb.setMin(Sampler.Value.LINEAR);//_MIP_LINEAR);
+ sb.setMag(Sampler.Value.LINEAR);
+ sb.setWrapS(Sampler.Value.CLAMP);
+ sb.setWrapT(Sampler.Value.CLAMP);
+ mSampler = sb.create();
+
+ sb.setMin(Sampler.Value.NEAREST);
+ sb.setMag(Sampler.Value.NEAREST);
+ mSamplerText = sb.create();
+
+
+ ProgramFragment.Builder bf = new ProgramFragment.Builder(mRS, null, null);
+ bf.setTexEnable(true, 0);
+ bf.setTexEnvMode(ProgramFragment.EnvMode.MODULATE, 0);
+ mPFImages = bf.create();
+ mPFImages.setName("PF");
+ mPFImages.bindSampler(mSampler, 0);
+
+ bf.setTexEnvMode(ProgramFragment.EnvMode.MODULATE, 0);
+ mPFText = bf.create();
+ mPFText.setName("PFText");
+ mPFText.bindSampler(mSamplerText, 0);
+
+ ProgramStore.Builder bs = new ProgramStore.Builder(mRS, null, null);
+ bs.setDepthFunc(ProgramStore.DepthFunc.LESS);
+ bs.setDitherEnable(false);
+ bs.setDepthMask(true);
+ bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
+ ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+ mPSBackground = bs.create();
+ mPSBackground.setName("PFS");
+
+ bs.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+ bs.setDepthMask(false);
+ bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
+ ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+ mPSText = bs.create();
+ mPSText.setName("PFSText");
+
+ mPVAlloc = new ProgramVertex.MatrixAllocation(mRS);
+ mPVAlloc.setupProjectionNormalized(mWidth, mHeight);
+
+ ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
+ mPV = pvb.create();
+ mPV.setName("PV");
+ mPV.bindAllocation(mPVAlloc);
+
+ mPVOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
+ mPVOrthoAlloc.setupOrthoWindow(mWidth, mHeight);
+
+ pvb.setTextureMatrixEnable(true);
+ mPVOrtho = pvb.create();
+ mPVOrtho.setName("PVOrtho");
+ mPVOrtho.bindAllocation(mPVOrthoAlloc);
+
+ mRS.contextBindProgramVertex(mPV);
+
+ mAllocScratchBuf = new int[32];
+ mAllocScratch = Allocation.createSized(mRS,
+ Element.USER_I32, mAllocScratchBuf.length);
+ mAllocScratch.data(mAllocScratchBuf);
+
+ Log.e("rs", "Done loading named");
+
+
+
+ {
+ mIcons = new Allocation[29];
+ mAllocIconIDBuf = new int[mIcons.length];
+ mAllocIconID = Allocation.createSized(mRS,
+ Element.USER_I32, mAllocIconIDBuf.length);
+
+ mLabels = new Allocation[29];
+ mAllocLabelIDBuf = new int[mLabels.length];
+ mAllocLabelID = Allocation.createSized(mRS,
+ Element.USER_I32, mLabels.length);
+
+ Element ie8888 = Element.RGBA_8888;
+
+ mIcons[0] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.browser, ie8888, true);
+ mIcons[1] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.market, ie8888, true);
+ mIcons[2] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.photos, ie8888, true);
+ mIcons[3] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.settings, ie8888, true);
+ mIcons[4] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.calendar, ie8888, true);
+ mIcons[5] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.g1155, ie8888, true);
+ mIcons[6] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.g2140, ie8888, true);
+ mIcons[7] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.maps, ie8888, true);
+ mIcons[8] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path431, ie8888, true);
+ mIcons[9] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path676, ie8888, true);
+ mIcons[10] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path754, ie8888, true);
+ mIcons[11] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path815, ie8888, true);
+ mIcons[12] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path1920, ie8888, true);
+ mIcons[13] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path1927, ie8888, true);
+ mIcons[14] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path3099, ie8888, true);
+ mIcons[15] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path3950, ie8888, true);
+ mIcons[16] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path4481, ie8888, true);
+ mIcons[17] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.path5168, ie8888, true);
+ mIcons[18] = Allocation.createFromBitmapResource(mRS, mRes, R.raw.polygon2408, ie8888, true);
+
+ mLabels[0] = makeTextBitmap("browser");
+ mLabels[1] = makeTextBitmap("market");
+ mLabels[2] = makeTextBitmap("photos");
+ mLabels[3] = makeTextBitmap("settings");
+ mLabels[4] = makeTextBitmap("calendar");
+ mLabels[5] = makeTextBitmap("g1155");
+ mLabels[6] = makeTextBitmap("g2140");
+ mLabels[7] = makeTextBitmap("maps");
+ mLabels[8] = makeTextBitmap("path431");
+ mLabels[9] = makeTextBitmap("path676");
+ mLabels[10] = makeTextBitmap("path754");
+ mLabels[11] = makeTextBitmap("path815");
+ mLabels[12] = makeTextBitmap("path1920");
+ mLabels[13] = makeTextBitmap("path1927");
+ mLabels[14] = makeTextBitmap("path3099");
+ mLabels[15] = makeTextBitmap("path3950");
+ mLabels[16] = makeTextBitmap("path4481");
+ mLabels[17] = makeTextBitmap("path5168");
+ mLabels[18] = makeTextBitmap("polygon2408");
+
+ mIcons[19] = mIcons[0];
+ mIcons[20] = mIcons[1];
+ mIcons[21] = mIcons[2];
+ mIcons[22] = mIcons[3];
+ mIcons[23] = mIcons[4];
+ mIcons[24] = mIcons[5];
+ mIcons[25] = mIcons[6];
+ mIcons[26] = mIcons[7];
+ mIcons[27] = mIcons[8];
+ mIcons[28] = mIcons[9];
+
+ mLabels[19] = mLabels[0];
+ mLabels[20] = mLabels[1];
+ mLabels[21] = mLabels[2];
+ mLabels[22] = mLabels[3];
+ mLabels[23] = mLabels[4];
+ mLabels[24] = mLabels[5];
+ mLabels[25] = mLabels[6];
+ mLabels[26] = mLabels[7];
+ mLabels[27] = mLabels[8];
+ mLabels[28] = mLabels[9];
+
+ for(int ct=0; ct < mIcons.length; ct++) {
+ mIcons[ct].uploadToTexture(0);
+ mLabels[ct].uploadToTexture(0);
+ mAllocIconIDBuf[ct] = mIcons[ct].getID();
+ mAllocLabelIDBuf[ct] = mLabels[ct].getID();
+ }
+ mAllocIconID.data(mAllocIconIDBuf);
+ mAllocLabelID.data(mAllocLabelIDBuf);
+ }
+
+ }
+
+ Allocation makeTextBitmap(String t) {
+ Bitmap b = Bitmap.createBitmap(128, 32, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(b);
+ Paint p = new Paint();
+ p.setTypeface(Typeface.DEFAULT_BOLD);
+ p.setTextSize(20);
+ p.setColor(0xffffffff);
+ c.drawText(t, 2, 26, p);
+ return Allocation.createFromBitmap(mRS, b, Element.RGBA_8888, true);
+ }
+
+
+ private void initRS() {
+ ScriptC.Builder sb = new ScriptC.Builder(mRS);
+ sb.setScript(mRes, R.raw.rollo);
+ //sb.setScript(mRes, R.raw.rollo2);
+ sb.setRoot(true);
+ mScript = sb.create();
+ mScript.setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, -1, 0, mAllocIconIDBuf.length, 0, 0};
+ mAllocState = Allocation.createSized(mRS,
+ Element.USER_I32, mAllocStateBuf.length);
+ mScript.bindAllocation(mAllocState, 0);
+ mScript.bindAllocation(mAllocIconID, 1);
+ mScript.bindAllocation(mAllocScratch, 2);
+ mScript.bindAllocation(mAllocLabelID, 3);
+ setPosition(0);
+ setZoom(1);
+
+ //RenderScript.File f = mRS.fileOpen("/sdcard/test.a3d");
+
+ mRS.contextBindRootScript(mScript);
+ }
+}
+
+
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
new file mode 100644
index 0000000..7524a0e
--- /dev/null
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloView.java
@@ -0,0 +1,214 @@
+/*
+ * 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.rollo;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import java.lang.Float;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.graphics.PixelFormat;
+
+
+public class RolloView extends RSSurfaceView {
+ public RolloView(Context context) {
+ super(context);
+ setFocusable(true);
+ getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+
+ private RenderScript mRS;
+ private RolloRS mRender;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+
+ mRS = createRenderScript(false);
+ mRender = new RolloRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+
+ @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);
+ }
+
+ boolean mControlMode = false;
+ boolean mZoomMode = false;
+ boolean mFlingMode = false;
+ float mFlingX = 0;
+ float mFlingY = 0;
+ float mColumn = -1;
+ float mOldColumn;
+ float mZoom = 1;
+
+ int mIconCount = 29;
+ int mRows = 4;
+ int mColumns = (mIconCount + mRows - 1) / mRows;
+
+ float mMaxZoom = ((float)mColumns) / 3.f;
+
+
+ void setColumn(boolean clamp)
+ {
+ //Log.e("rs", " col = " + Float.toString(mColumn));
+ float c = mColumn;
+ if(c > (mColumns -2)) {
+ c = (mColumns -2);
+ }
+ if(c < 0) {
+ c = 0;
+ }
+ mRender.setPosition(c);
+ if(clamp) {
+ mColumn = c;
+ }
+ }
+
+ void computeSelection(float x, float y)
+ {
+ float col = mColumn + (x - 0.5f) * 4 + 1.25f;
+ int iCol = (int)(col + 0.25f);
+
+ float row = (y / 0.8f) * mRows;
+ int iRow = (int)(row - 0.5f);
+
+ mRender.setSelected(iCol * mRows + iRow);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ boolean ret = true;
+ int act = ev.getAction();
+ if (act == ev.ACTION_UP) {
+ ret = false;
+ }
+
+ float nx = ev.getX() / getWidth();
+ float ny = ev.getY() / getHeight();
+
+ //Log.e("rs", "width=" + Float.toString(getWidth()));
+ //Log.e("rs", "height=" + Float.toString(getHeight()));
+
+ mRender.setTouch(ret);
+
+ if((ny > 0.85f) || mControlMode) {
+ mFlingMode = false;
+
+ // Projector control
+ if((nx > 0.2f) && (nx < 0.8f) || mControlMode) {
+ if(act != ev.ACTION_UP) {
+ float zoom = mMaxZoom;
+ if(mControlMode) {
+ if(!mZoomMode) {
+ zoom = 1.f;
+ }
+ float dx = nx - mFlingX;
+
+ if((ny < 0.9) && mZoomMode) {
+ zoom = mMaxZoom - ((0.9f - ny) * 10.f);
+ if(zoom < 1) {
+ zoom = 1;
+ mZoomMode = false;
+ }
+ mOldColumn = mColumn;
+ }
+ mColumn += dx * 4;// * zoom;
+ if(zoom > 1.01f) {
+ mColumn += (mZoom - zoom) * (nx - 0.5f) * 4 * zoom;
+ }
+ } else {
+ mOldColumn = mColumn;
+ mColumn = ((float)mColumns) / 2;
+ mControlMode = true;
+ mZoomMode = true;
+ }
+ mZoom = zoom;
+ mFlingX = nx;
+ mRender.setZoom(zoom);
+ if(mZoom < 1.01f) {
+ computeSelection(nx, ny);
+ }
+ } else {
+ mControlMode = false;
+ mColumn = mOldColumn;
+ mRender.setZoom(1.f);
+ mRender.setSelected(-1);
+ }
+ } else {
+ // Do something with corners here....
+ }
+ setColumn(true);
+
+ } else {
+ // icon control
+ if(act != ev.ACTION_UP) {
+ if(mFlingMode) {
+ mColumn += (mFlingX - nx) * 4;
+ setColumn(true);
+ }
+ mFlingMode = true;
+ mFlingX = nx;
+ mFlingY = ny;
+ } else {
+ mFlingMode = false;
+ mColumn = (float)(java.lang.Math.floor(mColumn * 0.25f + 0.3f) * 4.f) + 1.f;
+ setColumn(true);
+ }
+ }
+
+
+ return ret;
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent ev)
+ {
+ float x = ev.getX();
+ float y = ev.getY();
+ //Float tx = new Float(x);
+ //Float ty = new Float(y);
+ //Log.e("rs", "tbe " + tx.toString() + ", " + ty.toString());
+
+
+ return true;
+ }
+
+}
+
+
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
new file mode 100644
index 0000000..cb4dd00
--- /dev/null
+++ b/libs/rs/rs.spec
@@ -0,0 +1,482 @@
+
+
+ContextBindRootScript {
+ param RsScript sampler
+ }
+
+ContextBindProgramFragmentStore {
+ param RsProgramFragmentStore pgm
+ }
+
+ContextBindProgramFragment {
+ param RsProgramFragment pgm
+ }
+
+ContextBindProgramVertex {
+ param RsProgramVertex pgm
+ }
+
+ContextSetDefineF {
+ param const char* name
+ param float value
+ }
+
+ContextSetDefineI32 {
+ param const char* name
+ param int32_t value
+ }
+
+AssignName {
+ param void *obj
+ param const char *name
+ param size_t len
+ }
+
+ObjDestroy {
+ param void *obj
+ }
+
+ElementBegin {
+}
+
+ElementAddPredefined {
+ param RsElementPredefined predef
+ }
+
+ElementAdd {
+ param RsDataKind dataKind
+ param RsDataType dataType
+ param bool isNormalized
+ param size_t bits
+ param const char * name
+ }
+
+ElementCreate {
+ ret RsElement
+ }
+
+ElementGetPredefined {
+ param RsElementPredefined predef
+ ret RsElement
+ }
+
+TypeBegin {
+ param RsElement type
+ }
+
+TypeAdd {
+ param RsDimension dim
+ param size_t value
+ }
+
+TypeCreate {
+ ret RsType
+ }
+
+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
+ }
+
+AllocationCreateFromBitmapBoxed {
+ 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
+ }
+
+
+AllocationData {
+ param RsAllocation va
+ param const void * data
+ param uint32_t bytes
+ handcodeApi
+ togglePlay
+ }
+
+Allocation1DSubData {
+ param RsAllocation va
+ param uint32_t xoff
+ param uint32_t count
+ param const void *data
+ param uint32_t bytes
+ handcodeApi
+ togglePlay
+ }
+
+Allocation2DSubData {
+ param RsAllocation va
+ param uint32_t xoff
+ param uint32_t yoff
+ param uint32_t w
+ param uint32_t h
+ param const void *data
+ param uint32_t bytes
+ }
+
+AllocationRead {
+ param RsAllocation va
+ param void * data
+ }
+
+Adapter1DCreate {
+ ret RsAdapter1D
+ }
+
+Adapter1DBindAllocation {
+ param RsAdapter1D adapt
+ param RsAllocation alloc
+ }
+
+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
+ }
+
+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
+ }
+
+
+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
+ }
+
+
+TriangleMeshRender {
+ param RsTriangleMesh vtm
+ }
+
+TriangleMeshRenderRange {
+ param RsTriangleMesh vtm
+ param uint32_t start
+ param uint32_t count
+ }
+
+
+ScriptBindAllocation {
+ param RsScript vtm
+ param RsAllocation va
+ param uint32_t slot
+ }
+
+
+ScriptCBegin {
+ }
+
+ScriptSetClearColor {
+ param RsScript s
+ param float r
+ param float g
+ param float b
+ param float a
+ }
+
+ScriptSetTimeZone {
+ param RsScript s
+ param const char * timeZone
+ param uint32_t length
+ }
+
+ScriptSetClearDepth {
+ param RsScript s
+ param float depth
+ }
+
+ScriptSetClearStencil {
+ param RsScript s
+ param uint32_t stencil
+ }
+
+ScriptSetType {
+ param RsType type
+ param uint32_t slot
+ param bool isWritable
+ param const char * name
+ }
+
+ScriptSetRoot {
+ param bool isRoot
+ }
+
+
+
+ScriptCSetScript {
+ param void * codePtr
+ }
+
+ScriptCSetText {
+ param const char * text
+ param uint32_t length
+ }
+
+ScriptCCreate {
+ ret RsScript
+ }
+
+ScriptCSetDefineF {
+ param const char* name
+ param float value
+ }
+
+ScriptCSetDefineI32 {
+ param const char* name
+ param int32_t value
+ }
+
+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
+ param bool pointSpriteEnable
+ }
+
+ProgramFragmentBindTexture {
+ param RsProgramFragment pf
+ param uint32_t slot
+ param RsAllocation a
+ }
+
+ProgramFragmentBindSampler {
+ param RsProgramFragment pf
+ param uint32_t slot
+ param RsSampler s
+ }
+
+ProgramFragmentSetSlot {
+ param uint32_t slot
+ param bool enable
+ param RsTexEnvMode env
+ param RsType t
+ }
+
+ProgramFragmentCreate {
+ ret RsProgramFragment
+ }
+
+
+ProgramVertexBegin {
+ param RsElement in
+ param RsElement out
+ }
+
+ProgramVertexCreate {
+ ret RsProgramVertex
+ }
+
+ProgramVertexBindAllocation {
+ param RsProgramVertex vpgm
+ param RsAllocation constants
+ }
+
+ProgramVertexSetTextureMatrixEnable {
+ param bool enable
+ }
+
+ProgramVertexAddLight {
+ param RsLight light
+ }
+
+LightBegin {
+ }
+
+LightSetLocal {
+ param bool isLocal
+ }
+
+LightSetMonochromatic {
+ param bool isMono
+ }
+
+LightCreate {
+ ret RsLight light
+ }
+
+
+LightSetPosition {
+ param RsLight light
+ param float x
+ param float y
+ param float z
+ }
+
+LightSetColor {
+ param RsLight light
+ param float r
+ param float g
+ param float b
+ }
+
+FileOpen {
+ ret RsFile
+ param const char *name
+ param size_t len
+ }
+
+
+SimpleMeshCreate {
+ ret RsSimpleMesh
+ param RsAllocation prim
+ param RsAllocation index
+ param RsAllocation *vtx
+ param uint32_t vtxCount
+ param uint32_t primType
+ }
+
+
+SimpleMeshBindIndex {
+ param RsSimpleMesh mesh
+ param RsAllocation idx
+ }
+
+SimpleMeshBindPrimitive {
+ param RsSimpleMesh mesh
+ param RsAllocation prim
+ }
+
+SimpleMeshBindVertex {
+ param RsSimpleMesh mesh
+ param RsAllocation vtx
+ param uint32_t slot
+ }
+
diff --git a/libs/rs/rsAdapter.cpp b/libs/rs/rsAdapter.cpp
new file mode 100644
index 0000000..d20e910
--- /dev/null
+++ b/libs/rs/rsAdapter.cpp
@@ -0,0 +1,237 @@
+
+/*
+ * 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)
+{
+ Adapter1D *a = new Adapter1D();
+ a->incUserRef();
+ return a;
+}
+
+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)
+{
+ Adapter2D *a = new Adapter2D();
+ a->incUserRef();
+ return a;
+}
+
+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..1f49ca1
--- /dev/null
+++ b/libs/rs/rsAllocation.cpp
@@ -0,0 +1,552 @@
+/*
+ * 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>
+
+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);
+ rsAssert(type);
+ mPtr = malloc(mType->getSizeBytes());
+ if (!mPtr) {
+ LOGE("Allocation::Allocation, alloc failure");
+ }
+}
+
+Allocation::~Allocation()
+{
+}
+
+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());
+
+ 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());
+
+ 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, uint32_t sizeBytes)
+{
+ uint32_t size = mType->getSizeBytes();
+ if (size != sizeBytes) {
+ LOGE("Allocation::data called with mismatched size expected %i, got %i", size, sizeBytes);
+ return;
+ }
+ memcpy(mPtr, data, size);
+}
+
+void Allocation::read(void *data)
+{
+ memcpy(data, mPtr, mType->getSizeBytes());
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
+{
+ uint32_t eSize = mType->getElementSizeBytes();
+ uint8_t * ptr = static_cast<uint8_t *>(mPtr);
+ ptr += eSize * xoff;
+ uint32_t size = count * eSize;
+
+ if (size != sizeBytes) {
+ LOGE("Allocation::subData called with mismatched size expected %i, got %i", size, sizeBytes);
+ return;
+ }
+ memcpy(ptr, data, size);
+}
+
+void Allocation::subData(uint32_t xoff, uint32_t yoff,
+ uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
+{
+ 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);
+
+ if ((lineSize * eSize * h) != sizeBytes) {
+ rsAssert(!"Allocation::subData called with mismatched size");
+ return;
+ }
+
+ 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, uint32_t sizeBytes)
+{
+}
+
+
+
+/////////////////
+//
+
+
+namespace android {
+namespace renderscript {
+
+RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype)
+{
+ const Type * type = static_cast<const Type *>(vtype);
+
+ Allocation * alloc = new Allocation(type);
+ alloc->incUserRef();
+ 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();
+}
+
+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 < h; 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 < w; 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 < h; 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 < w; x++) {
+ *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
+ oPtr ++;
+ i1 += 2;
+ i2 += 2;
+ }
+ }
+}
+
+static void mip(const Adapter2D &out, const Adapter2D &in)
+{
+ switch(out.getBaseType()->getElement()->getSizeBits()) {
+ case 32:
+ mip8888(out, in);
+ break;
+ case 16:
+ mip565(out, in);
+ break;
+
+ }
+
+}
+
+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, src %i, dst %i", srcFmt, dstFmt);
+ return 0;
+}
+
+
+RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
+{
+ rsAssert(!(w & (w-1)));
+ rsAssert(!(h & (h-1)));
+
+ //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips);
+ rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, dstFmt));
+ 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->incUserRef();
+
+ 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);
+ mip(adapt2, adapt);
+ }
+ }
+
+ return texAlloc;
+}
+
+static uint32_t fmtToBits(RsElementPredefined fmt)
+{
+ return 16;
+}
+
+RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data)
+{
+ uint32_t w2 = rsHigherPow2(w);
+ uint32_t h2 = rsHigherPow2(h);
+
+ if ((w2 == w) && (h2 == h)) {
+ return rsi_AllocationCreateFromBitmap(rsc, w, h, dstFmt, srcFmt, genMips, data);
+ }
+
+ uint32_t bpp = fmtToBits(srcFmt) >> 3;
+ size_t size = w2 * h2 * bpp;
+ uint8_t *tmp = static_cast<uint8_t *>(malloc(size));
+ memset(tmp, 0, size);
+
+ const uint8_t * src = static_cast<const uint8_t *>(data);
+ for (uint32_t y = 0; y < h; y++) {
+ uint8_t * ydst = &tmp[(y + ((h2 - h) >> 1)) * w2 * bpp];
+ memcpy(&ydst[(w2 - w) >> 1], src, w * bpp);
+ src += w * bpp;
+ }
+
+ RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, dstFmt, srcFmt, genMips, tmp);
+ free(tmp);
+ return ret;
+
+
+
+
+}
+
+
+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->incUserRef();
+ 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);
+ mip(adapt2, adapt);
+ }
+ }
+
+ return texAlloc;
+}
+
+void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->data(data, sizeBytes);
+ rsc->allocationCheck(a);
+}
+
+void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->subData(xoff, count, data, sizeBytes);
+ rsc->allocationCheck(a);
+}
+
+void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->subData(xoff, yoff, w, h, data, sizeBytes);
+ rsc->allocationCheck(a);
+}
+
+void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
+{
+ Allocation *a = static_cast<Allocation *>(va);
+ a->read(data);
+}
+
+
+}
+}
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
new file mode 100644
index 0000000..1f58ec5
--- /dev/null
+++ b/libs/rs/rsAllocation.h
@@ -0,0 +1,101 @@
+/*
+ * 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, uint32_t sizeBytes);
+ void subData(uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes);
+ void subData(uint32_t xoff, uint32_t yoff,
+ uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes);
+ void subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
+ uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes);
+
+ void read(void *data);
+
+ void enableGLVertexBuffers() const;
+ void setupGLIndexBuffers() const;
+
+
+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..4a043f3
--- /dev/null
+++ b/libs/rs/rsComponent.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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"
+#include <GLES/gl.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Component::Component()
+{
+ mType = FLOAT;
+ mKind = USER;
+ mIsNormalized = false;
+ mBits = 0;
+}
+
+Component::Component(
+ DataKind dk, DataType dt,
+ bool isNormalized, uint32_t bits, const char * name)
+{
+ mType = dt;
+ mKind = dk;
+ mIsNormalized = isNormalized;
+ mBits = bits;
+ if (name) {
+ mName = name;
+ }
+}
+
+const char * Component::getCType() const
+{
+ switch(mType) {
+ case FLOAT:
+ return "float";
+ case SIGNED:
+ case UNSIGNED:
+ switch(mBits) {
+ case 32:
+ return "int";
+ case 16:
+ return "short";
+ case 8:
+ return "char";
+ }
+ break;
+ }
+ return NULL;
+}
+
+Component::~Component()
+{
+}
+
+uint32_t Component::getGLType() const
+{
+ switch(mType) {
+ case RS_TYPE_FLOAT:
+ rsAssert(mBits == 32);
+ return GL_FLOAT;
+ case RS_TYPE_SIGNED:
+ switch(mBits) {
+ case 32:
+ return 0;//GL_INT;
+ case 16:
+ return GL_SHORT;
+ case 8:
+ return GL_BYTE;
+ }
+ break;
+ case RS_TYPE_UNSIGNED:
+ switch(mBits) {
+ case 32:
+ return 0;//GL_UNSIGNED_INT;
+ case 16:
+ return GL_UNSIGNED_SHORT;
+ case 8:
+ return GL_UNSIGNED_BYTE;
+ }
+ break;
+ }
+ //rsAssert(!"Bad type");
+ //LOGE("mType %i, mKind %i, mBits %i, mIsNormalized %i", mType, mKind, mBits, mIsNormalized);
+ return 0;
+}
+
+
diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h
new file mode 100644
index 0000000..5856524
--- /dev/null
+++ b/libs/rs/rsComponent.h
@@ -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.
+ */
+
+#ifndef ANDROID_RS_STRUCTURED_COMPONENT_H
+#define ANDROID_RS_STRUCTURED_COMPONENT_H
+
+#include "rsUtils.h"
+#include "rsObjectBase.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Component : public ObjectBase
+{
+public:
+ enum DataType {
+ FLOAT,
+ UNSIGNED,
+ SIGNED
+ };
+
+ enum DataKind {
+ USER,
+ RED, GREEN, BLUE, ALPHA, LUMINANCE, INTENSITY,
+ X, Y, Z, W,
+ S, T, Q, R,
+ NX, NY, NZ,
+ INDEX,
+ POINT_SIZE
+ };
+
+
+ Component(DataKind dk, DataType dt, bool isNorm, uint32_t bits, const char *);
+ virtual ~Component();
+
+ DataType getType() const {return mType;}
+ bool getIsNormalized() const {return mIsNormalized;}
+ DataKind getKind() const {return mKind;}
+ uint32_t getBits() const {return mBits;}
+
+ uint32_t getGLType() const;
+ const char * getCType() const;
+
+ const char * getComponentName() const {return mName.string();}
+
+protected:
+
+ DataType mType;
+ bool mIsNormalized;
+ DataKind mKind;
+ uint32_t mBits;
+ String8 mName;
+
+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..c28bd02
--- /dev/null
+++ b/libs/rs/rsContext.cpp
@@ -0,0 +1,561 @@
+/*
+ * 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"
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+pthread_key_t Context::gThreadTLSKey = 0;
+
+void Context::initEGL()
+{
+ mEGL.mNumConfigs = -1;
+ EGLint configAttribs[128];
+ EGLint *configAttribsPtr = configAttribs;
+
+ memset(configAttribs, 0, sizeof(configAttribs));
+
+ configAttribsPtr[0] = EGL_SURFACE_TYPE;
+ configAttribsPtr[1] = EGL_WINDOW_BIT;
+ configAttribsPtr += 2;
+
+ if (mUseDepth) {
+ configAttribsPtr[0] = EGL_DEPTH_SIZE;
+ configAttribsPtr[1] = 16;
+ configAttribsPtr += 2;
+ }
+
+ configAttribsPtr[0] = EGL_NONE;
+ rsAssert(configAttribsPtr < (configAttribs + (sizeof(configAttribs) / sizeof(EGLint))));
+
+ mEGL.mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(mEGL.mDisplay, &mEGL.mMajorVersion, &mEGL.mMinorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(mEGL.mDisplay, configAttribs, mWndSurface, &mEGL.mConfig);
+ if (err) {
+ LOGE("couldn't find an EGLConfig matching the screen format\n");
+ }
+ //eglChooseConfig(mEGL.mDisplay, configAttribs, &mEGL.mConfig, 1, &mEGL.mNumConfigs);
+
+ if (mWndSurface) {
+ mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig, mWndSurface, NULL);
+ } else {
+ mEGL.mSurface = eglCreateWindowSurface(mEGL.mDisplay, mEGL.mConfig,
+ android_createDisplaySurface(),
+ NULL);
+ }
+
+ mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, NULL, NULL);
+ eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext);
+ eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth);
+ eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight);
+
+
+ mGL.mVersion = glGetString(GL_VERSION);
+ mGL.mVendor = glGetString(GL_VENDOR);
+ mGL.mRenderer = glGetString(GL_RENDERER);
+ mGL.mExtensions = glGetString(GL_EXTENSIONS);
+
+ LOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
+ LOGV("GL Version %s", mGL.mVersion);
+ LOGV("GL Vendor %s", mGL.mVendor);
+ LOGV("GL Renderer %s", mGL.mRenderer);
+ LOGV("GL Extensions %s", mGL.mExtensions);
+
+ if ((strlen((const char *)mGL.mVersion) < 12) || memcmp(mGL.mVersion, "OpenGL ES-CM", 12)) {
+ LOGE("Error, OpenGL ES Lite not supported");
+ } else {
+ sscanf((const char *)mGL.mVersion + 13, "%i.%i", &mGL.mMajorVersion, &mGL.mMinorVersion);
+ }
+}
+
+bool Context::runScript(Script *s, uint32_t launchID)
+{
+ ObjectBaseRef<ProgramFragment> frag(mFragment);
+ ObjectBaseRef<ProgramVertex> vtx(mVertex);
+ ObjectBaseRef<ProgramFragmentStore> store(mFragmentStore);
+
+ bool ret = s->run(this, launchID);
+
+ mFragment.set(frag);
+ mVertex.set(vtx);
+ mFragmentStore.set(store);
+ return ret;
+}
+
+
+bool Context::runRootScript()
+{
+#if RS_LOG_TIMES
+ timerSet(RS_TIMER_CLEAR_SWAP);
+#endif
+ rsAssert(mRootScript->mEnviroment.mIsRoot);
+
+ //glColor4f(1,1,1,1);
+ //glEnable(GL_LIGHT0);
+ glViewport(0, 0, mEGL.mWidth, mEGL.mHeight);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ glClearColor(mRootScript->mEnviroment.mClearColor[0],
+ mRootScript->mEnviroment.mClearColor[1],
+ mRootScript->mEnviroment.mClearColor[2],
+ mRootScript->mEnviroment.mClearColor[3]);
+ if (mUseDepth) {
+ glDepthMask(GL_TRUE);
+ glClearDepthf(mRootScript->mEnviroment.mClearDepth);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ } else {
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+#if RS_LOG_TIMES
+ timerSet(RS_TIMER_SCRIPT);
+#endif
+ bool ret = runScript(mRootScript.get(), 0);
+ return ret;
+}
+
+uint64_t Context::getTime() const
+{
+ struct timespec t;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return t.tv_nsec + ((uint64_t)t.tv_sec * 1000 * 1000 * 1000);
+}
+
+void Context::timerReset()
+{
+ for (int ct=0; ct < _RS_TIMER_TOTAL; ct++) {
+ mTimers[ct] = 0;
+ }
+}
+
+void Context::timerInit()
+{
+ mTimeLast = getTime();
+ mTimerActive = RS_TIMER_INTERNAL;
+ timerReset();
+}
+
+void Context::timerSet(Timers tm)
+{
+ uint64_t last = mTimeLast;
+ mTimeLast = getTime();
+ mTimers[mTimerActive] += mTimeLast - last;
+ mTimerActive = tm;
+}
+
+void Context::timerPrint()
+{
+ double total = 0;
+ for (int ct = 0; ct < _RS_TIMER_TOTAL; ct++) {
+ total += mTimers[ct];
+ }
+
+ LOGV("RS Time Data: Idle %2.1f (%lli), Internal %2.1f (%lli), Script %2.1f (%lli), Clear & Swap %2.1f (%lli)",
+ 100.0 * mTimers[RS_TIMER_IDLE] / total, mTimers[RS_TIMER_IDLE] / 1000000,
+ 100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000,
+ 100.0 * mTimers[RS_TIMER_SCRIPT] / total, mTimers[RS_TIMER_SCRIPT] / 1000000,
+ 100.0 * mTimers[RS_TIMER_CLEAR_SWAP] / total, mTimers[RS_TIMER_CLEAR_SWAP] / 1000000);
+}
+
+void Context::setupCheck()
+{
+ if (mFragmentStore.get()) {
+ mFragmentStore->setupGL(this, &mStateFragmentStore);
+ }
+ if (mFragment.get()) {
+ mFragment->setupGL(this, &mStateFragment);
+ }
+ if (mVertex.get()) {
+ mVertex->setupGL(this, &mStateVertex);
+ }
+
+}
+
+
+void * Context::threadProc(void *vrsc)
+{
+ Context *rsc = static_cast<Context *>(vrsc);
+
+ rsc->initEGL();
+
+ ScriptTLSStruct *tlsStruct = new ScriptTLSStruct;
+ if (!tlsStruct) {
+ LOGE("Error allocating tls storage");
+ return NULL;
+ }
+ tlsStruct->mContext = rsc;
+ tlsStruct->mScript = NULL;
+ int status = pthread_setspecific(rsc->gThreadTLSKey, tlsStruct);
+ if (status) {
+ LOGE("pthread_setspecific %i", status);
+ }
+
+ rsc->mStateVertex.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->setVertex(NULL);
+ rsc->mStateFragment.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->setFragment(NULL);
+ rsc->mStateFragmentStore.init(rsc, rsc->mEGL.mWidth, rsc->mEGL.mHeight);
+ rsc->setFragmentStore(NULL);
+
+ rsc->mRunning = true;
+ bool mDraw = true;
+ while (!rsc->mExit) {
+ mDraw |= rsc->mIO.playCoreCommands(rsc, !mDraw);
+ mDraw &= (rsc->mRootScript.get() != NULL);
+
+ if (mDraw) {
+ mDraw = rsc->runRootScript();
+#if RS_LOG_TIMES
+ rsc->timerSet(RS_TIMER_CLEAR_SWAP);
+#endif
+ eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface);
+#if RS_LOG_TIMES
+ rsc->timerSet(RS_TIMER_INTERNAL);
+ rsc->timerPrint();
+ rsc->timerReset();
+#endif
+ }
+ if (rsc->mObjDestroy.mNeedToEmpty) {
+ rsc->objDestroyOOBRun();
+ }
+ }
+
+ LOGV("RS Thread exiting");
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface);
+ eglTerminate(rsc->mEGL.mDisplay);
+ rsc->objDestroyOOBRun();
+ LOGV("RS Thread exited");
+ return NULL;
+}
+
+Context::Context(Device *dev, Surface *sur, bool useDepth)
+{
+ dev->addContext(this);
+ mDev = dev;
+ mRunning = false;
+ mExit = false;
+ mUseDepth = useDepth;
+
+ int status;
+ pthread_attr_t threadAttr;
+
+ status = pthread_key_create(&gThreadTLSKey, NULL);
+ if (status) {
+ LOGE("Failed to init thread tls key.");
+ return;
+ }
+
+ 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);
+
+ mWndSurface = sur;
+
+ objDestroyOOBInit();
+ timerInit();
+
+ LOGV("RS Launching thread");
+ status = pthread_create(&mThreadId, &threadAttr, threadProc, this);
+ if (status) {
+ LOGE("Failed to start rs context thread.");
+ }
+
+ while(!mRunning) {
+ sleep(1);
+ }
+
+ pthread_attr_destroy(&threadAttr);
+}
+
+Context::~Context()
+{
+ LOGV("Context::~Context");
+ mExit = true;
+ void *res;
+
+ mIO.shutdown();
+ int status = pthread_join(mThreadId, &res);
+ objDestroyOOBRun();
+
+ if (mDev) {
+ mDev->removeContext(this);
+ pthread_key_delete(gThreadTLSKey);
+ }
+
+ objDestroyOOBDestroy();
+}
+
+void Context::setRootScript(Script *s)
+{
+ mRootScript.set(s);
+}
+
+void Context::setFragmentStore(ProgramFragmentStore *pfs)
+{
+ if (pfs == NULL) {
+ mFragmentStore.set(mStateFragmentStore.mDefault);
+ } else {
+ mFragmentStore.set(pfs);
+ }
+}
+
+void Context::setFragment(ProgramFragment *pf)
+{
+ if (pf == NULL) {
+ mFragment.set(mStateFragment.mDefault);
+ } else {
+ mFragment.set(pf);
+ }
+}
+
+void Context::allocationCheck(const Allocation *a)
+{
+ mVertex->checkUpdatedAllocation(a);
+ mFragment->checkUpdatedAllocation(a);
+ mFragmentStore->checkUpdatedAllocation(a);
+}
+
+void Context::setVertex(ProgramVertex *pv)
+{
+ if (pv == NULL) {
+ mVertex.set(mStateVertex.mDefault);
+ } else {
+ mVertex.set(pv);
+ }
+}
+
+void Context::assignName(ObjectBase *obj, const char *name, uint32_t len)
+{
+ rsAssert(!obj->getName());
+ obj->setName(name, len);
+ mNames.add(obj);
+}
+
+void Context::removeName(ObjectBase *obj)
+{
+ for(size_t ct=0; ct < mNames.size(); ct++) {
+ if (obj == mNames[ct]) {
+ mNames.removeAt(ct);
+ return;
+ }
+ }
+}
+
+ObjectBase * Context::lookupName(const char *name) const
+{
+ for(size_t ct=0; ct < mNames.size(); ct++) {
+ if (!strcmp(name, mNames[ct]->getName())) {
+ return mNames[ct];
+ }
+ }
+ return NULL;
+}
+
+void Context::appendNameDefines(String8 *str) const
+{
+ char buf[256];
+ for (size_t ct=0; ct < mNames.size(); ct++) {
+ str->append("#define NAMED_");
+ str->append(mNames[ct]->getName());
+ str->append(" ");
+ sprintf(buf, "%i\n", (int)mNames[ct]);
+ str->append(buf);
+ }
+}
+
+void Context::appendVarDefines(String8 *str) const
+{
+ char buf[256];
+ for (size_t ct=0; ct < mInt32Defines.size(); ct++) {
+ str->append("#define ");
+ str->append(mInt32Defines.keyAt(ct));
+ str->append(" ");
+ sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct));
+ str->append(buf);
+
+ }
+ for (size_t ct=0; ct < mFloatDefines.size(); ct++) {
+ str->append("#define ");
+ str->append(mFloatDefines.keyAt(ct));
+ str->append(" ");
+ sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct));
+ str->append(buf);
+ }
+}
+
+bool Context::objDestroyOOBInit()
+{
+ int status = pthread_mutex_init(&mObjDestroy.mMutex, NULL);
+ if (status) {
+ LOGE("Context::ObjDestroyOOBInit mutex init failure");
+ return false;
+ }
+ return true;
+}
+
+void Context::objDestroyOOBRun()
+{
+ if (mObjDestroy.mNeedToEmpty) {
+ int status = pthread_mutex_lock(&mObjDestroy.mMutex);
+ if (status) {
+ LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status);
+ return;
+ }
+
+ for (size_t ct = 0; ct < mObjDestroy.mDestroyList.size(); ct++) {
+ mObjDestroy.mDestroyList[ct]->decUserRef();
+ }
+ mObjDestroy.mDestroyList.clear();
+ mObjDestroy.mNeedToEmpty = false;
+
+ status = pthread_mutex_unlock(&mObjDestroy.mMutex);
+ if (status) {
+ LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status);
+ }
+ }
+}
+
+void Context::objDestroyOOBDestroy()
+{
+ rsAssert(!mObjDestroy.mNeedToEmpty);
+ pthread_mutex_destroy(&mObjDestroy.mMutex);
+}
+
+void Context::objDestroyAdd(ObjectBase *obj)
+{
+ int status = pthread_mutex_lock(&mObjDestroy.mMutex);
+ if (status) {
+ LOGE("Context::ObjDestroyOOBRun: error %i locking for OOBRun.", status);
+ return;
+ }
+
+ mObjDestroy.mNeedToEmpty = true;
+ mObjDestroy.mDestroyList.add(obj);
+
+ status = pthread_mutex_unlock(&mObjDestroy.mMutex);
+ if (status) {
+ LOGE("Context::ObjDestroyOOBRun: error %i unlocking for set condition.", status);
+ }
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//
+
+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);
+}
+
+void rsi_AssignName(Context *rsc, void * obj, const char *name, uint32_t len)
+{
+ ObjectBase *ob = static_cast<ObjectBase *>(obj);
+ rsc->assignName(ob, name, len);
+}
+
+void rsi_ObjDestroy(Context *rsc, void *obj)
+{
+ ObjectBase *ob = static_cast<ObjectBase *>(obj);
+ rsc->removeName(ob);
+ ob->decUserRef();
+}
+
+void rsi_ContextSetDefineF(Context *rsc, const char* name, float value)
+{
+ rsc->addInt32Define(name, value);
+}
+
+void rsi_ContextSetDefineI32(Context *rsc, const char* name, int32_t value)
+{
+ rsc->addFloatDefine(name, value);
+}
+
+}
+}
+
+
+RsContext rsContextCreate(RsDevice vdev, void *sur, uint32_t version, bool useDepth)
+{
+ Device * dev = static_cast<Device *>(vdev);
+ Context *rsc = new Context(dev, (Surface *)sur, useDepth);
+ return rsc;
+}
+
+void rsContextDestroy(RsContext vrsc)
+{
+ Context * rsc = static_cast<Context *>(vrsc);
+ delete rsc;
+}
+
+void rsObjDestroyOOB(RsContext vrsc, void *obj)
+{
+ Context * rsc = static_cast<Context *>(vrsc);
+ rsc->objDestroyAdd(static_cast<ObjectBase *>(obj));
+}
+
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
new file mode 100644
index 0000000..c58a88c
--- /dev/null
+++ b/libs/rs/rsContext.h
@@ -0,0 +1,210 @@
+/*
+ * 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 "rsUtils.h"
+
+#include <ui/Surface.h>
+
+#include "rsThreadIO.h"
+#include "rsType.h"
+#include "rsMatrix.h"
+#include "rsAllocation.h"
+#include "rsTriangleMesh.h"
+#include "rsSimpleMesh.h"
+#include "rsMesh.h"
+#include "rsDevice.h"
+#include "rsScriptC.h"
+#include "rsAllocation.h"
+#include "rsAdapter.h"
+#include "rsSampler.h"
+#include "rsLight.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 *, bool useDepth);
+ ~Context();
+
+ static pthread_key_t gThreadTLSKey;
+ struct ScriptTLSStruct {
+ Context * mContext;
+ Script * mScript;
+ };
+
+
+ //StructuredAllocationContext mStateAllocation;
+ ElementState mStateElement;
+ TypeState mStateType;
+ SamplerState mStateSampler;
+ ProgramFragmentState mStateFragment;
+ ProgramFragmentStoreState mStateFragmentStore;
+ ProgramVertexState mStateVertex;
+ LightState mStateLight;
+
+ TriangleMeshContext mStateTriangleMesh;
+
+ ScriptCState mScriptC;
+
+ 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();}
+ const ProgramVertex * getVertex() {return mVertex.get();}
+
+ void setupCheck();
+ void allocationCheck(const Allocation *);
+
+ void assignName(ObjectBase *obj, const char *name, uint32_t len);
+ void removeName(ObjectBase *obj);
+ ObjectBase * lookupName(const char *name) const;
+ void appendNameDefines(String8 *str) const;
+ void appendVarDefines(String8 *str) const;
+
+ ProgramFragment * getDefaultProgramFragment() const {
+ return mStateFragment.mDefault.get();
+ }
+ ProgramVertex * getDefaultProgramVertex() const {
+ return mStateVertex.mDefault.get();
+ }
+ ProgramFragmentStore * getDefaultProgramFragmentStore() const {
+ return mStateFragmentStore.mDefault.get();
+ }
+
+ void addInt32Define(const char* name, int32_t value) {
+ mInt32Defines.add(String8(name), value);
+ }
+
+ void addFloatDefine(const char* name, float value) {
+ mFloatDefines.add(String8(name), value);
+ }
+
+ uint32_t getWidth() const {return mEGL.mWidth;}
+ uint32_t getHeight() const {return mEGL.mHeight;}
+
+
+ ThreadIO mIO;
+ void objDestroyAdd(ObjectBase *);
+
+ // Timers
+ enum Timers {
+ RS_TIMER_IDLE,
+ RS_TIMER_INTERNAL,
+ RS_TIMER_SCRIPT,
+ RS_TIMER_CLEAR_SWAP,
+ _RS_TIMER_TOTAL
+ };
+ uint64_t getTime() const;
+ void timerInit();
+ void timerReset();
+ void timerSet(Timers);
+ void timerPrint();
+
+ bool checkVersion1_1() const {return (mGL.mMajorVersion > 1) || (mGL.mMinorVersion >= 1); }
+ bool checkVersion2_0() const {return mGL.mMajorVersion >= 2; }
+
+protected:
+ Device *mDev;
+
+ struct {
+ EGLint mNumConfigs;
+ EGLint mMajorVersion;
+ EGLint mMinorVersion;
+ EGLConfig mConfig;
+ EGLContext mContext;
+ EGLSurface mSurface;
+ EGLint mWidth;
+ EGLint mHeight;
+ EGLDisplay mDisplay;
+ } mEGL;
+
+ struct {
+ const uint8_t * mVendor;
+ const uint8_t * mRenderer;
+ const uint8_t * mVersion;
+ const uint8_t * mExtensions;
+
+ uint32_t mMajorVersion;
+ uint32_t mMinorVersion;
+
+ } mGL;
+
+ bool mRunning;
+ bool mExit;
+ bool mUseDepth;
+
+ pthread_t mThreadId;
+
+ ObjectBaseRef<Script> mRootScript;
+ ObjectBaseRef<ProgramFragment> mFragment;
+ ObjectBaseRef<ProgramVertex> mVertex;
+ ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
+
+
+ struct ObjDestroyOOB {
+ pthread_mutex_t mMutex;
+ Vector<ObjectBase *> mDestroyList;
+ bool mNeedToEmpty;
+ };
+ ObjDestroyOOB mObjDestroy;
+ bool objDestroyOOBInit();
+ void objDestroyOOBRun();
+ void objDestroyOOBDestroy();
+
+private:
+ Context();
+
+ void initEGL();
+
+ bool runScript(Script *s, uint32_t launchID);
+ bool runRootScript();
+
+ static void * threadProc(void *);
+
+ Surface *mWndSurface;
+
+ Vector<ObjectBase *> mNames;
+ KeyedVector<String8,int> mInt32Defines;
+ KeyedVector<String8,float> mFloatDefines;
+
+ uint64_t mTimers[_RS_TIMER_TOTAL];
+ Timers mTimerActive;
+ uint64_t mTimeLast;
+};
+
+
+}
+}
+#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..156315f
--- /dev/null
+++ b/libs/rs/rsDevice.h
@@ -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.
+ */
+
+#ifndef ANDROID_RS_DEVICE_H
+#define ANDROID_RS_DEVICE_H
+
+#include "rsUtils.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..6794522
--- /dev/null
+++ b/libs/rs/rsElement.cpp
@@ -0,0 +1,421 @@
+/*
+ * 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, 0);
+ Component * i_8 = new Component(Component::USER, Component::SIGNED, true, 8, 0);
+ Component * u_16 = new Component(Component::USER, Component::UNSIGNED, true, 16, 0);
+ Component * i_16 = new Component(Component::USER, Component::SIGNED, true, 16, 0);
+ Component * u_32 = new Component(Component::USER, Component::UNSIGNED, true, 32, 0);
+ Component * i_32 = new Component(Component::USER, Component::SIGNED, true, 32, 0);
+ Component * f_32 = new Component(Component::USER, Component::FLOAT, true, 32, 0);
+
+
+ Component * r_4 = new Component(Component::RED, Component::UNSIGNED, true, 4, 0);
+ Component * r_5 = new Component(Component::RED, Component::UNSIGNED, true, 5, 0);
+ Component * r_8 = new Component(Component::RED, Component::UNSIGNED, true, 8, 0);
+
+ Component * g_4 = new Component(Component::GREEN, Component::UNSIGNED, true, 4, 0);
+ Component * g_5 = new Component(Component::GREEN, Component::UNSIGNED, true, 5, 0);
+ Component * g_6 = new Component(Component::GREEN, Component::UNSIGNED, true, 6, 0);
+ Component * g_8 = new Component(Component::GREEN, Component::UNSIGNED, true, 8, 0);
+
+ Component * b_4 = new Component(Component::BLUE, Component::UNSIGNED, true, 4, 0);
+ Component * b_5 = new Component(Component::BLUE, Component::UNSIGNED, true, 5, 0);
+ Component * b_8 = new Component(Component::BLUE, Component::UNSIGNED, true, 8, 0);
+
+ Component * a_1 = new Component(Component::ALPHA, Component::UNSIGNED, true, 1, 0);
+ Component * a_4 = new Component(Component::ALPHA, Component::UNSIGNED, true, 4, 0);
+ Component * a_8 = new Component(Component::ALPHA, Component::UNSIGNED, true, 8, 0);
+
+ Component * idx_16 = new Component(Component::INDEX, Component::UNSIGNED, false, 16, 0);
+ Component * idx_32 = new Component(Component::INDEX, Component::UNSIGNED, false, 32, 0);
+
+ Component * x = new Component(Component::X, Component::FLOAT, false, 32, 0);
+ Component * y = new Component(Component::Y, Component::FLOAT, false, 32, 0);
+ Component * z = new Component(Component::Z, Component::FLOAT, false, 32, 0);
+
+ Component * nx = new Component(Component::NX, Component::FLOAT, false, 32, 0);
+ Component * ny = new Component(Component::NY, Component::FLOAT, false, 32, 0);
+ Component * nz = new Component(Component::NZ, Component::FLOAT, false, 32, 0);
+
+ Component * s = new Component(Component::S, Component::FLOAT, false, 32, 0);
+ Component * t = new Component(Component::T, Component::FLOAT, false, 32, 0);
+
+ 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->incUserRef();
+}
+
+
+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->incUserRef();
+ return e;
+}
+
+void rsi_ElementAdd(Context *rsc, RsDataKind dk, RsDataType dt, bool isNormalized, size_t bits, const char *name)
+{
+ ElementState * sec = &rsc->mStateElement;
+ Component *c = new Component(static_cast<Component::DataKind>(dk),
+ static_cast<Component::DataType>(dt),
+ isNormalized,
+ bits,
+ name);
+ sec->mComponentBuildList.add(c);
+}
+
+RsElement rsi_ElementCreate(Context *rsc)
+{
+ ElementState * sec = &rsc->mStateElement;
+ Element *se = new Element(sec->mComponentBuildList.size());
+
+ for (size_t ct = 0; ct < se->getComponentCount(); ct++) {
+ se->setComponent(ct, sec->mComponentBuildList[ct]);
+ }
+
+ rsc->mStateElement.mComponentBuildList.clear();
+ se->incUserRef();
+ return se;
+}
+
+
+}
+}
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
new file mode 100644
index 0000000..0918522
--- /dev/null
+++ b/libs/rs/rsElement.h
@@ -0,0 +1,95 @@
+/*
+ * 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 "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<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/rsFileA3D.cpp b/libs/rs/rsFileA3D.cpp
new file mode 100644
index 0000000..347ef23
--- /dev/null
+++ b/libs/rs/rsFileA3D.cpp
@@ -0,0 +1,384 @@
+
+/*
+ * 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/String8.h>
+#include "rsFileA3D.h"
+
+#include "rsMesh.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+
+FileA3D::FileA3D()
+{
+ mRsc = NULL;
+}
+
+FileA3D::~FileA3D()
+{
+}
+
+bool FileA3D::load(Context *rsc, FILE *f)
+{
+ char magicString[12];
+ size_t len;
+
+ LOGE("file open 1");
+ len = fread(magicString, 1, 12, f);
+ if ((len != 12) ||
+ memcmp(magicString, "Android3D_ff", 12)) {
+ return false;
+ }
+
+ LOGE("file open 2");
+ len = fread(&mMajorVersion, 1, sizeof(mMajorVersion), f);
+ if (len != sizeof(mMajorVersion)) {
+ return false;
+ }
+
+ LOGE("file open 3");
+ len = fread(&mMinorVersion, 1, sizeof(mMinorVersion), f);
+ if (len != sizeof(mMinorVersion)) {
+ return false;
+ }
+
+ LOGE("file open 4");
+ uint32_t flags;
+ len = fread(&flags, 1, sizeof(flags), f);
+ if (len != sizeof(flags)) {
+ return false;
+ }
+ mUse64BitOffsets = (flags & 1) != 0;
+
+ LOGE("file open 64bit = %i", mUse64BitOffsets);
+
+ if (mUse64BitOffsets) {
+ len = fread(&mDataSize, 1, sizeof(mDataSize), f);
+ if (len != sizeof(mDataSize)) {
+ return false;
+ }
+ } else {
+ uint32_t tmp;
+ len = fread(&tmp, 1, sizeof(tmp), f);
+ if (len != sizeof(tmp)) {
+ return false;
+ }
+ mDataSize = tmp;
+ }
+
+ LOGE("file open size = %lli", mDataSize);
+
+ // We should know enough to read the file in at this point.
+ fseek(f, SEEK_SET, 0);
+ mAlloc= malloc(mDataSize);
+ if (!mAlloc) {
+ return false;
+ }
+ mData = (uint8_t *)mAlloc;
+ len = fread(mAlloc, 1, mDataSize, f);
+ if (len != mDataSize) {
+ return false;
+ }
+
+ LOGE("file start processing");
+ return process(rsc);
+}
+
+bool FileA3D::processIndex(Context *rsc, A3DIndexEntry *ie)
+{
+ bool ret = false;
+ IO io(mData + ie->mOffset, mUse64BitOffsets);
+
+ LOGE("process index, type %i", ie->mType);
+
+ switch(ie->mType) {
+ case CHUNK_ELEMENT:
+ processChunk_Element(rsc, &io, ie);
+ break;
+ case CHUNK_ELEMENT_SOURCE:
+ processChunk_ElementSource(rsc, &io, ie);
+ break;
+ case CHUNK_VERTICIES:
+ processChunk_Verticies(rsc, &io, ie);
+ break;
+ case CHUNK_MESH:
+ processChunk_Mesh(rsc, &io, ie);
+ break;
+ case CHUNK_PRIMITIVE:
+ processChunk_Primitive(rsc, &io, ie);
+ break;
+ default:
+ LOGE("FileA3D Unknown chunk type");
+ break;
+ }
+ return (ie->mRsObj != NULL);
+}
+
+bool FileA3D::process(Context *rsc)
+{
+ LOGE("process");
+ IO io(mData + 12, mUse64BitOffsets);
+ bool ret = true;
+
+ // Build the index first
+ LOGE("process 1");
+ io.loadU32(); // major version, already loaded
+ io.loadU32(); // minor version, already loaded
+ LOGE("process 2");
+
+ io.loadU32(); // flags
+ io.loadOffset(); // filesize, already loaded.
+ LOGE("process 4");
+ uint64_t mIndexOffset = io.loadOffset();
+ uint64_t mStringOffset = io.loadOffset();
+
+ LOGE("process mIndexOffset= 0x%016llx", mIndexOffset);
+ LOGE("process mStringOffset= 0x%016llx", mStringOffset);
+
+ IO index(mData + mIndexOffset, mUse64BitOffsets);
+ IO stringTable(mData + mStringOffset, mUse64BitOffsets);
+
+ uint32_t stringEntryCount = stringTable.loadU32();
+ LOGE("stringEntryCount %i", stringEntryCount);
+ mStrings.setCapacity(stringEntryCount);
+ mStringIndexValues.setCapacity(stringEntryCount);
+ if (stringEntryCount) {
+ uint32_t stringType = stringTable.loadU32();
+ LOGE("stringType %i", stringType);
+ rsAssert(stringType==0);
+ for (uint32_t ct = 0; ct < stringEntryCount; ct++) {
+ uint64_t offset = stringTable.loadOffset();
+ LOGE("string offset 0x%016llx", offset);
+ IO tmp(mData + offset, mUse64BitOffsets);
+ String8 s;
+ tmp.loadString(&s);
+ LOGE("string %s", s.string());
+ mStrings.push(s);
+ }
+ }
+
+ LOGE("strings done");
+ uint32_t indexEntryCount = index.loadU32();
+ LOGE("index count %i", indexEntryCount);
+ mIndex.setCapacity(indexEntryCount);
+ for (uint32_t ct = 0; ct < indexEntryCount; ct++) {
+ A3DIndexEntry e;
+ uint32_t stringIndex = index.loadU32();
+ LOGE("index %i", ct);
+ LOGE(" string index %i", stringIndex);
+ e.mType = (A3DChunkType)index.loadU32();
+ LOGE(" type %i", e.mType);
+ e.mOffset = index.loadOffset();
+ LOGE(" offset 0x%016llx", e.mOffset);
+
+ if (stringIndex && (stringIndex < mStrings.size())) {
+ e.mID = mStrings[stringIndex];
+ mStringIndexValues.editItemAt(stringIndex) = ct;
+ LOGE(" id %s", e.mID.string());
+ }
+
+ mIndex.push(e);
+ }
+ LOGE("index done");
+
+ // At this point the index should be fully populated.
+ // We can now walk though it and load all the objects.
+ for (uint32_t ct = 0; ct < indexEntryCount; ct++) {
+ LOGE("processing index entry %i", ct);
+ processIndex(rsc, &mIndex.editItemAt(ct));
+ }
+
+ return ret;
+}
+
+
+FileA3D::IO::IO(const uint8_t *buf, bool use64)
+{
+ mData = buf;
+ mPos = 0;
+ mUse64 = use64;
+}
+
+uint64_t FileA3D::IO::loadOffset()
+{
+ uint64_t tmp;
+ if (mUse64) {
+ mPos = (mPos + 7) & (~7);
+ tmp = reinterpret_cast<const uint64_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint64_t);
+ return tmp;
+ }
+ return loadU32();
+}
+
+void FileA3D::IO::loadString(String8 *s)
+{
+ LOGE("loadString");
+ uint32_t len = loadU32();
+ LOGE("loadString len %i", len);
+ s->setTo((const char *)&mData[mPos], len);
+ mPos += len;
+}
+
+
+void FileA3D::processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ Mesh * m = new Mesh;
+
+ m->mPrimitivesCount = io->loadU32();
+ m->mPrimitives = new Mesh::Primitive_t *[m->mPrimitivesCount];
+
+ for (uint32_t ct = 0; ct < m->mPrimitivesCount; ct++) {
+ uint32_t index = io->loadU32();
+
+ m->mPrimitives[ct] = (Mesh::Primitive_t *)mIndex[index].mRsObj;
+ }
+ ie->mRsObj = m;
+}
+
+void FileA3D::processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ Mesh::Primitive_t * p = new Mesh::Primitive_t;
+
+ p->mIndexCount = io->loadU32();
+ uint32_t vertIdx = io->loadU32();
+ p->mRestartCounts = io->loadU16();
+ uint32_t bits = io->loadU8();
+ p->mType = (RsPrimitive)io->loadU8();
+
+ LOGE("processChunk_Primitive count %i, bits %i", p->mIndexCount, bits);
+
+ p->mVerticies = (Mesh::Verticies_t *)mIndex[vertIdx].mRsObj;
+
+ p->mIndicies = new uint16_t[p->mIndexCount];
+ for (uint32_t ct = 0; ct < p->mIndexCount; ct++) {
+ switch(bits) {
+ case 8:
+ p->mIndicies[ct] = io->loadU8();
+ break;
+ case 16:
+ p->mIndicies[ct] = io->loadU16();
+ break;
+ case 32:
+ p->mIndicies[ct] = io->loadU32();
+ break;
+ }
+ LOGE(" idx %i", p->mIndicies[ct]);
+ }
+
+ if (p->mRestartCounts) {
+ p->mRestarts = new uint16_t[p->mRestartCounts];
+ for (uint32_t ct = 0; ct < p->mRestartCounts; ct++) {
+ switch(bits) {
+ case 8:
+ p->mRestarts[ct] = io->loadU8();
+ break;
+ case 16:
+ p->mRestarts[ct] = io->loadU16();
+ break;
+ case 32:
+ p->mRestarts[ct] = io->loadU32();
+ break;
+ }
+ LOGE(" idx %i", p->mRestarts[ct]);
+ }
+ } else {
+ p->mRestarts = NULL;
+ }
+
+ ie->mRsObj = p;
+}
+
+void FileA3D::processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ Mesh::Verticies_t *cv = new Mesh::Verticies_t;
+ cv->mAllocationCount = io->loadU32();
+ cv->mAllocations = new Allocation *[cv->mAllocationCount];
+ LOGE("processChunk_Verticies count %i", cv->mAllocationCount);
+ for (uint32_t ct = 0; ct < cv->mAllocationCount; ct++) {
+ uint32_t i = io->loadU32();
+ cv->mAllocations[ct] = (Allocation *)mIndex[i].mRsObj;
+ LOGE(" idx %i", i);
+ }
+ ie->mRsObj = cv;
+}
+
+void FileA3D::processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ rsi_ElementBegin(rsc);
+
+ uint32_t count = io->loadU32();
+ LOGE("processChunk_Element count %i", count);
+ while (count--) {
+ RsDataKind dk = (RsDataKind)io->loadU8();
+ RsDataType dt = (RsDataType)io->loadU8();
+ uint32_t bits = io->loadU8();
+ bool isNorm = io->loadU8() != 0;
+ LOGE(" %i %i %i %i", dk, dt, bits, isNorm);
+ rsi_ElementAdd(rsc, dk, dt, isNorm, bits, 0);
+ }
+ LOGE("processChunk_Element create");
+ ie->mRsObj = rsi_ElementCreate(rsc);
+}
+
+void FileA3D::processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie)
+{
+ uint32_t index = io->loadU32();
+ uint32_t count = io->loadU32();
+
+ LOGE("processChunk_ElementSource count %i, index %i", count, index);
+
+ RsElement e = (RsElement)mIndex[index].mRsObj;
+
+ RsAllocation a = rsi_AllocationCreateSized(rsc, e, count);
+ Allocation * alloc = static_cast<Allocation *>(a);
+
+ float * data = (float *)alloc->getPtr();
+ while(count--) {
+ *data = io->loadF();
+ LOGE(" %f", *data);
+ data++;
+ }
+ ie->mRsObj = alloc;
+}
+
+namespace android {
+namespace renderscript {
+
+
+RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len)
+{
+ FileA3D *fa3d = new FileA3D;
+
+ FILE *f = fopen("/sdcard/test.a3d", "rb");
+ if (f) {
+ fa3d->load(rsc, f);
+ fclose(f);
+ return fa3d;
+ }
+ delete fa3d;
+ return NULL;
+}
+
+
+}
+}
diff --git a/libs/rs/rsFileA3D.h b/libs/rs/rsFileA3D.h
new file mode 100644
index 0000000..9ee08ec
--- /dev/null
+++ b/libs/rs/rsFileA3D.h
@@ -0,0 +1,122 @@
+/*
+ * 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_FILE_A3D_H
+#define ANDROID_RS_FILE_A3D_H
+
+#include "RenderScript.h"
+#include "rsFileA3DDecls.h"
+#include "rsMesh.h"
+
+#include <utils/String8.h>
+#include <stdio.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class FileA3D
+{
+public:
+ FileA3D();
+ ~FileA3D();
+
+ uint32_t mMajorVersion;
+ uint32_t mMinorVersion;
+ uint64_t mIndexOffset;
+ uint64_t mStringTableOffset;
+ bool mUse64BitOffsets;
+
+ struct A3DIndexEntry {
+ String8 mID;
+ A3DChunkType mType;
+ uint64_t mOffset;
+ void * mRsObj;
+ };
+
+ bool load(Context *rsc, FILE *f);
+
+protected:
+ class IO
+ {
+ public:
+ IO(const uint8_t *, bool use64);
+
+ float loadF() {
+ mPos = (mPos + 3) & (~3);
+ float tmp = reinterpret_cast<const float *>(&mData[mPos])[0];
+ mPos += sizeof(float);
+ return tmp;
+ }
+ int32_t loadI32() {
+ mPos = (mPos + 3) & (~3);
+ int32_t tmp = reinterpret_cast<const int32_t *>(&mData[mPos])[0];
+ mPos += sizeof(int32_t);
+ return tmp;
+ }
+ uint32_t loadU32() {
+ mPos = (mPos + 3) & (~3);
+ uint32_t tmp = reinterpret_cast<const uint32_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint32_t);
+ return tmp;
+ }
+ uint16_t loadU16() {
+ mPos = (mPos + 1) & (~1);
+ uint16_t tmp = reinterpret_cast<const uint16_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint16_t);
+ return tmp;
+ }
+ uint8_t loadU8() {
+ uint8_t tmp = reinterpret_cast<const uint8_t *>(&mData[mPos])[0];
+ mPos += sizeof(uint8_t);
+ return tmp;
+ }
+ uint64_t loadOffset();
+ void loadString(String8 *s);
+ uint64_t getPos() const {return mPos;}
+ const uint8_t * getPtr() const;
+ protected:
+ const uint8_t * mData;
+ uint64_t mPos;
+ bool mUse64;
+ };
+
+
+ bool process(Context *rsc);
+ bool processIndex(Context *rsc, A3DIndexEntry *);
+ void processChunk_Mesh(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_Primitive(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_Verticies(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie);
+ void processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie);
+
+ const uint8_t * mData;
+ void * mAlloc;
+ uint64_t mDataSize;
+ Context * mRsc;
+
+ Vector<A3DIndexEntry> mIndex;
+ Vector<String8> mStrings;
+ Vector<uint32_t> mStringIndexValues;
+
+};
+
+
+}
+}
+#endif //ANDROID_RS_FILE_A3D_H
+
+
diff --git a/libs/rs/rsFileA3DDecls.h b/libs/rs/rsFileA3DDecls.h
new file mode 100644
index 0000000..2a08bd3
--- /dev/null
+++ b/libs/rs/rsFileA3DDecls.h
@@ -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.
+ */
+
+#ifndef ANDROID_RS_FILE_A3D_DECLS_H
+#define ANDROID_RS_FILE_A3D_DECLS_H
+
+
+#define A3D_MAGIC_KEY "Android3D_ff"
+
+namespace android {
+namespace renderscript {
+
+ enum A3DChunkType {
+ CHUNK_EMPTY,
+
+ CHUNK_ELEMENT,
+ CHUNK_ELEMENT_SOURCE,
+ CHUNK_VERTICIES,
+ CHUNK_MESH,
+ CHUNK_PRIMITIVE,
+
+ CHUNK_LAST
+ };
+
+
+}
+}
+#endif //ANDROID_RS_FILE_A3D_H
+
+
+
diff --git a/libs/rs/rsHandcode.h b/libs/rs/rsHandcode.h
new file mode 100644
index 0000000..800eddd
--- /dev/null
+++ b/libs/rs/rsHandcode.h
@@ -0,0 +1,47 @@
+
+#define DATA_SYNC_SIZE 1024
+
+static inline void rsHCAPI_AllocationData (RsContext rsc, RsAllocation va, const void * data, uint32_t sizeBytes)
+{
+ ThreadIO *io = &((Context *)rsc)->mIO;
+ uint32_t size = sizeof(RS_CMD_AllocationData);
+ if (sizeBytes < DATA_SYNC_SIZE) {
+ size += (sizeBytes + 3) & ~3;
+ }
+ RS_CMD_AllocationData *cmd = static_cast<RS_CMD_AllocationData *>(io->mToCore.reserve(size));
+ cmd->va = va;
+ cmd->bytes = sizeBytes;
+ cmd->data = data;
+ if (sizeBytes < DATA_SYNC_SIZE) {
+ cmd->data = (void *)(cmd+1);
+ memcpy(cmd+1, data, sizeBytes);
+ io->mToCore.commit(RS_CMD_ID_AllocationData, size);
+ } else {
+ io->mToCore.commitSync(RS_CMD_ID_AllocationData, size);
+ }
+}
+
+
+static inline void rsHCAPI_Allocation1DSubData (RsContext rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void * data, uint32_t sizeBytes)
+{
+ ThreadIO *io = &((Context *)rsc)->mIO;
+ uint32_t size = sizeof(RS_CMD_Allocation1DSubData);
+ if (sizeBytes < DATA_SYNC_SIZE) {
+ size += (sizeBytes + 3) & ~3;
+ }
+ RS_CMD_Allocation1DSubData *cmd = static_cast<RS_CMD_Allocation1DSubData *>(io->mToCore.reserve(size));
+ cmd->va = va;
+ cmd->xoff = xoff;
+ cmd->count = count;
+ cmd->data = data;
+ cmd->bytes = sizeBytes;
+ if (sizeBytes < DATA_SYNC_SIZE) {
+ cmd->data = (void *)(cmd+1);
+ memcpy(cmd+1, data, sizeBytes);
+ io->mToCore.commit(RS_CMD_ID_Allocation1DSubData, size);
+ } else {
+ io->mToCore.commitSync(RS_CMD_ID_Allocation1DSubData, size);
+ }
+
+}
+
diff --git a/libs/rs/rsLight.cpp b/libs/rs/rsLight.cpp
new file mode 100644
index 0000000..ad06c1f
--- /dev/null
+++ b/libs/rs/rsLight.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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;
+
+
+Light::Light(bool isLocal, bool isMono)
+{
+ mIsLocal = isLocal;
+ mIsMono = isMono;
+
+ mPosition[0] = 0;
+ mPosition[1] = 0;
+ mPosition[2] = 1;
+ mPosition[3] = 0;
+
+ mColor[0] = 1.f;
+ mColor[1] = 1.f;
+ mColor[2] = 1.f;
+ mColor[3] = 1.f;
+}
+
+Light::~Light()
+{
+}
+
+void Light::setPosition(float x, float y, float z)
+{
+ mPosition[0] = x;
+ mPosition[1] = y;
+ mPosition[2] = z;
+}
+
+void Light::setColor(float r, float g, float b)
+{
+ mColor[0] = r;
+ mColor[1] = g;
+ mColor[2] = b;
+}
+
+void Light::setupGL(uint32_t num) const
+{
+ glLightfv(GL_LIGHT0 + num, GL_DIFFUSE, mColor);
+ glLightfv(GL_LIGHT0 + num, GL_SPECULAR, mColor);
+ glLightfv(GL_LIGHT0 + num, GL_POSITION, mPosition);
+}
+
+////////////////////////////////////////////
+
+LightState::LightState()
+{
+ clear();
+}
+
+LightState::~LightState()
+{
+}
+
+void LightState::clear()
+{
+ mIsLocal = false;
+ mIsMono = false;
+}
+
+
+////////////////////////////////////////////////////
+//
+
+namespace android {
+namespace renderscript {
+
+void rsi_LightBegin(Context *rsc)
+{
+ rsc->mStateLight.clear();
+}
+
+void rsi_LightSetLocal(Context *rsc, bool isLocal)
+{
+ rsc->mStateLight.mIsLocal = isLocal;
+}
+
+void rsi_LightSetMonochromatic(Context *rsc, bool isMono)
+{
+ rsc->mStateLight.mIsMono = isMono;
+}
+
+RsLight rsi_LightCreate(Context *rsc)
+{
+ Light *l = new Light(rsc->mStateLight.mIsLocal,
+ rsc->mStateLight.mIsMono);
+ l->incUserRef();
+ return l;
+}
+
+void rsi_LightSetColor(Context *rsc, RsLight vl, float r, float g, float b)
+{
+ Light *l = static_cast<Light *>(vl);
+ l->setColor(r, g, b);
+}
+
+void rsi_LightSetPosition(Context *rsc, RsLight vl, float x, float y, float z)
+{
+ Light *l = static_cast<Light *>(vl);
+ l->setPosition(x, y, z);
+}
+
+
+
+}
+}
diff --git a/libs/rs/rsLight.h b/libs/rs/rsLight.h
new file mode 100644
index 0000000..b0c3386
--- /dev/null
+++ b/libs/rs/rsLight.h
@@ -0,0 +1,64 @@
+/*
+ * 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_LIGHT_H
+#define ANDROID_LIGHT_H
+
+
+#include "rsObjectBase.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class Light : public ObjectBase
+{
+public:
+ Light(bool isLocal, bool isMono);
+ virtual ~Light();
+
+ // Values, mutable after creation.
+ void setPosition(float x, float y, float z);
+ void setColor(float r, float g, float b);
+
+ void setupGL(uint32_t num) const;
+
+protected:
+ float mColor[4];
+ float mPosition[4];
+ bool mIsLocal;
+ bool mIsMono;
+};
+
+
+class LightState {
+public:
+ LightState();
+ ~LightState();
+
+ void clear();
+
+ bool mIsMono;
+ bool mIsLocal;
+};
+
+
+}
+}
+#endif //ANDROID_LIGHT_H
+
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
new file mode 100644
index 0000000..0c40389
--- /dev/null
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -0,0 +1,258 @@
+/*
+ * 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;
+
+
+LocklessCommandFifo::LocklessCommandFifo()
+{
+}
+
+LocklessCommandFifo::~LocklessCommandFifo()
+{
+ if (!mInShutdown) {
+ shutdown();
+ }
+ free(mBuffer);
+}
+
+void LocklessCommandFifo::shutdown()
+{
+ mInShutdown = true;
+ mSignalToWorker.set();
+}
+
+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;
+ }
+
+ if (!mSignalToControl.init() || !mSignalToWorker.init()) {
+ LOGE("Signal setup failed");
+ free(mBuffer);
+ return false;
+ }
+
+ mInShutdown = 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;
+ }
+ 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)
+{
+ //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");
+ mSignalToWorker.set();
+}
+
+void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes)
+{
+ commit(command, sizeInBytes);
+ flush();
+}
+
+void LocklessCommandFifo::flush()
+{
+ //dumpState("flush 1");
+ while(mPut != mGet) {
+ mSignalToControl.wait();
+ }
+ //dumpState("flush 2");
+}
+
+const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
+{
+ while(1) {
+ //dumpState("get");
+ while(isEmpty() && !mInShutdown) {
+ mSignalToControl.set();
+ mSignalToWorker.wait();
+ }
+
+ *command = reinterpret_cast<const uint16_t *>(mGet)[0];
+ *bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
+ 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;
+ if (isEmpty()) {
+ mSignalToControl.set();
+ }
+ //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
+{
+ LOGV("%s put %p, get %p, buf %p, end %p", s, mPut, mGet, mBuffer, mEnd);
+}
+
+LocklessCommandFifo::Signal::Signal()
+{
+ mSet = true;
+}
+
+LocklessCommandFifo::Signal::~Signal()
+{
+ pthread_mutex_destroy(&mMutex);
+ pthread_cond_destroy(&mCondition);
+}
+
+bool LocklessCommandFifo::Signal::init()
+{
+ int status = pthread_mutex_init(&mMutex, NULL);
+ if (status) {
+ LOGE("LocklessFifo mutex init failure");
+ return false;
+ }
+
+ status = pthread_cond_init(&mCondition, NULL);
+ if (status) {
+ LOGE("LocklessFifo condition init failure");
+ pthread_mutex_destroy(&mMutex);
+ return false;
+ }
+
+ return true;
+}
+
+void LocklessCommandFifo::Signal::set()
+{
+ int status;
+
+ status = pthread_mutex_lock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
+ return;
+ }
+
+ mSet = true;
+
+ status = pthread_cond_signal(&mCondition);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i on set condition.", status);
+ }
+
+ status = pthread_mutex_unlock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
+ }
+}
+
+void LocklessCommandFifo::Signal::wait()
+{
+ int status;
+
+ status = pthread_mutex_lock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i locking for condition.", status);
+ return;
+ }
+
+ if (!mSet) {
+ status = pthread_cond_wait(&mCondition, &mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
+ }
+ }
+ mSet = false;
+
+ status = pthread_mutex_unlock(&mMutex);
+ if (status) {
+ LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
+ }
+}
+
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
new file mode 100644
index 0000000..d0a4356
--- /dev/null
+++ b/libs/rs/rsLocklessFifo.h
@@ -0,0 +1,91 @@
+/*
+ * 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 "rsUtils.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);
+ void shutdown();
+
+ LocklessCommandFifo();
+ ~LocklessCommandFifo();
+
+
+protected:
+ class Signal {
+ public:
+ Signal();
+ ~Signal();
+
+ bool init();
+
+ void set();
+ void wait();
+
+ protected:
+ bool mSet;
+ pthread_mutex_t mMutex;
+ pthread_cond_t mCondition;
+ };
+
+ uint8_t * volatile mPut;
+ uint8_t * volatile mGet;
+ uint8_t * mBuffer;
+ uint8_t * mEnd;
+ uint8_t mSize;
+ bool mInShutdown;
+
+ Signal mSignalToWorker;
+ Signal mSignalToControl;
+
+
+
+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..5f68197
--- /dev/null
+++ b/libs/rs/rsMatrix.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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"
+
+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);
+ }
+}
+
+void Matrix::loadOrtho(float l, float r, float b, float t, float n, float f) {
+ loadIdentity();
+ m[0] = 2 / (r - l);
+ m[5] = 2 / (t - b);
+ m[10]= -2 / (f - n);
+ m[12]= -(r + l) / (r - l);
+ m[13]= -(t + b) / (t - b);
+ m[14]= -(f + n) / (f - n);
+}
+
+void Matrix::loadFrustum(float l, float r, float b, float t, float n, float f) {
+ loadIdentity();
+ m[0] = 2 * n / (r - l);
+ m[5] = 2 * n / (t - b);
+ m[8] = (r + l) / (r - l);
+ m[9] = (t + b) / (t - b);
+ m[10]= -(f + n) / (f - n);
+ m[11]= -1;
+ m[14]= -2*f*n / (f - n);
+ m[15]= 0;
+}
+
+
diff --git a/libs/rs/rsMatrix.h b/libs/rs/rsMatrix.h
new file mode 100644
index 0000000..7dc4165
--- /dev/null
+++ b/libs/rs/rsMatrix.h
@@ -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.
+ */
+
+#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 loadOrtho(float l, float r, float b, float t, float n, float f);
+ void loadFrustum(float l, float r, float b, float t, float n, float f);
+
+ 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/rsMesh.cpp b/libs/rs/rsMesh.cpp
new file mode 100644
index 0000000..aeb52ed
--- /dev/null
+++ b/libs/rs/rsMesh.cpp
@@ -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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+Mesh::Mesh()
+{
+ mVerticies = NULL;
+ mVerticiesCount = 0;
+ mPrimitives = NULL;
+ mPrimitivesCount = 0;
+}
+
+Mesh::~Mesh()
+{
+}
+
+
+
+MeshContext::MeshContext()
+{
+}
+
+MeshContext::~MeshContext()
+{
+}
+
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
new file mode 100644
index 0000000..be207a3
--- /dev/null
+++ b/libs/rs/rsMesh.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_MESH_H
+#define ANDROID_RS_MESH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class Mesh : public ObjectBase
+{
+public:
+ Mesh();
+ ~Mesh();
+
+ struct Verticies_t
+ {
+ Allocation ** mAllocations;
+ uint32_t mAllocationCount;
+
+ size_t mVertexDataSize;
+
+ size_t mOffsetCoord;
+ size_t mOffsetTex;
+ size_t mOffsetNorm;
+
+ size_t mSizeCoord;
+ size_t mSizeTex;
+ size_t mSizeNorm;
+
+ uint32_t mBufferObject;
+ };
+
+ struct Primitive_t
+ {
+ RsPrimitive mType;
+ Verticies_t *mVerticies;
+
+ uint32_t mIndexCount;
+ uint16_t *mIndicies;
+
+ uint32_t mRestartCounts;
+ uint16_t *mRestarts;
+ };
+
+ Verticies_t * mVerticies;
+ uint32_t mVerticiesCount;
+
+ Primitive_t ** mPrimitives;
+ uint32_t mPrimitivesCount;
+
+
+
+ void analyzeElement();
+protected:
+};
+
+class MeshContext
+{
+public:
+ MeshContext();
+ ~MeshContext();
+
+};
+
+
+}
+}
+#endif //ANDROID_RS_TRIANGLE_MESH_H
+
+
diff --git a/libs/rs/rsNoise.cpp b/libs/rs/rsNoise.cpp
new file mode 100644
index 0000000..764dc1a
--- /dev/null
+++ b/libs/rs/rsNoise.cpp
@@ -0,0 +1,256 @@
+/*
+ * This implementation of the noise functions was ported from the Java
+ * implementation by Jerry Huxtable (http://www.jhlabs.com) under
+ * Apache License 2.0 (see http://jhlabs.com/ip/filters/download.html)
+ *
+ * Original header:
+ *
+ * Copyright 2006 Jerry Huxtable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "rsNoise.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>
+
+namespace android {
+namespace renderscript {
+
+#define B 0x100
+#define BM 0xff
+#define N 0x1000
+
+static int p[B + B + 2];
+static float g3[B + B + 2][3];
+static float g2[B + B + 2][2];
+static float g1[B + B + 2];
+static bool noise_start = true;
+
+#define lerpf(start, stop, amount) start + (stop - start) * amount
+
+static inline float noise_sCurve(float t)
+{
+ return t * t * (3.0f - 2.0f * t);
+}
+
+inline void SC_normalizef2(float v[])
+{
+ float s = (float)sqrtf(v[0] * v[0] + v[1] * v[1]);
+ v[0] = v[0] / s;
+ v[1] = v[1] / s;
+}
+
+inline void SC_normalizef3(float v[])
+{
+ float s = (float)sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ v[0] = v[0] / s;
+ v[1] = v[1] / s;
+ v[2] = v[2] / s;
+}
+
+static void noise_init()
+{
+ int i, j, k;
+
+ for (i = 0; i < B; i++) {
+ p[i] = i;
+
+ g1[i] = (float)((rand() % (B + B)) - B) / B;
+
+ for (j = 0; j < 2; j++)
+ g2[i][j] = (float)((rand() % (B + B)) - B) / B;
+ SC_normalizef2(g2[i]);
+
+ for (j = 0; j < 3; j++)
+ g3[i][j] = (float)((rand() % (B + B)) - B) / B;
+ SC_normalizef3(g3[i]);
+ }
+
+ for (i = B-1; i >= 0; i--) {
+ k = p[i];
+ p[i] = p[j = rand() % B];
+ p[j] = k;
+ }
+
+ for (i = 0; i < B + 2; i++) {
+ p[B + i] = p[i];
+ g1[B + i] = g1[i];
+ for (j = 0; j < 2; j++)
+ g2[B + i][j] = g2[i][j];
+ for (j = 0; j < 3; j++)
+ g3[B + i][j] = g3[i][j];
+ }
+}
+
+float SC_noisef(float x)
+{
+ srand(time(NULL));
+ int bx0, bx1;
+ float rx0, rx1, sx, t, u, v;
+
+ if (noise_start) {
+ noise_start = false;
+ noise_init();
+ }
+
+ t = x + N;
+ bx0 = ((int)t) & BM;
+ bx1 = (bx0+1) & BM;
+ rx0 = t - (int)t;
+ rx1 = rx0 - 1.0f;
+
+ sx = noise_sCurve(rx0);
+
+ u = rx0 * g1[p[bx0]];
+ v = rx1 * g1[p[bx1]];
+ return 2.3f * lerpf(u, v, sx);
+}
+
+float SC_noisef2(float x, float y)
+{
+ srand(time(NULL));
+ int bx0, bx1, by0, by1, b00, b10, b01, b11;
+ float rx0, rx1, ry0, ry1, sx, sy, a, b, t, u, v;
+ float *q;
+ int i, j;
+
+ if (noise_start) {
+ noise_start = false;
+ noise_init();
+ }
+
+ t = x + N;
+ bx0 = ((int)t) & BM;
+ bx1 = (bx0+1) & BM;
+ rx0 = t - (int)t;
+ rx1 = rx0 - 1.0f;
+
+ t = y + N;
+ by0 = ((int)t) & BM;
+ by1 = (by0+1) & BM;
+ ry0 = t - (int)t;
+ ry1 = ry0 - 1.0f;
+
+ i = p[bx0];
+ j = p[bx1];
+
+ b00 = p[i + by0];
+ b10 = p[j + by0];
+ b01 = p[i + by1];
+ b11 = p[j + by1];
+
+ sx = noise_sCurve(rx0);
+ sy = noise_sCurve(ry0);
+
+ q = g2[b00]; u = rx0 * q[0] + ry0 * q[1];
+ q = g2[b10]; v = rx1 * q[0] + ry0 * q[1];
+ a = lerpf(u, v, sx);
+
+ q = g2[b01]; u = rx0 * q[0] + ry1 * q[1];
+ q = g2[b11]; v = rx1 * q[0] + ry1 * q[1];
+ b = lerpf(u, v, sx);
+
+ return 1.5f*lerpf(a, b, sy);
+}
+
+float SC_noisef3(float x, float y, float z)
+{
+ srand(time(NULL));
+ int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
+ float rx0, rx1, ry0, ry1, rz0, rz1, sy, sz, a, b, c, d, t, u, v;
+ float *q;
+ int i, j;
+
+ if (noise_start) {
+ noise_start = false;
+ noise_init();
+ }
+
+ t = x + N;
+ bx0 = ((int)t) & BM;
+ bx1 = (bx0+1) & BM;
+ rx0 = t - (int)t;
+ rx1 = rx0 - 1.0f;
+
+ t = y + N;
+ by0 = ((int)t) & BM;
+ by1 = (by0+1) & BM;
+ ry0 = t - (int)t;
+ ry1 = ry0 - 1.0f;
+
+ t = z + N;
+ bz0 = ((int)t) & BM;
+ bz1 = (bz0+1) & BM;
+ rz0 = t - (int)t;
+ rz1 = rz0 - 1.0f;
+
+ i = p[bx0];
+ j = p[bx1];
+
+ b00 = p[i + by0];
+ b10 = p[j + by0];
+ b01 = p[i + by1];
+ b11 = p[j + by1];
+
+ t = noise_sCurve(rx0);
+ sy = noise_sCurve(ry0);
+ sz = noise_sCurve(rz0);
+
+ q = g3[b00 + bz0]; u = rx0 * q[0] + ry0 * q[1] + rz0 * q[2];
+ q = g3[b10 + bz0]; v = rx1 * q[0] + ry0 * q[1] + rz0 * q[2];
+ a = lerpf(u, v, t);
+
+ q = g3[b01 + bz0]; u = rx0 * q[0] + ry1 * q[1] + rz0 * q[2];
+ q = g3[b11 + bz0]; v = rx1 * q[0] + ry1 * q[1] + rz0 * q[2];
+ b = lerpf(u, v, t);
+
+ c = lerpf(a, b, sy);
+
+ q = g3[b00 + bz1]; u = rx0 * q[0] + ry0 * q[1] + rz1 * q[2];
+ q = g3[b10 + bz1]; v = rx1 * q[0] + ry0 * q[1] + rz1 * q[2];
+ a = lerpf(u, v, t);
+
+ q = g3[b01 + bz1]; u = rx0 * q[0] + ry1 * q[1] + rz1 * q[2];
+ q = g3[b11 + bz1]; v = rx1 * q[0] + ry1 * q[1] + rz1 * q[2];
+ b = lerpf(u, v, t);
+
+ d = lerpf(a, b, sy);
+
+ return 1.5f*lerpf(c, d, sz);
+}
+
+float SC_turbulencef2(float x, float y, float octaves)
+{
+ srand(time(NULL));
+ float t = 0.0f;
+
+ for (float f = 1.0f; f <= octaves; f *= 2)
+ t += fabs(SC_noisef2(f * x, f * y)) / f;
+ return t;
+}
+
+float SC_turbulencef3(float x, float y, float z, float octaves)
+{
+ srand(time(NULL));
+ float t = 0.0f;
+
+ for (float f = 1.0f; f <= octaves; f *= 2)
+ t += fabs(SC_noisef3(f * x, f * y, f * z)) / f;
+ return t;
+}
+
+}
+} \ No newline at end of file
diff --git a/libs/rs/rsNoise.h b/libs/rs/rsNoise.h
new file mode 100644
index 0000000..9040751
--- /dev/null
+++ b/libs/rs/rsNoise.h
@@ -0,0 +1,35 @@
+/*
+ * 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_NOISE_H
+#define ANDROID_RS_NOISE_H
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+void SC_normalizef2(float v[]);
+void SC_normalizef3(float v[]);
+float SC_noisef(float x);
+float SC_noisef2(float x, float y);
+float SC_noisef3(float x, float y, float z);
+float SC_turbulencef2(float x, float y, float octaves);
+float SC_turbulencef3(float x, float y, float z, float octaves);
+
+}
+}
+
+#endif
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
new file mode 100644
index 0000000..7e7afab
--- /dev/null
+++ b/libs/rs/rsObjectBase.cpp
@@ -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.
+ */
+
+#include "rsObjectBase.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+ObjectBase::ObjectBase()
+{
+ mUserRefCount = 0;
+ mSysRefCount = 0;
+ mName = NULL;
+}
+
+ObjectBase::~ObjectBase()
+{
+ //LOGV("~ObjectBase %p ref %i", this, mRefCount);
+ rsAssert(!mUserRefCount);
+ rsAssert(!mSysRefCount);
+}
+
+void ObjectBase::incUserRef() const
+{
+ mUserRefCount ++;
+ //LOGV("ObjectBase %p inc ref %i", this, mRefCount);
+}
+
+void ObjectBase::incSysRef() const
+{
+ mSysRefCount ++;
+ //LOGV("ObjectBase %p inc ref %i", this, mRefCount);
+}
+
+void ObjectBase::decUserRef() const
+{
+ rsAssert(mUserRefCount > 0);
+ mUserRefCount --;
+ //LOGV("ObjectBase %p dec ref %i", this, mRefCount);
+ if (!(mSysRefCount | mUserRefCount)) {
+ if (mName) {
+ LOGV("Deleting RS object %p, name %s", this, mName);
+ } else {
+ LOGV("Deleting RS object %p, no name", this);
+ }
+ delete this;
+ }
+}
+
+void ObjectBase::decSysRef() const
+{
+ rsAssert(mSysRefCount > 0);
+ mSysRefCount --;
+ //LOGV("ObjectBase %p dec ref %i", this, mRefCount);
+ if (!(mSysRefCount | mUserRefCount)) {
+ if (mName) {
+ LOGV("Deleting RS object %p, name %s", this, mName);
+ } else {
+ LOGV("Deleting RS object %p, no name", this);
+ }
+ delete this;
+ }
+}
+
+void ObjectBase::setName(const char *name)
+{
+ delete mName;
+ mName = NULL;
+ if (name) {
+ mName = new char[strlen(name) +1];
+ strcpy(mName, name);
+ }
+}
+
+void ObjectBase::setName(const char *name, uint32_t len)
+{
+ delete mName;
+ mName = NULL;
+ if (name) {
+ mName = new char[len + 1];
+ memcpy(mName, name, len);
+ mName[len] = 0;
+ }
+}
+
diff --git a/libs/rs/rsObjectBase.h b/libs/rs/rsObjectBase.h
new file mode 100644
index 0000000..d1e6baa
--- /dev/null
+++ b/libs/rs/rsObjectBase.h
@@ -0,0 +1,118 @@
+/*
+ * 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 incSysRef() const;
+ void decSysRef() const;
+
+ void incUserRef() const;
+ void decUserRef() const;
+
+ const char * getName() const {
+ return mName;
+ }
+ void setName(const char *);
+ void setName(const char *, uint32_t len);
+
+private:
+ char * mName;
+ mutable int32_t mSysRefCount;
+ mutable int32_t mUserRefCount;
+
+
+};
+
+template<class T>
+class ObjectBaseRef
+{
+public:
+ ObjectBaseRef() {
+ mRef = NULL;
+ }
+
+ ObjectBaseRef(const ObjectBaseRef &ref) {
+ mRef = ref.get();
+ if (mRef) {
+ mRef->incSysRef();
+ }
+ }
+
+ ObjectBaseRef(T *ref) {
+ mRef = ref;
+ if (mRef) {
+ ref->incSysRef();
+ }
+ }
+
+ ~ObjectBaseRef() {
+ clear();
+ }
+
+ void set(T *ref) {
+ if (mRef != ref) {
+ clear();
+ mRef = ref;
+ if (mRef) {
+ ref->incSysRef();
+ }
+ }
+ }
+
+ void set(const ObjectBaseRef &ref) {
+ set(ref.mRef);
+ }
+
+ void clear() {
+ if (mRef) {
+ mRef->decSysRef();
+ }
+ mRef = NULL;
+ }
+
+ inline T * get() const {
+ return mRef;
+ }
+
+ inline T * operator-> () const {
+ return mRef;
+ }
+
+protected:
+ T * mRef;
+
+};
+
+
+}
+}
+
+#endif //ANDROID_RS_OBJECT_BASE_H
+
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
new file mode 100644
index 0000000..18eacfb
--- /dev/null
+++ b/libs/rs/rsProgram.cpp
@@ -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.
+ */
+
+#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::bindAllocation(Allocation *alloc)
+{
+ mConstants.set(alloc);
+ mDirty = true;
+}
+
+void Program::checkUpdatedAllocation(const Allocation *alloc)
+{
+ if (mConstants.get() == alloc) {
+ mDirty = true;
+ }
+}
+
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
new file mode 100644
index 0000000..bb3d9ac
--- /dev/null
+++ b/libs/rs/rsProgram.h
@@ -0,0 +1,56 @@
+/*
+ * 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 bindAllocation(Allocation *);
+ void checkUpdatedAllocation(const Allocation *);
+
+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;
+
+ mutable bool mDirty;
+};
+
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
new file mode 100644
index 0000000..0adce75
--- /dev/null
+++ b/libs/rs/rsProgramFragment.cpp
@@ -0,0 +1,238 @@
+/*
+ * 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"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramFragment::ProgramFragment(Element *in, Element *out, bool pointSpriteEnable) :
+ Program(in, out)
+{
+ for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
+ mEnvModes[ct] = RS_TEX_ENV_MODE_REPLACE;
+ mTextureDimensions[ct] = 2;
+ }
+ mTextureEnableMask = 0;
+ mPointSpriteEnable = pointSpriteEnable;
+ mEnvModes[1] = RS_TEX_ENV_MODE_DECAL;
+}
+
+ProgramFragment::~ProgramFragment()
+{
+}
+
+void ProgramFragment::setupGL(const Context *rsc, ProgramFragmentState *state)
+{
+ if ((state->mLast.get() == this) && !mDirty) {
+ return;
+ }
+ state->mLast.set(this);
+
+ for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
+ glActiveTexture(GL_TEXTURE0 + ct);
+ if (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) {
+ glDisable(GL_TEXTURE_2D);
+ continue;
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ if (rsc->checkVersion1_1()) {
+ glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, mPointSpriteEnable);
+ }
+ glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
+
+ switch(mEnvModes[ct]) {
+ case RS_TEX_ENV_MODE_REPLACE:
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ break;
+ case RS_TEX_ENV_MODE_MODULATE:
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ break;
+ case RS_TEX_ENV_MODE_DECAL:
+ glTexEnvf(GL_TEXTURE_ENV, 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_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
+
+ // Gross hack.
+ if (ct == 2) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ }
+ }
+ glActiveTexture(GL_TEXTURE0);
+ mDirty = false;
+}
+
+
+void ProgramFragment::bindTexture(uint32_t slot, Allocation *a)
+{
+ if (slot >= MAX_TEXTURE) {
+ LOGE("Attempt to bind a texture to a slot > MAX_TEXTURE");
+ return;
+ }
+
+ //LOGE("bindtex %i %p", slot, a);
+ mTextures[slot].set(a);
+ mDirty = true;
+}
+
+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);
+ mDirty = true;
+}
+
+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;
+
+}
+
+void ProgramFragmentState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramFragment *pf = new ProgramFragment(NULL, NULL, false);
+ mDefault.set(pf);
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ProgramFragmentBegin(Context * rsc, RsElement in, RsElement out, bool pointSpriteEnable)
+{
+ delete rsc->mStateFragment.mPF;
+ rsc->mStateFragment.mPF = new ProgramFragment((Element *)in, (Element *)out, pointSpriteEnable);
+}
+
+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));
+}
+
+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));
+}
+
+void rsi_ProgramFragmentSetSlot(Context *rsc, uint32_t slot, bool enable, RsTexEnvMode env, RsType vt)
+{
+ const Type *t = static_cast<const Type *>(vt);
+ if (t) {
+ uint32_t dim = 1;
+ if (t->getDimY()) {
+ dim ++;
+ if (t->getDimZ()) {
+ dim ++;
+ }
+ }
+ rsc->mStateFragment.mPF->setType(slot, t->getElement(), dim);
+ }
+ rsc->mStateFragment.mPF->setEnvMode(slot, env);
+ rsc->mStateFragment.mPF->setTexEnable(slot, enable);
+}
+
+RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc)
+{
+ ProgramFragment *pf = rsc->mStateFragment.mPF;
+ pf->incUserRef();
+ rsc->mStateFragment.mPF = 0;
+ return pf;
+}
+
+
+}
+}
+
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
new file mode 100644
index 0000000..51117eb
--- /dev/null
+++ b/libs/rs/rsProgramFragment.h
@@ -0,0 +1,93 @@
+/*
+ * 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 ProgramFragmentState;
+
+class ProgramFragment : public Program
+{
+public:
+ const static uint32_t MAX_TEXTURE = 2;
+
+
+
+ ProgramFragment(Element *in, Element *out, bool pointSpriteEnable);
+ virtual ~ProgramFragment();
+
+ virtual void setupGL(const Context *, ProgramFragmentState *);
+
+
+
+ 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];
+
+
+ // Hacks to create a program for now
+ RsTexEnvMode mEnvModes[MAX_TEXTURE];
+ uint32_t mTextureEnableMask;
+ bool mPointSpriteEnable;
+};
+
+class ProgramFragmentState
+{
+public:
+ ProgramFragmentState();
+ ~ProgramFragmentState();
+
+ ProgramFragment *mPF;
+ void init(Context *rsc, int32_t w, int32_t h);
+
+ ObjectBaseRef<Type> mTextureTypes[ProgramFragment::MAX_TEXTURE];
+ ObjectBaseRef<ProgramFragment> mDefault;
+ Vector<ProgramFragment *> mPrograms;
+
+ ObjectBaseRef<ProgramFragment> mLast;
+};
+
+
+}
+}
+#endif
+
+
+
+
diff --git a/libs/rs/rsProgramFragmentStore.cpp b/libs/rs/rsProgramFragmentStore.cpp
new file mode 100644
index 0000000..3179484
--- /dev/null
+++ b/libs/rs/rsProgramFragmentStore.cpp
@@ -0,0 +1,266 @@
+/*
+ * 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"
+
+#include <GLES/gl.h>
+#include <GLES/glext.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(const Context *rsc, ProgramFragmentStoreState *state)
+{
+ if (state->mLast.get() == this) {
+ return;
+ }
+ state->mLast.set(this);
+
+ glColorMask(mColorRWriteEnable,
+ mColorGWriteEnable,
+ mColorBWriteEnable,
+ mColorAWriteEnable);
+ if (mBlendEnable) {
+ glEnable(GL_BLEND);
+ glBlendFunc(mBlendSrc, mBlendDst);
+ } else {
+ glDisable(GL_BLEND);
+ }
+
+ //LOGE("pfs %i, %i, %x", mDepthWriteEnable, mDepthTestEnable, mDepthFunc);
+
+ glDepthMask(mDepthWriteEnable);
+ if(mDepthTestEnable || mDepthWriteEnable) {
+ 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;
+
+}
+
+void ProgramFragmentStoreState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramFragmentStore *pfs = new ProgramFragmentStore(NULL, NULL);
+ mDefault.set(pfs);
+}
+
+
+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->incUserRef();
+ 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..e646e03
--- /dev/null
+++ b/libs/rs/rsProgramFragmentStore.h
@@ -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.
+ */
+
+#ifndef ANDROID_RS_PROGRAM_FRAGMENT_STORE_H
+#define ANDROID_RS_PROGRAM_FRAGMENT_STORE_H
+
+#include "rsProgram.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class ProgramFragmentStoreState;
+
+class ProgramFragmentStore : public Program
+{
+public:
+ ProgramFragmentStore(Element *in, Element *out);
+ virtual ~ProgramFragmentStore();
+
+ virtual void setupGL(const Context *, ProgramFragmentStoreState *);
+
+ 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();
+ void init(Context *rsc, int32_t w, int32_t h);
+
+ ObjectBaseRef<ProgramFragmentStore> mDefault;
+ ObjectBaseRef<ProgramFragmentStore> mLast;
+
+
+ ProgramFragmentStore *mPFS;
+};
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
new file mode 100644
index 0000000..a07e166
--- /dev/null
+++ b/libs/rs/rsProgramVertex.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+
+ProgramVertex::ProgramVertex(Element *in, Element *out) :
+ Program(in, out)
+{
+ mTextureMatrixEnable = false;
+ mLightCount = 0;
+}
+
+ProgramVertex::~ProgramVertex()
+{
+}
+
+static void logMatrix(const char *txt, const float *f)
+{
+ LOGV("Matrix %s, %p", txt, f);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[0], f[4], f[8], f[12]);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[1], f[5], f[9], f[13]);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[2], f[6], f[10], f[14]);
+ LOGV("%6.2f, %6.2f, %6.2f, %6.2f", f[3], f[7], f[11], f[15]);
+}
+
+void ProgramVertex::setupGL(const Context *rsc, ProgramVertexState *state)
+{
+ if ((state->mLast.get() == this) && !mDirty) {
+ return;
+ }
+ state->mLast.set(this);
+
+ const float *f = static_cast<const float *>(mConstants->getPtr());
+
+ glMatrixMode(GL_TEXTURE);
+ if (mTextureMatrixEnable) {
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET]);
+ } else {
+ glLoadIdentity();
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ if (mLightCount) {
+ int v = 0;
+ glEnable(GL_LIGHTING);
+ glLightModelxv(GL_LIGHT_MODEL_TWO_SIDE, &v);
+ for (uint32_t ct = 0; ct < mLightCount; ct++) {
+ const Light *l = mLights[ct].get();
+ glEnable(GL_LIGHT0 + ct);
+ l->setupGL(ct);
+ }
+ for (uint32_t ct = mLightCount; ct < MAX_LIGHTS; ct++) {
+ glDisable(GL_LIGHT0 + ct);
+ }
+ } else {
+ glDisable(GL_LIGHTING);
+ }
+
+ if (!f) {
+ LOGE("Must bind constants to vertex program");
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET]);
+
+ mDirty = false;
+}
+
+void ProgramVertex::addLight(const Light *l)
+{
+ if (mLightCount < MAX_LIGHTS) {
+ mLights[mLightCount].set(l);
+ mLightCount++;
+ }
+}
+
+void ProgramVertex::setProjectionMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
+ mDirty = true;
+}
+
+void ProgramVertex::setModelviewMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
+ mDirty = true;
+}
+
+void ProgramVertex::setTextureMatrix(const rsc_Matrix *m) const
+{
+ float *f = static_cast<float *>(mConstants->getPtr());
+ memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
+ mDirty = true;
+}
+
+
+
+ProgramVertexState::ProgramVertexState()
+{
+ mPV = NULL;
+}
+
+ProgramVertexState::~ProgramVertexState()
+{
+ delete mPV;
+}
+
+void ProgramVertexState::init(Context *rsc, int32_t w, int32_t h)
+{
+ ProgramVertex *pv = new ProgramVertex(NULL, NULL);
+ Allocation *alloc = (Allocation *)
+ rsi_AllocationCreatePredefSized(rsc, RS_ELEMENT_USER_FLOAT, 48);
+ mDefaultAlloc.set(alloc);
+ mDefault.set(pv);
+
+ pv->bindAllocation(alloc);
+
+ Matrix m;
+ m.loadOrtho(0,w, h,0, -1,1);
+ alloc->subData(RS_PROGRAM_VERTEX_PROJECTION_OFFSET, 16, &m.m[0], 16*4);
+
+ m.loadIdentity();
+ alloc->subData(RS_PROGRAM_VERTEX_MODELVIEW_OFFSET, 16, &m.m[0], 16*4);
+}
+
+
+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->incUserRef();
+ rsc->mStateVertex.mPV = 0;
+ return pv;
+}
+
+void rsi_ProgramVertexBindAllocation(Context *rsc, RsProgramVertex vpgm, RsAllocation constants)
+{
+ ProgramVertex *pv = static_cast<ProgramVertex *>(vpgm);
+ pv->bindAllocation(static_cast<Allocation *>(constants));
+}
+
+void rsi_ProgramVertexSetTextureMatrixEnable(Context *rsc, bool enable)
+{
+ rsc->mStateVertex.mPV->setTextureMatrixEnable(enable);
+}
+
+void rsi_ProgramVertexAddLight(Context *rsc, RsLight light)
+{
+ rsc->mStateVertex.mPV->addLight(static_cast<const Light *>(light));
+}
+
+
+}
+}
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
new file mode 100644
index 0000000..523c3ed
--- /dev/null
+++ b/libs/rs/rsProgramVertex.h
@@ -0,0 +1,81 @@
+/*
+ * 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 ProgramVertexState;
+
+class ProgramVertex : public Program
+{
+public:
+ const static uint32_t MAX_LIGHTS = 8;
+
+ ProgramVertex(Element *in, Element *out);
+ virtual ~ProgramVertex();
+
+ virtual void setupGL(const Context *rsc, ProgramVertexState *state);
+
+
+ void setTextureMatrixEnable(bool e) {mTextureMatrixEnable = e;}
+ void addLight(const Light *);
+
+ void setProjectionMatrix(const rsc_Matrix *) const;
+ void setModelviewMatrix(const rsc_Matrix *) const;
+ void setTextureMatrix(const rsc_Matrix *) const;
+
+protected:
+ uint32_t mLightCount;
+ ObjectBaseRef<const Light> mLights[MAX_LIGHTS];
+
+ // Hacks to create a program for now
+ bool mTextureMatrixEnable;
+};
+
+
+class ProgramVertexState
+{
+public:
+ ProgramVertexState();
+ ~ProgramVertexState();
+
+ void init(Context *rsc, int32_t w, int32_t h);
+
+ ObjectBaseRef<ProgramVertex> mDefault;
+ ObjectBaseRef<ProgramVertex> mLast;
+ ObjectBaseRef<Allocation> mDefaultAlloc;
+
+
+
+ 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..3f56faa
--- /dev/null
+++ b/libs/rs/rsSampler.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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 <GLES/gl.h>
+#include <GLES/glext.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);
+ s->incUserRef();
+ return s;
+}
+
+
+}}
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
new file mode 100644
index 0000000..4b504f6
--- /dev/null
+++ b/libs/rs/rsSampler.h
@@ -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.
+ */
+
+#ifndef ANDROID_RS_SAMPLER_H
+#define ANDROID_RS_SAMPLER_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..fde31a1
--- /dev/null
+++ b/libs/rs/rsScript.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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()
+{
+ memset(&mEnviroment, 0, sizeof(mEnviroment));
+ mEnviroment.mClearColor[0] = 0;
+ mEnviroment.mClearColor[1] = 0;
+ mEnviroment.mClearColor[2] = 0;
+ mEnviroment.mClearColor[3] = 1;
+ mEnviroment.mClearDepth = 1;
+}
+
+Script::~Script()
+{
+}
+
+namespace android {
+namespace renderscript {
+
+
+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));
+}
+
+void rsi_ScriptSetClearColor(Context * rsc, RsScript vs, float r, float g, float b, float a)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mEnviroment.mClearColor[0] = r;
+ s->mEnviroment.mClearColor[1] = g;
+ s->mEnviroment.mClearColor[2] = b;
+ s->mEnviroment.mClearColor[3] = a;
+}
+
+void rsi_ScriptSetTimeZone(Context * rsc, RsScript vs, const char * timeZone, uint32_t length)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mEnviroment.mTimeZone = timeZone;
+}
+
+void rsi_ScriptSetClearDepth(Context * rsc, RsScript vs, float v)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mEnviroment.mClearDepth = v;
+}
+
+void rsi_ScriptSetClearStencil(Context * rsc, RsScript vs, uint32_t v)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->mEnviroment.mClearStencil = v;
+}
+
+void rsi_ScriptSetType(Context * rsc, RsType vt, uint32_t slot, bool writable, const char *name)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ const Type *t = static_cast<const Type *>(vt);
+ ss->mConstantBufferTypes[slot].set(t);
+ ss->mSlotWritable[slot] = writable;
+ if (name) {
+ ss->mSlotNames[slot].setTo(name);
+ } else {
+ ss->mSlotNames[slot].setTo("");
+ }
+}
+
+void rsi_ScriptSetRoot(Context * rsc, bool isRoot)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mEnviroment.mIsRoot = isRoot;
+}
+
+
+}
+}
+
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
new file mode 100644
index 0000000..60f83a6
--- /dev/null
+++ b/libs/rs/rsScript.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_SCRIPT_H
+#define ANDROID_RS_SCRIPT_H
+
+#include "rsAllocation.h"
+
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class ProgramVertex;
+class ProgramFragment;
+class ProgramRaster;
+class ProgramFragmentStore;
+
+#define MAX_SCRIPT_BANKS 16
+
+class Script : public ObjectBase
+{
+public:
+
+ Script();
+ virtual ~Script();
+
+
+ struct Enviroment_t {
+ bool mIsRoot;
+ float mClearColor[4];
+ float mClearDepth;
+ uint32_t mClearStencil;
+
+ uint32_t mStartTimeMillis;
+ const char* mTimeZone;
+
+ ObjectBaseRef<ProgramVertex> mVertex;
+ ObjectBaseRef<ProgramFragment> mFragment;
+ //ObjectBaseRef<ProgramRaster> mRaster;
+ ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
+
+ };
+ Enviroment_t mEnviroment;
+
+ uint32_t mCounstantBufferCount;
+
+ ObjectBaseRef<Allocation> mSlots[MAX_SCRIPT_BANKS];
+ ObjectBaseRef<const Type> mTypes[MAX_SCRIPT_BANKS];
+ String8 mSlotNames[MAX_SCRIPT_BANKS];
+ bool mSlotWritable[MAX_SCRIPT_BANKS];
+
+ 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..0c7ac18
--- /dev/null
+++ b/libs/rs/rsScriptC.cpp
@@ -0,0 +1,367 @@
+/*
+ * 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"
+#include "utils/Timers.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+#define GET_TLS() Context::ScriptTLSStruct * tls = \
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
+ Context * rsc = tls->mContext; \
+ ScriptC * sc = (ScriptC *) tls->mScript
+
+
+ScriptC::ScriptC()
+{
+ mAccScript = NULL;
+ memset(&mProgram, 0, sizeof(mProgram));
+}
+
+ScriptC::~ScriptC()
+{
+ if (mAccScript) {
+ accDeleteScript(mAccScript);
+ }
+}
+
+
+bool ScriptC::run(Context *rsc, uint32_t launchIndex)
+{
+ Context::ScriptTLSStruct * tls =
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey);
+
+ if (mEnviroment.mFragmentStore.get()) {
+ rsc->setFragmentStore(mEnviroment.mFragmentStore.get());
+ }
+ if (mEnviroment.mFragment.get()) {
+ rsc->setFragment(mEnviroment.mFragment.get());
+ }
+ if (mEnviroment.mVertex.get()) {
+ rsc->setVertex(mEnviroment.mVertex.get());
+ }
+
+ if (launchIndex == 0) {
+ mEnviroment.mStartTimeMillis
+ = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+ }
+
+ bool ret = false;
+ tls->mScript = this;
+ ret = mProgram.mScript(launchIndex) != 0;
+ tls->mScript = NULL;
+ return ret;
+}
+
+ScriptCState::ScriptCState()
+{
+ clear();
+}
+
+ScriptCState::~ScriptCState()
+{
+ if (mAccScript) {
+ accDeleteScript(mAccScript);
+ }
+}
+
+void ScriptCState::clear()
+{
+ memset(&mProgram, 0, sizeof(mProgram));
+
+ for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
+ mConstantBufferTypes[ct].clear();
+ mSlotNames[ct].setTo("");
+ mSlotWritable[ct] = false;
+ }
+
+ memset(&mEnviroment, 0, sizeof(mEnviroment));
+ mEnviroment.mClearColor[0] = 0;
+ mEnviroment.mClearColor[1] = 0;
+ mEnviroment.mClearColor[2] = 0;
+ mEnviroment.mClearColor[3] = 1;
+ mEnviroment.mClearDepth = 1;
+ mEnviroment.mClearStencil = 0;
+ mEnviroment.mIsRoot = false;
+
+ mAccScript = NULL;
+
+ mInt32Defines.clear();
+ mFloatDefines.clear();
+}
+
+static ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name)
+{
+ const ScriptCState::SymbolTable_t *sym = ScriptCState::lookupSymbol(name);
+ if (sym) {
+ return sym->mPtr;
+ }
+ LOGE("ScriptC sym lookup failed for %s", name);
+ return NULL;
+}
+
+void ScriptCState::runCompiler(Context *rsc)
+{
+ mAccScript = accCreateScript();
+ String8 tmp;
+
+ rsc->appendNameDefines(&tmp);
+ appendDecls(&tmp);
+ rsc->appendVarDefines(&tmp);
+ appendVarDefines(&tmp);
+ appendTypes(&tmp);
+ tmp.append("#line 1\n");
+
+ const char* scriptSource[] = {tmp.string(), mProgram.mScriptText};
+ int scriptLength[] = {tmp.length(), mProgram.mScriptTextLength} ;
+ accScriptSource(mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength);
+ accRegisterSymbolCallback(mAccScript, symbolLookup, NULL);
+ accCompileScript(mAccScript);
+ accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mProgram.mScript);
+ rsAssert(mProgram.mScript);
+
+ if (!mProgram.mScript) {
+ ACCchar buf[4096];
+ ACCsizei len;
+ accGetScriptInfoLog(mAccScript, sizeof(buf), &len, buf);
+ LOGE(buf);
+ }
+
+ mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
+ mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
+ mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
+
+ if (mProgram.mScript) {
+ const static int pragmaMax = 16;
+ ACCsizei pragmaCount;
+ ACCchar * str[pragmaMax];
+ accGetPragmas(mAccScript, &pragmaCount, pragmaMax, &str[0]);
+
+ for (int ct=0; ct < pragmaCount; ct+=2) {
+ if (!strcmp(str[ct], "version")) {
+ continue;
+ }
+
+ if (!strcmp(str[ct], "stateVertex")) {
+ if (!strcmp(str[ct+1], "default")) {
+ continue;
+ }
+ if (!strcmp(str[ct+1], "parent")) {
+ mEnviroment.mVertex.clear();
+ continue;
+ }
+ ProgramVertex * pv = (ProgramVertex *)rsc->lookupName(str[ct+1]);
+ if (pv != NULL) {
+ mEnviroment.mVertex.set(pv);
+ continue;
+ }
+ LOGE("Unreconized value %s passed to stateVertex", str[ct+1]);
+ }
+
+ if (!strcmp(str[ct], "stateRaster")) {
+ LOGE("Unreconized value %s passed to stateRaster", str[ct+1]);
+ }
+
+ if (!strcmp(str[ct], "stateFragment")) {
+ if (!strcmp(str[ct+1], "default")) {
+ continue;
+ }
+ if (!strcmp(str[ct+1], "parent")) {
+ mEnviroment.mFragment.clear();
+ continue;
+ }
+ ProgramFragment * pf = (ProgramFragment *)rsc->lookupName(str[ct+1]);
+ if (pf != NULL) {
+ mEnviroment.mFragment.set(pf);
+ continue;
+ }
+ LOGE("Unreconized value %s passed to stateFragment", str[ct+1]);
+ }
+
+ if (!strcmp(str[ct], "stateFragmentStore")) {
+ if (!strcmp(str[ct+1], "default")) {
+ continue;
+ }
+ if (!strcmp(str[ct+1], "parent")) {
+ mEnviroment.mFragmentStore.clear();
+ continue;
+ }
+ ProgramFragmentStore * pfs =
+ (ProgramFragmentStore *)rsc->lookupName(str[ct+1]);
+ if (pfs != NULL) {
+ mEnviroment.mFragmentStore.set(pfs);
+ continue;
+ }
+ LOGE("Unreconized value %s passed to stateFragmentStore", str[ct+1]);
+ }
+
+ }
+
+
+ } else {
+ // Deal with an error.
+ }
+}
+
+
+void ScriptCState::appendVarDefines(String8 *str)
+{
+ char buf[256];
+ LOGD("appendVarDefines mInt32Defines.size()=%d mFloatDefines.size()=%d\n",
+ mInt32Defines.size(), mFloatDefines.size());
+ for (size_t ct=0; ct < mInt32Defines.size(); ct++) {
+ str->append("#define ");
+ str->append(mInt32Defines.keyAt(ct));
+ str->append(" ");
+ sprintf(buf, "%i\n", (int)mInt32Defines.valueAt(ct));
+ str->append(buf);
+ }
+ for (size_t ct=0; ct < mFloatDefines.size(); ct++) {
+ str->append("#define ");
+ str->append(mFloatDefines.keyAt(ct));
+ str->append(" ");
+ sprintf(buf, "%ff\n", mFloatDefines.valueAt(ct));
+ str->append(buf);
+ }
+}
+
+void ScriptCState::appendTypes(String8 *str)
+{
+ char buf[256];
+ String8 tmp;
+
+ for (size_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
+ const Type *t = mConstantBufferTypes[ct].get();
+ if (!t) {
+ continue;
+ }
+ const Element *e = t->getElement();
+
+ if (t->getName()) {
+ for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) {
+ const Component *c = e->getComponent(ct2);
+ tmp.setTo("#define OFFSETOF_");
+ tmp.append(t->getName());
+ tmp.append("_");
+ tmp.append(c->getComponentName());
+ sprintf(buf, " %i\n", ct2);
+ tmp.append(buf);
+ //LOGD(tmp);
+ str->append(tmp);
+ }
+ }
+
+ if (mSlotNames[ct].length() > 0) {
+ for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) {
+ const Component *c = e->getComponent(ct2);
+ tmp.setTo("#define ");
+ tmp.append(mSlotNames[ct]);
+ tmp.append("_");
+ tmp.append(c->getComponentName());
+ switch (c->getType()) {
+ case Component::FLOAT:
+ tmp.append(" loadF(");
+ break;
+ case Component::SIGNED:
+ sprintf(buf, " loadI%i(", c->getBits());
+ tmp.append(buf);
+ break;
+ case Component::UNSIGNED:
+ sprintf(buf, " loadU%i(", c->getBits());
+ tmp.append(buf);
+ break;
+ }
+ sprintf(buf, "%i, %i)\n", ct, ct2);
+ tmp.append(buf);
+
+ //LOGD(tmp);
+ str->append(tmp);
+ }
+ }
+ }
+
+}
+
+
+namespace android {
+namespace renderscript {
+
+void rsi_ScriptCBegin(Context * rsc)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->clear();
+}
+
+void rsi_ScriptCSetScript(Context * rsc, void *vp)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
+}
+
+void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mProgram.mScriptText = text;
+ ss->mProgram.mScriptTextLength = len;
+}
+
+
+RsScript rsi_ScriptCCreate(Context * rsc)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+
+ ss->runCompiler(rsc);
+
+ ScriptC *s = new ScriptC();
+ s->incUserRef();
+ s->mAccScript = ss->mAccScript;
+ ss->mAccScript = NULL;
+ s->mEnviroment = ss->mEnviroment;
+ s->mProgram = ss->mProgram;
+ for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
+ s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get());
+ s->mSlotNames[ct] = ss->mSlotNames[ct];
+ s->mSlotWritable[ct] = ss->mSlotWritable[ct];
+ }
+
+ ss->clear();
+ return s;
+}
+
+void rsi_ScriptCSetDefineF(Context *rsc, const char* name, float value)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mFloatDefines.add(String8(name), value);
+}
+
+void rsi_ScriptCSetDefineI32(Context *rsc, const char* name, int32_t value)
+{
+ ScriptCState *ss = &rsc->mScriptC;
+ ss->mInt32Defines.add(String8(name), value);
+}
+
+}
+}
+
+
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
new file mode 100644
index 0000000..302515e
--- /dev/null
+++ b/libs/rs/rsScriptC.h
@@ -0,0 +1,100 @@
+/*
+ * 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"
+
+#include <utils/KeyedVector.h>
+
+struct ACCscript;
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+
+class ScriptC : public Script
+{
+public:
+ typedef int (*RunScript_t)(uint32_t launchIndex);
+
+ ScriptC();
+ virtual ~ScriptC();
+
+ struct Program_t {
+ const char * mScriptText;
+ uint32_t mScriptTextLength;
+
+
+ int mVersionMajor;
+ int mVersionMinor;
+
+ RunScript_t mScript;
+ };
+
+ Program_t mProgram;
+
+ ACCscript* mAccScript;
+
+ virtual bool run(Context *, uint32_t launchID);
+};
+
+class ScriptCState
+{
+public:
+ ScriptCState();
+ ~ScriptCState();
+
+ ACCscript* mAccScript;
+
+ ScriptC::Program_t mProgram;
+ Script::Enviroment_t mEnviroment;
+
+ ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS];
+ String8 mSlotNames[MAX_SCRIPT_BANKS];
+ bool mSlotWritable[MAX_SCRIPT_BANKS];
+
+ void clear();
+ void runCompiler(Context *rsc);
+ void appendVarDefines(String8 *str);
+ void appendTypes(String8 *str);
+
+ struct SymbolTable_t {
+ const char * mName;
+ void * mPtr;
+ const char * mRet;
+ const char * mParam;
+ };
+ static SymbolTable_t gSyms[];
+ static const SymbolTable_t * lookupSymbol(const char *);
+ static void appendDecls(String8 *str);
+
+ KeyedVector<String8,int> mInt32Defines;
+ KeyedVector<String8,float> mFloatDefines;
+};
+
+
+}
+}
+#endif
+
+
+
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
new file mode 100644
index 0000000..84a39aa
--- /dev/null
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -0,0 +1,1159 @@
+/*
+ * 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 "rsNoise.h"
+
+#include "acc/acc.h"
+#include "utils/Timers.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <time.h>
+#include <cutils/tztime.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+#define GET_TLS() Context::ScriptTLSStruct * tls = \
+ (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey); \
+ Context * rsc = tls->mContext; \
+ ScriptC * sc = (ScriptC *) tls->mScript
+
+
+//////////////////////////////////////////////////////////////////////////////
+// IO routines
+//////////////////////////////////////////////////////////////////////////////
+
+static float SC_loadF(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const float *f = static_cast<const float *>(vp);
+ //LOGE("loadF %i %i = %f %x", bank, offset, f, ((int *)&f)[0]);
+ return f[offset];
+}
+
+static int32_t SC_loadI32(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const int32_t *i = static_cast<const int32_t *>(vp);
+ //LOGE("loadI32 %i %i = %i", bank, offset, t);
+ return i[offset];
+}
+
+static float* SC_loadArrayF(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ return f + offset;
+}
+
+static int32_t* SC_loadArrayI32(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ int32_t *i = static_cast<int32_t *>(vp);
+ return i + offset;
+}
+
+static float* SC_loadTriangleMeshVerticesF(RsTriangleMesh mesh)
+{
+ TriangleMesh *tm = static_cast<TriangleMesh *>(mesh);
+ void *vp = tm->mVertexData;
+ float *f = static_cast<float *>(vp);
+ return f;
+}
+
+static void SC_updateTriangleMesh(RsTriangleMesh mesh)
+{
+ TriangleMesh *tm = static_cast<TriangleMesh *>(mesh);
+ 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);
+}
+
+static uint32_t SC_loadU32(uint32_t bank, uint32_t offset)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const uint32_t *i = static_cast<const uint32_t *>(vp);
+ return i[offset];
+}
+
+static void SC_loadVec4(uint32_t bank, uint32_t offset, rsc_Vector4 *v)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const float *f = static_cast<const float *>(vp);
+ memcpy(v, &f[offset], sizeof(rsc_Vector4));
+}
+
+static void SC_loadMatrix(uint32_t bank, uint32_t offset, rsc_Matrix *m)
+{
+ GET_TLS();
+ const void *vp = sc->mSlots[bank]->getPtr();
+ const float *f = static_cast<const float *>(vp);
+ memcpy(m, &f[offset], sizeof(rsc_Matrix));
+}
+
+
+static void SC_storeF(uint32_t bank, uint32_t offset, float v)
+{
+ //LOGE("storeF %i %i %f", bank, offset, v);
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ f[offset] = v;
+}
+
+static void SC_storeI32(uint32_t bank, uint32_t offset, int32_t v)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ int32_t *f = static_cast<int32_t *>(vp);
+ static_cast<int32_t *>(sc->mSlots[bank]->getPtr())[offset] = v;
+}
+
+static void SC_storeU32(uint32_t bank, uint32_t offset, uint32_t v)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ uint32_t *f = static_cast<uint32_t *>(vp);
+ static_cast<uint32_t *>(sc->mSlots[bank]->getPtr())[offset] = v;
+}
+
+static void SC_storeVec4(uint32_t bank, uint32_t offset, const rsc_Vector4 *v)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ memcpy(&f[offset], v, sizeof(rsc_Vector4));
+}
+
+static void SC_storeMatrix(uint32_t bank, uint32_t offset, const rsc_Matrix *m)
+{
+ GET_TLS();
+ void *vp = sc->mSlots[bank]->getPtr();
+ float *f = static_cast<float *>(vp);
+ memcpy(&f[offset], m, sizeof(rsc_Matrix));
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Math routines
+//////////////////////////////////////////////////////////////////////////////
+
+#define PI 3.1415926f
+#define DEG_TO_RAD PI / 180.0f
+#define RAD_TO_DEG 180.0f / PI
+
+static float SC_sinf_fast(float x)
+{
+ const float A = 1.0f / (2.0f * M_PI);
+ const float B = -16.0f;
+ const float C = 8.0f;
+
+ // scale angle for easy argument reduction
+ x *= A;
+
+ if (fabsf(x) >= 0.5f) {
+ // argument reduction
+ x = x - ceilf(x + 0.5f) + 1.0f;
+ }
+
+ const float y = B * x * fabsf(x) + C * x;
+ return 0.2215f * (y * fabsf(y) - y) + y;
+}
+
+static float SC_cosf_fast(float x)
+{
+ x += float(M_PI / 2);
+
+ const float A = 1.0f / (2.0f * M_PI);
+ const float B = -16.0f;
+ const float C = 8.0f;
+
+ // scale angle for easy argument reduction
+ x *= A;
+
+ if (fabsf(x) >= 0.5f) {
+ // argument reduction
+ x = x - ceilf(x + 0.5f) + 1.0f;
+ }
+
+ const float y = B * x * fabsf(x) + C * x;
+ return 0.2215f * (y * fabsf(y) - y) + y;
+}
+
+static float SC_randf(float max)
+{
+ float r = (float)rand();
+ return r / RAND_MAX * max;
+}
+
+static float SC_randf2(float min, float max)
+{
+ float r = (float)rand();
+ return r / RAND_MAX * (max - min) + min;
+}
+
+static float SC_clampf(float amount, float low, float high)
+{
+ return amount < low ? low : (amount > high ? high : amount);
+}
+
+static int SC_clamp(int amount, int low, int high)
+{
+ return amount < low ? low : (amount > high ? high : amount);
+}
+
+static float SC_maxf(float a, float b)
+{
+ return a > b ? a : b;
+}
+
+static float SC_minf(float a, float b)
+{
+ return a < b ? a : b;
+}
+
+static float SC_sqrf(float v)
+{
+ return v * v;
+}
+
+static int SC_sqr(int v)
+{
+ return v * v;
+}
+
+static float SC_distf2(float x1, float y1, float x2, float y2)
+{
+ float x = x2 - x1;
+ float y = y2 - y1;
+ return sqrtf(x * x + y * y);
+}
+
+static float SC_distf3(float x1, float y1, float z1, float x2, float y2, float z2)
+{
+ float x = x2 - x1;
+ float y = y2 - y1;
+ float z = z2 - z1;
+ return sqrtf(x * x + y * y + z * z);
+}
+
+static float SC_magf2(float a, float b)
+{
+ return sqrtf(a * a + b * b);
+}
+
+static float SC_magf3(float a, float b, float c)
+{
+ return sqrtf(a * a + b * b + c * c);
+}
+
+static float SC_radf(float degrees)
+{
+ return degrees * DEG_TO_RAD;
+}
+
+static float SC_degf(float radians)
+{
+ return radians * RAD_TO_DEG;
+}
+
+static float SC_lerpf(float start, float stop, float amount)
+{
+ return start + (stop - start) * amount;
+}
+
+static float SC_normf(float start, float stop, float value)
+{
+ return (value - start) / (stop - start);
+}
+
+static float SC_mapf(float minStart, float minStop, float maxStart, float maxStop, float value)
+{
+ return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Time routines
+//////////////////////////////////////////////////////////////////////////////
+
+static int32_t SC_second()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_sec;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_sec;
+ }
+}
+
+static int32_t SC_minute()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_min;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_min;
+ }
+}
+
+static int32_t SC_hour()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_hour;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_hour;
+ }
+}
+
+static int32_t SC_day()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_mday;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_mday;
+ }
+}
+
+static int32_t SC_month()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_mon;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_mon;
+ }
+}
+
+static int32_t SC_year()
+{
+ GET_TLS();
+
+ time_t rawtime;
+ time(&rawtime);
+
+ if (sc->mEnviroment.mTimeZone) {
+ struct tm timeinfo;
+ localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+ return timeinfo.tm_year;
+ } else {
+ struct tm *timeinfo;
+ timeinfo = localtime(&rawtime);
+ return timeinfo->tm_year;
+ }
+}
+
+static int32_t SC_uptimeMillis()
+{
+ return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+}
+
+static int32_t SC_startTimeMillis()
+{
+ GET_TLS();
+ return sc->mEnviroment.mStartTimeMillis;
+}
+
+static int32_t SC_elapsedTimeMillis()
+{
+ GET_TLS();
+ return nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC))
+ - sc->mEnviroment.mStartTimeMillis;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Matrix routines
+//////////////////////////////////////////////////////////////////////////////
+
+
+static void SC_matrixLoadIdentity(rsc_Matrix *mat)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadIdentity();
+}
+
+static void SC_matrixLoadFloat(rsc_Matrix *mat, const float *f)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->load(f);
+}
+
+static void SC_matrixLoadMat(rsc_Matrix *mat, const rsc_Matrix *newmat)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->load(reinterpret_cast<const Matrix *>(newmat));
+}
+
+static void SC_matrixLoadRotate(rsc_Matrix *mat, float rot, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadRotate(rot, x, y, z);
+}
+
+static void SC_matrixLoadScale(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadScale(x, y, z);
+}
+
+static void SC_matrixLoadTranslate(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->loadTranslate(x, y, z);
+}
+
+static void SC_matrixLoadMultiply(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));
+}
+
+static void SC_matrixMultiply(rsc_Matrix *mat, const rsc_Matrix *rhs)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->multiply(reinterpret_cast<const Matrix *>(rhs));
+}
+
+static void SC_matrixRotate(rsc_Matrix *mat, float rot, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->rotate(rot, x, y, z);
+}
+
+static void SC_matrixScale(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->scale(x, y, z);
+}
+
+static void SC_matrixTranslate(rsc_Matrix *mat, float x, float y, float z)
+{
+ Matrix *m = reinterpret_cast<Matrix *>(mat);
+ m->translate(x, y, z);
+}
+
+
+static void SC_vec2Rand(float *vec, float maxLen)
+{
+ float angle = SC_randf(PI * 2);
+ float len = SC_randf(maxLen);
+ vec[0] = len * sinf(angle);
+ vec[1] = len * cosf(angle);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Context
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_bindTexture(RsProgramFragment vpf, uint32_t slot, RsAllocation va)
+{
+ GET_TLS();
+ rsi_ProgramFragmentBindTexture(rsc,
+ static_cast<ProgramFragment *>(vpf),
+ slot,
+ static_cast<Allocation *>(va));
+
+}
+
+static void SC_bindSampler(RsProgramFragment vpf, uint32_t slot, RsSampler vs)
+{
+ GET_TLS();
+ rsi_ProgramFragmentBindSampler(rsc,
+ static_cast<ProgramFragment *>(vpf),
+ slot,
+ static_cast<Sampler *>(vs));
+
+}
+
+static void SC_bindProgramFragmentStore(RsProgramFragmentStore pfs)
+{
+ GET_TLS();
+ rsi_ContextBindProgramFragmentStore(rsc, pfs);
+
+}
+
+static void SC_bindProgramFragment(RsProgramFragment pf)
+{
+ GET_TLS();
+ rsi_ContextBindProgramFragment(rsc, pf);
+
+}
+
+static void SC_bindProgramVertex(RsProgramVertex pv)
+{
+ GET_TLS();
+ rsi_ContextBindProgramVertex(rsc, pv);
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// VP
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_vpLoadModelMatrix(const rsc_Matrix *m)
+{
+ GET_TLS();
+ rsc->getVertex()->setModelviewMatrix(m);
+}
+
+static void SC_vpLoadTextureMatrix(const rsc_Matrix *m)
+{
+ GET_TLS();
+ rsc->getVertex()->setTextureMatrix(m);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Drawing
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_drawTriangleMesh(RsTriangleMesh mesh)
+{
+ GET_TLS();
+ rsi_TriangleMeshRender(rsc, mesh);
+}
+
+static void SC_drawTriangleMeshRange(RsTriangleMesh mesh, uint32_t start, uint32_t count)
+{
+ GET_TLS();
+ rsi_TriangleMeshRenderRange(rsc, mesh, start, count);
+}
+
+static void SC_drawLine(float x1, float y1, float z1,
+ float x2, float y2, float z2)
+{
+ GET_TLS();
+ rsc->setupCheck();
+
+ float vtx[] = { x1, y1, z1, x2, y2, z2 };
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, vtx);
+
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ glDrawArrays(GL_LINES, 0, 2);
+}
+
+static void SC_drawQuadTexCoords(float x1, float y1, float z1,
+ float u1, float v1,
+ float x2, float y2, float z2,
+ float u2, float v2,
+ float x3, float y3, float z3,
+ float u3, float v3,
+ float x4, float y4, float z4,
+ float u4, float v4)
+{
+ GET_TLS();
+
+ //LOGE("Quad");
+ //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
+ //LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2);
+ //LOGE("%4.2f, %4.2f, %4.2f", x3, y3, z3);
+ //LOGE("%4.2f, %4.2f, %4.2f", x4, y4, z4);
+
+ float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
+ const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
+
+ rsc->setupCheck();
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tm->mBufferObjects[1]);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, vtx);
+
+ glClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex);
+ glClientActiveTexture(GL_TEXTURE1);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex);
+ glClientActiveTexture(GL_TEXTURE0);
+
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ //glColorPointer(4, GL_UNSIGNED_BYTE, 12, ptr);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+}
+
+static void SC_drawQuad(float x1, float y1, float z1,
+ float x2, float y2, float z2,
+ float x3, float y3, float z3,
+ float x4, float y4, float z4)
+{
+ SC_drawQuadTexCoords(x1, y1, z1, 0, 1,
+ x2, y2, z2, 1, 1,
+ x3, y3, z3, 1, 0,
+ x4, y4, z4, 0, 0);
+}
+
+static void SC_drawRect(float x1, float y1,
+ float x2, float y2, float z)
+{
+ SC_drawQuad(x1, y2, z,
+ x2, y2, z,
+ x2, y1, z,
+ x1, y1, z);
+}
+
+static void SC_drawSimpleMesh(RsSimpleMesh vsm)
+{
+ GET_TLS();
+ SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+ rsc->setupCheck();
+ sm->render();
+}
+
+static void SC_drawSimpleMeshRange(RsSimpleMesh vsm, uint32_t start, uint32_t len)
+{
+ GET_TLS();
+ SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
+ rsc->setupCheck();
+ sm->renderRange(start, len);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//////////////////////////////////////////////////////////////////////////////
+
+static void SC_color(float r, float g, float b, float a)
+{
+ glColor4f(r, g, b, a);
+}
+
+static void SC_ambient(float r, float g, float b, float a)
+{
+ GLfloat params[] = { r, g, b, a };
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, params);
+}
+
+static void SC_diffuse(float r, float g, float b, float a)
+{
+ GLfloat params[] = { r, g, b, a };
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, params);
+}
+
+static void SC_specular(float r, float g, float b, float a)
+{
+ GLfloat params[] = { r, g, b, a };
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, params);
+}
+
+static void SC_emission(float r, float g, float b, float a)
+{
+ GLfloat params[] = { r, g, b, a };
+ glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, params);
+}
+
+static void SC_shininess(float s)
+{
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, s);
+}
+
+static void SC_hsbToRgb(float h, float s, float b, float* rgb)
+{
+ float red = 0.0f;
+ float green = 0.0f;
+ float blue = 0.0f;
+
+ float x = h;
+ float y = s;
+ float z = b;
+
+ float hf = (x - (int) x) * 6.0f;
+ int ihf = (int) hf;
+ float f = hf - ihf;
+ float pv = z * (1.0f - y);
+ float qv = z * (1.0f - y * f);
+ float tv = z * (1.0f - y * (1.0f - f));
+
+ switch (ihf) {
+ case 0: // Red is the dominant color
+ red = z;
+ green = tv;
+ blue = pv;
+ break;
+ case 1: // Green is the dominant color
+ red = qv;
+ green = z;
+ blue = pv;
+ break;
+ case 2:
+ red = pv;
+ green = z;
+ blue = tv;
+ break;
+ case 3: // Blue is the dominant color
+ red = pv;
+ green = qv;
+ blue = z;
+ break;
+ case 4:
+ red = tv;
+ green = pv;
+ blue = z;
+ break;
+ case 5: // Red is the dominant color
+ red = z;
+ green = pv;
+ blue = qv;
+ break;
+ }
+
+ rgb[0] = red;
+ rgb[1] = green;
+ rgb[2] = blue;
+}
+
+static int SC_hsbToAbgr(float h, float s, float b, float a)
+{
+ float rgb[3];
+ SC_hsbToRgb(h, s, b, rgb);
+ return int(a * 255.0f) << 24 |
+ int(rgb[2] * 255.0f) << 16 |
+ int(rgb[1] * 255.0f) << 8 |
+ int(rgb[0] * 255.0f);
+}
+
+static void SC_hsb(float h, float s, float b, float a)
+{
+ float rgb[3];
+ SC_hsbToRgb(h, s, b, rgb);
+ glColor4f(rgb[0], rgb[1], rgb[2], a);
+}
+
+static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
+{
+ GET_TLS();
+ rsi_AllocationUploadToTexture(rsc, va, baseMipLevel);
+}
+
+static void SC_uploadToBufferObject(RsAllocation va)
+{
+ GET_TLS();
+ rsi_AllocationUploadToBufferObject(rsc, va);
+}
+
+static void SC_ClearColor(float r, float g, float b, float a)
+{
+ //LOGE("c %f %f %f %f", r, g, b, a);
+ GET_TLS();
+ sc->mEnviroment.mClearColor[0] = r;
+ sc->mEnviroment.mClearColor[1] = g;
+ sc->mEnviroment.mClearColor[2] = b;
+ sc->mEnviroment.mClearColor[3] = a;
+}
+
+static void SC_debugF(const char *s, float f)
+{
+ LOGE("%s %f", s, f);
+}
+
+static void SC_debugHexF(const char *s, float f)
+{
+ LOGE("%s 0x%x", s, *((int *) (&f)));
+}
+
+static void SC_debugI32(const char *s, int32_t i)
+{
+ LOGE("%s %i", s, i);
+}
+
+static void SC_debugHexI32(const char *s, int32_t i)
+{
+ LOGE("%s 0x%x", s, i);
+}
+
+static uint32_t SC_getWidth()
+{
+ GET_TLS();
+ return rsc->getWidth();
+}
+
+static uint32_t SC_getHeight()
+{
+ GET_TLS();
+ return rsc->getHeight();
+}
+
+static uint32_t SC_colorFloatRGBAtoUNorm8(float r, float g, float b, float a)
+{
+ uint32_t c = 0;
+ c |= (uint32_t)(r * 255.f + 0.5f);
+ c |= ((uint32_t)(g * 255.f + 0.5f)) << 8;
+ c |= ((uint32_t)(b * 255.f + 0.5f)) << 16;
+ c |= ((uint32_t)(a * 255.f + 0.5f)) << 24;
+ return c;
+}
+
+static uint32_t SC_colorFloatRGBAto565(float r, float g, float b)
+{
+ uint32_t ir = (uint32_t)(r * 255.f + 0.5f);
+ uint32_t ig = (uint32_t)(g * 255.f + 0.5f);
+ uint32_t ib = (uint32_t)(b * 255.f + 0.5f);
+ return rs888to565(ir, ig, ib);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Class implementation
+//////////////////////////////////////////////////////////////////////////////
+
+ScriptCState::SymbolTable_t ScriptCState::gSyms[] = {
+ // IO
+ { "loadI32", (void *)&SC_loadI32,
+ "int", "(int, int)" },
+ //{ "loadU32", (void *)&SC_loadU32, "unsigned int", "(int, int)" },
+ { "loadF", (void *)&SC_loadF,
+ "float", "(int, int)" },
+ { "loadArrayF", (void *)&SC_loadArrayF,
+ "float*", "(int, int)" },
+ { "loadArrayI32", (void *)&SC_loadArrayI32,
+ "int*", "(int, int)" },
+ { "loadVec4", (void *)&SC_loadVec4,
+ "void", "(int, int, float *)" },
+ { "loadMatrix", (void *)&SC_loadMatrix,
+ "void", "(int, int, float *)" },
+ { "storeI32", (void *)&SC_storeI32,
+ "void", "(int, int, int)" },
+ //{ "storeU32", (void *)&SC_storeU32, "void", "(int, int, unsigned int)" },
+ { "storeF", (void *)&SC_storeF,
+ "void", "(int, int, float)" },
+ { "storeVec4", (void *)&SC_storeVec4,
+ "void", "(int, int, float *)" },
+ { "storeMatrix", (void *)&SC_storeMatrix,
+ "void", "(int, int, float *)" },
+ { "loadTriangleMeshVerticesF", (void *)&SC_loadTriangleMeshVerticesF,
+ "float*", "(int)" },
+ { "updateTriangleMesh", (void *)&SC_updateTriangleMesh,
+ "void", "(int)" },
+
+ // math
+ { "modf", (void *)&fmod,
+ "float", "(float, float)" },
+ { "abs", (void *)&abs,
+ "int", "(int)" },
+ { "absf", (void *)&fabs,
+ "float", "(float)" },
+ { "sinf_fast", (void *)&SC_sinf_fast,
+ "float", "(float)" },
+ { "cosf_fast", (void *)&SC_cosf_fast,
+ "float", "(float)" },
+ { "sinf", (void *)&sinf,
+ "float", "(float)" },
+ { "cosf", (void *)&cosf,
+ "float", "(float)" },
+ { "asinf", (void *)&asinf,
+ "float", "(float)" },
+ { "acosf", (void *)&acosf,
+ "float", "(float)" },
+ { "atanf", (void *)&atanf,
+ "float", "(float)" },
+ { "atan2f", (void *)&atan2f,
+ "float", "(float, float)" },
+ { "fabsf", (void *)&fabsf,
+ "float", "(float)" },
+ { "randf", (void *)&SC_randf,
+ "float", "(float)" },
+ { "randf2", (void *)&SC_randf2,
+ "float", "(float, float)" },
+ { "floorf", (void *)&floorf,
+ "float", "(float)" },
+ { "ceilf", (void *)&ceilf,
+ "float", "(float)" },
+ { "expf", (void *)&expf,
+ "float", "(float)" },
+ { "logf", (void *)&logf,
+ "float", "(float)" },
+ { "powf", (void *)&powf,
+ "float", "(float, float)" },
+ { "maxf", (void *)&SC_maxf,
+ "float", "(float, float)" },
+ { "minf", (void *)&SC_minf,
+ "float", "(float, float)" },
+ { "sqrt", (void *)&sqrt,
+ "int", "(int)" },
+ { "sqrtf", (void *)&sqrtf,
+ "float", "(float)" },
+ { "sqr", (void *)&SC_sqr,
+ "int", "(int)" },
+ { "sqrf", (void *)&SC_sqrf,
+ "float", "(float)" },
+ { "clamp", (void *)&SC_clamp,
+ "int", "(int, int, int)" },
+ { "clampf", (void *)&SC_clampf,
+ "float", "(float, float, float)" },
+ { "distf2", (void *)&SC_distf2,
+ "float", "(float, float, float, float)" },
+ { "distf3", (void *)&SC_distf3,
+ "float", "(float, float, float, float, float, float)" },
+ { "magf2", (void *)&SC_magf2,
+ "float", "(float, float)" },
+ { "magf3", (void *)&SC_magf3,
+ "float", "(float, float, float)" },
+ { "radf", (void *)&SC_radf,
+ "float", "(float)" },
+ { "degf", (void *)&SC_degf,
+ "float", "(float)" },
+ { "lerpf", (void *)&SC_lerpf,
+ "float", "(float, float, float)" },
+ { "normf", (void *)&SC_normf,
+ "float", "(float, float, float)" },
+ { "mapf", (void *)&SC_mapf,
+ "float", "(float, float, float, float, float)" },
+ { "noisef", (void *)&SC_noisef,
+ "float", "(float)" },
+ { "noisef2", (void *)&SC_noisef2,
+ "float", "(float, float)" },
+ { "noisef3", (void *)&SC_noisef3,
+ "float", "(float, float, float)" },
+ { "turbulencef2", (void *)&SC_turbulencef2,
+ "float", "(float, float, float)" },
+ { "turbulencef3", (void *)&SC_turbulencef3,
+ "float", "(float, float, float, float)" },
+
+ // time
+ { "second", (void *)&SC_second,
+ "int", "()" },
+ { "minute", (void *)&SC_minute,
+ "int", "()" },
+ { "hour", (void *)&SC_hour,
+ "int", "()" },
+ { "day", (void *)&SC_day,
+ "int", "()" },
+ { "month", (void *)&SC_month,
+ "int", "()" },
+ { "year", (void *)&SC_year,
+ "int", "()" },
+ { "uptimeMillis", (void*)&SC_uptimeMillis,
+ "int", "()" }, // TODO: use long instead
+ { "startTimeMillis", (void*)&SC_startTimeMillis,
+ "int", "()" }, // TODO: use long instead
+ { "elapsedTimeMillis", (void*)&SC_elapsedTimeMillis,
+ "int", "()" }, // TODO: use long instead
+
+ // matrix
+ { "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity,
+ "void", "(float *mat)" },
+ { "matrixLoadFloat", (void *)&SC_matrixLoadFloat,
+ "void", "(float *mat, float *f)" },
+ { "matrixLoadMat", (void *)&SC_matrixLoadMat,
+ "void", "(float *mat, float *newmat)" },
+ { "matrixLoadRotate", (void *)&SC_matrixLoadRotate,
+ "void", "(float *mat, float rot, float x, float y, float z)" },
+ { "matrixLoadScale", (void *)&SC_matrixLoadScale,
+ "void", "(float *mat, float x, float y, float z)" },
+ { "matrixLoadTranslate", (void *)&SC_matrixLoadTranslate,
+ "void", "(float *mat, float x, float y, float z)" },
+ { "matrixLoadMultiply", (void *)&SC_matrixLoadMultiply,
+ "void", "(float *mat, float *lhs, float *rhs)" },
+ { "matrixMultiply", (void *)&SC_matrixMultiply,
+ "void", "(float *mat, float *rhs)" },
+ { "matrixRotate", (void *)&SC_matrixRotate,
+ "void", "(float *mat, float rot, float x, float y, float z)" },
+ { "matrixScale", (void *)&SC_matrixScale,
+ "void", "(float *mat, float x, float y, float z)" },
+ { "matrixTranslate", (void *)&SC_matrixTranslate,
+ "void", "(float *mat, float x, float y, float z)" },
+
+ // vector
+ { "vec2Rand", (void *)&SC_vec2Rand,
+ "void", "(float *vec, float maxLen)" },
+
+ // context
+ { "bindProgramFragment", (void *)&SC_bindProgramFragment,
+ "void", "(int)" },
+ { "bindProgramFragmentStore", (void *)&SC_bindProgramFragmentStore,
+ "void", "(int)" },
+ { "bindProgramVertex", (void *)&SC_bindProgramVertex,
+ "void", "(int)" },
+ { "bindSampler", (void *)&SC_bindSampler,
+ "void", "(int, int, int)" },
+ { "bindTexture", (void *)&SC_bindTexture,
+ "void", "(int, int, int)" },
+
+ // vp
+ { "vpLoadModelMatrix", (void *)&SC_vpLoadModelMatrix,
+ "void", "(void *)" },
+ { "vpLoadTextureMatrix", (void *)&SC_vpLoadTextureMatrix,
+ "void", "(void *)" },
+
+
+
+ // drawing
+ { "drawRect", (void *)&SC_drawRect,
+ "void", "(float x1, float y1, float x2, float y2, float z)" },
+ { "drawQuad", (void *)&SC_drawQuad,
+ "void", "(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4)" },
+ { "drawQuadTexCoords", (void *)&SC_drawQuadTexCoords,
+ "void", "(float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, float x4, float y4, float z4, float u4, float v4)" },
+ { "drawTriangleMesh", (void *)&SC_drawTriangleMesh,
+ "void", "(int mesh)" },
+ { "drawTriangleMeshRange", (void *)&SC_drawTriangleMeshRange,
+ "void", "(int mesh, int start, int count)" },
+ { "drawLine", (void *)&SC_drawLine,
+ "void", "(float x1, float y1, float z1, float x2, float y2, float z2)" },
+ { "drawSimpleMesh", (void *)&SC_drawSimpleMesh,
+ "void", "(int ism)" },
+ { "drawSimpleMeshRange", (void *)&SC_drawSimpleMeshRange,
+ "void", "(int ism, int start, int len)" },
+
+
+ // misc
+ { "pfClearColor", (void *)&SC_ClearColor,
+ "void", "(float, float, float, float)" },
+ { "color", (void *)&SC_color,
+ "void", "(float, float, float, float)" },
+ { "hsb", (void *)&SC_hsb,
+ "void", "(float, float, float, float)" },
+ { "hsbToRgb", (void *)&SC_hsbToRgb,
+ "void", "(float, float, float, float*)" },
+ { "hsbToAbgr", (void *)&SC_hsbToAbgr,
+ "int", "(float, float, float, float)" },
+ { "ambient", (void *)&SC_ambient,
+ "void", "(float, float, float, float)" },
+ { "diffuse", (void *)&SC_diffuse,
+ "void", "(float, float, float, float)" },
+ { "specular", (void *)&SC_specular,
+ "void", "(float, float, float, float)" },
+ { "emission", (void *)&SC_emission,
+ "void", "(float, float, float, float)" },
+ { "shininess", (void *)&SC_shininess,
+ "void", "(float)" },
+
+ { "uploadToTexture", (void *)&SC_uploadToTexture,
+ "void", "(int, int)" },
+ { "uploadToBufferObject", (void *)&SC_uploadToBufferObject,
+ "void", "(int)" },
+
+ { "colorFloatRGBAtoUNorm8", (void *)&SC_colorFloatRGBAtoUNorm8,
+ "int", "(float, float, float, float)" },
+ { "colorFloatRGBto565", (void *)&SC_colorFloatRGBAto565,
+ "int", "(float, float, float)" },
+
+
+ { "getWidth", (void *)&SC_getWidth,
+ "int", "()" },
+ { "getHeight", (void *)&SC_getHeight,
+ "int", "()" },
+
+
+
+ { "debugF", (void *)&SC_debugF,
+ "void", "(void *, float)" },
+ { "debugI32", (void *)&SC_debugI32,
+ "void", "(void *, int)" },
+ { "debugHexF", (void *)&SC_debugHexF,
+ "void", "(void *, float)" },
+ { "debugHexI32", (void *)&SC_debugHexI32,
+ "void", "(void *, int)" },
+
+
+ { NULL, NULL, NULL, NULL }
+};
+
+const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym)
+{
+ ScriptCState::SymbolTable_t *syms = gSyms;
+
+ while (syms->mPtr) {
+ if (!strcmp(syms->mName, sym)) {
+ return syms;
+ }
+ syms++;
+ }
+ return NULL;
+}
+
+void ScriptCState::appendDecls(String8 *str)
+{
+ ScriptCState::SymbolTable_t *syms = gSyms;
+ while (syms->mPtr) {
+ str->append(syms->mRet);
+ str->append(" ");
+ str->append(syms->mName);
+ str->append(syms->mParam);
+ str->append(";\n");
+ syms++;
+ }
+}
+
+
diff --git a/libs/rs/rsSimpleMesh.cpp b/libs/rs/rsSimpleMesh.cpp
new file mode 100644
index 0000000..7c73eb9
--- /dev/null
+++ b/libs/rs/rsSimpleMesh.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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>
+
+SimpleMesh::SimpleMesh()
+{
+}
+
+SimpleMesh::~SimpleMesh()
+{
+}
+
+void SimpleMesh::render() const
+{
+ if (mPrimitiveType.get()) {
+ renderRange(0, mPrimitiveType->getDimX());
+ return;
+ }
+
+ if (mIndexType.get()) {
+ renderRange(0, mIndexType->getDimX());
+ return;
+ }
+
+ renderRange(0, mVertexTypes[0]->getDimX());
+}
+
+void SimpleMesh::renderRange(uint32_t start, uint32_t len) const
+{
+ if (len < 1) {
+ return;
+ }
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
+ glClientActiveTexture(GL_TEXTURE0 + ct);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+ glClientActiveTexture(GL_TEXTURE0);
+
+ for (uint32_t ct=0; ct < mVertexTypeCount; ct++) {
+ glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[ct]->getBufferObjectID());
+ mVertexTypes[ct]->enableGLVertexBuffer();
+ }
+
+ if (mIndexType.get()) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
+ glDrawElements(mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
+ } else {
+ glDrawArrays(mGLPrimitive, start, len);
+ }
+}
+
+
+
+SimpleMeshContext::SimpleMeshContext()
+{
+}
+
+SimpleMeshContext::~SimpleMeshContext()
+{
+}
+
+
+namespace android {
+namespace renderscript {
+
+
+RsSimpleMesh rsi_SimpleMeshCreate(Context *rsc, RsType prim, RsType idx, RsType *vtx, uint32_t vtxCount, uint32_t primType)
+{
+ SimpleMesh *sm = new SimpleMesh();
+ sm->incUserRef();
+
+ sm->mIndexType.set((const Type *)idx);
+ sm->mPrimitiveType.set((const Type *)prim);
+
+ sm->mVertexTypeCount = vtxCount;
+ sm->mVertexTypes = new ObjectBaseRef<const Type>[vtxCount];
+ sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
+ for (uint32_t ct=0; ct < vtxCount; ct++) {
+ sm->mVertexTypes[ct].set((const Type *)vtx[ct]);
+ }
+
+ sm->mPrimitive = (RsPrimitive)primType;
+ switch(sm->mPrimitive) {
+ case RS_PRIMITIVE_POINT: sm->mGLPrimitive = GL_POINTS; break;
+ case RS_PRIMITIVE_LINE: sm->mGLPrimitive = GL_LINES; break;
+ case RS_PRIMITIVE_LINE_STRIP: sm->mGLPrimitive = GL_LINE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE: sm->mGLPrimitive = GL_TRIANGLES; break;
+ case RS_PRIMITIVE_TRIANGLE_STRIP: sm->mGLPrimitive = GL_TRIANGLE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE_FAN: sm->mGLPrimitive = GL_TRIANGLE_FAN; break;
+ }
+ return sm;
+}
+
+void rsi_SimpleMeshBindVertex(Context *rsc, RsSimpleMesh mv, RsAllocation va, uint32_t slot)
+{
+ SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
+ rsAssert(slot < sm->mVertexTypeCount);
+
+ sm->mVertexBuffers[slot].set((Allocation *)va);
+}
+
+void rsi_SimpleMeshBindIndex(Context *rsc, RsSimpleMesh mv, RsAllocation va)
+{
+ SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
+ sm->mIndexBuffer.set((Allocation *)va);
+}
+
+void rsi_SimpleMeshBindPrimitive(Context *rsc, RsSimpleMesh mv, RsAllocation va)
+{
+ SimpleMesh *sm = static_cast<SimpleMesh *>(mv);
+ sm->mPrimitiveBuffer.set((Allocation *)va);
+}
+
+
+
+
+}}
+
diff --git a/libs/rs/rsSimpleMesh.h b/libs/rs/rsSimpleMesh.h
new file mode 100644
index 0000000..03b6c2c
--- /dev/null
+++ b/libs/rs/rsSimpleMesh.h
@@ -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.
+ */
+
+#ifndef ANDROID_RS_SIMPLE_MESH_H
+#define ANDROID_RS_SIMPLE_MESH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class SimpleMesh : public ObjectBase
+{
+public:
+ SimpleMesh();
+ ~SimpleMesh();
+
+ ObjectBaseRef<const Type> mIndexType;
+ ObjectBaseRef<const Type> mPrimitiveType;
+ ObjectBaseRef<const Type> *mVertexTypes;
+ uint32_t mVertexTypeCount;
+
+ ObjectBaseRef<Allocation> mIndexBuffer;
+ ObjectBaseRef<Allocation> mPrimitiveBuffer;
+ ObjectBaseRef<Allocation> *mVertexBuffers;
+
+ RsPrimitive mPrimitive;
+ uint32_t mGLPrimitive;
+
+
+ void render() const;
+ void renderRange(uint32_t start, uint32_t len) const;
+
+
+protected:
+};
+
+class SimpleMeshContext
+{
+public:
+ SimpleMeshContext();
+ ~SimpleMeshContext();
+
+
+};
+
+
+}
+}
+#endif //ANDROID_RS_SIMPLE_MESH_H
+
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
new file mode 100644
index 0000000..db4bb81
--- /dev/null
+++ b/libs/rs/rsThreadIO.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 "rsThreadIO.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+ThreadIO::ThreadIO()
+{
+ mToCore.init(16 * 1024);
+}
+
+ThreadIO::~ThreadIO()
+{
+}
+
+void ThreadIO::shutdown()
+{
+ mToCore.shutdown();
+}
+
+bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand)
+{
+ bool ret = false;
+ while(!mToCore.isEmpty() || waitForCommand) {
+ uint32_t cmdID = 0;
+ uint32_t cmdSize = 0;
+ ret = true;
+#if RS_LOG_TIMES
+ con->timerSet(Context::RS_TIMER_IDLE);
+#endif
+ const void * data = mToCore.get(&cmdID, &cmdSize);
+#if RS_LOG_TIMES
+ con->timerSet(Context::RS_TIMER_INTERNAL);
+#endif
+ waitForCommand = false;
+ //LOGV("playCoreCommands 3 %i %i", cmdID, cmdSize);
+
+ gPlaybackFuncs[cmdID](con, data);
+ mToCore.next();
+ }
+ return ret;
+}
+
+
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
new file mode 100644
index 0000000..1f6a0c2
--- /dev/null
+++ b/libs/rs/rsThreadIO.h
@@ -0,0 +1,52 @@
+/*
+ * 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 "rsUtils.h"
+#include "rsLocklessFifo.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Context;
+
+class ThreadIO {
+public:
+ ThreadIO();
+ ~ThreadIO();
+
+ void shutdown();
+
+ // Plays back commands from the client.
+ // Returns true if any commands were processed.
+ bool playCoreCommands(Context *con, bool waitForCommand);
+
+
+ LocklessCommandFifo mToCore;
+ //LocklessCommandFifo mToClient;
+
+ intptr_t mToCoreRet;
+
+};
+
+
+}
+}
+#endif
+
diff --git a/libs/rs/rsTriangleMesh.cpp b/libs/rs/rsTriangleMesh.cpp
new file mode 100644
index 0000000..64bb71b
--- /dev/null
+++ b/libs/rs/rsTriangleMesh.cpp
@@ -0,0 +1,287 @@
+/*
+ * 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>
+
+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;
+ }
+ }
+ LOGV("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)
+{
+ 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();
+
+ 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;
+ }
+
+ memcpy(tm->mVertexData, tmc->mVertexData.array(), tm->mVertexDataSize);
+ memcpy(tm->mIndexData, tmc->mIndexData.array(), tm->mIndexDataSize);
+ tm->analyzeElement();
+
+ tm->incUserRef();
+ 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();
+
+ 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);
+ }
+
+ if (first >= tm->mTriangleCount) {
+ return;
+ }
+ if (count >= (tm->mTriangleCount - first)) {
+ count = tm->mTriangleCount - first;
+ }
+ if (!count) {
+ return;
+ }
+
+ const float *f = (const float *)tm->mVertexData;
+
+ 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));
+
+ 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..e56c7c2
--- /dev/null
+++ b/libs/rs/rsTriangleMesh.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.
+ */
+
+#ifndef ANDROID_RS_TRIANGLE_MESH_H
+#define ANDROID_RS_TRIANGLE_MESH_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 ObjectBase
+{
+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
+ uint32_t 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..1838fa6
--- /dev/null
+++ b/libs/rs/rsType.cpp
@@ -0,0 +1,382 @@
+/*
+ * 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;
+
+Type::Type()
+{
+ mLODs = 0;
+ mLODCount = 0;
+ memset(&mGL, 0, sizeof(mGL));
+ 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()
+{
+ 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];
+ }
+
+ 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;
+ offset += tx * rsMax(ty, 1u) * rsMax(tz, 1u) * mElement->getSizeBytes();
+ tx = (tx + 1) >> 1;
+ ty = (ty + 1) >> 1;
+ tz = (tz + 1) >> 1;
+ }
+
+ // At this point the offset is the size of a mipmap chain;
+ mMipChainSizeBytes = offset;
+
+ if (mFaces) {
+ offset *= 6;
+ }
+ mTotalSizeBytes = offset;
+
+ makeGLComponents();
+}
+
+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;
+}
+
+
+void Type::makeGLComponents()
+{
+ uint32_t texNum = 0;
+ memset(&mGL, 0, sizeof(mGL));
+
+ for (uint32_t ct=0; ct < getElement()->getComponentCount(); ct++) {
+ const Component *c = getElement()->getComponent(ct);
+
+ switch(c->getKind()) {
+ case Component::X:
+ rsAssert(mGL.mVtx.size == 0);
+ mGL.mVtx.size = 1;
+ mGL.mVtx.offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mVtx.type = c->getGLType();
+ break;
+ case Component::Y:
+ rsAssert(mGL.mVtx.size == 1);
+ rsAssert(mGL.mVtx.type == c->getGLType());
+ mGL.mVtx.size = 2;
+ break;
+ case Component::Z:
+ rsAssert(mGL.mVtx.size == 2);
+ rsAssert(mGL.mVtx.type == c->getGLType());
+ mGL.mVtx.size = 3;
+ break;
+ case Component::W:
+ rsAssert(mGL.mVtx.size == 4);
+ rsAssert(mGL.mVtx.type == c->getGLType());
+ mGL.mVtx.size = 4;
+ break;
+
+ case Component::RED:
+ rsAssert(mGL.mColor.size == 0);
+ mGL.mColor.size = 1;
+ mGL.mColor.offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mColor.type = c->getGLType();
+ break;
+ case Component::GREEN:
+ rsAssert(mGL.mColor.size == 1);
+ rsAssert(mGL.mColor.type == c->getGLType());
+ mGL.mColor.size = 2;
+ break;
+ case Component::BLUE:
+ rsAssert(mGL.mColor.size == 2);
+ rsAssert(mGL.mColor.type == c->getGLType());
+ mGL.mColor.size = 3;
+ break;
+ case Component::ALPHA:
+ // Can be RGBA or A at this point
+ if (mGL.mColor.size > 0) {
+ rsAssert(mGL.mColor.size == 3);
+ rsAssert(mGL.mColor.type == c->getGLType());
+ mGL.mColor.size = 4;
+ } else {
+ mGL.mColor.size = 1;
+ mGL.mColor.offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mColor.type = c->getGLType();
+ }
+ break;
+
+ case Component::NX:
+ rsAssert(mGL.mNorm.size == 0);
+ mGL.mNorm.size = 1;
+ mGL.mNorm.offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mNorm.type = c->getGLType();
+ break;
+ case Component::NY:
+ rsAssert(mGL.mNorm.size == 1);
+ rsAssert(mGL.mNorm.type == c->getGLType());
+ mGL.mNorm.size = 2;
+ break;
+ case Component::NZ:
+ rsAssert(mGL.mNorm.size == 2);
+ rsAssert(mGL.mNorm.type == c->getGLType());
+ mGL.mNorm.size = 3;
+ break;
+
+ case Component::S:
+ if (mGL.mTex[texNum].size) {
+ texNum++;
+ }
+ mGL.mTex[texNum].size = 1;
+ mGL.mTex[texNum].offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mTex[texNum].type = c->getGLType();
+ break;
+ case Component::T:
+ rsAssert(mGL.mTex[texNum].size == 1);
+ rsAssert(mGL.mTex[texNum].type == c->getGLType());
+ mGL.mTex[texNum].size = 2;
+ break;
+ case Component::R:
+ rsAssert(mGL.mTex[texNum].size == 2);
+ rsAssert(mGL.mTex[texNum].type == c->getGLType());
+ mGL.mTex[texNum].size = 3;
+ break;
+ case Component::Q:
+ rsAssert(mGL.mTex[texNum].size == 3);
+ rsAssert(mGL.mTex[texNum].type == c->getGLType());
+ mGL.mTex[texNum].size = 4;
+ break;
+
+ case Component::POINT_SIZE:
+ rsAssert(!mGL.mPointSize.size);
+ mGL.mPointSize.size = 1;
+ mGL.mPointSize.offset = mElement->getComponentOffsetBytes(ct);
+ mGL.mPointSize.type = c->getGLType();
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Type::enableGLVertexBuffer() const
+{
+ // Note: We are only going to enable buffers and never disable them
+ // here. The reasonis more than one Allocation may be used as a vertex
+ // source. So we cannot disable arrays that may have been in use by
+ // another allocation.
+
+ uint32_t stride = mElement->getSizeBytes();
+ if (mGL.mVtx.size) {
+ //LOGE("va vtx %i %x, %i, %p", mGL.mVtx.size, mGL.mVtx.type, stride, (void *)mGL.mVtx.offset);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(mGL.mVtx.size,
+ mGL.mVtx.type,
+ stride,
+ (void *)mGL.mVtx.offset);
+ }
+
+ if (mGL.mNorm.size) {
+ //LOGE("va norm %i %x, %i, %p", mGL.mNorm.size, mGL.mNorm.type, stride, (void *)mGL.mNorm.offset);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ rsAssert(mGL.mNorm.size == 3);
+ glNormalPointer(mGL.mNorm.type,
+ stride,
+ (void *)mGL.mNorm.offset);
+ }
+
+ if (mGL.mColor.size) {
+ glEnableClientState(GL_COLOR_ARRAY);
+ glColorPointer(mGL.mColor.size,
+ mGL.mColor.type,
+ stride,
+ (void *)mGL.mColor.offset);
+ }
+
+ for (uint32_t ct=0; ct < RS_MAX_TEXTURE; ct++) {
+ if (mGL.mTex[ct].size) {
+ //LOGE("va tex%i %i %x, %i, %p", ct, mGL.mTex[ct].size, mGL.mTex[ct].type, stride, (void *)mGL.mTex[ct].offset);
+ glClientActiveTexture(GL_TEXTURE0 + ct);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(mGL.mTex[ct].size,
+ mGL.mTex[ct].type,
+ stride,
+ (void *)mGL.mTex[ct].offset);
+ }
+ }
+ glClientActiveTexture(GL_TEXTURE0);
+
+ if (mGL.mPointSize.size) {
+ glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
+ glPointSizePointerOES(mGL.mPointSize.type,
+ stride,
+ (void *)mGL.mPointSize.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->incUserRef();
+ 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();
+
+ return st;
+}
+
+
+}
+}
+
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
new file mode 100644
index 0000000..6c39a4c
--- /dev/null
+++ b/libs/rs/rsType.h
@@ -0,0 +1,153 @@
+/*
+ * 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();
+
+ void enableGLVertexBuffer() const;
+
+
+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;
+
+ struct VertexComponent_t {
+ uint32_t offset;
+ uint32_t type;
+ uint32_t size;
+ uint32_t stride;
+ };
+ struct GLState_t {
+ VertexComponent_t mVtx;
+ VertexComponent_t mNorm;
+ VertexComponent_t mColor;
+ VertexComponent_t mTex[RS_MAX_TEXTURE];
+ VertexComponent_t mPointSize;
+ };
+ GLState_t mGL;
+ void makeGLComponents();
+
+private:
+ Type(const Type &);
+};
+
+
+class TypeState {
+public:
+ TypeState();
+ ~TypeState();
+
+ size_t mX;
+ size_t mY;
+ size_t mZ;
+ uint32_t mLOD;
+ bool mFaces;
+ ObjectBaseRef<const Element> mElement;
+
+ ObjectBaseRef<const Type> mIndexType;
+ ObjectBaseRef<const Type> mPrimitiveType;
+ ObjectBaseRef<const Type> *mVertexTypes;
+
+
+};
+
+
+}
+}
+#endif //ANDROID_STRUCTURED_TYPE
diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h
new file mode 100644
index 0000000..ec928db
--- /dev/null
+++ b/libs/rs/rsUtils.h
@@ -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.
+ */
+
+#ifndef ANDROID_RS_UTILS_H
+#define ANDROID_RS_UTILS_H
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "rs"
+#include <utils/Log.h>
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <time.h>
+
+#include <EGL/egl.h>
+#include <math.h>
+
+#include "RenderScript.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
+
+#define RS_LOG_TIMES 0
+
+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..74ba248
--- /dev/null
+++ b/libs/rs/rsg_generator.c
@@ -0,0 +1,306 @@
+
+#include "spec.h"
+#include <stdio.h>
+
+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 *");
+ } else {
+ fprintf(f, "RsContext rsc");
+ }
+ printArgList(f, api, 1);
+ 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, "#include \"rsHandcode.h\"\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");
+ if (api->handcodeApi) {
+ fprintf(f, " rsHCAPI_%s(rsc", api->name);
+ for(ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ fprintf(f, ", %s", vt->name);
+ }
+ fprintf(f, ");\n");
+ } else {
+ fprintf(f, " ThreadIO *io = &((Context *)rsc)->mIO;\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, "#include \"rsHandcode.h\"\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");
+ if (api->handcodePlay) {
+ fprintf(f, " rsHCPLAY_%s(con, vp);\n", api->name);
+ } else {
+ //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, "con->mIO.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, ",\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.h b/libs/rs/spec.h
new file mode 100644
index 0000000..82650a7
--- /dev/null
+++ b/libs/rs/spec.h
@@ -0,0 +1,43 @@
+#ifndef SPEC_H
+#define SPEC_H
+
+#include <string.h>
+#include <stdlib.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+extern int num_lines;
+
+typedef struct {
+ int isConst;
+ int type;
+ int bits;
+ int ptrLevel;
+ char name[256];
+ char typeName[256];
+} VarType;
+
+extern VarType *currType;
+
+typedef struct {
+ char name[256];
+ int sync;
+ int handcodeApi;
+ int handcodePlay;
+ int paramCount;
+ VarType ret;
+ VarType params[16];
+} ApiEntry;
+
+extern ApiEntry apis[128];
+extern int apiCount;
+
+extern int typeNextState;
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // SPEC_H
diff --git a/libs/rs/spec.l b/libs/rs/spec.l
new file mode 100644
index 0000000..d81d47e
--- /dev/null
+++ b/libs/rs/spec.l
@@ -0,0 +1,165 @@
+%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_]*
+
+ #include "spec.h"
+
+ int num_lines = 0;
+
+ VarType *currType = 0;
+
+ ApiEntry apis[128];
+ int apiCount = 0;
+
+ int typeNextState;
+
+ extern "C" int yylex();
+
+%%
+
+"/*" 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>"handcodeApi" {
+ apis[apiCount].handcodeApi = 1;
+ }
+
+<api_entry2>"handcodePlay" {
+ apis[apiCount].handcodePlay = 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 ec5aa3f..c4a70c8 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -5,44 +5,52 @@ LOCAL_SRC_FILES:= \
clz.cpp.arm \
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
- GPUHardware/GPUHardware.cpp \
BlurFilter.cpp.arm \
- CPUGauge.cpp \
+ BufferAllocator.cpp \
Layer.cpp \
LayerBase.cpp \
LayerBuffer.cpp \
LayerBlur.cpp \
LayerBitmap.cpp \
LayerDim.cpp \
- LayerOrientationAnim.cpp \
- OrientationAnimation.cpp \
+ MessageQueue.cpp \
SurfaceFlinger.cpp \
Tokenizer.cpp \
- Transform.cpp \
- VRamHeap.cpp
+ Transform.cpp
+LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+ifeq ($(TARGET_BOARD_PLATFORM), msm7k)
+ LOCAL_CFLAGS += -DDIM_WITH_TEXTURE
+endif
+ifeq ($(TARGET_BOARD_PLATFORM), qsd8k)
+ LOCAL_CFLAGS += -DDIM_WITH_TEXTURE
+endif
# need "-lrt" on Linux simulator to pick up clock_gettime
ifeq ($(TARGET_SIMULATOR),true)
ifeq ($(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt
+ LOCAL_LDLIBS += -lrt -lpthread
endif
endif
LOCAL_SHARED_LIBRARIES := \
- libhardware \
- libutils \
libcutils \
- libui \
- libcorecg \
- libsgl \
libpixelflinger \
+ libhardware \
+ libutils \
+ libskia \
libEGL \
- libGLESv1_CM
+ libGLESv1_CM \
+ libbinder \
+ libui
LOCAL_C_INCLUDES := \
$(call include-path-for, corecg graphics)
+LOCAL_C_INCLUDES += hardware/libhardware/modules/gralloc
+
LOCAL_MODULE:= libsurfaceflinger
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/surfaceflinger/BufferAllocator.cpp b/libs/surfaceflinger/BufferAllocator.cpp
new file mode 100644
index 0000000..cee8b64
--- /dev/null
+++ b/libs/surfaceflinger/BufferAllocator.cpp
@@ -0,0 +1,118 @@
+/*
+**
+** 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.
+*/
+
+#include <sys/mman.h>
+#include <cutils/ashmem.h>
+#include <cutils/log.h>
+
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include "BufferAllocator.h"
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( BufferAllocator )
+
+Mutex BufferAllocator::sLock;
+KeyedVector<buffer_handle_t, BufferAllocator::alloc_rec_t> BufferAllocator::sAllocList;
+
+BufferAllocator::BufferAllocator()
+ : mAllocDev(0)
+{
+ hw_module_t const* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ gralloc_open(module, &mAllocDev);
+ }
+}
+
+BufferAllocator::~BufferAllocator()
+{
+ gralloc_close(mAllocDev);
+}
+
+void BufferAllocator::dump(String8& result) const
+{
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ size_t total = 0;
+ const size_t SIZE = 512;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "Allocated buffers:\n");
+ result.append(buffer);
+ const size_t c = list.size();
+ for (size_t i=0 ; i<c ; i++) {
+ const alloc_rec_t& rec(list.valueAt(i));
+ snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u x %4u | %2d | 0x%08x\n",
+ list.keyAt(i), rec.size/1024.0f,
+ rec.w, rec.h, rec.format, rec.usage);
+ result.append(buffer);
+ total += rec.size;
+ }
+ snprintf(buffer, SIZE, "Total allocated: %.2f KB\n", total/1024.0f);
+ result.append(buffer);
+}
+
+status_t BufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
+ int usage, buffer_handle_t* handle, int32_t* stride)
+{
+ Mutex::Autolock _l(mLock);
+
+ // we have a h/w allocator and h/w buffer is requested
+ status_t err = mAllocDev->alloc(mAllocDev,
+ w, h, format, usage, handle, stride);
+ LOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
+ w, h, format, usage, err, strerror(-err));
+
+ if (err == NO_ERROR) {
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ alloc_rec_t rec;
+ rec.w = w;
+ rec.h = h;
+ rec.format = format;
+ rec.usage = usage;
+ rec.vaddr = 0;
+ rec.size = h * stride[0] * bytesPerPixel(format);
+ list.add(*handle, rec);
+ }
+
+ return err;
+}
+
+status_t BufferAllocator::free(buffer_handle_t handle)
+{
+ Mutex::Autolock _l(mLock);
+
+ status_t err = mAllocDev->free(mAllocDev, handle);
+ LOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
+
+ if (err == NO_ERROR) {
+ Mutex::Autolock _l(sLock);
+ KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ list.removeItem(handle);
+ }
+
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/BufferAllocator.h b/libs/surfaceflinger/BufferAllocator.h
new file mode 100644
index 0000000..a279ded
--- /dev/null
+++ b/libs/surfaceflinger/BufferAllocator.h
@@ -0,0 +1,96 @@
+/*
+**
+** 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.
+*/
+
+#ifndef ANDROID_BUFFER_ALLOCATOR_H
+#define ANDROID_BUFFER_ALLOCATOR_H
+
+#include <stdint.h>
+
+#include <cutils/native_handle.h>
+
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Singleton.h>
+
+#include <ui/PixelFormat.h>
+
+#include <hardware/gralloc.h>
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class String8;
+
+class BufferAllocator : public Singleton<BufferAllocator>
+{
+public:
+ enum {
+ USAGE_SW_READ_NEVER = GRALLOC_USAGE_SW_READ_NEVER,
+ USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY,
+ USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN,
+ USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK,
+
+ USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER,
+ USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY,
+ USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN,
+ USAGE_SW_WRITE_MASK = GRALLOC_USAGE_SW_WRITE_MASK,
+
+ USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK,
+
+ USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE,
+ USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER,
+ USAGE_HW_2D = GRALLOC_USAGE_HW_2D,
+ USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK
+ };
+
+ static inline BufferAllocator& get() { return getInstance(); }
+
+
+ status_t alloc(uint32_t w, uint32_t h, PixelFormat format, int usage,
+ buffer_handle_t* handle, int32_t* stride);
+
+ status_t free(buffer_handle_t handle);
+
+ void dump(String8& res) const;
+
+private:
+ struct alloc_rec_t {
+ uint32_t w;
+ uint32_t h;
+ PixelFormat format;
+ uint32_t usage;
+ void* vaddr;
+ size_t size;
+ };
+
+ static Mutex sLock;
+ static KeyedVector<buffer_handle_t, alloc_rec_t> sAllocList;
+
+ friend class Singleton<BufferAllocator>;
+ BufferAllocator();
+ ~BufferAllocator();
+
+ mutable Mutex mLock;
+ alloc_device_t *mAllocDev;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_BUFFER_ALLOCATOR_H
diff --git a/libs/surfaceflinger/CPUGauge.cpp b/libs/surfaceflinger/CPUGauge.cpp
deleted file mode 100644
index 74a9270..0000000
--- a/libs/surfaceflinger/CPUGauge.cpp
+++ /dev/null
@@ -1,171 +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 "CPUGauge"
-
-#include <stdint.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <math.h>
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <ui/DisplayInfo.h>
-#include <ui/ISurfaceComposer.h>
-#include <ui/ISurfaceFlingerClient.h>
-
-#include <pixelflinger/pixelflinger.h>
-
-#include "CPUGauge.h"
-
-namespace android {
-
-CPUGauge::CPUGauge( const sp<ISurfaceComposer>& composer,
- nsecs_t interval,
- int clock,
- int refclock)
- : Thread(false),
- mInterval(interval), mClock(clock), mRefClock(refclock),
- mReferenceTime(0),
- mReferenceWorkingTime(0), mCpuUsage(0),
- mRefIdleTime(0), mIdleTime(0)
-{
- mFd = fopen("/proc/stat", "r");
- setvbuf(mFd, NULL, _IONBF, 0);
-
- mSession = SurfaceComposerClient::clientForConnection(
- composer->createConnection()->asBinder());
-}
-
-CPUGauge::~CPUGauge()
-{
- fclose(mFd);
-}
-
-const sp<SurfaceComposerClient>& CPUGauge::session() const
-{
- return mSession;
-}
-
-void CPUGauge::onFirstRef()
-{
- run("CPU Gauge");
-}
-
-status_t CPUGauge::readyToRun()
-{
- LOGI("Starting CPU gauge...");
- return NO_ERROR;
-}
-
-bool CPUGauge::threadLoop()
-{
- DisplayInfo dinfo;
- session()->getDisplayInfo(0, &dinfo);
- sp<Surface> s(session()->createSurface(getpid(), 0, dinfo.w, 4, PIXEL_FORMAT_OPAQUE));
- session()->openTransaction();
- s->setLayer(INT_MAX);
- session()->closeTransaction();
-
- static const GGLfixed colors[4][4] = {
- { 0x00000, 0x10000, 0x00000, 0x10000 },
- { 0x10000, 0x10000, 0x00000, 0x10000 },
- { 0x10000, 0x00000, 0x00000, 0x10000 },
- { 0x00000, 0x00000, 0x00000, 0x10000 },
- };
-
- GGLContext* gl;
- gglInit(&gl);
- gl->activeTexture(gl, 0);
- gl->disable(gl, GGL_TEXTURE_2D);
- gl->disable(gl, GGL_BLEND);
-
- const int w = dinfo.w;
-
- while(!exitPending())
- {
- mLock.lock();
- const float cpuUsage = this->cpuUsage();
- const float totalCpuUsage = 1.0f - idle();
- mLock.unlock();
-
- Surface::SurfaceInfo info;
- s->lock(&info);
- GGLSurface fb;
- fb.version = sizeof(GGLSurface);
- fb.width = info.w;
- fb.height = info.h;
- fb.stride = info.w;
- fb.format = info.format;
- fb.data = (GGLubyte*)info.bits;
-
- gl->colorBuffer(gl, &fb);
- gl->color4xv(gl, colors[3]);
- gl->recti(gl, 0, 0, w, 4);
- gl->color4xv(gl, colors[2]); // red
- gl->recti(gl, 0, 0, int(totalCpuUsage*w), 2);
- gl->color4xv(gl, colors[0]); // green
- gl->recti(gl, 0, 2, int(cpuUsage*w), 4);
-
- s->unlockAndPost();
-
- usleep(ns2us(mInterval));
- }
-
- gglUninit(gl);
- return false;
-}
-
-void CPUGauge::sample()
-{
- if (mLock.tryLock() == NO_ERROR) {
- const nsecs_t now = systemTime(mRefClock);
- const nsecs_t referenceTime = now-mReferenceTime;
- if (referenceTime >= mInterval) {
- const float reftime = 1.0f / referenceTime;
- const nsecs_t nowWorkingTime = systemTime(mClock);
-
- char buf[256];
- fgets(buf, 256, mFd);
- rewind(mFd);
- char *str = buf+5;
- char const * const usermode = strsep(&str, " "); (void)usermode;
- char const * const usernice = strsep(&str, " "); (void)usernice;
- char const * const systemmode = strsep(&str, " ");(void)systemmode;
- char const * const idle = strsep(&str, " ");
- const nsecs_t nowIdleTime = atoi(idle) * 10000000LL;
- mIdleTime = float(nowIdleTime - mRefIdleTime) * reftime;
- mRefIdleTime = nowIdleTime;
-
- const nsecs_t workingTime = nowWorkingTime - mReferenceWorkingTime;
- const float newCpuUsage = float(workingTime) * reftime;
- if (mCpuUsage != newCpuUsage) {
- mCpuUsage = newCpuUsage;
- mReferenceWorkingTime = nowWorkingTime;
- mReferenceTime = now;
- }
- }
- mLock.unlock();
- }
-}
-
-
-}; // namespace android
diff --git a/libs/surfaceflinger/CPUGauge.h b/libs/surfaceflinger/CPUGauge.h
deleted file mode 100644
index 5bb53c0..0000000
--- a/libs/surfaceflinger/CPUGauge.h
+++ /dev/null
@@ -1,74 +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_CPUGAUGE_H
-#define ANDROID_CPUGAUGE_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Timers.h>
-
-#include <ui/SurfaceComposerClient.h>
-
-namespace android {
-
-class CPUGauge : public Thread
-{
-public:
- CPUGauge( const sp<ISurfaceComposer>& composer,
- nsecs_t interval=s2ns(1),
- int clock=SYSTEM_TIME_THREAD,
- int refclock=SYSTEM_TIME_MONOTONIC);
-
- ~CPUGauge();
-
- const sp<SurfaceComposerClient>& session() const;
-
- void sample();
-
- inline float cpuUsage() const { return mCpuUsage; }
- inline float idle() const { return mIdleTime; }
-
-private:
- virtual void onFirstRef();
- virtual status_t readyToRun();
- virtual bool threadLoop();
-
- Mutex mLock;
-
- sp<SurfaceComposerClient> mSession;
-
- const nsecs_t mInterval;
- const int mClock;
- const int mRefClock;
-
- nsecs_t mReferenceTime;
- nsecs_t mReferenceWorkingTime;
- float mCpuUsage;
- nsecs_t mRefIdleTime;
- float mIdleTime;
- FILE* mFd;
-};
-
-
-}; // namespace android
-
-#endif // ANDROID_CPUGAUGE_H
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index ab02fa0..3f607f6 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -23,43 +21,27 @@
#include <cutils/properties.h>
+#include <utils/RefBase.h>
#include <utils/Log.h>
-#include <ui/EGLDisplaySurface.h>
+#include <ui/PixelFormat.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
#include <GLES/gl.h>
+#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <pixelflinger/pixelflinger.h>
#include "DisplayHardware/DisplayHardware.h"
#include <hardware/copybit.h>
#include <hardware/overlay.h>
+#include <hardware/gralloc.h>
using namespace android;
-static __attribute__((noinline))
-const char *egl_strerror(EGLint err)
-{
- switch (err){
- case EGL_SUCCESS: return "EGL_SUCCESS";
- case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
- case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
- case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
- case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
- case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
- case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
- case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
- case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
- case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
- case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
- case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
- case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
- case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
- case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
- default: return "UNKNOWN";
- }
-}
static __attribute__((noinline))
void checkGLErrors()
@@ -76,7 +58,7 @@ void checkEGLErrors(const char* token)
// GLESonGL seems to be returning 0 when there is no errors?
if (error && error != EGL_SUCCESS)
LOGE("%s error 0x%04x (%s)",
- token, int(error), egl_strerror(error));
+ token, int(error), EGLUtils::strerror(error));
}
@@ -108,17 +90,22 @@ PixelFormat DisplayHardware::getFormat() const { return mFormat; }
void DisplayHardware::init(uint32_t dpy)
{
+ mNativeWindow = new FramebufferNativeWindow();
+ framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
+
+ mOverlayEngine = NULL;
+ hw_module_t const* module;
+ if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
+ overlay_control_open(module, &mOverlayEngine);
+ }
+
// initialize EGL
const EGLint attribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_DEPTH_SIZE, 0,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
EGLint w, h, dummy;
- EGLint numConfigs, n;
- EGLConfig config;
+ EGLint numConfigs=0;
EGLSurface surface;
EGLContext context;
mFlags = 0;
@@ -129,7 +116,17 @@ void DisplayHardware::init(uint32_t dpy)
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, NULL, NULL);
eglGetConfigs(display, NULL, 0, &numConfigs);
- eglChooseConfig(display, attribs, &config, 1, &n);
+
+ EGLConfig config;
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ display, attribs, mNativeWindow.get(), &config);
+ LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
+
+ EGLint r,g,b,a;
+ eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
/*
* Gather EGL extensions
@@ -144,13 +141,13 @@ void DisplayHardware::init(uint32_t dpy)
LOGI("version : %s", eglQueryString(display, EGL_VERSION));
LOGI("extensions: %s", egl_extensions);
LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
-
- // TODO: get this from the devfb driver (probably should be HAL module)
- mFlags |= SWAP_RECTANGLE_EXTENSION;
+ LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
- // TODO: get the real "update_on_demand" behavior (probably should be HAL module)
- mFlags |= UPDATE_ON_DEMAND;
+ if (mNativeWindow->isUpdateOnDemand()) {
+ mFlags |= UPDATE_ON_DEMAND;
+ }
+
if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
if (dummy == EGL_SLOW_CONFIG)
mFlags |= SLOW_CONFIG;
@@ -160,37 +157,43 @@ void DisplayHardware::init(uint32_t dpy)
* Create our main surface
*/
- mDisplaySurface = new EGLDisplaySurface();
-
- surface = eglCreateWindowSurface(display, config, mDisplaySurface.get(), NULL);
- //checkEGLErrors("eglCreateDisplaySurfaceANDROID");
+ surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
+ checkEGLErrors("eglCreateWindowSurface");
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
if (dummy == EGL_BUFFER_PRESERVED) {
mFlags |= BUFFER_PRESERVED;
}
}
-
- GLint value = EGL_UNKNOWN;
- eglQuerySurface(display, surface, EGL_HORIZONTAL_RESOLUTION, &value);
- if (value == EGL_UNKNOWN) {
- mDpiX = 160.0f;
- } else {
- mDpiX = 25.4f * float(value)/EGL_DISPLAY_SCALING;
- }
- value = EGL_UNKNOWN;
- eglQuerySurface(display, surface, EGL_VERTICAL_RESOLUTION, &value);
- if (value == EGL_UNKNOWN) {
- mDpiY = 160.0f;
- } else {
- mDpiY = 25.4f * float(value)/EGL_DISPLAY_SCALING;
+
+ eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
+ eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
+
+#ifdef EGL_ANDROID_swap_rectangle
+ if (strstr(egl_extensions, "EGL_ANDROID_swap_rectangle")) {
+ if (eglSetSwapRectangleANDROID(display, surface,
+ 0, 0, mWidth, mHeight) == EGL_TRUE) {
+ // This could fail if this extension is not supported by this
+ // specific surface (of config)
+ mFlags |= SWAP_RECTANGLE;
+ }
}
- mRefreshRate = 60.f; // TODO: get the real refresh rate
+ // when we have the choice between UPDATE_ON_DEMAND and SWAP_RECTANGLE
+ // choose UPDATE_ON_DEMAND, which is more efficient
+ if (mFlags & UPDATE_ON_DEMAND)
+ mFlags &= ~SWAP_RECTANGLE;
+#endif
+
+
+ LOGI("flags : %08x", mFlags);
+ mDpiX = mNativeWindow->xdpi;
+ mDpiY = mNativeWindow->ydpi;
+ mRefreshRate = fbDev->fps;
char property[PROPERTY_VALUE_MAX];
/* Read density from build-specific ro.sf.lcd_density property
- * except if it is overriden by qemu.sf.lcd_density.
+ * except if it is overridden by qemu.sf.lcd_density.
*/
if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
@@ -211,9 +214,6 @@ void DisplayHardware::init(uint32_t dpy)
context = eglCreateContext(display, config, NULL, NULL);
//checkEGLErrors("eglCreateContext");
- eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
- eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
-
/*
* Gather OpenGL ES extensions
@@ -233,7 +233,10 @@ void DisplayHardware::init(uint32_t dpy)
if (strstr(gl_extensions, "GL_OES_draw_texture")) {
mFlags |= DRAW_TEXTURE_EXTENSION;
}
- if (strstr(gl_extensions, "GL_ANDROID_direct_texture")) {
+ if (strstr( gl_extensions, "GL_OES_EGL_image") &&
+ (strstr(egl_extensions, "EGL_KHR_image_base") ||
+ strstr(egl_extensions, "EGL_KHR_image")) &&
+ strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) {
mFlags |= DIRECT_TEXTURE;
}
@@ -244,19 +247,8 @@ void DisplayHardware::init(uint32_t dpy)
mConfig = config;
mSurface = surface;
mContext = context;
- mFormat = GGL_PIXEL_FORMAT_RGB_565;
-
- hw_module_t const* module;
-
- mBlitEngine = NULL;
- if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
- copybit_open(module, &mBlitEngine);
- }
-
- mOverlayEngine = NULL;
- if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
- overlay_control_open(module, &mOverlayEngine);
- }
+ mFormat = fbDev->format;
+ mPageFlipCount = 0;
}
/*
@@ -270,7 +262,6 @@ void DisplayHardware::fini()
{
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mDisplay);
- copybit_close(mBlitEngine);
overlay_control_close(mOverlayEngine);
}
@@ -284,28 +275,8 @@ void DisplayHardware::acquireScreen() const
DisplayHardwareBase::acquireScreen();
}
-void DisplayHardware::getDisplaySurface(copybit_image_t* img) const
-{
- img->w = mDisplaySurface->stride;
- img->h = mDisplaySurface->height;
- img->format = mDisplaySurface->format;
- img->offset = mDisplaySurface->offset;
- img->base = (void*)mDisplaySurface->base;
- img->fd = mDisplaySurface->fd;
-}
-
-void DisplayHardware::getDisplaySurface(GGLSurface* fb) const
-{
- fb->version= sizeof(GGLSurface);
- fb->width = mDisplaySurface->width;
- fb->height = mDisplaySurface->height;
- fb->stride = mDisplaySurface->stride;
- fb->format = mDisplaySurface->format;
- fb->data = (GGLubyte*)mDisplaySurface->base + mDisplaySurface->offset;
-}
-
uint32_t DisplayHardware::getPageFlipCount() const {
- return mDisplaySurface->getPageFlipCount();
+ return mPageFlipCount;
}
/*
@@ -319,21 +290,20 @@ void DisplayHardware::flip(const Region& dirty) const
EGLDisplay dpy = mDisplay;
EGLSurface surface = mSurface;
- Region newDirty(dirty);
- newDirty.andSelf(Rect(mWidth, mHeight));
-
- if (mFlags & BUFFER_PRESERVED) {
- const Region copyback(mDirty.subtract(newDirty));
- mDirty = newDirty;
- mDisplaySurface->copyFrontToBack(copyback);
- }
-
- if (mFlags & SWAP_RECTANGLE_EXTENSION) {
- const Rect& b(newDirty.bounds());
- mDisplaySurface->setSwapRectangle(
+#ifdef EGL_ANDROID_swap_rectangle
+ if (mFlags & SWAP_RECTANGLE) {
+ const Region newDirty(dirty.intersect(bounds()));
+ const Rect b(newDirty.getBounds());
+ eglSetSwapRectangleANDROID(dpy, surface,
b.left, b.top, b.width(), b.height());
+ }
+#endif
+
+ if (mFlags & UPDATE_ON_DEMAND) {
+ mNativeWindow->setUpdateRectangle(dirty.getBounds());
}
-
+
+ mPageFlipCount++;
eglSwapBuffers(dpy, surface);
checkEGLErrors("eglSwapBuffers");
@@ -351,11 +321,3 @@ void DisplayHardware::makeCurrent() const
{
eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
}
-
-void DisplayHardware::copyFrontToImage(const copybit_image_t& front) const {
- mDisplaySurface->copyFrontToImage(front);
-}
-
-void DisplayHardware::copyBackToImage(const copybit_image_t& front) const {
- mDisplaySurface->copyBackToImage(front);
-}
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index 550a4d1..8972d51 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -22,31 +22,35 @@
#include <ui/PixelFormat.h>
#include <ui/Region.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <pixelflinger/pixelflinger.h>
#include "DisplayHardware/DisplayHardwareBase.h"
struct overlay_control_device_t;
-struct copybit_device_t;
+struct framebuffer_device_t;
struct copybit_image_t;
-struct copybit_t;
namespace android {
-class EGLDisplaySurface;
+class FramebufferNativeWindow;
class DisplayHardware : public DisplayHardwareBase
{
public:
enum {
DIRECT_TEXTURE = 0x00000002,
- SWAP_RECTANGLE_EXTENSION= 0x00000004,
COPY_BITS_EXTENSION = 0x00000008,
NPOT_EXTENSION = 0x00000100,
DRAW_TEXTURE_EXTENSION = 0x00000200,
BUFFER_PRESERVED = 0x00010000,
UPDATE_ON_DEMAND = 0x00020000, // video driver feature
SLOW_CONFIG = 0x00040000, // software
+ SWAP_RECTANGLE = 0x00080000,
};
DisplayHardware(
@@ -73,15 +77,9 @@ public:
void makeCurrent() const;
uint32_t getPageFlipCount() const;
- void getDisplaySurface(copybit_image_t* img) const;
- void getDisplaySurface(GGLSurface* fb) const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
- copybit_device_t* getBlitEngine() const { return mBlitEngine; }
overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
- void copyFrontToImage(const copybit_image_t& front) const;
- void copyBackToImage(const copybit_image_t& front) const;
-
Rect bounds() const {
return Rect(mWidth, mHeight);
}
@@ -102,9 +100,9 @@ private:
int mHeight;
PixelFormat mFormat;
uint32_t mFlags;
- mutable Region mDirty;
- sp<EGLDisplaySurface> mDisplaySurface;
- copybit_device_t* mBlitEngine;
+ mutable uint32_t mPageFlipCount;
+
+ sp<FramebufferNativeWindow> mNativeWindow;
overlay_control_device_t* mOverlayEngine;
};
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index f75e5c2..1d09f84 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
deleted file mode 100644
index 7168bf2..0000000
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.cpp
+++ /dev/null
@@ -1,585 +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.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <math.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#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 <utils/StopWatch.h>
-
-#include <ui/ISurfaceComposer.h>
-
-#include "VRamHeap.h"
-#include "GPUHardware.h"
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-#include "GPUHardware/GPUHardware.h"
-
-
-/*
- * Manage the GPU. This implementation is very specific to the G1.
- * There are no abstraction here.
- *
- * All this code will soon go-away and be replaced by a new architecture
- * for managing graphics accelerators.
- *
- * In the meantime, it is conceptually possible to instantiate a
- * GPUHardwareInterface for another GPU (see GPUFactory at the bottom
- * of this file); practically... doubtful.
- *
- */
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class GPUClientHeap;
-class GPUAreaHeap;
-
-class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
-{
-public:
- static const int GPU_RESERVED_SIZE;
- static const int GPUR_SIZE;
-
- GPUHardware();
- virtual ~GPUHardware();
-
- virtual void revoke(int pid);
- virtual sp<MemoryDealer> request(int pid);
- virtual status_t request(int pid,
- const sp<IGPUCallback>& callback,
- ISurfaceComposer::gpu_info_t* gpu);
-
- virtual status_t friendlyRevoke();
- virtual void unconditionalRevoke();
-
- virtual pid_t getOwner() const { return mOwner; }
-
- // used for debugging only...
- virtual sp<SimpleBestFitAllocator> getAllocator() const;
-
-private:
-
-
- enum {
- NO_OWNER = -1,
- };
-
- struct GPUArea {
- sp<GPUAreaHeap> heap;
- sp<MemoryHeapPmem> clientHeap;
- sp<IMemory> map();
- };
-
- struct Client {
- pid_t pid;
- GPUArea smi;
- GPUArea ebi;
- GPUArea reg;
- void createClientHeaps();
- void revokeAllHeaps();
- };
-
- Client& getClientLocked(pid_t pid);
- status_t requestLocked(int pid);
- void releaseLocked();
- void takeBackGPULocked();
- void registerCallbackLocked(const sp<IGPUCallback>& callback,
- Client& client);
-
- virtual void binderDied(const wp<IBinder>& who);
-
- mutable Mutex mLock;
- sp<GPUAreaHeap> mSMIHeap;
- sp<GPUAreaHeap> mEBIHeap;
- sp<GPUAreaHeap> mREGHeap;
-
- KeyedVector<pid_t, Client> mClients;
- DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
-
- pid_t mOwner;
-
- sp<MemoryDealer> mCurrentAllocator;
- sp<IGPUCallback> mCallback;
-
- sp<SimpleBestFitAllocator> mAllocator;
-
- Condition mCondition;
-};
-
-// size reserved for GPU surfaces
-// 1200 KB fits exactly:
-// - two 320*480 16-bits double-buffered surfaces
-// - one 320*480 32-bits double-buffered surface
-// - one 320*240 16-bits double-buffered, 4x anti-aliased surface
-const int GPUHardware::GPU_RESERVED_SIZE = 1200 * 1024;
-const int GPUHardware::GPUR_SIZE = 1 * 1024 * 1024;
-
-// ---------------------------------------------------------------------------
-
-/*
- * GPUHandle is a special IMemory given to the client. It represents their
- * handle to the GPU. Once they give it up, they loose GPU access, or if
- * they explicitly revoke their access through the binder code 1000.
- * In both cases, this triggers a callback to revoke()
- * first, and then actually powers down the chip.
- *
- * In the case of a misbehaving app, GPUHardware can ask for an immediate
- * release of the GPU to the target process which should answer by calling
- * code 1000 on GPUHandle. If it doesn't in a timely manner, the GPU will
- * be revoked from under their feet.
- *
- * We should never hold a strong reference on GPUHandle. In practice this
- * shouldn't be a big issue though because clients should use code 1000 and
- * not rely on the dtor being called.
- *
- */
-
-class GPUClientHeap : public MemoryHeapPmem
-{
-public:
- GPUClientHeap(const wp<GPUHardware>& gpu,
- const sp<MemoryHeapBase>& heap)
- : MemoryHeapPmem(heap), mGPU(gpu) { }
-protected:
- wp<GPUHardware> mGPU;
-};
-
-class GPUAreaHeap : public MemoryHeapBase
-{
-public:
- GPUAreaHeap(const wp<GPUHardware>& gpu,
- const char* const vram, size_t size=0, size_t reserved=0)
- : MemoryHeapBase(vram, size), mGPU(gpu) {
- if (base() != MAP_FAILED) {
- if (reserved == 0)
- reserved = virtualSize();
- mAllocator = new SimpleBestFitAllocator(reserved);
- }
- }
- virtual sp<MemoryHeapPmem> createClientHeap() {
- sp<MemoryHeapBase> parentHeap(this);
- return new GPUClientHeap(mGPU, parentHeap);
- }
- virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
- return mAllocator;
- }
-private:
- sp<SimpleBestFitAllocator> mAllocator;
-protected:
- wp<GPUHardware> mGPU;
-};
-
-class GPURegisterHeap : public GPUAreaHeap
-{
-public:
- GPURegisterHeap(const sp<GPUHardware>& gpu)
- : GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
- virtual sp<MemoryHeapPmem> createClientHeap() {
- sp<MemoryHeapBase> parentHeap(this);
- return new MemoryHeapRegs(mGPU, parentHeap);
- }
-private:
- class MemoryHeapRegs : public GPUClientHeap {
- public:
- MemoryHeapRegs(const wp<GPUHardware>& gpu,
- const sp<MemoryHeapBase>& heap)
- : GPUClientHeap(gpu, heap) { }
- sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
- virtual void revoke();
- private:
- class GPUHandle : public MemoryHeapPmem::MemoryPmem {
- public:
- GPUHandle(const sp<GPUHardware>& gpu,
- const sp<MemoryHeapPmem>& heap)
- : MemoryHeapPmem::MemoryPmem(heap),
- mGPU(gpu), mOwner(gpu->getOwner()) { }
- virtual ~GPUHandle();
- virtual sp<IMemoryHeap> getMemory(
- ssize_t* offset, size_t* size) const;
- virtual void revoke() { };
- virtual status_t onTransact(
- uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
- private:
- void revokeNotification();
- wp<GPUHardware> mGPU;
- pid_t mOwner;
- };
- };
-};
-
-GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() {
- //LOGD("GPUHandle %p released, revoking GPU", this);
- revokeNotification();
-}
-void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification() {
- sp<GPUHardware> hw(mGPU.promote());
- if (hw != 0) {
- hw->revoke(mOwner);
- }
-}
-sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
- ssize_t* offset, size_t* size) const
-{
- sp<MemoryHeapPmem> heap = getHeap();
- if (offset) *offset = 0;
- if (size) *size = heap !=0 ? heap->virtualSize() : 0;
- return heap;
-}
-status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- status_t err = BnMemory::onTransact(code, data, reply, flags);
- if (err == UNKNOWN_TRANSACTION && code == 1000) {
- int callingPid = IPCThreadState::self()->getCallingPid();
- //LOGD("pid %d voluntarily revoking gpu", callingPid);
- if (callingPid == mOwner) {
- revokeNotification();
- // we've revoked the GPU, don't do it again later when we
- // are destroyed.
- mGPU.clear();
- } else {
- LOGW("%d revoking someone else's gpu? (owner=%d)",
- callingPid, mOwner);
- }
- err = NO_ERROR;
- }
- return err;
-}
-
-// ---------------------------------------------------------------------------
-
-
-sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
- size_t offset, size_t size)
-{
- sp<GPUHandle> memory;
- sp<GPUHardware> gpu = mGPU.promote();
- if (heapID()>0 && gpu!=0) {
-#if HAVE_ANDROID_OS
- /* this is where the GPU is powered on and the registers are mapped
- * in the client */
- //LOGD("ioctl(HW3D_GRANT_GPU)");
- int err = ioctl(heapID(), HW3D_GRANT_GPU, base());
- if (err) {
- // it can happen if the master heap has been closed already
- // in which case the GPU already is revoked (app crash for
- // instance).
- LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
- strerror(errno), heapID(), base());
- }
- memory = new GPUHandle(gpu, this);
-#endif
- }
- return memory;
-}
-
-void GPURegisterHeap::MemoryHeapRegs::revoke()
-{
- MemoryHeapPmem::revoke();
-#if HAVE_ANDROID_OS
- if (heapID() > 0) {
- //LOGD("ioctl(HW3D_REVOKE_GPU)");
- int err = ioctl(heapID(), HW3D_REVOKE_GPU, base());
- LOGE_IF(err, "HW3D_REVOKE_GPU failed (%s), mFD=%d, base=%p",
- strerror(errno), heapID(), base());
- }
-#endif
-}
-
-/*****************************************************************************/
-
-GPUHardware::GPUHardware()
- : mOwner(NO_OWNER)
-{
-}
-
-GPUHardware::~GPUHardware()
-{
-}
-
-status_t GPUHardware::requestLocked(int pid)
-{
- const int self_pid = getpid();
- if (pid == self_pid) {
- // can't use GPU from surfaceflinger's process
- return PERMISSION_DENIED;
- }
-
- if (mOwner != pid) {
- if (mREGHeap != 0) {
- if (mOwner != NO_OWNER) {
- // someone already has the gpu.
- takeBackGPULocked();
- releaseLocked();
- }
- } else {
- // first time, initialize the stuff.
- if (mSMIHeap == 0)
- mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
- if (mEBIHeap == 0)
- mEBIHeap = new GPUAreaHeap(this,
- "/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
- mREGHeap = new GPURegisterHeap(this);
- mAllocator = mEBIHeap->getAllocator();
- if (mAllocator == NULL) {
- // something went terribly wrong.
- mSMIHeap.clear();
- mEBIHeap.clear();
- mREGHeap.clear();
- return INVALID_OPERATION;
- }
- }
- Client& client = getClientLocked(pid);
- mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
- mOwner = pid;
- }
- return NO_ERROR;
-}
-
-sp<MemoryDealer> GPUHardware::request(int pid)
-{
- sp<MemoryDealer> dealer;
- Mutex::Autolock _l(mLock);
- Client* client;
- LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
- if (requestLocked(pid) == NO_ERROR) {
- dealer = mCurrentAllocator;
- LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
- }
- return dealer;
-}
-
-status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
- ISurfaceComposer::gpu_info_t* gpu)
-{
- if (callback == 0)
- return BAD_VALUE;
-
- sp<IMemory> gpuHandle;
- LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
- Mutex::Autolock _l(mLock);
- status_t err = requestLocked(pid);
- if (err == NO_ERROR) {
- // it's guaranteed to be there, be construction
- Client& client = mClients.editValueFor(pid);
- registerCallbackLocked(callback, client);
- gpu->count = 2;
- gpu->regions[0].region = client.smi.map();
- gpu->regions[1].region = client.ebi.map();
- gpu->regs = client.reg.map();
- gpu->regions[0].reserved = 0;
- gpu->regions[1].reserved = GPU_RESERVED_SIZE;
- if (gpu->regs != 0) {
- //LOGD("gpu core granted to pid %d, handle base=%p",
- // mOwner, gpu->regs->pointer());
- }
- mCallback = callback;
- } else {
- LOGW("couldn't grant gpu core to pid %d", pid);
- }
- return err;
-}
-
-void GPUHardware::revoke(int pid)
-{
- Mutex::Autolock _l(mLock);
- if (mOwner > 0) {
- if (pid != mOwner) {
- LOGW("GPU owned by %d, revoke from %d", mOwner, pid);
- return;
- }
- //LOGD("revoke pid=%d, owner=%d", pid, mOwner);
- // mOwner could be <0 if the same process acquired the GPU
- // several times without releasing it first.
- mCondition.signal();
- releaseLocked();
- }
-}
-
-status_t GPUHardware::friendlyRevoke()
-{
- Mutex::Autolock _l(mLock);
- //LOGD("friendlyRevoke owner=%d", mOwner);
- takeBackGPULocked();
- releaseLocked();
- return NO_ERROR;
-}
-
-void GPUHardware::takeBackGPULocked()
-{
- sp<IGPUCallback> callback = mCallback;
- mCallback.clear();
- if (callback != 0) {
- callback->gpuLost(); // one-way
- mCondition.waitRelative(mLock, ms2ns(250));
- }
-}
-
-void GPUHardware::releaseLocked()
-{
- //LOGD("revoking gpu from pid %d", mOwner);
- if (mOwner != NO_OWNER) {
- // this may fail because the client might have died, and have
- // been removed from the list.
- ssize_t index = mClients.indexOfKey(mOwner);
- if (index >= 0) {
- Client& client(mClients.editValueAt(index));
- client.revokeAllHeaps();
- }
- mOwner = NO_OWNER;
- mCurrentAllocator.clear();
- mCallback.clear();
- }
-}
-
-GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
-{
- ssize_t index = mClients.indexOfKey(pid);
- if (index < 0) {
- Client client;
- client.pid = pid;
- client.smi.heap = mSMIHeap;
- client.ebi.heap = mEBIHeap;
- client.reg.heap = mREGHeap;
- index = mClients.add(pid, client);
- }
- Client& client(mClients.editValueAt(index));
- client.createClientHeaps();
- return client;
-}
-
-// ----------------------------------------------------------------------------
-// for debugging / testing ...
-
-sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
- Mutex::Autolock _l(mLock);
- return mAllocator;
-}
-
-void GPUHardware::unconditionalRevoke()
-{
- Mutex::Autolock _l(mLock);
- releaseLocked();
-}
-
-// ---------------------------------------------------------------------------
-
-sp<IMemory> GPUHardware::GPUArea::map() {
- sp<IMemory> memory;
- if (clientHeap != 0 && heap != 0) {
- memory = clientHeap->mapMemory(0, heap->virtualSize());
- }
- return memory;
-}
-
-void GPUHardware::Client::createClientHeaps()
-{
- if (smi.clientHeap == 0)
- smi.clientHeap = smi.heap->createClientHeap();
- if (ebi.clientHeap == 0)
- ebi.clientHeap = ebi.heap->createClientHeap();
- if (reg.clientHeap == 0)
- reg.clientHeap = reg.heap->createClientHeap();
-}
-
-void GPUHardware::Client::revokeAllHeaps()
-{
- if (smi.clientHeap != 0)
- smi.clientHeap->revoke();
- if (ebi.clientHeap != 0)
- ebi.clientHeap->revoke();
- if (reg.clientHeap != 0)
- reg.clientHeap->revoke();
-}
-
-void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
- Client& client)
-{
- sp<IBinder> binder = callback->asBinder();
- if (mRegisteredClients.add(binder, client.pid) >= 0) {
- binder->linkToDeath(this);
- }
-}
-
-void GPUHardware::binderDied(const wp<IBinder>& who)
-{
- Mutex::Autolock _l(mLock);
- pid_t pid = mRegisteredClients.valueFor(who);
- if (pid != 0) {
- ssize_t index = mClients.indexOfKey(pid);
- if (index >= 0) {
- //LOGD("*** removing client at %d", index);
- Client& client(mClients.editValueAt(index));
- client.revokeAllHeaps(); // not really needed in theory
- mClients.removeItemsAt(index);
- if (mClients.size() == 0) {
- //LOGD("*** was last client closing everything");
- mCallback.clear();
- mAllocator.clear();
- mCurrentAllocator.clear();
- mSMIHeap.clear();
- mREGHeap.clear();
-
- // NOTE: we cannot clear the EBI heap because surfaceflinger
- // itself may be using it, since this is where surfaces
- // are allocated. if we're in the middle of compositing
- // a surface (even if its process just died), we cannot
- // rip the heap under our feet.
-
- mOwner = NO_OWNER;
- }
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-sp<GPUHardwareInterface> GPUFactory::getGPU()
-{
- sp<GPUHardwareInterface> gpu;
- if (access("/dev/hw3d", F_OK) == 0) {
- gpu = new GPUHardware();
- }
- return gpu;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 96395a8..6f92515 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -14,26 +14,24 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <cutils/properties.h>
+#include <cutils/native_handle.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/StopWatch.h>
#include <ui/PixelFormat.h>
-#include <ui/EGLDisplaySurface.h>
+#include <ui/Surface.h>
#include "clz.h"
#include "Layer.h"
#include "LayerBitmap.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
@@ -49,13 +47,12 @@ const char* const Layer::typeID = "Layer";
// ---------------------------------------------------------------------------
-Layer::Layer(SurfaceFlinger* flinger, DisplayID display, Client* c, int32_t i)
+Layer::Layer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& c, int32_t i)
: LayerBaseClient(flinger, display, c, i),
mSecure(false),
mFrontBufferIndex(1),
mNeedsBlending(true),
- mResizeTransactionDone(false),
- mTextureName(-1U), mTextureWidth(0), mTextureHeight(0)
+ mResizeTransactionDone(false)
{
// no OpenGL operation is possible here, since we might not be
// in the OpenGL thread.
@@ -63,12 +60,25 @@ Layer::Layer(SurfaceFlinger* flinger, DisplayID display, Client* c, int32_t i)
Layer::~Layer()
{
- client->free(clientIndex());
- // this should always be called from the OpenGL thread
- if (mTextureName != -1U) {
- //glDeleteTextures(1, &mTextureName);
- deletedTextures.add(mTextureName);
+ destroy();
+ // the actual buffers will be destroyed here
+}
+
+void Layer::destroy()
+{
+ for (int i=0 ; i<NUM_BUFFERS ; i++) {
+ if (mTextures[i].name != -1U) {
+ glDeleteTextures(1, &mTextures[i].name);
+ mTextures[i].name = -1U;
+ }
+ if (mTextures[i].image != EGL_NO_IMAGE_KHR) {
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ eglDestroyImageKHR(dpy, mTextures[i].image);
+ mTextures[i].image = EGL_NO_IMAGE_KHR;
+ }
+ mBuffers[i].free();
}
+ mSurface.clear();
}
void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
@@ -79,148 +89,193 @@ void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
lcblk->flags |= eNoCopyBack;
}
-sp<LayerBaseClient::Surface> Layer::getSurface() const
+sp<LayerBaseClient::Surface> Layer::createSurface() const
{
return mSurface;
}
-status_t Layer::setBuffers( Client* client,
- uint32_t w, uint32_t h,
+status_t Layer::ditch()
+{
+ // the layer is not on screen anymore. free as much resources as possible
+ destroy();
+ return NO_ERROR;
+}
+
+status_t Layer::setBuffers( uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags)
{
PixelFormatInfo info;
status_t err = getPixelFormatInfo(format, &info);
if (err) return err;
- // TODO: if eHardware is explicitly requested, we should fail
- // on systems where we can't allocate memory that can be used with
- // DMA engines for instance.
-
- // FIXME: we always ask for hardware for now (this should come from copybit)
- flags |= ISurfaceComposer::eHardware;
-
- const uint32_t memory_flags = flags &
- (ISurfaceComposer::eGPU |
- ISurfaceComposer::eHardware |
- ISurfaceComposer::eSecure);
-
- // pixel-alignment. the final alignment may be bigger because
- // we always force a 4-byte aligned bpr.
- uint32_t alignment = 1;
-
- if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) {
- // FIXME: this value should come from the h/w
- alignment = 8;
- // FIXME: this is msm7201A specific, as its GPU only supports
- // BGRA_8888.
- if (format == PIXEL_FORMAT_RGBA_8888) {
- format = PIXEL_FORMAT_BGRA_8888;
- }
- }
+ uint32_t bufferFlags = 0;
+ if (flags & ISurfaceComposer::eSecure)
+ bufferFlags |= Buffer::SECURE;
- mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
+ mSecure = (bufferFlags & Buffer::SECURE) ? true : false;
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0;
- sp<MemoryDealer> allocators[2];
for (int i=0 ; i<2 ; i++) {
- allocators[i] = client->createAllocator(memory_flags);
- if (allocators[i] == 0)
- return NO_MEMORY;
- mBuffers[i].init(allocators[i]);
- int err = mBuffers[i].setBits(w, h, alignment, format, LayerBitmap::SECURE_BITS);
- if (err != NO_ERROR)
+ err = mBuffers[i].init(lcblk->surface + i, w, h, format, bufferFlags);
+ if (err != NO_ERROR) {
return err;
- mBuffers[i].clear(); // clear the bits for security
- mBuffers[i].getInfo(lcblk->surface + i);
+ }
}
-
- mSurface = new Surface(clientIndex(),
- allocators[0]->getMemoryHeap(),
- allocators[1]->getMemoryHeap(),
- mIdentity);
-
+ mSurface = new SurfaceLayer(mFlinger, clientIndex(), this);
return NO_ERROR;
}
void Layer::reloadTexture(const Region& dirty)
{
- if (UNLIKELY(mTextureName == -1U)) {
- // create the texture name the first time
- // can't do that in the ctor, because it runs in another thread.
- mTextureName = createTexture();
+ const sp<Buffer>& buffer(frontBuffer().getBuffer());
+ if (LIKELY(mFlags & DisplayHardware::DIRECT_TEXTURE)) {
+ int index = mFrontBufferIndex;
+ if (LIKELY(!mTextures[index].dirty)) {
+ glBindTexture(GL_TEXTURE_2D, mTextures[index].name);
+ } else {
+ // we need to recreate the texture
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+
+ // create the new texture name if needed
+ if (UNLIKELY(mTextures[index].name == -1U)) {
+ mTextures[index].name = createTexture();
+ } else {
+ glBindTexture(GL_TEXTURE_2D, mTextures[index].name);
+ }
+
+ // free the previous image
+ if (mTextures[index].image != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(dpy, mTextures[index].image);
+ mTextures[index].image = EGL_NO_IMAGE_KHR;
+ }
+
+ // construct an EGL_NATIVE_BUFFER_ANDROID
+ android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+ // create the new EGLImageKHR
+ const EGLint attrs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE, EGL_NONE
+ };
+ mTextures[index].image = eglCreateImageKHR(
+ dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ (EGLClientBuffer)clientBuf, attrs);
+
+ LOGE_IF(mTextures[index].image == EGL_NO_IMAGE_KHR,
+ "eglCreateImageKHR() failed. err=0x%4x",
+ eglGetError());
+
+ if (mTextures[index].image != EGL_NO_IMAGE_KHR) {
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+ (GLeglImageOES)mTextures[index].image);
+ GLint error = glGetError();
+ if (UNLIKELY(error != GL_NO_ERROR)) {
+ // this failed, for instance, because we don't support
+ // NPOT.
+ // FIXME: do something!
+ mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
+ } else {
+ // Everything went okay!
+ mTextures[index].dirty = false;
+ mTextures[index].width = clientBuf->width;
+ mTextures[index].height = clientBuf->height;
+ }
+ }
+ }
+ } else {
+ GGLSurface t;
+ status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_RARELY);
+ LOGE_IF(res, "error %d (%s) locking buffer %p",
+ res, strerror(res), buffer.get());
+ if (res == NO_ERROR) {
+ if (UNLIKELY(mTextures[0].name == -1U)) {
+ mTextures[0].name = createTexture();
+ }
+ loadTexture(&mTextures[0], mTextures[0].name, dirty, t);
+ buffer->unlock();
+ }
}
- const GGLSurface& t(frontBuffer().surface());
- loadTexture(dirty, mTextureName, t, mTextureWidth, mTextureHeight);
}
void Layer::onDraw(const Region& clip) const
{
- if (UNLIKELY(mTextureName == -1LU)) {
- //LOGW("Layer %p doesn't have a texture", this);
+ const int index = (mFlags & DisplayHardware::DIRECT_TEXTURE) ?
+ mFrontBufferIndex : 0;
+ GLuint textureName = mTextures[index].name;
+
+ if (UNLIKELY(textureName == -1LU)) {
+ LOGW("Layer %p doesn't have a texture", this);
// the texture has not been created yet, this Layer has
// in fact never been drawn into. this happens frequently with
// SurfaceView.
clearWithOpenGL(clip);
return;
}
+ drawWithOpenGL(clip, mTextures[index]);
+}
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- const LayerBitmap& front(frontBuffer());
- const GGLSurface& t(front.surface());
+sp<SurfaceBuffer> Layer::peekBuffer(int usage)
+{
+ /*
+ * This is called from the client's Surface::lock(), after it locked
+ * the surface successfully. We're therefore guaranteed that the
+ * back-buffer is not in use by ourselves.
+ * Of course, we need to validate all this, which is not trivial.
+ *
+ * FIXME: A resize could happen at any time here. What to do about this?
+ * - resize() form post()
+ * - resize() from doTransaction()
+ *
+ * We'll probably need an internal lock for this.
+ *
+ *
+ * TODO: We need to make sure that post() doesn't swap
+ * the buffers under us.
+ */
- status_t err = NO_ERROR;
- const int can_use_copybit = canUseCopybit();
- if (can_use_copybit) {
- // StopWatch watch("copybit");
- const State& s(drawingState());
-
- copybit_image_t dst;
- hw.getDisplaySurface(&dst);
- const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
-
- copybit_image_t src;
- front.getBitmapSurface(&src);
- copybit_rect_t srect = { 0, 0, t.width, t.height };
-
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, getOrientation());
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER,
- s.flags & ISurfaceComposer::eLayerDither ?
- COPYBIT_ENABLE : COPYBIT_DISABLE);
-
- region_iterator it(clip);
- err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ // it's okay to read swapState for the purpose of figuring out the
+ // backbuffer index, which cannot change (since the app has locked it).
+ const uint32_t state = lcblk->swapState;
+ const int32_t backBufferIndex = layer_cblk_t::backBuffer(state);
+
+ // get rid of the EGL image, since we shouldn't need it anymore
+ // (note that we're in a different thread than where it is being used)
+ if (mTextures[backBufferIndex].image != EGL_NO_IMAGE_KHR) {
+ EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+ eglDestroyImageKHR(dpy, mTextures[backBufferIndex].image);
+ mTextures[backBufferIndex].image = EGL_NO_IMAGE_KHR;
}
-
- if (!can_use_copybit || err) {
- drawWithOpenGL(clip, mTextureName, t);
+
+ LayerBitmap& layerBitmap(mBuffers[backBufferIndex]);
+ sp<SurfaceBuffer> buffer = layerBitmap.allocate(usage);
+
+ LOGD_IF(DEBUG_RESIZE,
+ "Layer::getBuffer(this=%p), index=%d, (%d,%d), (%d,%d)",
+ this, backBufferIndex,
+ layerBitmap.getWidth(),
+ layerBitmap.getHeight(),
+ layerBitmap.getBuffer()->getWidth(),
+ layerBitmap.getBuffer()->getHeight());
+
+ if (UNLIKELY(buffer == 0)) {
+ // XXX: what to do, what to do?
+ } else {
+ // texture is now dirty...
+ mTextures[backBufferIndex].dirty = true;
+ // ... so it the visible region (because we consider the surface's
+ // buffer size for visibility calculations)
+ forceVisibilityTransaction();
+ mFlinger->setTransactionFlags(eTraversalNeeded);
}
+ return buffer;
}
-status_t Layer::reallocateBuffer(int32_t index, uint32_t w, uint32_t h)
+void Layer::scheduleBroadcast()
{
- LOGD_IF(DEBUG_RESIZE,
- "reallocateBuffer (layer=%p), "
- "requested (%dx%d), "
- "index=%d, (%dx%d), (%dx%d)",
- this,
- int(w), int(h),
- int(index),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
-
- status_t err = mBuffers[index].resize(w, h);
- if (err == NO_ERROR) {
- mBuffers[index].getInfo(lcblk->surface + index);
- } else {
- LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s",
- index, w, h, err, strerror(err));
- // XXX: what to do, what to do? We could try to free some
- // hidden surfaces, instead of killing this one?
+ sp<Client> ourClient(client.promote());
+ if (ourClient != 0) {
+ mFlinger->scheduleBroadcast(ourClient);
}
- return err;
}
uint32_t Layer::doTransaction(uint32_t flags)
@@ -232,7 +287,7 @@ uint32_t Layer::doTransaction(uint32_t flags)
// that the size changed back to its previous value before the buffer
// was resized (in the eLocked case below), in which case, we still
// need to execute the code below so the clients have a chance to be
- // release. resze() deals with the fact that the size can be the same.
+ // release. resize() deals with the fact that the size can be the same.
/*
* Various states we could be in...
@@ -276,8 +331,8 @@ uint32_t Layer::doTransaction(uint32_t flags)
int(temp.w), int(temp.h),
int(drawingState().w), int(drawingState().h),
int(clientBackBufferIndex),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// if we get there we're pretty screwed. the only reasonable
// thing to do is to pretend we should do the resize since
// backbufferChanged is set (this also will give a chance to
@@ -299,8 +354,8 @@ uint32_t Layer::doTransaction(uint32_t flags)
int(temp.w), int(temp.h),
int(drawingState().w), int(drawingState().h),
int(clientBackBufferIndex),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
if (state & eLocked) {
// if the buffer is locked, we can't resize anything because
@@ -314,10 +369,11 @@ uint32_t Layer::doTransaction(uint32_t flags)
status_t err =
resize(clientBackBufferIndex, temp.w, temp.h, "transaction");
if (err == NO_ERROR) {
- const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0;
+ const uint32_t mask = clientBackBufferIndex ?
+ eResizeBuffer1 : eResizeBuffer0;
android_atomic_and(~mask, &(lcblk->swapState));
// since a buffer became available, we can let the client go...
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
mResizeTransactionDone = true;
// we're being resized and there is a freeze display request,
@@ -353,14 +409,15 @@ status_t Layer::resize(
{
/*
* handle resize (backbuffer and frontbuffer reallocation)
+ * this is called from post() or from doTransaction()
*/
const LayerBitmap& clientBackBuffer(mBuffers[clientBackBufferIndex]);
// if the new (transaction) size is != from the the backbuffer
// then we need to reallocate the backbuffer
- bool backbufferChanged = (clientBackBuffer.width() != width) ||
- (clientBackBuffer.height() != height);
+ bool backbufferChanged = (clientBackBuffer.getWidth() != width) ||
+ (clientBackBuffer.getHeight() != height);
LOGD_IF(!backbufferChanged,
"(%s) eResizeRequested (layer=%p), but size not changed: "
@@ -372,18 +429,28 @@ status_t Layer::resize(
int(currentState().w), int(currentState().h),
long(lcblk->swapState),
int(clientBackBufferIndex),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// this can happen when changing the size back and forth quickly
status_t err = NO_ERROR;
if (backbufferChanged) {
- err = reallocateBuffer(clientBackBufferIndex, width, height);
- }
- if (UNLIKELY(err != NO_ERROR)) {
- // couldn't reallocate the surface
- android_atomic_write(eInvalidSurface, &lcblk->swapState);
- memset(lcblk->surface+clientBackBufferIndex, 0, sizeof(surface_info_t));
+
+ LOGD_IF(DEBUG_RESIZE,
+ "resize (layer=%p), requested (%dx%d), "
+ "index=%d, (%dx%d), (%dx%d)",
+ this, int(width), int(height), int(clientBackBufferIndex),
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
+
+ err = mBuffers[clientBackBufferIndex].setSize(width, height);
+ if (UNLIKELY(err != NO_ERROR)) {
+ // This really should never happen
+ LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s",
+ clientBackBufferIndex, width, height, err, strerror(err));
+ // couldn't reallocate the surface
+ android_atomic_write(eInvalidSurface, &lcblk->swapState);
+ }
}
return err;
}
@@ -415,7 +482,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
if (UNLIKELY(state & eInvalidSurface)) {
// if eInvalidSurface is set, this means the surface
// became invalid during a transaction (NO_MEMORY for instance)
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
return;
}
@@ -457,15 +524,21 @@ Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
} while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState)));
*previousSate = oldValue;
-
+
const int32_t index = (newValue & eIndex) ^ 1;
mFrontBufferIndex = index;
+ /* NOTE: it's safe to set this flag here because this is only touched
+ * from LayerBitmap::allocate(), which by construction cannot happen
+ * while we're in post().
+ */
+ lcblk->surface[index].flags &= ~surface_info_t::eBufferDirty;
+
// ... post the new front-buffer
Region dirty(lcblk->region + index);
- dirty.andSelf(frontBuffer().bounds());
+ dirty.andSelf(frontBuffer().getBounds());
- //LOGI("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
+ //LOGD("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n",
// oldValue, newValue, mFrontBufferIndex);
//dirty.dump("dirty");
@@ -476,8 +549,8 @@ Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
"index=%d, (%dx%d), (%dx%d)",
this, newValue,
int(1-index),
- int(mBuffers[0].width()), int(mBuffers[0].height()),
- int(mBuffers[1].width()), int(mBuffers[1].height()));
+ int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()),
+ int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight()));
// here, we just posted the surface and we have resolved
// the front/back buffer indices. The client is blocked, so
@@ -522,8 +595,13 @@ Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions)
Point Layer::getPhysicalSize() const
{
- const LayerBitmap& front(frontBuffer());
- return Point(front.width(), front.height());
+ sp<const Buffer> front(frontBuffer().getBuffer());
+ Point size(front->getWidth(), front->getHeight());
+ if ((size.x | size.y) == 0) {
+ // if we don't have a buffer yet, just use the state's size.
+ size = LayerBase::getPhysicalSize();
+ }
+ return size;
}
void Layer::unlockPageFlip(
@@ -547,7 +625,7 @@ void Layer::unlockPageFlip(
// client could be blocked, so signal them so they get a
// chance to reevaluate their condition.
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
}
}
@@ -558,9 +636,30 @@ void Layer::finishPageFlip()
"layer %p wasn't locked!", this);
android_atomic_and(~eBusy, &(lcblk->swapState));
}
- mFlinger->scheduleBroadcast(client);
+ scheduleBroadcast();
+}
+
+// ---------------------------------------------------------------------------
+
+Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<Layer>& owner)
+ : Surface(flinger, id, owner->getIdentity(), owner)
+{
+}
+
+Layer::SurfaceLayer::~SurfaceLayer()
+{
}
+sp<SurfaceBuffer> Layer::SurfaceLayer::getBuffer(int usage)
+{
+ sp<SurfaceBuffer> buffer = 0;
+ sp<Layer> owner(getOwner());
+ if (owner != 0) {
+ buffer = owner->peekBuffer(usage);
+ }
+ return buffer;
+}
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 2867f2b..add5d50 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -27,6 +27,11 @@
#include <pixelflinger/pixelflinger.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
#include "LayerBitmap.h"
#include "LayerBase.h"
#include "Transform.h"
@@ -37,11 +42,12 @@ namespace android {
class Client;
class LayerBitmap;
-class MemoryDealer;
class FreezeLock;
// ---------------------------------------------------------------------------
+const int NUM_BUFFERS = 2;
+
class Layer : public LayerBaseClient
{
public:
@@ -51,16 +57,15 @@ public:
virtual uint32_t getTypeInfo() const { return typeInfo; }
Layer(SurfaceFlinger* flinger, DisplayID display,
- Client* c, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~Layer();
inline PixelFormat pixelFormat() const {
- return frontBuffer().pixelFormat();
+ return frontBuffer().getPixelFormat();
}
- status_t setBuffers( Client* client,
- uint32_t w, uint32_t h,
+ status_t setBuffers( uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags=0);
virtual void onDraw(const Region& clip) const;
@@ -73,8 +78,8 @@ public:
virtual void finishPageFlip();
virtual bool needsBlending() const { return mNeedsBlending; }
virtual bool isSecure() const { return mSecure; }
- virtual GLuint getTextureName() const { return mTextureName; }
- virtual sp<Surface> getSurface() const;
+ virtual sp<Surface> createSurface() const;
+ virtual status_t ditch();
const LayerBitmap& getBuffer(int i) const { return mBuffers[i]; }
LayerBitmap& getBuffer(int i) { return mBuffers[i]; }
@@ -96,21 +101,37 @@ private:
status_t resize(int32_t index, uint32_t w, uint32_t h, const char* what);
Region post(uint32_t* oldState, bool& recomputeVisibleRegions);
- status_t reallocateBuffer(int32_t index, uint32_t w, uint32_t h);
-
+ sp<SurfaceBuffer> peekBuffer(int usage);
+ void destroy();
+ void scheduleBroadcast();
+
+
+ class SurfaceLayer : public LayerBaseClient::Surface
+ {
+ public:
+ SurfaceLayer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<Layer>& owner);
+ ~SurfaceLayer();
+
+ private:
+ virtual sp<SurfaceBuffer> getBuffer(int usage);
+
+ sp<Layer> getOwner() const {
+ return static_cast<Layer*>(Surface::getOwner().get());
+ }
+ };
+ friend class SurfaceLayer;
+
sp<Surface> mSurface;
bool mSecure;
- LayerBitmap mBuffers[2];
+ LayerBitmap mBuffers[NUM_BUFFERS];
+ Texture mTextures[NUM_BUFFERS];
int32_t mFrontBufferIndex;
bool mNeedsBlending;
bool mResizeTransactionDone;
Region mPostedDirtyRegion;
sp<FreezeLock> mFreezeLock;
-
- GLuint mTextureName;
- GLuint mTextureWidth;
- GLuint mTextureHeight;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 0cf53f7..fd54e35 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -14,14 +14,14 @@
* 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 <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
@@ -53,19 +53,13 @@ const char* const LayerBaseClient::typeID = "LayerBaseClient";
// ---------------------------------------------------------------------------
-Vector<GLuint> LayerBase::deletedTextures;
-
-int32_t LayerBase::sIdentity = 0;
-
LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
: dpy(display), contentDirty(false),
mFlinger(flinger),
mTransformed(false),
mOrientation(0),
- mCanUseCopyBit(false),
mTransactionFlags(0),
mPremultipliedAlpha(true),
- mIdentity(uint32_t(android_atomic_inc(&sIdentity))),
mInvalidate(0)
{
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
@@ -265,43 +259,6 @@ void LayerBase::validateVisibility(const Transform& planeTransform)
mTransformed = transformed;
mLeft = tr.tx();
mTop = tr.ty();
-
- // see if we can/should use 2D h/w with the new configuration
- mCanUseCopyBit = false;
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- if (copybit) {
- const int step = copybit->get(copybit, COPYBIT_ROTATION_STEP_DEG);
- const int scaleBits = copybit->get(copybit, COPYBIT_SCALING_FRAC_BITS);
- mCanUseCopyBit = true;
- if ((mOrientation < 0) && (step > 1)) {
- // arbitrary orientations not supported
- mCanUseCopyBit = false;
- } else if ((mOrientation > 0) && (step > 90)) {
- // 90 deg rotations not supported
- mCanUseCopyBit = false;
- } else if ((tr.getType() & SkMatrix::kScale_Mask) && (scaleBits < 12)) {
- // arbitrary scaling not supported
- mCanUseCopyBit = false;
- }
-#if HONOR_PREMULTIPLIED_ALPHA
- else if (needsBlending() && mPremultipliedAlpha) {
- // pre-multiplied alpha not supported
- mCanUseCopyBit = false;
- }
-#endif
- else {
- // here, we determined we can use copybit
- if (tr.getType() & SkMatrix::kScale_Mask) {
- // and we have scaling
- if (!transparentRegionScreen.isRect()) {
- // we punt because blending is cheap (h/w) and the region is
- // complex, which may causes artifacts when copying
- // scaled content
- transparentRegionScreen.clear();
- }
- }
- }
- }
}
void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
@@ -329,8 +286,9 @@ void LayerBase::invalidate()
void LayerBase::drawRegion(const Region& reg) const
{
- Region::iterator iterator(reg);
- if (iterator) {
+ Region::const_iterator it = reg.begin();
+ Region::const_iterator const end = reg.end();
+ if (it != end) {
Rect r;
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const int32_t fbWidth = hw.getWidth();
@@ -338,7 +296,8 @@ void LayerBase::drawRegion(const Region& reg) const
const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 },
{ fbWidth, fbHeight }, { 0, fbHeight } };
glVertexPointer(2, GL_SHORT, 0, vertices);
- while (iterator.iterate(&r)) {
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -403,12 +362,14 @@ void LayerBase::clearWithOpenGL(const Region& clip) const
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
- Rect r;
- Region::iterator iterator(clip);
- if (iterator) {
+
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
glEnable(GL_SCISSOR_TEST);
glVertexPointer(2, GL_FIXED, 0, mVertices);
- while (iterator.iterate(&r)) {
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -416,15 +377,17 @@ void LayerBase::clearWithOpenGL(const Region& clip) const
}
}
-void LayerBase::drawWithOpenGL(const Region& clip,
- GLint textureName, const GGLSurface& t, int transform) const
+void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
const State& s(drawingState());
-
+
// bind our texture
- validateTexture(textureName);
+ validateTexture(texture.name);
+ uint32_t width = texture.width;
+ uint32_t height = texture.height;
+
glEnable(GL_TEXTURE_2D);
// Dithering...
@@ -472,8 +435,9 @@ void LayerBase::drawWithOpenGL(const Region& clip,
|| !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) ))
{
//StopWatch watch("GL transformed");
- Region::iterator iterator(clip);
- if (iterator) {
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
// always use high-quality filtering with fast configurations
bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG);
if (!fast && s.flags & ISurfaceComposer::eLayerFilter) {
@@ -490,21 +454,24 @@ void LayerBase::drawWithOpenGL(const Region& clip,
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
- if (transform == HAL_TRANSFORM_ROT_90) {
+ // the texture's source is rotated
+ if (texture.transform == HAL_TRANSFORM_ROT_90) {
+ // TODO: handle the other orientations
glTranslatef(0, 1, 0);
glRotatef(-90, 0, 0, 1);
}
- if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
+ if (!(mFlags & (DisplayHardware::NPOT_EXTENSION |
+ DisplayHardware::DIRECT_TEXTURE))) {
// find the smallest power-of-two that will accommodate our surface
- GLuint tw = 1 << (31 - clz(t.width));
- GLuint th = 1 << (31 - clz(t.height));
- if (tw < t.width) tw <<= 1;
- if (th < t.height) th <<= 1;
+ GLuint tw = 1 << (31 - clz(width));
+ GLuint th = 1 << (31 - clz(height));
+ if (tw < width) tw <<= 1;
+ if (th < height) th <<= 1;
// this divide should be relatively fast because it's
// a power-of-two (optimized path in libgcc)
- GLfloat ws = GLfloat(t.width) /tw;
- GLfloat hs = GLfloat(t.height)/th;
+ GLfloat ws = GLfloat(width) /tw;
+ GLfloat hs = GLfloat(height)/th;
glScalef(ws, hs, 1.0f);
}
@@ -512,8 +479,8 @@ void LayerBase::drawWithOpenGL(const Region& clip,
glVertexPointer(2, GL_FIXED, 0, mVertices);
glTexCoordPointer(2, GL_FIXED, 0, texCoords);
- Rect r;
- while (iterator.iterate(&r)) {
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -526,18 +493,19 @@ void LayerBase::drawWithOpenGL(const Region& clip,
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
} else {
- Region::iterator iterator(clip);
- if (iterator) {
- Rect r;
- GLint crop[4] = { 0, t.height, t.width, -t.height };
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
+ GLint crop[4] = { 0, height, width, -height };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
int x = tx();
int y = ty();
- y = fbHeight - (y + t.height);
- while (iterator.iterate(&r)) {
+ y = fbHeight - (y + height);
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
- glDrawTexiOES(x, y, 0, t.width, t.height);
+ glDrawTexiOES(x, y, 0, width, height);
}
}
}
@@ -550,13 +518,16 @@ void LayerBase::validateTexture(GLint textureName) const
// this is currently done in loadTexture() below
}
-void LayerBase::loadTexture(const Region& dirty,
- GLint textureName, const GGLSurface& t,
- GLuint& textureWidth, GLuint& textureHeight) const
+void LayerBase::loadTexture(Texture* texture, GLint textureName,
+ const Region& dirty, const GGLSurface& t) const
{
// TODO: defer the actual texture reload until LayerBase::validateTexture
// is called.
+ texture->name = textureName;
+ GLuint& textureWidth(texture->width);
+ GLuint& textureHeight(texture->height);
+
uint32_t flags = mFlags;
glBindTexture(GL_TEXTURE_2D, textureName);
@@ -565,8 +536,7 @@ void LayerBase::loadTexture(const Region& dirty,
/*
* In OpenGL ES we can't specify a stride with glTexImage2D (however,
- * GL_UNPACK_ALIGNMENT is 4, which in essence allows a limited form of
- * stride).
+ * GL_UNPACK_ALIGNMENT is a limited form of stride).
* So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we
* need to do something reasonable (here creating a bigger texture).
*
@@ -579,9 +549,11 @@ void LayerBase::loadTexture(const Region& dirty,
*
* This should never be a problem with POT textures
*/
-
- tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4);
-
+
+ int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format));
+ unpack = 1 << ((unpack > 3) ? 3 : unpack);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
+
/*
* round to POT if needed
*/
@@ -594,119 +566,98 @@ void LayerBase::loadTexture(const Region& dirty,
texture_h = 1 << (31 - clz(t.height));
if (texture_w < t.width) texture_w <<= 1;
if (texture_h < t.height) texture_h <<= 1;
- if (texture_w != tw || texture_h != th) {
- // we can't use DIRECT_TEXTURE since we changed the size
- // of the texture
- flags &= ~DisplayHardware::DIRECT_TEXTURE;
- }
}
-
- if (flags & DisplayHardware::DIRECT_TEXTURE) {
- // here we're guaranteed that texture_{w|h} == t{w|h}
- if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
- glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
- GL_RGB, tw, th, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
- glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
- GL_RGBA, tw, th, 0,
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
- glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0,
- GL_RGBA, tw, th, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, t.data);
- } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) {
- // TODO: add GL_BGRA extension
- } else {
- // oops, we don't handle this format, try the regular path
- goto regular;
- }
- textureWidth = tw;
- textureHeight = th;
- } else {
+
regular:
- Rect bounds(dirty.bounds());
- GLvoid* data = 0;
- if (texture_w!=textureWidth || texture_h!=textureHeight) {
- // texture size changed, we need to create a new one
-
- if (!textureWidth || !textureHeight) {
- // this is the first time, load the whole texture
- if (texture_w==tw && texture_h==th) {
- // we can do it one pass
- data = t.data;
- } else {
- // we have to create the texture first because it
- // doesn't match the size of the buffer
- bounds.set(Rect(tw, th));
- }
- }
-
- if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGB, texture_w, texture_h, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGBA, texture_w, texture_h, 0,
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGBA, texture_w, texture_h, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, data);
- } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
- t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
- // just show the Y plane of YUV buffers
+ Rect bounds(dirty.bounds());
+ GLvoid* data = 0;
+ if (texture_w!=textureWidth || texture_h!=textureHeight) {
+ // texture size changed, we need to create a new one
+
+ if (!textureWidth || !textureHeight) {
+ // this is the first time, load the whole texture
+ if (texture_w==tw && texture_h==th) {
+ // we can do it one pass
data = t.data;
- glTexImage2D(GL_TEXTURE_2D, 0,
- GL_LUMINANCE, texture_w, texture_h, 0,
- GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
} else {
- // oops, we don't handle this format!
- LOGE("layer %p, texture=%d, using format %d, which is not "
- "supported by the GL", this, textureName, t.format);
- textureName = -1;
+ // we have to create the texture first because it
+ // doesn't match the size of the buffer
+ bounds.set(Rect(tw, th));
}
- textureWidth = texture_w;
- textureHeight = texture_h;
}
- if (!data && textureName>=0) {
- if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, bounds.top, t.width, bounds.height(),
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
- t.data + bounds.top*t.width*2);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, bounds.top, t.width, bounds.height(),
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
- t.data + bounds.top*t.width*2);
- } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, bounds.top, t.width, bounds.height(),
- GL_RGBA, GL_UNSIGNED_BYTE,
- t.data + bounds.top*t.width*4);
- }
+
+ if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGB, texture_w, texture_h, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture_w, texture_h, 0,
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGBA, texture_w, texture_h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+ } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
+ t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
+ // just show the Y plane of YUV buffers
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_LUMINANCE, texture_w, texture_h, 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+ } else {
+ // oops, we don't handle this format!
+ LOGE("layer %p, texture=%d, using format %d, which is not "
+ "supported by the GL", this, textureName, t.format);
+ textureName = -1;
+ }
+ textureWidth = texture_w;
+ textureHeight = texture_h;
+ }
+ if (!data && textureName>=0) {
+ if (t.format == GGL_PIXEL_FORMAT_RGB_565) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
+ t.data + bounds.top*t.stride*2);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,
+ t.data + bounds.top*t.stride*2);
+ } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_RGBA, GL_UNSIGNED_BYTE,
+ t.data + bounds.top*t.stride*4);
+ } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP ||
+ t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) {
+ // just show the Y plane of YUV buffers
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, bounds.top, t.width, bounds.height(),
+ GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ t.data + bounds.top*t.stride);
}
}
-}
-
-bool LayerBase::canUseCopybit() const
-{
- return mCanUseCopyBit;
}
// ---------------------------------------------------------------------------
+int32_t LayerBaseClient::sIdentity = 0;
+
LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
- Client* c, int32_t i)
- : LayerBase(flinger, display), client(c),
- lcblk( c ? &(c->ctrlblk->layers[i]) : 0 ),
- mIndex(i)
+ const sp<Client>& client, int32_t i)
+ : LayerBase(flinger, display), client(client),
+ lcblk( client!=0 ? &(client->ctrlblk->layers[i]) : 0 ),
+ mIndex(i),
+ mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
{
- if (client) {
- client->bindLayer(this, i);
+}
+void LayerBaseClient::onFirstRef()
+{
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
+ client->bindLayer(this, mIndex);
// Initialize this layer's control block
memset(this->lcblk, 0, sizeof(layer_cblk_t));
this->lcblk->identity = mIdentity;
@@ -717,23 +668,113 @@ LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
LayerBaseClient::~LayerBaseClient()
{
- if (client) {
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
client->free(mIndex);
}
}
-int32_t LayerBaseClient::serverIndex() const {
- if (client) {
+int32_t LayerBaseClient::serverIndex() const
+{
+ sp<Client> client(this->client.promote());
+ if (client != 0) {
return (client->cid<<16)|mIndex;
}
return 0xFFFF0000 | mIndex;
}
-sp<LayerBaseClient::Surface> LayerBaseClient::getSurface() const
+sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
+{
+ sp<Surface> s;
+ Mutex::Autolock _l(mLock);
+ s = mClientSurface.promote();
+ if (s == 0) {
+ s = createSurface();
+ mClientSurface = s;
+ }
+ return s;
+}
+
+sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
+{
+ return new Surface(mFlinger, clientIndex(), mIdentity,
+ const_cast<LayerBaseClient *>(this));
+}
+
+// ---------------------------------------------------------------------------
+
+LayerBaseClient::Surface::Surface(
+ const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, int identity,
+ const sp<LayerBaseClient>& owner)
+ : mFlinger(flinger), mToken(id), mIdentity(identity), mOwner(owner)
+{
+}
+
+
+LayerBaseClient::Surface::~Surface()
+{
+ /*
+ * This is a good place to clean-up all client resources
+ */
+
+ // destroy client resources
+ sp<LayerBaseClient> layer = getOwner();
+ if (layer != 0) {
+ mFlinger->destroySurface(layer);
+ }
+}
+
+sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const {
+ sp<LayerBaseClient> owner(mOwner.promote());
+ return owner;
+}
+
+status_t LayerBaseClient::Surface::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case REGISTER_BUFFERS:
+ case UNREGISTER_BUFFERS:
+ case CREATE_OVERLAY:
+ {
+ if (!mFlinger->mAccessSurfaceFlinger.checkCalling()) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ }
+ return BnSurface::onTransact(code, data, reply, flags);
+}
+
+sp<SurfaceBuffer> LayerBaseClient::Surface::getBuffer(int)
{
- return new Surface(clientIndex(), mIdentity);
+ return NULL;
}
+status_t LayerBaseClient::Surface::registerBuffers(
+ const ISurface::BufferHeap& buffers)
+{
+ return INVALID_OPERATION;
+}
+
+void LayerBaseClient::Surface::postBuffer(ssize_t offset)
+{
+}
+
+void LayerBaseClient::Surface::unregisterBuffers()
+{
+}
+
+sp<OverlayRef> LayerBaseClient::Surface::createOverlay(
+ uint32_t w, uint32_t h, int32_t format)
+{
+ return NULL;
+};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index a020f44..7791941 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -20,8 +20,13 @@
#include <stdint.h>
#include <sys/types.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
#include <private/ui/LayerState.h>
+#include <utils/RefBase.h>
+
#include <ui/Region.h>
#include <ui/Overlay.h>
@@ -37,10 +42,12 @@ class SurfaceFlinger;
class DisplayHardware;
class GraphicPlane;
class Client;
+class SurfaceBuffer;
+class Buffer;
// ---------------------------------------------------------------------------
-class LayerBase
+class LayerBase : public RefBase
{
// poor man's dynamic_cast below
template<typename T>
@@ -69,10 +76,7 @@ public:
}
- static Vector<GLuint> deletedTextures;
-
LayerBase(SurfaceFlinger* flinger, DisplayID display);
- virtual ~LayerBase();
DisplayID dpy;
mutable bool contentDirty;
@@ -201,21 +205,29 @@ public:
/**
* isSecure - true if this surface is secure, that is if it prevents
- * screenshots or vns servers.
+ * screenshots or VNC servers.
*/
virtual bool isSecure() const { return false; }
- enum { // flags for doTransaction()
- eVisibleRegion = 0x00000002,
- eRestartTransaction = 0x00000008
- };
+ /** signal this layer that it's not needed any longer. called from the
+ * main thread */
+ virtual status_t ditch() { return NO_ERROR; }
+
+
+
+ enum { // flags for doTransaction()
+ eVisibleRegion = 0x00000002,
+ eRestartTransaction = 0x00000008
+ };
inline const State& drawingState() const { return mDrawingState; }
inline const State& currentState() const { return mCurrentState; }
inline State& currentState() { return mCurrentState; }
- static int compareCurrentStateZ(LayerBase*const* layerA, LayerBase*const* layerB) {
+ static int compareCurrentStateZ(
+ sp<LayerBase> const * layerA,
+ sp<LayerBase> const * layerB) {
return layerA[0]->currentState().z - layerB[0]->currentState().z;
}
@@ -229,20 +241,24 @@ protected:
GLuint createTexture() const;
- void drawWithOpenGL(const Region& clip,
- GLint textureName,
- const GGLSurface& surface,
- int transform = 0) const;
-
+ struct Texture {
+ Texture() : name(-1U), width(0), height(0),
+ image(EGL_NO_IMAGE_KHR), transform(0), dirty(true) { }
+ GLuint name;
+ GLuint width;
+ GLuint height;
+ EGLImageKHR image;
+ uint32_t transform;
+ bool dirty;
+ };
+
void clearWithOpenGL(const Region& clip) const;
+ void drawWithOpenGL(const Region& clip, const Texture& texture) const;
+ void loadTexture(Texture* texture, GLint textureName,
+ const Region& dirty, const GGLSurface& t) const;
- void loadTexture(const Region& dirty,
- GLint textureName, const GGLSurface& t,
- GLuint& textureWidth, GLuint& textureHeight) const;
-
- bool canUseCopybit() const;
- SurfaceFlinger* mFlinger;
+ sp<SurfaceFlinger> mFlinger;
uint32_t mFlags;
// cached during validateVisibility()
@@ -250,7 +266,6 @@ protected:
int32_t mOrientation;
GLfixed mVertices[4][2];
Rect mTransformedBounds;
- bool mCanUseCopyBit;
int mLeft;
int mTop;
@@ -262,16 +277,16 @@ protected:
// don't change, don't need a lock
bool mPremultipliedAlpha;
- // only read
- const uint32_t mIdentity;
-
// atomic
volatile int32_t mInvalidate;
+protected:
+ virtual ~LayerBase();
+
private:
- void validateTexture(GLint textureName) const;
- static int32_t sIdentity;
+ LayerBase(const LayerBase& rhs);
+ void validateTexture(GLint textureName) const;
};
@@ -287,66 +302,62 @@ public:
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerBaseClient();
+ virtual void onFirstRef();
-
- Client* const client;
+ wp<Client> client;
layer_cblk_t* const lcblk;
+ inline uint32_t getIdentity() const { return mIdentity; }
inline int32_t clientIndex() const { return mIndex; }
int32_t serverIndex() const;
- virtual sp<Surface> getSurface() const;
- uint32_t getIdentity() const { return mIdentity; }
+ sp<Surface> getSurface();
+ virtual sp<Surface> createSurface() const;
+
class Surface : public BnSurface
{
public:
- Surface(SurfaceID id, int identity) {
- mParams.token = id;
- mParams.identity = identity;
- }
- Surface(SurfaceID id,
- const sp<IMemoryHeap>& heap0,
- const sp<IMemoryHeap>& heap1,
- int identity)
- {
- mParams.token = id;
- mParams.identity = identity;
- mParams.heap[0] = heap0;
- mParams.heap[1] = heap1;
- }
- virtual ~Surface() {
- // TODO: We now have a point here were we can clean-up the
- // client's mess.
- // This is also where surface id should be recycled.
- //LOGD("Surface %d, heaps={%p, %p} destroyed",
- // mId, mHeap[0].get(), mHeap[1].get());
- }
-
- virtual void getSurfaceData(
- ISurfaceFlingerClient::surface_data_t* params) const {
- *params = mParams;
- }
-
- virtual status_t registerBuffers(const ISurface::BufferHeap& buffers)
- { return INVALID_OPERATION; }
- virtual void postBuffer(ssize_t offset) { }
- virtual void unregisterBuffers() { };
- virtual sp<OverlayRef> createOverlay(
- uint32_t w, uint32_t h, int32_t format) {
- return NULL;
- };
+ int32_t getToken() const { return mToken; }
+ int32_t getIdentity() const { return mIdentity; }
+
+ protected:
+ Surface(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, int identity,
+ const sp<LayerBaseClient>& owner);
+ virtual ~Surface();
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+ sp<LayerBaseClient> getOwner() const;
private:
- ISurfaceFlingerClient::surface_data_t mParams;
+ virtual sp<SurfaceBuffer> getBuffer(int usage);
+ virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
+ virtual void postBuffer(ssize_t offset);
+ virtual void unregisterBuffers();
+ virtual sp<OverlayRef> createOverlay(uint32_t w, uint32_t h,
+ int32_t format);
+
+ protected:
+ friend class LayerBaseClient;
+ sp<SurfaceFlinger> mFlinger;
+ int32_t mToken;
+ int32_t mIdentity;
+ wp<LayerBaseClient> mOwner;
};
-private:
- int32_t mIndex;
+ friend class Surface;
+private:
+ int32_t mIndex;
+ mutable Mutex mLock;
+ mutable wp<Surface> mClientSurface;
+ // only read
+ const uint32_t mIdentity;
+ static int32_t sIdentity;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 397ddc8..dd61e1a 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -14,174 +14,185 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
-#include <cutils/memory.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <utils/MemoryDealer.h>
-#include <utils/IMemory.h>
+#include <binder/MemoryBase.h>
+#include <binder/IMemory.h>
+
#include <ui/PixelFormat.h>
+#include <ui/Surface.h>
#include <pixelflinger/pixelflinger.h>
+#include "BufferAllocator.h"
#include "LayerBitmap.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
namespace android {
-// ---------------------------------------------------------------------------
+// ===========================================================================
+// Buffer and implementation of android_native_buffer_t
+// ===========================================================================
-LayerBitmap::LayerBitmap()
- : mAllocFlags(0), mOffset(0), mSize(-1U), mAlignment(2)
+Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t reqUsage, uint32_t flags)
+ : SurfaceBuffer(), mInitCheck(NO_INIT), mFlags(flags),
+ mVStride(0)
{
- memset(&mSurface, 0, sizeof(mSurface));
+ this->format = format;
+ if (w>0 && h>0) {
+ mInitCheck = initSize(w, h, reqUsage);
+ }
}
-LayerBitmap::~LayerBitmap()
+Buffer::~Buffer()
{
- mSurface.data = 0;
+ if (handle) {
+ BufferAllocator& allocator(BufferAllocator::get());
+ allocator.free(handle);
+ }
}
-status_t LayerBitmap::init(const sp<MemoryDealer>& allocator)
-{
- if (mAllocator != NULL)
- return BAD_VALUE;
- mAllocator = allocator;
- return NO_ERROR;
+status_t Buffer::initCheck() const {
+ return mInitCheck;
}
-status_t LayerBitmap::setBits(uint32_t w, uint32_t h, uint32_t alignment,
- PixelFormat format, uint32_t flags)
+android_native_buffer_t* Buffer::getNativeBuffer() const
{
- const sp<MemoryDealer>& allocator(mAllocator);
- if (allocator == NULL)
- return NO_INIT;
-
- if (UNLIKELY(w == mSurface.width && h == mSurface.height &&
- format == mSurface.format))
- { // same format and size, do nothing.
- return NO_ERROR;
- }
-
- PixelFormatInfo info;
- getPixelFormatInfo(format, &info);
-
- uint32_t allocFlags = MemoryDealer::PAGE_ALIGNED;
- const uint32_t align = 4; // must match GL_UNPACK_ALIGNMENT
- const uint32_t Bpp = info.bytesPerPixel;
- uint32_t stride = (w + (alignment-1)) & ~(alignment-1);
- stride = ((stride * Bpp + (align-1)) & ~(align-1)) / Bpp;
- size_t size = info.getScanlineSize(stride) * h;
- if (allocFlags & MemoryDealer::PAGE_ALIGNED) {
- size_t pagesize = getpagesize();
- size = (size + (pagesize-1)) & ~(pagesize-1);
- }
+ return static_cast<android_native_buffer_t*>(const_cast<Buffer*>(this));
+}
- /* FIXME: we should be able to have a h/v stride because the user of the
- * surface might have stride limitation (for instance h/w codecs often do)
+status_t Buffer::initSize(uint32_t w, uint32_t h, uint32_t reqUsage)
+{
+ status_t err = NO_ERROR;
+
+ BufferAllocator& allocator = BufferAllocator::get();
+
+ /*
+ * buffers used for software rendering, but h/w composition
+ * are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE
+ *
+ * buffers used for h/w rendering and h/w composition
+ * are allocated with HW_RENDER | HW_TEXTURE
+ *
+ * buffers used with h/w rendering and either NPOT or no egl_image_ext
+ * are allocated with SW_READ_RARELY | HW_RENDER
+ *
*/
- int32_t vstride = 0;
-
- mAlignment = alignment;
- mAllocFlags = allocFlags;
- mOffset = 0;
- if (mSize != size) {
- // would be nice to have a reallocate() api
- mBitsMemory.clear(); // free-memory
- mBitsMemory = allocator->allocate(size, allocFlags);
- mSize = size;
+
+ if (mFlags & Buffer::SECURE) {
+ // secure buffer, don't store it into the GPU
+ usage = BufferAllocator::USAGE_SW_READ_OFTEN |
+ BufferAllocator::USAGE_SW_WRITE_OFTEN;
} else {
- // don't erase memory if we didn't have to reallocate
- flags &= ~SECURE_BITS;
- }
- if (mBitsMemory != 0) {
- mOffset = mBitsMemory->offset();
- mSurface.data = static_cast<GGLubyte*>(mBitsMemory->pointer());
- mSurface.version = sizeof(GGLSurface);
- mSurface.width = w;
- mSurface.height = h;
- mSurface.stride = stride;
- mSurface.vstride = vstride;
- mSurface.format = format;
- if (flags & SECURE_BITS)
- clear();
+ // it's allowed to modify the usage flags here, but generally
+ // the requested flags should be honored.
+ usage = reqUsage | BufferAllocator::USAGE_HW_TEXTURE;
}
- if (mBitsMemory==0 || mSurface.data==0) {
- LOGE("not enough memory for layer bitmap "
- "size=%u (w=%d, h=%d, stride=%d, format=%d)",
- size, int(w), int(h), int(stride), int(format));
- allocator->dump("LayerBitmap");
- mSurface.data = 0;
- mSize = -1U;
- return NO_MEMORY;
+ err = allocator.alloc(w, h, format, usage, &handle, &stride);
+
+ if (err == NO_ERROR) {
+ width = w;
+ height = h;
+ mVStride = 0;
}
- return NO_ERROR;
+
+ return err;
}
-void LayerBitmap::clear()
+status_t Buffer::lock(GGLSurface* sur, uint32_t usage)
{
- // NOTE: this memset should not be necessary, at least for
- // opaque surface. However, for security reasons it's better to keep it
- // (in the case of pmem, it's possible that the memory contains old
- // data)
- if (mSurface.data) {
- memset(mSurface.data, 0, mSize);
- //if (bytesPerPixel(mSurface.format) == 4) {
- // android_memset32((uint32_t*)mSurface.data, 0xFF0000FF, mSize);
- //} else {
- // android_memset16((uint16_t*)mSurface.data, 0xF800, mSize);
- //}
+ void* vaddr;
+ status_t res = SurfaceBuffer::lock(usage, &vaddr);
+ if (res == NO_ERROR && sur) {
+ sur->version = sizeof(GGLSurface);
+ sur->width = width;
+ sur->height = height;
+ sur->stride = stride;
+ sur->format = format;
+ sur->vstride = mVStride;
+ sur->data = static_cast<GGLubyte*>(vaddr);
}
+ return res;
}
-status_t LayerBitmap::getInfo(surface_info_t* info) const
+// ===========================================================================
+// LayerBitmap
+// ===========================================================================
+
+LayerBitmap::LayerBitmap()
+ : mInfo(0), mWidth(0), mHeight(0)
{
- if (mSurface.data == 0) {
- memset(info, 0, sizeof(surface_info_t));
- info->bits_offset = NO_MEMORY;
- return NO_MEMORY;
- }
- info->w = uint16_t(width());
- info->h = uint16_t(height());
- info->stride= uint16_t(stride());
- info->bpr = uint16_t(stride() * bytesPerPixel(pixelFormat()));
- info->format= uint8_t(pixelFormat());
- info->flags = surface_info_t::eBufferDirty;
- info->bits_offset = ssize_t(mOffset);
+}
+
+LayerBitmap::~LayerBitmap()
+{
+}
+
+status_t LayerBitmap::init(surface_info_t* info,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+{
+ if (info == NULL)
+ return BAD_VALUE;
+
+ mFormat = format;
+ mFlags = flags;
+ mWidth = w;
+ mHeight = h;
+
+ mInfo = info;
+ memset(info, 0, sizeof(surface_info_t));
+ info->flags = surface_info_t::eNeedNewBuffer;
+
+ // init the buffer, but don't trigger an allocation
+ mBuffer = new Buffer(0, 0, format, flags);
return NO_ERROR;
}
-status_t LayerBitmap::resize(uint32_t w, uint32_t h)
+status_t LayerBitmap::setSize(uint32_t w, uint32_t h)
{
- int err = setBits(w, h, mAlignment, pixelFormat(), SECURE_BITS);
- return err;
+ Mutex::Autolock _l(mLock);
+ if ((w != mWidth) || (h != mHeight)) {
+ mWidth = w;
+ mHeight = h;
+ // this will signal the client that it needs to asks us for a new buffer
+ mInfo->flags = surface_info_t::eNeedNewBuffer;
+ }
+ return NO_ERROR;
}
-size_t LayerBitmap::size() const
+sp<Buffer> LayerBitmap::allocate(uint32_t reqUsage)
{
- return mSize;
+ Mutex::Autolock _l(mLock);
+ surface_info_t* info = mInfo;
+ mBuffer.clear(); // free buffer before allocating a new one
+ sp<Buffer> buffer = new Buffer(mWidth, mHeight, mFormat, reqUsage, mFlags);
+ status_t err = buffer->initCheck();
+ if (LIKELY(err == NO_ERROR)) {
+ info->flags = surface_info_t::eBufferDirty;
+ info->status = NO_ERROR;
+ } else {
+ memset(info, 0, sizeof(surface_info_t));
+ info->status = NO_MEMORY;
+ }
+ mBuffer = buffer;
+ return buffer;
}
-void LayerBitmap::getBitmapSurface(copybit_image_t* img) const
+status_t LayerBitmap::free()
{
- const sp<IMemoryHeap>& mh(getAllocator()->getMemoryHeap());
- void* sbase = mh->base();
- const GGLSurface& t(surface());
- img->w = t.stride ?: t.width;
- img->h = t.vstride ?: t.height;
- img->format = t.format;
- img->offset = intptr_t(t.data) - intptr_t(sbase);
- img->base = sbase;
- img->fd = mh->heapID();
+ mBuffer.clear();
+ mWidth = 0;
+ mHeight = 0;
+ return NO_ERROR;
}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
index 9ad64c4..87e8f42 100644
--- a/libs/surfaceflinger/LayerBitmap.h
+++ b/libs/surfaceflinger/LayerBitmap.h
@@ -20,63 +20,113 @@
#include <stdint.h>
#include <sys/types.h>
+#include <hardware/gralloc.h>
+
#include <utils/Atomic.h>
+
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
-#include <private/ui/SharedState.h>
+#include <ui/Surface.h>
+
#include <pixelflinger/pixelflinger.h>
+#include <private/ui/SharedState.h>
+#include <private/ui/SurfaceBuffer.h>
+
class copybit_image_t;
+struct android_native_buffer_t;
namespace android {
// ---------------------------------------------------------------------------
-
class IMemory;
-class MemoryDealer;
class LayerBitmap;
-// ---------------------------------------------------------------------------
+// ===========================================================================
+// Buffer
+// ===========================================================================
-class LayerBitmap
+class NativeBuffer;
+
+class Buffer : public SurfaceBuffer
{
public:
-
enum {
- // erase memory to ensure security when necessary
- SECURE_BITS = 0x00000001
+ DONT_CLEAR = 0x00000001,
+ SECURE = 0x00000004
};
- LayerBitmap();
- ~LayerBitmap();
- status_t init(const sp<MemoryDealer>& allocator);
+ // creates w * h buffer
+ Buffer(uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t reqUsage, uint32_t flags = 0);
+
+ // return status
+ status_t initCheck() const;
+
+ uint32_t getWidth() const { return width; }
+ uint32_t getHeight() const { return height; }
+ uint32_t getStride() const { return stride; }
+ uint32_t getUsage() const { return usage; }
+ PixelFormat getPixelFormat() const { return format; }
+ Rect getBounds() const { return Rect(width, height); }
+
+ status_t lock(GGLSurface* surface, uint32_t usage);
+
+ android_native_buffer_t* getNativeBuffer() const;
+
+private:
+ friend class LightRefBase<Buffer>;
+ Buffer(const Buffer& rhs);
+ virtual ~Buffer();
+ Buffer& operator = (const Buffer& rhs);
+ const Buffer& operator = (const Buffer& rhs) const;
- status_t setBits(uint32_t w, uint32_t h, uint32_t alignment,
- PixelFormat format, uint32_t flags = 0);
- void clear();
+ status_t initSize(uint32_t w, uint32_t h, uint32_t reqUsage);
- status_t getInfo(surface_info_t* info) const;
- status_t resize(uint32_t w, uint32_t h);
+ ssize_t mInitCheck;
+ uint32_t mFlags;
+ uint32_t mVStride;
+};
- const GGLSurface& surface() const { return mSurface; }
- Rect bounds() const { return Rect(width(), height()); }
- uint32_t width() const { return surface().width; }
- uint32_t height() const { return surface().height; }
- uint32_t stride() const { return surface().stride; }
- PixelFormat pixelFormat() const { return surface().format; }
- void* serverBits() const { return surface().data; }
- size_t size() const;
- const sp<MemoryDealer>& getAllocator() const { return mAllocator; }
- void getBitmapSurface(copybit_image_t* img) const;
+// ===========================================================================
+// LayerBitmap
+// ===========================================================================
+class LayerBitmap
+{
+public:
+ enum {
+ DONT_CLEAR = Buffer::DONT_CLEAR,
+ SECURE = Buffer::SECURE
+ };
+ LayerBitmap();
+ ~LayerBitmap();
+
+ status_t init(surface_info_t* info,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags = 0);
+
+ status_t setSize(uint32_t w, uint32_t h);
+
+ sp<Buffer> allocate(uint32_t reqUsage);
+ status_t free();
+
+ sp<const Buffer> getBuffer() const { return mBuffer; }
+ sp<Buffer> getBuffer() { return mBuffer; }
+
+ uint32_t getWidth() const { return mWidth; }
+ uint32_t getHeight() const { return mHeight; }
+ PixelFormat getPixelFormat() const { return mBuffer->getPixelFormat(); }
+ Rect getBounds() const { return mBuffer->getBounds(); }
+
private:
- sp<MemoryDealer> mAllocator;
- sp<IMemory> mBitsMemory;
- uint32_t mAllocFlags;
- ssize_t mOffset;
- GGLSurface mSurface;
- size_t mSize;
- uint32_t mAlignment;
+ surface_info_t* mInfo;
+ sp<Buffer> mBuffer;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ PixelFormat mFormat;
+ uint32_t mFlags;
+ // protects setSize() and allocate()
+ mutable Mutex mLock;
};
}; // namespace android
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index d3e456f..00abd5a 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
@@ -40,7 +38,7 @@ const char* const LayerBlur::typeID = "LayerBlur";
// ---------------------------------------------------------------------------
LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i)
+ const sp<Client>& client, int32_t i)
: LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
mRefreshCache(true), mCacheAge(0), mTextureName(-1U)
{
@@ -49,8 +47,7 @@ LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
LayerBlur::~LayerBlur()
{
if (mTextureName != -1U) {
- //glDeleteTextures(1, &mTextureName);
- deletedTextures.add(mTextureName);
+ glDeleteTextures(1, &mTextureName);
}
}
@@ -139,8 +136,9 @@ void LayerBlur::onDraw(const Region& clip) const
glGenTextures(1, &mTextureName);
}
- Region::iterator iterator(clip);
- if (iterator) {
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (it != end) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mTextureName);
@@ -201,27 +199,25 @@ void LayerBlur::onDraw(const Region& clip) const
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FIXED, 0, mVertices);
glTexCoordPointer(2, GL_FIXED, 0, mVertices);
- Rect r;
- while (iterator.iterate(&r)) {
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
} else {
- Region::iterator iterator(clip);
- if (iterator) {
- // NOTE: this is marginally faster with the software gl, because
- // glReadPixels() reads the fb bottom-to-top, however we'll
- // skip all the jaccobian computations.
- Rect r;
- GLint crop[4] = { 0, 0, w, h };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- y = fbHeight - (y + h);
- while (iterator.iterate(&r)) {
- const GLint sy = fbHeight - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glDrawTexiOES(x, y, 0, w, h);
- }
+ // NOTE: this is marginally faster with the software gl, because
+ // glReadPixels() reads the fb bottom-to-top, however we'll
+ // skip all the jaccobian computations.
+ Rect r;
+ GLint crop[4] = { 0, 0, w, h };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ y = fbHeight - (y + h);
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawTexiOES(x, y, 0, w, h);
}
}
}
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index 24b1156..0c3e6eb 100644
--- a/libs/surfaceflinger/LayerBlur.h
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -39,7 +39,7 @@ public:
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerBlur(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerBlur();
virtual void onDraw(const Region& clip) const;
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 00fab70..bd6d472 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
@@ -25,17 +23,17 @@
#include <utils/Log.h>
#include <utils/StopWatch.h>
-#include <utils/IPCThreadState.h>
-#include <utils/IServiceManager.h>
-
#include <ui/PixelFormat.h>
-#include <ui/EGLDisplaySurface.h>
+#include <ui/FramebufferNativeWindow.h>
+
+#include <hardware/copybit.h>
+#include "BufferAllocator.h"
#include "LayerBuffer.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
+#include "gralloc_priv.h" // needed for msm / copybit
namespace android {
@@ -47,7 +45,7 @@ const char* const LayerBuffer::typeID = "LayerBuffer";
// ---------------------------------------------------------------------------
LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i)
+ const sp<Client>& client, int32_t i)
: LayerBaseClient(flinger, display, client, i),
mNeedsBlending(false)
{
@@ -55,30 +53,24 @@ LayerBuffer::LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
LayerBuffer::~LayerBuffer()
{
- sp<SurfaceBuffer> s(getClientSurface());
- if (s != 0) {
- s->disown();
- mClientSurface.clear();
- }
}
-sp<LayerBuffer::SurfaceBuffer> LayerBuffer::getClientSurface() const
+void LayerBuffer::onFirstRef()
{
- Mutex::Autolock _l(mLock);
- return mClientSurface.promote();
+ LayerBaseClient::onFirstRef();
+ mSurface = new SurfaceBuffer(mFlinger, clientIndex(),
+ const_cast<LayerBuffer *>(this));
}
-sp<LayerBaseClient::Surface> LayerBuffer::getSurface() const
+sp<LayerBaseClient::Surface> LayerBuffer::createSurface() const
{
- sp<SurfaceBuffer> s;
- Mutex::Autolock _l(mLock);
- s = mClientSurface.promote();
- if (s == 0) {
- s = new SurfaceBuffer(clientIndex(),
- const_cast<LayerBuffer *>(this));
- mClientSurface = s;
- }
- return s;
+ return mSurface;
+}
+
+status_t LayerBuffer::ditch()
+{
+ mSurface.clear();
+ return NO_ERROR;
}
bool LayerBuffer::needsBlending() const {
@@ -192,82 +184,49 @@ sp<LayerBuffer::Source> LayerBuffer::clearSource() {
// LayerBuffer::SurfaceBuffer
// ============================================================================
-LayerBuffer::SurfaceBuffer::SurfaceBuffer(SurfaceID id, LayerBuffer* owner)
-: LayerBaseClient::Surface(id, owner->getIdentity()), mOwner(owner)
+LayerBuffer::SurfaceBuffer::SurfaceBuffer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<LayerBuffer>& owner)
+ : LayerBaseClient::Surface(flinger, id, owner->getIdentity(), owner)
{
}
LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
{
unregisterBuffers();
- mOwner = 0;
-}
-
-status_t LayerBuffer::SurfaceBuffer::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
- case REGISTER_BUFFERS:
- case UNREGISTER_BUFFERS:
- case CREATE_OVERLAY:
- {
- // codes that require permission check
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int self_pid = getpid();
- if (LIKELY(pid != self_pid)) {
- // we're called from a different process, do the real check
- if (!checkCallingPermission(
- String16("android.permission.ACCESS_SURFACE_FLINGER")))
- {
- const int uid = ipc->getCallingUid();
- LOGE("Permission Denial: "
- "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- }
- }
- }
- return LayerBaseClient::Surface::onTransact(code, data, reply, flags);
}
-status_t LayerBuffer::SurfaceBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
+status_t LayerBuffer::SurfaceBuffer::registerBuffers(
+ const ISurface::BufferHeap& buffers)
{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
return owner->registerBuffers(buffers);
return NO_INIT;
}
void LayerBuffer::SurfaceBuffer::postBuffer(ssize_t offset)
{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
owner->postBuffer(offset);
}
void LayerBuffer::SurfaceBuffer::unregisterBuffers()
{
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
owner->unregisterBuffers();
}
sp<OverlayRef> LayerBuffer::SurfaceBuffer::createOverlay(
uint32_t w, uint32_t h, int32_t format) {
sp<OverlayRef> result;
- LayerBuffer* owner(getOwner());
- if (owner)
+ sp<LayerBuffer> owner(getOwner());
+ if (owner != 0)
result = owner->createOverlay(w, h, format);
return result;
}
-void LayerBuffer::SurfaceBuffer::disown()
-{
- Mutex::Autolock _l(mLock);
- mOwner = 0;
-}
-
// ============================================================================
// LayerBuffer::Buffer
// ============================================================================
@@ -276,20 +235,30 @@ LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
: mBufferHeap(buffers)
{
NativeBuffer& src(mNativeBuffer);
+
src.crop.l = 0;
src.crop.t = 0;
src.crop.r = buffers.w;
src.crop.b = buffers.h;
- src.img.w = buffers.hor_stride ?: buffers.w;
- src.img.h = buffers.ver_stride ?: buffers.h;
- src.img.format = buffers.format;
- src.img.offset = offset;
- src.img.base = buffers.heap->base();
- src.img.fd = buffers.heap->heapID();
+
+ src.img.w = buffers.hor_stride ?: buffers.w;
+ src.img.h = buffers.ver_stride ?: buffers.h;
+ src.img.format = buffers.format;
+ src.img.base = (void*)(intptr_t(buffers.heap->base()) + offset);
+
+ // FIXME: gross hack, we should never access private_handle_t from here,
+ // but this is needed by msm drivers
+ private_handle_t* hnd = new private_handle_t(
+ buffers.heap->heapID(), buffers.heap->getSize(), 0);
+ hnd->offset = offset;
+ src.img.handle = hnd;
}
LayerBuffer::Buffer::~Buffer()
{
+ NativeBuffer& src(mNativeBuffer);
+ if (src.img.handle)
+ delete (private_handle_t*)src.img.handle;
}
// ============================================================================
@@ -323,8 +292,7 @@ bool LayerBuffer::Source::transformed() const {
LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
const ISurface::BufferHeap& buffers)
- : Source(layer), mStatus(NO_ERROR),
- mBufferSize(0), mTextureName(-1U)
+ : Source(layer), mStatus(NO_ERROR), mBufferSize(0)
{
if (buffers.heap == NULL) {
// this is allowed, but in this case, it is illegal to receive
@@ -363,13 +331,21 @@ LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
mLayer.forceVisibilityTransaction();
-
+
+ hw_module_t const* module;
+ mBlitEngine = NULL;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ copybit_open(module, &mBlitEngine);
+ }
}
LayerBuffer::BufferSource::~BufferSource()
{
- if (mTextureName != -1U) {
- LayerBase::deletedTextures.add(mTextureName);
+ if (mTexture.name != -1U) {
+ glDeleteTextures(1, &mTexture.name);
+ }
+ if (mBlitEngine) {
+ copybit_close(mBlitEngine);
}
}
@@ -427,19 +403,19 @@ bool LayerBuffer::BufferSource::transformed() const
void LayerBuffer::BufferSource::onDraw(const Region& clip) const
{
- sp<Buffer> buffer(getBuffer());
- if (UNLIKELY(buffer == 0)) {
+ sp<Buffer> ourBuffer(getBuffer());
+ if (UNLIKELY(ourBuffer == 0)) {
// nothing to do, we don't have a buffer
mLayer.clearWithOpenGL(clip);
return;
}
status_t err = NO_ERROR;
- NativeBuffer src(buffer->getBuffer());
+ NativeBuffer src(ourBuffer->getBuffer());
const Rect& transformedBounds = mLayer.getTransformedBounds();
- const int can_use_copybit = mLayer.canUseCopybit();
+ copybit_device_t* copybit = mBlitEngine;
- if (can_use_copybit) {
+ if (copybit) {
const int src_width = src.crop.r - src.crop.l;
const int src_height = src.crop.b - src.crop.t;
int W = transformedBounds.width();
@@ -448,89 +424,110 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
int t(W); W=H; H=t;
}
- /* With LayerBuffer, it is likely that we'll have to rescale the
- * surface, because this is often used for video playback or
- * camera-preview. Since we want these operation as fast as possible
- * we make sure we can use the 2D H/W even if it doesn't support
- * the requested scale factor, in which case we perform the scaling
- * in several passes. */
-
- copybit_device_t* copybit = mLayer.mFlinger->getBlitEngine();
- const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
- const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
-
- float xscale = 1.0f;
- if (src_width > W*min) xscale = 1.0f / min;
- else if (src_width*mag < W) xscale = mag;
-
- float yscale = 1.0f;
- if (src_height > H*min) yscale = 1.0f / min;
- else if (src_height*mag < H) yscale = mag;
-
- if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
- if (UNLIKELY(mTemporaryDealer == 0)) {
- // allocate a memory-dealer for this the first time
- mTemporaryDealer = mLayer.mFlinger->getSurfaceHeapManager()
- ->createHeap(ISurfaceComposer::eHardware);
- mTempBitmap.init(mTemporaryDealer);
+#ifdef EGL_ANDROID_get_render_buffer
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLSurface draw = eglGetCurrentSurface(EGL_DRAW);
+ EGLClientBuffer clientBuf = eglGetRenderBufferANDROID(dpy, draw);
+ android_native_buffer_t* nb = (android_native_buffer_t*)clientBuf;
+ if (nb == 0) {
+ err = BAD_VALUE;
+ } else {
+ copybit_image_t dst;
+ dst.w = nb->width;
+ dst.h = nb->height;
+ dst.format = nb->format;
+ dst.base = NULL; // unused by copybit on msm7k
+ dst.handle = (native_handle_t *)nb->handle;
+
+ /* With LayerBuffer, it is likely that we'll have to rescale the
+ * surface, because this is often used for video playback or
+ * camera-preview. Since we want these operation as fast as possible
+ * we make sure we can use the 2D H/W even if it doesn't support
+ * the requested scale factor, in which case we perform the scaling
+ * in several passes. */
+
+ const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
+ const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
+
+ float xscale = 1.0f;
+ if (src_width > W*min) xscale = 1.0f / min;
+ else if (src_width*mag < W) xscale = mag;
+
+ float yscale = 1.0f;
+ if (src_height > H*min) yscale = 1.0f / min;
+ else if (src_height*mag < H) yscale = mag;
+
+ if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
+ const int tmp_w = floorf(src_width * xscale);
+ const int tmp_h = floorf(src_height * yscale);
+
+ if (mTempBitmap==0 ||
+ mTempBitmap->getWidth() < tmp_w ||
+ mTempBitmap->getHeight() < tmp_h) {
+ mTempBitmap.clear();
+ mTempBitmap = new android::Buffer(
+ tmp_w, tmp_h, src.img.format,
+ BufferAllocator::USAGE_HW_2D);
+ err = mTempBitmap->initCheck();
+ }
+
+ if (LIKELY(err == NO_ERROR)) {
+ NativeBuffer tmp;
+ tmp.img.w = tmp_w;
+ tmp.img.h = tmp_h;
+ tmp.img.format = src.img.format;
+ tmp.img.handle = (native_handle_t*)mTempBitmap->getNativeBuffer()->handle;
+ tmp.crop.l = 0;
+ tmp.crop.t = 0;
+ tmp.crop.r = tmp.img.w;
+ tmp.crop.b = tmp.img.h;
+
+ region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+ err = copybit->stretch(copybit,
+ &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
+ src = tmp;
+ }
}
- const int tmp_w = floorf(src_width * xscale);
- const int tmp_h = floorf(src_height * yscale);
- err = mTempBitmap.setBits(tmp_w, tmp_h, 1, src.img.format);
-
- if (LIKELY(err == NO_ERROR)) {
- NativeBuffer tmp;
- mTempBitmap.getBitmapSurface(&tmp.img);
- tmp.crop.l = 0;
- tmp.crop.t = 0;
- tmp.crop.r = tmp.img.w;
- tmp.crop.b = tmp.img.h;
-
- region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
- err = copybit->stretch(copybit,
- &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
- src = tmp;
+ const Rect& transformedBounds = mLayer.getTransformedBounds();
+ const copybit_rect_t& drect =
+ reinterpret_cast<const copybit_rect_t&>(transformedBounds);
+ const State& s(mLayer.drawingState());
+ region_iterator it(clip);
+
+ // pick the right orientation for this buffer
+ int orientation = mLayer.getOrientation();
+ if (UNLIKELY(mBufferHeap.transform)) {
+ Transform rot90;
+ GraphicPlane::orientationToTransfrom(
+ ISurfaceComposer::eOrientation90, 0, 0, &rot90);
+ const Transform& planeTransform(mLayer.graphicPlane(0).transform());
+ const Layer::State& s(mLayer.drawingState());
+ Transform tr(planeTransform * s.transform * rot90);
+ orientation = tr.getOrientation();
}
- }
- const DisplayHardware& hw(mLayer.graphicPlane(0).displayHardware());
- copybit_image_t dst;
- hw.getDisplaySurface(&dst);
- const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
- const State& s(mLayer.drawingState());
- region_iterator it(clip);
-
- // pick the right orientation for this buffer
- int orientation = mLayer.getOrientation();
- if (UNLIKELY(mBufferHeap.transform)) {
- Transform rot90;
- GraphicPlane::orientationToTransfrom(
- ISurfaceComposer::eOrientation90, 0, 0, &rot90);
- const Transform& planeTransform(mLayer.graphicPlane(0).transform());
- const Layer::State& s(mLayer.drawingState());
- Transform tr(planeTransform * s.transform * rot90);
- orientation = tr.getOrientation();
- }
-
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
-
- err = copybit->stretch(copybit,
- &dst, &src.img, &drect, &src.crop, &it);
- if (err != NO_ERROR) {
- LOGE("copybit failed (%s)", strerror(err));
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
+ err = copybit->stretch(copybit,
+ &dst, &src.img, &drect, &src.crop, &it);
+ if (err != NO_ERROR) {
+ LOGE("copybit failed (%s)", strerror(err));
+ }
}
}
-
- if (!can_use_copybit || err) {
- if (UNLIKELY(mTextureName == -1LU)) {
- mTextureName = mLayer.createTexture();
+#endif
+
+ if (!copybit || err)
+ {
+ // OpenGL fall-back
+ if (UNLIKELY(mTexture.name == -1LU)) {
+ mTexture.name = mLayer.createTexture();
}
GLuint w = 0;
GLuint h = 0;
@@ -541,10 +538,11 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
t.stride = src.img.w;
t.vstride= src.img.h;
t.format = src.img.format;
- t.data = (GGLubyte*)(intptr_t(src.img.base) + src.img.offset);
+ t.data = (GGLubyte*)src.img.base;
const Region dirty(Rect(t.width, t.height));
- mLayer.loadTexture(dirty, mTextureName, t, w, h);
- mLayer.drawWithOpenGL(clip, mTextureName, t, mBufferHeap.transform);
+ mLayer.loadTexture(&mTexture, mTexture.name, dirty, t);
+ mTexture.transform = mBufferHeap.transform;
+ mLayer.drawWithOpenGL(clip, mTexture);
}
}
@@ -580,6 +578,7 @@ LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
mFormat = overlay->format;
mWidthStride = overlay->w_stride;
mHeightStride = overlay->h_stride;
+ mInitialized = false;
mOverlayHandle = overlay->getHandleRef(overlay);
@@ -599,6 +598,11 @@ LayerBuffer::OverlaySource::~OverlaySource()
}
}
+void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
+{
+ mLayer.clearWithOpenGL(clip);
+}
+
void LayerBuffer::OverlaySource::onTransaction(uint32_t flags)
{
const Layer::State& front(mLayer.drawingState());
@@ -614,8 +618,9 @@ void LayerBuffer::OverlaySource::onVisibilityResolved(
// this code-path must be as tight as possible, it's called each time
// the screen is composited.
if (UNLIKELY(mOverlay != 0)) {
- if (mVisibilityChanged) {
+ if (mVisibilityChanged || !mInitialized) {
mVisibilityChanged = false;
+ mInitialized = true;
const Rect& bounds = mLayer.getTransformedBounds();
int x = bounds.left;
int y = bounds.top;
@@ -627,8 +632,9 @@ void LayerBuffer::OverlaySource::onVisibilityResolved(
if (mOverlay) {
overlay_control_device_t* overlay_dev = mOverlayDevice;
overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
- overlay_dev->setParameter(overlay_dev, mOverlay,
+ overlay_dev->setParameter(overlay_dev, mOverlay,
OVERLAY_TRANSFORM, mLayer.getOrientation());
+ overlay_dev->commit(overlay_dev, mOverlay);
}
}
}
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 2dc77f1..8057219 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -20,18 +20,18 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/IMemory.h>
+#include <binder/IMemory.h>
#include <private/ui/LayerState.h>
-#include <EGL/eglnatives.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
+struct copybit_device_t;
+
namespace android {
// ---------------------------------------------------------------------------
-class MemoryDealer;
class Region;
class OverlayRef;
@@ -51,7 +51,6 @@ class LayerBuffer : public LayerBaseClient
LayerBuffer& mLayer;
};
-
public:
static const uint32_t typeInfo;
static const char* const typeID;
@@ -59,12 +58,14 @@ public:
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerBuffer(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerBuffer();
+ virtual void onFirstRef();
virtual bool needsBlending() const;
- virtual sp<LayerBaseClient::Surface> getSurface() const;
+ virtual sp<LayerBaseClient::Surface> createSurface() const;
+ virtual status_t ditch();
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t flags);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
@@ -121,14 +122,14 @@ private:
virtual void unregisterBuffers();
virtual bool transformed() const;
private:
- mutable Mutex mLock;
- sp<Buffer> mBuffer;
- status_t mStatus;
- ISurface::BufferHeap mBufferHeap;
- size_t mBufferSize;
- mutable sp<MemoryDealer> mTemporaryDealer;
- mutable LayerBitmap mTempBitmap;
- mutable GLuint mTextureName;
+ mutable Mutex mLock;
+ sp<Buffer> mBuffer;
+ status_t mStatus;
+ ISurface::BufferHeap mBufferHeap;
+ size_t mBufferSize;
+ mutable sp<android::Buffer> mTempBitmap;
+ mutable LayerBase::Texture mTexture;
+ copybit_device_t* mBlitEngine;
};
class OverlaySource : public Source {
@@ -137,6 +138,7 @@ private:
sp<OverlayRef>* overlayRef,
uint32_t w, uint32_t h, int32_t format);
virtual ~OverlaySource();
+ virtual void onDraw(const Region& clip) const;
virtual void onTransaction(uint32_t flags);
virtual void onVisibilityResolved(const Transform& planeTransform);
private:
@@ -173,40 +175,34 @@ private:
int32_t mWidthStride;
int32_t mHeightStride;
mutable Mutex mLock;
+ bool mInitialized;
};
class SurfaceBuffer : public LayerBaseClient::Surface
{
public:
- SurfaceBuffer(SurfaceID id, LayerBuffer* owner);
+ SurfaceBuffer(const sp<SurfaceFlinger>& flinger,
+ SurfaceID id, const sp<LayerBuffer>& owner);
virtual ~SurfaceBuffer();
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+
virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
+
virtual sp<OverlayRef> createOverlay(
uint32_t w, uint32_t h, int32_t format);
- void disown();
private:
- LayerBuffer* getOwner() const {
- Mutex::Autolock _l(mLock);
- return mOwner;
+ sp<LayerBuffer> getOwner() const {
+ return static_cast<LayerBuffer*>(Surface::getOwner().get());
}
- mutable Mutex mLock;
- LayerBuffer* mOwner;
};
-
- friend class SurfaceFlinger;
- sp<SurfaceBuffer> getClientSurface() const;
-
+
mutable Mutex mLock;
sp<Source> mSource;
-
+ sp<Surface> mSurface;
bool mInvalidate;
bool mNeedsBlending;
- mutable wp<SurfaceBuffer> mClientSurface;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index 0c347cc..f613767 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
@@ -23,9 +21,9 @@
#include <utils/Errors.h>
#include <utils/Log.h>
+#include "BufferAllocator.h"
#include "LayerDim.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
namespace android {
@@ -33,27 +31,77 @@ namespace android {
const uint32_t LayerDim::typeInfo = LayerBaseClient::typeInfo | 0x10;
const char* const LayerDim::typeID = "LayerDim";
-sp<MemoryDealer> LayerDim::mDimmerDealer;
-LayerBitmap LayerDim::mDimmerBitmap;
+
+bool LayerDim::sUseTexture;
+GLuint LayerDim::sTexId;
+EGLImageKHR LayerDim::sImage;
+int32_t LayerDim::sWidth;
+int32_t LayerDim::sHeight;
// ---------------------------------------------------------------------------
LayerDim::LayerDim(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i)
- : LayerBaseClient(flinger, display, client, i)
+ const sp<Client>& client, int32_t i)
+ : LayerBaseClient(flinger, display, client, i)
{
}
void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h)
{
- // must only be called once.
- mDimmerDealer = flinger->getSurfaceHeapManager()
- ->createHeap(ISurfaceComposer::eHardware);
- if (mDimmerDealer != 0) {
- mDimmerBitmap.init(mDimmerDealer);
- mDimmerBitmap.setBits(w, h, 1, PIXEL_FORMAT_RGB_565);
- mDimmerBitmap.clear();
+ sTexId = -1;
+ sImage = EGL_NO_IMAGE_KHR;
+ sWidth = w;
+ sHeight = h;
+ sUseTexture = false;
+
+#ifdef DIM_WITH_TEXTURE
+
+#warning "using a texture to implement LayerDim"
+
+ /* On some h/w like msm7K, it is faster to use a texture because the
+ * software renderer will defer to copybit, for this to work we need to
+ * use an EGLImage texture so copybit can actually make use of it.
+ * This burns a full-screen worth of graphic memory.
+ */
+
+ const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
+ uint32_t flags = hw.getFlags();
+
+ if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) {
+ // TODO: api to pass the usage flags
+ sp<Buffer> buffer = new Buffer(w, h, PIXEL_FORMAT_RGB_565,
+ BufferAllocator::USAGE_SW_WRITE_OFTEN |
+ BufferAllocator::USAGE_HW_TEXTURE);
+
+ android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+ glGenTextures(1, &sTexId);
+ glBindTexture(GL_TEXTURE_2D, sTexId);
+
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ sImage = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)clientBuf, 0);
+ if (sImage == EGL_NO_IMAGE_KHR) {
+ LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError());
+ return;
+ }
+
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)sImage);
+ GLint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ eglDestroyImageKHR(dpy, sImage);
+ LOGE("glEGLImageTargetTexture2DOES() failed. err=0x%4x", error);
+ return;
+ }
+
+ // initialize the texture with zeros
+ GGLSurface t;
+ buffer->lock(&t, GRALLOC_USAGE_SW_WRITE_OFTEN);
+ memset(t.data, 0, t.stride * t.height * 2);
+ buffer->unlock();
+ sUseTexture = true;
}
+#endif
}
LayerDim::~LayerDim()
@@ -63,49 +111,56 @@ LayerDim::~LayerDim()
void LayerDim::onDraw(const Region& clip) const
{
const State& s(drawingState());
-
- Region::iterator iterator(clip);
- if (s.alpha>0 && iterator) {
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
+ if (s.alpha>0 && (it != end)) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
-
- status_t err = NO_ERROR;
- const int can_use_copybit = canUseCopybit();
- if (can_use_copybit) {
- // StopWatch watch("copybit");
- copybit_image_t dst;
- hw.getDisplaySurface(&dst);
- const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(mTransformedBounds);
-
- copybit_image_t src;
- mDimmerBitmap.getBitmapSurface(&src);
- const copybit_rect_t& srect(drect);
-
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
- region_iterator it(clip);
- err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ const GGLfixed alpha = (s.alpha << 16)/255;
+ const uint32_t fbHeight = hw.getHeight();
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4x(0, 0, 0, alpha);
+
+#ifdef DIM_WITH_TEXTURE
+ if (sUseTexture) {
+ glBindTexture(GL_TEXTURE_2D, sTexId);
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ const GLshort texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 1 },
+ { 1, 0 }
+ };
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_SHORT, 0, texCoords);
+ } else
+#endif
+ {
+ glDisable(GL_TEXTURE_2D);
}
- if (!can_use_copybit || err) {
- const GGLfixed alpha = (s.alpha << 16)/255;
- const uint32_t fbHeight = hw.getHeight();
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_DITHER);
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glColor4x(0, 0, 0, alpha);
- glVertexPointer(2, GL_FIXED, 0, mVertices);
- Rect r;
- while (iterator.iterate(&r)) {
- const GLint sy = fbHeight - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- }
+ GLshort w = sWidth;
+ GLshort h = sHeight;
+ const GLshort vertices[4][2] = {
+ { 0, 0 },
+ { 0, h },
+ { w, h },
+ { w, 0 }
+ };
+ glVertexPointer(2, GL_SHORT, 0, vertices);
+
+ while (it != end) {
+ const Rect& r = *it++;
+ const GLint sy = fbHeight - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
}
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerDim.h b/libs/surfaceflinger/LayerDim.h
index 3e37a47..33bd49d 100644
--- a/libs/surfaceflinger/LayerDim.h
+++ b/libs/surfaceflinger/LayerDim.h
@@ -20,6 +20,9 @@
#include <stdint.h>
#include <sys/types.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
#include "LayerBase.h"
#include "LayerBitmap.h"
@@ -29,6 +32,11 @@ namespace android {
class LayerDim : public LayerBaseClient
{
+ static bool sUseTexture;
+ static GLuint sTexId;
+ static EGLImageKHR sImage;
+ static int32_t sWidth;
+ static int32_t sHeight;
public:
static const uint32_t typeInfo;
static const char* const typeID;
@@ -36,7 +44,7 @@ public:
virtual uint32_t getTypeInfo() const { return typeInfo; }
LayerDim(SurfaceFlinger* flinger, DisplayID display,
- Client* client, int32_t i);
+ const sp<Client>& client, int32_t i);
virtual ~LayerDim();
virtual void onDraw(const Region& clip) const;
@@ -44,10 +52,6 @@ public:
virtual bool isSecure() const { return false; }
static void initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h);
-
-private:
- static sp<MemoryDealer> mDimmerDealer;
- static LayerBitmap mDimmerBitmap;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp
deleted file mode 100644
index 79e5328..0000000
--- a/libs/surfaceflinger/LayerOrientationAnim.cpp
+++ /dev/null
@@ -1,206 +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 "SurfaceFlinger"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/StopWatch.h>
-
-#include <core/SkBitmap.h>
-
-#include <ui/EGLDisplaySurface.h>
-
-#include "BlurFilter.h"
-#include "LayerBase.h"
-#include "LayerOrientationAnim.h"
-#include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
-#include "OrientationAnimation.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
-const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
-
-// ---------------------------------------------------------------------------
-
-// Animation...
-const float DURATION = ms2ns(200);
-const float BOUNCES_PER_SECOND = 0.5f;
-const float DIM_TARGET = 0.40f;
-#define INTERPOLATED_TIME(_t) (_t)
-
-// ---------------------------------------------------------------------------
-
-LayerOrientationAnim::LayerOrientationAnim(
- SurfaceFlinger* flinger, DisplayID display,
- OrientationAnimation* anim,
- const LayerBitmap& bitmapIn,
- const LayerBitmap& bitmapOut)
- : LayerOrientationAnimBase(flinger, display), mAnim(anim),
- mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
- mTextureName(-1), mTextureNameIn(-1)
-{
- // blur that texture.
- mOrientationCompleted = false;
- mNeedsBlending = false;
-}
-
-LayerOrientationAnim::~LayerOrientationAnim()
-{
- if (mTextureName != -1U) {
- LayerBase::deletedTextures.add(mTextureName);
- }
- if (mTextureNameIn != -1U) {
- LayerBase::deletedTextures.add(mTextureNameIn);
- }
-}
-
-bool LayerOrientationAnim::needsBlending() const
-{
- return mNeedsBlending;
-}
-
-Point LayerOrientationAnim::getPhysicalSize() const
-{
- const GraphicPlane& plane(graphicPlane(0));
- const DisplayHardware& hw(plane.displayHardware());
- return Point(hw.getWidth(), hw.getHeight());
-}
-
-void LayerOrientationAnim::validateVisibility(const Transform&)
-{
- const Layer::State& s(drawingState());
- const Transform tr(s.transform);
- const Point size(getPhysicalSize());
- uint32_t w = size.x;
- uint32_t h = size.y;
- mTransformedBounds = tr.makeBounds(w, h);
- mLeft = tr.tx();
- mTop = tr.ty();
- transparentRegionScreen.clear();
- mTransformed = true;
- mCanUseCopyBit = false;
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- if (copybit) {
- mCanUseCopyBit = true;
- }
-}
-
-void LayerOrientationAnim::onOrientationCompleted()
-{
- mAnim->onAnimationFinished();
-}
-
-void LayerOrientationAnim::onDraw(const Region& clip) const
-{
- float alphaIn = DIM_TARGET;
-
- // clear screen
- // TODO: with update on demand, we may be able
- // to not erase the screen at all during the animation
- if (!mOrientationCompleted) {
- glDisable(GL_BLEND);
- glDisable(GL_DITHER);
- glDisable(GL_SCISSOR_TEST);
- glClearColor(0,0,0,0);
- glClear(GL_COLOR_BUFFER_BIT);
- }
-
- copybit_image_t dst;
- const GraphicPlane& plane(graphicPlane(0));
- const DisplayHardware& hw(plane.displayHardware());
- hw.getDisplaySurface(&dst);
-
- copybit_image_t src;
- mBitmapIn.getBitmapSurface(&src);
-
- copybit_image_t srcOut;
- mBitmapOut.getBitmapSurface(&srcOut);
-
- const int w = dst.w;
- const int h = dst.h;
- const int xc = uint32_t(dst.w-w)/2;
- const int yc = uint32_t(dst.h-h)/2;
- const copybit_rect_t drect = { xc, yc, xc+w, yc+h };
- const copybit_rect_t srect = { 0, 0, src.w, src.h };
- const Region reg(Rect( drect.l, drect.t, drect.r, drect.b ));
-
- int err = NO_ERROR;
- const int can_use_copybit = canUseCopybit();
- if (can_use_copybit) {
- copybit_device_t* copybit = mFlinger->getBlitEngine();
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
-
- if (alphaIn > 0) {
- region_iterator it(reg);
- copybit->set_parameter(copybit, COPYBIT_BLUR, COPYBIT_ENABLE);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alphaIn*255));
- err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
- copybit->set_parameter(copybit, COPYBIT_BLUR, COPYBIT_DISABLE);
- }
- LOGE_IF(err != NO_ERROR, "copybit failed (%s)", strerror(err));
- }
- if (!can_use_copybit || err) {
- GGLSurface t;
- t.version = sizeof(GGLSurface);
- t.width = src.w;
- t.height = src.h;
- t.stride = src.w;
- t.vstride= src.h;
- t.format = src.format;
- t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
-
- Transform tr;
- tr.set(xc, yc);
-
- // FIXME: we should not access mVertices and mDrawingState like that,
- // but since we control the animation, we know it's going to work okay.
- // eventually we'd need a more formal way of doing things like this.
- LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
- tr.transform(self.mVertices[0], 0, 0);
- tr.transform(self.mVertices[1], 0, src.h);
- tr.transform(self.mVertices[2], src.w, src.h);
- tr.transform(self.mVertices[3], src.w, 0);
- if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
- // Too slow to do this in software
- self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
- }
-
- if (alphaIn > 0.0f) {
- t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
- if (UNLIKELY(mTextureNameIn == -1LU)) {
- mTextureNameIn = createTexture();
- GLuint w=0, h=0;
- const Region dirty(Rect(t.width, t.height));
- loadTexture(dirty, mTextureNameIn, t, w, h);
- }
- self.mDrawingState.alpha = int(alphaIn*255);
- drawWithOpenGL(reg, mTextureNameIn, t);
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/surfaceflinger/LayerOrientationAnim.h b/libs/surfaceflinger/LayerOrientationAnim.h
deleted file mode 100644
index 12b6f1c..0000000
--- a/libs/surfaceflinger/LayerOrientationAnim.h
+++ /dev/null
@@ -1,80 +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_LAYER_ORIENTATION_ANIM_H
-#define ANDROID_LAYER_ORIENTATION_ANIM_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/threads.h>
-#include <utils/Parcel.h>
-
-#include "LayerBase.h"
-#include "LayerBitmap.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-class OrientationAnimation;
-
-
-class LayerOrientationAnimBase : public LayerBase
-{
-public:
- LayerOrientationAnimBase(SurfaceFlinger* flinger, DisplayID display)
- : LayerBase(flinger, display) {
- }
- virtual void onOrientationCompleted() = 0;
-};
-
-// ---------------------------------------------------------------------------
-
-class LayerOrientationAnim : public LayerOrientationAnimBase
-{
-public:
- static const uint32_t typeInfo;
- static const char* const typeID;
- virtual char const* getTypeID() const { return typeID; }
- virtual uint32_t getTypeInfo() const { return typeInfo; }
-
- LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
- OrientationAnimation* anim,
- const LayerBitmap& bitmapIn,
- const LayerBitmap& bitmapOut);
- virtual ~LayerOrientationAnim();
-
- void onOrientationCompleted();
-
- virtual void onDraw(const Region& clip) const;
- virtual Point getPhysicalSize() const;
- virtual void validateVisibility(const Transform& globalTransform);
- virtual bool needsBlending() const;
- virtual bool isSecure() const { return false; }
-private:
- OrientationAnimation* mAnim;
- LayerBitmap mBitmapIn;
- LayerBitmap mBitmapOut;
- bool mOrientationCompleted;
- mutable GLuint mTextureName;
- mutable GLuint mTextureNameIn;
- mutable bool mNeedsBlending;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
diff --git a/libs/surfaceflinger/MessageQueue.cpp b/libs/surfaceflinger/MessageQueue.cpp
new file mode 100644
index 0000000..b43d801
--- /dev/null
+++ b/libs/surfaceflinger/MessageQueue.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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 <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+
+#include "MessageQueue.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+void MessageList::insert(const sp<MessageBase>& node)
+{
+ LIST::iterator cur(mList.begin());
+ LIST::iterator end(mList.end());
+ while (cur != end) {
+ if (*node < **cur) {
+ mList.insert(cur, node);
+ return;
+ }
+ ++cur;
+ }
+ mList.insert(++end, node);
+}
+
+void MessageList::remove(MessageList::LIST::iterator pos)
+{
+ mList.erase(pos);
+}
+
+// ---------------------------------------------------------------------------
+
+MessageQueue::MessageQueue()
+ : mInvalidate(false)
+{
+ mInvalidateMessage = new MessageBase(INVALIDATE);
+}
+
+MessageQueue::~MessageQueue()
+{
+}
+
+MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout)
+{
+ MessageList::value_type result;
+
+ bool again;
+ do {
+ const nsecs_t timeoutTime = systemTime() + timeout;
+ while (true) {
+ Mutex::Autolock _l(mLock);
+ nsecs_t now = systemTime();
+ nsecs_t nextEventTime = -1;
+
+ // invalidate messages are always handled first
+ if (mInvalidate) {
+ mInvalidate = false;
+ mInvalidateMessage->when = now;
+ result = mInvalidateMessage;
+ break;
+ }
+
+ LIST::iterator cur(mMessages.begin());
+ if (cur != mMessages.end()) {
+ result = *cur;
+ }
+
+ if (result != 0) {
+ if (result->when <= now) {
+ // there is a message to deliver
+ mMessages.remove(cur);
+ break;
+ }
+ if (timeout>=0 && timeoutTime < now) {
+ // we timed-out, return a NULL message
+ result = 0;
+ break;
+ }
+ nextEventTime = result->when;
+ result = 0;
+ }
+
+ if (timeout >= 0 && nextEventTime > 0) {
+ if (nextEventTime > timeoutTime) {
+ nextEventTime = timeoutTime;
+ }
+ }
+
+ if (nextEventTime >= 0) {
+ //LOGD("nextEventTime = %lld ms", nextEventTime);
+ if (nextEventTime > 0) {
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ const nsecs_t reltime = nextEventTime - systemTime();
+ if (reltime > 0) {
+ mCondition.waitRelative(mLock, reltime);
+ }
+ }
+ } else {
+ //LOGD("going to wait");
+ // we're about to wait, flush the binder command buffer
+ IPCThreadState::self()->flushCommands();
+ mCondition.wait(mLock);
+ }
+ }
+ // here we're not holding the lock anymore
+
+ if (result == 0)
+ break;
+
+ again = result->handler();
+ if (again) {
+ // the message has been processed. release our reference to it
+ // without holding the lock.
+ result = 0;
+ }
+
+ } while (again);
+
+ return result;
+}
+
+status_t MessageQueue::postMessage(
+ const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
+{
+ return queueMessage(message, relTime, flags);
+}
+
+status_t MessageQueue::invalidate() {
+ Mutex::Autolock _l(mLock);
+ mInvalidate = true;
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+status_t MessageQueue::queueMessage(
+ const MessageList::value_type& message, nsecs_t relTime, uint32_t flags)
+{
+ Mutex::Autolock _l(mLock);
+ message->when = systemTime() + relTime;
+ mMessages.insert(message);
+
+ //LOGD("MessageQueue::queueMessage time = %lld ms", message->when);
+ //dumpLocked(message);
+
+ mCondition.signal();
+ return NO_ERROR;
+}
+
+void MessageQueue::dump(const MessageList::value_type& message)
+{
+ Mutex::Autolock _l(mLock);
+ dumpLocked(message);
+}
+
+void MessageQueue::dumpLocked(const MessageList::value_type& message)
+{
+ LIST::const_iterator cur(mMessages.begin());
+ LIST::const_iterator end(mMessages.end());
+ int c = 0;
+ while (cur != end) {
+ const char tick = (*cur == message) ? '>' : ' ';
+ LOGD("%c %d: msg{.what=%08x, when=%lld}",
+ tick, c, (*cur)->what, (*cur)->when);
+ ++cur;
+ c++;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/MessageQueue.h b/libs/surfaceflinger/MessageQueue.h
new file mode 100644
index 0000000..dc8138d
--- /dev/null
+++ b/libs/surfaceflinger/MessageQueue.h
@@ -0,0 +1,127 @@
+/*
+ * 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_MESSAGE_QUEUE_H
+#define ANDROID_MESSAGE_QUEUE_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/List.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class MessageBase;
+
+class MessageList
+{
+ List< sp<MessageBase> > mList;
+ typedef List< sp<MessageBase> > LIST;
+public:
+ typedef sp<MessageBase> value_type;
+ inline LIST::iterator begin() { return mList.begin(); }
+ inline LIST::const_iterator begin() const { return mList.begin(); }
+ inline LIST::iterator end() { return mList.end(); }
+ inline LIST::const_iterator end() const { return mList.end(); }
+ inline bool isEmpty() const { return mList.empty(); }
+ void insert(const sp<MessageBase>& node);
+ void remove(LIST::iterator pos);
+};
+
+// ============================================================================
+
+class MessageBase :
+ public LightRefBase<MessageBase>
+{
+public:
+ nsecs_t when;
+ uint32_t what;
+ int32_t arg0;
+
+ MessageBase() : when(0), what(0), arg0(0) { }
+ MessageBase(uint32_t what, int32_t arg0=0)
+ : when(0), what(what), arg0(arg0) { }
+
+ // return true if message has a handler
+ virtual bool handler() { return false; }
+
+protected:
+ virtual ~MessageBase() { }
+
+private:
+ friend class LightRefBase<MessageBase>;
+};
+
+inline bool operator < (const MessageBase& lhs, const MessageBase& rhs) {
+ return lhs.when < rhs.when;
+}
+
+// ---------------------------------------------------------------------------
+
+class MessageQueue
+{
+ typedef List< sp<MessageBase> > LIST;
+public:
+
+ // this is a work-around the multichar constant warning. A macro would
+ // work too, but would pollute the namespace.
+ template <int a, int b, int c, int d>
+ struct WHAT {
+ static const uint32_t Value =
+ (uint32_t(a&0xff)<<24)|(uint32_t(b&0xff)<<16)|
+ (uint32_t(c&0xff)<<8)|uint32_t(d&0xff);
+ };
+
+ MessageQueue();
+ ~MessageQueue();
+
+ // pre-defined messages
+ enum {
+ INVALIDATE = WHAT<'_','p','d','t'>::Value
+ };
+
+ MessageList::value_type waitMessage(nsecs_t timeout = -1);
+
+ status_t postMessage(const MessageList::value_type& message,
+ nsecs_t reltime=0, uint32_t flags = 0);
+
+ status_t invalidate();
+
+ void dump(const MessageList::value_type& message);
+
+private:
+ status_t queueMessage(const MessageList::value_type& message,
+ nsecs_t reltime, uint32_t flags);
+ void dumpLocked(const MessageList::value_type& message);
+
+ Mutex mLock;
+ Condition mCondition;
+ MessageList mMessages;
+ bool mInvalidate;
+ MessageList::value_type mInvalidateMessage;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /* ANDROID_MESSAGE_QUEUE_H */
diff --git a/libs/surfaceflinger/OrientationAnimation.cpp b/libs/surfaceflinger/OrientationAnimation.cpp
deleted file mode 100644
index 12c0eef..0000000
--- a/libs/surfaceflinger/OrientationAnimation.cpp
+++ /dev/null
@@ -1,155 +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 "SurfaceFlinger"
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <limits.h>
-
-#include "LayerOrientationAnim.h"
-#include "OrientationAnimation.h"
-#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
-
-#include "DisplayHardware/DisplayHardware.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
- : mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
-{
- // allocate a memory-dealer for this the first time
- mTemporaryDealer = mFlinger->getSurfaceHeapManager()->createHeap(
- ISurfaceComposer::eHardware);
-}
-
-OrientationAnimation::~OrientationAnimation()
-{
-}
-
-void OrientationAnimation::onOrientationChanged(uint32_t type)
-{
- if (mState == DONE) {
- mType = type;
- if (!(type & ISurfaceComposer::eOrientationAnimationDisable)) {
- mState = PREPARE;
- }
- }
-}
-
-void OrientationAnimation::onAnimationFinished()
-{
- if (mState != DONE)
- mState = FINISH;
-}
-
-bool OrientationAnimation::run_impl()
-{
- bool skip_frame;
- switch (mState) {
- default:
- case DONE:
- skip_frame = done();
- break;
- case PREPARE:
- skip_frame = prepare();
- break;
- case PHASE1:
- skip_frame = phase1();
- break;
- case PHASE2:
- skip_frame = phase2();
- break;
- case FINISH:
- skip_frame = finished();
- break;
- }
- return skip_frame;
-}
-
-bool OrientationAnimation::done()
-{
- return done_impl();
-}
-
-bool OrientationAnimation::prepare()
-{
- mState = PHASE1;
-
- const GraphicPlane& plane(mFlinger->graphicPlane(0));
- const DisplayHardware& hw(plane.displayHardware());
- const uint32_t w = hw.getWidth();
- const uint32_t h = hw.getHeight();
-
- LayerBitmap bitmap;
- bitmap.init(mTemporaryDealer);
- bitmap.setBits(w, h, 1, hw.getFormat());
-
- LayerBitmap bitmapIn;
- bitmapIn.init(mTemporaryDealer);
- bitmapIn.setBits(w, h, 1, hw.getFormat());
-
- copybit_image_t front;
- bitmap.getBitmapSurface(&front);
- hw.copyFrontToImage(front);
-
- LayerOrientationAnimBase* l;
-
- l = new LayerOrientationAnim(
- mFlinger.get(), 0, this, bitmap, bitmapIn);
-
- l->initStates(w, h, 0);
- l->setLayer(INT_MAX-1);
- mFlinger->addLayer(l);
- mLayerOrientationAnim = l;
- return true;
-}
-
-bool OrientationAnimation::phase1()
-{
- if (mFlinger->isFrozen() == false) {
- // start phase 2
- mState = PHASE2;
- mLayerOrientationAnim->onOrientationCompleted();
- mLayerOrientationAnim->invalidate();
- return true;
-
- }
- //mLayerOrientationAnim->invalidate();
- return false;
-}
-
-bool OrientationAnimation::phase2()
-{
- // do the 2nd phase of the animation
- mLayerOrientationAnim->invalidate();
- return false;
-}
-
-bool OrientationAnimation::finished()
-{
- mState = DONE;
- mFlinger->removeLayer(mLayerOrientationAnim);
- mLayerOrientationAnim = NULL;
- return true;
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/surfaceflinger/OrientationAnimation.h b/libs/surfaceflinger/OrientationAnimation.h
deleted file mode 100644
index cafa38d..0000000
--- a/libs/surfaceflinger/OrientationAnimation.h
+++ /dev/null
@@ -1,85 +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_ORIENTATION_ANIMATION_H
-#define ANDROID_ORIENTATION_ANIMATION_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "SurfaceFlinger.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-class SurfaceFlinger;
-class MemoryDealer;
-class LayerOrientationAnim;
-
-class OrientationAnimation
-{
-public:
- OrientationAnimation(const sp<SurfaceFlinger>& flinger);
- virtual ~OrientationAnimation();
-
- void onOrientationChanged(uint32_t type);
- void onAnimationFinished();
- inline bool run() {
- if (LIKELY(mState == DONE))
- return done_impl();
- return run_impl();
- }
-
-private:
- enum {
- DONE = 0,
- PREPARE,
- PHASE1,
- PHASE2,
- FINISH
- };
-
- bool run_impl();
- inline bool done_impl() {
- if (mFlinger->isFrozen()) {
- // we are not allowed to draw, but pause a bit to make sure
- // apps don't end up using the whole CPU, if they depend on
- // surfaceflinger for synchronization.
- usleep(8333); // 8.3ms ~ 120fps
- return true;
- }
- return false;
- }
-
- bool done();
- bool prepare();
- bool phase1();
- bool phase2();
- bool finished();
-
- sp<SurfaceFlinger> mFlinger;
- sp<MemoryDealer> mTemporaryDealer;
- LayerOrientationAnimBase* mLayerOrientationAnim;
- int mState;
- uint32_t mType;
-};
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_ORIENTATION_ANIMATION_H
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 97dfecc..a72294a 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlinger"
-
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
@@ -23,6 +21,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,36 +29,30 @@
#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/MemoryHeapBase.h>
+
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/StopWatch.h>
#include <ui/PixelFormat.h>
#include <ui/DisplayInfo.h>
-#include <ui/EGLDisplaySurface.h>
#include <pixelflinger/pixelflinger.h>
#include <GLES/gl.h>
#include "clz.h"
-#include "CPUGauge.h"
+#include "BufferAllocator.h"
#include "Layer.h"
#include "LayerBlur.h"
#include "LayerBuffer.h"
#include "LayerDim.h"
#include "LayerBitmap.h"
-#include "LayerOrientationAnim.h"
-#include "OrientationAnimation.h"
#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
-#include "GPUHardware/GPUHardware.h"
-
/* ideally AID_GRAPHICS would be in a semi-public header
* or there would be a way to map a user/group name to its id
@@ -93,30 +86,30 @@ SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs)
}
ssize_t SurfaceFlinger::LayerVector::indexOf(
- LayerBase* key, size_t guess) const
+ const sp<LayerBase>& key, size_t guess) const
{
if (guess<size() && lookup.keyAt(guess) == key)
return guess;
const ssize_t i = lookup.indexOfKey(key);
if (i>=0) {
const size_t idx = lookup.valueAt(i);
- LOG_ASSERT(layers[idx]==key,
+ LOGE_IF(layers[idx]!=key,
"LayerVector[%p]: layers[%d]=%p, key=%p",
- this, int(idx), layers[idx], key);
+ this, int(idx), layers[idx].get(), key.get());
return idx;
}
return i;
}
ssize_t SurfaceFlinger::LayerVector::add(
- LayerBase* layer,
- Vector<LayerBase*>::compar_t cmp)
+ const sp<LayerBase>& layer,
+ Vector< sp<LayerBase> >::compar_t cmp)
{
size_t count = layers.size();
ssize_t l = 0;
ssize_t h = count-1;
ssize_t mid;
- LayerBase* const* a = layers.array();
+ sp<LayerBase> const* a = layers.array();
while (l <= h) {
mid = l + (h - l)/2;
const int c = cmp(a+mid, &layer);
@@ -139,14 +132,14 @@ ssize_t SurfaceFlinger::LayerVector::add(
return order;
}
-ssize_t SurfaceFlinger::LayerVector::remove(LayerBase* layer)
+ssize_t SurfaceFlinger::LayerVector::remove(const sp<LayerBase>& layer)
{
const ssize_t keyIndex = lookup.indexOfKey(layer);
if (keyIndex >= 0) {
const size_t index = lookup.valueAt(keyIndex);
- LOG_ASSERT(layers[index]==layer,
+ LOGE_IF(layers[index]!=layer,
"LayerVector[%p]: layers[%u]=%p, layer=%p",
- this, int(index), layers[index], layer);
+ this, int(index), layers[index].get(), layer.get());
layers.removeItemsAt(index);
lookup.removeItemsAt(keyIndex);
const size_t count = lookup.size();
@@ -161,8 +154,8 @@ ssize_t SurfaceFlinger::LayerVector::remove(LayerBase* layer)
}
ssize_t SurfaceFlinger::LayerVector::reorder(
- LayerBase* layer,
- Vector<LayerBase*>::compar_t cmp)
+ const sp<LayerBase>& layer,
+ Vector< sp<LayerBase> >::compar_t cmp)
{
// XXX: it's a little lame. but oh well...
ssize_t err = remove(layer);
@@ -180,7 +173,11 @@ SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(), Thread(false),
mTransactionFlags(0),
mTransactionCount(0),
+ mLayersRemoved(false),
mBootTime(systemTime()),
+ mHardwareTest("android.permission.HARDWARE_TEST"),
+ mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
+ mDump("android.permission.DUMP"),
mLastScheduledBroadcast(NULL),
mVisibleRegionsDirty(false),
mDeferReleaseConsole(false),
@@ -188,11 +185,11 @@ SurfaceFlinger::SurfaceFlinger()
mFreezeCount(0),
mFreezeDisplayTime(0),
mDebugRegion(0),
- mDebugCpu(0),
- mDebugFps(0),
mDebugBackground(0),
- mSyncObject(),
- mDeplayedTransactionPending(0),
+ mDebugInSwapBuffers(0),
+ mLastSwapBufferTime(0),
+ mDebugInTransaction(0),
+ mLastTransactionTime(0),
mConsoleSignals(0),
mSecureFrameBuffer(0)
{
@@ -207,28 +204,16 @@ void SurfaceFlinger::init()
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
- property_get("debug.sf.showcpu", value, "0");
- mDebugCpu = atoi(value);
property_get("debug.sf.showbackground", value, "0");
mDebugBackground = atoi(value);
- property_get("debug.sf.showfps", value, "0");
- mDebugFps = atoi(value);
LOGI_IF(mDebugRegion, "showupdates enabled");
- LOGI_IF(mDebugCpu, "showcpu enabled");
LOGI_IF(mDebugBackground, "showbackground enabled");
- LOGI_IF(mDebugFps, "showfps enabled");
}
SurfaceFlinger::~SurfaceFlinger()
{
glDeleteTextures(1, &mWormholeTexName);
- delete mOrientationAnimation;
-}
-
-copybit_device_t* SurfaceFlinger::getBlitEngine() const
-{
- return graphicPlane(0).displayHardware().getBlitEngine();
}
overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
@@ -236,29 +221,9 @@ overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const
return graphicPlane(0).displayHardware().getOverlayEngine();
}
-sp<IMemory> SurfaceFlinger::getCblk() const
+sp<IMemoryHeap> SurfaceFlinger::getCblk() const
{
- return mServerCblkMemory;
-}
-
-status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback,
- gpu_info_t* gpu)
-{
- if (mGPU == 0)
- return INVALID_OPERATION;
-
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- status_t err = mGPU->request(pid, callback, gpu);
- return err;
-}
-
-status_t SurfaceFlinger::revokeGPU()
-{
- if (mGPU == 0)
- return INVALID_OPERATION;
-
- return mGPU->friendlyRevoke();
+ return mServerHeap;
}
sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
@@ -266,33 +231,34 @@ sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()
Mutex::Autolock _l(mStateLock);
uint32_t token = mTokens.acquire();
- Client* client = new Client(token, this);
- if ((client == 0) || (client->ctrlblk == 0)) {
+ sp<Client> client = new Client(token, this);
+ if (client->ctrlblk == 0) {
mTokens.release(token);
return 0;
}
status_t err = mClientsMap.add(token, client);
if (err < 0) {
- delete client;
mTokens.release(token);
return 0;
}
sp<BClient> bclient =
- new BClient(this, token, client->controlBlockMemory());
+ new BClient(this, token, client->getControlBlockMemory());
return bclient;
}
void SurfaceFlinger::destroyConnection(ClientID cid)
{
Mutex::Autolock _l(mStateLock);
- Client* const client = mClientsMap.valueFor(cid);
- if (client) {
+ sp<Client> client = mClientsMap.valueFor(cid);
+ if (client != 0) {
// free all the layers this client owns
- const Vector<LayerBaseClient*>& layers = client->getLayers();
+ Vector< wp<LayerBaseClient> > layers(client->getLayers());
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- LayerBaseClient* const layer = layers[i];
- removeLayer_l(layer);
+ sp<LayerBaseClient> layer(layers[i].promote());
+ if (layer != 0) {
+ purgatorizeLayer_l(layer);
+ }
}
// the resources associated with this client will be freed
@@ -339,41 +305,15 @@ void SurfaceFlinger::onFirstRef()
mReadyToRunBarrier.wait();
}
-
static inline uint16_t pack565(int r, int g, int b) {
return (r<<11)|(g<<5)|b;
}
-// this is defined in libGLES_CM.so
-extern ISurfaceComposer* GLES_localSurfaceManager;
-
status_t SurfaceFlinger::readyToRun()
{
LOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- // create the shared control-block
- mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY);
- LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
-
- mServerCblkMemory = mServerHeap->allocate(4096);
- LOGE_IF(mServerCblkMemory==0, "can't create shared control block");
-
- mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer());
- LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
- new(mServerCblk) surface_flinger_cblk_t;
-
- // get a reference to the GPU if we have one
- mGPU = GPUFactory::getGPU();
-
- // create the surface Heap manager, which manages the heaps
- // (be it in RAM or VRAM) where surfaces are allocated
- // We give 8 MB per client.
- mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20);
-
-
- GLES_localSurfaceManager = static_cast<ISurfaceComposer*>(this);
-
// we only support one display currently
int dpy = 0;
@@ -384,6 +324,16 @@ status_t SurfaceFlinger::readyToRun()
plane.setDisplayHardware(hw);
}
+ // create the shared control-block
+ mServerHeap = new MemoryHeapBase(4096,
+ MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
+ LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
+
+ mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
+ LOGE_IF(mServerCblk==0, "can't get to shared control block's address");
+
+ new(mServerCblk) surface_flinger_cblk_t;
+
// initialize primary screen
// (other display should be initialized in the same manner, but
// asynchronously, as they could come and go. None of this is supported
@@ -450,13 +400,6 @@ status_t SurfaceFlinger::readyToRun()
* We're now ready to accept clients...
*/
- mOrientationAnimation = new OrientationAnimation(this);
-
- // start CPU gauge display
- if (mDebugCpu)
- mCpuGauge = new CPUGauge(this, ms2ns(500));
-
-
// start boot animation
property_set("ctl.start", "bootanim");
@@ -471,45 +414,53 @@ status_t SurfaceFlinger::readyToRun()
void SurfaceFlinger::waitForEvent()
{
- // wait for something to do
- if (UNLIKELY(isFrozen())) {
- // wait 5 seconds
- const nsecs_t freezeDisplayTimeout = ms2ns(5000);
- const nsecs_t now = systemTime();
- if (mFreezeDisplayTime == 0) {
- mFreezeDisplayTime = now;
+ while (true) {
+ nsecs_t timeout = -1;
+ if (UNLIKELY(isFrozen())) {
+ // wait 5 seconds
+ const nsecs_t freezeDisplayTimeout = ms2ns(5000);
+ const nsecs_t now = systemTime();
+ if (mFreezeDisplayTime == 0) {
+ mFreezeDisplayTime = now;
+ }
+ nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
+ timeout = waitTime>0 ? waitTime : 0;
}
- nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
- int err = (waitTime > 0) ? mSyncObject.wait(waitTime) : TIMED_OUT;
- if (err != NO_ERROR) {
+
+ MessageList::value_type msg = mEventQueue.waitMessage(timeout);
+ if (msg != 0) {
+ mFreezeDisplayTime = 0;
+ switch (msg->what) {
+ case MessageQueue::INVALIDATE:
+ // invalidate message, just return to the main loop
+ return;
+ }
+ } else {
+ // we timed out
if (isFrozen()) {
// we timed out and are still frozen
LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
mFreezeDisplay, mFreezeCount);
mFreezeCount = 0;
mFreezeDisplay = false;
+ return;
}
}
- } else {
- mFreezeDisplayTime = 0;
- mSyncObject.wait();
}
}
void SurfaceFlinger::signalEvent() {
- mSyncObject.open();
+ mEventQueue.invalidate();
}
void SurfaceFlinger::signal() const {
- mSyncObject.open();
+ // this is the IPC call
+ const_cast<SurfaceFlinger*>(this)->signalEvent();
}
void SurfaceFlinger::signalDelayedEvent(nsecs_t delay)
{
- if (android_atomic_or(1, &mDeplayedTransactionPending) == 0) {
- sp<DelayedTransaction> delayedEvent(new DelayedTransaction(this, delay));
- delayedEvent->run("DelayedeEvent", PRIORITY_URGENT_DISPLAY);
- }
+ mEventQueue.postMessage( new MessageBase(MessageQueue::INVALIDATE), delay);
}
// ----------------------------------------------------------------------------
@@ -548,11 +499,6 @@ bool SurfaceFlinger::threadLoop()
unlockClients();
executeScheduledBroadcasts();
- // sample the cpu gauge
- if (UNLIKELY(mDebugCpu)) {
- handleDebugCpu();
- }
-
postFramebuffer();
} else {
// pretend we did the post
@@ -565,28 +511,22 @@ bool SurfaceFlinger::threadLoop()
void SurfaceFlinger::postFramebuffer()
{
- const bool skip = mOrientationAnimation->run();
- if (UNLIKELY(skip)) {
+ if (isFrozen()) {
+ // we are not allowed to draw, but pause a bit to make sure
+ // apps don't end up using the whole CPU, if they depend on
+ // surfaceflinger for synchronization.
+ usleep(8333); // 8.3ms ~ 120fps
return;
}
if (!mInvalidRegion.isEmpty()) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
-
- if (UNLIKELY(mDebugFps)) {
- debugShowFPS();
- }
-
+ const nsecs_t now = systemTime();
+ mDebugInSwapBuffers = now;
hw.flip(mInvalidRegion);
-
+ mLastSwapBufferTime = systemTime() - now;
+ mDebugInSwapBuffers = 0;
mInvalidRegion.clear();
-
- if (Layer::deletedTextures.size()) {
- glDeleteTextures(
- Layer::deletedTextures.size(),
- Layer::deletedTextures.array());
- Layer::deletedTextures.clear();
- }
}
}
@@ -601,15 +541,13 @@ void SurfaceFlinger::handleConsoleEvents()
}
if (mDeferReleaseConsole && hw.canDraw()) {
- // We got the release signal before the aquire signal
+ // We got the release signal before the acquire signal
mDeferReleaseConsole = false;
- revokeGPU();
hw.releaseScreen();
}
if (what & eConsoleReleased) {
if (hw.canDraw()) {
- revokeGPU();
hw.releaseScreen();
} else {
mDeferReleaseConsole = true;
@@ -621,9 +559,29 @@ void SurfaceFlinger::handleConsoleEvents()
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
- Mutex::Autolock _l(mStateLock);
+ Vector< sp<LayerBase> > ditchedLayers;
+
+ { // scope for the lock
+ Mutex::Autolock _l(mStateLock);
+ const nsecs_t now = systemTime();
+ mDebugInTransaction = now;
+ handleTransactionLocked(transactionFlags, ditchedLayers);
+ mLastTransactionTime = systemTime() - now;
+ mDebugInTransaction = 0;
+ }
- const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ // do this without lock held
+ const size_t count = ditchedLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ //LOGD("ditching layer %p", ditchedLayers[i].get());
+ ditchedLayers[i]->ditch();
+ }
+}
+
+void SurfaceFlinger::handleTransactionLocked(
+ uint32_t transactionFlags, Vector< sp<LayerBase> >& ditchedLayers)
+{
+ const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
/*
@@ -634,7 +592,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
const bool layersNeedTransaction = transactionFlags & eTraversalNeeded;
if (layersNeedTransaction) {
for (size_t i=0 ; i<count ; i++) {
- LayerBase* const layer = currentLayers[i];
+ const sp<LayerBase>& layer = currentLayers[i];
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
@@ -681,7 +639,6 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
mVisibleRegionsDirty = true;
mDirtyRegion.set(hw.bounds());
mFreezeDisplayTime = 0;
- mOrientationAnimation->onOrientationChanged(type);
}
if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
@@ -689,22 +646,25 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
mFreezeDisplay = mCurrentState.freezeDisplay;
}
- // some layers might have been removed, so
- // we need to update the regions they're exposing.
- const SortedVector<LayerBase*>& removedLayers(mRemovedLayers);
- size_t c = removedLayers.size();
- if (c) {
+ if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
+ // layers have been added
mVisibleRegionsDirty = true;
- while (c--) {
- mDirtyRegionRemovedLayer.orSelf(
- removedLayers[c]->visibleRegionScreen);
- }
}
- const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
- if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
- // layers have been added
+ // some layers might have been removed, so
+ // we need to update the regions they're exposing.
+ if (mLayersRemoved) {
mVisibleRegionsDirty = true;
+ const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
+ const size_t count = previousLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(previousLayers[i]);
+ if (currentLayers.indexOf( layer ) < 0) {
+ // this layer is not visible anymore
+ ditchedLayers.add(layer);
+ mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
+ }
+ }
}
// get rid of all resources we don't need anymore
@@ -734,7 +694,7 @@ void SurfaceFlinger::computeVisibleRegions(
size_t i = currentLayers.size();
while (i--) {
- LayerBase* const layer = currentLayers[i];
+ const sp<LayerBase>& layer = currentLayers[i];
layer->validateVisibility(planeTransform);
// start with the whole surface at its current location
@@ -785,7 +745,7 @@ void SurfaceFlinger::computeVisibleRegions(
// accumulate to the screen dirty region
dirtyRegion.orSelf(dirty);
- // updade aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
+ // Update aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer
aboveOpaqueLayers.orSelf(opaqueRegion);
aboveCoveredLayers.orSelf(visibleRegion);
@@ -837,9 +797,9 @@ bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
{
bool recomputeVisibleRegions = false;
size_t count = currentLayers.size();
- LayerBase* const* layers = currentLayers.array();
+ sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
- LayerBase* const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
layer->lockPageFlip(recomputeVisibleRegions);
}
return recomputeVisibleRegions;
@@ -850,37 +810,58 @@ void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
const GraphicPlane& plane(graphicPlane(0));
const Transform& planeTransform(plane.transform());
size_t count = currentLayers.size();
- LayerBase* const* layers = currentLayers.array();
+ sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
- LayerBase* const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
layer->unlockPageFlip(planeTransform, mDirtyRegion);
}
}
+
void SurfaceFlinger::handleRepaint()
{
- // set the frame buffer
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
+ // compute the invalid region
+ mInvalidRegion.orSelf(mDirtyRegion);
+ if (mInvalidRegion.isEmpty()) {
+ // nothing to do
+ return;
+ }
if (UNLIKELY(mDebugRegion)) {
debugFlashRegions();
}
- // compute the invalid region
- mInvalidRegion.orSelf(mDirtyRegion);
+ // set the frame buffer
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
uint32_t flags = hw.getFlags();
- if (flags & DisplayHardware::BUFFER_PRESERVED) {
- // here we assume DisplayHardware::flip()'s implementation
- // performs the copy-back optimization.
+ if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
+ (flags & DisplayHardware::BUFFER_PRESERVED))
+ {
+ // we can redraw only what's dirty, but since SWAP_RECTANGLE only
+ // takes a rectangle, we must make sure to update that whole
+ // rectangle in that case
+ if (flags & DisplayHardware::SWAP_RECTANGLE) {
+ // FIXME: we really should be able to pass a region to
+ // SWAP_RECTANGLE so that we don't have to redraw all this.
+ mDirtyRegion.set(mInvalidRegion.bounds());
+ } else {
+ // in the BUFFER_PRESERVED case, obviously, we can update only
+ // what's needed and nothing more.
+ // NOTE: this is NOT a common case, as preserving the backbuffer
+ // is costly and usually involves copying the whole update back.
+ }
} else {
if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
- // we need to fully redraw the part that will be updated
+ // We need to redraw the rectangle that will be updated
+ // (pushed to the framebuffer).
+ // This is needed because UPDATE_ON_DEMAND only takes one
+ // rectangle instead of a region (see DisplayHardware::flip())
mDirtyRegion.set(mInvalidRegion.bounds());
} else {
- // we need to redraw everything
+ // we need to redraw everything (the whole screen)
mDirtyRegion.set(hw.bounds());
mInvalidRegion = mDirtyRegion;
}
@@ -903,9 +884,9 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty)
const SurfaceFlinger& flinger(*this);
const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
const size_t count = drawingLayers.size();
- LayerBase const* const* const layers = drawingLayers.array();
+ sp<LayerBase> const* const layers = drawingLayers.array();
for (size_t i=0 ; i<count ; ++i) {
- LayerBase const * const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
const Region& visibleRegion(layer->visibleRegionScreen);
if (!visibleRegion.isEmpty()) {
const Region clip(dirty.intersect(visibleRegion));
@@ -920,14 +901,14 @@ void SurfaceFlinger::unlockClients()
{
const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
const size_t count = drawingLayers.size();
- LayerBase* const* const layers = drawingLayers.array();
+ sp<LayerBase> const* const layers = drawingLayers.array();
for (size_t i=0 ; i<count ; ++i) {
- LayerBase* const layer = layers[i];
+ const sp<LayerBase>& layer = layers[i];
layer->finishPageFlip();
}
}
-void SurfaceFlinger::scheduleBroadcast(Client* client)
+void SurfaceFlinger::scheduleBroadcast(const sp<Client>& client)
{
if (mLastScheduledBroadcast != client) {
mLastScheduledBroadcast = client;
@@ -937,50 +918,56 @@ void SurfaceFlinger::scheduleBroadcast(Client* client)
void SurfaceFlinger::executeScheduledBroadcasts()
{
- SortedVector<Client*>& list = mScheduledBroadcasts;
+ SortedVector< wp<Client> >& list(mScheduledBroadcasts);
size_t count = list.size();
while (count--) {
- per_client_cblk_t* const cblk = list[count]->ctrlblk;
- if (cblk->lock.tryLock() == NO_ERROR) {
- cblk->cv.broadcast();
- list.removeAt(count);
- cblk->lock.unlock();
- } else {
- // schedule another round
- LOGW("executeScheduledBroadcasts() skipped, "
- "contention on the client. We'll try again later...");
- signalDelayedEvent(ms2ns(4));
+ sp<Client> client = list[count].promote();
+ if (client != 0) {
+ per_client_cblk_t* const cblk = client->ctrlblk;
+ if (cblk->lock.tryLock() == NO_ERROR) {
+ cblk->cv.broadcast();
+ list.removeAt(count);
+ cblk->lock.unlock();
+ } else {
+ // schedule another round
+ LOGW("executeScheduledBroadcasts() skipped, "
+ "contention on the client. We'll try again later...");
+ signalDelayedEvent(ms2ns(4));
+ }
}
}
mLastScheduledBroadcast = 0;
}
-void SurfaceFlinger::handleDebugCpu()
-{
- Mutex::Autolock _l(mDebugLock);
- if (mCpuGauge != 0)
- mCpuGauge->sample();
-}
-
void SurfaceFlinger::debugFlashRegions()
{
- if (UNLIKELY(!mDirtyRegion.isRect())) {
- // TODO: do this only if we don't have preserving
- // swapBuffer. If we don't have update-on-demand,
- // redraw everything.
- composeSurfaces(Region(mDirtyRegion.bounds()));
- }
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const uint32_t flags = hw.getFlags();
+ if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
+ (flags & DisplayHardware::BUFFER_PRESERVED))) {
+ const Region repaint((flags & DisplayHardware::UPDATE_ON_DEMAND) ?
+ mDirtyRegion.bounds() : hw.bounds());
+ composeSurfaces(repaint);
+ }
+
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_SCISSOR_TEST);
- glColor4x(0x10000, 0, 0x10000, 0x10000);
+ static int toggle = 0;
+ toggle = 1 - toggle;
+ if (toggle) {
+ glColor4x(0x10000, 0, 0x10000, 0x10000);
+ } else {
+ glColor4x(0x10000, 0x10000, 0, 0x10000);
+ }
- Rect r;
- Region::iterator iterator(mDirtyRegion);
- while (iterator.iterate(&r)) {
+ Region::const_iterator it = mDirtyRegion.begin();
+ Region::const_iterator const end = mDirtyRegion.end();
+ while (it != end) {
+ const Rect& r = *it++;
GLfloat vertices[][2] = {
{ r.left, r.top },
{ r.left, r.bottom },
@@ -990,10 +977,12 @@ void SurfaceFlinger::debugFlashRegions()
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
-
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- hw.flip(mDirtyRegion.merge(mInvalidRegion));
- mInvalidRegion.clear();
+
+ if (mInvalidRegion.isEmpty()) {
+ mDirtyRegion.dump("mDirtyRegion");
+ mInvalidRegion.dump("mInvalidRegion");
+ }
+ hw.flip(mInvalidRegion);
if (mDebugRegion > 1)
usleep(mDebugRegion * 1000);
@@ -1017,9 +1006,10 @@ void SurfaceFlinger::drawWormhole() const
if (LIKELY(!mDebugBackground)) {
glClearColorx(0,0,0,0);
- Rect r;
- Region::iterator iterator(region);
- while (iterator.iterate(&r)) {
+ Region::const_iterator it = region.begin();
+ Region::const_iterator const end = region.end();
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = height - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glClear(GL_COLOR_BUFFER_BIT);
@@ -1037,9 +1027,10 @@ void SurfaceFlinger::drawWormhole() const
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1);
- Rect r;
- Region::iterator iterator(region);
- while (iterator.iterate(&r)) {
+ Region::const_iterator it = region.begin();
+ Region::const_iterator const end = region.end();
+ while (it != end) {
+ const Rect& r = *it++;
const GLint sy = height - (r.top + r.height());
glScissor(r.left, sy, r.width(), r.height());
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -1065,7 +1056,7 @@ void SurfaceFlinger::debugShowFPS() const
// XXX: mFPS has the value we want
}
-status_t SurfaceFlinger::addLayer(LayerBase* layer)
+status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer)
{
Mutex::Autolock _l(mStateLock);
addLayer_l(layer);
@@ -1073,62 +1064,72 @@ status_t SurfaceFlinger::addLayer(LayerBase* layer)
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer(LayerBase* layer)
+status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
{
Mutex::Autolock _l(mStateLock);
- removeLayer_l(layer);
- setTransactionFlags(eTransactionNeeded);
- return NO_ERROR;
+ status_t err = purgatorizeLayer_l(layer);
+ if (err == NO_ERROR)
+ setTransactionFlags(eTransactionNeeded);
+ return err;
}
-status_t SurfaceFlinger::invalidateLayerVisibility(LayerBase* layer)
+status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer)
{
layer->forceVisibilityTransaction();
setTransactionFlags(eTraversalNeeded);
return NO_ERROR;
}
-status_t SurfaceFlinger::addLayer_l(LayerBase* layer)
+status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
{
ssize_t i = mCurrentState.layersSortedByZ.add(
layer, &LayerBase::compareCurrentStateZ);
- LayerBaseClient* lbc = LayerBase::dynamicCast<LayerBaseClient*>(layer);
- if (lbc) {
+ sp<LayerBaseClient> lbc = LayerBase::dynamicCast< LayerBaseClient* >(layer.get());
+ if (lbc != 0) {
mLayerMap.add(lbc->serverIndex(), lbc);
}
- mRemovedLayers.remove(layer);
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer_l(LayerBase* layerBase)
+status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
{
ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
if (index >= 0) {
- mRemovedLayers.add(layerBase);
- LayerBaseClient* layer = LayerBase::dynamicCast<LayerBaseClient*>(layerBase);
- if (layer) {
+ mLayersRemoved = true;
+ sp<LayerBaseClient> layer =
+ LayerBase::dynamicCast< LayerBaseClient* >(layerBase.get());
+ if (layer != 0) {
mLayerMap.removeItem(layer->serverIndex());
}
return NO_ERROR;
}
+ return status_t(index);
+}
+
+status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)
+{
+ // remove the layer from the main list (through a transaction).
+ ssize_t err = removeLayer_l(layerBase);
+
// it's possible that we don't find a layer, because it might
// have been destroyed already -- this is not technically an error
- // from the user because there is a race between destroySurface,
- // destroyclient and destroySurface-from-a-transaction.
- return (index == NAME_NOT_FOUND) ? status_t(NO_ERROR) : index;
+ // from the user because there is a race between BClient::destroySurface(),
+ // ~BClient() and ~ISurface().
+ return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err;
}
+
void SurfaceFlinger::free_resources_l()
{
// Destroy layers that were removed
- destroy_all_removed_layers_l();
-
+ mLayersRemoved = false;
+
// free resources associated with disconnected clients
- SortedVector<Client*>& scheduledBroadcasts(mScheduledBroadcasts);
- Vector<Client*>& disconnectedClients(mDisconnectedClients);
+ SortedVector< wp<Client> >& scheduledBroadcasts(mScheduledBroadcasts);
+ Vector< sp<Client> >& disconnectedClients(mDisconnectedClients);
const size_t count = disconnectedClients.size();
for (size_t i=0 ; i<count ; i++) {
- Client* client = disconnectedClients[i];
+ sp<Client> client = disconnectedClients[i];
// if this client is the scheduled broadcast list,
// remove it from there (and we don't need to signal it
// since it is dead).
@@ -1137,27 +1138,10 @@ void SurfaceFlinger::free_resources_l()
scheduledBroadcasts.removeItemsAt(index);
}
mTokens.release(client->cid);
- delete client;
}
disconnectedClients.clear();
}
-void SurfaceFlinger::destroy_all_removed_layers_l()
-{
- size_t c = mRemovedLayers.size();
- while (c--) {
- LayerBase* const removed_layer = mRemovedLayers[c];
-
- LOGE_IF(mCurrentState.layersSortedByZ.indexOf(removed_layer) >= 0,
- "layer %p removed but still in the current state list",
- removed_layer);
-
- delete removed_layer;
- }
- mRemovedLayers.clear();
-}
-
-
uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
{
return android_atomic_and(~flags, &mTransactionFlags) & flags;
@@ -1198,7 +1182,7 @@ status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags)
setTransactionFlags(eTransactionNeeded);
// flags is intended to communicate some sort of animation behavior
- // (for instance fadding)
+ // (for instance fading)
return NO_ERROR;
}
@@ -1212,7 +1196,7 @@ status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
setTransactionFlags(eTransactionNeeded);
// flags is intended to communicate some sort of animation behavior
- // (for instance fadding)
+ // (for instance fading)
return NO_ERROR;
}
@@ -1241,7 +1225,7 @@ sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
- LayerBaseClient* layer = 0;
+ sp<LayerBaseClient> layer;
sp<LayerBaseClient::Surface> surfaceHandle;
if (int32_t(w|h) < 0) {
@@ -1251,14 +1235,14 @@ sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
}
Mutex::Autolock _l(mStateLock);
- Client* const c = mClientsMap.valueFor(clientId);
- if (UNLIKELY(!c)) {
+ sp<Client> client = mClientsMap.valueFor(clientId);
+ if (UNLIKELY(client == 0)) {
LOGE("createSurface() failed, client not found (id=%d)", clientId);
return surfaceHandle;
}
//LOGD("createSurface for pid %d (%d x %d)", pid, w, h);
- int32_t id = c->generateId(pid);
+ int32_t id = client->generateId(pid);
if (uint32_t(id) >= NUM_LAYERS_MAX) {
LOGE("createSurface() failed, generateId = %d", id);
return surfaceHandle;
@@ -1267,32 +1251,40 @@ sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
switch (flags & eFXSurfaceMask) {
case eFXSurfaceNormal:
if (UNLIKELY(flags & ePushBuffers)) {
- layer = createPushBuffersSurfaceLocked(c, d, id, w, h, flags);
+ layer = createPushBuffersSurfaceLocked(client, d, id,
+ w, h, flags);
} else {
- layer = createNormalSurfaceLocked(c, d, id, w, h, format, flags);
+ layer = createNormalSurfaceLocked(client, d, id,
+ w, h, flags, format);
}
break;
case eFXSurfaceBlur:
- layer = createBlurSurfaceLocked(c, d, id, w, h, flags);
+ layer = createBlurSurfaceLocked(client, d, id, w, h, flags);
break;
case eFXSurfaceDim:
- layer = createDimSurfaceLocked(c, d, id, w, h, flags);
+ layer = createDimSurfaceLocked(client, d, id, w, h, flags);
break;
}
- if (layer) {
+ if (layer != 0) {
setTransactionFlags(eTransactionNeeded);
surfaceHandle = layer->getSurface();
- if (surfaceHandle != 0)
- surfaceHandle->getSurfaceData(params);
+ if (surfaceHandle != 0) {
+ params->token = surfaceHandle->getToken();
+ params->identity = surfaceHandle->getIdentity();
+ params->width = w;
+ params->height = h;
+ params->format = format;
+ }
}
return surfaceHandle;
}
-LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
- Client* client, DisplayID display,
- int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+sp<LayerBaseClient> SurfaceFlinger::createNormalSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags,
+ PixelFormat& format)
{
// initialize the surfaces
switch (format) { // TODO: take h/w into account
@@ -1305,57 +1297,99 @@ LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
break;
}
- Layer* layer = new Layer(this, display, client, id);
- status_t err = layer->setBuffers(client, w, h, format, flags);
+ sp<Layer> layer = new Layer(this, display, client, id);
+ status_t err = layer->setBuffers(w, h, format, flags);
if (LIKELY(err == NO_ERROR)) {
layer->initStates(w, h, flags);
addLayer_l(layer);
} else {
LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err));
- delete layer;
- return 0;
+ layer.clear();
}
return layer;
}
-LayerBaseClient* SurfaceFlinger::createBlurSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createBlurSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
- LayerBlur* layer = new LayerBlur(this, display, client, id);
+ sp<LayerBlur> layer = new LayerBlur(this, display, client, id);
layer->initStates(w, h, flags);
addLayer_l(layer);
return layer;
}
-LayerBaseClient* SurfaceFlinger::createDimSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createDimSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
- LayerDim* layer = new LayerDim(this, display, client, id);
+ sp<LayerDim> layer = new LayerDim(this, display, client, id);
layer->initStates(w, h, flags);
addLayer_l(layer);
return layer;
}
-LayerBaseClient* SurfaceFlinger::createPushBuffersSurfaceLocked(
- Client* client, DisplayID display,
+sp<LayerBaseClient> SurfaceFlinger::createPushBuffersSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags)
{
- LayerBuffer* layer = new LayerBuffer(this, display, client, id);
+ sp<LayerBuffer> layer = new LayerBuffer(this, display, client, id);
layer->initStates(w, h, flags);
addLayer_l(layer);
return layer;
}
-status_t SurfaceFlinger::destroySurface(SurfaceID index)
+status_t SurfaceFlinger::removeSurface(SurfaceID index)
{
+ /*
+ * called by the window manager, when a surface should be marked for
+ * destruction.
+ *
+ * The surface is removed from the current and drawing lists, but placed
+ * in the purgatory queue, so it's not destroyed right-away (we need
+ * to wait for all client's references to go away first).
+ */
+
Mutex::Autolock _l(mStateLock);
- LayerBaseClient* const layer = getLayerUser_l(index);
- status_t err = removeLayer_l(layer);
- if (err < 0)
- return err;
- setTransactionFlags(eTransactionNeeded);
+ sp<LayerBaseClient> layer = getLayerUser_l(index);
+ status_t err = purgatorizeLayer_l(layer);
+ if (err == NO_ERROR) {
+ setTransactionFlags(eTransactionNeeded);
+ }
+ return err;
+}
+
+status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
+{
+ // called by ~ISurface() when all references are gone
+
+ class MessageDestroySurface : public MessageBase {
+ SurfaceFlinger* flinger;
+ sp<LayerBaseClient> layer;
+ public:
+ MessageDestroySurface(
+ SurfaceFlinger* flinger, const sp<LayerBaseClient>& layer)
+ : flinger(flinger), layer(layer) { }
+ virtual bool handler() {
+ sp<LayerBaseClient> l(layer);
+ layer.clear(); // clear it outside of the lock;
+ Mutex::Autolock _l(flinger->mStateLock);
+ /*
+ * remove the layer from the current list -- chances are that it's
+ * not in the list anyway, because it should have been removed
+ * already upon request of the client (eg: window manager).
+ * However, a buggy client could have not done that.
+ * Since we know we don't have any more clients, we don't need
+ * to use the purgatory.
+ */
+ status_t err = flinger->removeLayer_l(l);
+ LOGE_IF(err<0 && err != NAME_NOT_FOUND,
+ "error removing layer=%p (%s)", l.get(), strerror(-err));
+ return true;
+ }
+ };
+
+ mEventQueue.postMessage( new MessageDestroySurface(this, layer) );
return NO_ERROR;
}
@@ -1369,18 +1403,9 @@ status_t SurfaceFlinger::setClientState(
cid <<= 16;
for (int i=0 ; i<count ; i++) {
const layer_state_t& s = states[i];
- LayerBaseClient* layer = getLayerUser_l(s.surface | cid);
- if (layer) {
+ sp<LayerBaseClient> layer(getLayerUser_l(s.surface | cid));
+ if (layer != 0) {
const uint32_t what = s.what;
- // check if it has been destroyed first
- if (what & eDestroyed) {
- if (removeLayer_l(layer) == NO_ERROR) {
- flags |= eTransactionNeeded;
- // we skip everything else... well, no, not really
- // we skip ONLY that transaction.
- continue;
- }
- }
if (what & ePositionChanged) {
if (layer->setPosition(s.x, s.y))
flags |= eTraversalNeeded;
@@ -1422,9 +1447,10 @@ status_t SurfaceFlinger::setClientState(
return NO_ERROR;
}
-LayerBaseClient* SurfaceFlinger::getLayerUser_l(SurfaceID s) const
+sp<LayerBaseClient> SurfaceFlinger::getLayerUser_l(SurfaceID s) const
{
- return mLayerMap.valueFor(s);
+ sp<LayerBaseClient> layer = mLayerMap.valueFor(s);
+ return layer;
}
void SurfaceFlinger::screenReleased(int dpy)
@@ -1446,20 +1472,40 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
const size_t SIZE = 1024;
char buffer[SIZE];
String8 result;
- if (checkCallingPermission(
- String16("android.permission.DUMP")) == false)
- { // not allowed
+ if (!mDump.checkCalling()) {
snprintf(buffer, SIZE, "Permission Denial: "
"can't dump SurfaceFlinger from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
result.append(buffer);
} else {
- Mutex::Autolock _l(mStateLock);
+
+ // figure out if we're stuck somewhere
+ const nsecs_t now = systemTime();
+ const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
+ const nsecs_t inTransaction(mDebugInTransaction);
+ nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
+ nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
+
+ // Try to get the main lock, but don't insist if we can't
+ // (this would indicate SF is stuck, but we want to be able to
+ // print something in dumpsys).
+ int retry = 3;
+ while (mStateLock.tryLock()<0 && --retry>=0) {
+ usleep(1000000);
+ }
+ const bool locked(retry >= 0);
+ if (!locked) {
+ snprintf(buffer, SIZE,
+ "SurfaceFlinger appears to be unresponsive, "
+ "dumping anyways (no locks held)\n");
+ result.append(buffer);
+ }
+
size_t s = mClientsMap.size();
char name[64];
for (size_t i=0 ; i<s ; i++) {
- Client* client = mClientsMap.valueAt(i);
+ sp<Client> client = mClientsMap.valueAt(i);
sprintf(name, " Client (id=0x%08x)", client->cid);
client->dump(name);
}
@@ -1467,7 +1513,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
/*** LayerBase ***/
- LayerBase const * const layer = currentLayers[i];
+ const sp<LayerBase>& layer = currentLayers[i];
const Layer::State& s = layer->drawingState();
snprintf(buffer, SIZE,
"+ %s %p\n"
@@ -1475,7 +1521,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
"z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
"needsBlending=%1d, invalidate=%1d, "
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
- layer->getTypeID(), layer,
+ layer->getTypeID(), layer.get(),
s.z, layer->tx(), layer->ty(), s.w, s.h,
layer->needsBlending(), layer->contentDirty,
s.alpha, s.flags,
@@ -1484,30 +1530,33 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
result.append(buffer);
buffer[0] = 0;
/*** LayerBaseClient ***/
- LayerBaseClient* const lbc =
- LayerBase::dynamicCast<LayerBaseClient*>((LayerBase*)layer);
- if (lbc) {
+ sp<LayerBaseClient> lbc =
+ LayerBase::dynamicCast< LayerBaseClient* >(layer.get());
+ if (lbc != 0) {
+ sp<Client> client(lbc->client.promote());
snprintf(buffer, SIZE,
" "
"id=0x%08x, client=0x%08x, identity=%u\n",
- lbc->clientIndex(), lbc->client ? lbc->client->cid : 0,
+ lbc->clientIndex(), client.get() ? client->cid : 0,
lbc->getIdentity());
}
result.append(buffer);
buffer[0] = 0;
/*** Layer ***/
- Layer* const l = LayerBase::dynamicCast<Layer*>((LayerBase*)layer);
- if (l) {
+ sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
+ if (l != 0) {
const LayerBitmap& buf0(l->getBuffer(0));
const LayerBitmap& buf1(l->getBuffer(1));
snprintf(buffer, SIZE,
" "
- "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u], mTextureName=%d,"
+ "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
" freezeLock=%p, swapState=0x%08x\n",
l->pixelFormat(),
- buf0.width(), buf0.height(), buf0.stride(),
- buf1.width(), buf1.height(), buf1.stride(),
- l->getTextureName(), l->getFreezeLock().get(),
+ buf0.getWidth(), buf0.getHeight(),
+ buf0.getBuffer()->getStride(),
+ buf1.getWidth(), buf1.getHeight(),
+ buf1.getBuffer()->getStride(),
+ l->getFreezeLock().get(),
l->lcblk->swapState);
}
result.append(buffer);
@@ -1523,19 +1572,28 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
mFreezeDisplay?"yes":"no", mFreezeCount,
mCurrentState.orientation, hw.canDraw());
result.append(buffer);
-
- sp<AllocatorInterface> allocator;
- if (mGPU != 0) {
- snprintf(buffer, SIZE, " GPU owner: %d\n", mGPU->getOwner());
+ snprintf(buffer, SIZE,
+ " last eglSwapBuffers() time: %f us\n"
+ " last transaction time : %f us\n",
+ mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0);
+ result.append(buffer);
+ if (inSwapBuffersDuration || !locked) {
+ snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n",
+ inSwapBuffersDuration/1000.0);
+ result.append(buffer);
+ }
+ if (inTransactionDuration || !locked) {
+ snprintf(buffer, SIZE, " transaction time: %f us\n",
+ inTransactionDuration/1000.0);
result.append(buffer);
- allocator = mGPU->getAllocator();
- if (allocator != 0) {
- allocator->dump(result, "GPU Allocator");
- }
}
- allocator = mSurfaceHeapManager->getAllocator(NATIVE_MEMORY_TYPE_PMEM);
- if (allocator != 0) {
- allocator->dump(result, "PMEM Allocator");
+ snprintf(buffer, SIZE, " client count: %d\n", mClientsMap.size());
+ result.append(buffer);
+ const BufferAllocator& alloc(BufferAllocator::get());
+ alloc.dump(result);
+
+ if (locked) {
+ mStateLock.unlock();
}
}
write(fd, result.string(), result.size());
@@ -1553,57 +1611,34 @@ status_t SurfaceFlinger::onTransact(
case FREEZE_DISPLAY:
case UNFREEZE_DISPLAY:
case BOOT_FINISHED:
- case REVOKE_GPU:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
- const int self_pid = getpid();
- if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS)) {
- // we're called from a different process, do the real check
- if (!checkCallingPermission(
- String16("android.permission.ACCESS_SURFACE_FLINGER")))
- {
- LOGE("Permission Denial: "
- "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
- return PERMISSION_DENIED;
- }
+ if ((uid != AID_GRAPHICS) && !mAccessSurfaceFlinger.check(pid, uid)) {
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
}
}
}
-
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
- // HARDWARE_TEST stuff...
- if (UNLIKELY(checkCallingPermission(
- String16("android.permission.HARDWARE_TEST")) == false))
- { // not allowed
- LOGE("Permission Denial: pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ if (UNLIKELY(!mHardwareTest.checkCalling())) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
}
int n;
switch (code) {
- case 1000: // SHOW_CPU
- n = data.readInt32();
- mDebugCpu = n ? 1 : 0;
- if (mDebugCpu) {
- if (mCpuGauge == 0) {
- mCpuGauge = new CPUGauge(this, ms2ns(500));
- }
- } else {
- if (mCpuGauge != 0) {
- mCpuGauge->requestExitAndWait();
- Mutex::Autolock _l(mDebugLock);
- mCpuGauge.clear();
- }
- }
+ case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
return NO_ERROR;
- case 1001: // SHOW_FPS
- n = data.readInt32();
- mDebugFps = n ? 1 : 0;
+ case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
return NO_ERROR;
case 1002: // SHOW_UPDATES
n = data.readInt32();
@@ -1620,21 +1655,11 @@ status_t SurfaceFlinger::onTransact(
signalEvent();
}
return NO_ERROR;
- case 1005: // ask GPU revoke
- if (mGPU != 0) {
- mGPU->friendlyRevoke();
- }
- return NO_ERROR;
- case 1006: // revoke GPU
- if (mGPU != 0) {
- mGPU->unconditionalRevoke();
- }
- return NO_ERROR;
case 1007: // set mFreezeCount
mFreezeCount = data.readInt32();
return NO_ERROR;
case 1010: // interrogate.
- reply->writeInt32(mDebugCpu);
+ reply->writeInt32(0);
reply->writeInt32(0);
reply->writeInt32(mDebugRegion);
reply->writeInt32(mDebugBackground);
@@ -1658,16 +1683,15 @@ status_t SurfaceFlinger::onTransact(
Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)
: ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)
{
- mSharedHeapAllocator = getSurfaceHeapManager()->createHeap();
const int pgsize = getpagesize();
- const int cblksize=((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
- mCblkHeap = new MemoryDealer(cblksize);
- mCblkMemory = mCblkHeap->allocate(cblksize);
- if (mCblkMemory != 0) {
- ctrlblk = static_cast<per_client_cblk_t *>(mCblkMemory->pointer());
- if (ctrlblk) { // construct the shared structure in-place.
- new(ctrlblk) per_client_cblk_t;
- }
+ const int cblksize = ((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1));
+
+ mCblkHeap = new MemoryHeapBase(cblksize, 0,
+ "SurfaceFlinger Client control-block");
+
+ ctrlblk = static_cast<per_client_cblk_t *>(mCblkHeap->getBase());
+ if (ctrlblk) { // construct the shared structure in-place.
+ new(ctrlblk) per_client_cblk_t;
}
}
@@ -1678,10 +1702,6 @@ Client::~Client() {
}
}
-const sp<SurfaceHeapManager>& Client::getSurfaceHeapManager() const {
- return mFlinger->getSurfaceHeapManager();
-}
-
int32_t Client::generateId(int pid)
{
const uint32_t i = clz( ~mBitmap );
@@ -1693,13 +1713,15 @@ int32_t Client::generateId(int pid)
mBitmap |= 1<<(31-i);
return i;
}
-status_t Client::bindLayer(LayerBaseClient* layer, int32_t id)
+
+status_t Client::bindLayer(const sp<LayerBaseClient>& layer, int32_t id)
{
ssize_t idx = mInUse.indexOf(id);
if (idx < 0)
return NAME_NOT_FOUND;
return mLayers.insertAt(layer, idx);
}
+
void Client::free(int32_t id)
{
ssize_t idx = mInUse.remove(uint8_t(id));
@@ -1709,27 +1731,18 @@ void Client::free(int32_t id)
}
}
-sp<MemoryDealer> Client::createAllocator(uint32_t flags)
-{
- sp<MemoryDealer> allocator;
- allocator = getSurfaceHeapManager()->createHeap(
- flags, getClientPid(), mSharedHeapAllocator);
- return allocator;
-}
-
bool Client::isValid(int32_t i) const {
return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i)));
}
-const uint8_t* Client::inUseArray() const {
- return mInUse.array();
-}
-size_t Client::numActiveLayers() const {
- return mInUse.size();
-}
-LayerBaseClient* Client::getLayerUser(int32_t i) const {
+
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
+ sp<LayerBaseClient> lbc;
ssize_t idx = mInUse.indexOf(uint8_t(i));
- if (idx<0) return 0;
- return mLayers[idx];
+ if (idx >= 0) {
+ lbc = mLayers[idx].promote();
+ LOGE_IF(lbc==0, "getLayerUser(i=%d), idx=%d is dead", int(i), int(idx));
+ }
+ return lbc;
}
void Client::dump(const char* what)
@@ -1741,7 +1754,7 @@ void Client::dump(const char* what)
#pragma mark -
#endif
-BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemory>& cblk)
+BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemoryHeap>& cblk)
: mId(cid), mFlinger(flinger), mCblk(cblk)
{
}
@@ -1751,8 +1764,8 @@ BClient::~BClient() {
mFlinger->destroyConnection(mId);
}
-void BClient::getControlBlocks(sp<IMemory>* ctrl) const {
- *ctrl = mCblk;
+sp<IMemoryHeap> BClient::getControlBlock() const {
+ return mCblk;
}
sp<ISurface> BClient::createSurface(
@@ -1766,7 +1779,7 @@ sp<ISurface> BClient::createSurface(
status_t BClient::destroySurface(SurfaceID sid)
{
sid |= (mId << 16); // add the client-part to id
- return mFlinger->destroySurface(sid);
+ return mFlinger->removeSurface(sid);
}
status_t BClient::setState(int32_t count, const layer_state_t* states)
@@ -1866,6 +1879,10 @@ const Transform& GraphicPlane::transform() const {
return mGlobalTransform;
}
+EGLDisplay GraphicPlane::getEGLDisplay() const {
+ return mHw->getEGLDisplay();
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index 0d63e1d..69e2f2e 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -25,7 +25,10 @@
#include <utils/threads.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
-#include <utils/MemoryDealer.h>
+#include <utils/RefBase.h>
+
+#include <binder/IMemory.h>
+#include <binder/Permission.h>
#include <ui/PixelFormat.h>
#include <ui/ISurfaceComposer.h>
@@ -33,13 +36,13 @@
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
-#include <private/ui/SurfaceFlingerSynchro.h>
#include "Barrier.h"
-#include "CPUGauge.h"
#include "Layer.h"
#include "Tokenizer.h"
+#include "MessageQueue.h"
+
struct copybit_device_t;
struct overlay_device_t;
@@ -51,13 +54,8 @@ class Client;
class BClient;
class DisplayHardware;
class FreezeLock;
-class GPUHardwareInterface;
-class IGPUCallback;
class Layer;
class LayerBuffer;
-class LayerOrientationAnim;
-class OrientationAnimation;
-class SurfaceHeapManager;
typedef int32_t ClientID;
@@ -66,7 +64,7 @@ typedef int32_t ClientID;
// ---------------------------------------------------------------------------
-class Client
+class Client : public RefBase
{
public:
Client(ClientID cid, const sp<SurfaceFlinger>& flinger);
@@ -74,17 +72,19 @@ public:
int32_t generateId(int pid);
void free(int32_t id);
- status_t bindLayer(LayerBaseClient* layer, int32_t id);
- sp<MemoryDealer> createAllocator(uint32_t memory_type);
+ status_t bindLayer(const sp<LayerBaseClient>& layer, int32_t id);
inline bool isValid(int32_t i) const;
- inline const uint8_t* inUseArray() const;
- inline size_t numActiveLayers() const;
- LayerBaseClient* getLayerUser(int32_t i) const;
- const Vector<LayerBaseClient*>& getLayers() const { return mLayers; }
- const sp<IMemory>& controlBlockMemory() const { return mCblkMemory; }
+ sp<LayerBaseClient> getLayerUser(int32_t i) const;
void dump(const char* what);
- const sp<SurfaceHeapManager>& getSurfaceHeapManager() const;
+
+ const Vector< wp<LayerBaseClient> >& getLayers() const {
+ return mLayers;
+ }
+
+ const sp<IMemoryHeap>& getControlBlockMemory() const {
+ return mCblkHeap;
+ }
// pointer to this client's control block
per_client_cblk_t* ctrlblk;
@@ -92,17 +92,14 @@ public:
private:
- int getClientPid() const { return mPid; }
+ int getClientPid() const { return mPid; }
- int mPid;
- uint32_t mBitmap;
- SortedVector<uint8_t> mInUse;
- Vector<LayerBaseClient*> mLayers;
- sp<MemoryDealer> mCblkHeap;
- sp<SurfaceFlinger> mFlinger;
- sp<MemoryDealer> mSharedHeapAllocator;
- sp<MemoryDealer> mPMemAllocator;
- sp<IMemory> mCblkMemory;
+ int mPid;
+ uint32_t mBitmap;
+ SortedVector<uint8_t> mInUse;
+ Vector< wp<LayerBaseClient> > mLayers;
+ sp<IMemoryHeap> mCblkHeap;
+ sp<SurfaceFlinger> mFlinger;
};
// ---------------------------------------------------------------------------
@@ -125,6 +122,8 @@ public:
const DisplayHardware& displayHardware() const;
const Transform& transform() const;
+ EGLDisplay getEGLDisplay() const;
+
private:
GraphicPlane(const GraphicPlane&);
GraphicPlane operator = (const GraphicPlane&);
@@ -160,7 +159,7 @@ public:
// ISurfaceComposer interface
virtual sp<ISurfaceFlingerClient> createConnection();
- virtual sp<IMemory> getCblk() const;
+ virtual sp<IMemoryHeap> getCblk() const;
virtual void bootFinished();
virtual void openGlobalTransaction();
virtual void closeGlobalTransaction();
@@ -168,56 +167,52 @@ public:
virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
virtual void signal() const;
- virtual status_t requestGPU(const sp<IGPUCallback>& callback,
- gpu_info_t* gpu);
- virtual status_t revokeGPU();
void screenReleased(DisplayID dpy);
void screenAcquired(DisplayID dpy);
- const sp<SurfaceHeapManager>& getSurfaceHeapManager() const {
- return mSurfaceHeapManager;
- }
-
- const sp<GPUHardwareInterface>& getGPU() const {
- return mGPU;
- }
-
- copybit_device_t* getBlitEngine() const;
overlay_control_device_t* getOverlayEngine() const;
- status_t removeLayer(LayerBase* layer);
- status_t addLayer(LayerBase* layer);
- status_t invalidateLayerVisibility(LayerBase* layer);
+ status_t removeLayer(const sp<LayerBase>& layer);
+ status_t addLayer(const sp<LayerBase>& layer);
+ status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
private:
friend class BClient;
friend class LayerBase;
friend class LayerBuffer;
friend class LayerBaseClient;
+ friend class LayerBaseClient::Surface;
friend class Layer;
friend class LayerBlur;
+ friend class LayerDim;
sp<ISurface> createSurface(ClientID client, int pid,
ISurfaceFlingerClient::surface_data_t* params,
DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags);
- LayerBaseClient* createNormalSurfaceLocked(Client* client, DisplayID display,
- int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+ sp<LayerBaseClient> createNormalSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
+ int32_t id, uint32_t w, uint32_t h, uint32_t flags,
+ PixelFormat& format);
- LayerBaseClient* createBlurSurfaceLocked(Client* client, DisplayID display,
+ sp<LayerBaseClient> createBlurSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags);
- LayerBaseClient* createDimSurfaceLocked(Client* client, DisplayID display,
+ sp<LayerBaseClient> createDimSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags);
- LayerBaseClient* createPushBuffersSurfaceLocked(Client* client, DisplayID display,
+ sp<LayerBaseClient> createPushBuffersSurfaceLocked(
+ const sp<Client>& client, DisplayID display,
int32_t id, uint32_t w, uint32_t h, uint32_t flags);
- status_t destroySurface(SurfaceID surface_id);
- status_t setClientState(ClientID cid, int32_t count, const layer_state_t* states);
+ status_t removeSurface(SurfaceID surface_id);
+ status_t destroySurface(const sp<LayerBaseClient>& layer);
+ status_t setClientState(ClientID cid, int32_t count, const layer_state_t* states);
class LayerVector {
@@ -225,15 +220,15 @@ private:
inline LayerVector() { }
LayerVector(const LayerVector&);
inline size_t size() const { return layers.size(); }
- inline LayerBase*const* array() const { return layers.array(); }
- ssize_t add(LayerBase*, Vector<LayerBase*>::compar_t);
- ssize_t remove(LayerBase*);
- ssize_t reorder(LayerBase*, Vector<LayerBase*>::compar_t);
- ssize_t indexOf(LayerBase* key, size_t guess=0) const;
- inline LayerBase* operator [] (size_t i) const { return layers[i]; }
+ inline sp<LayerBase> const* array() const { return layers.array(); }
+ ssize_t add(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
+ ssize_t remove(const sp<LayerBase>&);
+ ssize_t reorder(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
+ ssize_t indexOf(const sp<LayerBase>& key, size_t guess=0) const;
+ inline sp<LayerBase> operator [] (size_t i) const { return layers[i]; }
private:
- KeyedVector<LayerBase*, size_t> lookup;
- Vector<LayerBase*> layers;
+ KeyedVector< sp<LayerBase> , size_t> lookup;
+ Vector< sp<LayerBase> > layers;
};
struct State {
@@ -247,25 +242,6 @@ private:
uint8_t freezeDisplay;
};
- class DelayedTransaction : public Thread
- {
- friend class SurfaceFlinger;
- sp<SurfaceFlinger> mFlinger;
- nsecs_t mDelay;
- public:
- DelayedTransaction(const sp<SurfaceFlinger>& flinger, nsecs_t delay)
- : Thread(false), mFlinger(flinger), mDelay(delay) {
- }
- virtual bool threadLoop() {
- usleep(mDelay / 1000);
- if (android_atomic_and(~1,
- &mFlinger->mDeplayedTransactionPending) == 1) {
- mFlinger->signalEvent();
- }
- return false;
- }
- };
-
virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
@@ -279,6 +255,9 @@ private:
void handleConsoleEvents();
void handleTransaction(uint32_t transactionFlags);
+ void handleTransactionLocked(
+ uint32_t transactionFlags,
+ Vector< sp<LayerBase> >& ditchedLayers);
void computeVisibleRegions(
LayerVector& currentLayers,
@@ -289,8 +268,7 @@ private:
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
void handleRepaint();
- void handleDebugCpu();
- void scheduleBroadcast(Client* client);
+ void scheduleBroadcast(const sp<Client>& client);
void executeScheduledBroadcasts();
void postFramebuffer();
void composeSurfaces(const Region& dirty);
@@ -298,10 +276,10 @@ private:
void destroyConnection(ClientID cid);
- LayerBaseClient* getLayerUser_l(SurfaceID index) const;
- status_t addLayer_l(LayerBase* layer);
- status_t removeLayer_l(LayerBase* layer);
- void destroy_all_removed_layers_l();
+ sp<LayerBaseClient> getLayerUser_l(SurfaceID index) const;
+ status_t addLayer_l(const sp<LayerBase>& layer);
+ status_t removeLayer_l(const sp<LayerBase>& layer);
+ status_t purgatorizeLayer_l(const sp<LayerBase>& layer);
void free_resources_l();
uint32_t getTransactionFlags(uint32_t flags);
@@ -323,6 +301,11 @@ private:
void debugShowFPS() const;
void drawWormhole() const;
+
+ mutable MessageQueue mEventQueue;
+
+
+
// access must be protected by mStateLock
mutable Mutex mStateLock;
State mCurrentState;
@@ -330,23 +313,23 @@ private:
volatile int32_t mTransactionFlags;
volatile int32_t mTransactionCount;
Condition mTransactionCV;
-
+
// protected by mStateLock (but we could use another lock)
Tokenizer mTokens;
- DefaultKeyedVector<ClientID, Client*> mClientsMap;
- DefaultKeyedVector<SurfaceID, LayerBaseClient*> mLayerMap;
+ DefaultKeyedVector<ClientID, sp<Client> > mClientsMap;
+ DefaultKeyedVector<SurfaceID, sp<LayerBaseClient> > mLayerMap;
GraphicPlane mGraphicPlanes[1];
- SortedVector<LayerBase*> mRemovedLayers;
- Vector<Client*> mDisconnectedClients;
+ bool mLayersRemoved;
+ Vector< sp<Client> > mDisconnectedClients;
// constant members (no synchronization needed for access)
- sp<MemoryDealer> mServerHeap;
- sp<IMemory> mServerCblkMemory;
+ sp<IMemoryHeap> mServerHeap;
surface_flinger_cblk_t* mServerCblk;
- sp<SurfaceHeapManager> mSurfaceHeapManager;
- sp<GPUHardwareInterface> mGPU;
GLuint mWormholeTexName;
nsecs_t mBootTime;
+ Permission mHardwareTest;
+ Permission mAccessSurfaceFlinger;
+ Permission mDump;
// Can only accessed from the main thread, these members
// don't need synchronization
@@ -354,30 +337,24 @@ private:
Region mDirtyRegionRemovedLayer;
Region mInvalidRegion;
Region mWormholeRegion;
- Client* mLastScheduledBroadcast;
- SortedVector<Client*> mScheduledBroadcasts;
+ wp<Client> mLastScheduledBroadcast;
+ SortedVector< wp<Client> > mScheduledBroadcasts;
bool mVisibleRegionsDirty;
bool mDeferReleaseConsole;
bool mFreezeDisplay;
int32_t mFreezeCount;
nsecs_t mFreezeDisplayTime;
- friend class OrientationAnimation;
- OrientationAnimation* mOrientationAnimation;
-
- // access protected by mDebugLock
- mutable Mutex mDebugLock;
- sp<CPUGauge> mCpuGauge;
// don't use a lock for these, we don't care
int mDebugRegion;
- int mDebugCpu;
- int mDebugFps;
int mDebugBackground;
+ volatile nsecs_t mDebugInSwapBuffers;
+ nsecs_t mLastSwapBufferTime;
+ volatile nsecs_t mDebugInTransaction;
+ nsecs_t mLastTransactionTime;
// these are thread safe
mutable Barrier mReadyToRunBarrier;
- mutable SurfaceFlingerSynchro mSyncObject;
- volatile int32_t mDeplayedTransactionPending;
// atomic variables
enum {
@@ -410,11 +387,11 @@ class BClient : public BnSurfaceFlingerClient
{
public:
BClient(SurfaceFlinger *flinger, ClientID cid,
- const sp<IMemory>& cblk);
+ const sp<IMemoryHeap>& cblk);
~BClient();
// ISurfaceFlingerClient interface
- virtual void getControlBlocks(sp<IMemory>* ctrl) const;
+ virtual sp<IMemoryHeap> getControlBlock() const;
virtual sp<ISurface> createSurface(
surface_data_t* params, int pid,
@@ -427,7 +404,7 @@ public:
private:
ClientID mId;
SurfaceFlinger* mFlinger;
- sp<IMemory> mCblk;
+ sp<IMemoryHeap> mCblk;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Tokenizer.cpp b/libs/surfaceflinger/Tokenizer.cpp
index ef51d6a..be3a239 100644
--- a/libs/surfaceflinger/Tokenizer.cpp
+++ b/libs/surfaceflinger/Tokenizer.cpp
@@ -162,9 +162,10 @@ void Tokenizer::dump() const
{
const run_t* ranges = mRanges.array();
const size_t c = mRanges.size();
- printf("Tokenizer (%p, size = %lu)\n", this, c);
+ printf("Tokenizer (%p, size = %d)\n", this, int(c));
for (size_t i=0 ; i<c ; i++) {
- printf("%lu: (%u, %u)\n", i, ranges[i].first, ranges[i].length);
+ printf("%u: (%u, %u)\n", i,
+ uint32_t(ranges[i].first), uint32_t(ranges[i].length));
}
}
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
index e8b0f45..1501536 100644
--- a/libs/surfaceflinger/Transform.cpp
+++ b/libs/surfaceflinger/Transform.cpp
@@ -177,10 +177,10 @@ Region Transform::transform(const Region& reg) const
Region out;
if (UNLIKELY(transformed())) {
if (LIKELY(preserveRects())) {
- Rect r;
- Region::iterator iterator(reg);
- while (iterator.iterate(&r)) {
- out.orSelf(transform(r));
+ Region::const_iterator it = reg.begin();
+ Region::const_iterator const end = reg.end();
+ while (it != end) {
+ out.orSelf(transform(*it++));
}
} else {
out.set(transform(reg.bounds()));
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
deleted file mode 100644
index 5f633bd..0000000
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ /dev/null
@@ -1,178 +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.
- */
-
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <math.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#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 <EGL/eglnatives.h>
-
-#include "GPUHardware/GPUHardware.h"
-#include "SurfaceFlinger.h"
-#include "VRamHeap.h"
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-/*
- * Amount of memory we reserve for surface, per client in PMEM
- * (PMEM is used for 2D acceleration)
- * 8 MB of address space per client should be enough.
- */
-static const int PMEM_SIZE = int(8 * 1024 * 1024);
-
-int SurfaceHeapManager::global_pmem_heap = 0;
-
-// ---------------------------------------------------------------------------
-
-SurfaceHeapManager::SurfaceHeapManager(const sp<SurfaceFlinger>& flinger,
- size_t clientHeapSize)
- : mFlinger(flinger), mClientHeapSize(clientHeapSize)
-{
- SurfaceHeapManager::global_pmem_heap = 1;
-}
-
-SurfaceHeapManager::~SurfaceHeapManager()
-{
-}
-
-void SurfaceHeapManager::onFirstRef()
-{
- if (global_pmem_heap) {
- const char* device = "/dev/pmem";
- mPMemHeap = new PMemHeap(device, PMEM_SIZE);
- if (mPMemHeap->base() == MAP_FAILED) {
- mPMemHeap.clear();
- global_pmem_heap = 0;
- }
- }
-}
-
-sp<MemoryDealer> SurfaceHeapManager::createHeap(
- uint32_t flags,
- pid_t client_pid,
- const sp<MemoryDealer>& defaultAllocator)
-{
- sp<MemoryDealer> dealer;
-
- if (flags & ISurfaceComposer::eGPU) {
- // don't grant GPU memory if GPU is disabled
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.hw", value, "1");
- if (atoi(value) == 0) {
- flags &= ~ISurfaceComposer::eGPU;
- }
- }
-
- if ((flags & ISurfaceComposer::eGPU) && (mFlinger->getGPU() != 0)) {
- // FIXME: this is msm7201A specific, where gpu surfaces may not be secure
- if (!(flags & ISurfaceComposer::eSecure)) {
- // if GPU doesn't work, we try eHardware
- flags |= ISurfaceComposer::eHardware;
- // asked for GPU memory, try that first
- dealer = mFlinger->getGPU()->request(client_pid);
- }
- }
-
- if (dealer == NULL) {
- if (defaultAllocator != NULL)
- // if a default allocator is given, use that
- dealer = defaultAllocator;
- }
-
- if (dealer == NULL) {
- // always try h/w accelerated memory first
- if (global_pmem_heap) {
- const sp<PMemHeap>& heap(mPMemHeap);
- if (dealer == NULL && heap != NULL) {
- dealer = new MemoryDealer(
- heap->createClientHeap(),
- heap->getAllocator());
- }
- }
- }
-
- if (dealer == NULL) {
- // return the ashmem allocator (software rendering)
- dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
- }
- return dealer;
-}
-
-sp<SimpleBestFitAllocator> SurfaceHeapManager::getAllocator(int type) const
-{
- Mutex::Autolock _l(mLock);
- sp<SimpleBestFitAllocator> allocator;
-
- // this is only used for debugging
- switch (type) {
- case NATIVE_MEMORY_TYPE_PMEM:
- if (mPMemHeap != 0) {
- allocator = mPMemHeap->getAllocator();
- }
- break;
- }
- return allocator;
-}
-
-// ---------------------------------------------------------------------------
-
-PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
- : MemoryHeapBase(device, size)
-{
- //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
- if (base() != MAP_FAILED) {
- //LOGD("%s, %u bytes", device, virtualSize());
- if (reserved == 0)
- reserved = virtualSize();
- mAllocator = new SimpleBestFitAllocator(reserved);
- }
-}
-
-PMemHeap::~PMemHeap() {
- //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
-}
-
-sp<MemoryHeapPmem> PMemHeap::createClientHeap() {
- sp<MemoryHeapBase> parentHeap(this);
- return new MemoryHeapPmem(parentHeap);
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.cpp b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.cpp
new file mode 100644
index 0000000..2de628b
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.cpp
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.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>
+
+#include "VRamHeap.h"
+#include "GPUHardware.h"
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+#include "GPUHardware/GPUHardware.h"
+
+
+/*
+ * Manage the GPU. This implementation is very specific to the G1.
+ * There are no abstraction here.
+ *
+ * All this code will soon go-away and be replaced by a new architecture
+ * for managing graphics accelerators.
+ *
+ * In the meantime, it is conceptually possible to instantiate a
+ * GPUHardwareInterface for another GPU (see GPUFactory at the bottom
+ * of this file); practically... doubtful.
+ *
+ */
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class GPUClientHeap;
+class GPUAreaHeap;
+
+class GPUHardware : public GPUHardwareInterface, public IBinder::DeathRecipient
+{
+public:
+ static const int GPU_RESERVED_SIZE;
+ static const int GPUR_SIZE;
+
+ GPUHardware();
+ virtual ~GPUHardware();
+
+ virtual void revoke(int pid);
+ virtual sp<MemoryDealer> request(int pid);
+ virtual status_t request(int pid,
+ const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu);
+
+ virtual status_t friendlyRevoke();
+ virtual void unconditionalRevoke();
+
+ virtual pid_t getOwner() const { return mOwner; }
+
+ // used for debugging only...
+ virtual sp<SimpleBestFitAllocator> getAllocator() const;
+
+private:
+
+
+ enum {
+ NO_OWNER = -1,
+ };
+
+ struct GPUArea {
+ sp<GPUAreaHeap> heap;
+ sp<MemoryHeapPmem> clientHeap;
+ sp<IMemory> map();
+ };
+
+ struct Client {
+ pid_t pid;
+ GPUArea smi;
+ GPUArea ebi;
+ GPUArea reg;
+ void createClientHeaps();
+ void revokeAllHeaps();
+ };
+
+ Client& getClientLocked(pid_t pid);
+ status_t requestLocked(int pid);
+ void releaseLocked();
+ void takeBackGPULocked();
+ void registerCallbackLocked(const sp<IGPUCallback>& callback,
+ Client& client);
+
+ virtual void binderDied(const wp<IBinder>& who);
+
+ mutable Mutex mLock;
+ sp<GPUAreaHeap> mSMIHeap;
+ sp<GPUAreaHeap> mEBIHeap;
+ sp<GPUAreaHeap> mREGHeap;
+
+ KeyedVector<pid_t, Client> mClients;
+ DefaultKeyedVector< wp<IBinder>, pid_t > mRegisteredClients;
+
+ pid_t mOwner;
+
+ sp<MemoryDealer> mCurrentAllocator;
+ sp<IGPUCallback> mCallback;
+
+ sp<SimpleBestFitAllocator> mAllocator;
+
+ Condition mCondition;
+};
+
+// size reserved for GPU surfaces
+// 1200 KB fits exactly:
+// - two 320*480 16-bits double-buffered surfaces
+// - one 320*480 32-bits double-buffered surface
+// - one 320*240 16-bits double-buffered, 4x anti-aliased surface
+const int GPUHardware::GPU_RESERVED_SIZE = 1200 * 1024;
+const int GPUHardware::GPUR_SIZE = 1 * 1024 * 1024;
+
+// ---------------------------------------------------------------------------
+
+/*
+ * GPUHandle is a special IMemory given to the client. It represents their
+ * handle to the GPU. Once they give it up, they loose GPU access, or if
+ * they explicitly revoke their access through the binder code 1000.
+ * In both cases, this triggers a callback to revoke()
+ * first, and then actually powers down the chip.
+ *
+ * In the case of a misbehaving app, GPUHardware can ask for an immediate
+ * release of the GPU to the target process which should answer by calling
+ * code 1000 on GPUHandle. If it doesn't in a timely manner, the GPU will
+ * be revoked from under their feet.
+ *
+ * We should never hold a strong reference on GPUHandle. In practice this
+ * shouldn't be a big issue though because clients should use code 1000 and
+ * not rely on the dtor being called.
+ *
+ */
+
+class GPUClientHeap : public MemoryHeapPmem
+{
+public:
+ GPUClientHeap(const wp<GPUHardware>& gpu,
+ const sp<MemoryHeapBase>& heap)
+ : MemoryHeapPmem(heap), mGPU(gpu) { }
+protected:
+ wp<GPUHardware> mGPU;
+};
+
+class GPUAreaHeap : public MemoryHeapBase
+{
+public:
+ GPUAreaHeap(const wp<GPUHardware>& gpu,
+ const char* const vram, size_t size=0, size_t reserved=0)
+ : MemoryHeapBase(vram, size), mGPU(gpu) {
+ if (base() != MAP_FAILED) {
+ if (reserved == 0)
+ reserved = virtualSize();
+ mAllocator = new SimpleBestFitAllocator(reserved);
+ }
+ }
+ virtual sp<MemoryHeapPmem> createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new GPUClientHeap(mGPU, parentHeap);
+ }
+ virtual const sp<SimpleBestFitAllocator>& getAllocator() const {
+ return mAllocator;
+ }
+private:
+ sp<SimpleBestFitAllocator> mAllocator;
+protected:
+ wp<GPUHardware> mGPU;
+};
+
+class GPURegisterHeap : public GPUAreaHeap
+{
+public:
+ GPURegisterHeap(const sp<GPUHardware>& gpu)
+ : GPUAreaHeap(gpu, "/dev/hw3d", GPUHardware::GPUR_SIZE) { }
+ virtual sp<MemoryHeapPmem> createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new MemoryHeapRegs(mGPU, parentHeap);
+ }
+private:
+ class MemoryHeapRegs : public GPUClientHeap {
+ public:
+ MemoryHeapRegs(const wp<GPUHardware>& gpu,
+ const sp<MemoryHeapBase>& heap)
+ : GPUClientHeap(gpu, heap) { }
+ sp<MemoryHeapPmem::MemoryPmem> createMemory(size_t offset, size_t size);
+ virtual void revoke();
+ private:
+ class GPUHandle : public MemoryHeapPmem::MemoryPmem {
+ public:
+ GPUHandle(const sp<GPUHardware>& gpu,
+ const sp<MemoryHeapPmem>& heap)
+ : MemoryHeapPmem::MemoryPmem(heap),
+ mGPU(gpu), mOwner(gpu->getOwner()) { }
+ virtual ~GPUHandle();
+ virtual sp<IMemoryHeap> getMemory(
+ ssize_t* offset, size_t* size) const;
+ virtual void revoke() { };
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags);
+ private:
+ void revokeNotification();
+ wp<GPUHardware> mGPU;
+ pid_t mOwner;
+ };
+ };
+};
+
+GPURegisterHeap::MemoryHeapRegs::GPUHandle::~GPUHandle() {
+ //LOGD("GPUHandle %p released, revoking GPU", this);
+ revokeNotification();
+}
+void GPURegisterHeap::MemoryHeapRegs::GPUHandle::revokeNotification() {
+ sp<GPUHardware> hw(mGPU.promote());
+ if (hw != 0) {
+ hw->revoke(mOwner);
+ }
+}
+sp<IMemoryHeap> GPURegisterHeap::MemoryHeapRegs::GPUHandle::getMemory(
+ ssize_t* offset, size_t* size) const
+{
+ sp<MemoryHeapPmem> heap = getHeap();
+ if (offset) *offset = 0;
+ if (size) *size = heap !=0 ? heap->virtualSize() : 0;
+ return heap;
+}
+status_t GPURegisterHeap::MemoryHeapRegs::GPUHandle::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ status_t err = BnMemory::onTransact(code, data, reply, flags);
+ if (err == UNKNOWN_TRANSACTION && code == 1000) {
+ int callingPid = IPCThreadState::self()->getCallingPid();
+ //LOGD("pid %d voluntarily revoking gpu", callingPid);
+ if (callingPid == mOwner) {
+ revokeNotification();
+ // we've revoked the GPU, don't do it again later when we
+ // are destroyed.
+ mGPU.clear();
+ } else {
+ LOGW("%d revoking someone else's gpu? (owner=%d)",
+ callingPid, mOwner);
+ }
+ err = NO_ERROR;
+ }
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+
+
+sp<MemoryHeapPmem::MemoryPmem> GPURegisterHeap::MemoryHeapRegs::createMemory(
+ size_t offset, size_t size)
+{
+ sp<GPUHandle> memory;
+ sp<GPUHardware> gpu = mGPU.promote();
+ if (heapID()>0 && gpu!=0) {
+#if HAVE_ANDROID_OS
+ /* this is where the GPU is powered on and the registers are mapped
+ * in the client */
+ //LOGD("ioctl(HW3D_GRANT_GPU)");
+ int err = ioctl(heapID(), HW3D_GRANT_GPU, base());
+ if (err) {
+ // it can happen if the master heap has been closed already
+ // in which case the GPU already is revoked (app crash for
+ // instance).
+ LOGW("HW3D_GRANT_GPU failed (%s), mFD=%d, base=%p",
+ strerror(errno), heapID(), base());
+ }
+ memory = new GPUHandle(gpu, this);
+#endif
+ }
+ return memory;
+}
+
+void GPURegisterHeap::MemoryHeapRegs::revoke()
+{
+ MemoryHeapPmem::revoke();
+#if HAVE_ANDROID_OS
+ if (heapID() > 0) {
+ //LOGD("ioctl(HW3D_REVOKE_GPU)");
+ int err = ioctl(heapID(), HW3D_REVOKE_GPU, base());
+ LOGE_IF(err, "HW3D_REVOKE_GPU failed (%s), mFD=%d, base=%p",
+ strerror(errno), heapID(), base());
+ }
+#endif
+}
+
+/*****************************************************************************/
+
+GPUHardware::GPUHardware()
+ : mOwner(NO_OWNER)
+{
+}
+
+GPUHardware::~GPUHardware()
+{
+}
+
+status_t GPUHardware::requestLocked(int pid)
+{
+ const int self_pid = getpid();
+ if (pid == self_pid) {
+ // can't use GPU from surfaceflinger's process
+ return PERMISSION_DENIED;
+ }
+
+ if (mOwner != pid) {
+ if (mREGHeap != 0) {
+ if (mOwner != NO_OWNER) {
+ // someone already has the gpu.
+ takeBackGPULocked();
+ releaseLocked();
+ }
+ } else {
+ // first time, initialize the stuff.
+ if (mSMIHeap == 0)
+ mSMIHeap = new GPUAreaHeap(this, "/dev/pmem_gpu0");
+ if (mEBIHeap == 0)
+ mEBIHeap = new GPUAreaHeap(this,
+ "/dev/pmem_gpu1", 0, GPU_RESERVED_SIZE);
+ mREGHeap = new GPURegisterHeap(this);
+ mAllocator = mEBIHeap->getAllocator();
+ if (mAllocator == NULL) {
+ // something went terribly wrong.
+ mSMIHeap.clear();
+ mEBIHeap.clear();
+ mREGHeap.clear();
+ return INVALID_OPERATION;
+ }
+ }
+ Client& client = getClientLocked(pid);
+ mCurrentAllocator = new MemoryDealer(client.ebi.clientHeap, mAllocator);
+ mOwner = pid;
+ }
+ return NO_ERROR;
+}
+
+sp<MemoryDealer> GPUHardware::request(int pid)
+{
+ sp<MemoryDealer> dealer;
+ Mutex::Autolock _l(mLock);
+ Client* client;
+ LOGD("pid %d requesting gpu surface (current owner = %d)", pid, mOwner);
+ if (requestLocked(pid) == NO_ERROR) {
+ dealer = mCurrentAllocator;
+ LOGD_IF(dealer!=0, "gpu surface granted to pid %d", mOwner);
+ }
+ return dealer;
+}
+
+status_t GPUHardware::request(int pid, const sp<IGPUCallback>& callback,
+ ISurfaceComposer::gpu_info_t* gpu)
+{
+ if (callback == 0)
+ return BAD_VALUE;
+
+ sp<IMemory> gpuHandle;
+ LOGD("pid %d requesting gpu core (owner = %d)", pid, mOwner);
+ Mutex::Autolock _l(mLock);
+ status_t err = requestLocked(pid);
+ if (err == NO_ERROR) {
+ // it's guaranteed to be there, be construction
+ Client& client = mClients.editValueFor(pid);
+ registerCallbackLocked(callback, client);
+ gpu->count = 2;
+ gpu->regions[0].region = client.smi.map();
+ gpu->regions[1].region = client.ebi.map();
+ gpu->regs = client.reg.map();
+ gpu->regions[0].reserved = 0;
+ gpu->regions[1].reserved = GPU_RESERVED_SIZE;
+ if (gpu->regs != 0) {
+ //LOGD("gpu core granted to pid %d, handle base=%p",
+ // mOwner, gpu->regs->pointer());
+ }
+ mCallback = callback;
+ } else {
+ LOGW("couldn't grant gpu core to pid %d", pid);
+ }
+ return err;
+}
+
+void GPUHardware::revoke(int pid)
+{
+ Mutex::Autolock _l(mLock);
+ if (mOwner > 0) {
+ if (pid != mOwner) {
+ LOGW("GPU owned by %d, revoke from %d", mOwner, pid);
+ return;
+ }
+ //LOGD("revoke pid=%d, owner=%d", pid, mOwner);
+ // mOwner could be <0 if the same process acquired the GPU
+ // several times without releasing it first.
+ mCondition.signal();
+ releaseLocked();
+ }
+}
+
+status_t GPUHardware::friendlyRevoke()
+{
+ Mutex::Autolock _l(mLock);
+ //LOGD("friendlyRevoke owner=%d", mOwner);
+ takeBackGPULocked();
+ releaseLocked();
+ return NO_ERROR;
+}
+
+void GPUHardware::takeBackGPULocked()
+{
+ sp<IGPUCallback> callback = mCallback;
+ mCallback.clear();
+ if (callback != 0) {
+ callback->gpuLost(); // one-way
+ mCondition.waitRelative(mLock, ms2ns(250));
+ }
+}
+
+void GPUHardware::releaseLocked()
+{
+ //LOGD("revoking gpu from pid %d", mOwner);
+ if (mOwner != NO_OWNER) {
+ // this may fail because the client might have died, and have
+ // been removed from the list.
+ ssize_t index = mClients.indexOfKey(mOwner);
+ if (index >= 0) {
+ Client& client(mClients.editValueAt(index));
+ client.revokeAllHeaps();
+ }
+ mOwner = NO_OWNER;
+ mCurrentAllocator.clear();
+ mCallback.clear();
+ }
+}
+
+GPUHardware::Client& GPUHardware::getClientLocked(pid_t pid)
+{
+ ssize_t index = mClients.indexOfKey(pid);
+ if (index < 0) {
+ Client client;
+ client.pid = pid;
+ client.smi.heap = mSMIHeap;
+ client.ebi.heap = mEBIHeap;
+ client.reg.heap = mREGHeap;
+ index = mClients.add(pid, client);
+ }
+ Client& client(mClients.editValueAt(index));
+ client.createClientHeaps();
+ return client;
+}
+
+// ----------------------------------------------------------------------------
+// for debugging / testing ...
+
+sp<SimpleBestFitAllocator> GPUHardware::getAllocator() const {
+ Mutex::Autolock _l(mLock);
+ return mAllocator;
+}
+
+void GPUHardware::unconditionalRevoke()
+{
+ Mutex::Autolock _l(mLock);
+ releaseLocked();
+}
+
+// ---------------------------------------------------------------------------
+
+sp<IMemory> GPUHardware::GPUArea::map() {
+ sp<IMemory> memory;
+ if (clientHeap != 0 && heap != 0) {
+ memory = clientHeap->mapMemory(0, heap->virtualSize());
+ }
+ return memory;
+}
+
+void GPUHardware::Client::createClientHeaps()
+{
+ if (smi.clientHeap == 0)
+ smi.clientHeap = smi.heap->createClientHeap();
+ if (ebi.clientHeap == 0)
+ ebi.clientHeap = ebi.heap->createClientHeap();
+ if (reg.clientHeap == 0)
+ reg.clientHeap = reg.heap->createClientHeap();
+}
+
+void GPUHardware::Client::revokeAllHeaps()
+{
+ if (smi.clientHeap != 0)
+ smi.clientHeap->revoke();
+ if (ebi.clientHeap != 0)
+ ebi.clientHeap->revoke();
+ if (reg.clientHeap != 0)
+ reg.clientHeap->revoke();
+}
+
+void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
+ Client& client)
+{
+ sp<IBinder> binder = callback->asBinder();
+ if (mRegisteredClients.add(binder, client.pid) >= 0) {
+ binder->linkToDeath(this);
+ }
+}
+
+void GPUHardware::binderDied(const wp<IBinder>& who)
+{
+ Mutex::Autolock _l(mLock);
+ pid_t pid = mRegisteredClients.valueFor(who);
+ if (pid != 0) {
+ ssize_t index = mClients.indexOfKey(pid);
+ if (index >= 0) {
+ //LOGD("*** removing client at %d", index);
+ Client& client(mClients.editValueAt(index));
+ client.revokeAllHeaps(); // not really needed in theory
+ mClients.removeItemsAt(index);
+ if (mClients.size() == 0) {
+ //LOGD("*** was last client closing everything");
+ mCallback.clear();
+ mAllocator.clear();
+ mCurrentAllocator.clear();
+ mSMIHeap.clear();
+ mREGHeap.clear();
+
+ // NOTE: we cannot clear the EBI heap because surfaceflinger
+ // itself may be using it, since this is where surfaces
+ // are allocated. if we're in the middle of compositing
+ // a surface (even if its process just died), we cannot
+ // rip the heap under our feet.
+
+ mOwner = NO_OWNER;
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+sp<GPUHardwareInterface> GPUFactory::getGPU()
+{
+ sp<GPUHardwareInterface> gpu;
+ if (access("/dev/hw3d", F_OK) == 0) {
+ gpu = new GPUHardware();
+ }
+ return gpu;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/surfaceflinger/GPUHardware/GPUHardware.h b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.h
index 3354528..3354528 100644
--- a/libs/surfaceflinger/GPUHardware/GPUHardware.h
+++ b/libs/surfaceflinger/purgatory/GPUHardware/GPUHardware.h
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp b/libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp
new file mode 100644
index 0000000..41c42d1
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnim.cpp
@@ -0,0 +1,272 @@
+/*
+ * 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 <utils/StopWatch.h>
+
+#include "BlurFilter.h"
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
+const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
+
+// ---------------------------------------------------------------------------
+
+// Animation...
+const float DURATION = ms2ns(200);
+const float BOUNCES_PER_SECOND = 0.5f;
+//const float BOUNCES_AMPLITUDE = 1.0f/16.0f;
+const float BOUNCES_AMPLITUDE = 0;
+const float DIM_TARGET = 0.40f;
+//#define INTERPOLATED_TIME(_t) ((_t)*(_t))
+#define INTERPOLATED_TIME(_t) (_t)
+
+// ---------------------------------------------------------------------------
+
+LayerOrientationAnim::LayerOrientationAnim(
+ SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut)
+ : LayerOrientationAnimBase(flinger, display), mAnim(anim),
+ mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
+ mTextureName(-1), mTextureNameIn(-1)
+{
+ // blur that texture.
+ mStartTime = systemTime();
+ mFinishTime = 0;
+ mOrientationCompleted = false;
+ mFirstRedraw = false;
+ mLastNormalizedTime = 0;
+ mNeedsBlending = false;
+ mAlphaInLerp.set(1.0f, DIM_TARGET);
+ mAlphaOutLerp.set(0.5f, 1.0f);
+}
+
+LayerOrientationAnim::~LayerOrientationAnim()
+{
+ if (mTextureName != -1U) {
+ glDeleteTextures(1, &mTextureName);
+ }
+ if (mTextureNameIn != -1U) {
+ glDeleteTextures(1, &mTextureNameIn);
+ }
+}
+
+bool LayerOrientationAnim::needsBlending() const
+{
+ return mNeedsBlending;
+}
+
+Point LayerOrientationAnim::getPhysicalSize() const
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnim::validateVisibility(const Transform&)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(s.transform);
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+ transparentRegionScreen.clear();
+ mTransformed = true;
+}
+
+void LayerOrientationAnim::onOrientationCompleted()
+{
+ mFinishTime = systemTime();
+ mOrientationCompleted = true;
+ mFirstRedraw = true;
+ mNeedsBlending = true;
+ mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnim::onDraw(const Region& clip) const
+{
+ const nsecs_t now = systemTime();
+ float alphaIn, alphaOut;
+
+ if (mOrientationCompleted) {
+ if (mFirstRedraw) {
+ mFirstRedraw = false;
+
+ // make a copy of what's on screen
+ copybit_image_t image;
+ mBitmapOut->getBitmapSurface(&image);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.copyBackToImage(image);
+
+ // and erase the screen for this round
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // FIXME: code below is gross
+ mNeedsBlending = false;
+ LayerOrientationAnim* self(const_cast<LayerOrientationAnim*>(this));
+ mFlinger->invalidateLayerVisibility(self);
+ }
+
+ // make sure pick-up where we left off
+ const float duration = DURATION * mLastNormalizedTime;
+ const float normalizedTime = (float(now - mFinishTime) / duration);
+ if (normalizedTime <= 1.0f) {
+ const float interpolatedTime = INTERPOLATED_TIME(normalizedTime);
+ alphaIn = mAlphaInLerp.getOut();
+ alphaOut = mAlphaOutLerp(interpolatedTime);
+ } else {
+ mAnim->onAnimationFinished();
+ alphaIn = mAlphaInLerp.getOut();
+ alphaOut = mAlphaOutLerp.getOut();
+ }
+ } else {
+ const float normalizedTime = float(now - mStartTime) / DURATION;
+ if (normalizedTime <= 1.0f) {
+ mLastNormalizedTime = normalizedTime;
+ const float interpolatedTime = INTERPOLATED_TIME(normalizedTime);
+ alphaIn = mAlphaInLerp(interpolatedTime);
+ alphaOut = 0.0f;
+ } else {
+ mLastNormalizedTime = 1.0f;
+ const float to_seconds = DURATION / seconds(1);
+ alphaIn = mAlphaInLerp.getOut();
+ if (BOUNCES_AMPLITUDE > 0.0f) {
+ const float phi = BOUNCES_PER_SECOND *
+ (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+ if (alphaIn > 1.0f) alphaIn = 1.0f;
+ else if (alphaIn < 0.0f) alphaIn = 0.0f;
+ alphaIn += BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
+ }
+ alphaOut = 0.0f;
+ }
+ mAlphaOutLerp.setIn(alphaIn);
+ }
+ drawScaled(1.0f, alphaIn, alphaOut);
+}
+
+void LayerOrientationAnim::drawScaled(float scale, float alphaIn, float alphaOut) const
+{
+ copybit_image_t dst;
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ //hw.getDisplaySurface(&dst);
+
+ // clear screen
+ // TODO: with update on demand, we may be able
+ // to not erase the screen at all during the animation
+ if (!mOrientationCompleted) {
+ if (scale==1.0f && (alphaIn>=1.0f || alphaOut>=1.0f)) {
+ // we don't need to erase the screen in that case
+ } else {
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ }
+
+ copybit_image_t src;
+ mBitmapIn->getBitmapSurface(&src);
+
+ copybit_image_t srcOut;
+ mBitmapOut->getBitmapSurface(&srcOut);
+
+ const int w = dst.w*scale;
+ const int h = dst.h*scale;
+ const int xc = uint32_t(dst.w-w)/2;
+ const int yc = uint32_t(dst.h-h)/2;
+ const copybit_rect_t drect = { xc, yc, xc+w, yc+h };
+ const copybit_rect_t srect = { 0, 0, src.w, src.h };
+ const Region reg(Rect( drect.l, drect.t, drect.r, drect.b ));
+
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.w;
+ t.height = src.h;
+ t.stride = src.w;
+ t.vstride= src.h;
+ t.format = src.format;
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+ Transform tr;
+ tr.set(scale,0,0,scale);
+ tr.set(xc, yc);
+
+ // FIXME: we should not access mVertices and mDrawingState like that,
+ // but since we control the animation, we know it's going to work okay.
+ // eventually we'd need a more formal way of doing things like this.
+ LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // Too slow to do this in software
+ self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+ }
+
+ if (alphaIn > 0.0f) {
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureNameIn == -1LU)) {
+ mTextureNameIn = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureNameIn, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alphaIn*255);
+ drawWithOpenGL(reg, mTextureNameIn, t);
+ }
+
+ if (alphaOut > 0.0f) {
+ t.data = (GGLubyte*)(intptr_t(srcOut.base) + srcOut.offset);
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alphaOut*255);
+ drawWithOpenGL(reg, mTextureName, t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnim.h b/libs/surfaceflinger/purgatory/LayerOrientationAnim.h
new file mode 100644
index 0000000..a1a2654
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnim.h
@@ -0,0 +1,112 @@
+/*
+ * 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_LAYER_ORIENTATION_ANIM_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <binder/Parcel.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+class OrientationAnimation;
+
+
+class LayerOrientationAnimBase : public LayerBase
+{
+public:
+ LayerOrientationAnimBase(SurfaceFlinger* flinger, DisplayID display)
+ : LayerBase(flinger, display) {
+ }
+ virtual void onOrientationCompleted() = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+class LayerOrientationAnim : public LayerOrientationAnimBase
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut);
+ virtual ~LayerOrientationAnim();
+
+ void onOrientationCompleted();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual Point getPhysicalSize() const;
+ virtual void validateVisibility(const Transform& globalTransform);
+ virtual bool needsBlending() const;
+ virtual bool isSecure() const { return false; }
+private:
+ void drawScaled(float scale, float alphaIn, float alphaOut) const;
+
+ class Lerp {
+ float in;
+ float outMinusIn;
+ public:
+ Lerp() : in(0), outMinusIn(0) { }
+ Lerp(float in, float out) : in(in), outMinusIn(out-in) { }
+ float getIn() const { return in; };
+ float getOut() const { return in + outMinusIn; }
+ void set(float in, float out) {
+ this->in = in;
+ this->outMinusIn = out-in;
+ }
+ void setIn(float in) {
+ this->in = in;
+ }
+ void setOut(float out) {
+ this->outMinusIn = out - this->in;
+ }
+ float operator()(float t) const {
+ return outMinusIn*t + in;
+ }
+ };
+
+ OrientationAnimation* mAnim;
+ sp<Buffer> mBitmapIn;
+ sp<Buffer> mBitmapOut;
+ nsecs_t mStartTime;
+ nsecs_t mFinishTime;
+ bool mOrientationCompleted;
+ mutable bool mFirstRedraw;
+ mutable float mLastNormalizedTime;
+ mutable GLuint mTextureName;
+ mutable GLuint mTextureNameIn;
+ mutable bool mNeedsBlending;
+
+ mutable Lerp mAlphaInLerp;
+ mutable Lerp mAlphaOutLerp;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp
new file mode 100644
index 0000000..dc6b632
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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 "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "LayerOrientationAnimRotate.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnimRotate::typeInfo = LayerBase::typeInfo | 0x100;
+const char* const LayerOrientationAnimRotate::typeID = "LayerOrientationAnimRotate";
+
+// ---------------------------------------------------------------------------
+
+const float ROTATION = M_PI * 0.5f;
+const float ROTATION_FACTOR = 1.0f; // 1.0 or 2.0
+const float DURATION = ms2ns(200);
+const float BOUNCES_PER_SECOND = 0.8;
+const float BOUNCES_AMPLITUDE = (5.0f/180.f) * M_PI;
+
+LayerOrientationAnimRotate::LayerOrientationAnimRotate(
+ SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut)
+ : LayerOrientationAnimBase(flinger, display), mAnim(anim),
+ mBitmapIn(bitmapIn), mBitmapOut(bitmapOut),
+ mTextureName(-1), mTextureNameIn(-1)
+{
+ mStartTime = systemTime();
+ mFinishTime = 0;
+ mOrientationCompleted = false;
+ mFirstRedraw = false;
+ mLastNormalizedTime = 0;
+ mLastAngle = 0;
+ mLastScale = 0;
+ mNeedsBlending = false;
+ const GraphicPlane& plane(graphicPlane(0));
+ mOriginalTargetOrientation = plane.getOrientation();
+}
+
+LayerOrientationAnimRotate::~LayerOrientationAnimRotate()
+{
+ if (mTextureName != -1U) {
+ glDeleteTextures(1, &mTextureName);
+ }
+ if (mTextureNameIn != -1U) {
+ glDeleteTextures(1, &mTextureNameIn);
+ }
+}
+
+bool LayerOrientationAnimRotate::needsBlending() const
+{
+ return mNeedsBlending;
+}
+
+Point LayerOrientationAnimRotate::getPhysicalSize() const
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnimRotate::validateVisibility(const Transform&)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(s.transform);
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+ transparentRegionScreen.clear();
+ mTransformed = true;
+}
+
+void LayerOrientationAnimRotate::onOrientationCompleted()
+{
+ mFinishTime = systemTime();
+ mOrientationCompleted = true;
+ mFirstRedraw = true;
+ mNeedsBlending = true;
+ mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnimRotate::onDraw(const Region& clip) const
+{
+ // Animation...
+
+ const nsecs_t now = systemTime();
+ float angle, scale, alpha;
+
+ if (mOrientationCompleted) {
+ if (mFirstRedraw) {
+ // make a copy of what's on screen
+ copybit_image_t image;
+ mBitmapIn->getBitmapSurface(&image);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.copyBackToImage(image);
+
+ // FIXME: code below is gross
+ mFirstRedraw = false;
+ mNeedsBlending = false;
+ LayerOrientationAnimRotate* self(const_cast<LayerOrientationAnimRotate*>(this));
+ mFlinger->invalidateLayerVisibility(self);
+ }
+
+ // make sure pick-up where we left off
+ const float duration = DURATION * mLastNormalizedTime;
+ const float normalizedTime = (float(now - mFinishTime) / duration);
+ if (normalizedTime <= 1.0f) {
+ const float squaredTime = normalizedTime*normalizedTime;
+ angle = (ROTATION*ROTATION_FACTOR - mLastAngle)*squaredTime + mLastAngle;
+ scale = (1.0f - mLastScale)*squaredTime + mLastScale;
+ alpha = normalizedTime;
+ } else {
+ mAnim->onAnimationFinished();
+ angle = ROTATION;
+ alpha = 1.0f;
+ scale = 1.0f;
+ }
+ } else {
+ // FIXME: works only for portrait framebuffers
+ const Point size(getPhysicalSize());
+ const float TARGET_SCALE = size.x * (1.0f / size.y);
+ const float normalizedTime = float(now - mStartTime) / DURATION;
+ if (normalizedTime <= 1.0f) {
+ mLastNormalizedTime = normalizedTime;
+ const float squaredTime = normalizedTime*normalizedTime;
+ angle = ROTATION * squaredTime;
+ scale = (TARGET_SCALE - 1.0f)*squaredTime + 1.0f;
+ alpha = 0;
+ } else {
+ mLastNormalizedTime = 1.0f;
+ angle = ROTATION;
+ if (BOUNCES_AMPLITUDE) {
+ const float to_seconds = DURATION / seconds(1);
+ const float phi = BOUNCES_PER_SECOND *
+ (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+ angle += BOUNCES_AMPLITUDE * sinf(phi);
+ }
+ scale = TARGET_SCALE;
+ alpha = 0;
+ }
+ mLastAngle = angle;
+ mLastScale = scale;
+ }
+ drawScaled(angle, scale, alpha);
+}
+
+void LayerOrientationAnimRotate::drawScaled(float f, float s, float alpha) const
+{
+ copybit_image_t dst;
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ //hw.getDisplaySurface(&dst);
+
+ // clear screen
+ // TODO: with update on demand, we may be able
+ // to not erase the screen at all during the animation
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ const int w = dst.w;
+ const int h = dst.h;
+
+ copybit_image_t src;
+ mBitmapIn->getBitmapSurface(&src);
+ const copybit_rect_t srect = { 0, 0, src.w, src.h };
+
+
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.w;
+ t.height = src.h;
+ t.stride = src.w;
+ t.vstride= src.h;
+ t.format = src.format;
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+ if (!mOriginalTargetOrientation) {
+ f = -f;
+ }
+
+ Transform tr;
+ tr.set(f, w*0.5f, h*0.5f);
+ tr.scale(s, w*0.5f, h*0.5f);
+
+ // FIXME: we should not access mVertices and mDrawingState like that,
+ // but since we control the animation, we know it's going to work okay.
+ // eventually we'd need a more formal way of doing things like this.
+ LayerOrientationAnimRotate& self(const_cast<LayerOrientationAnimRotate&>(*this));
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // Too slow to do this in software
+ self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+ }
+
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ }
+ self.mDrawingState.alpha = 255; //-int(alpha*255);
+ const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
+ drawWithOpenGL(clip, mTextureName, t);
+
+ if (alpha > 0) {
+ const float sign = (!mOriginalTargetOrientation) ? 1.0f : -1.0f;
+ tr.set(f + sign*(M_PI * 0.5f * ROTATION_FACTOR), w*0.5f, h*0.5f);
+ tr.scale(s, w*0.5f, h*0.5f);
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+
+ copybit_image_t src;
+ mBitmapIn->getBitmapSurface(&src);
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureNameIn == -1LU)) {
+ mTextureNameIn = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureNameIn, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alpha*255);
+ const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
+ drawWithOpenGL(clip, mTextureNameIn, t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.h b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.h
new file mode 100644
index 0000000..a88eec0
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/LayerOrientationAnimRotate.h
@@ -0,0 +1,77 @@
+/*
+ * 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_LAYER_ORIENTATION_ANIM_ROTATE_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+#include <binder/Parcel.h>
+
+#include "LayerBase.h"
+#include "LayerBitmap.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+class OrientationAnimation;
+
+class LayerOrientationAnimRotate : public LayerOrientationAnimBase
+{
+public:
+ static const uint32_t typeInfo;
+ static const char* const typeID;
+ virtual char const* getTypeID() const { return typeID; }
+ virtual uint32_t getTypeInfo() const { return typeInfo; }
+
+ LayerOrientationAnimRotate(SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const sp<Buffer>& bitmapIn,
+ const sp<Buffer>& bitmapOut);
+ virtual ~LayerOrientationAnimRotate();
+
+ void onOrientationCompleted();
+
+ virtual void onDraw(const Region& clip) const;
+ virtual Point getPhysicalSize() const;
+ virtual void validateVisibility(const Transform& globalTransform);
+ virtual bool needsBlending() const;
+ virtual bool isSecure() const { return false; }
+private:
+ void drawScaled(float angle, float scale, float alpha) const;
+
+ OrientationAnimation* mAnim;
+ sp<Buffer> mBitmapIn;
+ sp<Buffer> mBitmapOut;
+ nsecs_t mStartTime;
+ nsecs_t mFinishTime;
+ bool mOrientationCompleted;
+ int mOriginalTargetOrientation;
+ mutable bool mFirstRedraw;
+ mutable float mLastNormalizedTime;
+ mutable float mLastAngle;
+ mutable float mLastScale;
+ mutable GLuint mTextureName;
+ mutable GLuint mTextureNameIn;
+ mutable bool mNeedsBlending;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_ROTATE_H
diff --git a/libs/surfaceflinger/purgatory/OrientationAnimation.cpp b/libs/surfaceflinger/purgatory/OrientationAnimation.cpp
new file mode 100644
index 0000000..a6c9c28
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/OrientationAnimation.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "LayerOrientationAnim.h"
+#include "LayerOrientationAnimRotate.h"
+#include "OrientationAnimation.h"
+#include "SurfaceFlinger.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
+ : mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
+{
+}
+
+OrientationAnimation::~OrientationAnimation()
+{
+}
+
+void OrientationAnimation::onOrientationChanged(uint32_t type)
+{
+ if (mState == DONE) {
+ mType = type;
+ if (!(type & ISurfaceComposer::eOrientationAnimationDisable)) {
+ mState = PREPARE;
+ }
+ }
+}
+
+void OrientationAnimation::onAnimationFinished()
+{
+ if (mState != DONE)
+ mState = FINISH;
+}
+
+bool OrientationAnimation::run_impl()
+{
+ bool skip_frame;
+ switch (mState) {
+ default:
+ case DONE:
+ skip_frame = done();
+ break;
+ case PREPARE:
+ skip_frame = prepare();
+ break;
+ case PHASE1:
+ skip_frame = phase1();
+ break;
+ case PHASE2:
+ skip_frame = phase2();
+ break;
+ case FINISH:
+ skip_frame = finished();
+ break;
+ }
+ return skip_frame;
+}
+
+bool OrientationAnimation::done()
+{
+ return done_impl();
+}
+
+bool OrientationAnimation::prepare()
+{
+ mState = PHASE1;
+
+ const GraphicPlane& plane(mFlinger->graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ const uint32_t w = hw.getWidth();
+ const uint32_t h = hw.getHeight();
+
+ sp<Buffer> bitmap = new Buffer(w, h, hw.getFormat());
+ sp<Buffer> bitmapIn = new Buffer(w, h, hw.getFormat());
+
+ copybit_image_t front;
+ bitmap->getBitmapSurface(&front);
+ hw.copyFrontToImage(front); // FIXME: we need an extension to do this
+
+ sp<LayerOrientationAnimBase> l;
+
+ if (mType & 0x80) {
+ l = new LayerOrientationAnimRotate(
+ mFlinger.get(), 0, this, bitmap, bitmapIn);
+ } else {
+ l = new LayerOrientationAnim(
+ mFlinger.get(), 0, this, bitmap, bitmapIn);
+ }
+
+ l->initStates(w, h, 0);
+ l->setLayer(INT_MAX-1);
+ mFlinger->addLayer(l);
+ mLayerOrientationAnim = l;
+ return true;
+}
+
+bool OrientationAnimation::phase1()
+{
+ if (mFlinger->isFrozen() == false) {
+ // start phase 2
+ mState = PHASE2;
+ mLayerOrientationAnim->onOrientationCompleted();
+ mLayerOrientationAnim->invalidate();
+ return true;
+
+ }
+ mLayerOrientationAnim->invalidate();
+ return false;
+}
+
+bool OrientationAnimation::phase2()
+{
+ // do the 2nd phase of the animation
+ mLayerOrientationAnim->invalidate();
+ return false;
+}
+
+bool OrientationAnimation::finished()
+{
+ mState = DONE;
+ mFlinger->removeLayer(mLayerOrientationAnim);
+ mLayerOrientationAnim.clear();
+ return true;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/purgatory/OrientationAnimation.h b/libs/surfaceflinger/purgatory/OrientationAnimation.h
new file mode 100644
index 0000000..8ba6621
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/OrientationAnimation.h
@@ -0,0 +1,84 @@
+/*
+ * 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_ORIENTATION_ANIMATION_H
+#define ANDROID_ORIENTATION_ANIMATION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class SurfaceFlinger;
+class MemoryDealer;
+class LayerOrientationAnim;
+
+class OrientationAnimation
+{
+public:
+ OrientationAnimation(const sp<SurfaceFlinger>& flinger);
+ virtual ~OrientationAnimation();
+
+ void onOrientationChanged(uint32_t type);
+ void onAnimationFinished();
+ inline bool run() {
+ if (LIKELY(mState == DONE))
+ return done_impl();
+ return run_impl();
+ }
+
+private:
+ enum {
+ DONE = 0,
+ PREPARE,
+ PHASE1,
+ PHASE2,
+ FINISH
+ };
+
+ bool run_impl();
+ inline bool done_impl() {
+ if (mFlinger->isFrozen()) {
+ // we are not allowed to draw, but pause a bit to make sure
+ // apps don't end up using the whole CPU, if they depend on
+ // surfaceflinger for synchronization.
+ usleep(8333); // 8.3ms ~ 120fps
+ return true;
+ }
+ return false;
+ }
+
+ bool done();
+ bool prepare();
+ bool phase1();
+ bool phase2();
+ bool finished();
+
+ sp<SurfaceFlinger> mFlinger;
+ sp< LayerOrientationAnimBase > mLayerOrientationAnim;
+ int mState;
+ uint32_t mType;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ORIENTATION_ANIMATION_H
diff --git a/libs/surfaceflinger/purgatory/VRamHeap.cpp b/libs/surfaceflinger/purgatory/VRamHeap.cpp
new file mode 100644
index 0000000..f3ed790
--- /dev/null
+++ b/libs/surfaceflinger/purgatory/VRamHeap.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#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 "GPUHardware/GPUHardware.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+/*
+ * Amount of memory we reserve for surface, per client in PMEM
+ * (PMEM is used for 2D acceleration)
+ * 8 MB of address space per client should be enough.
+ */
+static const int PMEM_SIZE = int(8 * 1024 * 1024);
+
+int SurfaceHeapManager::global_pmem_heap = 0;
+
+// ---------------------------------------------------------------------------
+
+SurfaceHeapManager::SurfaceHeapManager(const sp<SurfaceFlinger>& flinger,
+ size_t clientHeapSize)
+ : mFlinger(flinger), mClientHeapSize(clientHeapSize)
+{
+ SurfaceHeapManager::global_pmem_heap = 1;
+}
+
+SurfaceHeapManager::~SurfaceHeapManager()
+{
+}
+
+void SurfaceHeapManager::onFirstRef()
+{
+ if (global_pmem_heap) {
+ const char* device = "/dev/pmem";
+ mPMemHeap = new PMemHeap(device, PMEM_SIZE);
+ if (mPMemHeap->base() == MAP_FAILED) {
+ mPMemHeap.clear();
+ global_pmem_heap = 0;
+ }
+ }
+}
+
+sp<MemoryDealer> SurfaceHeapManager::createHeap(
+ uint32_t flags,
+ pid_t client_pid,
+ const sp<MemoryDealer>& defaultAllocator)
+{
+ sp<MemoryDealer> dealer;
+
+ if (flags & ISurfaceComposer::eGPU) {
+ // don't grant GPU memory if GPU is disabled
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.hw", value, "1");
+ if (atoi(value) == 0) {
+ flags &= ~ISurfaceComposer::eGPU;
+ }
+ }
+
+ if (flags & ISurfaceComposer::eGPU) {
+ // FIXME: this is msm7201A specific, where gpu surfaces may not be secure
+ if (!(flags & ISurfaceComposer::eSecure)) {
+ // if GPU doesn't work, we try eHardware
+ flags |= ISurfaceComposer::eHardware;
+ // asked for GPU memory, try that first
+ dealer = mFlinger->getGPU()->request(client_pid);
+ }
+ }
+
+ if (dealer == NULL) {
+ if (defaultAllocator != NULL)
+ // if a default allocator is given, use that
+ dealer = defaultAllocator;
+ }
+
+ if (dealer == NULL) {
+ // always try h/w accelerated memory first
+ if (global_pmem_heap) {
+ const sp<PMemHeap>& heap(mPMemHeap);
+ if (dealer == NULL && heap != NULL) {
+ dealer = new MemoryDealer(
+ heap->createClientHeap(),
+ heap->getAllocator());
+ }
+ }
+ }
+
+ if (dealer == NULL) {
+ // return the ashmem allocator (software rendering)
+ dealer = new MemoryDealer(mClientHeapSize, 0, "SFNativeHeap");
+ }
+ return dealer;
+}
+
+sp<SimpleBestFitAllocator> SurfaceHeapManager::getAllocator(int type) const
+{
+ Mutex::Autolock _l(mLock);
+ sp<SimpleBestFitAllocator> allocator;
+
+ // this is only used for debugging
+ switch (type) {
+ case NATIVE_MEMORY_TYPE_PMEM:
+ if (mPMemHeap != 0) {
+ allocator = mPMemHeap->getAllocator();
+ }
+ break;
+ }
+ return allocator;
+}
+
+// ---------------------------------------------------------------------------
+
+PMemHeap::PMemHeap(const char* const device, size_t size, size_t reserved)
+ : MemoryHeapBase(device, size)
+{
+ //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
+ if (base() != MAP_FAILED) {
+ //LOGD("%s, %u bytes", device, virtualSize());
+ if (reserved == 0)
+ reserved = virtualSize();
+ mAllocator = new SimpleBestFitAllocator(reserved);
+ }
+}
+
+PMemHeap::~PMemHeap() {
+ //LOGD("%s, %p, mFD=%d", __PRETTY_FUNCTION__, this, heapID());
+}
+
+sp<MemoryHeapPmem> PMemHeap::createClientHeap() {
+ sp<MemoryHeapBase> parentHeap(this);
+ return new MemoryHeapPmem(parentHeap);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/surfaceflinger/VRamHeap.h b/libs/surfaceflinger/purgatory/VRamHeap.h
index 9140167..9140167 100644
--- a/libs/surfaceflinger/VRamHeap.h
+++ b/libs/surfaceflinger/purgatory/VRamHeap.h
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/surfaceflinger/tests/resize/Android.mk b/libs/surfaceflinger/tests/resize/Android.mk
new file mode 100644
index 0000000..ef1532f
--- /dev/null
+++ b/libs/surfaceflinger/tests/resize/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ resize.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui
+
+LOCAL_MODULE:= test-resize
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libs/surfaceflinger/tests/resize/resize.cpp b/libs/surfaceflinger/tests/resize/resize.cpp
new file mode 100644
index 0000000..21c6ab6
--- /dev/null
+++ b/libs/surfaceflinger/tests/resize/resize.cpp
@@ -0,0 +1,60 @@
+#include <cutils/memory.h>
+
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <ui/Surface.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+#include <ui/SurfaceComposerClient.h>
+
+using namespace android;
+
+namespace android {
+class Test {
+public:
+ static const sp<ISurface>& getISurface(const sp<Surface>& s) {
+ return s->getISurface();
+ }
+};
+};
+
+int main(int argc, char** argv)
+{
+ // set up the thread-pool
+ sp<ProcessState> proc(ProcessState::self());
+ ProcessState::self()->startThreadPool();
+
+ // create a client to surfaceflinger
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+
+ // create pushbuffer surface
+ sp<Surface> surface = client->createSurface(getpid(), 0, 160, 240,
+ PIXEL_FORMAT_RGB_565);
+
+
+ client->openTransaction();
+ surface->setLayer(100000);
+ client->closeTransaction();
+
+ Surface::SurfaceInfo info;
+ surface->lock(&info);
+ ssize_t bpr = info.s * bytesPerPixel(info.format);
+ android_memset16((uint16_t*)info.bits, 0xF800, bpr*info.h);
+ surface->unlockAndPost();
+
+ surface->lock(&info);
+ android_memset16((uint16_t*)info.bits, 0x07E0, bpr*info.h);
+ surface->unlockAndPost();
+
+ client->openTransaction();
+ surface->setSize(320, 240);
+ client->closeTransaction();
+
+
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 7bbe38b..93c7263 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -2,12 +2,13 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ BufferMapper.cpp \
Camera.cpp \
CameraParameters.cpp \
- EGLDisplaySurface.cpp \
- EGLNativeWindowSurface.cpp \
+ EGLUtils.cpp \
EventHub.cpp \
EventRecurrence.cpp \
+ FramebufferNativeWindow.cpp \
KeyLayoutMap.cpp \
KeyCharacterMap.cpp \
ICamera.cpp \
@@ -27,9 +28,10 @@ LOCAL_SRC_FILES:= \
SurfaceFlingerSynchro.cpp
LOCAL_SHARED_LIBRARIES := \
- libcorecg \
libcutils \
libutils \
+ libEGL \
+ libbinder \
libpixelflinger \
libhardware \
libhardware_legacy
diff --git a/libs/ui/BufferMapper.cpp b/libs/ui/BufferMapper.cpp
new file mode 100644
index 0000000..4add8f9
--- /dev/null
+++ b/libs/ui/BufferMapper.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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 "BufferMapper"
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <ui/BufferMapper.h>
+#include <ui/Rect.h>
+
+#include <hardware/gralloc.h>
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE( BufferMapper )
+
+BufferMapper::BufferMapper()
+ : mAllocMod(0)
+{
+ hw_module_t const* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ mAllocMod = (gralloc_module_t const *)module;
+ }
+}
+
+status_t BufferMapper::registerBuffer(buffer_handle_t handle)
+{
+ status_t err = mAllocMod->registerBuffer(mAllocMod, handle);
+ LOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
+ handle, err, strerror(-err));
+ return err;
+}
+
+status_t BufferMapper::unregisterBuffer(buffer_handle_t handle)
+{
+ status_t err = mAllocMod->unregisterBuffer(mAllocMod, handle);
+ LOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)",
+ handle, err, strerror(-err));
+ return err;
+}
+
+status_t BufferMapper::lock(buffer_handle_t handle,
+ int usage, const Rect& bounds, void** vaddr)
+{
+ status_t err = mAllocMod->lock(mAllocMod, handle, usage,
+ bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr);
+ LOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
+ return err;
+}
+
+status_t BufferMapper::unlock(buffer_handle_t handle)
+{
+ status_t err = mAllocMod->unlock(mAllocMod, handle);
+ LOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 5015379..12a7725 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/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
deleted file mode 100644
index d06c98b..0000000
--- a/libs/ui/EGLDisplaySurface.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- **
- ** 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.
- */
-
-#define LOG_TAG "EGLDisplaySurface"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-#include <cutils/properties.h>
-
-#include <hardware/copybit.h>
-
-#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <ui/EGLDisplaySurface.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/msm_mdp.h>
-#endif
-
-#include <EGL/egl.h>
-
-#include <pixelflinger/format.h>
-
-
-// ----------------------------------------------------------------------------
-
-egl_native_window_t* android_createDisplaySurface()
-{
- egl_native_window_t* s = new android::EGLDisplaySurface();
- s->memory_type = NATIVE_MEMORY_TYPE_GPU;
- return s;
-}
-
-#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
-#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-EGLDisplaySurface::EGLDisplaySurface()
- : EGLNativeSurface<EGLDisplaySurface>()
-{
- egl_native_window_t::version = sizeof(egl_native_window_t);
- egl_native_window_t::ident = 0;
- egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
- egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
- egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
- egl_native_window_t::connect = 0;
- egl_native_window_t::disconnect = 0;
-
- mFb[0].data = 0;
- mFb[1].data = 0;
- mBlitEngine = 0;
- egl_native_window_t::fd = mapFrameBuffer();
- if (egl_native_window_t::fd >= 0) {
-
- hw_module_t const* module;
- if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
- copybit_open(module, &mBlitEngine);
- }
-
- const float in2mm = 25.4f;
- float refreshRate = 1000000000000000LLU / (
- float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
- * ( mInfo.left_margin + mInfo.right_margin + mInfo.xres )
- * mInfo.pixclock);
-
- const GGLSurface& buffer = mFb[1 - mIndex];
- egl_native_window_t::width = buffer.width;
- egl_native_window_t::height = buffer.height;
- egl_native_window_t::stride = buffer.stride;
- egl_native_window_t::format = buffer.format;
- egl_native_window_t::base = intptr_t(mFb[0].data);
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
- egl_native_window_t::flags = 0;
- egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width;
- egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height;
- egl_native_window_t::fps = refreshRate;
- egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB;
- // no error, set the magic word
- egl_native_window_t::magic = 0x600913;
- }
- mSwapCount = -1;
- mPageFlipCount = 0;
-}
-
-EGLDisplaySurface::~EGLDisplaySurface()
-{
- magic = 0;
- copybit_close(mBlitEngine);
- mBlitEngine = 0;
- close(egl_native_window_t::fd);
- munmap(mFb[0].data, mSize);
- if (!(mFlags & PAGE_FLIP))
- free((void*)mFb[1].data);
-}
-
-void EGLDisplaySurface::hook_incRef(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->incStrong(that);
-}
-void EGLDisplaySurface::hook_decRef(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->decStrong(that);
-}
-uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- return that->swapBuffers();
-}
-
-void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
-{
- mInfo.reserved[0] = 0x54445055; // "UPDT";
- mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
- mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
-}
-
-uint32_t EGLDisplaySurface::swapBuffers()
-{
-#define SHOW_FPS 0
-#if SHOW_FPS
- nsecs_t now = systemTime();
- if (mSwapCount == -1) {
- mTime = now;
- mSwapCount = 0;
- mSleep = 0;
- } else {
- nsecs_t d = now-mTime;
- if (d >= seconds(1)) {
- double fps = (mSwapCount * double(seconds(1))) / double(d);
- LOGD("%f fps, sleep=%d / frame",
- fps, (int)ns2us(mSleep / mSwapCount));
- mSwapCount = 0;
- mTime = now;
- mSleep = 0;
- } else {
- mSwapCount++;
- }
- }
-#endif
- /* If we can't do the page_flip, just copy the back buffer to the front */
- if (!(mFlags & PAGE_FLIP)) {
- memcpy(mFb[0].data, mFb[1].data, mInfo.xres*mInfo.yres*2);
- return 0;
- }
-
- // do the actual flip
- mIndex = 1 - mIndex;
- mInfo.activate = FB_ACTIVATE_VBL;
- mInfo.yoffset = mIndex ? mInfo.yres : 0;
- if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) {
- LOGE("FBIOPUT_VSCREENINFO failed");
- return 0;
- }
-
- /*
- * this is a monstrous hack: Because the h/w accelerator is not able
- * to render directly into the framebuffer, we need to copy its
- * internal framebuffer out to the fb.
- * oem[0] is used to access the fd of internal fb.
- * All this is needed only in standalone mode, in SurfaceFlinger mode
- * we control where the GPU renders.
- * We do this only if we have copybit, since this hack is needed only
- * with msm7k.
- */
- if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0] && mBlitEngine) {
- copybit_device_t *copybit = mBlitEngine;
- copybit_rect_t sdrect = { 0, 0,
- egl_native_window_t::width, egl_native_window_t::height };
- copybit_image_t dst = {
- egl_native_window_t::width,
- egl_native_window_t::height,
- egl_native_window_t::format,
- egl_native_window_t::offset,
- (void*)egl_native_window_t::base,
- egl_native_window_t::fd
- };
- copybit_image_t src = {
- egl_native_window_t::width,
- egl_native_window_t::height,
- egl_native_window_t::format, // XXX: use proper format
- egl_native_window_t::offset,
- (void*)egl_native_window_t::base, // XXX: use proper base
- egl_native_window_t::oem[0]
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
- copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
- copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
- copybit->stretch(copybit, &dst, &src, &sdrect, &sdrect, &it);
- }
-
- // update the address of the buffer to draw to next
- const GGLSurface& buffer = mFb[1 - mIndex];
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
-
-#if SHOW_FPS
- mSleep += systemTime()-now;
-#endif
-
- mPageFlipCount++;
-
- // We don't support screen-size changes for now
- return 0;
-}
-
-int32_t EGLDisplaySurface::getPageFlipCount() const
-{
- return mPageFlipCount;
-}
-
-void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t dst = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[1-mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(copyback);
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- /* no extra copy needed since we copied back to front instead of
- * flipping */
- if (!(mFlags & PAGE_FLIP)) {
- return;
- }
-
- Region::iterator iterator(copyback);
- if (iterator) {
- Rect r;
- uint8_t* const screen_src = mFb[ mIndex].data;
- uint8_t* const screen_dst = mFb[1-mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- while (iterator.iterate(&r)) {
- ssize_t h = r.bottom - r.top;
- if (h) {
- size_t size = (r.right - r.left) * bpp;
- size_t o = (r.left + egl_native_window_t::stride * r.top) * bpp;
- uint8_t* s = screen_src + o;
- uint8_t* d = screen_dst + o;
- if (size == bpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += bpr;
- s += bpr;
- } while (--h > 0);
- }
- }
- }
- }
-}
-
-void EGLDisplaySurface::copyFrontToImage(const copybit_image_t& dst)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- uint8_t* const screen_src = mFb[ mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- memcpy((char*)dst.base + dst.offset, screen_src,
- bpr*egl_native_window_t::height);
- }
-}
-
-void EGLDisplaySurface::copyBackToImage(const copybit_image_t& dst)
-{
-#if HAVE_ANDROID_OS
- if (mBlitEngine) {
- copybit_image_t src = {
- w: egl_native_window_t::stride,
- h: egl_native_window_t::height,
- format: egl_native_window_t::format,
- offset: mFb[1-mIndex].data - mFb[0].data,
- base: (void*)egl_native_window_t::base,
- fd: egl_native_window_t::fd
- };
- region_iterator it(Region(Rect(
- egl_native_window_t::width, egl_native_window_t::height)));
- mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
- } else
-#endif
- {
- uint8_t* const screen_src = mFb[1-mIndex].data;
- const size_t bpp = bytesPerPixel(egl_native_window_t::format);
- const size_t bpr = egl_native_window_t::stride * bpp;
- memcpy((char*)dst.base + dst.offset, screen_src,
- bpr*egl_native_window_t::height);
- }
-}
-
-
-status_t EGLDisplaySurface::mapFrameBuffer()
-{
- char const * const device_template[] = {
- "/dev/graphics/fb%u",
- "/dev/fb%u",
- 0 };
- int fd = -1;
- int i=0;
- char name[64];
- while ((fd==-1) && device_template[i]) {
- snprintf(name, 64, device_template[i], 0);
- fd = open(name, O_RDWR, 0);
- i++;
- }
- if (fd < 0)
- return -errno;
-
- struct fb_fix_screeninfo finfo;
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- struct fb_var_screeninfo info;
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- info.reserved[0] = 0;
- info.reserved[1] = 0;
- info.reserved[2] = 0;
- info.xoffset = 0;
- info.yoffset = 0;
- info.yres_virtual = info.yres * 2;
- info.bits_per_pixel = 16;
- /* Explicitly request 5/6/5 */
- info.red.offset = 11;
- info.red.length = 5;
- info.green.offset = 5;
- info.green.length = 6;
- info.blue.offset = 0;
- info.blue.length = 5;
- info.transp.offset = 0;
- info.transp.length = 0;
- info.activate = FB_ACTIVATE_NOW;
-
- uint32_t flags = PAGE_FLIP;
- if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
- }
-
- if (info.yres_virtual < info.yres * 2) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
- info.yres_virtual, info.yres*2);
- }
-
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- int refreshRate = 1000000000000000LLU /
- (
- uint64_t( info.upper_margin + info.lower_margin + info.yres )
- * ( info.left_margin + info.right_margin + info.xres )
- * info.pixclock
- );
-
- if (refreshRate == 0) {
- // bleagh, bad info from the driver
- refreshRate = 60*1000; // 60 Hz
- }
- if (int(info.width) <= 0 || int(info.height) <= 0) {
- // the driver doesn't return that information
- // default to 160 dpi
- info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
- info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
- }
-
- float xdpi = (info.xres * 25.4f) / info.width;
- float ydpi = (info.yres * 25.4f) / info.height;
- float fps = refreshRate / 1000.0f;
-
- LOGI( "using (fd=%d)\n"
- "id = %s\n"
- "xres = %d px\n"
- "yres = %d px\n"
- "xres_virtual = %d px\n"
- "yres_virtual = %d px\n"
- "bpp = %d\n"
- "r = %2u:%u\n"
- "g = %2u:%u\n"
- "b = %2u:%u\n",
- fd,
- finfo.id,
- info.xres,
- info.yres,
- info.xres_virtual,
- info.yres_virtual,
- info.bits_per_pixel,
- info.red.offset, info.red.length,
- info.green.offset, info.green.length,
- info.blue.offset, info.blue.length
- );
-
- LOGI( "width = %d mm (%f dpi)\n"
- "height = %d mm (%f dpi)\n"
- "refresh rate = %.2f Hz\n",
- info.width, xdpi,
- info.height, ydpi,
- fps
- );
-
-
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- if (finfo.smem_len <= 0)
- return -errno;
-
- /*
- * Open and map the display.
- */
-
- void* buffer = (uint16_t*) mmap(
- 0, finfo.smem_len,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd, 0);
-
- if (buffer == MAP_FAILED)
- return -errno;
-
- // at least for now, always clear the fb
- memset(buffer, 0, finfo.smem_len);
-
- uint8_t* offscreen[2];
- offscreen[0] = (uint8_t*)buffer;
- if (flags & PAGE_FLIP) {
- offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres;
- } else {
- offscreen[1] = (uint8_t*)malloc(finfo.smem_len);
- if (offscreen[1] == 0) {
- munmap(buffer, finfo.smem_len);
- return NO_MEMORY;
- }
- }
-
- mFlags = flags;
- mInfo = info;
- mFinfo = finfo;
- mSize = finfo.smem_len;
- mIndex = 0;
- for (int i=0 ; i<2 ; i++) {
- mFb[i].version = sizeof(GGLSurface);
- mFb[i].width = info.xres;
- mFb[i].height = info.yres;
- mFb[i].stride = finfo.line_length / (info.bits_per_pixel >> 3);
- mFb[i].data = (GGLubyte*)(offscreen[i]);
- mFb[i].format = GGL_PIXEL_FORMAT_RGB_565;
- }
- return fd;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
deleted file mode 100644
index f1071cf..0000000
--- a/libs/ui/EGLNativeWindowSurface.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
-**
-** 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.
-*/
-
-#define LOG_TAG "EGLNativeWindowSurface"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-
-#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-
-#include <EGL/egl.h>
-
-#include <pixelflinger/format.h>
-
-#include <ui/EGLNativeWindowSurface.h>
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-EGLNativeWindowSurface::EGLNativeWindowSurface(const sp<Surface>& surface)
- : EGLNativeSurface<EGLNativeWindowSurface>(),
- mSurface(surface), mConnected(false)
-{
- egl_native_window_t::magic = 0x600913;
- egl_native_window_t::version = sizeof(egl_native_window_t);
- egl_native_window_t::ident = 0;
- egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef;
- egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef;
- egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers;
- egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect;
- egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect;
-
- DisplayInfo dinfo;
- SurfaceComposerClient::getDisplayInfo(0, &dinfo);
- egl_native_window_t::xdpi = dinfo.xdpi;
- egl_native_window_t::ydpi = dinfo.ydpi;
- egl_native_window_t::fps = dinfo.fps;
- egl_native_window_t::flags= EGL_NATIVES_FLAG_DESTROY_BACKBUFFER;
-}
-
-EGLNativeWindowSurface::~EGLNativeWindowSurface()
-{
- disconnect();
- mSurface.clear();
- magic = 0;
-}
-
-void EGLNativeWindowSurface::hook_incRef(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->incStrong(that);
-}
-
-void EGLNativeWindowSurface::hook_decRef(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->decStrong(that);
-}
-
-void EGLNativeWindowSurface::hook_connect(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->connect();
-}
-
-void EGLNativeWindowSurface::hook_disconnect(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->disconnect();
-}
-
-uint32_t EGLNativeWindowSurface::hook_swapBuffers(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- return that->swapBuffers();
-}
-
-void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h)
-{
- mSurface->setSwapRectangle(Rect(l, t, l+w, t+h));
-}
-
-uint32_t EGLNativeWindowSurface::swapBuffers()
-{
- const int w = egl_native_window_t::width;
- const int h = egl_native_window_t::height;
- const sp<Surface>& surface(mSurface);
- Surface::SurfaceInfo info;
- surface->unlockAndPost();
- surface->lock(&info);
- // update the address of the buffer to draw to next
- egl_native_window_t::base = intptr_t(info.base);
- egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
-
- // update size if it changed
- if (w != int(info.w) || h != int(info.h)) {
- egl_native_window_t::width = info.w;
- egl_native_window_t::height = info.h;
- egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
- egl_native_window_t::format = info.format;
- return EGL_NATIVES_FLAG_SIZE_CHANGED;
- }
- return 0;
-}
-
-void EGLNativeWindowSurface::connect()
-{
- if (!mConnected) {
- Surface::SurfaceInfo info;
- mSurface->lock(&info);
- mSurface->setSwapRectangle(Rect(info.w, info.h));
- mConnected = true;
-
- egl_native_window_t::width = info.w;
- egl_native_window_t::height = info.h;
- egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
- egl_native_window_t::format = info.format;
- egl_native_window_t::base = intptr_t(info.base);
- egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
- // FIXME: egl_native_window_t::memory_type used to be set from
- // mSurface, but we wanted to break this dependency. We set it to
- // GPU because the software rendered doesn't care, but the h/w
- // accelerator needs it. Eventually, this value should go away
- // completely, since memory will be managed by OpenGL.
- egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_GPU;
- egl_native_window_t::fd = 0;
- }
-}
-
-void EGLNativeWindowSurface::disconnect()
-{
- if (mConnected) {
- mSurface->unlock();
- mConnected = false;
- }
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp
new file mode 100644
index 0000000..1663313
--- /dev/null
+++ b/libs/ui/EGLUtils.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+
+#define LOG_TAG "EGLUtils"
+
+#include <cutils/log.h>
+#include <utils/Errors.h>
+
+#include <ui/EGLUtils.h>
+
+#include <EGL/egl.h>
+
+#include <private/ui/android_natives_priv.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+const char *EGLUtils::strerror(EGLint err)
+{
+ switch (err){
+ case EGL_SUCCESS: return "EGL_SUCCESS";
+ case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
+ case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
+ case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
+ case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
+ case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
+ case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
+ default: return "UNKNOWN";
+ }
+}
+
+status_t EGLUtils::selectConfigForPixelFormat(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ PixelFormat format,
+ EGLConfig* outConfig)
+{
+ EGLint numConfigs = -1, n=0;
+
+ if (!attrs)
+ return BAD_VALUE;
+
+ if (outConfig == NULL)
+ return BAD_VALUE;
+
+ int err;
+ PixelFormatInfo fbFormatInfo;
+ if ((err = getPixelFormatInfo(PixelFormat(format), &fbFormatInfo)) < 0) {
+ return err;
+ }
+
+ // Get all the "potential match" configs...
+ if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
+ return BAD_VALUE;
+
+ EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
+ if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
+ free(configs);
+ return BAD_VALUE;
+ }
+
+ const int fbSzA = fbFormatInfo.getSize(PixelFormatInfo::INDEX_ALPHA);
+ const int fbSzR = fbFormatInfo.getSize(PixelFormatInfo::INDEX_RED);
+ const int fbSzG = fbFormatInfo.getSize(PixelFormatInfo::INDEX_GREEN);
+ const int fbSzB = fbFormatInfo.getSize(PixelFormatInfo::INDEX_BLUE);
+
+ int i;
+ EGLConfig config = NULL;
+ for (i=0 ; i<n ; i++) {
+ EGLint r,g,b,a;
+ EGLConfig curr = configs[i];
+ eglGetConfigAttrib(dpy, curr, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(dpy, curr, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(dpy, curr, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(dpy, curr, EGL_ALPHA_SIZE, &a);
+ if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB == b) {
+ config = curr;
+ break;
+ }
+ }
+
+ free(configs);
+
+ if (i<n) {
+ *outConfig = config;
+ return NO_ERROR;
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+status_t EGLUtils::selectConfigForNativeWindow(
+ EGLDisplay dpy,
+ EGLint const* attrs,
+ EGLNativeWindowType window,
+ EGLConfig* outConfig)
+{
+ int err;
+ int format;
+
+ if (!window)
+ return BAD_VALUE;
+
+ if ((err = window->query(window, NATIVE_WINDOW_FORMAT, &format)) < 0) {
+ return err;
+ }
+
+ return selectConfigForPixelFormat(dpy, attrs, format, outConfig);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 7c2fc8e..60c177b 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -16,13 +16,14 @@
//#define LOG_NDEBUG 0
#include <ui/EventHub.h>
+#include <ui/KeycodeLabels.h>
#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/Errors.h>
#include <stdlib.h>
#include <stdio.h>
@@ -58,6 +59,18 @@
#define SEQ_SHIFT 16
#define id_to_index(id) ((id&ID_MASK)+1)
+#ifndef ABS_MT_TOUCH_MAJOR
+#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
+#endif
+
+#ifndef ABS_MT_POSITION_X
+#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
+#endif
+
+#ifndef ABS_MT_POSITION_Y
+#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
+#endif
+
namespace android {
static const char *WAKE_LOCK_ID = "KeyEvents";
@@ -69,8 +82,8 @@ static inline int max(int v1, int v2)
return (v1 > v2) ? v1 : v2;
}
-EventHub::device_t::device_t(int32_t _id, const char* _path)
- : id(_id), path(_path), classes(0)
+EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
+ : id(_id), path(_path), name(name), classes(0)
, keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
}
@@ -83,7 +96,7 @@ EventHub::EventHub(void)
: mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
, mDevicesById(0), mNumDevicesById(0)
, mOpeningDevices(0), mClosingDevices(0)
- , mDevices(0), mFDs(0), mFDCount(0)
+ , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
{
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
#ifdef EV_SW
@@ -100,11 +113,6 @@ EventHub::~EventHub(void)
// we should free stuff here...
}
-void EventHub::onFirstRef()
-{
- mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
-}
-
status_t EventHub::errorCheck() const
{
return mError;
@@ -239,6 +247,41 @@ int EventHub::getKeycodeState(int32_t deviceId, int code) const
return 0;
}
+status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
+ int32_t* outKeycode, uint32_t* outFlags) const
+{
+ AutoMutex _l(mLock);
+ device_t* device = getDevice(deviceId);
+
+ if (device != NULL && device->layoutMap != NULL) {
+ status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+
+ if (mHaveFirstKeyboard) {
+ device = getDevice(mFirstKeyboardId);
+
+ if (device != NULL && device->layoutMap != NULL) {
+ status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+ }
+
+ *outKeycode = 0;
+ *outFlags = 0;
+ return NAME_NOT_FOUND;
+}
+
+void EventHub::addExcludedDevice(const char* deviceName)
+{
+ String8 name(deviceName);
+ mExcludedDevices.push_back(name);
+}
+
EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
{
if (deviceId == 0) deviceId = mFirstKeyboardId;
@@ -276,7 +319,12 @@ bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
// Note that we only allow one caller to getEvent(), so don't need
// to do locking here... only when adding/removing devices.
-
+
+ if (!mOpened) {
+ mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
+ mOpened = true;
+ }
+
while(1) {
// First, report any devices that had last been added/removed.
@@ -474,6 +522,20 @@ int EventHub::open_device(const char *deviceName)
//fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
name[0] = '\0';
}
+
+ // check to see if the device is on our excluded list
+ List<String8>::iterator iter = mExcludedDevices.begin();
+ List<String8>::iterator end = mExcludedDevices.end();
+ for ( ; iter != end; iter++) {
+ const char* test = *iter;
+ if (strcmp(name, test) == 0) {
+ LOGI("ignoring event id %s driver %s\n", deviceName, test);
+ close(fd);
+ fd = -1;
+ return -1;
+ }
+ }
+
if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
//fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
location[0] = '\0';
@@ -531,7 +593,7 @@ int EventHub::open_device(const char *deviceName)
version >> 16, (version >> 8) & 0xff, version & 0xff);
#endif
- device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName);
+ device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
if (device == NULL) {
LOGE("out of memory");
return -1;
@@ -541,6 +603,8 @@ int EventHub::open_device(const char *deviceName)
mFDs[mFDCount].events = POLLIN;
// figure out the kinds of events the device reports
+
+ // See if this is a keyboard, and classify it.
uint8_t key_bitmask[(KEY_MAX+1)/8];
memset(key_bitmask, 0, sizeof(key_bitmask));
LOGV("Getting keys...");
@@ -552,15 +616,11 @@ int EventHub::open_device(const char *deviceName)
for (int i=0; i<((BTN_MISC+7)/8); i++) {
if (key_bitmask[i] != 0) {
device->classes |= CLASS_KEYBOARD;
- // 'Q' key support = cheap test of whether this is an alpha-capable kbd
- if (test_bit(KEY_Q, key_bitmask)) {
- device->classes |= CLASS_ALPHAKEY;
- }
break;
}
}
if ((device->classes & CLASS_KEYBOARD) != 0) {
- device->keyBitmask = new uint8_t[(KEY_MAX+1)/8];
+ device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
if (device->keyBitmask != NULL) {
memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
} else {
@@ -570,6 +630,8 @@ int EventHub::open_device(const char *deviceName)
}
}
}
+
+ // See if this is a trackball.
if (test_bit(BTN_MOUSE, key_bitmask)) {
uint8_t rel_bitmask[(REL_MAX+1)/8];
memset(rel_bitmask, 0, sizeof(rel_bitmask));
@@ -581,16 +643,22 @@ int EventHub::open_device(const char *deviceName)
}
}
}
- if (test_bit(BTN_TOUCH, key_bitmask)) {
- uint8_t abs_bitmask[(ABS_MAX+1)/8];
- memset(abs_bitmask, 0, sizeof(abs_bitmask));
- LOGV("Getting absolute controllers...");
- if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0)
- {
- if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
- device->classes |= CLASS_TOUCHSCREEN;
- }
- }
+
+ uint8_t abs_bitmask[(ABS_MAX+1)/8];
+ memset(abs_bitmask, 0, sizeof(abs_bitmask));
+ LOGV("Getting absolute controllers...");
+ ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
+
+ // Is this a new modern multi-touch driver?
+ if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
+ && test_bit(ABS_MT_POSITION_X, abs_bitmask)
+ && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
+ device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;
+
+ // Is this an old style single-touch driver?
+ } else if (test_bit(BTN_TOUCH, key_bitmask)
+ && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
+ device->classes |= CLASS_TOUCHSCREEN;
}
#ifdef EV_SW
@@ -609,21 +677,15 @@ int EventHub::open_device(const char *deviceName)
}
#endif
- LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
- deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
-
if ((device->classes&CLASS_KEYBOARD) != 0) {
- char devname[101];
- char tmpfn[101];
+ char tmpfn[sizeof(name)];
char keylayoutFilename[300];
// a more descriptive name
- ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
- devname[sizeof(devname)-1] = 0;
- device->name = devname;
+ device->name = name;
// replace all the spaces with underscores
- strcpy(tmpfn, devname);
+ strcpy(tmpfn, name);
for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
*p = '_';
@@ -656,12 +718,29 @@ int EventHub::open_device(const char *deviceName)
}
char propName[100];
sprintf(propName, "hw.keyboards.%u.devname", publicID);
- property_set(propName, devname);
+ property_set(propName, name);
- LOGI("New keyboard: publicID=%d device->id=%d devname='%s' propName='%s' keylayout='%s'\n",
- publicID, device->id, devname, propName, keylayoutFilename);
+ // 'Q' key support = cheap test of whether this is an alpha-capable kbd
+ if (hasKeycode(device, kKeyCodeQ)) {
+ device->classes |= CLASS_ALPHAKEY;
+ }
+
+ // See if this has a DPAD.
+ if (hasKeycode(device, kKeyCodeDpadUp) &&
+ hasKeycode(device, kKeyCodeDpadDown) &&
+ hasKeycode(device, kKeyCodeDpadLeft) &&
+ hasKeycode(device, kKeyCodeDpadRight) &&
+ hasKeycode(device, kKeyCodeDpadCenter)) {
+ device->classes |= CLASS_DPAD;
+ }
+
+ LOGI("New keyboard: publicID=%d device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
+ publicID, device->id, name, propName, keylayoutFilename);
}
+ LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
+ deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
+
LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
deviceName, device, mFDCount, devid, device->classes);
@@ -674,6 +753,25 @@ int EventHub::open_device(const char *deviceName)
return 0;
}
+bool EventHub::hasKeycode(device_t* device, int keycode) const
+{
+ if (device->keyBitmask == NULL || device->layoutMap == NULL) {
+ return false;
+ }
+
+ Vector<int32_t> scanCodes;
+ device->layoutMap->findScancodes(keycode, &scanCodes);
+ const size_t N = scanCodes.size();
+ for (size_t i=0; i<N && i<=KEY_MAX; i++) {
+ int32_t sc = scanCodes.itemAt(i);
+ if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
int EventHub::close_device(const char *deviceName)
{
AutoMutex _l(mLock);
@@ -686,6 +784,7 @@ int EventHub::close_device(const char *deviceName)
int count = mFDCount - i - 1;
int index = (device->id&ID_MASK);
mDevicesById[index].device = NULL;
+ close(mFDs[i].fd);
memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
@@ -733,6 +832,7 @@ int EventHub::read_notify(int nfd)
int event_pos = 0;
struct inotify_event *event;
+LOGD("EventHub::read_notify nfd: %d\n", nfd);
res = read(nfd, event_buf, sizeof(event_buf));
if(res < (int)sizeof(*event)) {
if(errno == EINTR)
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
new file mode 100644
index 0000000..90b5163
--- /dev/null
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -0,0 +1,267 @@
+/*
+**
+** 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.
+*/
+
+#define LOG_TAG "FramebufferNativeWindow"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/Rect.h>
+#include <ui/FramebufferNativeWindow.h>
+
+#include <EGL/egl.h>
+
+#include <pixelflinger/format.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+#include <private/ui/android_natives_priv.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class NativeBuffer
+ : public EGLNativeBase<
+ android_native_buffer_t,
+ NativeBuffer,
+ LightRefBase<NativeBuffer> >
+{
+public:
+ NativeBuffer(int w, int h, int f, int u) : BASE() {
+ android_native_buffer_t::width = w;
+ android_native_buffer_t::height = h;
+ android_native_buffer_t::format = f;
+ android_native_buffer_t::usage = u;
+ }
+private:
+ friend class LightRefBase<NativeBuffer>;
+ ~NativeBuffer() { }; // this class cannot be overloaded
+};
+
+
+/*
+ * This implements the (main) framebuffer management. This class is used
+ * mostly by SurfaceFlinger, but also by command line GL application.
+ *
+ * In fact this is an implementation of android_native_window_t on top of
+ * the framebuffer.
+ *
+ * Currently it is pretty simple, it manages only two buffers (the front and
+ * back buffer).
+ *
+ */
+
+FramebufferNativeWindow::FramebufferNativeWindow()
+ : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
+{
+ hw_module_t const* module;
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
+ int stride;
+ int err;
+ err = framebuffer_open(module, &fbDev);
+ LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
+
+ err = gralloc_open(module, &grDev);
+ LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
+
+ // bail out if we can't initialize the modules
+ if (!fbDev || !grDev)
+ return;
+
+ mUpdateOnDemand = (fbDev->setUpdateRect != 0);
+
+ // initialize the buffer FIFO
+ mNumBuffers = 2;
+ mNumFreeBuffers = 2;
+ mBufferHead = mNumBuffers-1;
+ buffers[0] = new NativeBuffer(
+ fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
+ buffers[1] = new NativeBuffer(
+ fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
+
+ err = grDev->alloc(grDev,
+ fbDev->width, fbDev->height, fbDev->format,
+ GRALLOC_USAGE_HW_FB, &buffers[0]->handle, &buffers[0]->stride);
+
+ LOGE_IF(err, "fb buffer 0 allocation failed w=%d, h=%d, err=%s",
+ fbDev->width, fbDev->height, strerror(-err));
+
+ err = grDev->alloc(grDev,
+ fbDev->width, fbDev->height, fbDev->format,
+ GRALLOC_USAGE_HW_FB, &buffers[1]->handle, &buffers[1]->stride);
+
+ LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s",
+ fbDev->width, fbDev->height, strerror(-err));
+ }
+
+ const_cast<uint32_t&>(android_native_window_t::flags) = fbDev->flags;
+ const_cast<float&>(android_native_window_t::xdpi) = fbDev->xdpi;
+ const_cast<float&>(android_native_window_t::ydpi) = fbDev->ydpi;
+ const_cast<int&>(android_native_window_t::minSwapInterval) =
+ fbDev->minSwapInterval;
+ const_cast<int&>(android_native_window_t::maxSwapInterval) =
+ fbDev->maxSwapInterval;
+
+ android_native_window_t::setSwapInterval = setSwapInterval;
+ android_native_window_t::dequeueBuffer = dequeueBuffer;
+ android_native_window_t::lockBuffer = lockBuffer;
+ android_native_window_t::queueBuffer = queueBuffer;
+ android_native_window_t::query = query;
+ android_native_window_t::perform = perform;
+}
+
+FramebufferNativeWindow::~FramebufferNativeWindow()
+{
+ if (grDev) {
+ if (buffers[0] != NULL)
+ grDev->free(grDev, buffers[0]->handle);
+ if (buffers[1] != NULL)
+ grDev->free(grDev, buffers[1]->handle);
+ gralloc_close(grDev);
+ }
+
+ if (fbDev) {
+ framebuffer_close(fbDev);
+ }
+}
+
+status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r)
+{
+ if (!mUpdateOnDemand) {
+ return INVALID_OPERATION;
+ }
+ return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
+}
+
+int FramebufferNativeWindow::setSwapInterval(
+ android_native_window_t* window, int interval)
+{
+ framebuffer_device_t* fb = getSelf(window)->fbDev;
+ return fb->setSwapInterval(fb, interval);
+}
+
+int FramebufferNativeWindow::dequeueBuffer(android_native_window_t* window,
+ android_native_buffer_t** buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+
+ // wait for a free buffer
+ while (!self->mNumFreeBuffers) {
+ self->mCondition.wait(self->mutex);
+ }
+ // get this buffer
+ self->mNumFreeBuffers--;
+ int index = self->mBufferHead++;
+ if (self->mBufferHead >= self->mNumBuffers)
+ self->mBufferHead = 0;
+
+ *buffer = self->buffers[index].get();
+
+ return 0;
+}
+
+int FramebufferNativeWindow::lockBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+
+ // wait that the buffer we're locking is not front anymore
+ while (self->front == buffer) {
+ self->mCondition.wait(self->mutex);
+ }
+
+ return NO_ERROR;
+}
+
+int FramebufferNativeWindow::queueBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+ buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
+ int res = fb->post(fb, handle);
+ self->front = static_cast<NativeBuffer*>(buffer);
+ self->mNumFreeBuffers++;
+ self->mCondition.broadcast();
+ return res;
+}
+
+int FramebufferNativeWindow::query(android_native_window_t* window,
+ int what, int* value)
+{
+ FramebufferNativeWindow* self = getSelf(window);
+ Mutex::Autolock _l(self->mutex);
+ framebuffer_device_t* fb = self->fbDev;
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ *value = fb->width;
+ return NO_ERROR;
+ case NATIVE_WINDOW_HEIGHT:
+ *value = fb->height;
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = fb->format;
+ return NO_ERROR;
+ }
+ *value = 0;
+ return BAD_VALUE;
+}
+
+int FramebufferNativeWindow::perform(android_native_window_t* window,
+ int operation, ...)
+{
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ break;
+ default:
+ return NAME_NOT_FOUND;
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+EGLNativeWindowType android_createDisplaySurface(void)
+{
+ FramebufferNativeWindow* w;
+ w = new FramebufferNativeWindow();
+ if (w->getDevice() == NULL) {
+ // get a ref so it can be destroyed when we exit this block
+ sp<FramebufferNativeWindow> ref(w);
+ return NULL;
+ }
+ return (EGLNativeWindowType)w;
+}
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 59a6cf2..42b4da4 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -78,12 +78,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..b78e8b5 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -14,19 +14,25 @@
* limitations under the License.
*/
+#define LOG_TAG "ISurface"
+
#include <stdio.h>
#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>
+#include <ui/Surface.h>
+#include <private/ui/SurfaceBuffer.h>
namespace android {
+// ----------------------------------------------------------------------
+
ISurface::BufferHeap::BufferHeap()
: w(0), h(0), hor_stride(0), ver_stride(0), format(0),
transform(0), flags(0)
@@ -55,6 +61,8 @@ ISurface::BufferHeap::~BufferHeap()
{
}
+// ----------------------------------------------------------------------
+
class BpSurface : public BpInterface<ISurface>
{
public:
@@ -63,6 +71,16 @@ public:
{
}
+ virtual sp<SurfaceBuffer> getBuffer(int usage)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ data.writeInt32(usage);
+ remote()->transact(GET_BUFFER, data, &reply);
+ sp<SurfaceBuffer> buffer = new SurfaceBuffer(reply);
+ return buffer;
+ }
+
virtual status_t registerBuffers(const BufferHeap& buffers)
{
Parcel data, reply;
@@ -112,16 +130,16 @@ 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)
{
switch(code) {
+ case GET_BUFFER: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ int usage = data.readInt32();
+ sp<SurfaceBuffer> buffer(getBuffer(usage));
+ return SurfaceBuffer::writeToParcel(reply, buffer.get());
+ }
case REGISTER_BUFFERS: {
CHECK_INTERFACE(ISurface, data, reply);
BufferHeap buffer;
diff --git a/libs/ui/ISurfaceComposer.cpp b/libs/ui/ISurfaceComposer.cpp
index 76597e1..fd2a590 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>
@@ -54,12 +54,12 @@ public:
return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder());
}
- virtual sp<IMemory> getCblk() const
+ virtual sp<IMemoryHeap> getCblk() const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::GET_CBLK, data, &reply);
- return interface_cast<IMemory>(reply.readStrongBinder());
+ return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
virtual void openGlobalTransaction()
@@ -114,36 +114,6 @@ public:
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
}
- virtual status_t requestGPU(
- const sp<IGPUCallback>& callback, gpu_info_t* gpu)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(callback->asBinder());
- remote()->transact(BnSurfaceComposer::REQUEST_GPU, data, &reply);
- gpu->regs = interface_cast<IMemory>(reply.readStrongBinder());
- gpu->count = reply.readInt32();
-
- // FIXME: for now, we don't dynamically allocate the regions array
- size_t maxCount = sizeof(gpu->regions)/sizeof(*gpu->regions);
- if (gpu->count > maxCount)
- return BAD_VALUE;
-
- for (size_t i=0 ; i<gpu->count ; i++) {
- gpu->regions[i].region = interface_cast<IMemory>(reply.readStrongBinder());
- gpu->regions[i].reserved = reply.readInt32();
- }
- return reply.readInt32();
- }
-
- virtual status_t revokeGPU()
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::REVOKE_GPU, data, &reply);
- return reply.readInt32();
- }
-
virtual void signal() const
{
Parcel data, reply;
@@ -156,124 +126,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: {
- 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: {
- // TODO: this should be protected by a permission
- gpu_info_t info;
- sp<IGPUCallback> callback
- = interface_cast<IGPUCallback>(data.readStrongBinder());
- status_t res = requestGPU(callback, &info);
-
- // FIXME: for now, we don't dynamically allocate the regions array
- size_t maxCount = sizeof(info.regions)/sizeof(*info.regions);
- if (info.count > maxCount)
- return BAD_VALUE;
-
- reply->writeStrongBinder(info.regs->asBinder());
- reply->writeInt32(info.count);
- for (size_t i=0 ; i<info.count ; i++) {
- reply->writeStrongBinder(info.regions[i].region->asBinder());
- reply->writeInt32(info.regions[i].reserved);
- }
- reply->writeInt32(res);
- } break;
default:
- return UNKNOWN_TRANSACTION;
+ return BBinder::onTransact(code, data, reply, flags);
}
return NO_ERROR;
}
// ----------------------------------------------------------------------------
-enum {
- // Note: BOOT_FINISHED must remain this value, it is called by ActivityManagerService.
- GPU_LOST = IBinder::FIRST_CALL_TRANSACTION
-};
-
-class BpGPUCallback : public BpInterface<IGPUCallback>
-{
-public:
- BpGPUCallback(const sp<IBinder>& impl)
- : BpInterface<IGPUCallback>(impl)
- {
- }
-
- virtual void gpuLost()
- {
- Parcel data, reply;
- data.writeInterfaceToken(IGPUCallback::getInterfaceDescriptor());
- remote()->transact(GPU_LOST, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(GPUCallback, "android.ui.IGPUCallback");
-
-status_t BnGPUCallback::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case GPU_LOST: {
- CHECK_INTERFACE(IGPUCallback, data, reply);
- gpuLost();
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
};
diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp
index dab5f71..4a6a1d7 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>
@@ -64,12 +64,12 @@ public:
{
}
- virtual void getControlBlocks(sp<IMemory>* ctl) const
+ virtual sp<IMemoryHeap> getControlBlock() const
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor());
remote()->transact(GET_CBLK, data, &reply);
- *ctl = interface_cast<IMemory>(reply.readStrongBinder());
+ return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
virtual sp<ISurface> createSurface( surface_data_t* params,
@@ -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)
{
@@ -132,8 +126,7 @@ status_t BnSurfaceFlingerClient::onTransact(
switch(code) {
case GET_CBLK: {
CHECK_INTERFACE(ISurfaceFlingerClient, data, reply);
- sp<IMemory> ctl;
- getControlBlocks(&ctl);
+ sp<IMemoryHeap> ctl(getControlBlock());
reply->writeStrongBinder(ctl->asBinder());
return NO_ERROR;
} break;
@@ -196,10 +189,11 @@ status_t BnSurfaceFlingerClient::onTransact(
status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel)
{
- token = parcel.readInt32();
- identity = parcel.readInt32();
- heap[0] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
- heap[1] = interface_cast<IMemoryHeap>(parcel.readStrongBinder());
+ token = parcel.readInt32();
+ identity = parcel.readInt32();
+ width = parcel.readInt32();
+ height = parcel.readInt32();
+ format = parcel.readInt32();
return NO_ERROR;
}
@@ -207,8 +201,9 @@ status_t ISurfaceFlingerClient::surface_data_t::writeToParcel(Parcel* parcel) co
{
parcel->writeInt32(token);
parcel->writeInt32(identity);
- parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
- parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
+ parcel->writeInt32(format);
return NO_ERROR;
}
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..3aa8950 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>
@@ -59,6 +59,30 @@ status_t Overlay::queueBuffer(overlay_buffer_t buffer)
return mOverlayData->queueBuffer(mOverlayData, buffer);
}
+status_t Overlay::resizeInput(uint32_t width, uint32_t height)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->resizeInput(mOverlayData, width, height);
+}
+
+status_t Overlay::setParameter(int param, int value)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->setParameter(mOverlayData, param, value);
+}
+
+status_t Overlay::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->setCrop(mOverlayData, x, y, w, h);
+}
+
+status_t Overlay::getCrop(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
+{
+ if (mStatus != NO_ERROR) return mStatus;
+ return mOverlayData->getCrop(mOverlayData, x, y, w, h);
+}
+
int32_t Overlay::getBufferCount() const
{
if (mStatus != NO_ERROR) return mStatus;
@@ -73,6 +97,15 @@ void* Overlay::getBufferAddress(overlay_buffer_t buffer)
void Overlay::destroy() {
if (mStatus != NO_ERROR) return;
+
+ // Must delete the objects in reverse creation order, thus the
+ // data side must be closed first and then the destroy send to
+ // the control side.
+ if (mOverlayData) {
+ overlay_data_close(mOverlayData);
+ mOverlayData = NULL;
+ }
+
mOverlayRef->mOverlayChannel->destroy();
}
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 26e694a..d21ed57 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -16,295 +16,661 @@
#define LOG_TAG "Region"
-#include <stdio.h>
-#include <utils/Atomic.h>
-#include <utils/Debug.h>
+#include <limits.h>
+
+#include <utils/Log.h>
#include <utils/String8.h>
+
+#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/Point.h>
+
+#include <private/ui/RegionHelper.h>
+
+// ----------------------------------------------------------------------------
+#define VALIDATE_REGIONS (false)
+#define VALIDATE_WITH_CORECG (false)
+// ----------------------------------------------------------------------------
+
+#if VALIDATE_WITH_CORECG
+#include <core/SkRegion.h>
+#endif
namespace android {
+// ----------------------------------------------------------------------------
+
+enum {
+ op_nand = region_operator<Rect>::op_nand,
+ op_and = region_operator<Rect>::op_and,
+ op_or = region_operator<Rect>::op_or,
+ op_xor = region_operator<Rect>::op_xor
+};
// ----------------------------------------------------------------------------
Region::Region()
+ : mBounds(0,0)
{
}
Region::Region(const Region& rhs)
- : mRegion(rhs.mRegion)
-{
-}
-
-Region::Region(const SkRegion& rhs)
- : mRegion(rhs)
-{
-}
-
-Region::~Region()
+ : mBounds(rhs.mBounds), mStorage(rhs.mStorage)
{
}
Region::Region(const Rect& rhs)
+ : mBounds(rhs)
{
- set(rhs);
}
Region::Region(const Parcel& parcel)
{
- read(parcel);
+ status_t err = read(parcel);
+ LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
}
Region::Region(const void* buffer)
{
- read(buffer);
+ status_t err = read(buffer);
+ LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
}
-Region& Region::operator = (const Region& rhs)
+Region::~Region()
{
- mRegion = rhs.mRegion;
- return *this;
}
-const SkRegion& Region::toSkRegion() const
+Region& Region::operator = (const Region& rhs)
{
- return mRegion;
+#if VALIDATE_REGIONS
+ validate(rhs, "operator=");
+#endif
+ mBounds = rhs.mBounds;
+ mStorage = rhs.mStorage;
+ return *this;
}
-Rect Region::bounds() const
+Region& Region::makeBoundsSelf()
{
- const SkIRect& b(mRegion.getBounds());
- return Rect(b.fLeft, b.fTop, b.fRight, b.fBottom);
+ mStorage.clear();
+ return *this;
}
void Region::clear()
{
- mRegion.setEmpty();
+ mBounds.clear();
+ mStorage.clear();
}
void Region::set(const Rect& r)
{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.setRect(ir);
+ mBounds = r;
+ mStorage.clear();
+}
+
+void Region::set(uint32_t w, uint32_t h)
+{
+ mBounds = Rect(int(w), int(h));
+ mStorage.clear();
}
// ----------------------------------------------------------------------------
-Region& Region::orSelf(const Rect& r)
+void Region::addRectUnchecked(int l, int t, int r, int b)
{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.op(ir, SkRegion::kUnion_Op);
- return *this;
+ mStorage.add(Rect(l,t,r,b));
+#if VALIDATE_REGIONS
+ validate(*this, "addRectUnchecked");
+#endif
}
-Region& Region::andSelf(const Rect& r)
-{
- SkIRect ir;
- ir.set(r.left, r.top, r.right, r.bottom);
- mRegion.op(ir, SkRegion::kIntersect_Op);
+// ----------------------------------------------------------------------------
+
+Region& Region::orSelf(const Rect& r) {
+ return operationSelf(r, op_or);
+}
+Region& Region::andSelf(const Rect& r) {
+ return operationSelf(r, op_and);
+}
+Region& Region::subtractSelf(const Rect& r) {
+ return operationSelf(r, op_nand);
+}
+Region& Region::operationSelf(const Rect& r, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, r);
return *this;
}
// ----------------------------------------------------------------------------
Region& Region::orSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kUnion_Op);
- return *this;
+ return operationSelf(rhs, op_or);
}
-
Region& Region::andSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kIntersect_Op);
- return *this;
+ return operationSelf(rhs, op_and);
}
-
Region& Region::subtractSelf(const Region& rhs) {
- mRegion.op(rhs.mRegion, SkRegion::kDifference_Op);
+ return operationSelf(rhs, op_nand);
+}
+Region& Region::operationSelf(const Region& rhs, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, rhs);
return *this;
}
Region& Region::translateSelf(int x, int y) {
- if (x|y) mRegion.translate(x, y);
+ if (x|y) translate(*this, x, y);
return *this;
}
-Region Region::merge(const Region& rhs) const {
- Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kUnion_Op);
- return result;
-}
+// ----------------------------------------------------------------------------
-Region Region::intersect(const Region& rhs) const {
+const Region Region::merge(const Rect& rhs) const {
+ return operation(rhs, op_or);
+}
+const Region Region::intersect(const Rect& rhs) const {
+ return operation(rhs, op_and);
+}
+const Region Region::subtract(const Rect& rhs) const {
+ return operation(rhs, op_nand);
+}
+const Region Region::operation(const Rect& rhs, int op) const {
Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kIntersect_Op);
+ boolean_operation(op, result, *this, rhs);
return result;
}
-Region Region::subtract(const Region& rhs) const {
+// ----------------------------------------------------------------------------
+
+const Region Region::merge(const Region& rhs) const {
+ return operation(rhs, op_or);
+}
+const Region Region::intersect(const Region& rhs) const {
+ return operation(rhs, op_and);
+}
+const Region Region::subtract(const Region& rhs) const {
+ return operation(rhs, op_nand);
+}
+const Region Region::operation(const Region& rhs, int op) const {
Region result;
- result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kDifference_Op);
+ boolean_operation(op, result, *this, rhs);
return result;
}
-Region Region::translate(int x, int y) const {
+const Region Region::translate(int x, int y) const {
Region result;
- mRegion.translate(x, y, &result.mRegion);
+ translate(result, *this, x, y);
return result;
}
// ----------------------------------------------------------------------------
Region& Region::orSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kUnion_Op);
- return *this;
+ return operationSelf(rhs, dx, dy, op_or);
}
-
Region& Region::andSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kIntersect_Op);
- return *this;
+ return operationSelf(rhs, dx, dy, op_and);
}
-
Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- mRegion.op(r, SkRegion::kDifference_Op);
+ return operationSelf(rhs, dx, dy, op_nand);
+}
+Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
+ Region lhs(*this);
+ boolean_operation(op, *this, lhs, rhs, dx, dy);
return *this;
}
-Region Region::merge(const Region& rhs, int dx, int dy) const {
+// ----------------------------------------------------------------------------
+
+const Region Region::merge(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_or);
+}
+const Region Region::intersect(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_and);
+}
+const Region Region::subtract(const Region& rhs, int dx, int dy) const {
+ return operation(rhs, dx, dy, op_nand);
+}
+const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kUnion_Op);
+ boolean_operation(op, result, *this, rhs, dx, dy);
return result;
}
-Region Region::intersect(const Region& rhs, int dx, int dy) const {
- Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kIntersect_Op);
+// ----------------------------------------------------------------------------
+
+// This is our region rasterizer, which merges rects and spans together
+// to obtain an optimal region.
+class Region::rasterizer : public region_operator<Rect>::region_rasterizer
+{
+ Rect& bounds;
+ Vector<Rect>& storage;
+ Rect* head;
+ Rect* tail;
+ Vector<Rect> span;
+ Rect* cur;
+public:
+ rasterizer(Region& reg)
+ : bounds(reg.mBounds), storage(reg.mStorage), head(), tail(), cur() {
+ bounds.top = bounds.bottom = 0;
+ bounds.left = INT_MAX;
+ bounds.right = INT_MIN;
+ storage.clear();
+ }
+
+ ~rasterizer() {
+ if (span.size()) {
+ flushSpan();
+ }
+ if (storage.size()) {
+ bounds.top = storage.itemAt(0).top;
+ bounds.bottom = storage.top().bottom;
+ if (storage.size() == 1) {
+ storage.clear();
+ }
+ } else {
+ bounds.left = 0;
+ bounds.right = 0;
+ }
+ }
+
+ virtual void operator()(const Rect& rect) {
+ //LOGD(">>> %3d, %3d, %3d, %3d",
+ // rect.left, rect.top, rect.right, rect.bottom);
+ if (span.size()) {
+ if (cur->top != rect.top) {
+ flushSpan();
+ } else if (cur->right == rect.left) {
+ cur->right = rect.right;
+ return;
+ }
+ }
+ span.add(rect);
+ cur = span.editArray() + (span.size() - 1);
+ }
+private:
+ template<typename T>
+ static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
+ template<typename T>
+ static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
+ void flushSpan() {
+ bool merge = false;
+ if (tail-head == ssize_t(span.size())) {
+ Rect const* p = cur;
+ Rect const* q = head;
+ if (p->top == q->bottom) {
+ merge = true;
+ while (q != tail) {
+ if ((p->left != q->left) || (p->right != q->right)) {
+ merge = false;
+ break;
+ }
+ p++, q++;
+ }
+ }
+ }
+ if (merge) {
+ const int bottom = span[0].bottom;
+ Rect* r = head;
+ while (r != tail) {
+ r->bottom = bottom;
+ r++;
+ }
+ } else {
+ bounds.left = min(span.itemAt(0).left, bounds.left);
+ bounds.right = max(span.top().right, bounds.right);
+ storage.appendVector(span);
+ tail = storage.editArray() + storage.size();
+ head = tail - span.size();
+ }
+ span.clear();
+ }
+};
+
+bool Region::validate(const Region& reg, const char* name)
+{
+ bool result = true;
+ const_iterator cur = reg.begin();
+ const_iterator const tail = reg.end();
+ const_iterator prev = cur++;
+ Rect b(*prev);
+ while (cur != tail) {
+ b.left = b.left < cur->left ? b.left : cur->left;
+ b.top = b.top < cur->top ? b.top : cur->top;
+ b.right = b.right > cur->right ? b.right : cur->right;
+ b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
+ if (cur->top == prev->top) {
+ if (cur->bottom != prev->bottom) {
+ LOGE("%s: invalid span %p", name, cur);
+ result = false;
+ } else if (cur->left < prev->right) {
+ LOGE("%s: spans overlap horizontally prev=%p, cur=%p",
+ name, prev, cur);
+ result = false;
+ }
+ } else if (cur->top < prev->bottom) {
+ LOGE("%s: spans overlap vertically prev=%p, cur=%p",
+ name, prev, cur);
+ result = false;
+ }
+ prev = cur;
+ cur++;
+ }
+ if (b != reg.getBounds()) {
+ result = false;
+ LOGE("%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
+ b.left, b.top, b.right, b.bottom,
+ reg.getBounds().left, reg.getBounds().top,
+ reg.getBounds().right, reg.getBounds().bottom);
+ }
+ if (result == false) {
+ reg.dump(name);
+ }
return result;
}
-Region Region::subtract(const Region& rhs, int dx, int dy) const {
- Region result;
- SkRegion r(rhs.mRegion);
- r.translate(dx, dy);
- result.mRegion.op(mRegion, r, SkRegion::kDifference_Op);
- return result;
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs,
+ const Region& rhs, int dx, int dy)
+{
+ size_t lhs_count;
+ Rect const * const lhs_rects = lhs.getArray(&lhs_count);
+
+ size_t rhs_count;
+ Rect const * const rhs_rects = rhs.getArray(&rhs_count);
+
+ region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
+ region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
+ region_operator<Rect> operation(op, lhs_region, rhs_region);
+ { // scope for rasterizer (dtor has side effects)
+ rasterizer r(dst);
+ operation(r);
+ }
+
+#if VALIDATE_REGIONS
+ validate(lhs, "boolean_operation: lhs");
+ validate(rhs, "boolean_operation: rhs");
+ validate(dst, "boolean_operation: dst");
+#endif
+
+#if VALIDATE_WITH_CORECG
+ SkRegion sk_lhs;
+ SkRegion sk_rhs;
+ SkRegion sk_dst;
+
+ for (size_t i=0 ; i<lhs_count ; i++)
+ sk_lhs.op(
+ lhs_rects[i].left + dx,
+ lhs_rects[i].top + dy,
+ lhs_rects[i].right + dx,
+ lhs_rects[i].bottom + dy,
+ SkRegion::kUnion_Op);
+
+ for (size_t i=0 ; i<rhs_count ; i++)
+ sk_rhs.op(
+ rhs_rects[i].left + dx,
+ rhs_rects[i].top + dy,
+ rhs_rects[i].right + dx,
+ rhs_rects[i].bottom + dy,
+ SkRegion::kUnion_Op);
+
+ const char* name = "---";
+ SkRegion::Op sk_op;
+ switch (op) {
+ case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
+ case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
+ case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
+ }
+ sk_dst.op(sk_lhs, sk_rhs, sk_op);
+
+ if (sk_dst.isEmpty() && dst.isEmpty())
+ return;
+
+ bool same = true;
+ Region::const_iterator head = dst.begin();
+ Region::const_iterator const tail = dst.end();
+ SkRegion::Iterator it(sk_dst);
+ while (!it.done()) {
+ if (head != tail) {
+ if (
+ head->left != it.rect().fLeft ||
+ head->top != it.rect().fTop ||
+ head->right != it.rect().fRight ||
+ head->bottom != it.rect().fBottom
+ ) {
+ same = false;
+ break;
+ }
+ } else {
+ same = false;
+ break;
+ }
+ head++;
+ it.next();
+ }
+
+ if (head != tail) {
+ same = false;
+ }
+
+ if(!same) {
+ LOGD("---\nregion boolean %s failed", name);
+ lhs.dump("lhs");
+ rhs.dump("rhs");
+ dst.dump("dst");
+ LOGD("should be");
+ SkRegion::Iterator it(sk_dst);
+ while (!it.done()) {
+ LOGD(" [%3d, %3d, %3d, %3d]",
+ it.rect().fLeft,
+ it.rect().fTop,
+ it.rect().fRight,
+ it.rect().fBottom);
+ it.next();
+ }
+ }
+#endif
}
-// ----------------------------------------------------------------------------
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs,
+ const Rect& rhs, int dx, int dy)
+{
+#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
+ boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
+#else
+ size_t lhs_count;
+ Rect const * const lhs_rects = lhs.getArray(&lhs_count);
+
+ region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
+ region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
+ region_operator<Rect> operation(op, lhs_region, rhs_region);
+ { // scope for rasterizer (dtor has side effects)
+ rasterizer r(dst);
+ operation(r);
+ }
+
+#endif
+}
-Region::iterator::iterator(const Region& r)
- : mIt(r.mRegion)
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs, const Region& rhs)
{
+ boolean_operation(op, dst, lhs, rhs, 0, 0);
}
-int Region::iterator::iterate(Rect* rect)
+void Region::boolean_operation(int op, Region& dst,
+ const Region& lhs, const Rect& rhs)
{
- if (mIt.done())
- return 0;
- const SkIRect& r(mIt.rect());
- rect->left = r.fLeft;
- rect->top = r.fTop;
- rect->right = r.fRight;
- rect->bottom= r.fBottom;
- mIt.next();
- return 1;
+ boolean_operation(op, dst, lhs, rhs, 0, 0);
}
-// ----------------------------------------------------------------------------
+void Region::translate(Region& reg, int dx, int dy)
+{
+ if (!reg.isEmpty()) {
+#if VALIDATE_REGIONS
+ validate(reg, "translate (before)");
+#endif
+ reg.mBounds.translate(dx, dy);
+ size_t count = reg.mStorage.size();
+ Rect* rects = reg.mStorage.editArray();
+ while (count) {
+ rects->translate(dx, dy);
+ rects++;
+ count--;
+ }
+#if VALIDATE_REGIONS
+ validate(reg, "translate (after)");
+#endif
+ }
+}
+
+void Region::translate(Region& dst, const Region& reg, int dx, int dy)
+{
+ dst = reg;
+ translate(dst, dx, dy);
+}
-// we write a 4byte size ahead of the actual region, so we know how much we'll need for reading
+// ----------------------------------------------------------------------------
status_t Region::write(Parcel& parcel) const
{
- int32_t size = mRegion.flatten(NULL);
- parcel.writeInt32(size);
- mRegion.flatten(parcel.writeInplace(size));
+#if VALIDATE_REGIONS
+ validate(*this, "write(Parcel)");
+#endif
+ status_t err;
+ const size_t count = mStorage.size();
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
+ void* buffer = parcel.writeInplace(sizeNeeded);
+ if (!buffer) return NO_MEMORY;
+ ssize_t written = Region::write(buffer, sizeNeeded);
+ if (written < 0) return status_t(written);
return NO_ERROR;
}
status_t Region::read(const Parcel& parcel)
{
- size_t size = parcel.readInt32();
- mRegion.unflatten(parcel.readInplace(size));
+ void const* buffer = parcel.readInplace(sizeof(int32_t));
+ if (!buffer) return NO_MEMORY;
+ const size_t count = *static_cast<int32_t const *>(buffer);
+ void const* dummy = parcel.readInplace((1+count)*sizeof(Rect));
+ if (!dummy) return NO_MEMORY;
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
+ const ssize_t read = Region::read(buffer);
+ if (read < 0) return status_t(read);
+#if VALIDATE_REGIONS
+ validate(*this, "read(Parcel)");
+#endif
return NO_ERROR;
}
ssize_t Region::write(void* buffer, size_t size) const
{
- size_t sizeNeeded = mRegion.flatten(NULL);
+#if VALIDATE_REGIONS
+ validate(*this, "write(buffer)");
+#endif
+ const size_t count = mStorage.size();
+ const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
if (sizeNeeded > size) return NO_MEMORY;
- return mRegion.flatten(buffer);
+ int32_t* const p = static_cast<int32_t*>(buffer);
+ *p = count;
+ memcpy(p+1, &mBounds, sizeof(Rect));
+ if (count) {
+ memcpy(p+5, mStorage.array(), count*sizeof(Rect));
+ }
+ return ssize_t(sizeNeeded);
}
ssize_t Region::read(const void* buffer)
{
- return mRegion.unflatten(buffer);
+ int32_t const* const p = static_cast<int32_t const*>(buffer);
+ const size_t count = *p;
+ memcpy(&mBounds, p+1, sizeof(Rect));
+ mStorage.clear();
+ if (count) {
+ mStorage.insertAt(0, count);
+ memcpy(mStorage.editArray(), p+5, count*sizeof(Rect));
+ }
+#if VALIDATE_REGIONS
+ validate(*this, "read(buffer)");
+#endif
+ return ssize_t(sizeof(int32_t) + (1+count)*sizeof(Rect));
}
ssize_t Region::writeEmpty(void* buffer, size_t size)
{
- if (size < 4) return NO_MEMORY;
- // this needs to stay in sync with SkRegion
- *static_cast<int32_t*>(buffer) = -1;
- return 4;
+ const size_t sizeNeeded = sizeof(int32_t) + sizeof(Rect);
+ if (sizeNeeded > size) return NO_MEMORY;
+ int32_t* const p = static_cast<int32_t*>(buffer);
+ memset(p, 0, sizeNeeded);
+ return ssize_t(sizeNeeded);
}
bool Region::isEmpty(void* buffer)
{
- // this needs to stay in sync with SkRegion
- return *static_cast<int32_t*>(buffer) == -1;
+ int32_t const* const p = static_cast<int32_t const*>(buffer);
+ Rect const* const b = reinterpret_cast<Rect const *>(p+1);
+ return b->isEmpty();
+}
+
+// ----------------------------------------------------------------------------
+
+Region::const_iterator Region::begin() const {
+ return isRect() ? &mBounds : mStorage.array();
+}
+
+Region::const_iterator Region::end() const {
+ return isRect() ? ((&mBounds) + 1) : (mStorage.array() + mStorage.size());
+}
+
+Rect const* Region::getArray(size_t* count) const {
+ const_iterator const b(begin());
+ const_iterator const e(end());
+ if (count) *count = e-b;
+ return b;
}
-size_t Region::rects(Vector<Rect>& rectList) const
+size_t Region::getRects(Vector<Rect>& rectList) const
{
- rectList.clear();
- if (!isEmpty()) {
- SkRegion::Iterator iterator(mRegion);
- while( !iterator.done() ) {
- const SkIRect& ir(iterator.rect());
- rectList.push(Rect(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom));
- iterator.next();
- }
+ rectList = mStorage;
+ if (rectList.isEmpty()) {
+ rectList.clear();
+ rectList.add(mBounds);
}
return rectList.size();
}
+// ----------------------------------------------------------------------------
+
void Region::dump(String8& out, const char* what, uint32_t flags) const
{
(void)flags;
- Vector<Rect> r;
- rects(r);
-
+ const_iterator head = begin();
+ const_iterator const tail = end();
+
size_t SIZE = 256;
char buffer[SIZE];
-
- snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n", what, this, r.size());
+
+ snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n",
+ what, this, tail-head);
out.append(buffer);
- for (size_t i=0 ; i<r.size() ; i++) {
+ while (head != tail) {
snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n",
- r[i].left, r[i].top,r[i].right,r[i].bottom);
+ head->left, head->top, head->right, head->bottom);
out.append(buffer);
+ head++;
}
}
void Region::dump(const char* what, uint32_t flags) const
{
(void)flags;
- Vector<Rect> r;
- rects(r);
- LOGD(" Region %s (this=%p, count=%d)\n", what, this, r.size());
- for (size_t i=0 ; i<r.size() ; i++) {
+ const_iterator head = begin();
+ const_iterator const tail = end();
+ LOGD(" Region %s (this=%p, count=%d)\n", what, this, tail-head);
+ while (head != tail) {
LOGD(" [%3d, %3d, %3d, %3d]\n",
- r[i].left, r[i].top,r[i].right,r[i].bottom);
+ head->left, head->top, head->right, head->bottom);
+ head++;
}
}
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index 4ea9ae2..474308a 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -23,233 +23,825 @@
#include <sys/types.h>
#include <sys/stat.h>
-#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/DisplayInfo.h>
+#include <ui/BufferMapper.h>
#include <ui/ISurface.h>
#include <ui/Surface.h>
#include <ui/SurfaceComposerClient.h>
#include <ui/Rect.h>
+#include <pixelflinger/pixelflinger.h>
+
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
+#include <private/ui/SurfaceBuffer.h>
namespace android {
-// ---------------------------------------------------------------------------
+// ============================================================================
+// SurfaceBuffer
+// ============================================================================
-Surface::Surface(const sp<SurfaceComposerClient>& client,
- const sp<ISurface>& surface,
- const ISurfaceFlingerClient::surface_data_t& data,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- bool owner)
- : mClient(client), mSurface(surface),
- mToken(data.token), mIdentity(data.identity),
- mFormat(format), mFlags(flags), mOwner(owner)
+SurfaceBuffer::SurfaceBuffer()
+ : BASE(), mOwner(false), mBufferMapper(BufferMapper::get())
{
- mSwapRectangle.makeInvalid();
- mSurfaceHeapBase[0] = 0;
- mSurfaceHeapBase[1] = 0;
- mHeap[0] = data.heap[0];
- mHeap[1] = data.heap[1];
-}
-
-Surface::Surface(Surface const* rhs)
- : mOwner(false)
-{
- mToken = rhs->mToken;
- mIdentity= rhs->mIdentity;
- mClient = rhs->mClient;
- mSurface = rhs->mSurface;
- mHeap[0] = rhs->mHeap[0];
- mHeap[1] = rhs->mHeap[1];
- mFormat = rhs->mFormat;
- mFlags = rhs->mFlags;
- mSurfaceHeapBase[0] = rhs->mSurfaceHeapBase[0];
- mSurfaceHeapBase[1] = rhs->mSurfaceHeapBase[1];
- mSwapRectangle.makeInvalid();
+ width =
+ height =
+ stride =
+ format =
+ usage = 0;
+ handle = NULL;
}
-Surface::~Surface()
+SurfaceBuffer::SurfaceBuffer(const Parcel& data)
+ : BASE(), mOwner(true), mBufferMapper(BufferMapper::get())
{
- if (mOwner && mToken>=0 && mClient!=0) {
- mClient->destroySurface(mToken);
+ // we own the handle in this case
+ width = data.readInt32();
+ if (width < 0) {
+ width = height = stride = format = usage = 0;
+ handle = 0;
+ } else {
+ height = data.readInt32();
+ stride = data.readInt32();
+ format = data.readInt32();
+ usage = data.readInt32();
+ handle = data.readNativeHandle();
}
- mClient.clear();
- mSurface.clear();
- mHeap[0].clear();
- mHeap[1].clear();
- IPCThreadState::self()->flushCommands();
}
-sp<Surface> Surface::dup() const
+SurfaceBuffer::~SurfaceBuffer()
{
- Surface const * r = this;
- if (this && mOwner) {
- // the only reason we need to do this is because of Java's garbage
- // collector: because we're creating a copy of the Surface
- // instead of a reference, we can garantee that when our last
- // reference goes away, the real surface will be deleted.
- // Without this hack (the code is correct too), we'd have to
- // wait for a GC for the surface to go away.
- r = new Surface(this);
+ if (handle && mOwner) {
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle*>(handle));
}
- return const_cast<Surface*>(r);
}
-status_t Surface::nextBuffer(SurfaceInfo* info) {
- return mClient->nextBuffer(this, info);
+status_t SurfaceBuffer::lock(uint32_t usage, void** vaddr)
+{
+ const Rect lockBounds(width, height);
+ status_t res = lock(usage, lockBounds, vaddr);
+ return res;
}
-status_t Surface::lock(SurfaceInfo* info, bool blocking) {
- return Surface::lock(info, NULL, blocking);
+status_t SurfaceBuffer::lock(uint32_t usage, const Rect& rect, void** vaddr)
+{
+ if (rect.left < 0 || rect.right > this->width ||
+ rect.top < 0 || rect.bottom > this->height) {
+ LOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
+ rect.left, rect.top, rect.right, rect.bottom,
+ this->width, this->height);
+ return BAD_VALUE;
+ }
+ status_t res = getBufferMapper().lock(handle, usage, rect, vaddr);
+ return res;
}
-status_t Surface::lock(SurfaceInfo* info, Region* dirty, bool blocking) {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->lockSurface(this, info, dirty, blocking);
+status_t SurfaceBuffer::unlock()
+{
+ status_t res = getBufferMapper().unlock(handle);
+ return res;
}
-status_t Surface::unlockAndPost() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockAndPostSurface(this);
+status_t SurfaceBuffer::writeToParcel(Parcel* reply,
+ android_native_buffer_t const* buffer)
+{
+ if (buffer == NULL)
+ return BAD_VALUE;
+
+ if (buffer->width < 0 || buffer->height < 0)
+ return BAD_VALUE;
+
+ status_t err = NO_ERROR;
+ if (buffer->handle == NULL) {
+ // this buffer doesn't have a handle
+ reply->writeInt32(NO_MEMORY);
+ } else {
+ reply->writeInt32(buffer->width);
+ reply->writeInt32(buffer->height);
+ reply->writeInt32(buffer->stride);
+ reply->writeInt32(buffer->format);
+ reply->writeInt32(buffer->usage);
+ err = reply->writeNativeHandle(buffer->handle);
+ }
+ return err;
}
-status_t Surface::unlock() {
- if (heapBase(0) == 0) return INVALID_OPERATION;
- if (heapBase(1) == 0) return INVALID_OPERATION;
- return mClient->unlockSurface(this);
+// ----------------------------------------------------------------------
+
+static status_t copyBlt(
+ const sp<SurfaceBuffer>& dst,
+ const sp<SurfaceBuffer>& src,
+ const Region& reg)
+{
+ status_t err;
+ uint8_t const * src_bits = NULL;
+ err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+ LOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+ uint8_t* dst_bits = NULL;
+ err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+ LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+ Region::const_iterator head(reg.begin());
+ Region::const_iterator tail(reg.end());
+ if (head != tail && src_bits && dst_bits) {
+ // NOTE: dst and src must be the same format
+ const size_t bpp = bytesPerPixel(src->format);
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ while (head != tail) {
+ const Rect& r(*head++);
+ ssize_t h = r.height();
+ if (h <= 0) continue;
+ size_t size = r.width() * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+
+ if (src_bits)
+ src->unlock();
+
+ if (dst_bits)
+ dst->unlock();
+
+ return err;
}
-status_t Surface::setLayer(int32_t layer) {
- return mClient->setLayer(this, layer);
+// ============================================================================
+// SurfaceControl
+// ============================================================================
+
+SurfaceControl::SurfaceControl(
+ const sp<SurfaceComposerClient>& client,
+ const sp<ISurface>& surface,
+ const ISurfaceFlingerClient::surface_data_t& data,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+ : mClient(client), mSurface(surface),
+ mToken(data.token), mIdentity(data.identity),
+ mWidth(data.width), mHeight(data.height), mFormat(data.format),
+ mFlags(flags)
+{
}
-status_t Surface::setPosition(int32_t x, int32_t y) {
- return mClient->setPosition(this, x, y);
+
+SurfaceControl::~SurfaceControl()
+{
+ destroy();
}
-status_t Surface::setSize(uint32_t w, uint32_t h) {
- return mClient->setSize(this, w, h);
+
+void SurfaceControl::destroy()
+{
+ if (isValid()) {
+ mClient->destroySurface(mToken);
+ }
+
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
+ mClient.clear();
+ mSurface.clear();
+ IPCThreadState::self()->flushCommands();
}
-status_t Surface::hide() {
- return mClient->hide(this);
+
+void SurfaceControl::clear()
+{
+ // here, the window manager tells us explicitly that we should destroy
+ // the surface's resource. Soon after this call, it will also release
+ // its last reference (which will call the dtor); however, it is possible
+ // that a client living in the same process still holds references which
+ // would delay the call to the dtor -- that is why we need this explicit
+ // "clear()" call.
+ destroy();
}
-status_t Surface::show(int32_t layer) {
- return mClient->show(this, layer);
+
+bool SurfaceControl::isSameSurface(
+ const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
+{
+ if (lhs == 0 || rhs == 0)
+ return false;
+ return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
}
-status_t Surface::freeze() {
- return mClient->freeze(this);
+
+status_t SurfaceControl::setLayer(int32_t layer) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setLayer(mToken, layer);
}
-status_t Surface::unfreeze() {
- return mClient->unfreeze(this);
+status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setPosition(mToken, x, y);
}
-status_t Surface::setFlags(uint32_t flags, uint32_t mask) {
- return mClient->setFlags(this, flags, mask);
+status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setSize(mToken, w, h);
}
-status_t Surface::setTransparentRegionHint(const Region& transparent) {
- return mClient->setTransparentRegionHint(this, transparent);
+status_t SurfaceControl::hide() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->hide(mToken);
}
-status_t Surface::setAlpha(float alpha) {
- return mClient->setAlpha(this, alpha);
+status_t SurfaceControl::show(int32_t layer) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->show(mToken, layer);
}
-status_t Surface::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
- return mClient->setMatrix(this, dsdx, dtdx, dsdy, dtdy);
+status_t SurfaceControl::freeze() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->freeze(mToken);
}
-status_t Surface::setFreezeTint(uint32_t tint) {
- return mClient->setFreezeTint(this, tint);
+status_t SurfaceControl::unfreeze() {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->unfreeze(mToken);
}
-
-Region Surface::dirtyRegion() const {
- return mDirtyRegion;
+status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setFlags(mToken, flags, mask);
}
-void Surface::setDirtyRegion(const Region& region) const {
- mDirtyRegion = region;
+status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setTransparentRegionHint(mToken, transparent);
}
-const Rect& Surface::swapRectangle() const {
- return mSwapRectangle;
+status_t SurfaceControl::setAlpha(float alpha) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setAlpha(mToken, alpha);
}
-void Surface::setSwapRectangle(const Rect& r) {
- mSwapRectangle = r;
+status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy);
+}
+status_t SurfaceControl::setFreezeTint(uint32_t tint) {
+ const sp<SurfaceComposerClient>& client(mClient);
+ if (client == 0) return NO_INIT;
+ status_t err = validate(client->mControl);
+ if (err < 0) return err;
+ return client->setFreezeTint(mToken, tint);
}
-sp<Surface> Surface::readFromParcel(Parcel* parcel)
+status_t SurfaceControl::validate(per_client_cblk_t const* cblk) const
{
- sp<SurfaceComposerClient> client;
- ISurfaceFlingerClient::surface_data_t data;
- sp<IBinder> clientBinder= parcel->readStrongBinder();
- sp<ISurface> surface = interface_cast<ISurface>(parcel->readStrongBinder());
- data.heap[0] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
- data.heap[1] = interface_cast<IMemoryHeap>(parcel->readStrongBinder());
- data.token = parcel->readInt32();
- data.identity = parcel->readInt32();
- PixelFormat format = parcel->readInt32();
- uint32_t flags = parcel->readInt32();
-
- if (clientBinder != NULL)
- client = SurfaceComposerClient::clientForConnection(clientBinder);
-
- return new Surface(client, surface, data, 0, 0, format, flags, false);
+ if (mToken<0 || mClient==0) {
+ LOGE("invalid token (%d, identity=%u) or client (%p)",
+ mToken, mIdentity, mClient.get());
+ return NO_INIT;
+ }
+ if (cblk == 0) {
+ LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
+ return NO_INIT;
+ }
+ status_t err = cblk->validate(mToken);
+ if (err != NO_ERROR) {
+ LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
+ mToken, mIdentity, err, strerror(-err));
+ return err;
+ }
+ if (mIdentity != uint32_t(cblk->layers[mToken].identity)) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, cblk->layers[mToken].identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
}
-status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel)
+status_t SurfaceControl::writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel)
{
- uint32_t flags=0;
- uint32_t format=0;
+ uint32_t flags = 0;
+ uint32_t format = 0;
SurfaceID token = -1;
uint32_t identity = 0;
+ uint32_t width = 0;
+ uint32_t height = 0;
sp<SurfaceComposerClient> client;
sp<ISurface> sur;
- sp<IMemoryHeap> heap[2];
- if (surface->isValid()) {
- token = surface->mToken;
- identity = surface->mIdentity;
- client = surface->mClient;
- sur = surface->mSurface;
- heap[0] = surface->mHeap[0];
- heap[1] = surface->mHeap[1];
- format = surface->mFormat;
- flags = surface->mFlags;
+ if (SurfaceControl::isValid(control)) {
+ token = control->mToken;
+ identity = control->mIdentity;
+ client = control->mClient;
+ sur = control->mSurface;
+ width = control->mWidth;
+ height = control->mHeight;
+ format = control->mFormat;
+ flags = control->mFlags;
}
parcel->writeStrongBinder(client!=0 ? client->connection() : NULL);
parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
- parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL);
- parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL);
parcel->writeInt32(token);
parcel->writeInt32(identity);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
parcel->writeInt32(format);
parcel->writeInt32(flags);
return NO_ERROR;
}
-bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs)
+sp<Surface> SurfaceControl::getSurface() const
+{
+ Mutex::Autolock _l(mLock);
+ if (mSurfaceData == 0) {
+ mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
+ }
+ return mSurfaceData;
+}
+
+// ============================================================================
+// Surface
+// ============================================================================
+
+Surface::Surface(const sp<SurfaceControl>& surface)
+ : mClient(surface->mClient), mSurface(surface->mSurface),
+ mToken(surface->mToken), mIdentity(surface->mIdentity),
+ mFormat(surface->mFormat), mFlags(surface->mFlags),
+ mBufferMapper(BufferMapper::get()),
+ mWidth(surface->mWidth), mHeight(surface->mHeight)
+{
+ init();
+}
+
+Surface::Surface(const Parcel& parcel)
+ : mBufferMapper(BufferMapper::get())
+{
+ sp<IBinder> clientBinder = parcel.readStrongBinder();
+ mSurface = interface_cast<ISurface>(parcel.readStrongBinder());
+ mToken = parcel.readInt32();
+ mIdentity = parcel.readInt32();
+ mWidth = parcel.readInt32();
+ mHeight = parcel.readInt32();
+ mFormat = parcel.readInt32();
+ mFlags = parcel.readInt32();
+
+ if (clientBinder != NULL)
+ mClient = SurfaceComposerClient::clientForConnection(clientBinder);
+
+ init();
+}
+
+void Surface::init()
+{
+ android_native_window_t::setSwapInterval = setSwapInterval;
+ android_native_window_t::dequeueBuffer = dequeueBuffer;
+ android_native_window_t::lockBuffer = lockBuffer;
+ android_native_window_t::queueBuffer = queueBuffer;
+ android_native_window_t::query = query;
+ android_native_window_t::perform = perform;
+ mSwapRectangle.makeInvalid();
+ DisplayInfo dinfo;
+ SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+ const_cast<float&>(android_native_window_t::xdpi) = dinfo.xdpi;
+ const_cast<float&>(android_native_window_t::ydpi) = dinfo.ydpi;
+ // FIXME: set real values here
+ const_cast<int&>(android_native_window_t::minSwapInterval) = 1;
+ const_cast<int&>(android_native_window_t::maxSwapInterval) = 1;
+ const_cast<uint32_t&>(android_native_window_t::flags) = 0;
+ // be default we request a hardware surface
+ mUsage = GRALLOC_USAGE_HW_RENDER;
+ mUsageChanged = true;
+}
+
+Surface::~Surface()
+{
+ // this is a client-side operation, the surface is destroyed, unmap
+ // its buffers in this process.
+ for (int i=0 ; i<2 ; i++) {
+ if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) {
+ getBufferMapper().unregisterBuffer(mBuffers[i]->handle);
+ }
+ }
+
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
+ mClient.clear();
+ mSurface.clear();
+ IPCThreadState::self()->flushCommands();
+}
+
+sp<SurfaceComposerClient> Surface::getClient() const {
+ return mClient;
+}
+
+sp<ISurface> Surface::getISurface() const {
+ return mSurface;
+}
+
+bool Surface::isValid() {
+ return mToken>=0 && mClient!=0;
+}
+
+status_t Surface::validate(per_client_cblk_t const* cblk) const
+{
+ sp<SurfaceComposerClient> client(getClient());
+ if (mToken<0 || mClient==0) {
+ LOGE("invalid token (%d, identity=%u) or client (%p)",
+ mToken, mIdentity, client.get());
+ return NO_INIT;
+ }
+ if (cblk == 0) {
+ LOGE("cblk is null (surface id=%d, identity=%u)", mToken, mIdentity);
+ return NO_INIT;
+ }
+ status_t err = cblk->validate(mToken);
+ if (err != NO_ERROR) {
+ LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
+ mToken, mIdentity, err, strerror(-err));
+ return err;
+ }
+ if (mIdentity != uint32_t(cblk->layers[mToken].identity)) {
+ LOGE("using an invalid surface id=%d, identity=%u should be %d",
+ mToken, mIdentity, cblk->layers[mToken].identity);
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+
+bool Surface::isSameSurface(
+ const sp<Surface>& lhs, const sp<Surface>& rhs)
{
if (lhs == 0 || rhs == 0)
return false;
+
return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
}
-void* Surface::heapBase(int i) const
+// ----------------------------------------------------------------------------
+
+int Surface::setSwapInterval(android_native_window_t* window, int interval)
+{
+ return 0;
+}
+
+int Surface::dequeueBuffer(android_native_window_t* window,
+ android_native_buffer_t** buffer)
+{
+ Surface* self = getSelf(window);
+ return self->dequeueBuffer(buffer);
+}
+
+int Surface::lockBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ Surface* self = getSelf(window);
+ return self->lockBuffer(buffer);
+}
+
+int Surface::queueBuffer(android_native_window_t* window,
+ android_native_buffer_t* buffer)
+{
+ Surface* self = getSelf(window);
+ return self->queueBuffer(buffer);
+}
+
+int Surface::query(android_native_window_t* window,
+ int what, int* value)
+{
+ Surface* self = getSelf(window);
+ return self->query(what, value);
+}
+
+int Surface::perform(android_native_window_t* window,
+ int operation, ...)
+{
+ va_list args;
+ va_start(args, operation);
+ Surface* self = getSelf(window);
+ int res = self->perform(operation, args);
+ va_end(args);
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer)
+{
+ android_native_buffer_t* out;
+ status_t err = dequeueBuffer(&out);
+ if (err == NO_ERROR) {
+ *buffer = SurfaceBuffer::getSelf(out);
+ }
+ return err;
+}
+
+status_t Surface::lockBuffer(const sp<SurfaceBuffer>& buffer)
{
- void* heapBase = mSurfaceHeapBase[i];
- // map lazily so it doesn't get mapped in clients that don't need it
- if (heapBase == 0) {
- const sp<IMemoryHeap>& heap(mHeap[i]);
- if (heap != 0) {
- heapBase = static_cast<uint8_t*>(heap->base());
- if (heapBase == MAP_FAILED) {
- heapBase = NULL;
- LOGE("Couldn't map Surface's heap (binder=%p, heap=%p)",
- heap->asBinder().get(), heap.get());
+ return lockBuffer(buffer.get());
+}
+
+status_t Surface::queueBuffer(const sp<SurfaceBuffer>& buffer)
+{
+ return queueBuffer(buffer.get());
+}
+
+// ----------------------------------------------------------------------------
+
+int Surface::dequeueBuffer(android_native_buffer_t** buffer)
+{
+ // FIXME: dequeueBuffer() needs proper implementation
+
+ Mutex::Autolock _l(mSurfaceLock);
+
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ SurfaceID index(mToken);
+
+ int32_t backIdx = cblk->lock_layer(size_t(index),
+ per_client_cblk_t::BLOCKING);
+
+ if (backIdx < 0)
+ return status_t(backIdx);
+
+ mBackbufferIndex = backIdx;
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+ volatile const surface_info_t* const back = lcblk->surface + backIdx;
+
+ const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
+
+ if (backBuffer==0 &&
+ !((back->flags & surface_info_t::eNeedNewBuffer) || mUsageChanged)) {
+ LOGW("dequeueBuffer: backbuffer is null, but eNeedNewBuffer "
+ "is not set, fetching a buffer anyways...");
+ }
+
+ if ((back->flags & surface_info_t::eNeedNewBuffer) ||mUsageChanged ||
+ backBuffer==0)
+ {
+ mUsageChanged = false;
+ err = getBufferLocked(backIdx, mUsage);
+ if (err == NO_ERROR) {
+ // reset the width/height with the what we get from the buffer
+ const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
+ mWidth = uint32_t(backBuffer->width);
+ mHeight = uint32_t(backBuffer->height);
+ }
+ }
+
+ if (err == NO_ERROR) {
+ if (backBuffer != 0) {
+ mDirtyRegion.set(backBuffer->width, backBuffer->height);
+ *buffer = backBuffer.get();
+ } else {
+ err = NO_MEMORY;
+ }
+ }
+
+ return err;
+}
+
+int Surface::lockBuffer(android_native_buffer_t* buffer)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ // FIXME: lockBuffer() needs proper implementation
+ return 0;
+}
+
+int Surface::queueBuffer(android_native_buffer_t* buffer)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
+ status_t err = validate(cblk);
+ if (err != NO_ERROR)
+ return err;
+
+ if (mSwapRectangle.isValid()) {
+ mDirtyRegion.set(mSwapRectangle);
+ }
+
+ // transmit the dirty region
+ SurfaceID index(mToken);
+ layer_cblk_t* const lcblk = &(cblk->layers[index]);
+ _send_dirty_region(lcblk, mDirtyRegion);
+
+ uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
+ if (!(newstate & eNextFlipPending))
+ client->signalServer();
+
+ return NO_ERROR;
+}
+
+int Surface::query(int what, int* value)
+{
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ *value = int(mWidth);
+ return NO_ERROR;
+ case NATIVE_WINDOW_HEIGHT:
+ *value = int(mHeight);
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = int(mFormat);
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+int Surface::perform(int operation, va_list args)
+{
+ int res = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ setUsage( va_arg(args, int) );
+ break;
+ default:
+ res = NAME_NOT_FOUND;
+ break;
+ }
+ return res;
+}
+
+void Surface::setUsage(uint32_t reqUsage)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ if (mUsage != reqUsage) {
+ mUsageChanged = true;
+ mUsage = reqUsage;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::lock(SurfaceInfo* info, bool blocking) {
+ return Surface::lock(info, NULL, blocking);
+}
+
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
+{
+ // we're intending to do software rendering from this point
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ sp<SurfaceBuffer> backBuffer;
+ status_t err = dequeueBuffer(&backBuffer);
+ if (err == NO_ERROR) {
+ err = lockBuffer(backBuffer);
+ if (err == NO_ERROR) {
+ // we handle copy-back here...
+
+ const Rect bounds(backBuffer->width, backBuffer->height);
+ Region scratch(bounds);
+ Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
+
+ sp<SurfaceComposerClient> client(getClient());
+ per_client_cblk_t* const cblk = client->mControl;
+ layer_cblk_t* const lcblk = &(cblk->layers[SurfaceID(mToken)]);
+ volatile const surface_info_t* const back = lcblk->surface + mBackbufferIndex;
+ if (back->flags & surface_info_t::eBufferDirty) {
+ // content is meaningless in this case and the whole surface
+ // needs to be redrawn.
+ newDirtyRegion.set(bounds);
+ } else {
+ newDirtyRegion.andSelf(bounds);
+ const sp<SurfaceBuffer>& frontBuffer(mBuffers[1-mBackbufferIndex]);
+ if (frontBuffer !=0 &&
+ backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ !(lcblk->flags & eNoCopyBack))
+ {
+ const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty() && frontBuffer!=0) {
+ // copy front to back
+ copyBlt(backBuffer, frontBuffer, copyback);
+ }
+ }
+ }
+ mDirtyRegion = newDirtyRegion;
+ mOldDirtyRegion = newDirtyRegion;
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ LOGW_IF(res, "failed locking buffer %d (%p)",
+ mBackbufferIndex, backBuffer->handle);
+
+ mLockedBuffer = backBuffer;
+ other->w = backBuffer->width;
+ other->h = backBuffer->height;
+ other->s = backBuffer->stride;
+ other->usage = backBuffer->usage;
+ other->format = backBuffer->format;
+ other->bits = vaddr;
+ }
+ }
+ return err;
+}
+
+status_t Surface::unlockAndPost()
+{
+ if (mLockedBuffer == 0)
+ return BAD_VALUE;
+
+ status_t res = mLockedBuffer->unlock();
+ LOGW_IF(res, "failed unlocking buffer %d (%p)",
+ mBackbufferIndex, mLockedBuffer->handle);
+
+ status_t err = queueBuffer(mLockedBuffer);
+ mLockedBuffer = 0;
+ return err;
+}
+
+void Surface::_send_dirty_region(
+ layer_cblk_t* lcblk, const Region& dirty)
+{
+ const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
+ flat_region_t* flat_region = lcblk->region + index;
+ status_t err = dirty.write(flat_region, sizeof(flat_region_t));
+ if (err < NO_ERROR) {
+ // region doesn't fit, use the bounds
+ const Region reg(dirty.bounds());
+ reg.write(flat_region, sizeof(flat_region_t));
+ }
+}
+
+void Surface::setSwapRectangle(const Rect& r) {
+ Mutex::Autolock _l(mSurfaceLock);
+ mSwapRectangle = r;
+}
+
+status_t Surface::getBufferLocked(int index, int usage)
+{
+ sp<ISurface> s(mSurface);
+ if (s == 0) return NO_INIT;
+
+ status_t err = NO_MEMORY;
+
+ // free the current buffer
+ sp<SurfaceBuffer>& currentBuffer(mBuffers[index]);
+ if (currentBuffer != 0) {
+ getBufferMapper().unregisterBuffer(currentBuffer->handle);
+ currentBuffer.clear();
+ }
+
+ sp<SurfaceBuffer> buffer = s->getBuffer(usage);
+ LOGE_IF(buffer==0, "ISurface::getBuffer() returned NULL");
+ if (buffer != 0) { // this should never happen by construction
+ if (buffer->handle != NULL) {
+ err = getBufferMapper().registerBuffer(buffer->handle);
+ LOGW_IF(err, "registerBuffer(...) failed %d (%s)",
+ err, strerror(-err));
+ if (err == NO_ERROR) {
+ currentBuffer = buffer;
}
- mSurfaceHeapBase[i] = heapBase;
}
}
- return heapBase;
+ return err;
}
}; // namespace android
diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp
index fe803ff..d2cef78 100644
--- a/libs/ui/SurfaceComposerClient.cpp
+++ b/libs/ui/SurfaceComposerClient.cpp
@@ -29,27 +29,21 @@
#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/IServiceManager.h>
+#include <binder/IMemory.h>
#include <utils/Log.h>
+#include <ui/DisplayInfo.h>
#include <ui/ISurfaceComposer.h>
#include <ui/ISurfaceFlingerClient.h>
#include <ui/ISurface.h>
#include <ui/SurfaceComposerClient.h>
-#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
-#include <ui/Point.h>
#include <private/ui/SharedState.h>
#include <private/ui/LayerState.h>
#include <private/ui/SurfaceFlingerSynchro.h>
-#include <pixelflinger/pixelflinger.h>
-
-#include <utils/BpBinder.h>
-
#define VERBOSE(...) ((void)0)
//#define VERBOSE LOGD
@@ -65,7 +59,7 @@ static Mutex gLock;
static sp<ISurfaceComposer> gSurfaceManager;
static DefaultKeyedVector< sp<IBinder>, sp<SurfaceComposerClient> > gActiveConnections;
static SortedVector<sp<SurfaceComposerClient> > gOpenTransactions;
-static sp<IMemory> gServerCblkMemory;
+static sp<IMemoryHeap> gServerCblkMemory;
static volatile surface_flinger_cblk_t* gServerCblk;
const sp<ISurfaceComposer>& _get_surface_manager()
@@ -100,7 +94,7 @@ static volatile surface_flinger_cblk_t const * get_cblk()
if (gServerCblk == 0) {
gServerCblkMemory = sm->getCblk();
LOGE_IF(gServerCblkMemory==0, "Can't get server control block");
- gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->pointer();
+ gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->getBase();
LOGE_IF(gServerCblk==0, "Can't get server control block address");
}
}
@@ -109,50 +103,8 @@ static volatile surface_flinger_cblk_t const * get_cblk()
// ---------------------------------------------------------------------------
-static void copyBlt(const GGLSurface& dst,
- const GGLSurface& src, const Region& reg)
-{
- Region::iterator iterator(reg);
- if (iterator) {
- // NOTE: dst and src must be the same format
- Rect r;
- const size_t bpp = bytesPerPixel(src.format);
- const size_t dbpr = dst.stride * bpp;
- const size_t sbpr = src.stride * bpp;
- while (iterator.iterate(&r)) {
- ssize_t h = r.bottom - r.top;
- if (h) {
- size_t size = (r.right - r.left) * bpp;
- uint8_t* s = src.data + (r.left + src.stride * r.top) * bpp;
- uint8_t* d = dst.data + (r.left + dst.stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += dbpr;
- s += sbpr;
- } while (--h > 0);
- }
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-surface_flinger_cblk_t::surface_flinger_cblk_t()
-{
-}
-
-// ---------------------------------------------------------------------------
-
-per_client_cblk_t::per_client_cblk_t()
-{
-}
-
// these functions are used by the clients
-inline status_t per_client_cblk_t::validate(size_t i) const {
+status_t per_client_cblk_t::validate(size_t i) const {
if (uint32_t(i) >= NUM_LAYERS_MAX)
return BAD_INDEX;
if (layers[i].swapState & eInvalidSurface)
@@ -248,8 +200,9 @@ int32_t per_client_cblk_t::lock_layer(size_t i, uint32_t flags)
index = (state&eIndex) ^ ((state&eFlipRequested)>>1);
// make sure this buffer is valid
- if (layer->surface[index].bits_offset < 0) {
- return status_t(layer->surface[index].bits_offset);
+ status_t err = layer->surface[index].status;
+ if (err < 0) {
+ return err;
}
if (inspect) {
@@ -273,7 +226,7 @@ done:
uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
{
- // atomically set eFlipRequested and clear eLocked and optionnaly
+ // atomically set eFlipRequested and clear eLocked and optionally
// set eNextFlipPending if eFlipRequested was already set
layer_cblk_t * const layer = layers + i;
@@ -290,7 +243,7 @@ uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
if (oldvalue & eFlipRequested)
newvalue |= eNextFlipPending;
- // if eFlipRequested was alread set, set eNextFlipPending
+ // if eFlipRequested was already set, set eNextFlipPending
} while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState)));
@@ -298,9 +251,9 @@ uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i)
int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift),
int(newvalue));
- // from this point, the server can kick in at anytime and use the first
+ // from this point, the server can kick in at any time and use the first
// buffer, so we cannot use it anymore, and we must use the 'other'
- // buffer instead (or wait if it is not availlable yet, see lock_layer).
+ // buffer instead (or wait if it is not available yet, see lock_layer).
return newvalue;
}
@@ -360,9 +313,9 @@ void SurfaceComposerClient::_init(
return;
}
- mClient->getControlBlocks(&mControlMemory);
+ mControlMemory = mClient->getControlBlock();
mSignalServer = new SurfaceFlingerSynchro(sm);
- mControl = static_cast<per_client_cblk_t *>(mControlMemory->pointer());
+ mControl = static_cast<per_client_cblk_t *>(mControlMemory->getBase());
}
SurfaceComposerClient::~SurfaceComposerClient()
@@ -376,32 +329,6 @@ status_t SurfaceComposerClient::initCheck() const
return mStatus;
}
-status_t SurfaceComposerClient::validateSurface(
- per_client_cblk_t const* cblk, Surface const * surface)
-{
- SurfaceID index = surface->ID();
- if (cblk == 0) {
- LOGE("cblk is null (surface id=%d, identity=%u)",
- index, surface->getIdentity());
- return NO_INIT;
- }
-
- status_t err = cblk->validate(index);
- if (err != NO_ERROR) {
- LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
- index, surface->getIdentity(), err, strerror(-err));
- return err;
- }
-
- if (surface->getIdentity() != uint32_t(cblk->layers[index].identity)) {
- LOGE("using an invalid surface id=%d, identity=%u should be %d",
- index, surface->getIdentity(), cblk->layers[index].identity);
- return NO_INIT;
- }
-
- return NO_ERROR;
-}
-
sp<IBinder> SurfaceComposerClient::connection() const
{
return (mClient != 0) ? mClient->asBinder() : 0;
@@ -437,9 +364,8 @@ void SurfaceComposerClient::dispose()
{
// this can be called more than once.
- sp<IMemory> controlMemory;
+ sp<IMemoryHeap> controlMemory;
sp<ISurfaceFlingerClient> client;
- sp<IMemoryHeap> surfaceHeap;
{
Mutex::Autolock _lg(gLock);
@@ -462,9 +388,7 @@ void SurfaceComposerClient::dispose()
delete mPrebuiltLayerState;
mPrebuiltLayerState = 0;
controlMemory = mControlMemory;
- surfaceHeap = mSurfaceHeap;
mControlMemory.clear();
- mSurfaceHeap.clear();
mControl = 0;
mStatus = NO_INIT;
}
@@ -528,7 +452,13 @@ ssize_t SurfaceComposerClient::getNumberOfDisplays()
return n;
}
-sp<Surface> SurfaceComposerClient::createSurface(
+
+void SurfaceComposerClient::signalServer()
+{
+ mSignalServer->signal();
+}
+
+sp<SurfaceControl> SurfaceComposerClient::createSurface(
int pid,
DisplayID display,
uint32_t w,
@@ -536,14 +466,14 @@ sp<Surface> SurfaceComposerClient::createSurface(
PixelFormat format,
uint32_t flags)
{
- sp<Surface> result;
+ sp<SurfaceControl> result;
if (mStatus == NO_ERROR) {
ISurfaceFlingerClient::surface_data_t data;
sp<ISurface> surface = mClient->createSurface(&data, pid,
display, w, h, format, flags);
if (surface != 0) {
if (uint32_t(data.token) < NUM_LAYERS_MAX) {
- result = new Surface(this, surface, data, w, h, format, flags);
+ result = new SurfaceControl(this, surface, data, w, h, format, flags);
}
}
}
@@ -568,186 +498,6 @@ status_t SurfaceComposerClient::destroySurface(SurfaceID sid)
return err;
}
-status_t SurfaceComposerClient::nextBuffer(Surface* surface,
- Surface::SurfaceInfo* info)
-{
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- int32_t backIdx = surface->mBackbufferIndex;
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- const surface_info_t* const front = lcblk->surface + (1-backIdx);
- info->w = front->w;
- info->h = front->h;
- info->format = front->format;
- info->base = surface->heapBase(1-backIdx);
- info->bits = reinterpret_cast<void*>(intptr_t(info->base) + front->bits_offset);
- info->bpr = front->bpr;
-
- return 0;
-}
-
-status_t SurfaceComposerClient::lockSurface(
- Surface* surface,
- Surface::SurfaceInfo* other,
- Region* dirty,
- bool blocking)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- int32_t backIdx = cblk->lock_layer(size_t(index),
- per_client_cblk_t::BLOCKING);
- if (backIdx >= 0) {
- surface->mBackbufferIndex = backIdx;
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- const surface_info_t* const back = lcblk->surface + backIdx;
- const surface_info_t* const front = lcblk->surface + (1-backIdx);
- other->w = back->w;
- other->h = back->h;
- other->format = back->format;
- other->base = surface->heapBase(backIdx);
- other->bits = reinterpret_cast<void*>(intptr_t(other->base) + back->bits_offset);
- other->bpr = back->bpr;
-
- const Rect bounds(other->w, other->h);
- Region newDirtyRegion;
-
- if (back->flags & surface_info_t::eBufferDirty) {
- /* it is safe to write *back here, because we're guaranteed
- * SurfaceFlinger is not touching it (since it just granted
- * access to us) */
- const_cast<surface_info_t*>(back)->flags &=
- ~surface_info_t::eBufferDirty;
-
- // content is meaningless in this case and the whole surface
- // needs to be redrawn.
-
- newDirtyRegion.set(bounds);
- if (dirty) {
- *dirty = newDirtyRegion;
- }
-
- //if (bytesPerPixel(other->format) == 4) {
- // android_memset32(
- // (uint32_t*)other->bits, 0xFF00FF00, other->h * other->bpr);
- //} else {
- // android_memset16( // fill with green
- // (uint16_t*)other->bits, 0x7E0, other->h * other->bpr);
- //}
- }
- else
- {
- if (dirty) {
- dirty->andSelf(Region(bounds));
- newDirtyRegion = *dirty;
- } else {
- newDirtyRegion.set(bounds);
- }
-
- Region copyback;
- if (!(lcblk->flags & eNoCopyBack)) {
- const Region previousDirtyRegion(surface->dirtyRegion());
- copyback = previousDirtyRegion.subtract(newDirtyRegion);
- }
-
- if (!copyback.isEmpty()) {
- // copy front to back
- GGLSurface cb;
- cb.version = sizeof(GGLSurface);
- cb.width = back->w;
- cb.height = back->h;
- cb.stride = back->stride;
- cb.data = (GGLubyte*)surface->heapBase(backIdx);
- cb.data += back->bits_offset;
- cb.format = back->format;
-
- GGLSurface t;
- t.version = sizeof(GGLSurface);
- t.width = front->w;
- t.height = front->h;
- t.stride = front->stride;
- t.data = (GGLubyte*)surface->heapBase(1-backIdx);
- t.data += front->bits_offset;
- t.format = front->format;
-
- //const Region copyback(lcblk->region + 1-backIdx);
- copyBlt(cb, t, copyback);
- }
- }
-
- // update dirty region
- surface->setDirtyRegion(newDirtyRegion);
- }
- return (backIdx < 0) ? status_t(backIdx) : status_t(NO_ERROR);
-}
-
-void SurfaceComposerClient::_signal_server()
-{
- mSignalServer->signal();
-}
-
-void SurfaceComposerClient::_send_dirty_region(
- layer_cblk_t* lcblk, const Region& dirty)
-{
- const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift;
- flat_region_t* flat_region = lcblk->region + index;
- status_t err = dirty.write(flat_region, sizeof(flat_region_t));
- if (err < NO_ERROR) {
- // region doesn't fit, use the bounds
- const Region reg(dirty.bounds());
- reg.write(flat_region, sizeof(flat_region_t));
- }
-}
-
-status_t SurfaceComposerClient::unlockAndPostSurface(Surface* surface)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- Region dirty(surface->dirtyRegion());
- const Rect& swapRect(surface->swapRectangle());
- if (swapRect.isValid()) {
- dirty.set(swapRect);
- }
-
- // transmit the dirty region
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- _send_dirty_region(lcblk, dirty);
- uint32_t newstate = cblk->unlock_layer_and_post(size_t(index));
- if (!(newstate & eNextFlipPending))
- _signal_server();
- return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::unlockSurface(Surface* surface)
-{
- Mutex::Autolock _l(surface->getLock());
-
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface);
- if (err != NO_ERROR)
- return err;
-
- layer_cblk_t* const lcblk = &(cblk->layers[index]);
- cblk->unlock_layer(size_t(index));
- return NO_ERROR;
-}
-
void SurfaceComposerClient::openGlobalTransaction()
{
Mutex::Autolock _l(gLock);
@@ -866,14 +616,8 @@ status_t SurfaceComposerClient::closeTransaction()
return NO_ERROR;
}
-layer_state_t* SurfaceComposerClient::_get_state_l(const sp<Surface>& surface)
+layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index)
{
- SurfaceID index = surface->ID();
- per_client_cblk_t* const cblk = mControl;
- status_t err = validateSurface(cblk, surface.get());
- if (err != NO_ERROR)
- return 0;
-
// API usage error, do nothing.
if (mTransactionOpen<=0) {
LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d",
@@ -892,11 +636,11 @@ layer_state_t* SurfaceComposerClient::_get_state_l(const sp<Surface>& surface)
return mStates.editArray() + i;
}
-layer_state_t* SurfaceComposerClient::_lockLayerState(const sp<Surface>& surface)
+layer_state_t* SurfaceComposerClient::_lockLayerState(SurfaceID id)
{
layer_state_t* s;
mLock.lock();
- s = _get_state_l(surface);
+ s = _get_state_l(id);
if (!s) mLock.unlock();
return s;
}
@@ -906,9 +650,9 @@ void SurfaceComposerClient::_unlockLayerState()
mLock.unlock();
}
-status_t SurfaceComposerClient::setPosition(Surface* surface, int32_t x, int32_t y)
+status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::ePositionChanged;
s->x = x;
@@ -917,9 +661,9 @@ status_t SurfaceComposerClient::setPosition(Surface* surface, int32_t x, int32_t
return NO_ERROR;
}
-status_t SurfaceComposerClient::setSize(Surface* surface, uint32_t w, uint32_t h)
+status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eSizeChanged;
s->w = w;
@@ -928,9 +672,9 @@ status_t SurfaceComposerClient::setSize(Surface* surface, uint32_t w, uint32_t h
return NO_ERROR;
}
-status_t SurfaceComposerClient::setLayer(Surface* surface, int32_t z)
+status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eLayerChanged;
s->z = z;
@@ -938,32 +682,32 @@ status_t SurfaceComposerClient::setLayer(Surface* surface, int32_t z)
return NO_ERROR;
}
-status_t SurfaceComposerClient::hide(Surface* surface)
+status_t SurfaceComposerClient::hide(SurfaceID id)
{
- return setFlags(surface, ISurfaceComposer::eLayerHidden,
+ return setFlags(id, ISurfaceComposer::eLayerHidden,
ISurfaceComposer::eLayerHidden);
}
-status_t SurfaceComposerClient::show(Surface* surface, int32_t)
+status_t SurfaceComposerClient::show(SurfaceID id, int32_t)
{
- return setFlags(surface, 0, ISurfaceComposer::eLayerHidden);
+ return setFlags(id, 0, ISurfaceComposer::eLayerHidden);
}
-status_t SurfaceComposerClient::freeze(Surface* surface)
+status_t SurfaceComposerClient::freeze(SurfaceID id)
{
- return setFlags(surface, ISurfaceComposer::eLayerFrozen,
+ return setFlags(id, ISurfaceComposer::eLayerFrozen,
ISurfaceComposer::eLayerFrozen);
}
-status_t SurfaceComposerClient::unfreeze(Surface* surface)
+status_t SurfaceComposerClient::unfreeze(SurfaceID id)
{
- return setFlags(surface, 0, ISurfaceComposer::eLayerFrozen);
+ return setFlags(id, 0, ISurfaceComposer::eLayerFrozen);
}
-status_t SurfaceComposerClient::setFlags(Surface* surface,
+status_t SurfaceComposerClient::setFlags(SurfaceID id,
uint32_t flags, uint32_t mask)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eVisibilityChanged;
s->flags &= ~mask;
@@ -973,11 +717,10 @@ status_t SurfaceComposerClient::setFlags(Surface* surface,
return NO_ERROR;
}
-
status_t SurfaceComposerClient::setTransparentRegionHint(
- Surface* surface, const Region& transparentRegion)
+ SurfaceID id, const Region& transparentRegion)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eTransparentRegionChanged;
s->transparentRegion = transparentRegion;
@@ -985,9 +728,9 @@ status_t SurfaceComposerClient::setTransparentRegionHint(
return NO_ERROR;
}
-status_t SurfaceComposerClient::setAlpha(Surface* surface, float alpha)
+status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eAlphaChanged;
s->alpha = alpha;
@@ -996,11 +739,11 @@ status_t SurfaceComposerClient::setAlpha(Surface* surface, float alpha)
}
status_t SurfaceComposerClient::setMatrix(
- Surface* surface,
+ SurfaceID id,
float dsdx, float dtdx,
float dsdy, float dtdy )
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eMatrixChanged;
layer_state_t::matrix22_t matrix;
@@ -1013,9 +756,9 @@ status_t SurfaceComposerClient::setMatrix(
return NO_ERROR;
}
-status_t SurfaceComposerClient::setFreezeTint(Surface* surface, uint32_t tint)
+status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
{
- layer_state_t* s = _lockLayerState(surface);
+ layer_state_t* s = _lockLayerState(id);
if (!s) return BAD_INDEX;
s->what |= ISurfaceComposer::eFreezeTintChanged;
s->tint = tint;
diff --git a/libs/ui/SurfaceFlingerSynchro.cpp b/libs/ui/SurfaceFlingerSynchro.cpp
index 5cd9755..c81db71 100644
--- a/libs/ui/SurfaceFlingerSynchro.cpp
+++ b/libs/ui/SurfaceFlingerSynchro.cpp
@@ -14,19 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceFlingerSynchro"
-
#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <utils/IPCThreadState.h>
-#include <utils/Log.h>
#include <private/ui/SurfaceFlingerSynchro.h>
@@ -34,61 +22,10 @@ namespace android {
// ---------------------------------------------------------------------------
-SurfaceFlingerSynchro::Barrier::Barrier()
- : state(CLOSED) {
-}
-
-SurfaceFlingerSynchro::Barrier::~Barrier() {
-}
-
-void SurfaceFlingerSynchro::Barrier::open() {
- asm volatile ("":::"memory");
- Mutex::Autolock _l(lock);
- state = OPENED;
- cv.broadcast();
-}
-
-void SurfaceFlingerSynchro::Barrier::close() {
- Mutex::Autolock _l(lock);
- state = CLOSED;
-}
-
-void SurfaceFlingerSynchro::Barrier::waitAndClose()
-{
- Mutex::Autolock _l(lock);
- while (state == CLOSED) {
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- cv.wait(lock);
- }
- state = CLOSED;
-}
-
-status_t SurfaceFlingerSynchro::Barrier::waitAndClose(nsecs_t timeout)
-{
- Mutex::Autolock _l(lock);
- while (state == CLOSED) {
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- int err = cv.waitRelative(lock, timeout);
- if (err != 0)
- return err;
- }
- state = CLOSED;
- return NO_ERROR;
-}
-
-// ---------------------------------------------------------------------------
-
SurfaceFlingerSynchro::SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger)
: mSurfaceComposer(flinger)
{
}
-
-SurfaceFlingerSynchro::SurfaceFlingerSynchro()
-{
-}
-
SurfaceFlingerSynchro::~SurfaceFlingerSynchro()
{
}
@@ -99,24 +36,6 @@ status_t SurfaceFlingerSynchro::signal()
return NO_ERROR;
}
-status_t SurfaceFlingerSynchro::wait()
-{
- mBarrier.waitAndClose();
- return NO_ERROR;
-}
-
-status_t SurfaceFlingerSynchro::wait(nsecs_t timeout)
-{
- if (timeout == 0)
- return SurfaceFlingerSynchro::wait();
- return mBarrier.waitAndClose(timeout);
-}
-
-void SurfaceFlingerSynchro::open()
-{
- mBarrier.open();
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
new file mode 100644
index 0000000..6cc4a5a
--- /dev/null
+++ b/libs/ui/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ region.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libui
+
+LOCAL_MODULE:= test-region
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/libs/ui/tests/region.cpp b/libs/ui/tests/region.cpp
new file mode 100644
index 0000000..0deb2ba
--- /dev/null
+++ b/libs/ui/tests/region.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.
+ */
+
+#define LOG_TAG "Region"
+
+#include <stdio.h>
+#include <utils/Debug.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+using namespace android;
+
+int main()
+{
+ Region reg0( Rect( 0, 0, 100, 100 ) );
+ Region reg1 = reg0;
+ Region reg2, reg3;
+
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ reg0 = reg0 | reg0.translate(150, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ reg0 = reg0 | reg0.translate(300, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+
+ //reg2 = reg0 | reg0.translate(0, 100);
+ //reg0.dump("reg0");
+ //reg1.dump("reg1");
+ //reg2.dump("reg2");
+
+ //reg3 = reg0 | reg0.translate(0, 150);
+ //reg0.dump("reg0");
+ //reg1.dump("reg1");
+ //reg2.dump("reg2");
+ //reg3.dump("reg3");
+
+ LOGD("---");
+ reg2 = reg0 | reg0.translate(100, 0);
+ reg0.dump("reg0");
+ reg1.dump("reg1");
+ reg2.dump("reg2");
+
+ return 0;
+}
+
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 9bdd64a..59409a2 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -32,52 +32,24 @@ 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)
-
-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
-endif
+LOCAL_SRC_FILES:= $(commonSources)
LOCAL_MODULE:= libutils
@@ -103,37 +75,18 @@ 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
-LOCAL_SRC_FILES += futex_synchro.c
LOCAL_LDLIBS += -lrt -ldl
endif
LOCAL_C_INCLUDES += \
external/zlib \
external/icu4c/common
+
LOCAL_LDLIBS += -lpthread
LOCAL_SHARED_LIBRARIES := \
@@ -144,15 +97,10 @@ LOCAL_SHARED_LIBRARIES := \
ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
# This is needed on x86 to bring in dl_iterate_phdr for CallStack.cpp
-LOCAL_SHARED_LIBRARIES += \
- libdl
+LOCAL_SHARED_LIBRARIES += libdl
endif # linux-x86
endif # sim
LOCAL_MODULE:= libutils
-
-#LOCAL_CFLAGS+=
-#LOCAL_LDFLAGS:=
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index cce754a..0cef35a 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -193,9 +193,11 @@ BackupDataReader::Status()
if ((actual) != (expected)) { \
if ((actual) == 0) { \
m_status = EIO; \
+ m_done = true; \
} else { \
m_status = errno; \
} \
+ LOGD("CHECK_SIZE failed with at line %d m_status='%s'", __LINE__, strerror(m_status)); \
return m_status; \
} \
} while(0)
@@ -203,6 +205,7 @@ BackupDataReader::Status()
do { \
status_t err = skip_padding(); \
if (err != NO_ERROR) { \
+ LOGD("SKIP_PADDING FAILED at line %d", __LINE__); \
m_status = err; \
return err; \
} \
@@ -218,10 +221,19 @@ BackupDataReader::ReadNextHeader(bool* done, int* type)
int amt;
- // No error checking here, in case we're at the end of the stream. Just let read() fail.
- skip_padding();
+ amt = skip_padding();
+ if (amt == EIO) {
+ *done = m_done = true;
+ return NO_ERROR;
+ }
+ else if (amt != NO_ERROR) {
+ return amt;
+ }
amt = read(m_fd, &m_header, sizeof(m_header));
*done = m_done = (amt == 0);
+ if (*done) {
+ return NO_ERROR;
+ }
CHECK_SIZE(amt, sizeof(m_header));
m_pos += sizeof(m_header);
if (type) {
@@ -298,10 +310,12 @@ BackupDataReader::SkipEntityData()
}
if (m_header.entity.dataSize > 0) {
int pos = lseek(m_fd, m_dataEndPos, SEEK_SET);
- return pos == -1 ? (int)errno : (int)NO_ERROR;
- } else {
- return NO_ERROR;
+ if (pos == -1) {
+ return errno;
+ }
}
+ SKIP_PADDING();
+ return NO_ERROR;
}
ssize_t
@@ -325,6 +339,10 @@ BackupDataReader::ReadEntityData(void* data, size_t size)
m_status = errno;
return -1;
}
+ if (amt == 0) {
+ m_status = EIO;
+ m_done = true;
+ }
m_pos += amt;
return amt;
}
diff --git a/libs/utils/Binder.cpp b/libs/utils/Binder.cpp
deleted file mode 100644
index 37e4685..0000000
--- a/libs/utils/Binder.cpp
+++ /dev/null
@@ -1,242 +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.
- */
-
-#include <utils/Binder.h>
-
-#include <utils/Atomic.h>
-#include <utils/BpBinder.h>
-#include <utils/IInterface.h>
-#include <utils/Parcel.h>
-
-#include <stdio.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-sp<IInterface> IBinder::queryLocalInterface(const String16& descriptor)
-{
- return NULL;
-}
-
-BBinder* IBinder::localBinder()
-{
- return NULL;
-}
-
-BpBinder* IBinder::remoteBinder()
-{
- return NULL;
-}
-
-bool IBinder::checkSubclass(const void* /*subclassID*/) const
-{
- return false;
-}
-
-// ---------------------------------------------------------------------------
-
-class BBinder::Extras
-{
-public:
- Mutex mLock;
- BpBinder::ObjectManager mObjects;
-};
-
-// ---------------------------------------------------------------------------
-
-BBinder::BBinder()
- : mExtras(NULL)
-{
-}
-
-bool BBinder::isBinderAlive() const
-{
- return true;
-}
-
-status_t BBinder::pingBinder()
-{
- return NO_ERROR;
-}
-
-String16 BBinder::getInterfaceDescriptor() const
-{
- LOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this);
- return String16();
-}
-
-status_t BBinder::transact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- data.setDataPosition(0);
-
- status_t err = NO_ERROR;
- switch (code) {
- case PING_TRANSACTION:
- reply->writeInt32(pingBinder());
- break;
- default:
- err = onTransact(code, data, reply, flags);
- break;
- }
-
- if (reply != NULL) {
- reply->setDataPosition(0);
- }
-
- return err;
-}
-
-status_t BBinder::linkToDeath(
- const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
-{
- return INVALID_OPERATION;
-}
-
-status_t BBinder::unlinkToDeath(
- const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
- wp<DeathRecipient>* outRecipient)
-{
- return INVALID_OPERATION;
-}
-
-status_t BBinder::dump(int fd, const Vector<String16>& args)
-{
- return NO_ERROR;
-}
-
-void BBinder::attachObject(
- const void* objectID, void* object, void* cleanupCookie,
- object_cleanup_func func)
-{
- Extras* e = mExtras;
-
- if (!e) {
- e = new Extras;
- if (android_atomic_cmpxchg(0, reinterpret_cast<int32_t>(e),
- reinterpret_cast<volatile int32_t*>(&mExtras)) != 0) {
- delete e;
- e = mExtras;
- }
- if (e == 0) return; // out of memory
- }
-
- AutoMutex _l(e->mLock);
- e->mObjects.attach(objectID, object, cleanupCookie, func);
-}
-
-void* BBinder::findObject(const void* objectID) const
-{
- Extras* e = mExtras;
- if (!e) return NULL;
-
- AutoMutex _l(e->mLock);
- return e->mObjects.find(objectID);
-}
-
-void BBinder::detachObject(const void* objectID)
-{
- Extras* e = mExtras;
- if (!e) return;
-
- AutoMutex _l(e->mLock);
- e->mObjects.detach(objectID);
-}
-
-BBinder* BBinder::localBinder()
-{
- return this;
-}
-
-BBinder::~BBinder()
-{
- if (mExtras) delete mExtras;
-}
-
-
-status_t BBinder::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch (code) {
- case INTERFACE_TRANSACTION:
- reply->writeString16(getInterfaceDescriptor());
- return NO_ERROR;
-
- case DUMP_TRANSACTION: {
- int fd = data.readFileDescriptor();
- int argc = data.readInt32();
- Vector<String16> args;
- for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
- args.add(data.readString16());
- }
- return dump(fd, args);
- }
- default:
- return UNKNOWN_TRANSACTION;
- }
-}
-
-// ---------------------------------------------------------------------------
-
-enum {
- // This is used to transfer ownership of the remote binder from
- // the BpRefBase object holding it (when it is constructed), to the
- // owner of the BpRefBase object when it first acquires that BpRefBase.
- kRemoteAcquired = 0x00000001
-};
-
-BpRefBase::BpRefBase(const sp<IBinder>& o)
- : mRemote(o.get()), mRefs(NULL), mState(0)
-{
- extendObjectLifetime(OBJECT_LIFETIME_WEAK);
-
- if (mRemote) {
- mRemote->incStrong(this); // Removed on first IncStrong().
- mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
- }
-}
-
-BpRefBase::~BpRefBase()
-{
- if (mRemote) {
- if (!(mState&kRemoteAcquired)) {
- mRemote->decStrong(this);
- }
- mRefs->decWeak(this);
- }
-}
-
-void BpRefBase::onFirstRef()
-{
- android_atomic_or(kRemoteAcquired, &mState);
-}
-
-void BpRefBase::onLastStrongRef(const void* id)
-{
- if (mRemote) {
- mRemote->decStrong(this);
- }
-}
-
-bool BpRefBase::onIncStrongAttempted(uint32_t flags, const void* id)
-{
- return mRemote ? mRefs->attemptIncStrong(this) : false;
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/utils/BpBinder.cpp b/libs/utils/BpBinder.cpp
deleted file mode 100644
index 69ab195..0000000
--- a/libs/utils/BpBinder.cpp
+++ /dev/null
@@ -1,348 +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.
- */
-
-#define LOG_TAG "BpBinder"
-//#define LOG_NDEBUG 0
-
-#include <utils/BpBinder.h>
-
-#include <utils/IPCThreadState.h>
-#include <utils/Log.h>
-
-#include <stdio.h>
-
-//#undef LOGV
-//#define LOGV(...) fprintf(stderr, __VA_ARGS__)
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-BpBinder::ObjectManager::ObjectManager()
-{
-}
-
-BpBinder::ObjectManager::~ObjectManager()
-{
- kill();
-}
-
-void BpBinder::ObjectManager::attach(
- const void* objectID, void* object, void* cleanupCookie,
- IBinder::object_cleanup_func func)
-{
- entry_t e;
- e.object = object;
- e.cleanupCookie = cleanupCookie;
- e.func = func;
-
- if (mObjects.indexOfKey(objectID) >= 0) {
- LOGE("Trying to attach object ID %p to binder ObjectManager %p with object %p, but object ID already in use",
- objectID, this, object);
- return;
- }
-
- mObjects.add(objectID, e);
-}
-
-void* BpBinder::ObjectManager::find(const void* objectID) const
-{
- const ssize_t i = mObjects.indexOfKey(objectID);
- if (i < 0) return NULL;
- return mObjects.valueAt(i).object;
-}
-
-void BpBinder::ObjectManager::detach(const void* objectID)
-{
- mObjects.removeItem(objectID);
-}
-
-void BpBinder::ObjectManager::kill()
-{
- const size_t N = mObjects.size();
- LOGV("Killing %d objects in manager %p", N, this);
- for (size_t i=0; i<N; i++) {
- const entry_t& e = mObjects.valueAt(i);
- if (e.func != NULL) {
- e.func(mObjects.keyAt(i), e.object, e.cleanupCookie);
- }
- }
-
- mObjects.clear();
-}
-
-// ---------------------------------------------------------------------------
-
-BpBinder::BpBinder(int32_t handle)
- : mHandle(handle)
- , mAlive(1)
- , mObitsSent(0)
- , mObituaries(NULL)
-{
- LOGV("Creating BpBinder %p handle %d\n", this, mHandle);
-
- extendObjectLifetime(OBJECT_LIFETIME_WEAK);
- IPCThreadState::self()->incWeakHandle(handle);
-}
-
-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();
- }
- return res;
-}
-
-bool BpBinder::isBinderAlive() const
-{
- return mAlive != 0;
-}
-
-status_t BpBinder::pingBinder()
-{
- Parcel send;
- Parcel reply;
- status_t err = transact(PING_TRANSACTION, send, &reply);
- if (err != NO_ERROR) return err;
- if (reply.dataSize() < sizeof(status_t)) return NOT_ENOUGH_DATA;
- return (status_t)reply.readInt32();
-}
-
-status_t BpBinder::dump(int fd, const Vector<String16>& args)
-{
- Parcel send;
- Parcel reply;
- send.writeFileDescriptor(fd);
- const size_t numArgs = args.size();
- send.writeInt32(numArgs);
- for (size_t i = 0; i < numArgs; i++) {
- send.writeString16(args[i]);
- }
- status_t err = transact(DUMP_TRANSACTION, send, &reply);
- return err;
-}
-
-status_t BpBinder::transact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- // Once a binder has died, it will never come back to life.
- if (mAlive) {
- status_t status = IPCThreadState::self()->transact(
- mHandle, code, data, reply, flags);
- if (status == DEAD_OBJECT) mAlive = 0;
- return status;
- }
-
- return DEAD_OBJECT;
-}
-
-status_t BpBinder::linkToDeath(
- const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
-{
- Obituary ob;
- ob.recipient = recipient;
- ob.cookie = cookie;
- ob.flags = flags;
-
- LOG_ALWAYS_FATAL_IF(recipient == NULL,
- "linkToDeath(): recipient must be non-NULL");
-
- {
- AutoMutex _l(mLock);
-
- if (!mObitsSent) {
- if (!mObituaries) {
- mObituaries = new Vector<Obituary>;
- if (!mObituaries) {
- return NO_MEMORY;
- }
- LOGV("Requesting death notification: %p handle %d\n", this, mHandle);
- getWeakRefs()->incWeak(this);
- IPCThreadState* self = IPCThreadState::self();
- self->requestDeathNotification(mHandle, this);
- self->flushCommands();
- }
- ssize_t res = mObituaries->add(ob);
- return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
- }
- }
-
- return DEAD_OBJECT;
-}
-
-status_t BpBinder::unlinkToDeath(
- const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
- wp<DeathRecipient>* outRecipient)
-{
- AutoMutex _l(mLock);
-
- if (mObitsSent) {
- return DEAD_OBJECT;
- }
-
- const size_t N = mObituaries ? mObituaries->size() : 0;
- for (size_t i=0; i<N; i++) {
- const Obituary& obit = mObituaries->itemAt(i);
- if ((obit.recipient == recipient
- || (recipient == NULL && obit.cookie == cookie))
- && obit.flags == flags) {
- const uint32_t allFlags = obit.flags|flags;
- if (outRecipient != NULL) {
- *outRecipient = mObituaries->itemAt(i).recipient;
- }
- mObituaries->removeAt(i);
- if (mObituaries->size() == 0) {
- LOGV("Clearing death notification: %p handle %d\n", this, mHandle);
- IPCThreadState* self = IPCThreadState::self();
- self->clearDeathNotification(mHandle, this);
- self->flushCommands();
- delete mObituaries;
- mObituaries = NULL;
- }
- return NO_ERROR;
- }
- }
-
- return NAME_NOT_FOUND;
-}
-
-void BpBinder::sendObituary()
-{
- LOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
- this, mHandle, mObitsSent ? "true" : "false");
-
- mAlive = 0;
- if (mObitsSent) return;
-
- mLock.lock();
- Vector<Obituary>* obits = mObituaries;
- if(obits != NULL) {
- LOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
- IPCThreadState* self = IPCThreadState::self();
- self->clearDeathNotification(mHandle, this);
- self->flushCommands();
- mObituaries = NULL;
- }
- mObitsSent = 1;
- mLock.unlock();
-
- LOGV("Reporting death of proxy %p for %d recipients\n",
- this, obits ? obits->size() : 0);
-
- if (obits != NULL) {
- const size_t N = obits->size();
- for (size_t i=0; i<N; i++) {
- reportOneDeath(obits->itemAt(i));
- }
-
- delete obits;
- }
-}
-
-void BpBinder::reportOneDeath(const Obituary& obit)
-{
- sp<DeathRecipient> recipient = obit.recipient.promote();
- LOGV("Reporting death to recipient: %p\n", recipient.get());
- if (recipient == NULL) return;
-
- recipient->binderDied(this);
-}
-
-
-void BpBinder::attachObject(
- const void* objectID, void* object, void* cleanupCookie,
- object_cleanup_func func)
-{
- AutoMutex _l(mLock);
- LOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects);
- mObjects.attach(objectID, object, cleanupCookie, func);
-}
-
-void* BpBinder::findObject(const void* objectID) const
-{
- AutoMutex _l(mLock);
- return mObjects.find(objectID);
-}
-
-void BpBinder::detachObject(const void* objectID)
-{
- AutoMutex _l(mLock);
- mObjects.detach(objectID);
-}
-
-BpBinder* BpBinder::remoteBinder()
-{
- return this;
-}
-
-BpBinder::~BpBinder()
-{
- LOGV("Destroying BpBinder %p handle %d\n", this, mHandle);
-
- IPCThreadState* ipc = IPCThreadState::self();
-
- mLock.lock();
- Vector<Obituary>* obits = mObituaries;
- if(obits != NULL) {
- if (ipc) ipc->clearDeathNotification(mHandle, this);
- mObituaries = NULL;
- }
- mLock.unlock();
-
- if (obits != NULL) {
- // XXX Should we tell any remaining DeathRecipient
- // objects that the last strong ref has gone away, so they
- // are no longer linked?
- delete obits;
- }
-
- if (ipc) {
- ipc->expungeHandle(mHandle, this);
- ipc->decWeakHandle(mHandle);
- }
-}
-
-void BpBinder::onFirstRef()
-{
- LOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
- IPCThreadState* ipc = IPCThreadState::self();
- if (ipc) ipc->incStrongHandle(mHandle);
-}
-
-void BpBinder::onLastStrongRef(const void* id)
-{
- LOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle);
- IF_LOGV() {
- printRefs();
- }
- IPCThreadState* ipc = IPCThreadState::self();
- if (ipc) ipc->decStrongHandle(mHandle);
-}
-
-bool BpBinder::onIncStrongAttempted(uint32_t flags, const void* id)
-{
- LOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle);
- IPCThreadState* ipc = IPCThreadState::self();
- return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
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/IInterface.cpp b/libs/utils/IInterface.cpp
deleted file mode 100644
index 6ea8178..0000000
--- a/libs/utils/IInterface.cpp
+++ /dev/null
@@ -1,35 +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.
- */
-
-#include <utils/IInterface.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-sp<IBinder> IInterface::asBinder()
-{
- return this ? onAsBinder() : NULL;
-}
-
-sp<const IBinder> IInterface::asBinder() const
-{
- return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
-}
-
-// ---------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libs/utils/IMemory.cpp b/libs/utils/IMemory.cpp
deleted file mode 100644
index 429bc2b..0000000
--- a/libs/utils/IMemory.cpp
+++ /dev/null
@@ -1,486 +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.
- */
-
-#define LOG_TAG "IMemory"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <utils/IMemory.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-#include <utils/Atomic.h>
-#include <utils/Parcel.h>
-#include <utils/CallStack.h>
-
-#define VERBOSE 0
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class HeapCache : public IBinder::DeathRecipient
-{
-public:
- HeapCache();
- virtual ~HeapCache();
-
- virtual void binderDied(const wp<IBinder>& who);
-
- sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);
- void pin_heap(const sp<IBinder>& binder);
- void free_heap(const sp<IBinder>& binder);
- sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
- void dump_heaps();
-
-private:
- // For IMemory.cpp
- struct heap_info_t {
- sp<IMemoryHeap> heap;
- int32_t count;
- };
-
- void free_heap(const wp<IBinder>& binder);
-
- Mutex mHeapCacheLock;
- KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
-};
-
-static sp<HeapCache> gHeapCache = new HeapCache();
-
-/******************************************************************************/
-
-enum {
- HEAP_ID = IBinder::FIRST_CALL_TRANSACTION
-};
-
-class BpMemoryHeap : public BpInterface<IMemoryHeap>
-{
-public:
- BpMemoryHeap(const sp<IBinder>& impl);
- virtual ~BpMemoryHeap();
-
- virtual int getHeapID() const;
- virtual void* getBase() const;
- virtual size_t getSize() const;
- virtual uint32_t getFlags() const;
-
-private:
- friend class IMemory;
- friend class HeapCache;
-
- // for debugging in this module
- static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
- return gHeapCache->find_heap(binder);
- }
- static inline void free_heap(const sp<IBinder>& binder) {
- gHeapCache->free_heap(binder);
- }
- static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) {
- return gHeapCache->get_heap(binder);
- }
- static inline void dump_heaps() {
- gHeapCache->dump_heaps();
- }
- void inline pin_heap() const {
- gHeapCache->pin_heap(const_cast<BpMemoryHeap*>(this)->asBinder());
- }
-
- void assertMapped() const;
- void assertReallyMapped() const;
- void pinHeap() const;
-
- mutable volatile int32_t mHeapId;
- mutable void* mBase;
- mutable size_t mSize;
- mutable uint32_t mFlags;
- mutable bool mRealHeap;
- mutable Mutex mLock;
-};
-
-// ----------------------------------------------------------------------------
-
-enum {
- GET_MEMORY = IBinder::FIRST_CALL_TRANSACTION
-};
-
-class BpMemory : public BpInterface<IMemory>
-{
-public:
- BpMemory(const sp<IBinder>& impl);
- virtual ~BpMemory();
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
-
-private:
- mutable sp<IMemoryHeap> mHeap;
- mutable ssize_t mOffset;
- mutable size_t mSize;
-};
-
-/******************************************************************************/
-
-void* IMemory::fastPointer(const sp<IBinder>& binder, ssize_t offset) const
-{
- sp<IMemoryHeap> realHeap = BpMemoryHeap::get_heap(binder);
- void* const base = realHeap->base();
- if (base == MAP_FAILED)
- return 0;
- return static_cast<char*>(base) + offset;
-}
-
-void* IMemory::pointer() const {
- ssize_t offset;
- sp<IMemoryHeap> heap = getMemory(&offset);
- void* const base = heap!=0 ? heap->base() : MAP_FAILED;
- if (base == MAP_FAILED)
- return 0;
- return static_cast<char*>(base) + offset;
-}
-
-size_t IMemory::size() const {
- size_t size;
- getMemory(NULL, &size);
- return size;
-}
-
-ssize_t IMemory::offset() const {
- ssize_t offset;
- getMemory(&offset);
- return offset;
-}
-
-/******************************************************************************/
-
-BpMemory::BpMemory(const sp<IBinder>& impl)
- : BpInterface<IMemory>(impl), mOffset(0), mSize(0)
-{
-}
-
-BpMemory::~BpMemory()
-{
-}
-
-sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
-{
- if (mHeap == 0) {
- Parcel data, reply;
- data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
- if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
- sp<IBinder> heap = reply.readStrongBinder();
- ssize_t o = reply.readInt32();
- size_t s = reply.readInt32();
- if (heap != 0) {
- mHeap = interface_cast<IMemoryHeap>(heap);
- if (mHeap != 0) {
- mOffset = o;
- mSize = s;
- }
- }
- }
- }
- if (offset) *offset = mOffset;
- if (size) *size = mSize;
- return mHeap;
-}
-
-// ---------------------------------------------------------------------------
-
-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)
-
-status_t BnMemory::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case GET_MEMORY: {
- CHECK_INTERFACE(IMemory, data, reply);
- ssize_t offset;
- size_t size;
- reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );
- reply->writeInt32(offset);
- reply->writeInt32(size);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-
-/******************************************************************************/
-
-BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
- : BpInterface<IMemoryHeap>(impl),
- mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
-{
-}
-
-BpMemoryHeap::~BpMemoryHeap() {
- if (mHeapId != -1) {
- close(mHeapId);
- if (mRealHeap) {
- // by construction we're the last one
- if (mBase != MAP_FAILED) {
- sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
-
- if (VERBOSE) {
- LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d",
- binder.get(), this, mSize, mHeapId);
- CallStack stack;
- stack.update();
- stack.dump("callstack");
- }
-
- munmap(mBase, mSize);
- }
- } else {
- // remove from list only if it was mapped before
- sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
- free_heap(binder);
- }
- }
-}
-
-void BpMemoryHeap::assertMapped() const
-{
- if (mHeapId == -1) {
- sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder());
- sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
- heap->assertReallyMapped();
- if (heap->mBase != MAP_FAILED) {
- Mutex::Autolock _l(mLock);
- if (mHeapId == -1) {
- mBase = heap->mBase;
- mSize = heap->mSize;
- android_atomic_write( dup( heap->mHeapId ), &mHeapId );
- }
- } else {
- // something went wrong
- free_heap(binder);
- }
- }
-}
-
-void BpMemoryHeap::assertReallyMapped() const
-{
- if (mHeapId == -1) {
-
- // remote call without mLock held, worse case scenario, we end up
- // calling transact() from multiple threads, but that's not a problem,
- // only mmap below must be in the critical section.
-
- Parcel data, reply;
- data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
- status_t err = remote()->transact(HEAP_ID, data, &reply);
- int parcel_fd = reply.readFileDescriptor();
- ssize_t size = reply.readInt32();
- uint32_t flags = reply.readInt32();
-
- LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%d, 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)",
- parcel_fd, size, err, strerror(errno));
-
- int access = PROT_READ;
- if (!(flags & READ_ONLY)) {
- access |= PROT_WRITE;
- }
-
- Mutex::Autolock _l(mLock);
- if (mHeapId == -1) {
- 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)",
- asBinder().get(), size, fd, strerror(errno));
- close(fd);
- } else {
- if (flags & MAP_ONCE) {
- //LOGD("pinning heap (binder=%p, size=%d, fd=%d",
- // asBinder().get(), size, fd);
- pin_heap();
- }
- mSize = size;
- mFlags = flags;
- android_atomic_write(fd, &mHeapId);
- }
- }
- }
-}
-
-int BpMemoryHeap::getHeapID() const {
- assertMapped();
- return mHeapId;
-}
-
-void* BpMemoryHeap::getBase() const {
- assertMapped();
- return mBase;
-}
-
-size_t BpMemoryHeap::getSize() const {
- assertMapped();
- return mSize;
-}
-
-uint32_t BpMemoryHeap::getFlags() const {
- assertMapped();
- return mFlags;
-}
-
-// ---------------------------------------------------------------------------
-
-IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
-
-status_t BnMemoryHeap::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case HEAP_ID: {
- CHECK_INTERFACE(IMemoryHeap, data, reply);
- reply->writeFileDescriptor(getHeapID());
- reply->writeInt32(getSize());
- reply->writeInt32(getFlags());
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-/*****************************************************************************/
-
-HeapCache::HeapCache()
- : DeathRecipient()
-{
-}
-
-HeapCache::~HeapCache()
-{
-}
-
-void HeapCache::binderDied(const wp<IBinder>& binder)
-{
- //LOGD("binderDied binder=%p", binder.unsafe_get());
- free_heap(binder);
-}
-
-sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
-{
- Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info = mHeapCache.editValueAt(i);
- LOGD_IF(VERBOSE,
- "found binder=%p, heap=%p, size=%d, fd=%d, count=%d",
- binder.get(), info.heap.get(),
- static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
- static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
- info.count);
- android_atomic_inc(&info.count);
- return info.heap;
- } else {
- heap_info_t info;
- info.heap = interface_cast<IMemoryHeap>(binder);
- info.count = 1;
- //LOGD("adding binder=%p, heap=%p, count=%d",
- // binder.get(), info.heap.get(), info.count);
- mHeapCache.add(binder, info);
- return info.heap;
- }
-}
-
-void HeapCache::pin_heap(const sp<IBinder>& binder)
-{
- Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info(mHeapCache.editValueAt(i));
- android_atomic_inc(&info.count);
- binder->linkToDeath(this);
- } else {
- LOGE("pin_heap binder=%p not found!!!", binder.get());
- }
-}
-
-void HeapCache::free_heap(const sp<IBinder>& binder) {
- free_heap( wp<IBinder>(binder) );
-}
-
-void HeapCache::free_heap(const wp<IBinder>& binder)
-{
- sp<IMemoryHeap> rel;
- {
- Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) {
- heap_info_t& info(mHeapCache.editValueAt(i));
- int32_t c = android_atomic_dec(&info.count);
- if (c == 1) {
- LOGD_IF(VERBOSE,
- "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d",
- binder.unsafe_get(), info.heap.get(),
- static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
- static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
- info.count);
- rel = mHeapCache.valueAt(i).heap;
- mHeapCache.removeItemsAt(i);
- }
- } else {
- LOGE("free_heap binder=%p not found!!!", binder.unsafe_get());
- }
- }
-}
-
-sp<IMemoryHeap> HeapCache::get_heap(const sp<IBinder>& binder)
-{
- sp<IMemoryHeap> realHeap;
- Mutex::Autolock _l(mHeapCacheLock);
- ssize_t i = mHeapCache.indexOfKey(binder);
- if (i>=0) realHeap = mHeapCache.valueAt(i).heap;
- else realHeap = interface_cast<IMemoryHeap>(binder);
- return realHeap;
-}
-
-void HeapCache::dump_heaps()
-{
- Mutex::Autolock _l(mHeapCacheLock);
- int c = mHeapCache.size();
- for (int i=0 ; i<c ; i++) {
- const heap_info_t& info = mHeapCache.valueAt(i);
- BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
- LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)",
- mHeapCache.keyAt(i).unsafe_get(),
- info.heap.get(), info.count,
- h->mHeapId, h->mBase, h->mSize);
- }
-}
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/utils/IPCThreadState.cpp b/libs/utils/IPCThreadState.cpp
deleted file mode 100644
index 04ae142..0000000
--- a/libs/utils/IPCThreadState.cpp
+++ /dev/null
@@ -1,1030 +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.
- */
-
-#include <utils/IPCThreadState.h>
-
-#include <utils/Binder.h>
-#include <utils/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 <sys/ioctl.h>
-#include <signal.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#ifdef HAVE_PTHREADS
-#include <pthread.h>
-#include <sched.h>
-#include <sys/resource.h>
-#endif
-#ifdef HAVE_WIN32_THREADS
-#include <windows.h>
-#endif
-
-
-#if LOG_NDEBUG
-
-#define IF_LOG_TRANSACTIONS() if (false)
-#define IF_LOG_COMMANDS() if (false)
-#define LOG_REMOTEREFS(...)
-#define IF_LOG_REMOTEREFS() if (false)
-#define LOG_THREADPOOL(...)
-#define LOG_ONEWAY(...)
-
-#else
-
-#define IF_LOG_TRANSACTIONS() IF_LOG(LOG_VERBOSE, "transact")
-#define IF_LOG_COMMANDS() IF_LOG(LOG_VERBOSE, "ipc")
-#define LOG_REMOTEREFS(...) LOG(LOG_DEBUG, "remoterefs", __VA_ARGS__)
-#define IF_LOG_REMOTEREFS() IF_LOG(LOG_DEBUG, "remoterefs")
-#define LOG_THREADPOOL(...) LOG(LOG_DEBUG, "threadpool", __VA_ARGS__)
-#define LOG_ONEWAY(...) LOG(LOG_DEBUG, "ipc", __VA_ARGS__)
-
-#endif
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-static const char* getReturnString(size_t idx);
-static const char* getCommandString(size_t idx);
-static const void* printReturnCommand(TextOutput& out, const void* _cmd);
-static const void* printCommand(TextOutput& out, const void* _cmd);
-
-// This will result in a missing symbol failure if the IF_LOG_COMMANDS()
-// conditionals don't get stripped... but that is probably what we want.
-#if !LOG_NDEBUG
-static const char *kReturnStrings[] = {
-#if 1 /* TODO: error update strings */
- "unknown",
-#else
- "BR_OK",
- "BR_TIMEOUT",
- "BR_WAKEUP",
- "BR_TRANSACTION",
- "BR_REPLY",
- "BR_ACQUIRE_RESULT",
- "BR_DEAD_REPLY",
- "BR_TRANSACTION_COMPLETE",
- "BR_INCREFS",
- "BR_ACQUIRE",
- "BR_RELEASE",
- "BR_DECREFS",
- "BR_ATTEMPT_ACQUIRE",
- "BR_EVENT_OCCURRED",
- "BR_NOOP",
- "BR_SPAWN_LOOPER",
- "BR_FINISHED",
- "BR_DEAD_BINDER",
- "BR_CLEAR_DEATH_NOTIFICATION_DONE"
-#endif
-};
-
-static const char *kCommandStrings[] = {
-#if 1 /* TODO: error update strings */
- "unknown",
-#else
- "BC_NOOP",
- "BC_TRANSACTION",
- "BC_REPLY",
- "BC_ACQUIRE_RESULT",
- "BC_FREE_BUFFER",
- "BC_TRANSACTION_COMPLETE",
- "BC_INCREFS",
- "BC_ACQUIRE",
- "BC_RELEASE",
- "BC_DECREFS",
- "BC_INCREFS_DONE",
- "BC_ACQUIRE_DONE",
- "BC_ATTEMPT_ACQUIRE",
- "BC_RETRIEVE_ROOT_OBJECT",
- "BC_SET_THREAD_ENTRY",
- "BC_REGISTER_LOOPER",
- "BC_ENTER_LOOPER",
- "BC_EXIT_LOOPER",
- "BC_SYNC",
- "BC_STOP_PROCESS",
- "BC_STOP_SELF",
- "BC_REQUEST_DEATH_NOTIFICATION",
- "BC_CLEAR_DEATH_NOTIFICATION",
- "BC_DEAD_BINDER_DONE"
-#endif
-};
-
-static const char* getReturnString(size_t idx)
-{
- if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0]))
- return kReturnStrings[idx];
- else
- return "unknown";
-}
-
-static const char* getCommandString(size_t idx)
-{
- if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[0]))
- return kCommandStrings[idx];
- else
- return "unknown";
-}
-
-static const void* printBinderTransactionData(TextOutput& out, const void* data)
-{
- const binder_transaction_data* btd =
- (const binder_transaction_data*)data;
- out << "target=" << btd->target.ptr << " (cookie " << btd->cookie << ")" << endl
- << "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl
- << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
- << " bytes)" << endl
- << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
- << " bytes)" << endl;
- return btd+1;
-}
-
-static const void* printReturnCommand(TextOutput& out, const void* _cmd)
-{
- static const int32_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]);
-
- const int32_t* cmd = (const int32_t*)_cmd;
- int32_t code = *cmd++;
- if (code == BR_ERROR) {
- out << "BR_ERROR: " << (void*)(*cmd++) << endl;
- return cmd;
- } else if (code < 0 || code >= N) {
- out << "Unknown reply: " << code << endl;
- return cmd;
- }
-
- out << kReturnStrings[code];
- switch (code) {
- case BR_TRANSACTION:
- case BR_REPLY: {
- out << ": " << indent;
- cmd = (const int32_t *)printBinderTransactionData(out, cmd);
- out << dedent;
- } break;
-
- case BR_ACQUIRE_RESULT: {
- const int32_t res = *cmd++;
- out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
- } break;
-
- case BR_INCREFS:
- case BR_ACQUIRE:
- case BR_RELEASE:
- case BR_DECREFS: {
- const int32_t b = *cmd++;
- const int32_t c = *cmd++;
- out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
- } break;
-
- case BR_ATTEMPT_ACQUIRE: {
- const int32_t p = *cmd++;
- const int32_t b = *cmd++;
- const int32_t c = *cmd++;
- out << ": target=" << (void*)b << " (cookie " << (void*)c
- << "), pri=" << p;
- } break;
-
- case BR_DEAD_BINDER:
- case BR_CLEAR_DEATH_NOTIFICATION_DONE: {
- const int32_t c = *cmd++;
- out << ": death cookie " << (void*)c;
- } break;
- }
-
- out << endl;
- return cmd;
-}
-
-static const void* printCommand(TextOutput& out, const void* _cmd)
-{
- static const int32_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
-
- const int32_t* cmd = (const int32_t*)_cmd;
- int32_t code = *cmd++;
- if (code < 0 || code >= N) {
- out << "Unknown command: " << code << endl;
- return cmd;
- }
-
- out << kCommandStrings[code];
- switch (code) {
- case BC_TRANSACTION:
- case BC_REPLY: {
- out << ": " << indent;
- cmd = (const int32_t *)printBinderTransactionData(out, cmd);
- out << dedent;
- } break;
-
- case BC_ACQUIRE_RESULT: {
- const int32_t res = *cmd++;
- out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
- } break;
-
- case BC_FREE_BUFFER: {
- const int32_t buf = *cmd++;
- out << ": buffer=" << (void*)buf;
- } break;
-
- case BC_INCREFS:
- case BC_ACQUIRE:
- case BC_RELEASE:
- case BC_DECREFS: {
- const int32_t d = *cmd++;
- out << ": descriptor=" << (void*)d;
- } break;
-
- case BC_INCREFS_DONE:
- case BC_ACQUIRE_DONE: {
- const int32_t b = *cmd++;
- const int32_t c = *cmd++;
- out << ": target=" << (void*)b << " (cookie " << (void*)c << ")";
- } break;
-
- case BC_ATTEMPT_ACQUIRE: {
- const int32_t p = *cmd++;
- const int32_t d = *cmd++;
- out << ": decriptor=" << (void*)d << ", pri=" << p;
- } break;
-
- case BC_REQUEST_DEATH_NOTIFICATION:
- case BC_CLEAR_DEATH_NOTIFICATION: {
- const int32_t h = *cmd++;
- const int32_t c = *cmd++;
- out << ": handle=" << h << " (death cookie " << (void*)c << ")";
- } break;
-
- case BC_DEAD_BINDER_DONE: {
- const int32_t c = *cmd++;
- out << ": death cookie " << (void*)c;
- } break;
- }
-
- out << endl;
- return cmd;
-}
-#endif
-
-static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
-static bool gHaveTLS = false;
-static pthread_key_t gTLS = 0;
-static bool gShutdown = false;
-
-IPCThreadState* IPCThreadState::self()
-{
- if (gHaveTLS) {
-restart:
- const pthread_key_t k = gTLS;
- IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
- if (st) return st;
- return new IPCThreadState;
- }
-
- if (gShutdown) return NULL;
-
- pthread_mutex_lock(&gTLSMutex);
- if (!gHaveTLS) {
- if (pthread_key_create(&gTLS, threadDestructor) != 0) {
- pthread_mutex_unlock(&gTLSMutex);
- return NULL;
- }
- gHaveTLS = true;
- }
- pthread_mutex_unlock(&gTLSMutex);
- goto restart;
-}
-
-void IPCThreadState::shutdown()
-{
- gShutdown = true;
-
- if (gHaveTLS) {
- // XXX Need to wait for all thread pool threads to exit!
- IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
- if (st) {
- delete st;
- pthread_setspecific(gTLS, NULL);
- }
- gHaveTLS = false;
- }
-}
-
-sp<ProcessState> IPCThreadState::process()
-{
- return mProcess;
-}
-
-status_t IPCThreadState::clearLastError()
-{
- const status_t err = mLastError;
- mLastError = NO_ERROR;
- return err;
-}
-
-int IPCThreadState::getCallingPid()
-{
- return mCallingPid;
-}
-
-int IPCThreadState::getCallingUid()
-{
- return mCallingUid;
-}
-
-int64_t IPCThreadState::clearCallingIdentity()
-{
- int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
- clearCaller();
- return token;
-}
-
-void IPCThreadState::restoreCallingIdentity(int64_t token)
-{
- mCallingUid = (int)(token>>32);
- mCallingPid = (int)token;
-}
-
-void IPCThreadState::clearCaller()
-{
- if (mProcess->supportsProcesses()) {
- mCallingPid = getpid();
- mCallingUid = getuid();
- } else {
- mCallingPid = -1;
- mCallingUid = -1;
- }
-}
-
-void IPCThreadState::flushCommands()
-{
- if (mProcess->mDriverFD <= 0)
- return;
- talkWithDriver(false);
-}
-
-void IPCThreadState::joinThreadPool(bool isMain)
-{
- LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
-
- mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
-
- status_t result;
- do {
- int32_t cmd;
-
- // When we've cleared the incoming command queue, process any pending derefs
- if (mIn.dataPosition() >= mIn.dataSize()) {
- size_t numPending = mPendingWeakDerefs.size();
- if (numPending > 0) {
- for (size_t i = 0; i < numPending; i++) {
- RefBase::weakref_type* refs = mPendingWeakDerefs[i];
- refs->decWeak(mProcess.get());
- }
- mPendingWeakDerefs.clear();
- }
-
- numPending = mPendingStrongDerefs.size();
- if (numPending > 0) {
- for (size_t i = 0; i < numPending; i++) {
- BBinder* obj = mPendingStrongDerefs[i];
- obj->decStrong(mProcess.get());
- }
- mPendingStrongDerefs.clear();
- }
- }
-
- // now get the next command to be processed, waiting if necessary
- result = talkWithDriver();
- if (result >= NO_ERROR) {
- size_t IN = mIn.dataAvail();
- if (IN < sizeof(int32_t)) continue;
- cmd = mIn.readInt32();
- IF_LOG_COMMANDS() {
- alog << "Processing top-level Command: "
- << getReturnString(cmd) << endl;
- }
- result = executeCommand(cmd);
- }
-
- // Let this thread exit the thread pool if it is no longer
- // needed and it is not the main process thread.
- if(result == TIMED_OUT && !isMain) {
- break;
- }
- } while (result != -ECONNREFUSED && result != -EBADF);
-
- LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
- (void*)pthread_self(), getpid(), (void*)result);
-
- mOut.writeInt32(BC_EXIT_LOOPER);
- talkWithDriver(false);
-}
-
-void IPCThreadState::stopProcess(bool immediate)
-{
- //LOGI("**** STOPPING PROCESS");
- flushCommands();
- int fd = mProcess->mDriverFD;
- mProcess->mDriverFD = -1;
- close(fd);
- //kill(getpid(), SIGKILL);
-}
-
-status_t IPCThreadState::transact(int32_t handle,
- uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags)
-{
- status_t err = data.errorCheck();
-
- flags |= TF_ACCEPT_FDS;
-
- IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
- << handle << " / code " << TypeCode(code) << ": "
- << indent << data << dedent << endl;
- }
-
- if (err == NO_ERROR) {
- LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
- (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
- err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
- }
-
- if (err != NO_ERROR) {
- if (reply) reply->setError(err);
- return (mLastError = err);
- }
-
- if ((flags & TF_ONE_WAY) == 0) {
- if (reply) {
- err = waitForResponse(reply);
- } else {
- Parcel fakeReply;
- err = waitForResponse(&fakeReply);
- }
-
- IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
- << handle << ": ";
- if (reply) alog << indent << *reply << dedent << endl;
- else alog << "(none requested)" << endl;
- }
- } else {
- err = waitForResponse(NULL, NULL);
- }
-
- return err;
-}
-
-void IPCThreadState::incStrongHandle(int32_t handle)
-{
- LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
- mOut.writeInt32(BC_ACQUIRE);
- mOut.writeInt32(handle);
-}
-
-void IPCThreadState::decStrongHandle(int32_t handle)
-{
- LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle);
- mOut.writeInt32(BC_RELEASE);
- mOut.writeInt32(handle);
-}
-
-void IPCThreadState::incWeakHandle(int32_t handle)
-{
- LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
- mOut.writeInt32(BC_INCREFS);
- mOut.writeInt32(handle);
-}
-
-void IPCThreadState::decWeakHandle(int32_t handle)
-{
- LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
- mOut.writeInt32(BC_DECREFS);
- mOut.writeInt32(handle);
-}
-
-status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
-{
- mOut.writeInt32(BC_ATTEMPT_ACQUIRE);
- mOut.writeInt32(0); // xxx was thread priority
- mOut.writeInt32(handle);
- status_t result = UNKNOWN_ERROR;
-
- waitForResponse(NULL, &result);
-
-#if LOG_REFCOUNTS
- printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
- handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
-#endif
-
- return result;
-}
-
-void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder)
-{
-#if LOG_REFCOUNTS
- printf("IPCThreadState::expungeHandle(%ld)\n", handle);
-#endif
- self()->mProcess->expungeHandle(handle, binder);
-}
-
-status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
-{
- mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
- mOut.writeInt32((int32_t)handle);
- mOut.writeInt32((int32_t)proxy);
- return NO_ERROR;
-}
-
-status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy)
-{
- mOut.writeInt32(BC_CLEAR_DEATH_NOTIFICATION);
- mOut.writeInt32((int32_t)handle);
- mOut.writeInt32((int32_t)proxy);
- return NO_ERROR;
-}
-
-IPCThreadState::IPCThreadState()
- : mProcess(ProcessState::self())
-{
- pthread_setspecific(gTLS, this);
- clearCaller();
- mIn.setDataCapacity(256);
- mOut.setDataCapacity(256);
-}
-
-IPCThreadState::~IPCThreadState()
-{
-}
-
-status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
-{
- status_t err;
- status_t statusBuffer;
- err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
- if (err < NO_ERROR) return err;
-
- return waitForResponse(NULL, NULL);
-}
-
-status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
-{
- int32_t cmd;
- int32_t err;
-
- while (1) {
- if ((err=talkWithDriver()) < NO_ERROR) break;
- err = mIn.errorCheck();
- if (err < NO_ERROR) break;
- if (mIn.dataAvail() == 0) continue;
-
- cmd = mIn.readInt32();
-
- IF_LOG_COMMANDS() {
- alog << "Processing waitForResponse Command: "
- << getReturnString(cmd) << endl;
- }
-
- switch (cmd) {
- case BR_TRANSACTION_COMPLETE:
- if (!reply && !acquireResult) goto finish;
- break;
-
- case BR_DEAD_REPLY:
- err = DEAD_OBJECT;
- goto finish;
-
- case BR_FAILED_REPLY:
- err = FAILED_TRANSACTION;
- goto finish;
-
- case BR_ACQUIRE_RESULT:
- {
- LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
- const int32_t result = mIn.readInt32();
- if (!acquireResult) continue;
- *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
- }
- goto finish;
-
- case BR_REPLY:
- {
- binder_transaction_data tr;
- err = mIn.read(&tr, sizeof(tr));
- LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
- if (err != NO_ERROR) goto finish;
-
- if (reply) {
- if ((tr.flags & TF_STATUS_CODE) == 0) {
- reply->ipcSetDataReference(
- reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
- tr.data_size,
- reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
- tr.offsets_size/sizeof(size_t),
- freeBuffer, this);
- } else {
- err = *static_cast<const status_t*>(tr.data.ptr.buffer);
- freeBuffer(NULL,
- reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
- tr.data_size,
- reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
- tr.offsets_size/sizeof(size_t), this);
- }
- } else {
- freeBuffer(NULL,
- reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
- tr.data_size,
- reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
- tr.offsets_size/sizeof(size_t), this);
- continue;
- }
- }
- goto finish;
-
- default:
- err = executeCommand(cmd);
- if (err != NO_ERROR) goto finish;
- break;
- }
- }
-
-finish:
- if (err != NO_ERROR) {
- if (acquireResult) *acquireResult = err;
- if (reply) reply->setError(err);
- mLastError = err;
- }
-
- return err;
-}
-
-status_t IPCThreadState::talkWithDriver(bool doReceive)
-{
- LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
-
- binder_write_read bwr;
-
- // Is the read buffer empty?
- const bool needRead = mIn.dataPosition() >= mIn.dataSize();
-
- // We don't want to write anything if we are still reading
- // from data left in the input buffer and the caller
- // has requested to read the next data.
- const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
-
- bwr.write_size = outAvail;
- bwr.write_buffer = (long unsigned int)mOut.data();
-
- // This is what we'll read.
- if (doReceive && needRead) {
- bwr.read_size = mIn.dataCapacity();
- bwr.read_buffer = (long unsigned int)mIn.data();
- } else {
- bwr.read_size = 0;
- }
-
- IF_LOG_COMMANDS() {
- TextOutput::Bundle _b(alog);
- if (outAvail != 0) {
- alog << "Sending commands to driver: " << indent;
- const void* cmds = (const void*)bwr.write_buffer;
- const void* end = ((const uint8_t*)cmds)+bwr.write_size;
- alog << HexDump(cmds, bwr.write_size) << endl;
- while (cmds < end) cmds = printCommand(alog, cmds);
- alog << dedent;
- }
- alog << "Size of receive buffer: " << bwr.read_size
- << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
- }
-
- // Return immediately if there is nothing to do.
- if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
-
- bwr.write_consumed = 0;
- bwr.read_consumed = 0;
- status_t err;
- do {
- IF_LOG_COMMANDS() {
- alog << "About to read/write, write size = " << mOut.dataSize() << endl;
- }
-#if defined(HAVE_ANDROID_OS)
- if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
- err = NO_ERROR;
- else
- err = -errno;
-#else
- err = INVALID_OPERATION;
-#endif
- IF_LOG_COMMANDS() {
- alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
- }
- } while (err == -EINTR);
-
- IF_LOG_COMMANDS() {
- alog << "Our err: " << (void*)err << ", write consumed: "
- << bwr.write_consumed << " (of " << mOut.dataSize()
- << "), read consumed: " << bwr.read_consumed << endl;
- }
-
- if (err >= NO_ERROR) {
- if (bwr.write_consumed > 0) {
- if (bwr.write_consumed < (ssize_t)mOut.dataSize())
- mOut.remove(0, bwr.write_consumed);
- else
- mOut.setDataSize(0);
- }
- if (bwr.read_consumed > 0) {
- mIn.setDataSize(bwr.read_consumed);
- mIn.setDataPosition(0);
- }
- IF_LOG_COMMANDS() {
- TextOutput::Bundle _b(alog);
- alog << "Remaining data size: " << mOut.dataSize() << endl;
- alog << "Received commands from driver: " << indent;
- const void* cmds = mIn.data();
- const void* end = mIn.data() + mIn.dataSize();
- alog << HexDump(cmds, mIn.dataSize()) << endl;
- while (cmds < end) cmds = printReturnCommand(alog, cmds);
- alog << dedent;
- }
- return NO_ERROR;
- }
-
- return err;
-}
-
-status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
- int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
-{
- binder_transaction_data tr;
-
- tr.target.handle = handle;
- tr.code = code;
- tr.flags = binderFlags;
-
- const status_t err = data.errorCheck();
- if (err == NO_ERROR) {
- tr.data_size = data.ipcDataSize();
- tr.data.ptr.buffer = data.ipcData();
- tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
- tr.data.ptr.offsets = data.ipcObjects();
- } else if (statusBuffer) {
- tr.flags |= TF_STATUS_CODE;
- *statusBuffer = err;
- tr.data_size = sizeof(status_t);
- tr.data.ptr.buffer = statusBuffer;
- tr.offsets_size = 0;
- tr.data.ptr.offsets = NULL;
- } else {
- return (mLastError = err);
- }
-
- mOut.writeInt32(cmd);
- mOut.write(&tr, sizeof(tr));
-
- return NO_ERROR;
-}
-
-sp<BBinder> the_context_object;
-
-void setTheContextObject(sp<BBinder> obj)
-{
- the_context_object = obj;
-}
-
-status_t IPCThreadState::executeCommand(int32_t cmd)
-{
- BBinder* obj;
- RefBase::weakref_type* refs;
- status_t result = NO_ERROR;
-
- switch (cmd) {
- case BR_ERROR:
- result = mIn.readInt32();
- break;
-
- case BR_OK:
- break;
-
- case BR_ACQUIRE:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- LOG_ASSERT(refs->refBase() == obj,
- "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
- refs, obj, refs->refBase());
- obj->incStrong(mProcess.get());
- IF_LOG_REMOTEREFS() {
- LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
- obj->printRefs();
- }
- mOut.writeInt32(BC_ACQUIRE_DONE);
- mOut.writeInt32((int32_t)refs);
- mOut.writeInt32((int32_t)obj);
- break;
-
- case BR_RELEASE:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- LOG_ASSERT(refs->refBase() == obj,
- "BR_RELEASE: object %p does not match cookie %p (expected %p)",
- refs, obj, refs->refBase());
- IF_LOG_REMOTEREFS() {
- LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
- obj->printRefs();
- }
- mPendingStrongDerefs.push(obj);
- break;
-
- case BR_INCREFS:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- refs->incWeak(mProcess.get());
- mOut.writeInt32(BC_INCREFS_DONE);
- mOut.writeInt32((int32_t)refs);
- mOut.writeInt32((int32_t)obj);
- break;
-
- case BR_DECREFS:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- // NOTE: This assertion is not valid, because the object may no
- // longer exist (thus the (BBinder*)cast above resulting in a different
- // memory address).
- //LOG_ASSERT(refs->refBase() == obj,
- // "BR_DECREFS: object %p does not match cookie %p (expected %p)",
- // refs, obj, refs->refBase());
- mPendingWeakDerefs.push(refs);
- break;
-
- case BR_ATTEMPT_ACQUIRE:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
-
- {
- const bool success = refs->attemptIncStrong(mProcess.get());
- LOG_ASSERT(success && refs->refBase() == obj,
- "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
- refs, obj, refs->refBase());
-
- mOut.writeInt32(BC_ACQUIRE_RESULT);
- mOut.writeInt32((int32_t)success);
- }
- break;
-
- case BR_TRANSACTION:
- {
- binder_transaction_data tr;
- result = mIn.read(&tr, sizeof(tr));
- LOG_ASSERT(result == NO_ERROR,
- "Not enough command data for brTRANSACTION");
- if (result != NO_ERROR) break;
-
- Parcel buffer;
- buffer.ipcSetDataReference(
- reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
- tr.data_size,
- reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
- tr.offsets_size/sizeof(size_t), freeBuffer, this);
-
- const pid_t origPid = mCallingPid;
- const uid_t origUid = mCallingUid;
-
- mCallingPid = tr.sender_pid;
- mCallingUid = tr.sender_euid;
-
- //LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
-
- Parcel reply;
- IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BR_TRANSACTION thr " << (void*)pthread_self()
- << " / obj " << tr.target.ptr << " / code "
- << TypeCode(tr.code) << ": " << indent << buffer
- << dedent << endl
- << "Data addr = "
- << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
- << ", offsets addr="
- << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
- }
- if (tr.target.ptr) {
- sp<BBinder> b((BBinder*)tr.cookie);
- const status_t error = b->transact(tr.code, buffer, &reply, 0);
- if (error < NO_ERROR) reply.setError(error);
-
- } else {
- const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);
- if (error < NO_ERROR) reply.setError(error);
- }
-
- //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
- // mCallingPid, origPid, origUid);
-
- if ((tr.flags & TF_ONE_WAY) == 0) {
- LOG_ONEWAY("Sending reply to %d!", mCallingPid);
- sendReply(reply, 0);
- } else {
- LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
- }
-
- mCallingPid = origPid;
- mCallingUid = origUid;
-
- IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
- << tr.target.ptr << ": " << indent << reply << dedent << endl;
- }
-
- }
- break;
-
- case BR_DEAD_BINDER:
- {
- BpBinder *proxy = (BpBinder*)mIn.readInt32();
- proxy->sendObituary();
- mOut.writeInt32(BC_DEAD_BINDER_DONE);
- mOut.writeInt32((int32_t)proxy);
- } break;
-
- case BR_CLEAR_DEATH_NOTIFICATION_DONE:
- {
- BpBinder *proxy = (BpBinder*)mIn.readInt32();
- proxy->getWeakRefs()->decWeak(proxy);
- } break;
-
- case BR_FINISHED:
- result = TIMED_OUT;
- break;
-
- case BR_NOOP:
- break;
-
- case BR_SPAWN_LOOPER:
- mProcess->spawnPooledThread(false);
- break;
-
- default:
- printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
- result = UNKNOWN_ERROR;
- break;
- }
-
- if (result != NO_ERROR) {
- mLastError = result;
- }
-
- return result;
-}
-
-void IPCThreadState::threadDestructor(void *st)
-{
- IPCThreadState* const self = static_cast<IPCThreadState*>(st);
- if (self) {
- self->flushCommands();
-#if defined(HAVE_ANDROID_OS)
- ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
-#endif
- delete self;
- }
-}
-
-
-void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize,
- const size_t* objects, size_t objectsSize,
- void* cookie)
-{
- //LOGI("Freeing parcel %p", &parcel);
- IF_LOG_COMMANDS() {
- alog << "Writing BC_FREE_BUFFER for " << data << endl;
- }
- LOG_ASSERT(data != NULL, "Called with NULL data");
- if (parcel != NULL) parcel->closeFileDescriptors();
- IPCThreadState* state = self();
- state->mOut.writeInt32(BC_FREE_BUFFER);
- state->mOut.writeInt32((int32_t)data);
-}
-
-}; // namespace android
diff --git a/libs/utils/IPermissionController.cpp b/libs/utils/IPermissionController.cpp
deleted file mode 100644
index f01d38f..0000000
--- a/libs/utils/IPermissionController.cpp
+++ /dev/null
@@ -1,86 +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.
- */
-
-#define LOG_TAG "PermissionController"
-
-#include <utils/IPermissionController.h>
-
-#include <utils/Debug.h>
-#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/String8.h>
-
-#include <private/utils/Static.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class BpPermissionController : public BpInterface<IPermissionController>
-{
-public:
- BpPermissionController(const sp<IBinder>& impl)
- : BpInterface<IPermissionController>(impl)
- {
- }
-
- virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
- data.writeString16(permission);
- data.writeInt32(pid);
- data.writeInt32(uid);
- remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
- // fail on exception
- if (reply.readInt32() != 0) return 0;
- return reply.readInt32() != 0;
- }
-};
-
-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)
-{
- //printf("PermissionController received: "); data.print();
- switch(code) {
- case CHECK_PERMISSION_TRANSACTION: {
- CHECK_INTERFACE(IPermissionController, data, reply);
- String16 permission = data.readString16();
- int32_t pid = data.readInt32();
- int32_t uid = data.readInt32();
- bool res = checkPermission(permission, pid, uid);
- // write exception
- reply->writeInt32(0);
- reply->writeInt32(res ? 1 : 0);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-}; // namespace android
-
diff --git a/libs/utils/IServiceManager.cpp b/libs/utils/IServiceManager.cpp
deleted file mode 100644
index 9beeadd..0000000
--- a/libs/utils/IServiceManager.cpp
+++ /dev/null
@@ -1,230 +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.
- */
-
-#define LOG_TAG "ServiceManager"
-
-#include <utils/IServiceManager.h>
-
-#include <utils/Debug.h>
-#include <utils/IPCThreadState.h>
-#include <utils/Log.h>
-#include <utils/Parcel.h>
-#include <utils/String8.h>
-#include <utils/SystemClock.h>
-
-#include <private/utils/Static.h>
-
-#include <unistd.h>
-
-namespace android {
-
-sp<IServiceManager> defaultServiceManager()
-{
- if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
-
- {
- AutoMutex _l(gDefaultServiceManagerLock);
- if (gDefaultServiceManager == NULL) {
- gDefaultServiceManager = interface_cast<IServiceManager>(
- ProcessState::self()->getContextObject(NULL));
- }
- }
-
- return gDefaultServiceManager;
-}
-
-bool checkCallingPermission(const String16& permission)
-{
- return checkCallingPermission(permission, NULL, NULL);
-}
-
-static String16 _permission("permission");
-
-bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t* outUid)
-{
- IPCThreadState* ipcState = IPCThreadState::self();
- int32_t pid = ipcState->getCallingPid();
- int32_t uid = ipcState->getCallingUid();
- if (outPid) *outPid = pid;
- if (outUid) *outUid= uid;
-
- sp<IPermissionController> pc;
- gDefaultServiceManagerLock.lock();
- pc = gPermissionController;
- gDefaultServiceManagerLock.unlock();
-
- int64_t startTime = 0;
-
- while (true) {
- if (pc != NULL) {
- bool res = pc->checkPermission(permission, pid, uid);
- if (res) {
- if (startTime != 0) {
- LOGI("Check passed after %d seconds for %s from uid=%d pid=%d",
- (int)((uptimeMillis()-startTime)/1000),
- String8(permission).string(), uid, pid);
- }
- return res;
- }
-
- // Is this a permission failure, or did the controller go away?
- if (pc->asBinder()->isBinderAlive()) {
- LOGW("Permission failure: %s from uid=%d pid=%d",
- String8(permission).string(), uid, pid);
- return false;
- }
-
- // Object is dead!
- gDefaultServiceManagerLock.lock();
- if (gPermissionController == pc) {
- gPermissionController = NULL;
- }
- gDefaultServiceManagerLock.unlock();
- }
-
- // Need to retrieve the permission controller.
- sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
- if (binder == NULL) {
- // Wait for the permission controller to come back...
- if (startTime == 0) {
- startTime = uptimeMillis();
- LOGI("Waiting to check permission %s from uid=%d pid=%d",
- String8(permission).string(), uid, pid);
- }
- sleep(1);
- } else {
- pc = interface_cast<IPermissionController>(binder);
- // Install the new permission controller, and try again.
- gDefaultServiceManagerLock.lock();
- gPermissionController = pc;
- gDefaultServiceManagerLock.unlock();
- }
- }
-}
-
-// ----------------------------------------------------------------------
-
-class BpServiceManager : public BpInterface<IServiceManager>
-{
-public:
- BpServiceManager(const sp<IBinder>& impl)
- : BpInterface<IServiceManager>(impl)
- {
- }
-
- virtual sp<IBinder> getService(const String16& name) const
- {
- unsigned n;
- for (n = 0; n < 5; n++){
- sp<IBinder> svc = checkService(name);
- if (svc != NULL) return svc;
- LOGI("Waiting for sevice %s...\n", String8(name).string());
- sleep(1);
- }
- return NULL;
- }
-
- virtual sp<IBinder> checkService( const String16& name) const
- {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
- return reply.readStrongBinder();
- }
-
- virtual status_t addService(const String16& name, const sp<IBinder>& service)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- data.writeStrongBinder(service);
- status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
- return err == NO_ERROR ? reply.readInt32() : err;
- }
-
- virtual Vector<String16> listServices()
- {
- Vector<String16> res;
- int n = 0;
-
- for (;;) {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeInt32(n++);
- status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
- if (err != NO_ERROR)
- break;
- res.add(reply.readString16());
- }
- return res;
- }
-};
-
-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)
-{
- //printf("ServiceManager received: "); data.print();
- switch(code) {
- case GET_SERVICE_TRANSACTION: {
- CHECK_INTERFACE(IServiceManager, data, reply);
- String16 which = data.readString16();
- sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which);
- reply->writeStrongBinder(b);
- return NO_ERROR;
- } break;
- case CHECK_SERVICE_TRANSACTION: {
- CHECK_INTERFACE(IServiceManager, data, reply);
- String16 which = data.readString16();
- sp<IBinder> b = const_cast<BnServiceManager*>(this)->checkService(which);
- reply->writeStrongBinder(b);
- return NO_ERROR;
- } break;
- case ADD_SERVICE_TRANSACTION: {
- CHECK_INTERFACE(IServiceManager, data, reply);
- String16 which = data.readString16();
- sp<IBinder> b = data.readStrongBinder();
- status_t err = addService(which, b);
- reply->writeInt32(err);
- return NO_ERROR;
- } break;
- case LIST_SERVICES_TRANSACTION: {
- CHECK_INTERFACE(IServiceManager, data, reply);
- Vector<String16> list = listServices();
- const size_t N = list.size();
- reply->writeInt32(N);
- for (size_t i=0; i<N; i++) {
- reply->writeString16(list[i]);
- }
- return NO_ERROR;
- } break;
- 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/MemoryBase.cpp b/libs/utils/MemoryBase.cpp
deleted file mode 100644
index f25e11c..0000000
--- a/libs/utils/MemoryBase.cpp
+++ /dev/null
@@ -1,46 +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 <stdlib.h>
-#include <stdint.h>
-
-#include <utils/MemoryBase.h>
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap,
- ssize_t offset, size_t size)
- : mSize(size), mOffset(offset), mHeap(heap)
-{
-}
-
-sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const
-{
- if (offset) *offset = mOffset;
- if (size) *size = mSize;
- return mHeap;
-}
-
-MemoryBase::~MemoryBase()
-{
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/utils/MemoryDealer.cpp b/libs/utils/MemoryDealer.cpp
deleted file mode 100644
index cf8201b..0000000
--- a/libs/utils/MemoryDealer.cpp
+++ /dev/null
@@ -1,409 +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 "MemoryDealer"
-
-#include <utils/MemoryDealer.h>
-
-#include <utils/Log.h>
-#include <utils/IPCThreadState.h>
-#include <utils/SortedVector.h>
-#include <utils/String8.h>
-#include <utils/MemoryBase.h>
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/file.h>
-
-namespace android {
-
-
-// ----------------------------------------------------------------------------
-
-class SimpleMemory : public MemoryBase {
-public:
- SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
- virtual ~SimpleMemory();
-};
-
-
-// ----------------------------------------------------------------------------
-
-MemoryDealer::Allocation::Allocation(
- const sp<MemoryDealer>& dealer, ssize_t offset, size_t size,
- const sp<IMemory>& memory)
- : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory)
-{
-}
-
-MemoryDealer::Allocation::~Allocation()
-{
- if (mSize) {
- /* 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 allocator
- * and could alias some real allocation (their offset is zero). */
- mDealer->deallocate(mOffset);
- }
-}
-
-sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
- ssize_t* offset, size_t* size) const
-{
- return mMemory->getMemory(offset, size);
-}
-
-// ----------------------------------------------------------------------------
-
-MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name)
- : mHeap(new SharedHeap(size, flags, name)),
- mAllocator(new SimpleBestFitAllocator(size))
-{
-}
-
-MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap)
- : mHeap(heap),
- mAllocator(new SimpleBestFitAllocator(heap->virtualSize()))
-{
-}
-
-MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap,
- const sp<AllocatorInterface>& allocator)
- : mHeap(heap), mAllocator(allocator)
-{
-}
-
-MemoryDealer::~MemoryDealer()
-{
-}
-
-sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
-{
- sp<IMemory> memory;
- const ssize_t offset = allocator()->allocate(size, flags);
- if (offset >= 0) {
- sp<IMemory> new_memory = heap()->mapMemory(offset, size);
- if (new_memory != 0) {
- memory = new Allocation(this, offset, size, new_memory);
- } else {
- LOGE("couldn't map [%8x, %d]", 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
- * allocator and could alias some real allocation
- * (their offset is zero). */
- allocator()->deallocate(offset);
- }
- }
- }
- return memory;
-}
-
-void MemoryDealer::deallocate(size_t offset)
-{
- allocator()->deallocate(offset);
-}
-
-void MemoryDealer::dump(const char* what, uint32_t flags) const
-{
- allocator()->dump(what, flags);
-}
-
-const sp<HeapInterface>& MemoryDealer::heap() const {
- return mHeap;
-}
-
-const sp<AllocatorInterface>& MemoryDealer::allocator() const {
- return mAllocator;
-}
-
-// ----------------------------------------------------------------------------
-
-// align all the memory blocks on a cache-line boundary
-const int SimpleBestFitAllocator::kMemoryAlign = 32;
-
-SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
-{
- size_t pagesize = getpagesize();
- mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
-
- chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
- mList.insertHead(node);
-}
-
-SimpleBestFitAllocator::~SimpleBestFitAllocator()
-{
- while(!mList.isEmpty()) {
- delete mList.remove(mList.head());
- }
-}
-
-size_t SimpleBestFitAllocator::size() const
-{
- return mHeapSize;
-}
-
-size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
-{
- Mutex::Autolock _l(mLock);
- ssize_t offset = alloc(size, flags);
- return offset;
-}
-
-status_t SimpleBestFitAllocator::deallocate(size_t offset)
-{
- Mutex::Autolock _l(mLock);
- chunk_t const * const freed = dealloc(offset);
- if (freed) {
- return NO_ERROR;
- }
- return NAME_NOT_FOUND;
-}
-
-ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
-{
- if (size == 0) {
- return 0;
- }
- size = (size + kMemoryAlign-1) / kMemoryAlign;
- chunk_t* free_chunk = 0;
- chunk_t* cur = mList.head();
-
- size_t pagesize = getpagesize();
- while (cur) {
- int extra = 0;
- if (flags & PAGE_ALIGNED)
- extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
-
- // best fit
- if (cur->free && (cur->size >= (size+extra))) {
- if ((!free_chunk) || (cur->size < free_chunk->size)) {
- free_chunk = cur;
- }
- if (cur->size == size) {
- break;
- }
- }
- cur = cur->next;
- }
-
- if (free_chunk) {
- const size_t free_size = free_chunk->size;
- free_chunk->free = 0;
- free_chunk->size = size;
- if (free_size > size) {
- int extra = 0;
- if (flags & PAGE_ALIGNED)
- extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
- if (extra) {
- chunk_t* split = new chunk_t(free_chunk->start, extra);
- free_chunk->start += extra;
- mList.insertBefore(free_chunk, split);
- }
-
- LOGE_IF((flags&PAGE_ALIGNED) &&
- ((free_chunk->start*kMemoryAlign)&(pagesize-1)),
- "PAGE_ALIGNED requested, but page is not aligned!!!");
-
- const ssize_t tail_free = free_size - (size+extra);
- if (tail_free > 0) {
- chunk_t* split = new chunk_t(
- free_chunk->start + free_chunk->size, tail_free);
- mList.insertAfter(free_chunk, split);
- }
- }
- return (free_chunk->start)*kMemoryAlign;
- }
- return NO_MEMORY;
-}
-
-SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
-{
- start = start / kMemoryAlign;
- chunk_t* cur = mList.head();
- while (cur) {
- if (cur->start == start) {
- LOG_FATAL_IF(cur->free,
- "block at offset 0x%08lX of size 0x%08lX already freed",
- cur->start*kMemoryAlign, cur->size*kMemoryAlign);
-
- // merge freed blocks together
- chunk_t* freed = cur;
- cur->free = 1;
- do {
- chunk_t* const p = cur->prev;
- chunk_t* const n = cur->next;
- if (p && (p->free || !cur->size)) {
- freed = p;
- p->size += cur->size;
- mList.remove(cur);
- delete cur;
- }
- cur = n;
- } while (cur && cur->free);
-
- #ifndef NDEBUG
- if (!freed->free) {
- dump_l("dealloc (!freed->free)");
- }
- #endif
- LOG_FATAL_IF(!freed->free,
- "freed block at offset 0x%08lX of size 0x%08lX is not free!",
- freed->start * kMemoryAlign, freed->size * kMemoryAlign);
-
- return freed;
- }
- cur = cur->next;
- }
- return 0;
-}
-
-void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const
-{
- Mutex::Autolock _l(mLock);
- dump_l(what, flags);
-}
-
-void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const
-{
- String8 result;
- dump_l(result, what, flags);
- LOGD("%s", result.string());
-}
-
-void SimpleBestFitAllocator::dump(String8& result,
- const char* what, uint32_t flags) const
-{
- Mutex::Autolock _l(mLock);
- dump_l(result, what, flags);
-}
-
-void SimpleBestFitAllocator::dump_l(String8& result,
- const char* what, uint32_t flags) const
-{
- size_t size = 0;
- int32_t i = 0;
- chunk_t const* cur = mList.head();
-
- const size_t SIZE = 256;
- char buffer[SIZE];
- snprintf(buffer, SIZE, " %s (%p, size=%u)\n",
- what, this, (unsigned int)mHeapSize);
-
- result.append(buffer);
-
- while (cur) {
- const char* errs[] = {"", "| link bogus NP",
- "| link bogus PN", "| link bogus NP+PN" };
- int np = ((cur->next) && cur->next->prev != cur) ? 1 : 0;
- int pn = ((cur->prev) && cur->prev->next != cur) ? 2 : 0;
-
- snprintf(buffer, SIZE, " %3u: %08x | 0x%08X | 0x%08X | %s %s\n",
- i, int(cur), int(cur->start*kMemoryAlign),
- int(cur->size*kMemoryAlign),
- int(cur->free) ? "F" : "A",
- errs[np|pn]);
-
- result.append(buffer);
-
- if (!cur->free)
- size += cur->size*kMemoryAlign;
-
- i++;
- cur = cur->next;
- }
- snprintf(buffer, SIZE, " size allocated: %u (%u KB)\n", int(size), int(size/1024));
- result.append(buffer);
-}
-
-// ----------------------------------------------------------------------------
-
-
-SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
- : MemoryHeapBase(size, flags, name)
-{
-}
-
-SharedHeap::~SharedHeap()
-{
-}
-
-sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size)
-{
- return new SimpleMemory(this, offset, size);
-}
-
-
-SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap,
- ssize_t offset, size_t size)
- : MemoryBase(heap, offset, size)
-{
-#ifndef NDEBUG
- void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
- memset(start_ptr, 0xda, size);
-#endif
-}
-
-SimpleMemory::~SimpleMemory()
-{
- size_t freedOffset = getOffset();
- size_t freedSize = getSize();
-
- // keep the size to unmap in excess
- size_t pagesize = getpagesize();
- size_t start = freedOffset;
- size_t end = start + freedSize;
- start &= ~(pagesize-1);
- end = (end + pagesize-1) & ~(pagesize-1);
-
- // give back to the kernel the pages we don't need
- size_t free_start = freedOffset;
- size_t free_end = free_start + freedSize;
- if (start < free_start)
- start = free_start;
- if (end > free_end)
- end = free_end;
- start = (start + pagesize-1) & ~(pagesize-1);
- end &= ~(pagesize-1);
-
- if (start < end) {
- void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
- size_t size = end-start;
-
-#ifndef NDEBUG
- memset(start_ptr, 0xdf, size);
-#endif
-
- // MADV_REMOVE is not defined on Dapper based Goobuntu
-#ifdef MADV_REMOVE
- if (size) {
- int err = madvise(start_ptr, size, MADV_REMOVE);
- LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
- start_ptr, size, err<0 ? strerror(errno) : "Ok");
- }
-#endif
- }
-}
-
-}; // namespace android
diff --git a/libs/utils/MemoryHeapBase.cpp b/libs/utils/MemoryHeapBase.cpp
deleted file mode 100644
index 8251728..0000000
--- a/libs/utils/MemoryHeapBase.cpp
+++ /dev/null
@@ -1,183 +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.
- */
-
-#define LOG_TAG "MemoryHeapBase"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <cutils/log.h>
-#include <cutils/ashmem.h>
-#include <cutils/atomic.h>
-
-#include <utils/MemoryHeapBase.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-MemoryHeapBase::MemoryHeapBase()
- : mFD(-1), mSize(0), mBase(MAP_FAILED),
- mDevice(NULL), mNeedUnmap(false)
-{
-}
-
-MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
- : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
- mDevice(0), mNeedUnmap(false)
-{
- const size_t pagesize = getpagesize();
- size = ((size + pagesize-1) & ~(pagesize-1));
- int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
- LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
- if (fd >= 0) {
- if (mapfd(fd, size) == NO_ERROR) {
- if (flags & READ_ONLY) {
- ashmem_set_prot_region(fd, PROT_READ);
- }
- }
- }
-}
-
-MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
- : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
- mDevice(0), mNeedUnmap(false)
-{
- int fd = open(device, O_RDWR);
- LOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
- if (fd >= 0) {
- const size_t pagesize = getpagesize();
- size = ((size + pagesize-1) & ~(pagesize-1));
- if (mapfd(fd, size) == NO_ERROR) {
- mDevice = device;
- }
- }
-}
-
-MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags)
- : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
- mDevice(0), mNeedUnmap(false)
-{
- const size_t pagesize = getpagesize();
- size = ((size + pagesize-1) & ~(pagesize-1));
- mapfd(dup(fd), size);
-}
-
-status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
-{
- if (mFD != -1) {
- return INVALID_OPERATION;
- }
- mFD = fd;
- mBase = base;
- mSize = size;
- mFlags = flags;
- mDevice = device;
- return NO_ERROR;
-}
-
-status_t MemoryHeapBase::mapfd(int fd, size_t size)
-{
- if (size == 0) {
- // try to figure out the size automatically
-#if HAVE_ANDROID_OS
- // first try the PMEM ioctl
- pmem_region reg;
- int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, &reg);
- if (err == 0)
- size = reg.len;
-#endif
- if (size == 0) { // try fstat
- struct stat sb;
- if (fstat(fd, &sb) == 0)
- size = sb.st_size;
- }
- // if it didn't work, let mmap() fail.
- }
-
- if ((mFlags & DONT_MAP_LOCALLY) == 0) {
- void* base = (uint8_t*)mmap(0, size,
- PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- if (base == MAP_FAILED) {
- LOGE("mmap(fd=%d, size=%u) failed (%s)",
- fd, uint32_t(size), strerror(errno));
- close(fd);
- return -errno;
- }
- //LOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
- mBase = base;
- mNeedUnmap = true;
- } else {
- mBase = 0; // not MAP_FAILED
- mNeedUnmap = false;
- }
- mFD = fd;
- mSize = size;
- return NO_ERROR;
-}
-
-MemoryHeapBase::~MemoryHeapBase()
-{
- dispose();
-}
-
-void MemoryHeapBase::dispose()
-{
- int fd = android_atomic_or(-1, &mFD);
- if (fd >= 0) {
- if (mNeedUnmap) {
- //LOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
- munmap(mBase, mSize);
- }
- mBase = 0;
- mSize = 0;
- close(fd);
- }
-}
-
-int MemoryHeapBase::getHeapID() const {
- return mFD;
-}
-
-void* MemoryHeapBase::getBase() const {
- return mBase;
-}
-
-size_t MemoryHeapBase::getSize() const {
- return mSize;
-}
-
-uint32_t MemoryHeapBase::getFlags() const {
- return mFlags;
-}
-
-const char* MemoryHeapBase::getDevice() const {
- return mDevice;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/utils/MemoryHeapPmem.cpp
deleted file mode 100644
index eba2b30..0000000
--- a/libs/utils/MemoryHeapPmem.cpp
+++ /dev/null
@@ -1,248 +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.
- */
-
-#define LOG_TAG "MemoryHeapPmem"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <cutils/log.h>
-
-#include <utils/MemoryHeapPmem.h>
-#include <utils/MemoryHeapBase.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
- : BnMemory(), mClientHeap(heap)
-{
-}
-
-MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
- if (mClientHeap != NULL) {
- mClientHeap->remove(this);
- }
-}
-
-// ---------------------------------------------------------------------------
-
-class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
-public:
- SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
- virtual ~SubRegionMemory();
- virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
-private:
- friend class MemoryHeapPmem;
- void revoke();
- size_t mSize;
- ssize_t mOffset;
-};
-
-SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
- ssize_t offset, size_t size)
- : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
-{
-#ifndef NDEBUG
- void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
- memset(start_ptr, 0xda, size);
-#endif
-
-#if HAVE_ANDROID_OS
- if (size > 0) {
- const size_t pagesize = getpagesize();
- size = (size + pagesize-1) & ~(pagesize-1);
- int our_fd = heap->heapID();
- struct pmem_region sub = { offset, size };
- int err = ioctl(our_fd, PMEM_MAP, &sub);
- LOGE_IF(err<0, "PMEM_MAP failed (%s), "
- "mFD=%d, sub.offset=%lu, sub.size=%lu",
- strerror(errno), our_fd, sub.offset, sub.len);
-}
-#endif
-}
-
-sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
-{
- if (offset) *offset = mOffset;
- if (size) *size = mSize;
- return getHeap();
-}
-
-SubRegionMemory::~SubRegionMemory()
-{
- revoke();
-}
-
-
-void SubRegionMemory::revoke()
-{
- // NOTE: revoke() doesn't need to be protected by a lock because it
- // can only be called from MemoryHeapPmem::revoke(), which means
- // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
- // which means MemoryHeapPmem::revoke() wouldn't have been able to
- // promote() it.
-
-#if HAVE_ANDROID_OS
- if (mSize != NULL) {
- const sp<MemoryHeapPmem>& heap(getHeap());
- int our_fd = heap->heapID();
- struct pmem_region sub;
- sub.offset = mOffset;
- sub.len = mSize;
- int err = ioctl(our_fd, PMEM_UNMAP, &sub);
- LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
- "mFD=%d, sub.offset=%lu, sub.size=%lu",
- strerror(errno), our_fd, sub.offset, sub.len);
- mSize = 0;
- }
-#endif
-}
-
-// ---------------------------------------------------------------------------
-
-MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
- uint32_t flags)
- : HeapInterface(), MemoryHeapBase()
-{
- char const * const device = pmemHeap->getDevice();
-#if HAVE_ANDROID_OS
- if (device) {
- int fd = open(device, O_RDWR);
- LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
- if (fd >= 0) {
- int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
- if (err < 0) {
- LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
- strerror(errno), fd, pmemHeap->heapID());
- close(fd);
- } else {
- // everything went well...
- mParentHeap = pmemHeap;
- MemoryHeapBase::init(fd,
- pmemHeap->getBase(),
- pmemHeap->getSize(),
- pmemHeap->getFlags() | flags,
- device);
- }
- }
- }
-#else
- mParentHeap = pmemHeap;
- MemoryHeapBase::init(
- dup(pmemHeap->heapID()),
- pmemHeap->getBase(),
- pmemHeap->getSize(),
- pmemHeap->getFlags() | flags,
- device);
-#endif
-}
-
-MemoryHeapPmem::~MemoryHeapPmem()
-{
-}
-
-sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
-{
- sp<MemoryPmem> memory = createMemory(offset, size);
- if (memory != 0) {
- Mutex::Autolock _l(mLock);
- mAllocations.add(memory);
- }
- return memory;
-}
-
-sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
- size_t offset, size_t size)
-{
- sp<SubRegionMemory> memory;
- if (heapID() > 0)
- memory = new SubRegionMemory(this, offset, size);
- return memory;
-}
-
-status_t MemoryHeapPmem::slap()
-{
-#if HAVE_ANDROID_OS
- size_t size = getSize();
- const size_t pagesize = getpagesize();
- size = (size + pagesize-1) & ~(pagesize-1);
- int our_fd = getHeapID();
- struct pmem_region sub = { 0, size };
- int err = ioctl(our_fd, PMEM_MAP, &sub);
- LOGE_IF(err<0, "PMEM_MAP failed (%s), "
- "mFD=%d, sub.offset=%lu, sub.size=%lu",
- strerror(errno), our_fd, sub.offset, sub.len);
- return -errno;
-#else
- return NO_ERROR;
-#endif
-}
-
-status_t MemoryHeapPmem::unslap()
-{
-#if HAVE_ANDROID_OS
- size_t size = getSize();
- const size_t pagesize = getpagesize();
- size = (size + pagesize-1) & ~(pagesize-1);
- int our_fd = getHeapID();
- struct pmem_region sub = { 0, size };
- int err = ioctl(our_fd, PMEM_UNMAP, &sub);
- LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
- "mFD=%d, sub.offset=%lu, sub.size=%lu",
- strerror(errno), our_fd, sub.offset, sub.len);
- return -errno;
-#else
- return NO_ERROR;
-#endif
-}
-
-void MemoryHeapPmem::revoke()
-{
- SortedVector< wp<MemoryPmem> > allocations;
-
- { // scope for lock
- Mutex::Autolock _l(mLock);
- allocations = mAllocations;
- }
-
- ssize_t count = allocations.size();
- for (ssize_t i=0 ; i<count ; i++) {
- sp<MemoryPmem> memory(allocations[i].promote());
- if (memory != 0)
- memory->revoke();
- }
-}
-
-void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
-{
- Mutex::Autolock _l(mLock);
- mAllocations.remove(memory);
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp
deleted file mode 100644
index b0e3750..0000000
--- a/libs/utils/Parcel.cpp
+++ /dev/null
@@ -1,1363 +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.
- */
-
-#define LOG_TAG "Parcel"
-//#define LOG_NDEBUG 0
-
-#include <utils/Parcel.h>
-
-#include <utils/Binder.h>
-#include <utils/BpBinder.h>
-#include <utils/Debug.h>
-#include <utils/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 <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#ifndef INT32_MAX
-#define INT32_MAX ((int32_t)(2147483647))
-#endif
-
-#define LOG_REFS(...)
-//#define LOG_REFS(...) LOG(LOG_DEBUG, "Parcel", __VA_ARGS__)
-
-// ---------------------------------------------------------------------------
-
-#define PAD_SIZE(s) (((s)+3)&~3)
-
-// XXX This can be made public if we want to provide
-// support for typed data.
-struct small_flat_data
-{
- uint32_t type;
- uint32_t data;
-};
-
-namespace android {
-
-void acquire_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who)
-{
- switch (obj.type) {
- case BINDER_TYPE_BINDER:
- if (obj.binder) {
- LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
- static_cast<IBinder*>(obj.cookie)->incStrong(who);
- }
- return;
- case BINDER_TYPE_WEAK_BINDER:
- if (obj.binder)
- static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);
- return;
- case BINDER_TYPE_HANDLE: {
- const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
- if (b != NULL) {
- LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get());
- b->incStrong(who);
- }
- return;
- }
- case BINDER_TYPE_WEAK_HANDLE: {
- const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
- if (b != NULL) b.get_refs()->incWeak(who);
- return;
- }
- case BINDER_TYPE_FD: {
- // intentionally blank -- nothing to do to acquire this, but we do
- // recognize it as a legitimate object type.
- return;
- }
- }
-
- LOGD("Invalid object type 0x%08lx", obj.type);
-}
-
-void release_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who)
-{
- switch (obj.type) {
- case BINDER_TYPE_BINDER:
- if (obj.binder) {
- LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
- static_cast<IBinder*>(obj.cookie)->decStrong(who);
- }
- return;
- case BINDER_TYPE_WEAK_BINDER:
- if (obj.binder)
- static_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who);
- return;
- case BINDER_TYPE_HANDLE: {
- const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
- if (b != NULL) {
- LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get());
- b->decStrong(who);
- }
- return;
- }
- case BINDER_TYPE_WEAK_HANDLE: {
- const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
- if (b != NULL) b.get_refs()->decWeak(who);
- return;
- }
- case BINDER_TYPE_FD: {
- if (obj.cookie != (void*)0) close(obj.handle);
- return;
- }
- }
-
- LOGE("Invalid object type 0x%08lx", obj.type);
-}
-
-inline static status_t finish_flatten_binder(
- const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out)
-{
- return out->writeObject(flat, false);
-}
-
-status_t flatten_binder(const sp<ProcessState>& proc,
- const sp<IBinder>& binder, Parcel* out)
-{
- flat_binder_object obj;
-
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- if (binder != NULL) {
- IBinder *local = binder->localBinder();
- if (!local) {
- BpBinder *proxy = binder->remoteBinder();
- if (proxy == NULL) {
- LOGE("null proxy");
- }
- const int32_t handle = proxy ? proxy->handle() : 0;
- obj.type = BINDER_TYPE_HANDLE;
- obj.handle = handle;
- obj.cookie = NULL;
- } else {
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = local->getWeakRefs();
- obj.cookie = local;
- }
- } else {
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = NULL;
- obj.cookie = NULL;
- }
-
- return finish_flatten_binder(binder, obj, out);
-}
-
-status_t flatten_binder(const sp<ProcessState>& proc,
- const wp<IBinder>& binder, Parcel* out)
-{
- flat_binder_object obj;
-
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- if (binder != NULL) {
- sp<IBinder> real = binder.promote();
- if (real != NULL) {
- IBinder *local = real->localBinder();
- if (!local) {
- BpBinder *proxy = real->remoteBinder();
- if (proxy == NULL) {
- LOGE("null proxy");
- }
- const int32_t handle = proxy ? proxy->handle() : 0;
- obj.type = BINDER_TYPE_WEAK_HANDLE;
- obj.handle = handle;
- obj.cookie = NULL;
- } else {
- obj.type = BINDER_TYPE_WEAK_BINDER;
- obj.binder = binder.get_refs();
- obj.cookie = binder.unsafe_get();
- }
- return finish_flatten_binder(real, obj, out);
- }
-
- // XXX How to deal? In order to flatten the given binder,
- // we need to probe it for information, which requires a primary
- // reference... but we don't have one.
- //
- // The OpenBinder implementation uses a dynamic_cast<> here,
- // but we can't do that with the different reference counting
- // implementation we are using.
- LOGE("Unable to unflatten Binder weak reference!");
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = NULL;
- obj.cookie = NULL;
- return finish_flatten_binder(NULL, obj, out);
-
- } else {
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = NULL;
- obj.cookie = NULL;
- return finish_flatten_binder(NULL, obj, out);
- }
-}
-
-inline static status_t finish_unflatten_binder(
- BpBinder* proxy, const flat_binder_object& flat, const Parcel& in)
-{
- return NO_ERROR;
-}
-
-status_t unflatten_binder(const sp<ProcessState>& proc,
- const Parcel& in, sp<IBinder>* out)
-{
- const flat_binder_object* flat = in.readObject(false);
-
- if (flat) {
- switch (flat->type) {
- case BINDER_TYPE_BINDER:
- *out = static_cast<IBinder*>(flat->cookie);
- return finish_unflatten_binder(NULL, *flat, in);
- case BINDER_TYPE_HANDLE:
- *out = proc->getStrongProxyForHandle(flat->handle);
- return finish_unflatten_binder(
- static_cast<BpBinder*>(out->get()), *flat, in);
- }
- }
- return BAD_TYPE;
-}
-
-status_t unflatten_binder(const sp<ProcessState>& proc,
- const Parcel& in, wp<IBinder>* out)
-{
- const flat_binder_object* flat = in.readObject(false);
-
- if (flat) {
- switch (flat->type) {
- case BINDER_TYPE_BINDER:
- *out = static_cast<IBinder*>(flat->cookie);
- return finish_unflatten_binder(NULL, *flat, in);
- case BINDER_TYPE_WEAK_BINDER:
- if (flat->binder != NULL) {
- out->set_object_and_refs(
- static_cast<IBinder*>(flat->cookie),
- static_cast<RefBase::weakref_type*>(flat->binder));
- } else {
- *out = NULL;
- }
- return finish_unflatten_binder(NULL, *flat, in);
- case BINDER_TYPE_HANDLE:
- case BINDER_TYPE_WEAK_HANDLE:
- *out = proc->getWeakProxyForHandle(flat->handle);
- return finish_unflatten_binder(
- static_cast<BpBinder*>(out->unsafe_get()), *flat, in);
- }
- }
- return BAD_TYPE;
-}
-
-// ---------------------------------------------------------------------------
-
-Parcel::Parcel()
-{
- initState();
-}
-
-Parcel::~Parcel()
-{
- freeDataNoInit();
-}
-
-const uint8_t* Parcel::data() const
-{
- return mData;
-}
-
-size_t Parcel::dataSize() const
-{
- return (mDataSize > mDataPos ? mDataSize : mDataPos);
-}
-
-size_t Parcel::dataAvail() const
-{
- // TODO: decide what to do about the possibility that this can
- // report an available-data size that exceeds a Java int's max
- // positive value, causing havoc. Fortunately this will only
- // happen if someone constructs a Parcel containing more than two
- // gigabytes of data, which on typical phone hardware is simply
- // not possible.
- return dataSize() - dataPosition();
-}
-
-size_t Parcel::dataPosition() const
-{
- return mDataPos;
-}
-
-size_t Parcel::dataCapacity() const
-{
- return mDataCapacity;
-}
-
-status_t Parcel::setDataSize(size_t size)
-{
- status_t err;
- err = continueWrite(size);
- if (err == NO_ERROR) {
- mDataSize = size;
- LOGV("setDataSize Setting data size of %p to %d\n", this, mDataSize);
- }
- return err;
-}
-
-void Parcel::setDataPosition(size_t pos) const
-{
- mDataPos = pos;
- mNextObjectHint = 0;
-}
-
-status_t Parcel::setDataCapacity(size_t size)
-{
- if (size > mDataSize) return continueWrite(size);
- return NO_ERROR;
-}
-
-status_t Parcel::setData(const uint8_t* buffer, size_t len)
-{
- status_t err = restartWrite(len);
- if (err == NO_ERROR) {
- memcpy(const_cast<uint8_t*>(data()), buffer, len);
- mDataSize = len;
- mFdsKnown = false;
- }
- return err;
-}
-
-status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)
-{
- const sp<ProcessState> proc(ProcessState::self());
- status_t err;
- uint8_t *data = parcel->mData;
- size_t *objects = parcel->mObjects;
- size_t size = parcel->mObjectsSize;
- int startPos = mDataPos;
- int firstIndex = -1, lastIndex = -2;
-
- if (len == 0) {
- return NO_ERROR;
- }
-
- // range checks against the source parcel size
- if ((offset > parcel->mDataSize)
- || (len > parcel->mDataSize)
- || (offset + len > parcel->mDataSize)) {
- return BAD_VALUE;
- }
-
- // Count objects in range
- for (int i = 0; i < (int) size; i++) {
- size_t off = objects[i];
- if ((off >= offset) && (off < offset + len)) {
- if (firstIndex == -1) {
- firstIndex = i;
- }
- lastIndex = i;
- }
- }
- int numObjects = lastIndex - firstIndex + 1;
-
- // grow data
- err = growData(len);
- if (err != NO_ERROR) {
- return err;
- }
-
- // append data
- memcpy(mData + mDataPos, data + offset, len);
- mDataPos += len;
- mDataSize += len;
-
- if (numObjects > 0) {
- // grow objects
- if (mObjectsCapacity < mObjectsSize + numObjects) {
- int newSize = ((mObjectsSize + numObjects)*3)/2;
- size_t *objects =
- (size_t*)realloc(mObjects, newSize*sizeof(size_t));
- if (objects == (size_t*)0) {
- return NO_MEMORY;
- }
- mObjects = objects;
- mObjectsCapacity = newSize;
- }
-
- // append and acquire objects
- int idx = mObjectsSize;
- for (int i = firstIndex; i <= lastIndex; i++) {
- size_t off = objects[i] - offset + startPos;
- mObjects[idx++] = off;
- mObjectsSize++;
-
- flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(mData + off);
- acquire_object(proc, *flat, this);
-
- if (flat->type == BINDER_TYPE_FD) {
- // If this is a file descriptor, we need to dup it so the
- // new Parcel now owns its own fd, and can declare that we
- // officially know we have fds.
- flat->handle = dup(flat->handle);
- flat->cookie = (void*)1;
- mHasFds = mFdsKnown = true;
- }
- }
- }
-
- return NO_ERROR;
-}
-
-bool Parcel::hasFileDescriptors() const
-{
- if (!mFdsKnown) {
- scanForFds();
- }
- return mHasFds;
-}
-
-status_t Parcel::writeInterfaceToken(const String16& interface)
-{
- // currently the interface identification token is just its name as a string
- return writeString16(interface);
-}
-
-bool Parcel::enforceInterface(const String16& interface) const
-{
- String16 str = readString16();
- if (str == interface) {
- return true;
- } else {
- LOGW("**** enforceInterface() expected '%s' but read '%s'\n",
- String8(interface).string(), String8(str).string());
- return false;
- }
-}
-
-const size_t* Parcel::objects() const
-{
- return mObjects;
-}
-
-size_t Parcel::objectsCount() const
-{
- return mObjectsSize;
-}
-
-status_t Parcel::errorCheck() const
-{
- return mError;
-}
-
-void Parcel::setError(status_t err)
-{
- mError = err;
-}
-
-status_t Parcel::finishWrite(size_t len)
-{
- //printf("Finish write of %d\n", len);
- mDataPos += len;
- LOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos);
- if (mDataPos > mDataSize) {
- mDataSize = mDataPos;
- LOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize);
- }
- //printf("New pos=%d, size=%d\n", mDataPos, mDataSize);
- return NO_ERROR;
-}
-
-status_t Parcel::writeUnpadded(const void* data, size_t len)
-{
- size_t end = mDataPos + len;
- if (end < mDataPos) {
- // integer overflow
- return BAD_VALUE;
- }
-
- if (end <= mDataCapacity) {
-restart_write:
- memcpy(mData+mDataPos, data, len);
- return finishWrite(len);
- }
-
- status_t err = growData(len);
- if (err == NO_ERROR) goto restart_write;
- return err;
-}
-
-status_t Parcel::write(const void* data, size_t len)
-{
- void* const d = writeInplace(len);
- if (d) {
- memcpy(d, data, len);
- return NO_ERROR;
- }
- return mError;
-}
-
-void* Parcel::writeInplace(size_t len)
-{
- const size_t padded = PAD_SIZE(len);
-
- // sanity check for integer overflow
- if (mDataPos+padded < mDataPos) {
- return NULL;
- }
-
- if ((mDataPos+padded) <= mDataCapacity) {
-restart_write:
- //printf("Writing %ld bytes, padded to %ld\n", len, padded);
- uint8_t* const data = mData+mDataPos;
-
- // Need to pad at end?
- if (padded != len) {
-#if BYTE_ORDER == BIG_ENDIAN
- static const uint32_t mask[4] = {
- 0x00000000, 0xffffff00, 0xffff0000, 0xff000000
- };
-#endif
-#if BYTE_ORDER == LITTLE_ENDIAN
- static const uint32_t mask[4] = {
- 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff
- };
-#endif
- //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len],
- // *reinterpret_cast<void**>(data+padded-4));
- *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len];
- }
-
- finishWrite(padded);
- return data;
- }
-
- status_t err = growData(padded);
- if (err == NO_ERROR) goto restart_write;
- return NULL;
-}
-
-status_t Parcel::writeInt32(int32_t val)
-{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<int32_t*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
-
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
-}
-
-status_t Parcel::writeInt64(int64_t val)
-{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<int64_t*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
-
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
-}
-
-status_t Parcel::writeFloat(float val)
-{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<float*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
-
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
-}
-
-status_t Parcel::writeDouble(double val)
-{
- if ((mDataPos+sizeof(val)) <= mDataCapacity) {
-restart_write:
- *reinterpret_cast<double*>(mData+mDataPos) = val;
- return finishWrite(sizeof(val));
- }
-
- status_t err = growData(sizeof(val));
- if (err == NO_ERROR) goto restart_write;
- return err;
-}
-
-status_t Parcel::writeCString(const char* str)
-{
- return write(str, strlen(str)+1);
-}
-
-status_t Parcel::writeString8(const String8& str)
-{
- status_t err = writeInt32(str.bytes());
- if (err == NO_ERROR) {
- err = write(str.string(), str.bytes()+1);
- }
- return err;
-}
-
-status_t Parcel::writeString16(const String16& str)
-{
- return writeString16(str.string(), str.size());
-}
-
-status_t Parcel::writeString16(const char16_t* str, size_t len)
-{
- if (str == NULL) return writeInt32(-1);
-
- status_t err = writeInt32(len);
- if (err == NO_ERROR) {
- len *= sizeof(char16_t);
- uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
- if (data) {
- memcpy(data, str, len);
- *reinterpret_cast<char16_t*>(data+len) = 0;
- return NO_ERROR;
- }
- err = mError;
- }
- return err;
-}
-
-status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
-{
- return flatten_binder(ProcessState::self(), val, this);
-}
-
-status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
-{
- return flatten_binder(ProcessState::self(), val, this);
-}
-
-status_t Parcel::writeNativeHandle(const native_handle* handle)
-{
- if (handle->version != sizeof(native_handle))
- return BAD_TYPE;
-
- status_t err;
- err = writeInt32(handle->numFds);
- if (err != NO_ERROR) return err;
-
- err = writeInt32(handle->numInts);
- if (err != NO_ERROR) return err;
-
- for (int i=0 ; err==NO_ERROR && i<handle->numFds ; i++)
- err = writeDupFileDescriptor(handle->data[i]);
-
- if (err != NO_ERROR) {
- LOGD("write native handle, write dup fd failed");
- return err;
- }
- err = write(handle->data + handle->numFds, sizeof(int)*handle->numInts);
- return err;
-}
-
-status_t Parcel::writeFileDescriptor(int fd)
-{
- flat_binder_object obj;
- obj.type = BINDER_TYPE_FD;
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj.handle = fd;
- obj.cookie = (void*)0;
- return writeObject(obj, true);
-}
-
-status_t Parcel::writeDupFileDescriptor(int fd)
-{
- flat_binder_object obj;
- obj.type = BINDER_TYPE_FD;
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj.handle = dup(fd);
- obj.cookie = (void*)1;
- return writeObject(obj, true);
-}
-
-status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
-{
- const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
- const bool enoughObjects = mObjectsSize < mObjectsCapacity;
- if (enoughData && enoughObjects) {
-restart_write:
- *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
-
- // Need to write meta-data?
- if (nullMetaData || val.binder != NULL) {
- mObjects[mObjectsSize] = mDataPos;
- acquire_object(ProcessState::self(), val, this);
- mObjectsSize++;
- }
-
- // remember if it's a file descriptor
- if (val.type == BINDER_TYPE_FD) {
- mHasFds = mFdsKnown = true;
- }
-
- return finishWrite(sizeof(flat_binder_object));
- }
-
- if (!enoughData) {
- const status_t err = growData(sizeof(val));
- if (err != NO_ERROR) return err;
- }
- if (!enoughObjects) {
- size_t newSize = ((mObjectsSize+2)*3)/2;
- size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));
- if (objects == NULL) return NO_MEMORY;
- mObjects = objects;
- mObjectsCapacity = newSize;
- }
-
- goto restart_write;
-}
-
-
-void Parcel::remove(size_t start, size_t amt)
-{
- LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
-}
-
-status_t Parcel::read(void* outData, size_t len) const
-{
- if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
- memcpy(outData, mData+mDataPos, len);
- mDataPos += PAD_SIZE(len);
- LOGV("read Setting data pos of %p to %d\n", this, mDataPos);
- return NO_ERROR;
- }
- return NOT_ENOUGH_DATA;
-}
-
-const void* Parcel::readInplace(size_t len) const
-{
- if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += PAD_SIZE(len);
- LOGV("readInplace Setting data pos of %p to %d\n", this, mDataPos);
- return data;
- }
- return NULL;
-}
-
-status_t Parcel::readInt32(int32_t *pArg) const
-{
- if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int32_t);
- *pArg = *reinterpret_cast<const int32_t*>(data);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
-}
-
-int32_t Parcel::readInt32() const
-{
- if ((mDataPos+sizeof(int32_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int32_t);
- LOGV("readInt32 Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const int32_t*>(data);
- }
- return 0;
-}
-
-
-status_t Parcel::readInt64(int64_t *pArg) const
-{
- if ((mDataPos+sizeof(int64_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int64_t);
- *pArg = *reinterpret_cast<const int64_t*>(data);
- LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
-}
-
-
-int64_t Parcel::readInt64() const
-{
- if ((mDataPos+sizeof(int64_t)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(int64_t);
- LOGV("readInt64 Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const int64_t*>(data);
- }
- return 0;
-}
-
-status_t Parcel::readFloat(float *pArg) const
-{
- if ((mDataPos+sizeof(float)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(float);
- LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos);
- *pArg = *reinterpret_cast<const float*>(data);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
-}
-
-
-float Parcel::readFloat() const
-{
- if ((mDataPos+sizeof(float)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(float);
- LOGV("readFloat Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const float*>(data);
- }
- return 0;
-}
-
-status_t Parcel::readDouble(double *pArg) const
-{
- if ((mDataPos+sizeof(double)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(double);
- LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos);
- *pArg = *reinterpret_cast<const double*>(data);
- return NO_ERROR;
- } else {
- return NOT_ENOUGH_DATA;
- }
-}
-
-
-double Parcel::readDouble() const
-{
- if ((mDataPos+sizeof(double)) <= mDataSize) {
- const void* data = mData+mDataPos;
- mDataPos += sizeof(double);
- LOGV("readDouble Setting data pos of %p to %d\n", this, mDataPos);
- return *reinterpret_cast<const double*>(data);
- }
- return 0;
-}
-
-
-const char* Parcel::readCString() const
-{
- const size_t avail = mDataSize-mDataPos;
- if (avail > 0) {
- const char* str = reinterpret_cast<const char*>(mData+mDataPos);
- // is the string's trailing NUL within the parcel's valid bounds?
- const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
- if (eos) {
- const size_t len = eos - str;
- mDataPos += PAD_SIZE(len+1);
- LOGV("readCString Setting data pos of %p to %d\n", this, mDataPos);
- return str;
- }
- }
- return NULL;
-}
-
-String8 Parcel::readString8() const
-{
- int32_t size = readInt32();
- // watch for potential int overflow adding 1 for trailing NUL
- if (size > 0 && size < INT32_MAX) {
- const char* str = (const char*)readInplace(size+1);
- if (str) return String8(str, size);
- }
- return String8();
-}
-
-String16 Parcel::readString16() const
-{
- size_t len;
- const char16_t* str = readString16Inplace(&len);
- if (str) return String16(str, len);
- LOGE("Reading a NULL string not supported here.");
- return String16();
-}
-
-const char16_t* Parcel::readString16Inplace(size_t* outLen) const
-{
- int32_t size = readInt32();
- // watch for potential int overflow from size+1
- if (size >= 0 && size < INT32_MAX) {
- *outLen = size;
- const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
- if (str != NULL) {
- return str;
- }
- }
- *outLen = 0;
- return NULL;
-}
-
-sp<IBinder> Parcel::readStrongBinder() const
-{
- sp<IBinder> val;
- unflatten_binder(ProcessState::self(), *this, &val);
- return val;
-}
-
-wp<IBinder> Parcel::readWeakBinder() const
-{
- wp<IBinder> val;
- unflatten_binder(ProcessState::self(), *this, &val);
- return val;
-}
-
-
-native_handle* Parcel::readNativeHandle() const
-{
- int numFds, numInts;
- status_t err;
- err = readInt32(&numFds);
- if (err != NO_ERROR) return 0;
- err = readInt32(&numInts);
- if (err != NO_ERROR) return 0;
-
- native_handle* h = native_handle_create(numFds, numInts);
- for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {
- h->data[i] = dup(readFileDescriptor());
- if (h->data[i] < 0) err = BAD_VALUE;
- }
- err = read(h->data + numFds, sizeof(int)*numInts);
- if (err != NO_ERROR) {
- native_handle_close(h);
- native_handle_delete(h);
- h = 0;
- }
- return h;
-}
-
-
-int Parcel::readFileDescriptor() const
-{
- const flat_binder_object* flat = readObject(true);
- if (flat) {
- switch (flat->type) {
- case BINDER_TYPE_FD:
- //LOGI("Returning file descriptor %ld from parcel %p\n", flat->handle, this);
- return flat->handle;
- }
- }
- return BAD_TYPE;
-}
-
-const flat_binder_object* Parcel::readObject(bool nullMetaData) const
-{
- const size_t DPOS = mDataPos;
- if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
- const flat_binder_object* obj
- = reinterpret_cast<const flat_binder_object*>(mData+DPOS);
- mDataPos = DPOS + sizeof(flat_binder_object);
- if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) {
- // When transferring a NULL object, we don't write it into
- // the object list, so we don't want to check for it when
- // reading.
- LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
- return obj;
- }
-
- // Ensure that this object is valid...
- size_t* const OBJS = mObjects;
- const size_t N = mObjectsSize;
- size_t opos = mNextObjectHint;
-
- if (N > 0) {
- LOGV("Parcel %p looking for obj at %d, hint=%d\n",
- this, DPOS, opos);
-
- // Start at the current hint position, looking for an object at
- // the current data position.
- if (opos < N) {
- while (opos < (N-1) && OBJS[opos] < DPOS) {
- opos++;
- }
- } else {
- opos = N-1;
- }
- if (OBJS[opos] == DPOS) {
- // Found it!
- LOGV("Parcel found obj %d at index %d with forward search",
- this, DPOS, opos);
- mNextObjectHint = opos+1;
- LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
- return obj;
- }
-
- // Look backwards for it...
- while (opos > 0 && OBJS[opos] > DPOS) {
- opos--;
- }
- if (OBJS[opos] == DPOS) {
- // Found it!
- LOGV("Parcel found obj %d at index %d with backward search",
- this, DPOS, opos);
- mNextObjectHint = opos+1;
- LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
- return obj;
- }
- }
- LOGW("Attempt to read object from Parcel %p at offset %d that is not in the object list",
- this, DPOS);
- }
- return NULL;
-}
-
-void Parcel::closeFileDescriptors()
-{
- size_t i = mObjectsSize;
- if (i > 0) {
- //LOGI("Closing file descriptors for %d objects...", mObjectsSize);
- }
- while (i > 0) {
- i--;
- const flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
- if (flat->type == BINDER_TYPE_FD) {
- //LOGI("Closing fd: %ld\n", flat->handle);
- close(flat->handle);
- }
- }
-}
-
-const uint8_t* Parcel::ipcData() const
-{
- return mData;
-}
-
-size_t Parcel::ipcDataSize() const
-{
- return (mDataSize > mDataPos ? mDataSize : mDataPos);
-}
-
-const size_t* Parcel::ipcObjects() const
-{
- return mObjects;
-}
-
-size_t Parcel::ipcObjectsCount() const
-{
- return mObjectsSize;
-}
-
-void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
- const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)
-{
- freeDataNoInit();
- mError = NO_ERROR;
- mData = const_cast<uint8_t*>(data);
- mDataSize = mDataCapacity = dataSize;
- //LOGI("setDataReference Setting data size of %p to %lu (pid=%d)\n", this, mDataSize, getpid());
- mDataPos = 0;
- LOGV("setDataReference Setting data pos of %p to %d\n", this, mDataPos);
- mObjects = const_cast<size_t*>(objects);
- mObjectsSize = mObjectsCapacity = objectsCount;
- mNextObjectHint = 0;
- mOwner = relFunc;
- mOwnerCookie = relCookie;
- scanForFds();
-}
-
-void Parcel::print(TextOutput& to, uint32_t flags) const
-{
- to << "Parcel(";
-
- if (errorCheck() != NO_ERROR) {
- const status_t err = errorCheck();
- to << "Error: " << (void*)err << " \"" << strerror(-err) << "\"";
- } else if (dataSize() > 0) {
- const uint8_t* DATA = data();
- to << indent << HexDump(DATA, dataSize()) << dedent;
- const size_t* OBJS = objects();
- const size_t N = objectsCount();
- for (size_t i=0; i<N; i++) {
- const flat_binder_object* flat
- = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);
- to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": "
- << TypeCode(flat->type & 0x7f7f7f00)
- << " = " << flat->binder;
- }
- } else {
- to << "NULL";
- }
-
- to << ")";
-}
-
-void Parcel::releaseObjects()
-{
- const sp<ProcessState> proc(ProcessState::self());
- size_t i = mObjectsSize;
- uint8_t* const data = mData;
- size_t* const objects = mObjects;
- while (i > 0) {
- i--;
- const flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(data+objects[i]);
- release_object(proc, *flat, this);
- }
-}
-
-void Parcel::acquireObjects()
-{
- const sp<ProcessState> proc(ProcessState::self());
- size_t i = mObjectsSize;
- uint8_t* const data = mData;
- size_t* const objects = mObjects;
- while (i > 0) {
- i--;
- const flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(data+objects[i]);
- acquire_object(proc, *flat, this);
- }
-}
-
-void Parcel::freeData()
-{
- freeDataNoInit();
- initState();
-}
-
-void Parcel::freeDataNoInit()
-{
- if (mOwner) {
- //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
- mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
- } else {
- releaseObjects();
- if (mData) free(mData);
- if (mObjects) free(mObjects);
- }
-}
-
-status_t Parcel::growData(size_t len)
-{
- size_t newSize = ((mDataSize+len)*3)/2;
- return (newSize <= mDataSize)
- ? (status_t) NO_MEMORY
- : continueWrite(newSize);
-}
-
-status_t Parcel::restartWrite(size_t desired)
-{
- if (mOwner) {
- freeData();
- return continueWrite(desired);
- }
-
- uint8_t* data = (uint8_t*)realloc(mData, desired);
- if (!data && desired > mDataCapacity) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
-
- releaseObjects();
-
- if (data) {
- mData = data;
- mDataCapacity = desired;
- }
-
- mDataSize = mDataPos = 0;
- LOGV("restartWrite Setting data size of %p to %d\n", this, mDataSize);
- LOGV("restartWrite Setting data pos of %p to %d\n", this, mDataPos);
-
- free(mObjects);
- mObjects = NULL;
- mObjectsSize = mObjectsCapacity = 0;
- mNextObjectHint = 0;
- mHasFds = false;
- mFdsKnown = true;
-
- return NO_ERROR;
-}
-
-status_t Parcel::continueWrite(size_t desired)
-{
- // If shrinking, first adjust for any objects that appear
- // after the new data size.
- size_t objectsSize = mObjectsSize;
- if (desired < mDataSize) {
- if (desired == 0) {
- objectsSize = 0;
- } else {
- while (objectsSize > 0) {
- if (mObjects[objectsSize-1] < desired)
- break;
- objectsSize--;
- }
- }
- }
-
- if (mOwner) {
- // If the size is going to zero, just release the owner's data.
- if (desired == 0) {
- freeData();
- return NO_ERROR;
- }
-
- // If there is a different owner, we need to take
- // posession.
- uint8_t* data = (uint8_t*)malloc(desired);
- if (!data) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
- size_t* objects = NULL;
-
- if (objectsSize) {
- objects = (size_t*)malloc(objectsSize*sizeof(size_t));
- if (!objects) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
-
- // Little hack to only acquire references on objects
- // we will be keeping.
- size_t oldObjectsSize = mObjectsSize;
- mObjectsSize = objectsSize;
- acquireObjects();
- mObjectsSize = oldObjectsSize;
- }
-
- if (mData) {
- memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
- }
- if (objects && mObjects) {
- memcpy(objects, mObjects, objectsSize*sizeof(size_t));
- }
- //LOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());
- mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
- mOwner = NULL;
-
- mData = data;
- mObjects = objects;
- mDataSize = (mDataSize < desired) ? mDataSize : desired;
- LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
- mDataCapacity = desired;
- mObjectsSize = mObjectsCapacity = objectsSize;
- mNextObjectHint = 0;
-
- } else if (mData) {
- if (objectsSize < mObjectsSize) {
- // Need to release refs on any objects we are dropping.
- const sp<ProcessState> proc(ProcessState::self());
- for (size_t i=objectsSize; i<mObjectsSize; i++) {
- const flat_binder_object* flat
- = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
- if (flat->type == BINDER_TYPE_FD) {
- // will need to rescan because we may have lopped off the only FDs
- mFdsKnown = false;
- }
- release_object(proc, *flat, this);
- }
- size_t* objects =
- (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
- if (objects) {
- mObjects = objects;
- }
- mObjectsSize = objectsSize;
- mNextObjectHint = 0;
- }
-
- // We own the data, so we can just do a realloc().
- if (desired > mDataCapacity) {
- uint8_t* data = (uint8_t*)realloc(mData, desired);
- if (data) {
- mData = data;
- mDataCapacity = desired;
- } else if (desired > mDataCapacity) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
- } else {
- mDataSize = desired;
- LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
- if (mDataPos > desired) {
- mDataPos = desired;
- LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
- }
- }
-
- } else {
- // This is the first data. Easy!
- uint8_t* data = (uint8_t*)malloc(desired);
- if (!data) {
- mError = NO_MEMORY;
- return NO_MEMORY;
- }
-
- if(!(mDataCapacity == 0 && mObjects == NULL
- && mObjectsCapacity == 0)) {
- LOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
- }
-
- mData = data;
- mDataSize = mDataPos = 0;
- LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
- LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
- mDataCapacity = desired;
- }
-
- return NO_ERROR;
-}
-
-void Parcel::initState()
-{
- mError = NO_ERROR;
- mData = 0;
- mDataSize = 0;
- mDataCapacity = 0;
- mDataPos = 0;
- LOGV("initState Setting data size of %p to %d\n", this, mDataSize);
- LOGV("initState Setting data pos of %p to %d\n", this, mDataPos);
- mObjects = NULL;
- mObjectsSize = 0;
- mObjectsCapacity = 0;
- mNextObjectHint = 0;
- mHasFds = false;
- mFdsKnown = true;
- mOwner = NULL;
-}
-
-void Parcel::scanForFds() const
-{
- bool hasFds = false;
- for (size_t i=0; i<mObjectsSize; i++) {
- const flat_binder_object* flat
- = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
- if (flat->type == BINDER_TYPE_FD) {
- hasFds = true;
- break;
- }
- }
- mHasFds = hasFds;
- mFdsKnown = true;
-}
-
-}; // namespace android
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/ProcessState.cpp b/libs/utils/ProcessState.cpp
deleted file mode 100644
index 4567df6..0000000
--- a/libs/utils/ProcessState.cpp
+++ /dev/null
@@ -1,398 +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.
- */
-
-#define LOG_TAG "ProcessState"
-
-#include <cutils/process_name.h>
-
-#include <utils/ProcessState.h>
-
-#include <utils/Atomic.h>
-#include <utils/BpBinder.h>
-#include <utils/IPCThreadState.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/IServiceManager.h>
-#include <utils/String8.h>
-#include <utils/threads.h>
-
-#include <private/utils/binder_module.h>
-#include <private/utils/Static.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#define BINDER_VM_SIZE (1*1024*1024)
-
-static bool gSingleProcess = false;
-
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-// Global variables
-int mArgC;
-const char* const* mArgV;
-int mArgLen;
-
-class PoolThread : public Thread
-{
-public:
- PoolThread(bool isMain)
- : mIsMain(isMain)
- {
- }
-
-protected:
- virtual bool threadLoop()
- {
- IPCThreadState::self()->joinThreadPool(mIsMain);
- return false;
- }
-
- const bool mIsMain;
-};
-
-sp<ProcessState> ProcessState::self()
-{
- if (gProcess != NULL) return gProcess;
-
- AutoMutex _l(gProcessMutex);
- if (gProcess == NULL) gProcess = new ProcessState;
- return gProcess;
-}
-
-void ProcessState::setSingleProcess(bool singleProcess)
-{
- gSingleProcess = singleProcess;
-}
-
-
-void ProcessState::setContextObject(const sp<IBinder>& object)
-{
- setContextObject(object, String16("default"));
-}
-
-sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
-{
- if (supportsProcesses()) {
- return getStrongProxyForHandle(0);
- } else {
- return getContextObject(String16("default"), caller);
- }
-}
-
-void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
-{
- AutoMutex _l(mLock);
- mContexts.add(name, object);
-}
-
-sp<IBinder> ProcessState::getContextObject(const String16& name, const sp<IBinder>& caller)
-{
- mLock.lock();
- sp<IBinder> object(
- mContexts.indexOfKey(name) >= 0 ? mContexts.valueFor(name) : NULL);
- mLock.unlock();
-
- //printf("Getting context object %s for %p\n", String8(name).string(), caller.get());
-
- if (object != NULL) return object;
-
- // Don't attempt to retrieve contexts if we manage them
- if (mManagesContexts) {
- LOGE("getContextObject(%s) failed, but we manage the contexts!\n",
- String8(name).string());
- return NULL;
- }
-
- IPCThreadState* ipc = IPCThreadState::self();
- {
- Parcel data, reply;
- // no interface token on this magic transaction
- data.writeString16(name);
- data.writeStrongBinder(caller);
- status_t result = ipc->transact(0 /*magic*/, 0, data, &reply, 0);
- if (result == NO_ERROR) {
- object = reply.readStrongBinder();
- }
- }
-
- ipc->flushCommands();
-
- if (object != NULL) setContextObject(object, name);
- return object;
-}
-
-bool ProcessState::supportsProcesses() const
-{
- return mDriverFD >= 0;
-}
-
-void ProcessState::startThreadPool()
-{
- AutoMutex _l(mLock);
- if (!mThreadPoolStarted) {
- mThreadPoolStarted = true;
- spawnPooledThread(true);
- }
-}
-
-bool ProcessState::isContextManager(void) const
-{
- return mManagesContexts;
-}
-
-bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData)
-{
- if (!mManagesContexts) {
- AutoMutex _l(mLock);
- mBinderContextCheckFunc = checkFunc;
- mBinderContextUserData = userData;
- if (mDriverFD >= 0) {
- int dummy = 0;
-#if defined(HAVE_ANDROID_OS)
- status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
-#else
- status_t result = INVALID_OPERATION;
-#endif
- if (result == 0) {
- mManagesContexts = true;
- } else if (result == -1) {
- mBinderContextCheckFunc = NULL;
- mBinderContextUserData = NULL;
- LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
- }
- } else {
- // If there is no driver, our only world is the local
- // process so we can always become the context manager there.
- mManagesContexts = true;
- }
- }
- return mManagesContexts;
-}
-
-ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
-{
- const size_t N=mHandleToObject.size();
- if (N <= (size_t)handle) {
- handle_entry e;
- e.binder = NULL;
- e.refs = NULL;
- status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
- if (err < NO_ERROR) return NULL;
- }
- return &mHandleToObject.editItemAt(handle);
-}
-
-sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
-{
- sp<IBinder> result;
-
- AutoMutex _l(mLock);
-
- handle_entry* e = lookupHandleLocked(handle);
-
- if (e != NULL) {
- // We need to create a new BpBinder if there isn't currently one, OR we
- // are unable to acquire a weak reference on this current one. See comment
- // in getWeakProxyForHandle() for more info about this.
- IBinder* b = e->binder;
- if (b == NULL || !e->refs->attemptIncWeak(this)) {
- b = new BpBinder(handle);
- e->binder = b;
- if (b) e->refs = b->getWeakRefs();
- result = b;
- } else {
- // This little bit of nastyness is to allow us to add a primary
- // reference to the remote proxy when this team doesn't have one
- // but another team is sending the handle to us.
- result.force_set(b);
- e->refs->decWeak(this);
- }
- }
-
- return result;
-}
-
-wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
-{
- wp<IBinder> result;
-
- AutoMutex _l(mLock);
-
- handle_entry* e = lookupHandleLocked(handle);
-
- if (e != NULL) {
- // We need to create a new BpBinder if there isn't currently one, OR we
- // are unable to acquire a weak reference on this current one. The
- // attemptIncWeak() is safe because we know the BpBinder destructor will always
- // call expungeHandle(), which acquires the same lock we are holding now.
- // We need to do this because there is a race condition between someone
- // releasing a reference on this BpBinder, and a new reference on its handle
- // arriving from the driver.
- IBinder* b = e->binder;
- if (b == NULL || !e->refs->attemptIncWeak(this)) {
- b = new BpBinder(handle);
- result = b;
- e->binder = b;
- if (b) e->refs = b->getWeakRefs();
- } else {
- result = b;
- e->refs->decWeak(this);
- }
- }
-
- return result;
-}
-
-void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
-{
- AutoMutex _l(mLock);
-
- handle_entry* e = lookupHandleLocked(handle);
-
- // This handle may have already been replaced with a new BpBinder
- // (if someone failed the AttemptIncWeak() above); we don't want
- // to overwrite it.
- if (e && e->binder == binder) e->binder = NULL;
-}
-
-void ProcessState::setArgs(int argc, const char* const argv[])
-{
- mArgC = argc;
- mArgV = (const char **)argv;
-
- mArgLen = 0;
- for (int i=0; i<argc; i++) {
- mArgLen += strlen(argv[i]) + 1;
- }
- mArgLen--;
-}
-
-int ProcessState::getArgC() const
-{
- return mArgC;
-}
-
-const char* const* ProcessState::getArgV() const
-{
- return mArgV;
-}
-
-void ProcessState::setArgV0(const char* txt)
-{
- if (mArgV != NULL) {
- strncpy((char*)mArgV[0], txt, mArgLen);
- set_process_name(txt);
- }
-}
-
-void ProcessState::spawnPooledThread(bool isMain)
-{
- if (mThreadPoolStarted) {
- int32_t s = android_atomic_add(1, &mThreadPoolSeq);
- char buf[32];
- sprintf(buf, "Binder Thread #%d", s);
- LOGV("Spawning new pooled thread, name=%s\n", buf);
- sp<Thread> t = new PoolThread(isMain);
- t->run(buf);
- }
-}
-
-static int open_driver()
-{
- if (gSingleProcess) {
- return -1;
- }
-
- int fd = open("/dev/binder", O_RDWR);
- if (fd >= 0) {
- fcntl(fd, F_SETFD, FD_CLOEXEC);
- int vers;
-#if defined(HAVE_ANDROID_OS)
- status_t result = ioctl(fd, BINDER_VERSION, &vers);
-#else
- status_t result = -1;
- errno = EPERM;
-#endif
- if (result == -1) {
- LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
- close(fd);
- fd = -1;
- }
- if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
- LOGE("Binder driver protocol does not match user space protocol!");
- close(fd);
- fd = -1;
- }
-#if defined(HAVE_ANDROID_OS)
- size_t maxThreads = 15;
- result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
- if (result == -1) {
- LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
- }
-#endif
-
- } else {
- LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
- }
- return fd;
-}
-
-ProcessState::ProcessState()
- : mDriverFD(open_driver())
- , mVMStart(MAP_FAILED)
- , mManagesContexts(false)
- , mBinderContextCheckFunc(NULL)
- , mBinderContextUserData(NULL)
- , mThreadPoolStarted(false)
- , mThreadPoolSeq(1)
-{
- if (mDriverFD >= 0) {
- // XXX Ideally, there should be a specific define for whether we
- // have mmap (or whether we could possibly have the kernel module
- // availabla).
-#if !defined(HAVE_WIN32_IPC)
- // mmap the binder, providing a chunk of virtual address space to receive transactions.
- mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
- if (mVMStart == MAP_FAILED) {
- // *sigh*
- LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
- close(mDriverFD);
- mDriverFD = -1;
- }
-#else
- mDriverFD = -1;
-#endif
- }
- if (mDriverFD < 0) {
- // Need to run without the driver, starting our own thread pool.
- }
-}
-
-ProcessState::~ProcessState()
-{
-}
-
-}; // namespace android
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/Threads.cpp b/libs/utils/Threads.cpp
index 9287c0b..6be372c 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -38,10 +38,6 @@
# define HAVE_CREATETHREAD // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW
#endif
-#if defined(HAVE_FUTEX)
-#include <private/utils/futex_synchro.h>
-#endif
-
#if defined(HAVE_PRCTL)
#include <sys/prctl.h>
#endif
@@ -56,10 +52,6 @@ using namespace android;
// ----------------------------------------------------------------------------
#if defined(HAVE_PTHREADS)
-#if 0
-#pragma mark -
-#pragma mark PTHREAD
-#endif
// ----------------------------------------------------------------------------
/*
@@ -163,10 +155,6 @@ android_thread_id_t androidGetThreadId()
// ----------------------------------------------------------------------------
#elif defined(HAVE_WIN32_THREADS)
-#if 0
-#pragma mark -
-#pragma mark WIN32_THREADS
-#endif
// ----------------------------------------------------------------------------
/*
@@ -252,11 +240,6 @@ android_thread_id_t androidGetThreadId()
// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Common Thread functions
-#endif
-
int androidCreateThread(android_thread_func_t fn, void* arg)
{
return createThreadEtc(fn, arg);
@@ -294,112 +277,23 @@ namespace android {
* ===========================================================================
*/
-#if 0
-#pragma mark -
-#pragma mark Mutex
-#endif
-
-#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
-/*
- * Simple pthread wrapper.
- */
+#if defined(HAVE_PTHREADS)
+// implemented as inlines in threads.h
+#elif defined(HAVE_WIN32_THREADS)
Mutex::Mutex()
{
- _init();
-}
-
-Mutex::Mutex(const char* name)
-{
- // XXX: name not used for now
- _init();
-}
-
-void Mutex::_init()
-{
- pthread_mutex_t* pMutex = new pthread_mutex_t;
- pthread_mutex_init(pMutex, NULL);
- mState = pMutex;
-}
-
-Mutex::~Mutex()
-{
- delete (pthread_mutex_t*) mState;
-}
-
-status_t Mutex::lock()
-{
- int res;
- while ((res=pthread_mutex_lock((pthread_mutex_t*) mState)) == EINTR) ;
- return -res;
-}
-
-void Mutex::unlock()
-{
- pthread_mutex_unlock((pthread_mutex_t*) mState);
-}
-
-status_t Mutex::tryLock()
-{
- int res;
- while ((res=pthread_mutex_trylock((pthread_mutex_t*) mState)) == EINTR) ;
- return -res;
-}
-
-#elif defined(HAVE_FUTEX)
-#if 0
-#pragma mark -
-#endif
+ HANDLE hMutex;
-#define STATE ((futex_mutex_t*) (&mState))
+ assert(sizeof(hMutex) == sizeof(mState));
-Mutex::Mutex()
-{
- _init();
+ hMutex = CreateMutex(NULL, FALSE, NULL);
+ mState = (void*) hMutex;
}
Mutex::Mutex(const char* name)
{
- _init();
-}
-
-void
-Mutex::_init()
-{
- futex_mutex_init(STATE);
-}
-
-Mutex::~Mutex()
-{
-}
-
-status_t Mutex::lock()
-{
- int res;
- while ((res=futex_mutex_lock(STATE, FUTEX_WAIT_INFINITE)) == EINTR) ;
- return -res;
-}
-
-void Mutex::unlock()
-{
- futex_mutex_unlock(STATE);
-}
-
-status_t Mutex::tryLock()
-{
- int res;
- while ((res=futex_mutex_trylock(STATE)) == EINTR) ;
- return -res;
-}
-#undef STATE
-
-#elif defined(HAVE_WIN32_THREADS)
-#if 0
-#pragma mark -
-#endif
-
-Mutex::Mutex()
-{
+ // XXX: name not used for now
HANDLE hMutex;
assert(sizeof(hMutex) == sizeof(mState));
@@ -408,11 +302,13 @@ Mutex::Mutex()
mState = (void*) hMutex;
}
-Mutex::Mutex(const char* name)
+Mutex::Mutex(int type, const char* name)
{
- // XXX: name not used for now
+ // XXX: type and name not used for now
HANDLE hMutex;
+ assert(sizeof(hMutex) == sizeof(mState));
+
hMutex = CreateMutex(NULL, FALSE, NULL);
mState = (void*) hMutex;
}
@@ -456,161 +352,9 @@ status_t Mutex::tryLock()
* ===========================================================================
*/
-#if 0
-#pragma mark -
-#pragma mark Condition
-#endif
-
-#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX)
-
-/*
- * Constructor. This is a simple pthread wrapper.
- */
-Condition::Condition()
-{
- pthread_cond_t* pCond = new pthread_cond_t;
-
- pthread_cond_init(pCond, NULL);
- mState = pCond;
-}
-
-/*
- * Destructor.
- */
-Condition::~Condition()
-{
- pthread_cond_destroy((pthread_cond_t*) mState);
- delete (pthread_cond_t*) mState;
-}
-
-/*
- * Wait on a condition variable. Lock the mutex before calling.
- */
-
-status_t Condition::wait(Mutex& mutex)
-{
- assert(mutex.mState != NULL);
-
- int cc;
- while ((cc = pthread_cond_wait((pthread_cond_t*)mState,
- (pthread_mutex_t*) mutex.mState)) == EINTR) ;
- return -cc;
-}
-
-status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
-{
- assert(mutex.mState != NULL);
-
- struct timespec ts;
- ts.tv_sec = abstime/1000000000;
- ts.tv_nsec = abstime-(ts.tv_sec*1000000000);
-
- int cc;
- while ((cc = pthread_cond_timedwait((pthread_cond_t*)mState,
- (pthread_mutex_t*) mutex.mState, &ts)) == EINTR) ;
- return -cc;
-}
-
-status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
-{
- return wait(mutex, systemTime()+reltime);
-}
-
-/*
- * Signal the condition variable, allowing one thread to continue.
- */
-void Condition::signal()
-{
- pthread_cond_signal((pthread_cond_t*) mState);
-}
-
-/*
- * Signal the condition variable, allowing all threads to continue.
- */
-void Condition::broadcast()
-{
- pthread_cond_broadcast((pthread_cond_t*) mState);
-}
-
-#elif defined(HAVE_FUTEX)
-#if 0
-#pragma mark -
-#endif
-
-#define STATE ((futex_cond_t*) (&mState))
-
-/*
- * Constructor. This is a simple pthread wrapper.
- */
-Condition::Condition()
-{
- futex_cond_init(STATE);
-}
-
-/*
- * Destructor.
- */
-Condition::~Condition()
-{
-}
-
-/*
- * Wait on a condition variable. Lock the mutex before calling.
- */
-
-status_t Condition::wait(Mutex& mutex)
-{
- assert(mutex.mState != NULL);
-
- int res;
- while ((res = futex_cond_wait(STATE,
- (futex_mutex_t*)(&mutex.mState), FUTEX_WAIT_INFINITE)) == -EINTR) ;
-
- return -res;
-}
-
-status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
-{
- nsecs_t reltime = abstime - systemTime();
- if (reltime <= 0) return true;
- return waitRelative(mutex, reltime);
-}
-
-status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
-{
- assert(mutex.mState != NULL);
- int res;
- unsigned msec = ns2ms(reltime);
- if(msec == 0)
- return true;
- // This code will not time out at the correct time if interrupted by signals
- while ((res = futex_cond_wait(STATE,
- (futex_mutex_t*)(&mutex.mState), msec)) == -EINTR) ;
- return res;
-}
-
-/*
- * Signal the condition variable, allowing one thread to continue.
- */
-void Condition::signal()
-{
- futex_cond_signal(STATE);
-}
-
-/*
- * Signal the condition variable, allowing all threads to continue.
- */
-void Condition::broadcast()
-{
- futex_cond_broadcast(STATE);
-}
-
-#undef STATE
-
+#if defined(HAVE_PTHREADS)
+// implemented as inlines in threads.h
#elif defined(HAVE_WIN32_THREADS)
-#if 0
-#pragma mark -
-#endif
/*
* Windows doesn't have a condition variable solution. It's possible
@@ -753,17 +497,13 @@ status_t Condition::wait(Mutex& mutex)
return ((WinCondition*)mState)->wait(condState, hMutex, NULL);
}
-status_t Condition::wait(Mutex& mutex, nsecs_t abstime)
+status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
{
WinCondition* condState = (WinCondition*) mState;
HANDLE hMutex = (HANDLE) mutex.mState;
+ nsecs_t absTime = systemTime()+reltime;
- return ((WinCondition*)mState)->wait(condState, hMutex, &abstime);
-}
-
-status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime)
-{
- return wait(mutex, systemTime()+reltime);
+ return ((WinCondition*)mState)->wait(condState, hMutex, &absTime);
}
/*
@@ -841,11 +581,6 @@ void Condition::broadcast()
// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Thread::Thread
-#endif
-
/*
* This is our thread object!
*/
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/ZipEntry.cpp b/libs/utils/ZipEntry.cpp
deleted file mode 100644
index 96f9fc4..0000000
--- a/libs/utils/ZipEntry.cpp
+++ /dev/null
@@ -1,696 +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.
- */
-
-//
-// Access to entries in a Zip archive.
-//
-
-#define LOG_TAG "zip"
-
-#include <utils/ZipEntry.h>
-#include <utils/Log.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-using namespace android;
-
-/*
- * Initialize a new ZipEntry structure from a FILE* positioned at a
- * CentralDirectoryEntry.
- *
- * On exit, the file pointer will be at the start of the next CDE or
- * at the EOCD.
- */
-status_t ZipEntry::initFromCDE(FILE* fp)
-{
- status_t result;
- long posn;
- bool hasDD;
-
- //LOGV("initFromCDE ---\n");
-
- /* read the CDE */
- result = mCDE.read(fp);
- if (result != NO_ERROR) {
- LOGD("mCDE.read failed\n");
- return result;
- }
-
- //mCDE.dump();
-
- /* using the info in the CDE, go load up the LFH */
- posn = ftell(fp);
- if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
- LOGD("local header seek failed (%ld)\n",
- mCDE.mLocalHeaderRelOffset);
- return UNKNOWN_ERROR;
- }
-
- result = mLFH.read(fp);
- if (result != NO_ERROR) {
- LOGD("mLFH.read failed\n");
- return result;
- }
-
- if (fseek(fp, posn, SEEK_SET) != 0)
- return UNKNOWN_ERROR;
-
- //mLFH.dump();
-
- /*
- * We *might* need to read the Data Descriptor at this point and
- * integrate it into the LFH. If this bit is set, the CRC-32,
- * compressed size, and uncompressed size will be zero. In practice
- * these seem to be rare.
- */
- hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
- if (hasDD) {
- // do something clever
- //LOGD("+++ has data descriptor\n");
- }
-
- /*
- * Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr"
- * flag is set, because the LFH is incomplete. (Not a problem, since we
- * prefer the CDE values.)
- */
- if (!hasDD && !compareHeaders()) {
- LOGW("WARNING: header mismatch\n");
- // keep going?
- }
-
- /*
- * If the mVersionToExtract is greater than 20, we may have an
- * issue unpacking the record -- could be encrypted, compressed
- * with something we don't support, or use Zip64 extensions. We
- * can defer worrying about that to when we're extracting data.
- */
-
- return NO_ERROR;
-}
-
-/*
- * Initialize a new entry. Pass in the file name and an optional comment.
- *
- * Initializes the CDE and the LFH.
- */
-void ZipEntry::initNew(const char* fileName, const char* comment)
-{
- assert(fileName != NULL && *fileName != '\0'); // name required
-
- /* most fields are properly initialized by constructor */
- mCDE.mVersionMadeBy = kDefaultMadeBy;
- mCDE.mVersionToExtract = kDefaultVersion;
- mCDE.mCompressionMethod = kCompressStored;
- mCDE.mFileNameLength = strlen(fileName);
- if (comment != NULL)
- mCDE.mFileCommentLength = strlen(comment);
- mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does
-
- if (mCDE.mFileNameLength > 0) {
- mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
- strcpy((char*) mCDE.mFileName, fileName);
- }
- if (mCDE.mFileCommentLength > 0) {
- /* TODO: stop assuming null-terminated ASCII here? */
- mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
- strcpy((char*) mCDE.mFileComment, comment);
- }
-
- copyCDEtoLFH();
-}
-
-/*
- * Initialize a new entry, starting with the ZipEntry from a different
- * archive.
- *
- * Initializes the CDE and the LFH.
- */
-status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
- const ZipEntry* pEntry)
-{
- /*
- * Copy everything in the CDE over, then fix up the hairy bits.
- */
- memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
-
- if (mCDE.mFileNameLength > 0) {
- mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
- if (mCDE.mFileName == NULL)
- return NO_MEMORY;
- strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
- }
- if (mCDE.mFileCommentLength > 0) {
- mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
- if (mCDE.mFileComment == NULL)
- return NO_MEMORY;
- strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
- }
- if (mCDE.mExtraFieldLength > 0) {
- /* we null-terminate this, though it may not be a string */
- mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
- if (mCDE.mExtraField == NULL)
- return NO_MEMORY;
- memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
- mCDE.mExtraFieldLength+1);
- }
-
- /* construct the LFH from the CDE */
- copyCDEtoLFH();
-
- /*
- * The LFH "extra" field is independent of the CDE "extra", so we
- * handle it here.
- */
- assert(mLFH.mExtraField == NULL);
- mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
- if (mLFH.mExtraFieldLength > 0) {
- mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
- if (mLFH.mExtraField == NULL)
- return NO_MEMORY;
- memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
- mLFH.mExtraFieldLength+1);
- }
-
- return NO_ERROR;
-}
-
-/*
- * Insert pad bytes in the LFH by tweaking the "extra" field. This will
- * potentially confuse something that put "extra" data in here earlier,
- * but I can't find an actual problem.
- */
-status_t ZipEntry::addPadding(int padding)
-{
- if (padding <= 0)
- return INVALID_OPERATION;
-
- //LOGI("HEY: adding %d pad bytes to existing %d in %s\n",
- // padding, mLFH.mExtraFieldLength, mCDE.mFileName);
-
- if (mLFH.mExtraFieldLength > 0) {
- /* extend existing field */
- unsigned char* newExtra;
-
- newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
- if (newExtra == NULL)
- return NO_MEMORY;
- memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
- memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
-
- delete[] mLFH.mExtraField;
- mLFH.mExtraField = newExtra;
- mLFH.mExtraFieldLength += padding;
- } else {
- /* create new field */
- mLFH.mExtraField = new unsigned char[padding];
- memset(mLFH.mExtraField, 0, padding);
- mLFH.mExtraFieldLength = padding;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Set the fields in the LFH equal to the corresponding fields in the CDE.
- *
- * This does not touch the LFH "extra" field.
- */
-void ZipEntry::copyCDEtoLFH(void)
-{
- mLFH.mVersionToExtract = mCDE.mVersionToExtract;
- mLFH.mGPBitFlag = mCDE.mGPBitFlag;
- mLFH.mCompressionMethod = mCDE.mCompressionMethod;
- mLFH.mLastModFileTime = mCDE.mLastModFileTime;
- mLFH.mLastModFileDate = mCDE.mLastModFileDate;
- mLFH.mCRC32 = mCDE.mCRC32;
- mLFH.mCompressedSize = mCDE.mCompressedSize;
- mLFH.mUncompressedSize = mCDE.mUncompressedSize;
- mLFH.mFileNameLength = mCDE.mFileNameLength;
- // the "extra field" is independent
-
- delete[] mLFH.mFileName;
- if (mLFH.mFileNameLength > 0) {
- mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
- strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
- } else {
- mLFH.mFileName = NULL;
- }
-}
-
-/*
- * Set some information about a file after we add it.
- */
-void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
- int compressionMethod)
-{
- mCDE.mCompressionMethod = compressionMethod;
- mCDE.mCRC32 = crc32;
- mCDE.mCompressedSize = compLen;
- mCDE.mUncompressedSize = uncompLen;
- mCDE.mCompressionMethod = compressionMethod;
- if (compressionMethod == kCompressDeflated) {
- mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used
- }
- copyCDEtoLFH();
-}
-
-/*
- * See if the data in mCDE and mLFH match up. This is mostly useful for
- * debugging these classes, but it can be used to identify damaged
- * archives.
- *
- * Returns "false" if they differ.
- */
-bool ZipEntry::compareHeaders(void) const
-{
- if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
- LOGV("cmp: VersionToExtract\n");
- return false;
- }
- if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
- LOGV("cmp: GPBitFlag\n");
- return false;
- }
- if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
- LOGV("cmp: CompressionMethod\n");
- return false;
- }
- if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
- LOGV("cmp: LastModFileTime\n");
- return false;
- }
- if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
- LOGV("cmp: LastModFileDate\n");
- return false;
- }
- if (mCDE.mCRC32 != mLFH.mCRC32) {
- LOGV("cmp: CRC32\n");
- return false;
- }
- if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
- LOGV("cmp: CompressedSize\n");
- return false;
- }
- if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
- LOGV("cmp: UncompressedSize\n");
- return false;
- }
- if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
- LOGV("cmp: FileNameLength\n");
- return false;
- }
-#if 0 // this seems to be used for padding, not real data
- if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
- LOGV("cmp: ExtraFieldLength\n");
- return false;
- }
-#endif
- if (mCDE.mFileName != NULL) {
- if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
- LOGV("cmp: FileName\n");
- return false;
- }
- }
-
- return true;
-}
-
-
-/*
- * Convert the DOS date/time stamp into a UNIX time stamp.
- */
-time_t ZipEntry::getModWhen(void) const
-{
- struct tm parts;
-
- parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
- parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
- parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
- parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
- parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
- parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
- parts.tm_wday = parts.tm_yday = 0;
- parts.tm_isdst = -1; // DST info "not available"
-
- return mktime(&parts);
-}
-
-/*
- * Set the CDE/LFH timestamp from UNIX time.
- */
-void ZipEntry::setModWhen(time_t when)
-{
-#ifdef HAVE_LOCALTIME_R
- struct tm tmResult;
-#endif
- time_t even;
- unsigned short zdate, ztime;
-
- struct tm* ptm;
-
- /* round up to an even number of seconds */
- even = (time_t)(((unsigned long)(when) + 1) & (~1));
-
- /* expand */
-#ifdef HAVE_LOCALTIME_R
- ptm = localtime_r(&even, &tmResult);
-#else
- ptm = localtime(&even);
-#endif
-
- int year;
- year = ptm->tm_year;
- if (year < 80)
- year = 80;
-
- zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
- ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
-
- mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
- mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
-}
-
-
-/*
- * ===========================================================================
- * ZipEntry::LocalFileHeader
- * ===========================================================================
- */
-
-/*
- * Read a local file header.
- *
- * On entry, "fp" points to the signature at the start of the header.
- * On exit, "fp" points to the start of data.
- */
-status_t ZipEntry::LocalFileHeader::read(FILE* fp)
-{
- status_t result = NO_ERROR;
- unsigned char buf[kLFHLen];
-
- assert(mFileName == NULL);
- assert(mExtraField == NULL);
-
- if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
- LOGD("whoops: didn't find expected signature\n");
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
- mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
- mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
- mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
- mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
- mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
- mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
- mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
- mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
- mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
-
- // TODO: validate sizes
-
- /* grab filename */
- if (mFileNameLength != 0) {
- mFileName = new unsigned char[mFileNameLength+1];
- if (mFileName == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mFileName[mFileNameLength] = '\0';
- }
-
- /* grab extra field */
- if (mExtraFieldLength != 0) {
- mExtraField = new unsigned char[mExtraFieldLength+1];
- if (mExtraField == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mExtraField[mExtraFieldLength] = '\0';
- }
-
-bail:
- return result;
-}
-
-/*
- * Write a local file header.
- */
-status_t ZipEntry::LocalFileHeader::write(FILE* fp)
-{
- unsigned char buf[kLFHLen];
-
- ZipEntry::putLongLE(&buf[0x00], kSignature);
- ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
- ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
- ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
- ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
- ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
- ZipEntry::putLongLE(&buf[0x0e], mCRC32);
- ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
- ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
- ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
- ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
-
- if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
- return UNKNOWN_ERROR;
-
- /* write filename */
- if (mFileNameLength != 0) {
- if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
- return UNKNOWN_ERROR;
- }
-
- /* write "extra field" */
- if (mExtraFieldLength != 0) {
- if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-
-/*
- * Dump the contents of a LocalFileHeader object.
- */
-void ZipEntry::LocalFileHeader::dump(void) const
-{
- LOGD(" LocalFileHeader contents:\n");
- LOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
- mVersionToExtract, mGPBitFlag, mCompressionMethod);
- LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
- mLastModFileTime, mLastModFileDate, mCRC32);
- LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
- mCompressedSize, mUncompressedSize);
- LOGD(" filenameLen=%u extraLen=%u\n",
- mFileNameLength, mExtraFieldLength);
- if (mFileName != NULL)
- LOGD(" filename: '%s'\n", mFileName);
-}
-
-
-/*
- * ===========================================================================
- * ZipEntry::CentralDirEntry
- * ===========================================================================
- */
-
-/*
- * Read the central dir entry that appears next in the file.
- *
- * On entry, "fp" should be positioned on the signature bytes for the
- * entry. On exit, "fp" will point at the signature word for the next
- * entry or for the EOCD.
- */
-status_t ZipEntry::CentralDirEntry::read(FILE* fp)
-{
- status_t result = NO_ERROR;
- unsigned char buf[kCDELen];
-
- /* no re-use */
- assert(mFileName == NULL);
- assert(mExtraField == NULL);
- assert(mFileComment == NULL);
-
- if (fread(buf, 1, kCDELen, fp) != kCDELen) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
- LOGD("Whoops: didn't find expected signature\n");
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
- mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
- mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
- mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
- mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
- mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
- mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
- mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
- mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
- mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
- mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
- mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
- mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
- mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
- mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
- mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
-
- // TODO: validate sizes and offsets
-
- /* grab filename */
- if (mFileNameLength != 0) {
- mFileName = new unsigned char[mFileNameLength+1];
- if (mFileName == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mFileName[mFileNameLength] = '\0';
- }
-
- /* read "extra field" */
- if (mExtraFieldLength != 0) {
- mExtraField = new unsigned char[mExtraFieldLength+1];
- if (mExtraField == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mExtraField[mExtraFieldLength] = '\0';
- }
-
-
- /* grab comment, if any */
- if (mFileCommentLength != 0) {
- mFileComment = new unsigned char[mFileCommentLength+1];
- if (mFileComment == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
- if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
- {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- mFileComment[mFileCommentLength] = '\0';
- }
-
-bail:
- return result;
-}
-
-/*
- * Write a central dir entry.
- */
-status_t ZipEntry::CentralDirEntry::write(FILE* fp)
-{
- unsigned char buf[kCDELen];
-
- ZipEntry::putLongLE(&buf[0x00], kSignature);
- ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
- ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
- ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
- ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
- ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
- ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
- ZipEntry::putLongLE(&buf[0x10], mCRC32);
- ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
- ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
- ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
- ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
- ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
- ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
- ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
- ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
- ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
-
- if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
- return UNKNOWN_ERROR;
-
- /* write filename */
- if (mFileNameLength != 0) {
- if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
- return UNKNOWN_ERROR;
- }
-
- /* write "extra field" */
- if (mExtraFieldLength != 0) {
- if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
- return UNKNOWN_ERROR;
- }
-
- /* write comment */
- if (mFileCommentLength != 0) {
- if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Dump the contents of a CentralDirEntry object.
- */
-void ZipEntry::CentralDirEntry::dump(void) const
-{
- LOGD(" CentralDirEntry contents:\n");
- LOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
- mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
- LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
- mLastModFileTime, mLastModFileDate, mCRC32);
- LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
- mCompressedSize, mUncompressedSize);
- LOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
- mFileNameLength, mExtraFieldLength, mFileCommentLength);
- LOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
- mDiskNumberStart, mInternalAttrs, mExternalAttrs,
- mLocalHeaderRelOffset);
-
- if (mFileName != NULL)
- LOGD(" filename: '%s'\n", mFileName);
- if (mFileComment != NULL)
- LOGD(" comment: '%s'\n", mFileComment);
-}
-
diff --git a/libs/utils/ZipFile.cpp b/libs/utils/ZipFile.cpp
deleted file mode 100644
index 6f27d17..0000000
--- a/libs/utils/ZipFile.cpp
+++ /dev/null
@@ -1,1296 +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.
- */
-
-//
-// Access to Zip archives.
-//
-
-#define LOG_TAG "zip"
-
-#include <utils/ZipFile.h>
-#include <utils/ZipUtils.h>
-#include <utils/Log.h>
-
-#include <zlib.h>
-#define DEF_MEM_LEVEL 8 // normally in zutil.h?
-
-#include <memory.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <assert.h>
-
-using namespace android;
-
-/*
- * Some environments require the "b", some choke on it.
- */
-#define FILE_OPEN_RO "rb"
-#define FILE_OPEN_RW "r+b"
-#define FILE_OPEN_RW_CREATE "w+b"
-
-/* should live somewhere else? */
-static status_t errnoToStatus(int err)
-{
- if (err == ENOENT)
- return NAME_NOT_FOUND;
- else if (err == EACCES)
- return PERMISSION_DENIED;
- else
- return UNKNOWN_ERROR;
-}
-
-/*
- * Open a file and parse its guts.
- */
-status_t ZipFile::open(const char* zipFileName, int flags)
-{
- bool newArchive = false;
-
- assert(mZipFp == NULL); // no reopen
-
- if ((flags & kOpenTruncate))
- flags |= kOpenCreate; // trunc implies create
-
- if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
- return INVALID_OPERATION; // not both
- if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
- return INVALID_OPERATION; // not neither
- if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
- return INVALID_OPERATION; // create requires write
-
- if (flags & kOpenTruncate) {
- newArchive = true;
- } else {
- newArchive = (access(zipFileName, F_OK) != 0);
- if (!(flags & kOpenCreate) && newArchive) {
- /* not creating, must already exist */
- LOGD("File %s does not exist", zipFileName);
- return NAME_NOT_FOUND;
- }
- }
-
- /* open the file */
- const char* openflags;
- if (flags & kOpenReadWrite) {
- if (newArchive)
- openflags = FILE_OPEN_RW_CREATE;
- else
- openflags = FILE_OPEN_RW;
- } else {
- openflags = FILE_OPEN_RO;
- }
- mZipFp = fopen(zipFileName, openflags);
- if (mZipFp == NULL) {
- int err = errno;
- LOGD("fopen failed: %d\n", err);
- return errnoToStatus(err);
- }
-
- status_t result;
- if (!newArchive) {
- /*
- * Load the central directory. If that fails, then this probably
- * isn't a Zip archive.
- */
- result = readCentralDir();
- } else {
- /*
- * Newly-created. The EndOfCentralDir constructor actually
- * sets everything to be the way we want it (all zeroes). We
- * set mNeedCDRewrite so that we create *something* if the
- * caller doesn't add any files. (We could also just unlink
- * the file if it's brand new and nothing was added, but that's
- * probably doing more than we really should -- the user might
- * have a need for empty zip files.)
- */
- mNeedCDRewrite = true;
- result = NO_ERROR;
- }
-
- if (flags & kOpenReadOnly)
- mReadOnly = true;
- else
- assert(!mReadOnly);
-
- return result;
-}
-
-/*
- * Return the Nth entry in the archive.
- */
-ZipEntry* ZipFile::getEntryByIndex(int idx) const
-{
- if (idx < 0 || idx >= (int) mEntries.size())
- return NULL;
-
- return mEntries[idx];
-}
-
-/*
- * Find an entry by name.
- */
-ZipEntry* ZipFile::getEntryByName(const char* fileName) const
-{
- /*
- * Do a stupid linear string-compare search.
- *
- * There are various ways to speed this up, especially since it's rare
- * to intermingle changes to the archive with "get by name" calls. We
- * don't want to sort the mEntries vector itself, however, because
- * it's used to recreate the Central Directory.
- *
- * (Hash table works, parallel list of pointers in sorted order is good.)
- */
- int idx;
-
- for (idx = mEntries.size()-1; idx >= 0; idx--) {
- ZipEntry* pEntry = mEntries[idx];
- if (!pEntry->getDeleted() &&
- strcmp(fileName, pEntry->getFileName()) == 0)
- {
- return pEntry;
- }
- }
-
- return NULL;
-}
-
-/*
- * Empty the mEntries vector.
- */
-void ZipFile::discardEntries(void)
-{
- int count = mEntries.size();
-
- while (--count >= 0)
- delete mEntries[count];
-
- mEntries.clear();
-}
-
-
-/*
- * Find the central directory and read the contents.
- *
- * The fun thing about ZIP archives is that they may or may not be
- * readable from start to end. In some cases, notably for archives
- * that were written to stdout, the only length information is in the
- * central directory at the end of the file.
- *
- * Of course, the central directory can be followed by a variable-length
- * comment field, so we have to scan through it backwards. The comment
- * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
- * itself, plus apparently sometimes people throw random junk on the end
- * just for the fun of it.
- *
- * This is all a little wobbly. If the wrong value ends up in the EOCD
- * area, we're hosed. This appears to be the way that everbody handles
- * it though, so we're in pretty good company if this fails.
- */
-status_t ZipFile::readCentralDir(void)
-{
- status_t result = NO_ERROR;
- unsigned char* buf = NULL;
- off_t fileLength, seekStart;
- long readAmount;
- int i;
-
- fseek(mZipFp, 0, SEEK_END);
- fileLength = ftell(mZipFp);
- rewind(mZipFp);
-
- /* too small to be a ZIP archive? */
- if (fileLength < EndOfCentralDir::kEOCDLen) {
- LOGD("Length is %ld -- too small\n", (long)fileLength);
- result = INVALID_OPERATION;
- goto bail;
- }
-
- buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
- if (buf == NULL) {
- LOGD("Failure allocating %d bytes for EOCD search",
- EndOfCentralDir::kMaxEOCDSearch);
- result = NO_MEMORY;
- goto bail;
- }
-
- if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
- seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
- readAmount = EndOfCentralDir::kMaxEOCDSearch;
- } else {
- seekStart = 0;
- readAmount = (long) fileLength;
- }
- if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
- LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /* read the last part of the file into the buffer */
- if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
- LOGD("short file? wanted %ld\n", readAmount);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /* find the end-of-central-dir magic */
- for (i = readAmount - 4; i >= 0; i--) {
- if (buf[i] == 0x50 &&
- ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
- {
- LOGV("+++ Found EOCD at buf+%d\n", i);
- break;
- }
- }
- if (i < 0) {
- LOGD("EOCD not found, not Zip\n");
- result = INVALID_OPERATION;
- goto bail;
- }
-
- /* extract eocd values */
- result = mEOCD.readBuf(buf + i, readAmount - i);
- if (result != NO_ERROR) {
- LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
- goto bail;
- }
- //mEOCD.dump();
-
- if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
- mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
- {
- LOGD("Archive spanning not supported\n");
- result = INVALID_OPERATION;
- goto bail;
- }
-
- /*
- * So far so good. "mCentralDirSize" is the size in bytes of the
- * central directory, so we can just seek back that far to find it.
- * We can also seek forward mCentralDirOffset bytes from the
- * start of the file.
- *
- * We're not guaranteed to have the rest of the central dir in the
- * buffer, nor are we guaranteed that the central dir will have any
- * sort of convenient size. We need to skip to the start of it and
- * read the header, then the other goodies.
- *
- * The only thing we really need right now is the file comment, which
- * we're hoping to preserve.
- */
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
- LOGD("Failure seeking to central dir offset %ld\n",
- mEOCD.mCentralDirOffset);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /*
- * Loop through and read the central dir entries.
- */
- LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
- int entry;
- for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
- ZipEntry* pEntry = new ZipEntry;
-
- result = pEntry->initFromCDE(mZipFp);
- if (result != NO_ERROR) {
- LOGD("initFromCDE failed\n");
- delete pEntry;
- goto bail;
- }
-
- mEntries.add(pEntry);
- }
-
-
- /*
- * If all went well, we should now be back at the EOCD.
- */
- {
- unsigned char checkBuf[4];
- if (fread(checkBuf, 1, 4, mZipFp) != 4) {
- LOGD("EOCD check read failed\n");
- result = INVALID_OPERATION;
- goto bail;
- }
- if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
- LOGD("EOCD read check failed\n");
- result = UNKNOWN_ERROR;
- goto bail;
- }
- LOGV("+++ EOCD read check passed\n");
- }
-
-bail:
- delete[] buf;
- return result;
-}
-
-
-/*
- * Add a new file to the archive.
- *
- * This requires creating and populating a ZipEntry structure, and copying
- * the data into the file at the appropriate position. The "appropriate
- * position" is the current location of the central directory, which we
- * casually overwrite (we can put it back later).
- *
- * If we were concerned about safety, we would want to make all changes
- * in a temp file and then overwrite the original after everything was
- * safely written. Not really a concern for us.
- */
-status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
- const char* storageName, int sourceType, int compressionMethod,
- ZipEntry** ppEntry)
-{
- ZipEntry* pEntry = NULL;
- status_t result = NO_ERROR;
- long lfhPosn, startPosn, endPosn, uncompressedLen;
- FILE* inputFp = NULL;
- unsigned long crc;
- time_t modWhen;
-
- if (mReadOnly)
- return INVALID_OPERATION;
-
- assert(compressionMethod == ZipEntry::kCompressDeflated ||
- compressionMethod == ZipEntry::kCompressStored);
-
- /* make sure we're in a reasonable state */
- assert(mZipFp != NULL);
- assert(mEntries.size() == mEOCD.mTotalNumEntries);
-
- /* make sure it doesn't already exist */
- if (getEntryByName(storageName) != NULL)
- return ALREADY_EXISTS;
-
- if (!data) {
- inputFp = fopen(fileName, FILE_OPEN_RO);
- if (inputFp == NULL)
- return errnoToStatus(errno);
- }
-
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- pEntry = new ZipEntry;
- pEntry->initNew(storageName, NULL);
-
- /*
- * From here on out, failures are more interesting.
- */
- mNeedCDRewrite = true;
-
- /*
- * Write the LFH, even though it's still mostly blank. We need it
- * as a place-holder. In theory the LFH isn't necessary, but in
- * practice some utilities demand it.
- */
- lfhPosn = ftell(mZipFp);
- pEntry->mLFH.write(mZipFp);
- startPosn = ftell(mZipFp);
-
- /*
- * Copy the data in, possibly compressing it as we go.
- */
- if (sourceType == ZipEntry::kCompressStored) {
- if (compressionMethod == ZipEntry::kCompressDeflated) {
- bool failed = false;
- result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
- if (result != NO_ERROR) {
- LOGD("compression failed, storing\n");
- failed = true;
- } else {
- /*
- * Make sure it has compressed "enough". This probably ought
- * to be set through an API call, but I don't expect our
- * criteria to change over time.
- */
- long src = inputFp ? ftell(inputFp) : size;
- long dst = ftell(mZipFp) - startPosn;
- if (dst + (dst / 10) > src) {
- LOGD("insufficient compression (src=%ld dst=%ld), storing\n",
- src, dst);
- failed = true;
- }
- }
-
- if (failed) {
- compressionMethod = ZipEntry::kCompressStored;
- if (inputFp) rewind(inputFp);
- fseek(mZipFp, startPosn, SEEK_SET);
- /* fall through to kCompressStored case */
- }
- }
- /* handle "no compression" request, or failed compression from above */
- if (compressionMethod == ZipEntry::kCompressStored) {
- if (inputFp) {
- result = copyFpToFp(mZipFp, inputFp, &crc);
- } else {
- result = copyDataToFp(mZipFp, data, size, &crc);
- }
- if (result != NO_ERROR) {
- // don't need to truncate; happens in CDE rewrite
- LOGD("failed copying data in\n");
- goto bail;
- }
- }
-
- // currently seeked to end of file
- uncompressedLen = inputFp ? ftell(inputFp) : size;
- } else if (sourceType == ZipEntry::kCompressDeflated) {
- /* we should support uncompressed-from-compressed, but it's not
- * important right now */
- assert(compressionMethod == ZipEntry::kCompressDeflated);
-
- bool scanResult;
- int method;
- long compressedLen;
-
- scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
- &compressedLen, &crc);
- if (!scanResult || method != ZipEntry::kCompressDeflated) {
- LOGD("this isn't a deflated gzip file?");
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
- if (result != NO_ERROR) {
- LOGD("failed copying gzip data in\n");
- goto bail;
- }
- } else {
- assert(false);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /*
- * We could write the "Data Descriptor", but there doesn't seem to
- * be any point since we're going to go back and write the LFH.
- *
- * Update file offsets.
- */
- endPosn = ftell(mZipFp); // seeked to end of compressed data
-
- /*
- * Success! Fill out new values.
- */
- pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
- compressionMethod);
- modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
- pEntry->setModWhen(modWhen);
- pEntry->setLFHOffset(lfhPosn);
- mEOCD.mNumEntries++;
- mEOCD.mTotalNumEntries++;
- mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
- mEOCD.mCentralDirOffset = endPosn;
-
- /*
- * Go back and write the LFH.
- */
- if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
- pEntry->mLFH.write(mZipFp);
-
- /*
- * Add pEntry to the list.
- */
- mEntries.add(pEntry);
- if (ppEntry != NULL)
- *ppEntry = pEntry;
- pEntry = NULL;
-
-bail:
- if (inputFp != NULL)
- fclose(inputFp);
- delete pEntry;
- return result;
-}
-
-/*
- * Add an entry by copying it from another zip file. If "padding" is
- * nonzero, the specified number of bytes will be added to the "extra"
- * field in the header.
- *
- * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
- */
-status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
- int padding, ZipEntry** ppEntry)
-{
- ZipEntry* pEntry = NULL;
- status_t result;
- long lfhPosn, endPosn;
-
- if (mReadOnly)
- return INVALID_OPERATION;
-
- /* make sure we're in a reasonable state */
- assert(mZipFp != NULL);
- assert(mEntries.size() == mEOCD.mTotalNumEntries);
-
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- pEntry = new ZipEntry;
- if (pEntry == NULL) {
- result = NO_MEMORY;
- goto bail;
- }
-
- result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
- if (result != NO_ERROR)
- goto bail;
- if (padding != 0) {
- result = pEntry->addPadding(padding);
- if (result != NO_ERROR)
- goto bail;
- }
-
- /*
- * From here on out, failures are more interesting.
- */
- mNeedCDRewrite = true;
-
- /*
- * Write the LFH. Since we're not recompressing the data, we already
- * have all of the fields filled out.
- */
- lfhPosn = ftell(mZipFp);
- pEntry->mLFH.write(mZipFp);
-
- /*
- * Copy the data over.
- *
- * If the "has data descriptor" flag is set, we want to copy the DD
- * fields as well. This is a fixed-size area immediately following
- * the data.
- */
- if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
- {
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- off_t copyLen;
- copyLen = pSourceEntry->getCompressedLen();
- if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
- copyLen += ZipEntry::kDataDescriptorLen;
-
- if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
- != NO_ERROR)
- {
- LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
- result = UNKNOWN_ERROR;
- goto bail;
- }
-
- /*
- * Update file offsets.
- */
- endPosn = ftell(mZipFp);
-
- /*
- * Success! Fill out new values.
- */
- pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset
- mEOCD.mNumEntries++;
- mEOCD.mTotalNumEntries++;
- mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
- mEOCD.mCentralDirOffset = endPosn;
-
- /*
- * Add pEntry to the list.
- */
- mEntries.add(pEntry);
- if (ppEntry != NULL)
- *ppEntry = pEntry;
- pEntry = NULL;
-
- result = NO_ERROR;
-
-bail:
- delete pEntry;
- return result;
-}
-
-/*
- * Copy all of the bytes in "src" to "dst".
- *
- * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
- * will be seeked immediately past the data.
- */
-status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
-{
- unsigned char tmpBuf[32768];
- size_t count;
-
- *pCRC32 = crc32(0L, Z_NULL, 0);
-
- while (1) {
- count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
- if (ferror(srcFp) || ferror(dstFp))
- return errnoToStatus(errno);
- if (count == 0)
- break;
-
- *pCRC32 = crc32(*pCRC32, tmpBuf, count);
-
- if (fwrite(tmpBuf, 1, count, dstFp) != count) {
- LOGD("fwrite %d bytes failed\n", (int) count);
- return UNKNOWN_ERROR;
- }
- }
-
- return NO_ERROR;
-}
-
-/*
- * Copy all of the bytes in "src" to "dst".
- *
- * On exit, "dstFp" will be seeked immediately past the data.
- */
-status_t ZipFile::copyDataToFp(FILE* dstFp,
- const void* data, size_t size, unsigned long* pCRC32)
-{
- size_t count;
-
- *pCRC32 = crc32(0L, Z_NULL, 0);
- if (size > 0) {
- *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
- if (fwrite(data, 1, size, dstFp) != size) {
- LOGD("fwrite %d bytes failed\n", (int) size);
- return UNKNOWN_ERROR;
- }
- }
-
- return NO_ERROR;
-}
-
-/*
- * Copy some of the bytes in "src" to "dst".
- *
- * If "pCRC32" is NULL, the CRC will not be computed.
- *
- * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
- * will be seeked immediately past the data just written.
- */
-status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
- unsigned long* pCRC32)
-{
- unsigned char tmpBuf[32768];
- size_t count;
-
- if (pCRC32 != NULL)
- *pCRC32 = crc32(0L, Z_NULL, 0);
-
- while (length) {
- long readSize;
-
- readSize = sizeof(tmpBuf);
- if (readSize > length)
- readSize = length;
-
- count = fread(tmpBuf, 1, readSize, srcFp);
- if ((long) count != readSize) { // error or unexpected EOF
- LOGD("fread %d bytes failed\n", (int) readSize);
- return UNKNOWN_ERROR;
- }
-
- if (pCRC32 != NULL)
- *pCRC32 = crc32(*pCRC32, tmpBuf, count);
-
- if (fwrite(tmpBuf, 1, count, dstFp) != count) {
- LOGD("fwrite %d bytes failed\n", (int) count);
- return UNKNOWN_ERROR;
- }
-
- length -= readSize;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Compress all of the data in "srcFp" and write it to "dstFp".
- *
- * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
- * will be seeked immediately past the compressed data.
- */
-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;
- 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) {
- LOGV("+++ reading %d bytes\n", (int)kBufSize);
- if (data) {
- getSize = size > kBufSize ? kBufSize : size;
- memcpy(inBuf, data, getSize);
- data = ((const char*)data) + getSize;
- size -= getSize;
- } else {
- getSize = fread(inBuf, 1, kBufSize, srcFp);
- if (ferror(srcFp)) {
- LOGD("deflate read failed (errno=%d)\n", errno);
- goto z_bail;
- }
- }
- if (getSize < kBufSize) {
- LOGV("+++ got %d bytes, EOF reached\n",
- (int)getSize);
- 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));
- if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
- (size_t)(zstream.next_out - outBuf))
- {
- LOGD("write %d failed in deflate\n",
- (int) (zstream.next_out - outBuf));
- goto z_bail;
- }
-
- zstream.next_out = outBuf;
- zstream.avail_out = kBufSize;
- }
- } while (zerr == Z_OK);
-
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
-
- *pCRC32 = crc;
-
-z_bail:
- deflateEnd(&zstream); /* free up any allocated structures */
-
-bail:
- delete[] inBuf;
- delete[] outBuf;
-
- return result;
-}
-
-/*
- * Mark an entry as deleted.
- *
- * We will eventually need to crunch the file down, but if several files
- * are being removed (perhaps as part of an "update" process) we can make
- * things considerably faster by deferring the removal to "flush" time.
- */
-status_t ZipFile::remove(ZipEntry* pEntry)
-{
- /*
- * Should verify that pEntry is actually part of this archive, and
- * not some stray ZipEntry from a different file.
- */
-
- /* mark entry as deleted, and mark archive as dirty */
- pEntry->setDeleted();
- mNeedCDRewrite = true;
- return NO_ERROR;
-}
-
-/*
- * Flush any pending writes.
- *
- * In particular, this will crunch out deleted entries, and write the
- * Central Directory and EOCD if we have stomped on them.
- */
-status_t ZipFile::flush(void)
-{
- status_t result = NO_ERROR;
- long eocdPosn;
- int i, count;
-
- if (mReadOnly)
- return INVALID_OPERATION;
- if (!mNeedCDRewrite)
- return NO_ERROR;
-
- assert(mZipFp != NULL);
-
- result = crunchArchive();
- if (result != NO_ERROR)
- return result;
-
- if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
- return UNKNOWN_ERROR;
-
- count = mEntries.size();
- for (i = 0; i < count; i++) {
- ZipEntry* pEntry = mEntries[i];
- pEntry->mCDE.write(mZipFp);
- }
-
- eocdPosn = ftell(mZipFp);
- mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
-
- mEOCD.write(mZipFp);
-
- /*
- * If we had some stuff bloat up during compression and get replaced
- * with plain files, or if we deleted some entries, there's a lot
- * of wasted space at the end of the file. Remove it now.
- */
- if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
- LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
- // not fatal
- }
-
- /* should we clear the "newly added" flag in all entries now? */
-
- mNeedCDRewrite = false;
- return NO_ERROR;
-}
-
-/*
- * Crunch deleted files out of an archive by shifting the later files down.
- *
- * Because we're not using a temp file, we do the operation inside the
- * current file.
- */
-status_t ZipFile::crunchArchive(void)
-{
- status_t result = NO_ERROR;
- int i, count;
- long delCount, adjust;
-
-#if 0
- printf("CONTENTS:\n");
- for (i = 0; i < (int) mEntries.size(); i++) {
- printf(" %d: lfhOff=%ld del=%d\n",
- i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
- }
- printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset);
-#endif
-
- /*
- * Roll through the set of files, shifting them as appropriate. We
- * could probably get a slight performance improvement by sliding
- * multiple files down at once (because we could use larger reads
- * when operating on batches of small files), but it's not that useful.
- */
- count = mEntries.size();
- delCount = adjust = 0;
- for (i = 0; i < count; i++) {
- ZipEntry* pEntry = mEntries[i];
- long span;
-
- if (pEntry->getLFHOffset() != 0) {
- long nextOffset;
-
- /* Get the length of this entry by finding the offset
- * of the next entry. Directory entries don't have
- * file offsets, so we need to find the next non-directory
- * entry.
- */
- nextOffset = 0;
- for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
- nextOffset = mEntries[ii]->getLFHOffset();
- if (nextOffset == 0)
- nextOffset = mEOCD.mCentralDirOffset;
- span = nextOffset - pEntry->getLFHOffset();
-
- assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
- } else {
- /* This is a directory entry. It doesn't have
- * any actual file contents, so there's no need to
- * move anything.
- */
- span = 0;
- }
-
- //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
- // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
-
- if (pEntry->getDeleted()) {
- adjust += span;
- delCount++;
-
- delete pEntry;
- mEntries.removeAt(i);
-
- /* adjust loop control */
- count--;
- i--;
- } else if (span != 0 && adjust > 0) {
- /* shuffle this entry back */
- //printf("+++ Shuffling '%s' back %ld\n",
- // pEntry->getFileName(), adjust);
- result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
- pEntry->getLFHOffset(), span);
- if (result != NO_ERROR) {
- /* this is why you use a temp file */
- LOGE("error during crunch - archive is toast\n");
- return result;
- }
-
- pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
- }
- }
-
- /*
- * Fix EOCD info. We have to wait until the end to do some of this
- * because we use mCentralDirOffset to determine "span" for the
- * last entry.
- */
- mEOCD.mCentralDirOffset -= adjust;
- mEOCD.mNumEntries -= delCount;
- mEOCD.mTotalNumEntries -= delCount;
- mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
-
- assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
- assert(mEOCD.mNumEntries == count);
-
- return result;
-}
-
-/*
- * Works like memmove(), but on pieces of a file.
- */
-status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
-{
- if (dst == src || n <= 0)
- return NO_ERROR;
-
- unsigned char readBuf[32768];
-
- if (dst < src) {
- /* shift stuff toward start of file; must read from start */
- while (n != 0) {
- size_t getSize = sizeof(readBuf);
- if (getSize > n)
- getSize = n;
-
- if (fseek(fp, (long) src, SEEK_SET) != 0) {
- LOGD("filemove src seek %ld failed\n", (long) src);
- return UNKNOWN_ERROR;
- }
-
- if (fread(readBuf, 1, getSize, fp) != getSize) {
- LOGD("filemove read %ld off=%ld failed\n",
- (long) getSize, (long) src);
- return UNKNOWN_ERROR;
- }
-
- if (fseek(fp, (long) dst, SEEK_SET) != 0) {
- LOGD("filemove dst seek %ld failed\n", (long) dst);
- return UNKNOWN_ERROR;
- }
-
- if (fwrite(readBuf, 1, getSize, fp) != getSize) {
- LOGD("filemove write %ld off=%ld failed\n",
- (long) getSize, (long) dst);
- return UNKNOWN_ERROR;
- }
-
- src += getSize;
- dst += getSize;
- n -= getSize;
- }
- } else {
- /* shift stuff toward end of file; must read from end */
- assert(false); // write this someday, maybe
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-
-/*
- * Get the modification time from a file descriptor.
- */
-time_t ZipFile::getModTime(int fd)
-{
- struct stat sb;
-
- if (fstat(fd, &sb) < 0) {
- LOGD("HEY: fstat on fd %d failed\n", fd);
- return (time_t) -1;
- }
-
- return sb.st_mtime;
-}
-
-
-#if 0 /* this is a bad idea */
-/*
- * Get a copy of the Zip file descriptor.
- *
- * We don't allow this if the file was opened read-write because we tend
- * to leave the file contents in an uncertain state between calls to
- * flush(). The duplicated file descriptor should only be valid for reads.
- */
-int ZipFile::getZipFd(void) const
-{
- if (!mReadOnly)
- return INVALID_OPERATION;
- assert(mZipFp != NULL);
-
- int fd;
- fd = dup(fileno(mZipFp));
- if (fd < 0) {
- LOGD("didn't work, errno=%d\n", errno);
- }
-
- return fd;
-}
-#endif
-
-
-#if 0
-/*
- * Expand data.
- */
-bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
-{
- return false;
-}
-#endif
-
-// free the memory when you're done
-void* ZipFile::uncompress(const ZipEntry* entry)
-{
- size_t unlen = entry->getUncompressedLen();
- size_t clen = entry->getCompressedLen();
-
- void* buf = malloc(unlen);
- if (buf == NULL) {
- return NULL;
- }
-
- fseek(mZipFp, 0, SEEK_SET);
-
- off_t offset = entry->getFileOffset();
- if (fseek(mZipFp, offset, SEEK_SET) != 0) {
- goto bail;
- }
-
- switch (entry->getCompressionMethod())
- {
- case ZipEntry::kCompressStored: {
- ssize_t amt = fread(buf, 1, unlen, mZipFp);
- if (amt != (ssize_t)unlen) {
- goto bail;
- }
-#if 0
- printf("data...\n");
- const unsigned char* p = (unsigned char*)buf;
- const unsigned char* end = p+unlen;
- for (int i=0; i<32 && p < end; i++) {
- printf("0x%08x ", (int)(offset+(i*0x10)));
- for (int j=0; j<0x10 && p < end; j++) {
- printf(" %02x", *p);
- p++;
- }
- printf("\n");
- }
-#endif
-
- }
- break;
- case ZipEntry::kCompressDeflated: {
- if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
- goto bail;
- }
- }
- break;
- default:
- goto bail;
- }
- return buf;
-
-bail:
- free(buf);
- return NULL;
-}
-
-
-/*
- * ===========================================================================
- * ZipFile::EndOfCentralDir
- * ===========================================================================
- */
-
-/*
- * Read the end-of-central-dir fields.
- *
- * "buf" should be positioned at the EOCD signature, and should contain
- * the entire EOCD area including the comment.
- */
-status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
-{
- /* don't allow re-use */
- assert(mComment == NULL);
-
- if (len < kEOCDLen) {
- /* looks like ZIP file got truncated */
- LOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
- kEOCDLen, len);
- return INVALID_OPERATION;
- }
-
- /* this should probably be an assert() */
- if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
- return UNKNOWN_ERROR;
-
- mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
- mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
- mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
- mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
- mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
- mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
- mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
-
- // TODO: validate mCentralDirOffset
-
- if (mCommentLen > 0) {
- if (kEOCDLen + mCommentLen > len) {
- LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
- kEOCDLen, mCommentLen, len);
- return UNKNOWN_ERROR;
- }
- mComment = new unsigned char[mCommentLen];
- memcpy(mComment, buf + kEOCDLen, mCommentLen);
- }
-
- return NO_ERROR;
-}
-
-/*
- * Write an end-of-central-directory section.
- */
-status_t ZipFile::EndOfCentralDir::write(FILE* fp)
-{
- unsigned char buf[kEOCDLen];
-
- ZipEntry::putLongLE(&buf[0x00], kSignature);
- ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
- ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
- ZipEntry::putShortLE(&buf[0x08], mNumEntries);
- ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
- ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
- ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
- ZipEntry::putShortLE(&buf[0x14], mCommentLen);
-
- if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
- return UNKNOWN_ERROR;
- if (mCommentLen > 0) {
- assert(mComment != NULL);
- if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
- return UNKNOWN_ERROR;
- }
-
- return NO_ERROR;
-}
-
-/*
- * Dump the contents of an EndOfCentralDir object.
- */
-void ZipFile::EndOfCentralDir::dump(void) const
-{
- LOGD(" EndOfCentralDir contents:\n");
- LOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
- mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
- LOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n",
- mCentralDirSize, mCentralDirOffset, mCommentLen);
-}
-
diff --git a/libs/utils/executablepath_darwin.cpp b/libs/utils/executablepath_darwin.cpp
deleted file mode 100644
index 2e3c3a0..0000000
--- a/libs/utils/executablepath_darwin.cpp
+++ /dev/null
@@ -1,31 +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/executablepath.h>
-#import <Carbon/Carbon.h>
-#include <unistd.h>
-
-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);
-}
-
diff --git a/libs/utils/executablepath_linux.cpp b/libs/utils/executablepath_linux.cpp
deleted file mode 100644
index b8d2a3d..0000000
--- a/libs/utils/executablepath_linux.cpp
+++ /dev/null
@@ -1,30 +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/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);
-}
-
diff --git a/libs/utils/futex_synchro.c b/libs/utils/futex_synchro.c
deleted file mode 100644
index ab48c69..0000000
--- a/libs/utils/futex_synchro.c
+++ /dev/null
@@ -1,176 +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 <stdio.h>
-#include <limits.h>
-
-#include <sys/time.h>
-#include <sched.h>
-
-#include <errno.h>
-
-#include <private/utils/futex_synchro.h>
-
-
-// This futex glue code is need on desktop linux, but is already part of bionic.
-#if !defined(HAVE_FUTEX_WRAPPERS)
-
-#include <unistd.h>
-#include <sys/syscall.h>
-typedef unsigned int u32;
-#define asmlinkage
-#define __user
-#include <linux/futex.h>
-#include <utils/Atomic.h>
-
-
-int futex (int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3)
-{
- int err = syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
- return err == 0 ? 0 : -errno;
-}
-
-int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout)
-{
- return futex((int*)ftx, FUTEX_WAIT, val, timeout, NULL, 0);
-}
-
-int __futex_wake(volatile void *ftx, int count)
-{
- return futex((int*)ftx, FUTEX_WAKE, count, NULL, NULL, 0);
-}
-
-int __atomic_cmpxchg(int old, int _new, volatile int *ptr)
-{
- return android_atomic_cmpxchg(old, _new, ptr);
-}
-
-int __atomic_swap(int _new, volatile int *ptr)
-{
- return android_atomic_swap(_new, ptr);
-}
-
-int __atomic_dec(volatile int *ptr)
-{
- return android_atomic_dec(ptr);
-}
-
-#else // !defined(__arm__)
-
-int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout);
-int __futex_wake(volatile void *ftx, int count);
-
-int __atomic_cmpxchg(int old, int _new, volatile int *ptr);
-int __atomic_swap(int _new, volatile int *ptr);
-int __atomic_dec(volatile int *ptr);
-
-#endif // !defined(HAVE_FUTEX_WRAPPERS)
-
-
-// lock states
-//
-// 0: unlocked
-// 1: locked, no waiters
-// 2: locked, maybe waiters
-
-void futex_mutex_init(futex_mutex_t *m)
-{
- m->value = 0;
-}
-
-int futex_mutex_lock(futex_mutex_t *m, unsigned msec)
-{
- if(__atomic_cmpxchg(0, 1, &m->value) == 0) {
- return 0;
- }
- if(msec == FUTEX_WAIT_INFINITE) {
- while(__atomic_swap(2, &m->value) != 0) {
- __futex_wait(&m->value, 2, 0);
- }
- } else {
- struct timespec ts;
- ts.tv_sec = msec / 1000;
- ts.tv_nsec = (msec % 1000) * 1000000;
- while(__atomic_swap(2, &m->value) != 0) {
- if(__futex_wait(&m->value, 2, &ts) == -ETIMEDOUT) {
- return -1;
- }
- }
- }
- return 0;
-}
-
-int futex_mutex_trylock(futex_mutex_t *m)
-{
- if(__atomic_cmpxchg(0, 1, &m->value) == 0) {
- return 0;
- }
- return -1;
-}
-
-void futex_mutex_unlock(futex_mutex_t *m)
-{
- if(__atomic_dec(&m->value) != 1) {
- m->value = 0;
- __futex_wake(&m->value, 1);
- }
-}
-
-/* XXX *technically* there is a race condition that could allow
- * XXX a signal to be missed. If thread A is preempted in _wait()
- * XXX after unlocking the mutex and before waiting, and if other
- * XXX threads call signal or broadcast UINT_MAX times (exactly),
- * XXX before thread A is scheduled again and calls futex_wait(),
- * XXX then the signal will be lost.
- */
-
-void futex_cond_init(futex_cond_t *c)
-{
- c->value = 0;
-}
-
-int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec)
-{
- if(msec == FUTEX_WAIT_INFINITE){
- int oldvalue = c->value;
- futex_mutex_unlock(m);
- __futex_wait(&c->value, oldvalue, 0);
- futex_mutex_lock(m, FUTEX_WAIT_INFINITE);
- return 0;
- } else {
- int oldvalue = c->value;
- struct timespec ts;
- ts.tv_sec = msec / 1000;
- ts.tv_nsec = (msec % 1000) * 1000000;
- futex_mutex_unlock(m);
- const int err = __futex_wait(&c->value, oldvalue, &ts);
- futex_mutex_lock(m, FUTEX_WAIT_INFINITE);
- return err;
- }
-}
-
-void futex_cond_signal(futex_cond_t *c)
-{
- __atomic_dec(&c->value);
- __futex_wake(&c->value, 1);
-}
-
-void futex_cond_broadcast(futex_cond_t *c)
-{
- __atomic_dec(&c->value);
- __futex_wake(&c->value, INT_MAX);
-}
-
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/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 2cda7fa..ce69ac1 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -115,6 +115,18 @@ public final class GpsStatus {
void onGpsStatusChanged(int event);
}
+ /**
+ * Used for receiving NMEA sentences from the GPS.
+ * NMEA 0183 is a standard for communicating with marine electronic devices
+ * and is a common method for receiving data from a GPS, typically over a serial port.
+ * See <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA 0183</a> for more details.
+ * You can implement this interface and call {@link LocationManager#addNmeaListener}
+ * to receive NMEA data from the GPS engine.
+ */
+ public interface NmeaListener {
+ void onNmeaReceived(long timestamp, String nmea);
+ }
+
GpsStatus() {
for (int i = 0; i < mSatellites.length; i++) {
mSatellites[i] = new GpsSatellite(i + 1);
diff --git a/location/java/android/location/IGpsStatusListener.aidl b/location/java/android/location/IGpsStatusListener.aidl
index 5dc0fe8..62b1c6b 100644
--- a/location/java/android/location/IGpsStatusListener.aidl
+++ b/location/java/android/location/IGpsStatusListener.aidl
@@ -29,4 +29,5 @@ oneway interface IGpsStatusListener
void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs,
in float[] elevations, in float[] azimuths,
int ephemerisMask, int almanacMask, int usedInFixMask);
+ void onNmeaReceived(long timestamp, String nmea);
}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index caf9516..b6c59d6 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -83,4 +83,7 @@ interface ILocationManager
/* for installing external Location Providers */
void installLocationProvider(String name, ILocationProvider provider);
void installGeocodeProvider(IGeocodeProvider provider);
+
+ // for NI support
+ boolean sendNiResponse(int notifId, int userResponse);
}
diff --git a/location/java/android/location/INetInitiatedListener.aidl b/location/java/android/location/INetInitiatedListener.aidl
new file mode 100755
index 0000000..f2f5a32
--- /dev/null
+++ b/location/java/android/location/INetInitiatedListener.aidl
@@ -0,0 +1,26 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.location;
+
+/**
+ * {@hide}
+ */
+interface INetInitiatedListener
+{
+ boolean sendNiResponse(int notifId, int userResponse);
+}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 86ea66f..8326361 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -51,6 +51,8 @@ public class LocationManager {
private ILocationManager mService;
private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
+ private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
+ new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>();
private final GpsStatus mGpsStatus = new GpsStatus();
/**
@@ -68,7 +70,7 @@ public class LocationManager {
* satellites. Depending on conditions, this provider may take a while to return
* a location fix.
*
- * Requires the permission android.permissions.ACCESS_FINE_LOCATION.
+ * Requires the permission android.permission.ACCESS_FINE_LOCATION.
*
* <p> The extras Bundle for the GPS location provider can contain the
* following key/value pairs:
@@ -1123,49 +1125,103 @@ public class LocationManager {
private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
private final GpsStatus.Listener mListener;
+ private final GpsStatus.NmeaListener mNmeaListener;
+
+ // This must not equal any of the GpsStatus event IDs
+ private static final int NMEA_RECEIVED = 1000;
+
+ private class Nmea {
+ long mTimestamp;
+ String mNmea;
+
+ Nmea(long timestamp, String nmea) {
+ mTimestamp = timestamp;
+ mNmea = nmea;
+ }
+ }
+ private ArrayList<Nmea> mNmeaBuffer;
GpsStatusListenerTransport(GpsStatus.Listener listener) {
mListener = listener;
+ mNmeaListener = null;
+ }
+
+ GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
+ mNmeaListener = listener;
+ mListener = null;
+ mNmeaBuffer = new ArrayList<Nmea>();
}
public void onGpsStarted() {
- Message msg = Message.obtain();
- msg.what = GpsStatus.GPS_EVENT_STARTED;
- mGpsHandler.sendMessage(msg);
+ if (mListener != null) {
+ Message msg = Message.obtain();
+ msg.what = GpsStatus.GPS_EVENT_STARTED;
+ mGpsHandler.sendMessage(msg);
+ }
}
public void onGpsStopped() {
- Message msg = Message.obtain();
- msg.what = GpsStatus.GPS_EVENT_STOPPED;
- mGpsHandler.sendMessage(msg);
+ if (mListener != null) {
+ Message msg = Message.obtain();
+ msg.what = GpsStatus.GPS_EVENT_STOPPED;
+ mGpsHandler.sendMessage(msg);
+ }
}
public void onFirstFix(int ttff) {
- mGpsStatus.setTimeToFirstFix(ttff);
- Message msg = Message.obtain();
- msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
- mGpsHandler.sendMessage(msg);
+ if (mListener != null) {
+ mGpsStatus.setTimeToFirstFix(ttff);
+ Message msg = Message.obtain();
+ msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
+ mGpsHandler.sendMessage(msg);
+ }
}
public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
float[] elevations, float[] azimuths, int ephemerisMask,
int almanacMask, int usedInFixMask) {
- mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
- ephemerisMask, almanacMask, usedInFixMask);
+ if (mListener != null) {
+ mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
+ ephemerisMask, almanacMask, usedInFixMask);
+
+ Message msg = Message.obtain();
+ msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
+ // remove any SV status messages already in the queue
+ mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
+ mGpsHandler.sendMessage(msg);
+ }
+ }
- Message msg = Message.obtain();
- msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
- // remove any SV status messages already in the queue
- mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
- mGpsHandler.sendMessage(msg);
+ public void onNmeaReceived(long timestamp, String nmea) {
+ if (mNmeaListener != null) {
+ synchronized (mNmeaBuffer) {
+ mNmeaBuffer.add(new Nmea(timestamp, nmea));
+ }
+ Message msg = Message.obtain();
+ msg.what = NMEA_RECEIVED;
+ // remove any NMEA_RECEIVED messages already in the queue
+ mGpsHandler.removeMessages(NMEA_RECEIVED);
+ mGpsHandler.sendMessage(msg);
+ }
}
private final Handler mGpsHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- // synchronize on mGpsStatus to ensure the data is copied atomically.
- synchronized(mGpsStatus) {
- mListener.onGpsStatusChanged(msg.what);
+ if (msg.what == NMEA_RECEIVED) {
+ synchronized (mNmeaBuffer) {
+ int length = mNmeaBuffer.size();
+ for (int i = 0; i < length; i++) {
+ Nmea nmea = mNmeaBuffer.get(i);
+ mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
+ }
+ mNmeaBuffer.clear();
+ }
+ } else {
+ // synchronize on mGpsStatus to ensure the data is copied atomically.
+ synchronized(mGpsStatus) {
+ mListener.onGpsStatusChanged(msg.what);
+ }
}
}
};
@@ -1217,6 +1273,52 @@ public class LocationManager {
}
}
+ /**
+ * Adds an NMEA listener.
+ *
+ * @param listener a {#link GpsStatus.NmeaListener} object to register
+ *
+ * @return true if the listener was successfully added
+ *
+ * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+ */
+ public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
+ boolean result;
+
+ if (mNmeaListeners.get(listener) != null) {
+ // listener is already registered
+ return true;
+ }
+ try {
+ GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
+ result = mService.addGpsStatusListener(transport);
+ if (result) {
+ mNmeaListeners.put(listener, transport);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
+ result = false;
+ }
+
+ return result;
+ }
+
+ /**
+ * Removes an NMEA listener.
+ *
+ * @param listener a {#link GpsStatus.NmeaListener} object to remove
+ */
+ public void removeNmeaListener(GpsStatus.NmeaListener listener) {
+ try {
+ GpsStatusListenerTransport transport = mNmeaListeners.remove(listener);
+ if (transport != null) {
+ mService.removeGpsStatusListener(transport);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
+ }
+ }
+
/**
* Retrieves information about the current status of the GPS engine.
* This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
@@ -1315,4 +1417,20 @@ public class LocationManager {
Log.e(TAG, "RemoteException in reportLocation: ", e);
}
}
+
+ /**
+ * Used by NetInitiatedActivity to report user response
+ * for network initiated GPS fix requests.
+ *
+ * {@hide}
+ */
+ public boolean sendNiResponse(int notifId, int userResponse) {
+ try {
+ return mService.sendNiResponse(notifId, userResponse);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in sendNiResponse: ", e);
+ return false;
+ }
+ }
+
}
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 4a51e31..bfa0671 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -27,6 +27,7 @@ import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationManager;
import android.location.ILocationProvider;
+import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
@@ -38,6 +39,7 @@ import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.Config;
import android.util.Log;
import android.util.SparseIntArray;
@@ -45,14 +47,18 @@ import android.util.SparseIntArray;
import com.android.internal.app.IBatteryStats;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.location.GpsNetInitiatedHandler;
+import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.StringBufferInputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Properties;
+import java.util.Map.Entry;
/**
* A GPS implementation of LocationProvider used by LocationManager.
@@ -183,8 +189,6 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
// number of fixes we have received since we started navigating
private int mFixCount;
- private int mPositionMode = GPS_POSITION_MODE_STANDALONE;
-
// true if we started navigation
private boolean mStarted;
@@ -198,6 +202,10 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
// properties loaded from PROPERTIES_FILE
private Properties mProperties;
private String mNtpServer;
+ private String mSuplServerHost;
+ private int mSuplServerPort;
+ private String mC2KServerHost;
+ private int mC2KServerPort;
private final Context mContext;
private final ILocationManager mLocationManager;
@@ -211,6 +219,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
private String mAGpsApn;
private int mAGpsDataConnectionState;
private final ConnectivityManager mConnMgr;
+ private final GpsNetInitiatedHandler mNIHandler;
// Wakelocks
private final static String WAKELOCK_KEY = "GpsLocationProvider";
@@ -321,6 +330,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
public GpsLocationProvider(Context context, ILocationManager locationManager) {
mContext = context;
mLocationManager = locationManager;
+ mNIHandler= new GpsNetInitiatedHandler(context, this);
// Create a wake lock
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -349,27 +359,21 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
stream.close();
mNtpServer = mProperties.getProperty("NTP_SERVER", null);
- String host = mProperties.getProperty("SUPL_HOST");
+ mSuplServerHost = mProperties.getProperty("SUPL_HOST");
String portString = mProperties.getProperty("SUPL_PORT");
- if (host != null && portString != null) {
+ if (mSuplServerHost != null && portString != null) {
try {
- int port = Integer.parseInt(portString);
- native_set_agps_server(AGPS_TYPE_SUPL, host, port);
- // use MS-Based position mode if SUPL support is enabled
- mPositionMode = GPS_POSITION_MODE_MS_BASED;
+ mSuplServerPort = Integer.parseInt(portString);
} catch (NumberFormatException e) {
Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
}
}
- host = mProperties.getProperty("C2K_HOST");
+ mC2KServerHost = mProperties.getProperty("C2K_HOST");
portString = mProperties.getProperty("C2K_PORT");
- if (host != null && portString != null) {
+ if (mC2KServerHost != null && portString != null) {
try {
- int port = Integer.parseInt(portString);
- native_set_agps_server(AGPS_TYPE_C2K, host, port);
- // use MS-Based position mode if SUPL support is enabled
- mPositionMode = GPS_POSITION_MODE_MS_BASED;
+ mC2KServerPort = Integer.parseInt(portString);
} catch (NumberFormatException e) {
Log.e(TAG, "unable to parse C2K_PORT: " + portString);
}
@@ -499,6 +503,13 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
mEnabled = native_init();
if (mEnabled) {
+ if (mSuplServerHost != null) {
+ native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
+ }
+ if (mC2KServerHost != null) {
+ native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
+ }
+
// run event listener thread while we are enabled
mEventThread = new GpsEventThread();
mEventThread.start();
@@ -722,7 +733,15 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
if (!mStarted) {
if (DEBUG) Log.d(TAG, "startNavigating");
mStarted = true;
- if (!native_start(mPositionMode, false, mFixInterval)) {
+ int positionMode;
+ if (Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ASSISTED_GPS_ENABLED, 1) != 0) {
+ positionMode = GPS_POSITION_MODE_MS_BASED;
+ } else {
+ positionMode = GPS_POSITION_MODE_STANDALONE;
+ }
+
+ if (!native_start(positionMode, false, mFixInterval)) {
mStarted = false;
Log.e(TAG, "native_start failed in startNavigating()");
return;
@@ -1002,6 +1021,32 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
}
+ /**
+ * called from native code to report NMEA data received
+ */
+ private void reportNmea(int index, long timestamp) {
+ synchronized(mListeners) {
+ int size = mListeners.size();
+ if (size > 0) {
+ // don't bother creating the String if we have no listeners
+ int length = native_read_nmea(index, mNmeaBuffer, mNmeaBuffer.length);
+ String nmea = new String(mNmeaBuffer, 0, length);
+
+ for (int i = 0; i < size; i++) {
+ Listener listener = mListeners.get(i);
+ try {
+ listener.mListener.onNmeaReceived(timestamp, nmea);
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException in reportNmea");
+ mListeners.remove(listener);
+ // adjust for size of list changing
+ size--;
+ }
+ }
+ }
+ }
+ }
+
private void xtraDownloadRequest() {
if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest");
if (mNetworkThread != null) {
@@ -1009,6 +1054,96 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
}
+ //=============================================================
+ // NI Client support
+ //=============================================================
+ private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
+ // Sends a response for an NI reqeust to HAL.
+ public boolean sendNiResponse(int notificationId, int userResponse)
+ {
+ // TODO Add Permission check
+
+ StringBuilder extrasBuf = new StringBuilder();
+
+ if (Config.LOGD) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
+ ", response: " + userResponse);
+
+ native_send_ni_response(notificationId, userResponse);
+
+ return true;
+ }
+ };
+
+ public INetInitiatedListener getNetInitiatedListener() {
+ return mNetInitiatedListener;
+ }
+
+ // Called by JNI function to report an NI request.
+ @SuppressWarnings("deprecation")
+ public void reportNiNotification(
+ int notificationId,
+ int niType,
+ int notifyFlags,
+ int timeout,
+ int defaultResponse,
+ String requestorId,
+ String text,
+ int requestorIdEncoding,
+ int textEncoding,
+ String extras // Encoded extra data
+ )
+ {
+ Log.i(TAG, "reportNiNotification: entered");
+ Log.i(TAG, "notificationId: " + notificationId +
+ ", niType: " + niType +
+ ", notifyFlags: " + notifyFlags +
+ ", timeout: " + timeout +
+ ", defaultResponse: " + defaultResponse);
+
+ Log.i(TAG, "requestorId: " + requestorId +
+ ", text: " + text +
+ ", requestorIdEncoding: " + requestorIdEncoding +
+ ", textEncoding: " + textEncoding);
+
+ GpsNiNotification notification = new GpsNiNotification();
+
+ notification.notificationId = notificationId;
+ notification.niType = niType;
+ notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
+ notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
+ notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
+ notification.timeout = timeout;
+ notification.defaultResponse = defaultResponse;
+ notification.requestorId = requestorId;
+ notification.text = text;
+ notification.requestorIdEncoding = requestorIdEncoding;
+ notification.textEncoding = textEncoding;
+
+ // Process extras, assuming the format is
+ // one of more lines of "key = value"
+ Bundle bundle = new Bundle();
+
+ if (extras == null) extras = "";
+ Properties extraProp = new Properties();
+
+ try {
+ extraProp.load(new StringBufferInputStream(extras));
+ }
+ catch (IOException e)
+ {
+ Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
+ }
+
+ for (Entry<Object, Object> ent : extraProp.entrySet())
+ {
+ bundle.putString((String) ent.getKey(), (String) ent.getValue());
+ }
+
+ notification.extras = bundle;
+
+ mNIHandler.handleNiNotification(notification);
+ }
+
private class GpsEventThread extends Thread {
public GpsEventThread() {
@@ -1182,6 +1317,8 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
private float mSvAzimuths[] = new float[MAX_SVS];
private int mSvMasks[] = new int[3];
private int mSvCount;
+ // preallocated to avoid memory allocation in reportNmea()
+ private byte[] mNmeaBuffer = new byte[120];
static { class_init_native(); }
private static native void class_init_native();
@@ -1199,6 +1336,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
// mask[0] is ephemeris mask and mask[1] is almanac mask
private native int native_read_sv_status(int[] svs, float[] snrs,
float[] elevations, float[] azimuths, int[] masks);
+ private native int native_read_nmea(int index, byte[] buffer, int bufferSize);
private native void native_inject_location(double latitude, double longitude, float accuracy);
// XTRA Support
@@ -1211,4 +1349,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
private native void native_agps_data_conn_closed();
private native void native_agps_data_conn_failed();
private native void native_set_agps_server(int type, String hostname, int port);
+
+ // Network-initiated (NI) Support
+ private native void native_send_ni_response(int notificationId, int userResponse);
}
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
new file mode 100755
index 0000000..a5466d1
--- /dev/null
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -0,0 +1,457 @@
+/*
+ * 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.internal.location;
+
+import java.io.UnsupportedEncodingException;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * A GPS Network-initiated Handler class used by LocationManager.
+ *
+ * {@hide}
+ */
+public class GpsNetInitiatedHandler {
+
+ private static final String TAG = "GpsNetInitiatedHandler";
+
+ private static final boolean DEBUG = true;
+ private static final boolean VERBOSE = false;
+
+ // NI verify activity for bringing up UI (not used yet)
+ public static final String ACTION_NI_VERIFY = "android.intent.action.NETWORK_INITIATED_VERIFY";
+
+ // string constants for defining data fields in NI Intent
+ public static final String NI_INTENT_KEY_NOTIF_ID = "notif_id";
+ public static final String NI_INTENT_KEY_TITLE = "title";
+ public static final String NI_INTENT_KEY_MESSAGE = "message";
+ public static final String NI_INTENT_KEY_TIMEOUT = "timeout";
+ public static final String NI_INTENT_KEY_DEFAULT_RESPONSE = "default_resp";
+
+ // the extra command to send NI response to GpsLocationProvider
+ public static final String NI_RESPONSE_EXTRA_CMD = "send_ni_response";
+
+ // the extra command parameter names in the Bundle
+ public static final String NI_EXTRA_CMD_NOTIF_ID = "notif_id";
+ public static final String NI_EXTRA_CMD_RESPONSE = "response";
+
+ // these need to match GpsNiType constants in gps_ni.h
+ public static final int GPS_NI_TYPE_VOICE = 1;
+ public static final int GPS_NI_TYPE_UMTS_SUPL = 2;
+ public static final int GPS_NI_TYPE_UMTS_CTRL_PLANE = 3;
+
+ // these need to match GpsUserResponseType constants in gps_ni.h
+ public static final int GPS_NI_RESPONSE_ACCEPT = 1;
+ public static final int GPS_NI_RESPONSE_DENY = 2;
+ public static final int GPS_NI_RESPONSE_NORESP = 3;
+
+ // these need to match GpsNiNotifyFlags constants in gps_ni.h
+ public static final int GPS_NI_NEED_NOTIFY = 0x0001;
+ public static final int GPS_NI_NEED_VERIFY = 0x0002;
+ public static final int GPS_NI_PRIVACY_OVERRIDE = 0x0004;
+
+ // these need to match GpsNiEncodingType in gps_ni.h
+ public static final int GPS_ENC_NONE = 0;
+ public static final int GPS_ENC_SUPL_GSM_DEFAULT = 1;
+ public static final int GPS_ENC_SUPL_UTF8 = 2;
+ public static final int GPS_ENC_SUPL_UCS2 = 3;
+ public static final int GPS_ENC_UNKNOWN = -1;
+
+ private final Context mContext;
+
+ // parent gps location provider
+ private final GpsLocationProvider mGpsLocationProvider;
+
+ // configuration of notificaiton behavior
+ private boolean mPlaySounds = false;
+ private boolean visible = true;
+ private boolean mPopupImmediately = true;
+
+ // Set to true if string from HAL is encoded as Hex, e.g., "3F0039"
+ static private boolean mIsHexInput = true;
+
+ public static class GpsNiNotification
+ {
+ int notificationId;
+ int niType;
+ boolean needNotify;
+ boolean needVerify;
+ boolean privacyOverride;
+ int timeout;
+ int defaultResponse;
+ String requestorId;
+ String text;
+ int requestorIdEncoding;
+ int textEncoding;
+ Bundle extras;
+ };
+
+ public static class GpsNiResponse {
+ /* User reponse, one of the values in GpsUserResponseType */
+ int userResponse;
+ /* Optional extra data to pass with the user response */
+ Bundle extras;
+ };
+
+ /**
+ * The notification that is shown when a network-initiated notification
+ * (and verification) event is received.
+ * <p>
+ * This is lazily created, so use {@link #setNINotification()}.
+ */
+ private Notification mNiNotification;
+
+ public GpsNetInitiatedHandler(Context context, GpsLocationProvider gpsLocationProvider) {
+ mContext = context;
+ mGpsLocationProvider = gpsLocationProvider;
+ }
+
+ // Handles NI events from HAL
+ public void handleNiNotification(GpsNiNotification notif)
+ {
+ if (DEBUG) Log.d(TAG, "handleNiNotification" + " notificationId: " + notif.notificationId
+ + " requestorId: " + notif.requestorId + " text: " + notif.text);
+
+ // Notify and verify with immediate pop-up
+ if (notif.needNotify && notif.needVerify && mPopupImmediately)
+ {
+ // Popup the dialog box now
+ openNiDialog(notif);
+ }
+
+ // Notify only, or delayed pop-up (change mPopupImmediately to FALSE)
+ if (notif.needNotify && !notif.needVerify ||
+ notif.needNotify && notif.needVerify && !mPopupImmediately)
+ {
+ // Show the notification
+
+ // if mPopupImmediately == FALSE and needVerify == TRUE, a dialog will be opened
+ // when the user opens the notification message
+
+ setNiNotification(notif);
+ }
+
+ // ACCEPT cases: 1. Notify, no verify; 2. no notify, no verify; 3. privacy override.
+ if ( notif.needNotify && !notif.needVerify ||
+ !notif.needNotify && !notif.needVerify ||
+ notif.privacyOverride)
+ {
+ try {
+ mGpsLocationProvider.getNetInitiatedListener().sendNiResponse(notif.notificationId, GPS_NI_RESPONSE_ACCEPT);
+ }
+ catch (RemoteException e)
+ {
+ Log.e(TAG, e.getMessage());
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // A note about timeout
+ // According to the protocol, in the need_notify and need_verify case,
+ // a default response should be sent when time out.
+ //
+ // In some GPS hardware, the GPS driver (under HAL) can handle the timeout case
+ // and this class GpsNetInitiatedHandler does not need to do anything.
+ //
+ // However, the UI should at least close the dialog when timeout. Further,
+ // for more general handling, timeout response should be added to the Handler here.
+ //
+ }
+
+ // Sets the NI notification.
+ private synchronized void setNiNotification(GpsNiNotification notif) {
+ NotificationManager notificationManager = (NotificationManager) mContext
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ if (notificationManager == null) {
+ return;
+ }
+
+ String title = getNotifTitle(notif);
+ String message = getNotifMessage(notif);
+
+ if (DEBUG) Log.d(TAG, "setNiNotification, notifyId: " + notif.notificationId +
+ ", title: " + title +
+ ", message: " + message);
+
+ // Construct Notification
+ if (mNiNotification == null) {
+ mNiNotification = new Notification();
+ mNiNotification.icon = com.android.internal.R.drawable.stat_sys_gps_on; /* Change notification icon here */
+ mNiNotification.when = 0;
+ }
+
+ if (mPlaySounds) {
+ mNiNotification.defaults |= Notification.DEFAULT_SOUND;
+ } else {
+ mNiNotification.defaults &= ~Notification.DEFAULT_SOUND;
+ }
+
+ mNiNotification.flags = Notification.FLAG_ONGOING_EVENT;
+ mNiNotification.tickerText = getNotifTicker(notif);
+
+ // if not to popup dialog immediately, pending intent will open the dialog
+ Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent();
+ PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ mNiNotification.setLatestEventInfo(mContext, title, message, pi);
+
+ if (visible) {
+ notificationManager.notify(notif.notificationId, mNiNotification);
+ } else {
+ notificationManager.cancel(notif.notificationId);
+ }
+ }
+
+ // Opens the notification dialog and waits for user input
+ private void openNiDialog(GpsNiNotification notif)
+ {
+ Intent intent = getDlgIntent(notif);
+
+ if (DEBUG) Log.d(TAG, "openNiDialog, notifyId: " + notif.notificationId +
+ ", requestorId: " + notif.requestorId +
+ ", text: " + notif.text);
+
+ mContext.startActivity(intent);
+ }
+
+ // Construct the intent for bringing up the dialog activity, which shows the
+ // notification and takes user input
+ private Intent getDlgIntent(GpsNiNotification notif)
+ {
+ Intent intent = new Intent();
+ String title = getDialogTitle(notif);
+ String message = getDialogMessage(notif);
+
+ // directly bring up the NI activity
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setClass(mContext, com.android.internal.app.NetInitiatedActivity.class);
+
+ // put data in the intent
+ intent.putExtra(NI_INTENT_KEY_NOTIF_ID, notif.notificationId);
+ intent.putExtra(NI_INTENT_KEY_TITLE, title);
+ intent.putExtra(NI_INTENT_KEY_MESSAGE, message);
+ intent.putExtra(NI_INTENT_KEY_TIMEOUT, notif.timeout);
+ intent.putExtra(NI_INTENT_KEY_DEFAULT_RESPONSE, notif.defaultResponse);
+
+ if (DEBUG) Log.d(TAG, "generateIntent, title: " + title + ", message: " + message +
+ ", timeout: " + notif.timeout);
+
+ return intent;
+ }
+
+ // Converts a string (or Hex string) to a char array
+ static byte[] stringToByteArray(String original, boolean isHex)
+ {
+ int length = isHex ? original.length() / 2 : original.length();
+ byte[] output = new byte[length];
+ int i;
+
+ if (isHex)
+ {
+ for (i = 0; i < length; i++)
+ {
+ output[i] = (byte) Integer.parseInt(original.substring(i*2, i*2+2), 16);
+ }
+ }
+ else {
+ for (i = 0; i < length; i++)
+ {
+ output[i] = (byte) original.charAt(i);
+ }
+ }
+
+ return output;
+ }
+
+ /**
+ * Unpacks an byte array containing 7-bit packed characters into a String.
+ *
+ * @param input a 7-bit packed char array
+ * @return the unpacked String
+ */
+ static String decodeGSMPackedString(byte[] input)
+ {
+ final char CHAR_CR = 0x0D;
+ int nStridx = 0;
+ int nPckidx = 0;
+ int num_bytes = input.length;
+ int cPrev = 0;
+ int cCurr = 0;
+ byte nShift;
+ byte nextChar;
+ byte[] stringBuf = new byte[input.length * 2];
+ String result = "";
+
+ while(nPckidx < num_bytes)
+ {
+ nShift = (byte) (nStridx & 0x07);
+ cCurr = input[nPckidx++];
+ if (cCurr < 0) cCurr += 256;
+
+ /* A 7-bit character can be split at the most between two bytes of packed
+ ** data.
+ */
+ nextChar = (byte) (( (cCurr << nShift) | (cPrev >> (8-nShift)) ) & 0x7F);
+ stringBuf[nStridx++] = nextChar;
+
+ /* Special case where the whole of the next 7-bit character fits inside
+ ** the current byte of packed data.
+ */
+ if(nShift == 6)
+ {
+ /* If the next 7-bit character is a CR (0x0D) and it is the last
+ ** character, then it indicates a padding character. Drop it.
+ */
+ if (nPckidx == num_bytes || (cCurr >> 1) == CHAR_CR)
+ {
+ break;
+ }
+
+ nextChar = (byte) (cCurr >> 1);
+ stringBuf[nStridx++] = nextChar;
+ }
+
+ cPrev = cCurr;
+ }
+
+ try{
+ result = new String(stringBuf, 0, nStridx, "US-ASCII");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ Log.e(TAG, e.getMessage());
+ }
+
+ return result;
+ }
+
+ static String decodeUTF8String(byte[] input)
+ {
+ String decoded = "";
+ try {
+ decoded = new String(input, "UTF-8");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ Log.e(TAG, e.getMessage());
+ }
+ return decoded;
+ }
+
+ static String decodeUCS2String(byte[] input)
+ {
+ String decoded = "";
+ try {
+ decoded = new String(input, "UTF-16");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ Log.e(TAG, e.getMessage());
+ }
+ return decoded;
+ }
+
+ /** Decode NI string
+ *
+ * @param original The text string to be decoded
+ * @param isHex Specifies whether the content of the string has been encoded as a Hex string. Encoding
+ * a string as Hex can allow zeros inside the coded text.
+ * @param coding Specifies the coding scheme of the string, such as GSM, UTF8, UCS2, etc. This coding scheme
+ * needs to match those used passed to HAL from the native GPS driver. Decoding is done according
+ * to the <code> coding </code>, after a Hex string is decoded. Generally, if the
+ * notification strings don't need further decoding, <code> coding </code> encoding can be
+ * set to -1, and <code> isHex </code> can be false.
+ * @return the decoded string
+ */
+ static private String decodeString(String original, boolean isHex, int coding)
+ {
+ String decoded = original;
+ byte[] input = stringToByteArray(original, isHex);
+
+ switch (coding) {
+ case GPS_ENC_NONE:
+ decoded = original;
+ break;
+
+ case GPS_ENC_SUPL_GSM_DEFAULT:
+ decoded = decodeGSMPackedString(input);
+ break;
+
+ case GPS_ENC_SUPL_UTF8:
+ decoded = decodeUTF8String(input);
+ break;
+
+ case GPS_ENC_SUPL_UCS2:
+ decoded = decodeUCS2String(input);
+ break;
+
+ case GPS_ENC_UNKNOWN:
+ decoded = original;
+ break;
+
+ default:
+ Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original);
+ break;
+ }
+ return decoded;
+ }
+
+ // change this to configure notification display
+ static private String getNotifTicker(GpsNiNotification notif)
+ {
+ String ticker = String.format("Position request! ReqId: [%s] ClientName: [%s]",
+ decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
+ decodeString(notif.text, mIsHexInput, notif.textEncoding));
+ return ticker;
+ }
+
+ // change this to configure notification display
+ static private String getNotifTitle(GpsNiNotification notif)
+ {
+ String title = String.format("Position Request");
+ return title;
+ }
+
+ // change this to configure notification display
+ static private String getNotifMessage(GpsNiNotification notif)
+ {
+ String message = String.format(
+ "NI Request received from [%s] for client [%s]!",
+ decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
+ decodeString(notif.text, mIsHexInput, notif.textEncoding));
+ return message;
+ }
+
+ // change this to configure dialog display (for verification)
+ static public String getDialogTitle(GpsNiNotification notif)
+ {
+ return getNotifTitle(notif);
+ }
+
+ // change this to configure dialog display (for verification)
+ static private String getDialogMessage(GpsNiNotification notif)
+ {
+ return getNotifMessage(notif);
+ }
+
+}
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/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 0732b61..b3aae72 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -37,15 +37,61 @@ public class AudioFormat {
public static final int ENCODING_PCM_8BIT = 3; // accessed by native code
/** Invalid audio channel configuration */
- public static final int CHANNEL_CONFIGURATION_INVALID = 0;
+ /** @deprecated use CHANNEL_INVALID instead */
+ @Deprecated public static final int CHANNEL_CONFIGURATION_INVALID = 0;
/** Default audio channel configuration */
- public static final int CHANNEL_CONFIGURATION_DEFAULT = 1;
+ /** @deprecated use CHANNEL_OUT_DEFAULT or CHANNEL_IN_DEFAULT instead */
+ @Deprecated public static final int CHANNEL_CONFIGURATION_DEFAULT = 1;
/** Mono audio configuration */
- public static final int CHANNEL_CONFIGURATION_MONO = 2;
+ /** @deprecated use CHANNEL_OUT_MONO or CHANNEL_IN_MONO instead */
+ @Deprecated public static final int CHANNEL_CONFIGURATION_MONO = 2;
/** Stereo (2 channel) audio configuration */
- public static final int CHANNEL_CONFIGURATION_STEREO = 3;
+ /** @deprecated use CHANNEL_OUT_STEREO or CHANNEL_IN_STEREO instead */
+ @Deprecated public static final int CHANNEL_CONFIGURATION_STEREO = 3;
-}
+ /** Invalid audio channel mask */
+ public static final int CHANNEL_INVALID = 0;
+ /** Default audio channel mask */
+ public static final int CHANNEL_OUT_DEFAULT = 1;
+ // Channel mask definitions must be kept in sync with native values in include/media/AudioSystem.h
+ public static final int CHANNEL_OUT_FRONT_LEFT = 0x4;
+ public static final int CHANNEL_OUT_FRONT_RIGHT = 0x8;
+ public static final int CHANNEL_OUT_FRONT_CENTER = 0x10;
+ public static final int CHANNEL_OUT_LOW_FREQUENCY = 0x20;
+ public static final int CHANNEL_OUT_BACK_LEFT = 0x40;
+ public static final int CHANNEL_OUT_BACK_RIGHT = 0x80;
+ public static final int CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100;
+ public static final int CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200;
+ public static final int CHANNEL_OUT_BACK_CENTER = 0x400;
+ public static final int CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT;
+ public static final int CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT);
+ public static final int CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT);
+ public static final int CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER);
+ public static final int CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT);
+ public static final int CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+ CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+ CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER);
+ public static final int CHANNEL_IN_DEFAULT = 1;
+ public static final int CHANNEL_IN_LEFT = 0x4;
+ public static final int CHANNEL_IN_RIGHT = 0x8;
+ public static final int CHANNEL_IN_FRONT = 0x10;
+ public static final int CHANNEL_IN_BACK = 0x20;
+ public static final int CHANNEL_IN_LEFT_PROCESSED = 0x40;
+ public static final int CHANNEL_IN_RIGHT_PROCESSED = 0x80;
+ public static final int CHANNEL_IN_FRONT_PROCESSED = 0x100;
+ public static final int CHANNEL_IN_BACK_PROCESSED = 0x200;
+ public static final int CHANNEL_IN_PRESSURE = 0x400;
+ public static final int CHANNEL_IN_X_AXIS = 0x800;
+ public static final int CHANNEL_IN_Y_AXIS = 0x1000;
+ public static final int CHANNEL_IN_Z_AXIS = 0x2000;
+ public static final int CHANNEL_IN_VOICE_UPLINK = 0x4000;
+ public static final int CHANNEL_IN_VOICE_DNLINK = 0x8000;
+ public static final int CHANNEL_IN_MONO = CHANNEL_IN_FRONT;
+ public static final int CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT);
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index a65a417..de944ee 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -140,24 +140,19 @@ public class AudioManager {
public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
/** @hide The audio stream for phone calls when connected to bluetooth */
public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
+ /** @hide The audio stream for enforced system sounds in certain countries (e.g camera in Japan) */
+ public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
+ /** The audio stream for DTMF Tones */
+ public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
+ /** @hide The audio stream for text to speech (TTS) */
+ public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
/** Number of audio streams */
/**
* @deprecated Use AudioSystem.getNumStreamTypes() instead
*/
- public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
+ @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
- /** @hide Maximum volume index values for audio streams */
- public static final int[] MAX_STREAM_VOLUME = new int[] {
- 6, // STREAM_VOICE_CALL
- 8, // STREAM_SYSTEM
- 8, // STREAM_RING
- 16, // STREAM_MUSIC
- 8, // STREAM_ALARM
- 8, // STREAM_NOTIFICATION
- 16, // STREAM_BLUETOOTH_SCO
- };
-
/** @hide Default volume index values for audio streams */
public static final int[] DEFAULT_STREAM_VOLUME = new int[] {
4, // STREAM_VOICE_CALL
@@ -166,7 +161,10 @@ public class AudioManager {
11, // STREAM_MUSIC
6, // STREAM_ALARM
5, // STREAM_NOTIFICATION
- 7 // STREAM_BLUETOOTH_SCO
+ 7, // STREAM_BLUETOOTH_SCO
+ 5, // STREAM_SYSTEM_ENFORCED
+ 11, // STREAM_DTMF
+ 11 // STREAM_TTS
};
/**
@@ -637,9 +635,12 @@ public class AudioManager {
* <var>false</var> to turn it off
*/
public void setSpeakerphoneOn(boolean on){
- // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
- // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
- setRoutingP(MODE_INVALID, on ? ROUTE_SPEAKER: 0, ROUTE_SPEAKER);
+ IAudioService service = getService();
+ try {
+ service.setSpeakerphoneOn(on);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setSpeakerphoneOn", e);
+ }
}
/**
@@ -648,41 +649,52 @@ public class AudioManager {
* @return true if speakerphone is on, false if it's off
*/
public boolean isSpeakerphoneOn() {
- return (getRoutingP(MODE_IN_CALL) & ROUTE_SPEAKER) == 0 ? false : true;
+ IAudioService service = getService();
+ try {
+ return service.isSpeakerphoneOn();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in isSpeakerphoneOn", e);
+ return false;
+ }
}
/**
- * Sets audio routing to the Bluetooth headset on or off.
+ * Request use of Bluetooth SCO headset for communications.
*
- * @param on set <var>true</var> to route SCO (voice) audio to/from Bluetooth
- * headset; <var>false</var> to route audio to/from phone earpiece
+ * @param on set <var>true</var> to use bluetooth SCO for communications;
+ * <var>false</var> to not use bluetooth SCO for communications
*/
public void setBluetoothScoOn(boolean on){
- // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
- // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
- setRoutingP(MODE_INVALID, on ? ROUTE_BLUETOOTH_SCO: 0, ROUTE_BLUETOOTH_SCO);
+ IAudioService service = getService();
+ try {
+ service.setBluetoothScoOn(on);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setBluetoothScoOn", e);
+ }
}
/**
- * Checks whether audio routing to the Bluetooth headset is on or off.
+ * Checks whether communications use Bluetooth SCO.
*
- * @return true if SCO audio is being routed to/from Bluetooth headset;
+ * @return true if SCO is used for communications;
* false if otherwise
*/
public boolean isBluetoothScoOn() {
- return (getRoutingP(MODE_IN_CALL) & ROUTE_BLUETOOTH_SCO) == 0 ? false : true;
+ IAudioService service = getService();
+ try {
+ return service.isBluetoothScoOn();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in isBluetoothScoOn", e);
+ return false;
+ }
}
/**
- * Sets A2DP audio routing to the Bluetooth headset on or off.
- *
* @param on set <var>true</var> to route A2DP audio to/from Bluetooth
* headset; <var>false</var> disable A2DP audio
+ * @deprecated Do not use.
*/
- public void setBluetoothA2dpOn(boolean on){
- // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
- // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
- setRoutingP(MODE_INVALID, on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP);
+ @Deprecated public void setBluetoothA2dpOn(boolean on){
}
/**
@@ -692,7 +704,12 @@ public class AudioManager {
* false if otherwise
*/
public boolean isBluetoothA2dpOn() {
- return (getRoutingP(MODE_NORMAL) & ROUTE_BLUETOOTH_A2DP) == 0 ? false : true;
+ if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,"")
+ == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
+ return false;
+ } else {
+ return true;
+ }
}
/**
@@ -700,12 +717,9 @@ public class AudioManager {
*
* @param on set <var>true</var> to route audio to/from wired
* headset; <var>false</var> disable wired headset audio
- * @hide
+ * @deprecated Do not use.
*/
- public void setWiredHeadsetOn(boolean on){
- // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
- // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
- setRoutingP(MODE_INVALID, on ? ROUTE_HEADSET: 0, ROUTE_HEADSET);
+ @Deprecated public void setWiredHeadsetOn(boolean on){
}
/**
@@ -713,10 +727,14 @@ public class AudioManager {
*
* @return true if audio is being routed to/from wired headset;
* false if otherwise
- * @hide
*/
public boolean isWiredHeadsetOn() {
- return (getRoutingP(MODE_NORMAL) & ROUTE_HEADSET) == 0 ? false : true;
+ if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,"")
+ == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
+ return false;
+ } else {
+ return true;
+ }
}
/**
@@ -726,12 +744,7 @@ public class AudioManager {
* <var>false</var> to turn mute off
*/
public void setMicrophoneMute(boolean on){
- IAudioService service = getService();
- try {
- service.setMicrophoneMute(on);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setMicrophoneMute", e);
- }
+ AudioSystem.muteMicrophone(on);
}
/**
@@ -740,13 +753,7 @@ public class AudioManager {
* @return true if microphone is muted, false if it's not
*/
public boolean isMicrophoneMute() {
- IAudioService service = getService();
- try {
- return service.isMicrophoneMute();
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in isMicrophoneMute", e);
- return false;
- }
+ return AudioSystem.isMicrophoneMuted();
}
/**
@@ -809,32 +816,46 @@ public class AudioManager {
/* Routing bits for setRouting/getRouting API */
/**
* Routing audio output to earpiece
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
- public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
+ @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
/**
- * Routing audio output to spaker
+ * Routing audio output to speaker
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
- public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
+ @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
/**
* @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
@Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
/**
* Routing audio output to bluetooth SCO
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
- public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
+ @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
/**
* Routing audio output to headset
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
- public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
+ @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
/**
* Routing audio output to bluetooth A2DP
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
- public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
+ @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
/**
* Used for mask parameter of {@link #setRouting(int,int,int)}.
+ * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
+ * setBluetoothScoOn() methods instead.
*/
- public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
+ @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
/**
* Sets the audio routing for a specified mode
@@ -846,16 +867,10 @@ public class AudioManager {
* ROUTE_xxx types. Unset bits indicate the route should be left unchanged
*
* @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
- * setBluetoothScoOn(), setBluetoothA2dpOn() and setWiredHeadsetOn() methods instead.
+ * setBluetoothScoOn() methods instead.
*/
-
+ @Deprecated
public void setRouting(int mode, int routes, int mask) {
- IAudioService service = getService();
- try {
- service.setRouting(mode, routes, mask);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setRouting", e);
- }
}
/**
@@ -869,13 +884,7 @@ public class AudioManager {
*/
@Deprecated
public int getRouting(int mode) {
- IAudioService service = getService();
- try {
- return service.getRouting(mode);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in getRouting", e);
- return -1;
- }
+ return -1;
}
/**
@@ -884,13 +893,7 @@ public class AudioManager {
* @return true if any music tracks are active.
*/
public boolean isMusicActive() {
- IAudioService service = getService();
- try {
- return service.isMusicActive();
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in isMusicActive", e);
- return false;
- }
+ return AudioSystem.isMusicActive();
}
/*
@@ -906,14 +909,32 @@ public class AudioManager {
*/
/**
* @hide
+ * @deprecated Use {@link #setPrameters(String)} instead
*/
- public void setParameter(String key, String value) {
- IAudioService service = getService();
- try {
- service.setParameter(key, value);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setParameter", e);
- }
+ @Deprecated public void setParameter(String key, String value) {
+ setParameters(key+"="+value);
+ }
+
+ /**
+ * Sets a variable number of parameter values to audio hardware.
+ *
+ * @param keyValuePairs list of parameters key value pairs in the form:
+ * key1=value1;key2=value2;...
+ *
+ */
+ public void setParameters(String keyValuePairs) {
+ AudioSystem.setParameters(keyValuePairs);
+ }
+
+ /**
+ * Sets a varaible number of parameter values to audio hardware.
+ *
+ * @param keys list of parameters
+ * @return list of parameters key value pairs in the form:
+ * key1=value1;key2=value2;...
+ */
+ public String getParameters(String keys) {
+ return AudioSystem.getParameters(keys);
}
/* Sound effect identifiers */
@@ -1082,31 +1103,4 @@ public class AudioManager {
* {@hide}
*/
private IBinder mICallBack = new Binder();
-
- /**
- * {@hide}
- */
- private void setRoutingP(int mode, int routes, int mask) {
- IAudioService service = getService();
- try {
- service.setRouting(mode, routes, mask);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setRouting", e);
- }
- }
-
-
- /**
- * {@hide}
- */
- private int getRoutingP(int mode) {
- IAudioService service = getService();
- try {
- return service.getRouting(mode);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in getRouting", e);
- return -1;
- }
- }
-
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 4d1535f..7a47157 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -86,7 +86,7 @@ public class AudioRecord
public static final int ERROR_INVALID_OPERATION = -3;
private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -16;
- private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT = -17;
+ private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK = -17;
private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -18;
private static final int AUDIORECORD_ERROR_SETUP_INVALIDSOURCE = -19;
private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED = -20;
@@ -133,9 +133,13 @@ public class AudioRecord
*/
private int mChannelCount = 1;
/**
+ * The audio channel mask
+ */
+ private int mChannels = AudioFormat.CHANNEL_IN_MONO;
+ /**
* The current audio channel configuration
*/
- private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ private int mChannelConfiguration = AudioFormat.CHANNEL_IN_MONO;
/**
* The encoding of the audio samples.
* @see AudioFormat#ENCODING_PCM_8BIT
@@ -193,8 +197,8 @@ public class AudioRecord
* @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
* not limited to) 44100, 22050 and 11025.
* @param channelConfig describes the configuration of the audio channels.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
- * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+ * See {@link AudioFormat#CHANNEL_IN_MONO} and
+ * {@link AudioFormat#CHANNEL_IN_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT} and
* {@link AudioFormat#ENCODING_PCM_8BIT}
@@ -224,7 +228,7 @@ public class AudioRecord
//TODO: update native initialization when information about hardware init failure
// due to capture device already open is available.
int initResult = native_setup( new WeakReference<AudioRecord>(this),
- mRecordSource, mSampleRate, mChannelCount, mAudioFormat, mNativeBufferSizeInBytes);
+ mRecordSource, mSampleRate, mChannels, mAudioFormat, mNativeBufferSizeInBytes);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing native AudioRecord object.");
return; // with mState == STATE_UNINITIALIZED
@@ -239,6 +243,7 @@ public class AudioRecord
// postconditions:
// mRecordSource is valid
// mChannelCount is valid
+ // mChannels is valid
// mAudioFormat is valid
// mSampleRate is valid
private void audioParamCheck(int audioSource, int sampleRateInHz,
@@ -264,20 +269,25 @@ public class AudioRecord
//--------------
// channel config
+ mChannelConfiguration = channelConfig;
+
switch (channelConfig) {
- case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT:
+ case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
+ case AudioFormat.CHANNEL_IN_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
mChannelCount = 1;
- mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ mChannels = AudioFormat.CHANNEL_IN_MONO;
break;
+ case AudioFormat.CHANNEL_IN_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
mChannelCount = 2;
- mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ mChannels = AudioFormat.CHANNEL_IN_STEREO;
break;
default:
mChannelCount = 0;
- mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_INVALID;
- throw (new IllegalArgumentException("Unsupported channel configuration."));
+ mChannels = AudioFormat.CHANNEL_INVALID;
+ mChannelConfiguration = AudioFormat.CHANNEL_INVALID;
+ throw (new IllegalArgumentException("Unsupported channel configuration."));
}
//--------------
@@ -368,8 +378,8 @@ public class AudioRecord
/**
* Returns the configured channel configuration.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO}
- * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}.
+ * See {@link AudioFormat#CHANNEL_IN_MONO}
+ * and {@link AudioFormat#CHANNEL_IN_STEREO}.
*/
public int getChannelConfiguration() {
return mChannelConfiguration;
@@ -425,8 +435,8 @@ public class AudioRecord
* will be polled for new data.
* @param sampleRateInHz the sample rate expressed in Hertz.
* @param channelConfig describes the configuration of the audio channels.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
- * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+ * See {@link AudioFormat#CHANNEL_IN_MONO} and
+ * {@link AudioFormat#CHANNEL_IN_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT}.
* @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
@@ -438,14 +448,16 @@ public class AudioRecord
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
int channelCount = 0;
switch(channelConfig) {
- case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT:
+ case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
+ case AudioFormat.CHANNEL_IN_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
channelCount = 1;
break;
+ case AudioFormat.CHANNEL_IN_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
channelCount = 2;
break;
- case AudioFormat.CHANNEL_CONFIGURATION_INVALID:
+ case AudioFormat.CHANNEL_INVALID:
default:
loge("getMinBufferSize(): Invalid channel configuration.");
return AudioRecord.ERROR_BAD_VALUE;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 58c04f3..754d5a2 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -17,9 +17,17 @@
package android.media;
import android.app.ActivityManagerNative;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothIntent;
+import android.bluetooth.BluetoothHeadset;
+
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.media.MediaPlayer.OnCompletionListener;
@@ -36,11 +44,16 @@ import android.provider.Settings;
import android.provider.Settings.System;
import android.util.Log;
import android.view.VolumePanel;
+import android.os.SystemProperties;
import com.android.internal.telephony.ITelephony;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
/**
@@ -94,16 +107,10 @@ public class AudioService extends IAudioService.Stub {
/** @see VolumeStreamState */
private VolumeStreamState[] mStreamStates;
private SettingsObserver mSettingsObserver;
-
- private boolean mMicMute;
+
private int mMode;
- private int[] mRoutes = new int[AudioSystem.NUM_MODES];
private Object mSettingsLock = new Object();
private boolean mMediaServerOk;
- private boolean mSpeakerIsOn;
- private boolean mBluetoothScoIsConnected;
- private boolean mHeadsetIsConnected;
- private boolean mBluetoothA2dpIsConnected;
private SoundPool mSoundPool;
private Object mSoundEffectsLock = new Object();
@@ -135,6 +142,36 @@ public class AudioService extends IAudioService.Stub {
{4, -1} // FX_FOCUS_RETURN
};
+ /** @hide Maximum volume index values for audio streams */
+ private int[] MAX_STREAM_VOLUME = new int[] {
+ 5, // STREAM_VOICE_CALL
+ 7, // STREAM_SYSTEM
+ 7, // STREAM_RING
+ 15, // STREAM_MUSIC
+ 7, // STREAM_ALARM
+ 7, // STREAM_NOTIFICATION
+ 15, // STREAM_BLUETOOTH_SCO
+ 7, // STREAM_SYSTEM_ENFORCED
+ 15, // STREAM_DTMF
+ 15 // STREAM_TTS
+ };
+ /* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings
+ * of another stream: This avoids multiplying the volume settings for hidden
+ * stream types that follow other stream behavior for volume settings
+ * NOTE: do not create loops in aliases! */
+ private int[] STREAM_VOLUME_ALIAS = new int[] {
+ AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
+ AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM
+ AudioSystem.STREAM_RING, // STREAM_RING
+ AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
+ AudioSystem.STREAM_ALARM, // STREAM_ALARM
+ AudioSystem.STREAM_NOTIFICATION, // STREAM_NOTIFICATION
+ AudioSystem.STREAM_VOICE_CALL, // STREAM_BLUETOOTH_SCO
+ AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM_ENFORCED
+ AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF
+ AudioSystem.STREAM_MUSIC // STREAM_TTS
+ };
+
private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
public void onError(int error) {
switch (error) {
@@ -178,6 +215,27 @@ public class AudioService extends IAudioService.Stub {
*/
private int mVibrateSetting;
+ /** @see System#NOTIFICATIONS_USE_RING_VOLUME */
+ private int mNotificationsUseRingVolume;
+
+ // Broadcast receiver for device connections intent broadcasts
+ private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
+
+ //TODO: use common definitions with HeadsetObserver
+ private static final int BIT_HEADSET = (1 << 0);
+ private static final int BIT_HEADSET_NO_MIC = (1 << 1);
+ private static final int BIT_TTY = (1 << 2);
+ private static final int BIT_FM_HEADSET = (1 << 3);
+ private static final int BIT_FM_SPEAKER = (1 << 4);
+
+ private int mHeadsetState;
+
+ // Devices currently connected
+ private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
+
+ // Forced device usage for communications
+ private int mForcedUseForComm;
+
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
@@ -186,20 +244,31 @@ public class AudioService extends IAudioService.Stub {
public AudioService(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
+
+ // Intialized volume
+ MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
+ "ro.config.vc_call_vol_steps",
+ MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
+
mVolumePanel = new VolumePanel(context, this);
mSettingsObserver = new SettingsObserver();
-
+ mMode = AudioSystem.MODE_NORMAL;
+ mHeadsetState = 0;
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
createAudioSystemThread();
- createStreamStates();
readPersistedSettings();
- readAudioSettings();
+ createStreamStates();
mMediaServerOk = true;
AudioSystem.setErrorCallback(mAudioSystemCallback);
loadSoundEffects();
- mSpeakerIsOn = false;
- mBluetoothScoIsConnected = false;
- mHeadsetIsConnected = false;
- mBluetoothA2dpIsConnected = false;
+
+ // Register for device connection intent broadcasts.
+ IntentFilter intentFilter =
+ new IntentFilter(Intent.ACTION_HEADSET_PLUG);
+ intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+ intentFilter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
+ context.registerReceiver(mReceiver, intentFilter);
+
}
private void createAudioSystemThread() {
@@ -223,63 +292,23 @@ public class AudioService extends IAudioService.Stub {
}
private void createStreamStates() {
- final int[] volumeLevelsPhone =
- createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]);
- final int[] volumeLevelsCoarse =
- createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]);
- final int[] volumeLevelsFine =
- createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
- final int[] volumeLevelsBtPhone =
- createVolumeLevels(0,
- AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_BLUETOOTH_SCO]);
-
int numStreamTypes = AudioSystem.getNumStreamTypes();
VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
for (int i = 0; i < numStreamTypes; i++) {
- final int[] levels;
-
- switch (i) {
-
- case AudioSystem.STREAM_MUSIC:
- levels = volumeLevelsFine;
- break;
-
- case AudioSystem.STREAM_VOICE_CALL:
- levels = volumeLevelsPhone;
- break;
-
- case AudioSystem.STREAM_BLUETOOTH_SCO:
- levels = volumeLevelsBtPhone;
- break;
-
- default:
- levels = volumeLevelsCoarse;
- break;
- }
-
- if (i == AudioSystem.STREAM_BLUETOOTH_SCO) {
- streams[i] = new VolumeStreamState(AudioManager.DEFAULT_STREAM_VOLUME[i], i,levels);
- } else {
- streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[i], i, levels);
- }
- }
- }
-
- private static int[] createVolumeLevels(int offset, int numlevels) {
- double curve = 1.0f; // 1.4f
- int [] volumes = new int[numlevels + offset];
- for (int i = 0; i < offset; i++) {
- volumes[i] = 0;
+ streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[i]], i);
}
- double val = 0;
- double max = Math.pow(numlevels - 1, curve);
- for (int i = 0; i < numlevels; i++) {
- val = Math.pow(i, curve) / max;
- volumes[offset + i] = (int) (val * 100.0f);
+ // Correct stream index values for streams with aliases
+ for (int i = 0; i < numStreamTypes; i++) {
+ if (STREAM_VOLUME_ALIAS[i] != i) {
+ int index = rescaleIndex(streams[i].mIndex, STREAM_VOLUME_ALIAS[i], i);
+ streams[i].mIndex = streams[i].getValidIndex(index);
+ setStreamVolumeIndex(i, index);
+ index = rescaleIndex(streams[i].mLastAudibleIndex, STREAM_VOLUME_ALIAS[i], i);
+ streams[i].mLastAudibleIndex = streams[i].getValidIndex(index);
+ }
}
- return volumes;
}
private void readPersistedSettings() {
@@ -291,12 +320,19 @@ public class AudioService extends IAudioService.Stub {
mRingerModeAffectedStreams = Settings.System.getInt(cr,
Settings.System.MODE_RINGER_STREAMS_AFFECTED,
- ((1 << AudioManager.STREAM_RING)|(1 << AudioManager.STREAM_NOTIFICATION)|(1 << AudioManager.STREAM_SYSTEM)));
+ ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
+ (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)));
mMuteAffectedStreams = System.getInt(cr,
System.MUTE_STREAMS_AFFECTED,
((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
+ mNotificationsUseRingVolume = System.getInt(cr,
+ Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1);
+
+ if (mNotificationsUseRingVolume == 1) {
+ STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
+ }
// Each stream will read its own persisted settings
// Broadcast the sticky intent
@@ -307,25 +343,13 @@ public class AudioService extends IAudioService.Stub {
broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
}
- private void readAudioSettings() {
- synchronized (mSettingsLock) {
- mMicMute = AudioSystem.isMicrophoneMuted();
- mMode = AudioSystem.getMode();
- for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) {
- mRoutes[mode] = AudioSystem.getRouting(mode);
- }
- }
+ private void setStreamVolumeIndex(int stream, int index) {
+ AudioSystem.setStreamVolumeIndex(stream, (index + 5)/10);
}
- private void applyAudioSettings() {
- synchronized (mSettingsLock) {
- AudioSystem.muteMicrophone(mMicMute);
- AudioSystem.setMode(mMode);
- for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) {
- AudioSystem.setRouting(mode, mRoutes[mode], AudioSystem.ROUTE_ALL);
- }
- }
- }
+ private int rescaleIndex(int index, int srcStream, int dstStream) {
+ return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
+ }
///////////////////////////////////////////////////////////////////////////
// IPC methods
@@ -354,44 +378,26 @@ public class AudioService extends IAudioService.Stub {
ensureValidDirection(direction);
ensureValidStreamType(streamType);
- boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
- Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
- if (notificationsUseRingVolume && streamType == AudioManager.STREAM_NOTIFICATION) {
- // Redirect the volume change to the ring stream
- streamType = AudioManager.STREAM_RING;
- }
- VolumeStreamState streamState = mStreamStates[streamType];
+ VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]];
final int oldIndex = streamState.mIndex;
boolean adjustVolume = true;
// If either the client forces allowing ringer modes for this adjustment,
// or the stream type is one that is affected by ringer modes
if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0
- || streamType == AudioManager.STREAM_RING) {
+ || streamType == AudioSystem.STREAM_RING) {
// Check if the ringer mode changes with this volume adjustment. If
// it does, it will handle adjusting the volume, so we won't below
adjustVolume = checkForRingerModeChange(oldIndex, direction);
}
if (adjustVolume && streamState.adjustIndex(direction)) {
-
- boolean alsoUpdateNotificationVolume = notificationsUseRingVolume &&
- streamType == AudioManager.STREAM_RING;
- if (alsoUpdateNotificationVolume) {
- mStreamStates[AudioManager.STREAM_NOTIFICATION].adjustIndex(direction);
- }
-
// Post message to set system volume (it in turn will post a message
// to persist). Do not change volume if stream is muted.
if (streamState.muteCount() == 0) {
- sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
+ sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, STREAM_VOLUME_ALIAS[streamType], SENDMSG_NOOP, 0, 0,
streamState, 0);
-
- if (alsoUpdateNotificationVolume) {
- sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, AudioManager.STREAM_NOTIFICATION,
- SENDMSG_NOOP, 0, 0, mStreamStates[AudioManager.STREAM_NOTIFICATION], 0);
- }
}
}
@@ -404,9 +410,8 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#setStreamVolume(int, int, int) */
public void setStreamVolume(int streamType, int index, int flags) {
ensureValidStreamType(streamType);
- syncRingerAndNotificationStreamVolume(streamType, index, false);
-
- setStreamVolumeInt(streamType, index, false, true);
+ index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]);
+ setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true);
// UI, etc.
mVolumePanel.postVolumeChanged(streamType, flags);
@@ -420,37 +425,12 @@ public class AudioService extends IAudioService.Stub {
intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType));
// Currently, sending the intent only when the stream is BLUETOOTH_SCO
- if (streamType == AudioManager.STREAM_BLUETOOTH_SCO) {
+ if (streamType == AudioSystem.STREAM_BLUETOOTH_SCO) {
mContext.sendBroadcast(intent);
}
}
/**
- * Sync the STREAM_RING and STREAM_NOTIFICATION volumes if mandated by the
- * value in Settings.
- *
- * @param streamType Type of the stream
- * @param index Volume index for the stream
- * @param force If true, set the volume even if the current and desired
- * volume as same
- */
- private void syncRingerAndNotificationStreamVolume(int streamType, int index, boolean force) {
- boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
- Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
- if (notificationsUseRingVolume) {
- if (streamType == AudioManager.STREAM_NOTIFICATION) {
- // Redirect the volume change to the ring stream
- streamType = AudioManager.STREAM_RING;
- }
- if (streamType == AudioManager.STREAM_RING) {
- // One-off to sync notification volume to ringer volume
- setStreamVolumeInt(AudioManager.STREAM_NOTIFICATION, index, force, true);
- }
- }
- }
-
-
- /**
* Sets the stream state's index, and posts a message to set system volume.
* This will not call out to the UI. Assumes a valid stream type.
*
@@ -491,13 +471,13 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#getStreamVolume(int) */
public int getStreamVolume(int streamType) {
ensureValidStreamType(streamType);
- return mStreamStates[streamType].mIndex;
+ return (mStreamStates[streamType].mIndex + 5) / 10;
}
/** @see AudioManager#getStreamMaxVolume(int) */
public int getStreamMaxVolume(int streamType) {
ensureValidStreamType(streamType);
- return mStreamStates[streamType].getMaxIndex();
+ return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
}
/** @see AudioManager#getRingerMode() */
@@ -507,11 +487,12 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#setRingerMode(int) */
public void setRingerMode(int ringerMode) {
- if (ringerMode != mRingerMode) {
- setRingerModeInt(ringerMode, true);
-
- // Send sticky broadcast
- broadcastRingerMode();
+ synchronized (mSettingsLock) {
+ if (ringerMode != mRingerMode) {
+ setRingerModeInt(ringerMode, true);
+ // Send sticky broadcast
+ broadcastRingerMode();
+ }
}
}
@@ -541,7 +522,7 @@ public class AudioService extends IAudioService.Stub {
}
}
}
-
+
// Post a persist ringer mode msg
if (persist) {
sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG,
@@ -606,39 +587,28 @@ public class AudioService extends IAudioService.Stub {
return existingValue;
}
- /** @see AudioManager#setMicrophoneMute(boolean) */
- public void setMicrophoneMute(boolean on) {
- if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
- return;
- }
- synchronized (mSettingsLock) {
- if (on != mMicMute) {
- AudioSystem.muteMicrophone(on);
- mMicMute = on;
- }
- }
- }
-
- /** @see AudioManager#isMicrophoneMute() */
- public boolean isMicrophoneMute() {
- return mMicMute;
- }
-
/** @see AudioManager#setMode(int) */
public void setMode(int mode) {
if (!checkAudioSettingsPermission("setMode()")) {
return;
}
+
+ if (mode < AudioSystem.MODE_CURRENT || mode > AudioSystem.MODE_IN_CALL) {
+ return;
+ }
+
synchronized (mSettingsLock) {
+ if (mode == AudioSystem.MODE_CURRENT) {
+ mode = mMode;
+ }
if (mode != mMode) {
- if (AudioSystem.setMode(mode) == AudioSystem.AUDIO_STATUS_OK) {
+ if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
mMode = mode;
}
}
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
- int index = mStreamStates[streamType].mIndex;
- syncRingerAndNotificationStreamVolume(streamType, index, true);
- setStreamVolumeInt(streamType, index, true, true);
+ int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
+ setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, true);
}
}
@@ -647,187 +617,6 @@ public class AudioService extends IAudioService.Stub {
return mMode;
}
- /** @see AudioManager#setRouting(int, int, int) */
- public void setRouting(int mode, int routes, int mask) {
- int incallMask = 0;
- int ringtoneMask = 0;
- int normalMask = 0;
-
- if (!checkAudioSettingsPermission("setRouting()")) {
- return;
- }
- synchronized (mSettingsLock) {
- // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
- // mode AudioSystem.MODE_INVALID is used only by the following AudioManager methods:
- // setWiredHeadsetOn(), setBluetoothA2dpOn(), setBluetoothScoOn() and setSpeakerphoneOn().
- // If applications are using AudioManager.setRouting() that is now deprecated, the routing
- // command will be ignored.
- if (mode == AudioSystem.MODE_INVALID) {
- switch (mask) {
- case AudioSystem.ROUTE_SPEAKER:
- // handle setSpeakerphoneOn()
- if (routes != 0 && !mSpeakerIsOn) {
- mSpeakerIsOn = true;
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
- incallMask = AudioSystem.ROUTE_ALL;
- } else if (routes == 0 && mSpeakerIsOn) {
- mSpeakerIsOn = false;
- if (mBluetoothScoIsConnected) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_BLUETOOTH_SCO;
- } else if (mHeadsetIsConnected) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
- } else {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
- }
- incallMask = AudioSystem.ROUTE_ALL;
- }
- break;
-
- case AudioSystem.ROUTE_BLUETOOTH_SCO:
- // handle setBluetoothScoOn()
- if (routes != 0 && !mBluetoothScoIsConnected) {
- mBluetoothScoIsConnected = true;
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_BLUETOOTH_SCO;
- mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_BLUETOOTH_SCO;
- mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_BLUETOOTH_SCO;
- incallMask = AudioSystem.ROUTE_ALL;
- // A2DP has higher priority than SCO headset, so headset connect/disconnect events
- // should not affect A2DP routing
- ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- } else if (routes == 0 && mBluetoothScoIsConnected) {
- mBluetoothScoIsConnected = false;
- if (mHeadsetIsConnected) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
- mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- (AudioSystem.ROUTE_HEADSET|AudioSystem.ROUTE_SPEAKER);
- mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_HEADSET;
- } else {
- if (mSpeakerIsOn) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
- } else {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
- }
- mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_SPEAKER;
- mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_SPEAKER;
- }
- incallMask = AudioSystem.ROUTE_ALL;
- // A2DP has higher priority than SCO headset, so headset connect/disconnect events
- // should not affect A2DP routing
- ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- }
- break;
-
- case AudioSystem.ROUTE_HEADSET:
- // handle setWiredHeadsetOn()
- if (routes != 0 && !mHeadsetIsConnected) {
- mHeadsetIsConnected = true;
- // do not act upon headset connection if bluetooth SCO is connected to match phone app behavior
- if (!mBluetoothScoIsConnected) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
- mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- (AudioSystem.ROUTE_HEADSET|AudioSystem.ROUTE_SPEAKER);
- mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_HEADSET;
- incallMask = AudioSystem.ROUTE_ALL;
- // A2DP has higher priority than wired headset, so headset connect/disconnect events
- // should not affect A2DP routing
- ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- }
- } else if (routes == 0 && mHeadsetIsConnected) {
- mHeadsetIsConnected = false;
- // do not act upon headset disconnection if bluetooth SCO is connected to match phone app behavior
- if (!mBluetoothScoIsConnected) {
- if (mSpeakerIsOn) {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
- } else {
- mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
- }
- mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_SPEAKER;
- mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
- AudioSystem.ROUTE_SPEAKER;
-
- incallMask = AudioSystem.ROUTE_ALL;
- // A2DP has higher priority than wired headset, so headset connect/disconnect events
- // should not affect A2DP routing
- ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- }
- }
- break;
-
- case AudioSystem.ROUTE_BLUETOOTH_A2DP:
- // handle setBluetoothA2dpOn()
- if (routes != 0 && !mBluetoothA2dpIsConnected) {
- mBluetoothA2dpIsConnected = true;
- mRoutes[AudioSystem.MODE_RINGTONE] |= AudioSystem.ROUTE_BLUETOOTH_A2DP;
- mRoutes[AudioSystem.MODE_NORMAL] |= AudioSystem.ROUTE_BLUETOOTH_A2DP;
- // the audio flinger chooses A2DP as a higher priority,
- // so there is no need to disable other routes.
- ringtoneMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
- } else if (routes == 0 && mBluetoothA2dpIsConnected) {
- mBluetoothA2dpIsConnected = false;
- mRoutes[AudioSystem.MODE_RINGTONE] &= ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- mRoutes[AudioSystem.MODE_NORMAL] &= ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
- // the audio flinger chooses A2DP as a higher priority,
- // so there is no need to disable other routes.
- ringtoneMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
- normalMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
- }
- break;
- }
-
- // incallMask is != 0 means we must apply ne routing to MODE_IN_CALL mode
- if (incallMask != 0) {
- AudioSystem.setRouting(AudioSystem.MODE_IN_CALL,
- mRoutes[AudioSystem.MODE_IN_CALL],
- incallMask);
- }
- // ringtoneMask is != 0 means we must apply ne routing to MODE_RINGTONE mode
- if (ringtoneMask != 0) {
- AudioSystem.setRouting(AudioSystem.MODE_RINGTONE,
- mRoutes[AudioSystem.MODE_RINGTONE],
- ringtoneMask);
- }
- // normalMask is != 0 means we must apply ne routing to MODE_NORMAL mode
- if (normalMask != 0) {
- AudioSystem.setRouting(AudioSystem.MODE_NORMAL,
- mRoutes[AudioSystem.MODE_NORMAL],
- normalMask);
- }
-
- int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
- int index = mStreamStates[streamType].mIndex;
- syncRingerAndNotificationStreamVolume(streamType, index, true);
- setStreamVolumeInt(streamType, index, true, true);
- }
- }
- }
-
- /** @see AudioManager#getRouting(int) */
- public int getRouting(int mode) {
- return mRoutes[mode];
- }
-
- /** @see AudioManager#isMusicActive() */
- public boolean isMusicActive() {
- return AudioSystem.isMusicActive();
- }
-
- /** @see AudioManager#setParameter(String, String) */
- public void setParameter(String key, String value) {
- AudioSystem.setParameter(key, value);
- }
-
/** @see AudioManager#playSoundEffect(int) */
public void playSoundEffect(int effectType) {
sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP,
@@ -926,18 +715,29 @@ public class AudioService extends IAudioService.Stub {
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
VolumeStreamState streamState = mStreamStates[streamType];
- // there is no volume setting for STREAM_BLUETOOTH_SCO
- if (streamType != AudioSystem.STREAM_BLUETOOTH_SCO) {
- String settingName = System.VOLUME_SETTINGS[streamType];
- String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
-
- streamState.mIndex = streamState.getValidIndex(Settings.System.getInt(mContentResolver,
- settingName,
- AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
- streamState.mLastAudibleIndex = streamState.getValidIndex(Settings.System.getInt(mContentResolver,
- lastAudibleSettingName,
- streamState.mIndex > 0 ? streamState.mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
+ String settingName = System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[streamType]];
+ String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
+ int index = Settings.System.getInt(mContentResolver,
+ settingName,
+ AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
+ if (STREAM_VOLUME_ALIAS[streamType] != streamType) {
+ index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType);
+ } else {
+ index *= 10;
}
+ streamState.mIndex = streamState.getValidIndex(index);
+
+ index = (index + 5) / 10;
+ index = Settings.System.getInt(mContentResolver,
+ lastAudibleSettingName,
+ (index > 0) ? index : AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
+ if (STREAM_VOLUME_ALIAS[streamType] != streamType) {
+ index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType);
+ } else {
+ index *= 10;
+ }
+ streamState.mLastAudibleIndex = streamState.getValidIndex(index);
+
// unmute stream that whas muted but is not affect by mute anymore
if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
int size = streamState.mDeathHandlers.size();
@@ -948,7 +748,7 @@ public class AudioService extends IAudioService.Stub {
}
// apply stream volume
if (streamState.muteCount() == 0) {
- AudioSystem.setVolume(streamType, streamState.mVolumes[streamState.mIndex]);
+ setStreamVolumeIndex(streamType, streamState.mIndex);
}
}
@@ -956,6 +756,48 @@ public class AudioService extends IAudioService.Stub {
setRingerModeInt(getRingerMode(), false);
}
+ /** @see AudioManager#setSpeakerphoneOn() */
+ public void setSpeakerphoneOn(boolean on){
+ if (on) {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER);
+ mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
+ } else {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
+ }
+ }
+
+ /** @see AudioManager#isSpeakerphoneOn() */
+ public boolean isSpeakerphoneOn() {
+ if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /** @see AudioManager#setBluetoothScoOn() */
+ public void setBluetoothScoOn(boolean on){
+ if (on) {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO);
+ AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO);
+ mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
+ } else {
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
+ AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE);
+ mForcedUseForComm = AudioSystem.FORCE_NONE;
+ }
+ }
+
+ /** @see AudioManager#isBluetoothScoOn() */
+ public boolean isBluetoothScoOn() {
+ if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
///////////////////////////////////////////////////////////////////////////
// Internal methods
///////////////////////////////////////////////////////////////////////////
@@ -969,7 +811,7 @@ public class AudioService extends IAudioService.Stub {
boolean adjustVolumeIndex = true;
int newRingerMode = mRingerMode;
- if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && oldIndex == 1
+ if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && (oldIndex + 5) / 10 == 1
&& direction == AudioManager.ADJUST_LOWER) {
newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
} else if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
@@ -1026,7 +868,7 @@ public class AudioService extends IAudioService.Stub {
Log.w(TAG, "Couldn't connect to phone service", e);
}
- if ((getRouting(AudioSystem.MODE_IN_CALL) & AudioSystem.ROUTE_BLUETOOTH_SCO) != 0) {
+ if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) {
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
return AudioSystem.STREAM_BLUETOOTH_SCO;
} else if (isOffhook) {
@@ -1110,47 +952,36 @@ public class AudioService extends IAudioService.Stub {
private final String mLastAudibleVolumeIndexSettingName;
private final int mStreamType;
- private final int[] mVolumes;
+ private int mIndexMax;
private int mIndex;
private int mLastAudibleIndex;
private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death
- private VolumeStreamState(String settingName, int streamType, int[] volumes) {
+ private VolumeStreamState(String settingName, int streamType) {
mVolumeIndexSettingName = settingName;
mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
mStreamType = streamType;
- mVolumes = volumes;
final ContentResolver cr = mContentResolver;
- mIndex = getValidIndex(Settings.System.getInt(cr, mVolumeIndexSettingName, AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
- mLastAudibleIndex = getValidIndex(Settings.System.getInt(cr,
- mLastAudibleVolumeIndexSettingName, mIndex > 0 ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
-
- AudioSystem.setVolume(streamType, volumes[mIndex]);
- mDeathHandlers = new ArrayList<VolumeDeathHandler>();
- }
-
- /**
- * Constructor to be used when there is no setting associated with the VolumeStreamState.
- *
- * @param defaultVolume Default volume of the stream to use.
- * @param streamType Type of the stream.
- * @param volumes Volumes levels associated with this stream.
- */
- private VolumeStreamState(int defaultVolume, int streamType, int[] volumes) {
- mVolumeIndexSettingName = null;
- mLastAudibleVolumeIndexSettingName = null;
- mIndex = mLastAudibleIndex = defaultVolume;
- mStreamType = streamType;
- mVolumes = volumes;
- AudioSystem.setVolume(mStreamType, defaultVolume);
+ mIndexMax = MAX_STREAM_VOLUME[streamType];
+ mIndex = Settings.System.getInt(cr,
+ mVolumeIndexSettingName,
+ AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
+ mLastAudibleIndex = Settings.System.getInt(cr,
+ mLastAudibleVolumeIndexSettingName,
+ (mIndex > 0) ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
+ AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
+ mIndexMax *= 10;
+ mIndex = getValidIndex(10 * mIndex);
+ mLastAudibleIndex = getValidIndex(10 * mLastAudibleIndex);
+ setStreamVolumeIndex(streamType, mIndex);
mDeathHandlers = new ArrayList<VolumeDeathHandler>();
}
public boolean adjustIndex(int deltaIndex) {
- return setIndex(mIndex + deltaIndex, true);
+ return setIndex(mIndex + deltaIndex * 10, true);
}
public boolean setIndex(int index, boolean lastAudible) {
@@ -1161,6 +992,13 @@ public class AudioService extends IAudioService.Stub {
if (lastAudible) {
mLastAudibleIndex = mIndex;
}
+ // Apply change to all streams using this one as alias
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) {
+ mStreamStates[streamType].setIndex(rescaleIndex(mIndex, mStreamType, streamType), lastAudible);
+ }
+ }
return true;
} else {
return false;
@@ -1168,7 +1006,7 @@ public class AudioService extends IAudioService.Stub {
}
public int getMaxIndex() {
- return mVolumes.length - 1;
+ return mIndexMax;
}
public void mute(IBinder cb, boolean state) {
@@ -1183,8 +1021,8 @@ public class AudioService extends IAudioService.Stub {
private int getValidIndex(int index) {
if (index < 0) {
return 0;
- } else if (index >= mVolumes.length) {
- return mVolumes.length - 1;
+ } else if (index > mIndexMax) {
+ return mIndexMax;
}
return index;
@@ -1318,8 +1156,16 @@ public class AudioService extends IAudioService.Stub {
private void setSystemVolume(VolumeStreamState streamState) {
// Adjust volume
- AudioSystem
- .setVolume(streamState.mStreamType, streamState.mVolumes[streamState.mIndex]);
+ setStreamVolumeIndex(streamState.mStreamType, streamState.mIndex);
+
+ // Apply change to all streams using this one as alias
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ if (streamType != streamState.mStreamType &&
+ STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) {
+ setStreamVolumeIndex(streamType, mStreamStates[streamType].mIndex);
+ }
+ }
// Post a persist volume msg
sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType,
@@ -1327,12 +1173,10 @@ public class AudioService extends IAudioService.Stub {
}
private void persistVolume(VolumeStreamState streamState) {
- if (streamState.mStreamType != AudioManager.STREAM_BLUETOOTH_SCO) {
- System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
- streamState.mIndex);
- System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
- streamState.mLastAudibleIndex);
- }
+ System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
+ (streamState.mIndex + 5)/ 10);
+ System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
+ (streamState.mLastAudibleIndex + 5) / 10);
}
private void persistRingerMode() {
@@ -1421,25 +1265,45 @@ public class AudioService extends IAudioService.Stub {
Log.e(TAG, "Media server died.");
// Force creation of new IAudioflinger interface
mMediaServerOk = false;
- AudioSystem.getMode();
+ AudioSystem.isMusicActive();
break;
case MSG_MEDIA_SERVER_STARTED:
Log.e(TAG, "Media server started.");
- // Restore audio routing and stream volumes
- applyAudioSettings();
+ // Restore device connection states
+ Set set = mConnectedDevices.entrySet();
+ Iterator i = set.iterator();
+ while(i.hasNext()){
+ Map.Entry device = (Map.Entry)i.next();
+ AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(),
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ (String)device.getValue());
+ }
+
+ // Restore call state
+ AudioSystem.setPhoneState(mMode);
+
+ // Restore forced usage for communcations and record
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
+ AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
+
+ // Restore stream volumes
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
- int volume;
+ int index;
VolumeStreamState streamState = mStreamStates[streamType];
+ AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
if (streamState.muteCount() == 0) {
- volume = streamState.mVolumes[streamState.mIndex];
+ index = streamState.mIndex;
} else {
- volume = streamState.mVolumes[0];
+ index = 0;
}
- AudioSystem.setVolume(streamType, volume);
+ setStreamVolumeIndex(streamType, index);
}
- setRingerMode(mRingerMode);
+
+ // Restore ringer mode
+ setRingerModeInt(getRingerMode(), false);
+
mMediaServerOk = true;
break;
@@ -1451,28 +1315,189 @@ public class AudioService extends IAudioService.Stub {
}
private class SettingsObserver extends ContentObserver {
-
+
SettingsObserver() {
super(new Handler());
mContentResolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
+ mContentResolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATIONS_USE_RING_VOLUME), false, this);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
-
- mRingerModeAffectedStreams = Settings.System.getInt(mContentResolver,
- Settings.System.MODE_RINGER_STREAMS_AFFECTED,
- 0);
+ synchronized (mSettingsLock) {
+ int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver,
+ Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ 0);
+ if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
+ /*
+ * Ensure all stream types that should be affected by ringer mode
+ * are in the proper state.
+ */
+ mRingerModeAffectedStreams = ringerModeAffectedStreams;
+ setRingerModeInt(getRingerMode(), false);
+ }
- /*
- * Ensure all stream types that should be affected by ringer mode
- * are in the proper state.
- */
- setRingerModeInt(getRingerMode(), false);
+ int notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
+ Settings.System.NOTIFICATIONS_USE_RING_VOLUME,
+ 1);
+ if (notificationsUseRingVolume != mNotificationsUseRingVolume) {
+ mNotificationsUseRingVolume = notificationsUseRingVolume;
+ if (mNotificationsUseRingVolume == 1) {
+ STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
+ } else {
+ STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION;
+ // Persist notification volume volume as it was not persisted while aliased to ring volume
+ sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION,
+ SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], PERSIST_DELAY);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Receiver for misc intent broadcasts the Phone app cares about.
+ */
+ private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
+ int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
+ BluetoothA2dp.STATE_DISCONNECTED);
+ BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
+ String address = btDevice.getAddress();
+ boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
+ ((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address));
+
+ if (isConnected &&
+ state != BluetoothA2dp.STATE_CONNECTED && state != BluetoothA2dp.STATE_PLAYING) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ address);
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ } else if (!isConnected &&
+ (state == BluetoothA2dp.STATE_CONNECTED ||
+ state == BluetoothA2dp.STATE_PLAYING)) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ address);
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
+ address);
+ }
+ } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
+ int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
+ BluetoothHeadset.STATE_ERROR);
+ int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
+ BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
+ String address = null;
+ int btClass = BluetoothClass.ERROR;
+ if (btDevice != null) {
+ address = btDevice.getAddress();
+ btClass = btDevice.getBluetoothClass();
+ if (BluetoothClass.Device.Major.getDeviceMajor(btClass) ==
+ BluetoothClass.Device.Major.AUDIO_VIDEO) {
+ switch (BluetoothClass.Device.getDevice(btClass)) {
+ case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
+ case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
+ device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ break;
+ case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+ device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ boolean isConnected = (mConnectedDevices.containsKey(device) &&
+ ((String)mConnectedDevices.get(device)).equals(address));
+
+ if (isConnected && state != BluetoothHeadset.STATE_CONNECTED) {
+ AudioSystem.setDeviceConnectionState(device,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ address);
+ mConnectedDevices.remove(device);
+ } else if (!isConnected && state == BluetoothHeadset.STATE_CONNECTED) {
+ AudioSystem.setDeviceConnectionState(device,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ address);
+ mConnectedDevices.put(new Integer(device), address);
+ }
+ } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
+ int state = intent.getIntExtra("state", 0);
+ if ((state & BIT_HEADSET) == 0 &&
+ (mHeadsetState & BIT_HEADSET) != 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
+ } else if ((state & BIT_HEADSET) != 0 &&
+ (mHeadsetState & BIT_HEADSET) == 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), "");
+ }
+ if ((state & BIT_HEADSET_NO_MIC) == 0 &&
+ (mHeadsetState & BIT_HEADSET_NO_MIC) != 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
+ } else if ((state & BIT_HEADSET_NO_MIC) != 0 &&
+ (mHeadsetState & BIT_HEADSET_NO_MIC) == 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), "");
+ }
+ if ((state & BIT_TTY) == 0 &&
+ (mHeadsetState & BIT_TTY) != 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_TTY);
+ } else if ((state & BIT_TTY) != 0 &&
+ (mHeadsetState & BIT_TTY) == 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_TTY), "");
+ }
+ if ((state & BIT_FM_HEADSET) == 0 &&
+ (mHeadsetState & BIT_FM_HEADSET) != 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_HEADPHONE);
+ } else if ((state & BIT_FM_HEADSET) != 0 &&
+ (mHeadsetState & BIT_FM_HEADSET) == 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_HEADPHONE), "");
+ }
+ if ((state & BIT_FM_SPEAKER) == 0 &&
+ (mHeadsetState & BIT_FM_SPEAKER) != 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ "");
+ mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_SPEAKER);
+ } else if ((state & BIT_FM_SPEAKER) != 0 &&
+ (mHeadsetState & BIT_FM_SPEAKER) == 0) {
+ AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER,
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ "");
+ mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_SPEAKER), "");
+ }
+ mHeadsetState = state;
+ }
}
-
}
-
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 5917ab9..dbf6d9d 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -45,38 +45,21 @@ public class AudioSystem
public static final int STREAM_NOTIFICATION = 5;
/* @hide The audio stream for phone calls when connected on bluetooth */
public static final int STREAM_BLUETOOTH_SCO = 6;
+ /* @hide The audio stream for enforced system sounds in certain countries (e.g camera in Japan) */
+ public static final int STREAM_SYSTEM_ENFORCED = 7;
+ /* @hide The audio stream for DTMF tones */
+ public static final int STREAM_DTMF = 8;
+ /* @hide The audio stream for text to speech (TTS) */
+ public static final int STREAM_TTS = 9;
/**
* @deprecated Use {@link #numStreamTypes() instead}
*/
public static final int NUM_STREAMS = 5;
// Expose only the getter method publicly so we can change it in the future
- private static final int NUM_STREAM_TYPES = 7;
+ private static final int NUM_STREAM_TYPES = 10;
public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; }
- /* max and min volume levels */
- /* Maximum volume setting, for use with setVolume(int,int) */
- public static final int MAX_VOLUME = 100;
- /* Minimum volume setting, for use with setVolume(int,int) */
- public static final int MIN_VOLUME = 0;
-
- /*
- * Sets the volume of a specified audio stream.
- *
- * param type the stream type to set the volume of (e.g. STREAM_MUSIC)
- * param volume the volume level to set (0-100)
- * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR
- */
- public static native int setVolume(int type, int volume);
-
- /*
- * Returns the volume of a specified audio stream.
- *
- * param type the stream type to get the volume of (e.g. STREAM_MUSIC)
- * return the current volume (0-100)
- */
- public static native int getVolume(int type);
-
/*
* Sets the microphone mute on or off.
*
@@ -101,17 +84,23 @@ public class AudioSystem
* it can route the audio appropriately.
* return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR
*/
- public static native int setMode(int mode);
-
+ /** @deprecated use {@link #setPhoneState(int)} */
+ public static int setMode(int mode) {
+ return AUDIO_STATUS_ERROR;
+ }
/*
* Returns the current audio mode.
*
* return the current audio mode (NORMAL, RINGTONE, or IN_CALL).
* Returns the current current audio state from the HAL.
+ *
*/
- public static native int getMode();
+ /** @deprecated Do not use. */
+ public static int getMode() {
+ return MODE_INVALID;
+ }
- /* modes for setMode/getMode/setRoute/getRoute */
+ /* modes for setPhoneState */
public static final int MODE_INVALID = -2;
public static final int MODE_CURRENT = -1;
public static final int MODE_NORMAL = 0;
@@ -121,15 +110,20 @@ public class AudioSystem
/* Routing bits for setRouting/getRouting API */
- public static final int ROUTE_EARPIECE = (1 << 0);
- public static final int ROUTE_SPEAKER = (1 << 1);
-
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_EARPIECE = (1 << 0);
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_SPEAKER = (1 << 1);
/** @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */
@Deprecated public static final int ROUTE_BLUETOOTH = (1 << 2);
- public static final int ROUTE_BLUETOOTH_SCO = (1 << 2);
- public static final int ROUTE_HEADSET = (1 << 3);
- public static final int ROUTE_BLUETOOTH_A2DP = (1 << 4);
- public static final int ROUTE_ALL = 0xFFFFFFFF;
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_BLUETOOTH_SCO = (1 << 2);
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_HEADSET = (1 << 3);
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = (1 << 4);
+ /** @deprecated */
+ @Deprecated public static final int ROUTE_ALL = 0xFFFFFFFF;
/*
* Sets the audio routing for a specified mode
@@ -141,7 +135,10 @@ public class AudioSystem
* ROUTE_xxx types. Unset bits indicate the route should be left unchanged
* return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR
*/
- public static native int setRouting(int mode, int routes, int mask);
+ /** @deprecated use {@link #setDeviceConnectionState(int,int,String)} */
+ public static int setRouting(int mode, int routes, int mask) {
+ return AUDIO_STATUS_ERROR;
+ }
/*
* Returns the current audio routing bit vector for a specified mode.
@@ -150,7 +147,10 @@ public class AudioSystem
* return an audio route bit vector that can be compared with ROUTE_xxx
* bits
*/
- public static native int getRouting(int mode);
+ /** @deprecated use {@link #getDeviceConnectionState(int,String)} */
+ public static int getRouting(int mode) {
+ return 0;
+ }
/*
* Checks whether any music is active.
@@ -160,17 +160,23 @@ public class AudioSystem
public static native boolean isMusicActive();
/*
- * Sets a generic audio configuration parameter. The use of these parameters
+ * Sets a group generic audio configuration parameters. The use of these parameters
* are platform dependant, see libaudio
*
- * ** Temporary interface - DO NOT USE
- *
- * TODO: Replace with a more generic key:value get/set mechanism
+ * param keyValuePairs list of parameters key value pairs in the form:
+ * key1=value1;key2=value2;...
+ */
+ public static native int setParameters(String keyValuePairs);
+
+ /*
+ * Gets a group generic audio configuration parameters. The use of these parameters
+ * are platform dependant, see libaudio
*
- * param key name of parameter to set. Must not be null.
- * param value value of parameter. Must not be null.
+ * param keys list of parameters
+ * return value: list of parameters key value pairs in the form:
+ * key1=value1;key2=value2;...
*/
- public static native void setParameter(String key, String value);
+ public static native String getParameters(String keys);
/*
private final static String TAG = "audio";
@@ -220,4 +226,68 @@ public class AudioSystem
mErrorCallback.onError(error);
}
}
+
+ /*
+ * AudioPolicyService methods
+ */
+
+ // output devices
+ public static final int DEVICE_OUT_EARPIECE = 0x1;
+ public static final int DEVICE_OUT_SPEAKER = 0x2;
+ public static final int DEVICE_OUT_WIRED_HEADSET = 0x4;
+ public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8;
+ public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10;
+ public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20;
+ public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40;
+ public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80;
+ public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100;
+ public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200;
+ public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
+ public static final int DEVICE_OUT_FM_HEADPHONE = 0x800;
+ public static final int DEVICE_OUT_FM_SPEAKER = 0x1000;
+ public static final int DEVICE_OUT_TTY = 0x2000;
+ public static final int DEVICE_OUT_DEFAULT = 0x8000;
+ // input devices
+ public static final int DEVICE_IN_COMMUNICATION = 0x10000;
+ public static final int DEVICE_IN_AMBIENT = 0x20000;
+ public static final int DEVICE_IN_BUILTIN_MIC1 = 0x40000;
+ public static final int DEVICE_IN_BUILTIN_MIC2 = 0x80000;
+ public static final int DEVICE_IN_MIC_ARRAY = 0x100000;
+ public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x200000;
+ public static final int DEVICE_IN_WIRED_HEADSET = 0x400000;
+ public static final int DEVICE_IN_AUX_DIGITAL = 0x800000;
+ public static final int DEVICE_IN_DEFAULT = 0x80000000;
+
+ // device states
+ public static final int DEVICE_STATE_UNAVAILABLE = 0;
+ public static final int DEVICE_STATE_AVAILABLE = 1;
+
+ // phone state
+ public static final int PHONE_STATE_OFFCALL = 0;
+ public static final int PHONE_STATE_RINGING = 1;
+ public static final int PHONE_STATE_INCALL = 2;
+
+ // config for setForceUse
+ public static final int FORCE_NONE = 0;
+ public static final int FORCE_SPEAKER = 1;
+ public static final int FORCE_HEADPHONES = 2;
+ public static final int FORCE_BT_SCO = 3;
+ public static final int FORCE_BT_A2DP = 4;
+ public static final int FORCE_WIRED_ACCESSORY = 5;
+ public static final int FORCE_DEFAULT = FORCE_NONE;
+
+ // usage for serForceUse
+ public static final int FOR_COMMUNICATION = 0;
+ public static final int FOR_MEDIA = 1;
+ public static final int FOR_RECORD = 2;
+
+ public static native int setDeviceConnectionState(int device, int state, String device_address);
+ public static native int getDeviceConnectionState(int device, String device_address);
+ public static native int setPhoneState(int state);
+ public static native int setRingerMode(int mode, int mask);
+ public static native int setForceUse(int usage, int config);
+ public static native int getForceUse(int usage);
+ public static native int initStreamVolume(int stream, int indexMin, int indexMax);
+ public static native int setStreamVolumeIndex(int stream, int index);
+ public static native int getStreamVolumeIndex(int stream);
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 5f1be9d..1e8d72f 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -120,7 +120,7 @@ public class AudioTrack
public static final int ERROR_INVALID_OPERATION = -3;
private static final int ERROR_NATIVESETUP_AUDIOSYSTEM = -16;
- private static final int ERROR_NATIVESETUP_INVALIDCHANNELCOUNT = -17;
+ private static final int ERROR_NATIVESETUP_INVALIDCHANNELMASK = -17;
private static final int ERROR_NATIVESETUP_INVALIDFORMAT = -18;
private static final int ERROR_NATIVESETUP_INVALIDSTREAMTYPE = -19;
private static final int ERROR_NATIVESETUP_NATIVEINITFAILED = -20;
@@ -181,10 +181,15 @@ public class AudioTrack
*/
private int mSampleRate = 22050;
/**
- * The number of input audio channels (1 is mono, 2 is stereo).
+ * The number of audio output channels (1 is mono, 2 is stereo).
*/
private int mChannelCount = 1;
/**
+ * The audio channel mask.
+ */
+ private int mChannels = AudioFormat.CHANNEL_OUT_MONO;
+
+ /**
* The type of the audio stream to play. See
* {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
* {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
@@ -198,7 +203,7 @@ public class AudioTrack
/**
* The current audio channel configuration.
*/
- private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ private int mChannelConfiguration = AudioFormat.CHANNEL_OUT_MONO;
/**
* The encoding of the audio samples.
* @see AudioFormat#ENCODING_PCM_8BIT
@@ -235,8 +240,8 @@ public class AudioTrack
* @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
* not limited to) 44100, 22050 and 11025.
* @param channelConfig describes the configuration of the audio channels.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
- * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+ * See {@link AudioFormat#CHANNEL_OUT_MONO} and
+ * {@link AudioFormat#CHANNEL_OUT_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT} and
* {@link AudioFormat#ENCODING_PCM_8BIT}
@@ -266,7 +271,7 @@ public class AudioTrack
// native initialization
int initResult = native_setup(new WeakReference<AudioTrack>(this),
- mStreamType, mSampleRate, mChannelCount, mAudioFormat,
+ mStreamType, mSampleRate, mChannels, mAudioFormat,
mNativeBufferSizeInBytes, mDataLoadMode);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
@@ -286,6 +291,7 @@ public class AudioTrack
// postconditions:
// mStreamType is valid
// mChannelCount is valid
+ // mChannels is valid
// mAudioFormat is valid
// mSampleRate is valid
// mDataLoadMode is valid
@@ -298,7 +304,8 @@ public class AudioTrack
&& (streamType != AudioManager.STREAM_RING) && (streamType != AudioManager.STREAM_SYSTEM)
&& (streamType != AudioManager.STREAM_VOICE_CALL)
&& (streamType != AudioManager.STREAM_NOTIFICATION)
- && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)) {
+ && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)
+ && (streamType != AudioManager.STREAM_DTMF)) {
throw (new IllegalArgumentException("Invalid stream type."));
} else {
mStreamType = streamType;
@@ -315,18 +322,23 @@ public class AudioTrack
//--------------
// channel config
+ mChannelConfiguration = channelConfig;
+
switch (channelConfig) {
- case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT:
+ case AudioFormat.CHANNEL_OUT_DEFAULT: //AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
+ case AudioFormat.CHANNEL_OUT_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
mChannelCount = 1;
- mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ mChannels = AudioFormat.CHANNEL_OUT_MONO;
break;
+ case AudioFormat.CHANNEL_OUT_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
mChannelCount = 2;
- mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ mChannels = AudioFormat.CHANNEL_OUT_STEREO;
break;
default:
mChannelCount = 0;
+ mChannels = AudioFormat.CHANNEL_INVALID;
mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_INVALID;
throw(new IllegalArgumentException("Unsupported channel configuration."));
}
@@ -452,8 +464,8 @@ public class AudioTrack
/**
* Returns the configured channel configuration.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO}
- * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}.
+ * See {@link AudioFormat#CHANNEL_OUT_MONO}
+ * and {@link AudioFormat#CHANNEL_OUT_STEREO}.
*/
public int getChannelConfiguration() {
return mChannelConfiguration;
@@ -531,8 +543,8 @@ public class AudioTrack
* the expected frequency at which the buffer will be refilled with additional data to play.
* @param sampleRateInHz the sample rate expressed in Hertz.
* @param channelConfig describes the configuration of the audio channels.
- * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
- * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+ * See {@link AudioFormat#CHANNEL_OUT_MONO} and
+ * {@link AudioFormat#CHANNEL_OUT_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT} and
* {@link AudioFormat#ENCODING_PCM_8BIT}
@@ -544,9 +556,11 @@ public class AudioTrack
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
int channelCount = 0;
switch(channelConfig) {
+ case AudioFormat.CHANNEL_OUT_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
channelCount = 1;
break;
+ case AudioFormat.CHANNEL_OUT_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
channelCount = 2;
break;
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 6d7c0ae..d578c81 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -18,6 +18,9 @@ package android.media;
import android.util.Log;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@@ -59,7 +62,7 @@ public class ExifInterface {
// The Exif tag names
public static final String TAG_ORIENTATION = "Orientation";
- public static final String TAG_DATE_TIME_ORIGINAL = "DateTimeOriginal";
+ public static final String TAG_DATETIME = "DateTime";
public static final String TAG_MAKE = "Make";
public static final String TAG_MODEL = "Model";
public static final String TAG_FLASH = "Flash";
@@ -321,6 +324,28 @@ public class ExifInterface {
return latlng;
}
+ private static SimpleDateFormat sFormatter =
+ new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
+
+ // Returns number of milliseconds since Jan. 1, 1970, midnight GMT.
+ // Returns -1 if the date time information if not available.
+ public static long getDateTime(HashMap<String, String> exifData) {
+ if (exifData == null) {
+ return -1;
+ }
+
+ String dateTimeString = exifData.get(ExifInterface.TAG_DATETIME);
+ if (dateTimeString == null) return -1;
+
+ ParsePosition pos = new ParsePosition(0);
+ try {
+ Date date = sFormatter.parse(dateTimeString, pos);
+ return date.getTime();
+ } catch (IllegalArgumentException ex) {
+ return -1;
+ }
+ }
+
public static float convertRationalLatLonToFloat(
String rationalString, String ref) {
try {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 9a8264f..d3d2d29 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -29,9 +29,9 @@ interface IAudioService {
void setStreamVolume(int streamType, int index, int flags);
- void setStreamSolo(int streamType, boolean state, IBinder cb);
+ void setStreamSolo(int streamType, boolean state, IBinder cb);
- void setStreamMute(int streamType, boolean state, IBinder cb);
+ void setStreamMute(int streamType, boolean state, IBinder cb);
int getStreamVolume(int streamType);
@@ -46,23 +46,11 @@ interface IAudioService {
int getVibrateSetting(int vibrateType);
boolean shouldVibrate(int vibrateType);
-
- void setMicrophoneMute(boolean on);
-
- boolean isMicrophoneMute();
void setMode(int mode);
int getMode();
- void setRouting(int mode, int routes, int mask);
-
- int getRouting(int mode);
-
- boolean isMusicActive();
-
- void setParameter(String key, String value);
-
oneway void playSoundEffect(int effectType);
oneway void playSoundEffectVolume(int effectType, float volume);
@@ -72,4 +60,12 @@ interface IAudioService {
oneway void unloadSoundEffects();
oneway void reloadAudioSettings();
+
+ void setSpeakerphoneOn(boolean on);
+
+ boolean isSpeakerphoneOn();
+
+ void setBluetoothScoOn(boolean on);
+
+ boolean isBluetoothScoOn();
}
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index d75d81d..1570db4 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -89,7 +89,7 @@ public class JetPlayer
// Jet rendering audio parameters
private static final int JET_OUTPUT_RATE = 22050; // _SAMPLE_RATE_22050 in Android.mk
private static final int JET_OUTPUT_CHANNEL_CONFIG =
- AudioFormat.CHANNEL_CONFIGURATION_STEREO; // NUM_OUTPUT_CHANNELS=2 in Android.mk
+ AudioFormat.CHANNEL_OUT_STEREO; // NUM_OUTPUT_CHANNELS=2 in Android.mk
//--------------------------------------------
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 8be11df..03ffc67 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -41,8 +41,9 @@ public class MediaFile {
public static final int FILE_TYPE_AWB = 5;
public static final int FILE_TYPE_WMA = 6;
public static final int FILE_TYPE_OGG = 7;
+ public static final int FILE_TYPE_AAC = 8;
private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3;
- private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_OGG;
+ private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_AAC;
// MIDI file types
public static final int FILE_TYPE_MID = 11;
@@ -57,8 +58,9 @@ public class MediaFile {
public static final int FILE_TYPE_3GPP = 23;
public static final int FILE_TYPE_3GPP2 = 24;
public static final int FILE_TYPE_WMV = 25;
+ public static final int FILE_TYPE_ASF = 26;
private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
- private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WMV;
+ private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_ASF;
// Image file types
public static final int FILE_TYPE_JPEG = 31;
@@ -104,6 +106,7 @@ public class MediaFile {
addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma");
addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
addFileType("OGA", FILE_TYPE_OGG, "application/ogg");
+ addFileType("AAC", FILE_TYPE_AAC, "audio/aac");
addFileType("MID", FILE_TYPE_MID, "audio/midi");
addFileType("MIDI", FILE_TYPE_MID, "audio/midi");
@@ -121,6 +124,7 @@ public class MediaFile {
addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv");
+ addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf");
addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg");
addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg");
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 3a49a5f..cecf4f8 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -35,6 +35,7 @@ public class MediaMetadataRetriever
{
static {
System.loadLibrary("media_jni");
+ native_init();
}
// The field below is accessed by native methods
@@ -211,7 +212,8 @@ public class MediaMetadataRetriever
* allocated internally.
*/
public native void release();
- private native void native_setup();
+ private native void native_setup();
+ private static native void native_init();
private native final void native_finalize();
@@ -252,5 +254,6 @@ public class MediaMetadataRetriever
public static final int METADATA_KEY_VIDEO_FORMAT = 18;
public static final int METADATA_KEY_VIDEO_HEIGHT = 19;
public static final int METADATA_KEY_VIDEO_WIDTH = 20;
+ public static final int METADATA_KEY_WRITER = 21;
// Add more here...
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 3b46d69..6a9a9bd 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -23,6 +23,7 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.util.Log;
@@ -33,7 +34,7 @@ import android.media.AudioManager;
import java.io.FileDescriptor;
import java.io.IOException;
-
+import java.util.Set;
import java.lang.ref.WeakReference;
/**
@@ -430,11 +431,49 @@ import java.lang.ref.WeakReference;
*/
public class MediaPlayer
{
+ /**
+ Constant to retrieve only the new metadata since the last
+ call.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean METADATA_UPDATE_ONLY = true;
+
+ /**
+ Constant to retrieve all the metadata.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean METADATA_ALL = false;
+
+ /**
+ Constant to enable the metadata filter during retrieval.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean APPLY_METADATA_FILTER = true;
+
+ /**
+ Constant to disable the metadata filter during retrieval.
+ // FIXME: unhide.
+ // FIXME: add link to getMetadata(boolean, boolean)
+ {@hide}
+ */
+ public static final boolean BYPASS_METADATA_FILTER = false;
+
static {
System.loadLibrary("media_jni");
+ native_init();
}
private final static String TAG = "MediaPlayer";
+ // Name of the remote interface for the media player. Must be kept
+ // in sync with the 2nd parameter of the IMPLEMENT_META_INTERFACE
+ // macro invocation in IMediaPlayer.cpp
+ private final static String IMEDIA_PLAYER = "android.media.IMediaPlayer";
private int mNativeContext; // accessed by native methods
private int mListenerContext; // accessed by native methods
@@ -475,6 +514,43 @@ public class MediaPlayer
private native void _setVideoSurface();
/**
+ * Create a request parcel which can be routed to the native media
+ * player using {@link #invoke(Parcel, Parcel)}. The Parcel
+ * returned has the proper InterfaceToken set. The caller should
+ * not overwrite that token, i.e it can only append data to the
+ * Parcel.
+ *
+ * @return A parcel suitable to hold a request for the native
+ * player.
+ */
+ public Parcel newRequest() {
+ Parcel parcel = Parcel.obtain();
+ parcel.writeInterfaceToken(IMEDIA_PLAYER);
+ return parcel;
+ }
+
+ /**
+ * Invoke a generic method on the native player using opaque
+ * parcels for the request and reply. Both payloads' format is a
+ * convention between the java caller and the native player.
+ * Must be called after setDataSource to make sure a native player
+ * exists.
+ *
+ * @param request Parcel with the data for the extension. The
+ * caller must use {@link #newRequest()} to get one.
+ *
+ * @param reply Output parcel with the data returned by the
+ * native player.
+ *
+ * @return The status code see utils/Errors.h
+ */
+ public int invoke(Parcel request, Parcel reply) {
+ int retcode = native_invoke(request, reply);
+ reply.setDataPosition(0);
+ return retcode;
+ }
+
+ /**
* Sets the SurfaceHolder to use for displaying the video portion of the media.
* This call is optional. Not calling it when playing back a video will
* result in only the audio track being played.
@@ -838,6 +914,89 @@ public class MediaPlayer
public native int getDuration();
/**
+ * Gets the media metadata.
+ *
+ * @param update_only controls whether the full set of available
+ * metadata is returned or just the set that changed since the
+ * last call. See {@see #METADATA_UPDATE_ONLY} and {@see
+ * #METADATA_ALL}.
+ *
+ * @param apply_filter if true only metadata that matches the
+ * filter is returned. See {@see #APPLY_METADATA_FILTER} and {@see
+ * #BYPASS_METADATA_FILTER}.
+ *
+ * @return The metadata, possibly empty. null if an error occured.
+ // FIXME: unhide.
+ * {@hide}
+ */
+ public Metadata getMetadata(final boolean update_only,
+ final boolean apply_filter) {
+ Parcel reply = Parcel.obtain();
+ Metadata data = new Metadata();
+
+ if (!native_getMetadata(update_only, apply_filter, reply)) {
+ reply.recycle();
+ return null;
+ }
+
+ // Metadata takes over the parcel, don't recycle it unless
+ // there is an error.
+ if (!data.parse(reply)) {
+ reply.recycle();
+ return null;
+ }
+ return data;
+ }
+
+ /**
+ * Set a filter for the metadata update notification and update
+ * retrieval. The caller provides 2 set of metadata keys, allowed
+ * and blocked. The blocked set always takes precedence over the
+ * allowed one.
+ * Metadata.MATCH_ALL and Metadata.MATCH_NONE are 2 sets available as
+ * shorthands to allow/block all or no metadata.
+ *
+ * By default, there is no filter set.
+ *
+ * @param allow Is the set of metadata the client is interested
+ * in receiving new notifications for.
+ * @param block Is the set of metadata the client is not interested
+ * in receiving new notifications for.
+ * @return The call status code.
+ *
+ // FIXME: unhide.
+ * {@hide}
+ */
+ public int setMetadataFilter(Set<Integer> allow, Set<Integer> block) {
+ // Do our serialization manually instead of calling
+ // Parcel.writeArray since the sets are made of the same type
+ // we avoid paying the price of calling writeValue (used by
+ // writeArray) which burns an extra int per element to encode
+ // the type.
+ Parcel request = newRequest();
+
+ // The parcel starts already with an interface token. There
+ // are 2 filters. Each one starts with a 4bytes number to
+ // store the len followed by a number of int (4 bytes as well)
+ // representing the metadata type.
+ int capacity = request.dataSize() + 4 * (1 + allow.size() + 1 + block.size());
+
+ if (request.dataCapacity() < capacity) {
+ request.setDataCapacity(capacity);
+ }
+
+ request.writeInt(allow.size());
+ for(Integer t: allow) {
+ request.writeInt(t);
+ }
+ request.writeInt(block.size());
+ for(Integer t: block) {
+ request.writeInt(t);
+ }
+ return native_setMetadataFilter(request);
+ }
+
+ /**
* Releases resources associated with this MediaPlayer object.
* It is considered good practice to call this method when you're
* done using the MediaPlayer.
@@ -915,8 +1074,46 @@ public class MediaPlayer
*/
public native Bitmap getFrameAt(int msec) throws IllegalStateException;
+ /**
+ * @param request Parcel destinated to the media player. The
+ * Interface token must be set to the IMediaPlayer
+ * one to be routed correctly through the system.
+ * @param reply[out] Parcel that will contain the reply.
+ * @return The status code.
+ */
+ private native final int native_invoke(Parcel request, Parcel reply);
+
+
+ /**
+ * @param update_only If true fetch only the set of metadata that have
+ * changed since the last invocation of getMetadata.
+ * The set is built using the unfiltered
+ * notifications the native player sent to the
+ * MediaPlayerService during that period of
+ * time. If false, all the metadatas are considered.
+ * @param apply_filter If true, once the metadata set has been built based on
+ * the value update_only, the current filter is applied.
+ * @param reply[out] On return contains the serialized
+ * metadata. Valid only if the call was successful.
+ * @return The status code.
+ */
+ private native final boolean native_getMetadata(boolean update_only,
+ boolean apply_filter,
+ Parcel reply);
+
+ /**
+ * @param request Parcel with the 2 serialized lists of allowed
+ * metadata types followed by the one to be
+ * dropped. Each list starts with an integer
+ * indicating the number of metadata type elements.
+ * @return The status code.
+ */
+ private native final int native_setMetadataFilter(Parcel request);
+
+ private static native final void native_init();
private native final void native_setup(Object mediaplayer_this);
private native final void native_finalize();
+
@Override
protected void finalize() { native_finalize(); }
@@ -1254,6 +1451,11 @@ public class MediaPlayer
*/
public static final int MEDIA_INFO_NOT_SEEKABLE = 801;
+ /** A new set of metadata is available.
+ * @see android.media.MediaPlayer.OnInfoListener
+ */
+ public static final int MEDIA_INFO_METADATA_UPDATE = 802;
+
/**
* Interface definition of a callback to be invoked to communicate some
* info and/or warning about the media or its playback.
@@ -1270,6 +1472,7 @@ public class MediaPlayer
* <li>{@link #MEDIA_INFO_VIDEO_TRACK_LAGGING}
* <li>{@link #MEDIA_INFO_BAD_INTERLEAVING}
* <li>{@link #MEDIA_INFO_NOT_SEEKABLE}
+ * <li>{@link #MEDIA_INFO_METADATA_UPDATE}
* </ul>
* @param extra an extra code, specific to the info. Typically
* implementation dependant.
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index be4b489..9bb00c6 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -57,6 +57,7 @@ public class MediaRecorder
{
static {
System.loadLibrary("media_jni");
+ native_init();
}
private final static String TAG = "MediaRecorder";
@@ -167,7 +168,7 @@ public class MediaRecorder
/** The following formats are audio only .aac or .amr formats **/
/** @deprecated Deprecated in favor of AMR_NB */
- /** @todo change link when AMR_NB is exposed. Deprecated in favor of {@link MediaRecorder.OutputFormat#AMR_NB} */
+ /** TODO: change link when AMR_NB is exposed. Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB */
public static final int RAW_AMR = 3;
/** @hide AMR NB file format */
public static final int AMR_NB = 3;
@@ -655,6 +656,8 @@ public class MediaRecorder
*/
public native void release();
+ private static native final void native_init();
+
private native final void native_setup(Object mediarecorder_this) throws IllegalStateException;
private native final void native_finalize();
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 8db874a..3d5aae3 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -99,6 +99,7 @@ public class MediaScanner
{
static {
System.loadLibrary("media_jni");
+ native_init();
}
private final static String TAG = "MediaScanner";
@@ -307,10 +308,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 +374,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();
@@ -389,6 +396,7 @@ public class MediaScanner
private String mPath;
private long mLastModified;
private long mFileSize;
+ private String mWriter;
public FileCacheEntry beginFile(String path, String mimeType, long lastModified, long fileSize) {
@@ -472,6 +480,7 @@ public class MediaScanner
mDuration = 0;
mPath = path;
mLastModified = lastModified;
+ mWriter = null;
return entry;
}
@@ -586,6 +595,8 @@ public class MediaScanner
mTrack = (num * 1000) + (mTrack % 1000);
} else if (name.equalsIgnoreCase("duration")) {
mDuration = parseSubstring(value, 0, 0);
+ } else if (name.equalsIgnoreCase("writer") || name.startsWith("writer;")) {
+ mWriter = value.trim();
}
}
@@ -709,6 +720,11 @@ public class MediaScanner
values.put(Images.Media.LATITUDE, latlng[0]);
values.put(Images.Media.LONGITUDE, latlng[1]);
}
+
+ long time = ExifInterface.getDateTime(exifData);
+ if (time != -1) {
+ values.put(Images.Media.DATE_TAKEN, time);
+ }
}
}
@@ -779,6 +795,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;
@@ -1412,6 +1434,7 @@ public class MediaScanner
public native byte[] extractAlbumArt(FileDescriptor fd);
+ private static native final void native_init();
private native final void native_setup();
private native final void native_finalize();
@Override
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
new file mode 100644
index 0000000..bd25da2
--- /dev/null
+++ b/media/java/android/media/Metadata.java
@@ -0,0 +1,418 @@
+/*
+ * 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.media;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.TimeZone;
+
+
+/**
+ Class to hold the media's metadata. Metadata are used
+ for human consumption and can be embedded in the media (e.g
+ shoutcast) or available from an external source. The source can be
+ local (e.g thumbnail stored in the DB) or remote (e.g caption
+ server).
+
+ Metadata is like a Bundle. It is sparse and each key can occur at
+ most once. The key is an integer and the value is the actual metadata.
+
+ The caller is expected to know the type of the metadata and call
+ the right get* method to fetch its value.
+
+ // FIXME: unhide.
+ {@hide}
+ */
+public class Metadata
+{
+ // The metadata are keyed using integers rather than more heavy
+ // weight strings. We considered using Bundle to ship the metadata
+ // between the native layer and the java layer but dropped that
+ // option since keeping in sync a native implementation of Bundle
+ // and the java one would be too burdensome. Besides Bundle uses
+ // String for its keys.
+ // The key range [0 8192) is reserved for the system.
+ //
+ // We manually serialize the data in Parcels. For large memory
+ // blob (bitmaps, raw pictures) we use MemoryFile which allow the
+ // client to make the data purge-able once it is done with it.
+ //
+
+ public static final int ANY = 0; // Never used for metadata returned, only for filtering.
+ // Keep in sync with kAny in MediaPlayerService.cpp
+
+ // TODO: Should we use numbers compatible with the metadata retriever?
+ public static final int TITLE = 1; // String
+ public static final int COMMENT = 2; // String
+ public static final int COPYRIGHT = 3; // String
+ public static final int ALBUM = 4; // String
+ public static final int ARTIST = 5; // String
+ public static final int AUTHOR = 6; // String
+ public static final int COMPOSER = 7; // String
+ public static final int GENRE = 8; // String
+ public static final int DATE = 9; // Date
+ public static final int DURATION = 10; // Integer(millisec)
+ public static final int CD_TRACK_NUM = 11; // Integer 1-based
+ public static final int CD_TRACK_MAX = 12; // Integer
+ public static final int RATING = 13; // String
+ public static final int ALBUM_ART = 14; // byte[]
+ public static final int VIDEO_FRAME = 15; // Bitmap
+ public static final int CAPTION = 16; // TimedText
+
+ public static final int BIT_RATE = 17; // Integer, Aggregate rate of
+ // all the streams in bps.
+
+ public static final int AUDIO_BIT_RATE = 18; // Integer, bps
+ public static final int VIDEO_BIT_RATE = 19; // Integer, bps
+ public static final int AUDIO_SAMPLE_RATE = 20; // Integer, Hz
+ public static final int VIDEO_FRAME_RATE = 21; // Integer, Hz
+
+ // See RFC2046 and RFC4281.
+ public static final int MIME_TYPE = 22; // String
+ public static final int AUDIO_CODEC = 23; // String
+ public static final int VIDEO_CODEC = 24; // String
+
+ public static final int VIDEO_HEIGHT = 25; // Integer
+ public static final int VIDEO_WIDTH = 26; // Integer
+ public static final int NUM_TRACKS = 27; // Integer
+ public static final int DRM_CRIPPLED = 28; // Boolean
+
+ // Playback capabilities.
+ public static final int PAUSE_AVAILABLE = 29; // Boolean
+ public static final int SEEK_BACKWARD_AVAILABLE = 30; // Boolean
+ public static final int SEEK_FORWARD_AVAILABLE = 31; // Boolean
+
+ private static final int LAST_SYSTEM = 31;
+ private static final int FIRST_CUSTOM = 8192;
+
+ // Shorthands to set the MediaPlayer's metadata filter.
+ public static final Set<Integer> MATCH_NONE = Collections.EMPTY_SET;
+ public static final Set<Integer> MATCH_ALL = Collections.singleton(ANY);
+
+ public static final int STRING_VAL = 1;
+ public static final int INTEGER_VAL = 2;
+ public static final int BOOLEAN_VAL = 3;
+ public static final int LONG_VAL = 4;
+ public static final int DOUBLE_VAL = 5;
+ public static final int TIMED_TEXT_VAL = 6;
+ public static final int DATE_VAL = 7;
+ public static final int BYTE_ARRAY_VAL = 8;
+ // FIXME: misses a type for shared heap is missing (MemoryFile).
+ // FIXME: misses a type for bitmaps.
+ private static final int LAST_TYPE = 8;
+
+ private static final String TAG = "media.Metadata";
+ private static final int kInt32Size = 4;
+ private static final int kMetaHeaderSize = 2 * kInt32Size; // size + marker
+ private static final int kRecordHeaderSize = 3 * kInt32Size; // size + id + type
+
+ private static final int kMetaMarker = 0x4d455441; // 'M' 'E' 'T' 'A'
+
+ // After a successful parsing, set the parcel with the serialized metadata.
+ private Parcel mParcel;
+
+ // Map to associate a Metadata key (e.g TITLE) with the offset of
+ // the record's payload in the parcel.
+ // Used to look up if a key was present too.
+ // Key: Metadata ID
+ // Value: Offset of the metadata type field in the record.
+ private final HashMap<Integer, Integer> mKeyToPosMap =
+ new HashMap<Integer, Integer>();
+
+ /**
+ * Helper class to hold a triple (time, duration, text). Can be used to
+ * implement caption.
+ */
+ public class TimedText {
+ private Date mTime;
+ private int mDuration; // millisec
+ private String mText;
+
+ public TimedText(Date time, int duration, String text) {
+ mTime = time;
+ mDuration = duration;
+ mText = text;
+ }
+
+ public String toString() {
+ StringBuilder res = new StringBuilder(80);
+ res.append(mTime).append("-").append(mDuration)
+ .append(":").append(mText);
+ return res.toString();
+ }
+ }
+
+ public Metadata() { }
+
+ /**
+ * Go over all the records, collecting metadata keys and records'
+ * type field offset in the Parcel. These are stored in
+ * mKeyToPosMap for latter retrieval.
+ * Format of a metadata record:
+ <pre>
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | record size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | metadata key | // TITLE
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | metadata type | // STRING_VAL
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ | .... metadata payload .... |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ </pre>
+ * @param parcel With the serialized records.
+ * @param bytesLeft How many bytes in the parcel should be processed.
+ * @return false if an error occurred during parsing.
+ */
+ private boolean scanAllRecords(Parcel parcel, int bytesLeft) {
+ int recCount = 0;
+ boolean error = false;
+
+ mKeyToPosMap.clear();
+ while (bytesLeft > kRecordHeaderSize) {
+ final int start = parcel.dataPosition();
+ // Check the size.
+ final int size = parcel.readInt();
+
+ if (size <= kRecordHeaderSize) { // at least 1 byte should be present.
+ Log.e(TAG, "Record is too short");
+ error = true;
+ break;
+ }
+
+ // Check the metadata key.
+ final int metadataId = parcel.readInt();
+ if (!checkMetadataId(metadataId)) {
+ error = true;
+ break;
+ }
+
+ // Store the record offset which points to the type
+ // field so we can later on read/unmarshall the record
+ // payload.
+ if (mKeyToPosMap.containsKey(metadataId)) {
+ Log.e(TAG, "Duplicate metadata ID found");
+ error = true;
+ break;
+ }
+
+ mKeyToPosMap.put(metadataId, parcel.dataPosition());
+
+ // Check the metadata type.
+ final int metadataType = parcel.readInt();
+ if (metadataType <= 0 || metadataType > LAST_TYPE) {
+ Log.e(TAG, "Invalid metadata type " + metadataType);
+ error = true;
+ break;
+ }
+
+ // Skip to the next one.
+ parcel.setDataPosition(start + size);
+ bytesLeft -= size;
+ ++recCount;
+ }
+
+ if (0 != bytesLeft || error) {
+ Log.e(TAG, "Ran out of data or error on record " + recCount);
+ mKeyToPosMap.clear();
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Check a parcel containing metadata is well formed. The header
+ * is checked as well as the individual records format. However, the
+ * data inside the record is not checked because we do lazy access
+ * (we check/unmarshall only data the user asks for.)
+ *
+ * Format of a metadata parcel:
+ <pre>
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | metadata total size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 'M' | 'E' | 'T' | 'A' |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ | .... metadata records .... |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ </pre>
+ *
+ * @param parcel With the serialized data. Metadata keeps a
+ * reference on it to access it later on. The caller
+ * should not modify the parcel after this call (and
+ * not call recycle on it.)
+ * @return false if an error occurred.
+ */
+ public boolean parse(Parcel parcel) {
+ if (parcel.dataAvail() < kMetaHeaderSize) {
+ Log.e(TAG, "Not enough data " + parcel.dataAvail());
+ return false;
+ }
+
+ final int pin = parcel.dataPosition(); // to roll back in case of errors.
+ final int size = parcel.readInt();
+
+ // The extra kInt32Size below is to account for the int32 'size' just read.
+ if (parcel.dataAvail() + kInt32Size < size || size < kMetaHeaderSize) {
+ Log.e(TAG, "Bad size " + size + " avail " + parcel.dataAvail() + " position " + pin);
+ parcel.setDataPosition(pin);
+ return false;
+ }
+
+ // Checks if the 'M' 'E' 'T' 'A' marker is present.
+ final int kShouldBeMetaMarker = parcel.readInt();
+ if (kShouldBeMetaMarker != kMetaMarker ) {
+ Log.e(TAG, "Marker missing " + Integer.toHexString(kShouldBeMetaMarker));
+ parcel.setDataPosition(pin);
+ return false;
+ }
+
+ // Scan the records to collect metadata ids and offsets.
+ if (!scanAllRecords(parcel, size - kMetaHeaderSize)) {
+ parcel.setDataPosition(pin);
+ return false;
+ }
+ mParcel = parcel;
+ return true;
+ }
+
+ /**
+ * @return The set of metadata ID found.
+ */
+ public Set<Integer> keySet() {
+ return mKeyToPosMap.keySet();
+ }
+
+ /**
+ * @return true if a value is present for the given key.
+ */
+ public boolean has(final int metadataId) {
+ if (!checkMetadataId(metadataId)) {
+ throw new IllegalArgumentException("Invalid key: " + metadataId);
+ }
+ return mKeyToPosMap.containsKey(metadataId);
+ }
+
+ // Accessors.
+ // Caller must make sure the key is present using the {@code has}
+ // method otherwise a RuntimeException will occur.
+
+ public String getString(final int key) {
+ checkType(key, STRING_VAL);
+ return mParcel.readString();
+ }
+
+ public int getInt(final int key) {
+ checkType(key, INTEGER_VAL);
+ return mParcel.readInt();
+ }
+
+ public boolean getBoolean(final int key) {
+ checkType(key, BOOLEAN_VAL);
+ return mParcel.readInt() == 1;
+ }
+
+ public long getLong(final int key) {
+ checkType(key, LONG_VAL);
+ return mParcel.readLong();
+ }
+
+ public double getDouble(final int key) {
+ checkType(key, DOUBLE_VAL);
+ return mParcel.readDouble();
+ }
+
+ public byte[] getByteArray(final int key) {
+ checkType(key, BYTE_ARRAY_VAL);
+ return mParcel.createByteArray();
+ }
+
+ public Date getDate(final int key) {
+ checkType(key, DATE_VAL);
+ final long timeSinceEpoch = mParcel.readLong();
+ final String timeZone = mParcel.readString();
+
+ if (timeZone.length() == 0) {
+ return new Date(timeSinceEpoch);
+ } else {
+ TimeZone tz = TimeZone.getTimeZone(timeZone);
+ Calendar cal = Calendar.getInstance(tz);
+
+ cal.setTimeInMillis(timeSinceEpoch);
+ return cal.getTime();
+ }
+ }
+
+ public TimedText getTimedText(final int key) {
+ checkType(key, TIMED_TEXT_VAL);
+ final Date startTime = new Date(mParcel.readLong()); // epoch
+ final int duration = mParcel.readInt(); // millisec
+
+ return new TimedText(startTime,
+ duration,
+ mParcel.readString());
+ }
+
+ // @return the last available system metadata id. Ids are
+ // 1-indexed.
+ public static int lastSytemId() { return LAST_SYSTEM; }
+
+ // @return the first available cutom metadata id.
+ public static int firstCustomId() { return FIRST_CUSTOM; }
+
+ // @return the last value of known type. Types are 1-indexed.
+ public static int lastType() { return LAST_TYPE; }
+
+ // Check val is either a system id or a custom one.
+ // @param val Metadata key to test.
+ // @return true if it is in a valid range.
+ private boolean checkMetadataId(final int val) {
+ if (val <= ANY || (LAST_SYSTEM < val && val < FIRST_CUSTOM)) {
+ Log.e(TAG, "Invalid metadata ID " + val);
+ return false;
+ }
+ return true;
+ }
+
+ // Check the type of the data match what is expected.
+ private void checkType(final int key, final int expectedType) {
+ final int pos = mKeyToPosMap.get(key);
+
+ mParcel.setDataPosition(pos);
+
+ final int type = mParcel.readInt();
+ if (type != expectedType) {
+ throw new IllegalStateException("Wrong type " + expectedType + " but got " + type);
+ }
+ }
+}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 42edae6..8481410 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
@@ -602,21 +605,6 @@ public class RingtoneManager {
Log.e(TAG, "Failed to open ringtone " + ringtoneUri);
}
- // Ringtone doesn't exist, use the fallback ringtone.
- try {
- AssetFileDescriptor afd = context.getResources().openRawResourceFd(
- com.android.internal.R.raw.fallbackring);
- if (afd != null) {
- Ringtone r = new Ringtone(context);
- r.open(afd);
- afd.close();
- return r;
- }
- } catch (Exception ex) {
- }
-
- // we should never get here
- Log.e(TAG, "unable to find a usable ringtone");
return null;
}
@@ -627,15 +615,16 @@ 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)
*/
public static Uri getActualDefaultRingtoneUri(Context context, int type) {
String setting = getSettingForType(type);
if (setting == null) return null;
- final String uriString = Settings.System.getString(context.getContentResolver(), setting);
- return uriString != null ? Uri.parse(uriString) : getValidRingtoneUri(context);
+ final String uriString = Settings.System.getString(context.getContentResolver(), setting);
+ return uriString != null ? Uri.parse(uriString) : null;
}
/**
@@ -643,14 +632,16 @@ 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)
*/
public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
String setting = getSettingForType(type);
if (setting == null) return;
- Settings.System.putString(context.getContentResolver(), setting, ringtoneUri.toString());
+ Settings.System.putString(context.getContentResolver(), setting,
+ ringtoneUri != null ? ringtoneUri.toString() : null);
}
private static String getSettingForType(int type) {
@@ -658,6 +649,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;
}
@@ -677,8 +670,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) {
@@ -688,6 +682,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;
}
@@ -707,6 +703,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/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java
index e5ee9a3..c60a1ac 100644
--- a/media/java/android/media/ToneGenerator.java
+++ b/media/java/android/media/ToneGenerator.java
@@ -724,9 +724,9 @@ public class ToneGenerator
public static final int TONE_CDMA_SIGNAL_OFF = 98;
/** Maximum volume, for use with {@link #ToneGenerator(int,int)} */
- public static final int MAX_VOLUME = AudioSystem.MAX_VOLUME;
+ public static final int MAX_VOLUME = 100;
/** Minimum volume setting, for use with {@link #ToneGenerator(int,int)} */
- public static final int MIN_VOLUME = AudioSystem.MIN_VOLUME;
+ public static final int MIN_VOLUME = 0;
/**
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 8ee0cbd..49a82e6 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -12,20 +12,20 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libopencore_player \
- libopencore_author \
libomx_amrenc_sharedlibrary \
libandroid_runtime \
libnativehelper \
- libcutils \
libutils \
+ libbinder \
libmedia \
- libsgl \
+ libskia \
libui
LOCAL_STATIC_LIBRARIES :=
LOCAL_C_INCLUDES += \
external/tremor/Tremor \
+ frameworks/base/core/jni \
$(PV_INCLUDES) \
$(JNI_H_INCLUDE) \
$(call include-path-for, corecg graphics)
diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp
index 51cb6c7..c4dd07e 100644
--- a/media/jni/android_media_AmrInputStream.cpp
+++ b/media/jni/android_media_AmrInputStream.cpp
@@ -169,13 +169,6 @@ static JNINativeMethod gMethods[] = {
int register_android_media_AmrInputStream(JNIEnv *env)
{
const char* const kClassPathName = "android/media/AmrInputStream";
- jclass clazz;
-
- clazz = env->FindClass(kClassPathName);
- if (clazz == NULL) {
- LOGE("Can't find %s", kClassPathName);
- return -1;
- }
return AndroidRuntime::registerNativeMethods(env,
kClassPathName, gMethods, NELEM(gMethods));
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 4624a18..49f8cdd 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -40,6 +40,7 @@ struct fields_t {
static fields_t fields;
static Mutex sLock;
+static const char* const kClassPathName = "android/media/MediaMetadataRetriever";
static void process_media_retriever_call(JNIEnv *env, status_t opStatus, const char* exception, const char *message)
{
@@ -269,6 +270,36 @@ static void android_media_MediaMetadataRetriever_native_finalize(JNIEnv *env, jo
android_media_MediaMetadataRetriever_release(env, thiz);
}
+// This function gets a field ID, which in turn causes class initialization.
+// It is called from a static block in MediaMetadataRetriever, which won't run until the
+// first time an instance of this class is used.
+static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env)
+{
+ jclass clazz = env->FindClass(kClassPathName);
+ if (clazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaMetadataRetriever");
+ return;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaMetadataRetriever.mNativeContext");
+ return;
+ }
+
+ fields.bitmapClazz = env->FindClass("android/graphics/Bitmap");
+ if (fields.bitmapClazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/graphics/Bitmap");
+ return;
+ }
+
+ fields.bitmapConstructor = env->GetMethodID(fields.bitmapClazz, "<init>", "(IZ[B)V");
+ if (fields.bitmapConstructor == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find Bitmap constructor");
+ return;
+ }
+}
+
static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz)
{
LOGV("native_setup");
@@ -292,36 +323,13 @@ static JNINativeMethod nativeMethods[] = {
{"release", "()V", (void *)android_media_MediaMetadataRetriever_release},
{"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize},
{"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup},
+ {"native_init", "()V", (void *)android_media_MediaMetadataRetriever_native_init},
};
-// Register native mehtods with Android runtime environment
+// This function only registers the native methods, and is called from
+// JNI_OnLoad in android_media_MediaPlayer.cpp
int register_android_media_MediaMetadataRetriever(JNIEnv *env)
{
- static const char* const kClassPathName = "android/media/MediaMetadataRetriever";
- jclass clazz = env->FindClass(kClassPathName);
- if (clazz == NULL) {
- LOGE("Can't find class: %s", kClassPathName);
- return -1;
- }
-
- fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
- if (fields.context == NULL) {
- LOGE("Can't find MediaMetadataRetriever.mNativeContext");
- return -1;
- }
-
- fields.bitmapClazz = env->FindClass("android/graphics/Bitmap");
- if (fields.bitmapClazz == NULL) {
- LOGE("Bitmap class is not found");
- return -1;
- }
-
- fields.bitmapConstructor = env->GetMethodID(fields.bitmapClazz, "<init>", "(IZ[B)V");
- if (fields.bitmapConstructor == NULL) {
- LOGE("Bitmap constructor is not found");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods
- (env, kClassPathName, nativeMethods, NELEM(nativeMethods));
+ (env, kClassPathName, nativeMethods, NELEM(nativeMethods));
}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 6317fe2..df98de5 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -20,6 +20,7 @@
#include "utils/Log.h"
#include <media/mediaplayer.h>
+#include <media/MediaPlayerInterface.h>
#include <stdio.h>
#include <assert.h>
#include <limits.h>
@@ -30,6 +31,8 @@
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include "utils/Errors.h" // for status_t
+#include "android_util_Binder.h"
+#include <binder/Parcel.h>
// ----------------------------------------------------------------------------
@@ -98,10 +101,9 @@ void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2)
// ----------------------------------------------------------------------------
-static sp<Surface> get_surface(JNIEnv* env, jobject clazz)
+static Surface* get_surface(JNIEnv* env, jobject clazz)
{
- Surface* const p = (Surface*)env->GetIntField(clazz, fields.surface_native);
- return sp<Surface>(p);
+ return (Surface*)env->GetIntField(clazz, fields.surface_native);
}
static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
@@ -202,7 +204,7 @@ static void setVideoSurface(const sp<MediaPlayer>& mp, JNIEnv *env, jobject thiz
{
jobject surface = env->GetObjectField(thiz, fields.surface);
if (surface != NULL) {
- const sp<Surface>& native_surface = get_surface(env, surface);
+ const sp<Surface> native_surface = get_surface(env, surface);
LOGV("prepare: surface=%p (id=%d)",
native_surface.get(), native_surface->ID());
mp->setVideoSurface(native_surface);
@@ -242,7 +244,7 @@ android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
}
jobject surface = env->GetObjectField(thiz, fields.surface);
if (surface != NULL) {
- const sp<Surface>& native_surface = get_surface(env, surface);
+ const sp<Surface> native_surface = get_surface(env, surface);
LOGV("prepareAsync: surface=%p (id=%d)",
native_surface.get(), native_surface->ID());
mp->setVideoSurface(native_surface);
@@ -442,6 +444,119 @@ android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec)
return NULL;
}
+
+// Sends the request and reply parcels to the media player via the
+// binder interface.
+static jint
+android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
+ jobject java_request, jobject java_reply)
+{
+ sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
+ if (media_player == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return UNKNOWN_ERROR;
+ }
+
+
+ Parcel *request = parcelForJavaObject(env, java_request);
+ Parcel *reply = parcelForJavaObject(env, java_reply);
+
+ // Don't use process_media_player_call which use the async loop to
+ // report errors, instead returns the status.
+ return media_player->invoke(*request, reply);
+}
+
+// Sends the new filter to the client.
+static jint
+android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
+{
+ sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
+ if (media_player == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return UNKNOWN_ERROR;
+ }
+
+ Parcel *filter = parcelForJavaObject(env, request);
+
+ if (filter == NULL ) {
+ jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
+ return UNKNOWN_ERROR;
+ }
+
+ return media_player->setMetadataFilter(*filter);
+}
+
+static jboolean
+android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
+ jboolean apply_filter, jobject reply)
+{
+ sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
+ if (media_player == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return false;
+ }
+
+ Parcel *metadata = parcelForJavaObject(env, reply);
+
+ if (metadata == NULL ) {
+ jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
+ return false;
+ }
+
+ metadata->freeData();
+ // On return metadata is positioned at the beginning of the
+ // metadata. Note however that the parcel actually starts with the
+ // return code so you should not rewind the parcel using
+ // setDataPosition(0).
+ return media_player->getMetadata(update_only, apply_filter, metadata) == OK;
+}
+
+// This function gets some field IDs, which in turn causes class initialization.
+// It is called from a static block in MediaPlayer, which won't run until the
+// first time an instance of this class is used.
+static void
+android_media_MediaPlayer_native_init(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/media/MediaPlayer");
+ if (clazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaPlayer");
+ return;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mNativeContext");
+ return;
+ }
+
+ fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
+ "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ if (fields.post_event == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.postEventFromNative");
+ return;
+ }
+
+ fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
+ if (fields.surface == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mSurface");
+ return;
+ }
+
+ jclass surface = env->FindClass("android/view/Surface");
+ if (surface == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/view/Surface");
+ return;
+ }
+
+ fields.surface_native = env->GetFieldID(surface, "mSurface", "I");
+ if (fields.surface_native == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface.mSurface");
+ return;
+ }
+}
+
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
@@ -503,53 +618,19 @@ static JNINativeMethod gMethods[] = {
{"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
{"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
{"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
+ {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
+ {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
+ {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
+ {"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
};
static const char* const kClassPathName = "android/media/MediaPlayer";
+// This function only registers the native methods
static int register_android_media_MediaPlayer(JNIEnv *env)
{
- jclass clazz;
-
- clazz = env->FindClass("android/media/MediaPlayer");
- if (clazz == NULL) {
- LOGE("Can't find android/media/MediaPlayer");
- return -1;
- }
-
- fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
- if (fields.context == NULL) {
- LOGE("Can't find MediaPlayer.mNativeContext");
- return -1;
- }
-
- fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
- "(Ljava/lang/Object;IIILjava/lang/Object;)V");
- if (fields.post_event == NULL) {
- LOGE("Can't find MediaPlayer.postEventFromNative");
- return -1;
- }
-
- fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
- if (fields.surface == NULL) {
- LOGE("Can't find MediaPlayer.mSurface");
- return -1;
- }
-
- jclass surface = env->FindClass("android/view/Surface");
- if (surface == NULL) {
- LOGE("Can't find android/view/Surface");
- return -1;
- }
-
- fields.surface_native = env->GetFieldID(surface, "mSurface", "I");
- if (fields.surface_native == NULL) {
- LOGE("Can't find Surface fields");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaPlayer", gMethods, NELEM(gMethods));
}
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 0273a5a..cad65b3 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -276,7 +276,7 @@ static void
android_media_MediaRecorder_setVideoFrameRate(JNIEnv *env, jobject thiz, jint rate)
{
LOGV("setVideoFrameRate(%d)", rate);
- if (rate <= 0 || rate > MEDIA_RECORDER_MAX_FRAME_RATE) {
+ if (rate <= 0) {
jniThrowException(env, "java/lang/IllegalArgumentException", "invalid frame rate");
return;
}
@@ -371,6 +371,53 @@ android_media_MediaRecorder_release(JNIEnv *env, jobject thiz)
}
}
+// This function gets some field IDs, which in turn causes class initialization.
+// It is called from a static block in MediaRecorder, which won't run until the
+// first time an instance of this class is used.
+static void
+android_media_MediaRecorder_native_init(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/media/MediaRecorder");
+ if (clazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaRecorder");
+ return;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaRecorder.mNativeContext");
+ return;
+ }
+
+ fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
+ if (fields.surface == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaRecorder.mSurface");
+ return;
+ }
+
+ jclass surface = env->FindClass("android/view/Surface");
+ if (surface == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/view/Surface");
+ return;
+ }
+
+ fields.surface_native = env->GetFieldID(surface, "mSurface", "I");
+ if (fields.surface_native == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface.mSurface");
+ return;
+ }
+
+ fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
+ "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ if (fields.post_event == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "MediaRecorder.postEventFromNative");
+ return;
+ }
+}
+
+
static void
android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
@@ -418,55 +465,19 @@ static JNINativeMethod gMethods[] = {
{"getMaxAmplitude", "()I", (void *)android_media_MediaRecorder_native_getMaxAmplitude},
{"start", "()V", (void *)android_media_MediaRecorder_start},
{"stop", "()V", (void *)android_media_MediaRecorder_stop},
- {"native_reset", "()V", (void *)android_media_MediaRecorder_native_reset},
+ {"native_reset", "()V", (void *)android_media_MediaRecorder_native_reset},
{"release", "()V", (void *)android_media_MediaRecorder_release},
+ {"native_init", "()V", (void *)android_media_MediaRecorder_native_init},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaRecorder_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize},
};
static const char* const kClassPathName = "android/media/MediaRecorder";
+// This function only registers the native methods, and is called from
+// JNI_OnLoad in android_media_MediaPlayer.cpp
int register_android_media_MediaRecorder(JNIEnv *env)
{
- jclass clazz;
-
- clazz = env->FindClass("android/media/MediaRecorder");
- if (clazz == NULL) {
- LOGE("Can't find android/media/MediaRecorder");
- return -1;
- }
-
- fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
- if (fields.context == NULL) {
- LOGE("Can't find MediaRecorder.mNativeContext");
- return -1;
- }
-
- fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
- if (fields.surface == NULL) {
- LOGE("Can't find MediaRecorder.mSurface");
- return -1;
- }
-
- jclass surface = env->FindClass("android/view/Surface");
- if (surface == NULL) {
- LOGE("Can't find android/view/Surface");
- return -1;
- }
-
- fields.surface_native = env->GetFieldID(surface, "mSurface", "I");
- if (fields.surface_native == NULL) {
- LOGE("Can't find Surface fields");
- return -1;
- }
-
- fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
- "(Ljava/lang/Object;IIILjava/lang/Object;)V");
- if (fields.post_event == NULL) {
- LOGE("Can't find MediaRecorder.postEventFromNative");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaRecorder", gMethods, NELEM(gMethods));
}
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 8764a70..97de486 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -241,6 +241,27 @@ done:
return array;
}
+// This function gets a field ID, which in turn causes class initialization.
+// It is called from a static block in MediaScanner, which won't run until the
+// first time an instance of this class is used.
+static void
+android_media_MediaScanner_native_init(JNIEnv *env)
+{
+ jclass clazz;
+
+ clazz = env->FindClass("android/media/MediaScanner");
+ if (clazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaScanner");
+ return;
+ }
+
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaScanner.mNativeContext");
+ return;
+ }
+}
+
static void
android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz)
{
@@ -275,28 +296,17 @@ static JNINativeMethod gMethods[] = {
(void *)android_media_MediaScanner_processFile},
{"setLocale", "(Ljava/lang/String;)V", (void *)android_media_MediaScanner_setLocale},
{"extractAlbumArt", "(Ljava/io/FileDescriptor;)[B", (void *)android_media_MediaScanner_extractAlbumArt},
+ {"native_init", "()V", (void *)android_media_MediaScanner_native_init},
{"native_setup", "()V", (void *)android_media_MediaScanner_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaScanner_native_finalize},
};
static const char* const kClassPathName = "android/media/MediaScanner";
+// This function only registers the native methods, and is called from
+// JNI_OnLoad in android_media_MediaPlayer.cpp
int register_android_media_MediaScanner(JNIEnv *env)
{
- jclass clazz;
-
- clazz = env->FindClass("android/media/MediaScanner");
- if (clazz == NULL) {
- LOGE("Can't find android/media/MediaScanner");
- return -1;
- }
-
- fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
- if (fields.context == NULL) {
- LOGE("Can't find MediaScanner.mNativeContext");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaScanner", gMethods, NELEM(gMethods));
}
diff --git a/media/jni/android_media_ResampleInputStream.cpp b/media/jni/android_media_ResampleInputStream.cpp
index 0247cdb..f248557 100644
--- a/media/jni/android_media_ResampleInputStream.cpp
+++ b/media/jni/android_media_ResampleInputStream.cpp
@@ -128,13 +128,6 @@ static JNINativeMethod gMethods[] = {
int register_android_media_ResampleInputStream(JNIEnv *env)
{
const char* const kClassPathName = "android/media/ResampleInputStream";
- jclass clazz;
-
- clazz = env->FindClass(kClassPathName);
- if (clazz == NULL) {
- LOGE("Can't find %s", kClassPathName);
- return -1;
- }
return AndroidRuntime::registerNativeMethods(env,
kClassPathName, gMethods, NELEM(gMethods));
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/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 00a121b..b17e31b 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -524,13 +524,14 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
// wrong audio audio buffer size (mAudioBufferSize)
unsigned long toggle = mToggle ^ 1;
void *userData = (void *)((unsigned long)this | toggle);
+ uint32_t channels = (numChannels == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO;
#ifdef USE_SHARED_MEM_BUFFER
newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- numChannels, sample->getIMemory(), 0, callback, userData);
+ channels, sample->getIMemory(), 0, callback, userData);
#else
newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- numChannels, frameCount, 0, callback, userData, bufferFrames);
+ channels, frameCount, 0, callback, userData, bufferFrames);
#endif
if (newTrack->initCheck() != NO_ERROR) {
LOGE("Error creating AudioTrack");
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/libdrm/mobile2/src/util/domcore/NodeIterator.cpp b/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp
index f076cda..fe13669 100644
--- a/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp
+++ b/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp
@@ -88,7 +88,7 @@ NodeImpl* NodeIterator::findPreviousOrderNode(NodeImpl* node)
node = node->getLastChild();
} else {
if (node == scopeNode)
- node == NULL;
+ node = NULL;
else
node = node->getParentNode();
}
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 8020da2..9d442c3 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -2,31 +2,34 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- AudioTrack.cpp \
- IAudioFlinger.cpp \
- IAudioFlingerClient.cpp \
- IAudioTrack.cpp \
- IAudioRecord.cpp \
- AudioRecord.cpp \
- AudioSystem.cpp \
- mediaplayer.cpp \
- IMediaPlayerService.cpp \
- IMediaPlayerClient.cpp \
- IMediaPlayer.cpp \
- IMediaRecorder.cpp \
- mediarecorder.cpp \
- IMediaMetadataRetriever.cpp \
- mediametadataretriever.cpp \
- ToneGenerator.cpp \
- JetPlayer.cpp
+ AudioTrack.cpp \
+ IAudioFlinger.cpp \
+ IAudioFlingerClient.cpp \
+ IAudioTrack.cpp \
+ IAudioRecord.cpp \
+ AudioRecord.cpp \
+ AudioSystem.cpp \
+ mediaplayer.cpp \
+ IMediaPlayerService.cpp \
+ IMediaPlayerClient.cpp \
+ IMediaPlayer.cpp \
+ IMediaRecorder.cpp \
+ Metadata.cpp \
+ mediarecorder.cpp \
+ IMediaMetadataRetriever.cpp \
+ mediametadataretriever.cpp \
+ ToneGenerator.cpp \
+ JetPlayer.cpp \
+ IOMX.cpp \
+ IAudioPolicyService.cpp
LOCAL_SHARED_LIBRARIES := \
- libui libcutils libutils libsonivox
+ libui libcutils libutils libbinder libsonivox
LOCAL_MODULE:= libmedia
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
-LOCAL_LDLIBS += -ldl
+LOCAL_LDLIBS += -ldl -lpthread
endif
ifneq ($(TARGET_SIMULATOR),true)
@@ -34,6 +37,7 @@ LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_C_INCLUDES := \
- $(call include-path-for, graphics corecg)
+ $(call include-path-for, graphics corecg) \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index e56efbb..5e35564 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -28,12 +28,13 @@
#include <media/AudioSystem.h>
#include <media/AudioRecord.h>
+#include <media/mediarecorder.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>
@@ -45,7 +46,7 @@ namespace android {
// ---------------------------------------------------------------------------
AudioRecord::AudioRecord()
- : mStatus(NO_INIT)
+ : mStatus(NO_INIT), mInput(0)
{
}
@@ -53,15 +54,15 @@ AudioRecord::AudioRecord(
int inputSource,
uint32_t sampleRate,
int format,
- int channelCount,
+ uint32_t channels,
int frameCount,
uint32_t flags,
callback_t cbf,
void* user,
int notificationFrames)
- : mStatus(NO_INIT)
+ : mStatus(NO_INIT), mInput(0)
{
- mStatus = set(inputSource, sampleRate, format, channelCount,
+ mStatus = set(inputSource, sampleRate, format, channels,
frameCount, flags, cbf, user, notificationFrames);
}
@@ -78,6 +79,7 @@ AudioRecord::~AudioRecord()
}
mAudioRecord.clear();
IPCThreadState::self()->flushCommands();
+ AudioSystem::releaseInput(mInput);
}
}
@@ -85,7 +87,7 @@ status_t AudioRecord::set(
int inputSource,
uint32_t sampleRate,
int format,
- int channelCount,
+ uint32_t channels,
int frameCount,
uint32_t flags,
callback_t cbf,
@@ -94,7 +96,7 @@ status_t AudioRecord::set(
bool threadCanCallJava)
{
- LOGV("set(): sampleRate %d, channelCount %d, frameCount %d",sampleRate, channelCount, frameCount);
+ LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
if (mAudioRecord != 0) {
return INVALID_OPERATION;
}
@@ -104,8 +106,8 @@ status_t AudioRecord::set(
return NO_INIT;
}
- if (inputSource == DEFAULT_INPUT) {
- inputSource = MIC_INPUT;
+ if (inputSource == AUDIO_SOURCE_DEFAULT) {
+ inputSource = AUDIO_SOURCE_MIC;
}
if (sampleRate == 0) {
@@ -115,15 +117,21 @@ status_t AudioRecord::set(
if (format == 0) {
format = AudioSystem::PCM_16_BIT;
}
- if (channelCount == 0) {
- channelCount = 1;
+ // validate parameters
+ if (!AudioSystem::isValidFormat(format)) {
+ LOGE("Invalid format");
+ return BAD_VALUE;
}
- // validate parameters
- if (format != AudioSystem::PCM_16_BIT) {
+ if (!AudioSystem::isInputChannel(channels)) {
return BAD_VALUE;
}
- if (channelCount != 1 && channelCount != 2) {
+ int channelCount = AudioSystem::popCount(channels);
+
+ mInput = AudioSystem::getInput(inputSource,
+ sampleRate, format, channels, (AudioSystem::audio_in_acoustics)flags);
+ if (mInput == 0) {
+ LOGE("Could not get audio output for stream type %d", inputSource);
return BAD_VALUE;
}
@@ -132,14 +140,22 @@ status_t AudioRecord::set(
if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes)
!= NO_ERROR) {
LOGE("AudioSystem could not query the input buffer size.");
- return NO_INIT;
+ return NO_INIT;
}
+
if (inputBuffSizeInBytes == 0) {
LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d",
sampleRate, channelCount, format);
return BAD_VALUE;
}
+
int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1);
+ if (AudioSystem::isLinearPCM(format)) {
+ frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? sizeof(int16_t) : sizeof(int8_t));
+ } else {
+ frameSizeInBytes = sizeof(int8_t);
+ }
+
// We use 2* size of input buffer for ping pong use of record buffer.
int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes;
@@ -157,11 +173,11 @@ status_t AudioRecord::set(
// open record channel
status_t status;
- sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), inputSource,
+ sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), mInput,
sampleRate, format,
channelCount,
frameCount,
- ((uint16_t)flags) << 16,
+ ((uint16_t)flags) << 16,
&status);
if (record == 0) {
LOGE("AudioFlinger could not create record track, status: %d", status);
@@ -188,7 +204,7 @@ status_t AudioRecord::set(
mFormat = format;
// Update buffer size in case it has been limited by AudioFlinger during track creation
mFrameCount = mCblk->frameCount;
- mChannelCount = channelCount;
+ mChannelCount = (uint8_t)channelCount;
mActive = 0;
mCbf = cbf;
mNotificationFrames = notificationFrames;
@@ -234,7 +250,11 @@ uint32_t AudioRecord::frameCount() const
int AudioRecord::frameSize() const
{
- return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ if (AudioSystem::isLinearPCM(mFormat)) {
+ return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ } else {
+ return sizeof(uint8_t);
+ }
}
int AudioRecord::inputSource() const
@@ -262,15 +282,18 @@ status_t AudioRecord::start()
}
if (android_atomic_or(1, &mActive) == 0) {
- mNewPosition = mCblk->user + mUpdatePeriod;
- mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
- mCblk->waitTimeMs = 0;
- if (t != 0) {
- t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
- } else {
- setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+ ret = AudioSystem::startInput(mInput);
+ if (ret == NO_ERROR) {
+ mNewPosition = mCblk->user + mUpdatePeriod;
+ mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ mCblk->waitTimeMs = 0;
+ if (t != 0) {
+ t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
+ } else {
+ setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+ }
+ ret = mAudioRecord->start();
}
- ret = mAudioRecord->start();
}
if (t != 0) {
@@ -301,6 +324,7 @@ status_t AudioRecord::stop()
} else {
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
}
+ AudioSystem::stopInput(mInput);
}
if (t != 0) {
@@ -421,7 +445,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
"this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
cblk->waitTimeMs = 0;
-
+
if (framesReq > framesReady) {
framesReq = framesReady;
}
@@ -437,7 +461,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
audioBuffer->channelCount= mChannelCount;
audioBuffer->format = mFormat;
audioBuffer->frameCount = framesReq;
- audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
+ audioBuffer->size = framesReq*cblk->frameSize;
audioBuffer->raw = (int8_t*)cblk->buffer(u);
active = mActive;
return active ? status_t(NO_ERROR) : status_t(STOPPED);
@@ -468,7 +492,7 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize)
do {
- audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t);
+ audioBuffer.frameCount = userSize/frameSize();
// Calling obtainBuffer() with a negative wait count causes
// an (almost) infinite wait time.
@@ -519,8 +543,8 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
do {
audioBuffer.frameCount = frames;
- // Calling obtainBuffer() with a wait count of 1
- // limits wait time to WAIT_PERIOD_MS. This prevents from being
+ // Calling obtainBuffer() with a wait count of 1
+ // limits wait time to WAIT_PERIOD_MS. This prevents from being
// stuck here not being able to handle timed events (position, markers).
status_t err = obtainBuffer(&audioBuffer, 1);
if (err < NO_ERROR) {
@@ -548,14 +572,14 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
if (readSize > reqSize) readSize = reqSize;
audioBuffer.size = readSize;
- audioBuffer.frameCount = readSize/mChannelCount/sizeof(int16_t);
+ audioBuffer.frameCount = readSize/frameSize();
frames -= audioBuffer.frameCount;
releaseBuffer(&audioBuffer);
} while (frames);
-
+
// Manage overrun callback
if (mActive && (mCblk->framesAvailable_l() == 0)) {
LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index a21a7a4..bd1b2d7 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -18,10 +18,20 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
-#include <utils/IServiceManager.h>
+#include <binder/IServiceManager.h>
#include <media/AudioSystem.h>
+#include <media/IAudioPolicyService.h>
#include <math.h>
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+
namespace android {
// client singleton for AudioFlinger binder interface
@@ -30,10 +40,9 @@ sp<IAudioFlinger> AudioSystem::gAudioFlinger;
sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
// Cached values
-int AudioSystem::gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
-int AudioSystem::gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
-uint32_t AudioSystem::gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
-bool AudioSystem::gA2dpEnabled;
+DefaultKeyedVector<int, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
+DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
+
// Cached values for recording queries
uint32_t AudioSystem::gPrevInSamplingRate = 16000;
int AudioSystem::gPrevInFormat = AudioSystem::PCM_16_BIT;
@@ -65,42 +74,10 @@ const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
binder->linkToDeath(gAudioFlingerClient);
gAudioFlinger = interface_cast<IAudioFlinger>(binder);
gAudioFlinger->registerClient(gAudioFlingerClient);
- // Cache frequently accessed parameters
- for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
- gOutFrameCount[output] = (int)gAudioFlinger->frameCount(output);
- gOutSamplingRate[output] = (int)gAudioFlinger->sampleRate(output);
- gOutLatency[output] = gAudioFlinger->latency(output);
- }
- gA2dpEnabled = gAudioFlinger->isA2dpEnabled();
}
LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
- return gAudioFlinger;
-}
-// routing helper functions
-status_t AudioSystem::speakerphone(bool state) {
- uint32_t routes = state ? ROUTE_SPEAKER : ROUTE_EARPIECE;
- return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
-}
-
-status_t AudioSystem::isSpeakerphoneOn(bool* state) {
- uint32_t routes = 0;
- status_t s = getRouting(MODE_IN_CALL, &routes);
- *state = !!(routes & ROUTE_SPEAKER);
- return s;
-}
-
-status_t AudioSystem::bluetoothSco(bool state) {
- uint32_t mask = ROUTE_BLUETOOTH_SCO;
- uint32_t routes = state ? mask : ROUTE_EARPIECE;
- return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
-}
-
-status_t AudioSystem::isBluetoothScoOn(bool* state) {
- uint32_t routes = 0;
- status_t s = getRouting(MODE_IN_CALL, &routes);
- *state = !!(routes & ROUTE_BLUETOOTH_SCO);
- return s;
+ return gAudioFlinger;
}
status_t AudioSystem::muteMicrophone(bool state) {
@@ -148,12 +125,12 @@ status_t AudioSystem::getMasterMute(bool* mute)
return NO_ERROR;
}
-status_t AudioSystem::setStreamVolume(int stream, float value)
+status_t AudioSystem::setStreamVolume(int stream, float value, int output)
{
if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- af->setStreamVolume(stream, value);
+ af->setStreamVolume(stream, value, output);
return NO_ERROR;
}
@@ -166,12 +143,12 @@ status_t AudioSystem::setStreamMute(int stream, bool mute)
return NO_ERROR;
}
-status_t AudioSystem::getStreamVolume(int stream, float* volume)
+status_t AudioSystem::getStreamVolume(int stream, float* volume, int output)
{
if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- *volume = af->streamVolume(stream);
+ *volume = af->streamVolume(stream, output);
return NO_ERROR;
}
@@ -192,43 +169,28 @@ status_t AudioSystem::setMode(int mode)
return af->setMode(mode);
}
-status_t AudioSystem::getMode(int* mode)
-{
+
+status_t AudioSystem::isMusicActive(bool* state) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- *mode = af->getMode();
+ *state = af->isMusicActive();
return NO_ERROR;
}
-status_t AudioSystem::setRouting(int mode, uint32_t routes, uint32_t mask)
-{
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
- return af->setRouting(mode, routes, mask);
-}
-status_t AudioSystem::getRouting(int mode, uint32_t* routes)
-{
+status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- uint32_t r = af->getRouting(mode);
- *routes = r;
- return NO_ERROR;
+ return af->setParameters(ioHandle, keyValuePairs);
}
-status_t AudioSystem::isMusicActive(bool* state) {
+String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
- *state = af->isMusicActive();
- return NO_ERROR;
-}
+ String8 result = String8("");
+ if (af == 0) return result;
-// Temporary interface, do not use
-// TODO: Replace with a more generic key:value get/set mechanism
-status_t AudioSystem::setParameter(const char* key, const char* value) {
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
- return af->setParameter(key, value);
+ result = af->getParameters(ioHandle, keys);
+ return result;
}
// convert volume steps to natural log scale
@@ -257,55 +219,108 @@ int AudioSystem::logToLinear(float volume)
status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
{
- int output = getOutput(streamType);
-
- if (output == NUM_AUDIO_OUTPUT_TYPES) return PERMISSION_DENIED;
+ OutputDescriptor *outputDesc;
+ audio_io_handle_t output;
+
+ if (streamType == DEFAULT) {
+ streamType = MUSIC;
+ }
+
+ output = getOutput((stream_type)streamType);
+ if (output == 0) {
+ return PERMISSION_DENIED;
+ }
+
+ gLock.lock();
+ outputDesc = AudioSystem::gOutputs.valueFor(output);
+ if (outputDesc == 0) {
+ LOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output);
+ gLock.unlock();
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *samplingRate = af->sampleRate(output);
+ } else {
+ LOGV("getOutputSamplingRate() reading from output desc");
+ *samplingRate = outputDesc->samplingRate;
+ gLock.unlock();
+ }
+
+ LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, *samplingRate);
- // gOutSamplingRate[] is updated by getOutput() which calls get_audio_flinger()
- LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, gOutSamplingRate[output]);
-
- *samplingRate = gOutSamplingRate[output];
-
return NO_ERROR;
}
status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType)
{
- int output = getOutput(streamType);
+ OutputDescriptor *outputDesc;
+ audio_io_handle_t output;
- if (output == NUM_AUDIO_OUTPUT_TYPES) return PERMISSION_DENIED;
+ if (streamType == DEFAULT) {
+ streamType = MUSIC;
+ }
- // gOutFrameCount[] is updated by getOutput() which calls get_audio_flinger()
- LOGV("getOutputFrameCount() streamType %d, output %d, frame count %d", streamType, output, gOutFrameCount[output]);
+ output = getOutput((stream_type)streamType);
+ if (output == 0) {
+ return PERMISSION_DENIED;
+ }
+
+ gLock.lock();
+ outputDesc = AudioSystem::gOutputs.valueFor(output);
+ if (outputDesc == 0) {
+ gLock.unlock();
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *frameCount = af->frameCount(output);
+ } else {
+ *frameCount = outputDesc->frameCount;
+ gLock.unlock();
+ }
+
+ LOGV("getOutputFrameCount() streamType %d, output %d, frameCount %d", streamType, output, *frameCount);
- *frameCount = gOutFrameCount[output];
-
return NO_ERROR;
}
status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType)
{
- int output = getOutput(streamType);
+ OutputDescriptor *outputDesc;
+ audio_io_handle_t output;
- if (output == NUM_AUDIO_OUTPUT_TYPES) return PERMISSION_DENIED;
+ if (streamType == DEFAULT) {
+ streamType = MUSIC;
+ }
- // gOutLatency[] is updated by getOutput() which calls get_audio_flinger()
- LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, gOutLatency[output]);
+ output = getOutput((stream_type)streamType);
+ if (output == 0) {
+ return PERMISSION_DENIED;
+ }
+
+ gLock.lock();
+ outputDesc = AudioSystem::gOutputs.valueFor(output);
+ if (outputDesc == 0) {
+ gLock.unlock();
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *latency = af->latency(output);
+ } else {
+ *latency = outputDesc->latency;
+ gLock.unlock();
+ }
+
+ LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, *latency);
- *latency = gOutLatency[output];
-
return NO_ERROR;
}
-status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
+status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
size_t* buffSize)
{
// Do we have a stale gInBufferSize or are we requesting the input buffer size for new values
- if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat)
+ if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat)
|| (channelCount != gPrevInChannelCount)) {
// save the request params
gPrevInSamplingRate = sampleRate;
- gPrevInFormat = format;
+ gPrevInFormat = format;
gPrevInChannelCount = channelCount;
gInBuffSize = 0;
@@ -314,24 +329,18 @@ status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int ch
return PERMISSION_DENIED;
}
gInBuffSize = af->getInputBufferSize(sampleRate, format, channelCount);
- }
+ }
*buffSize = gInBuffSize;
-
+
return NO_ERROR;
}
// ---------------------------------------------------------------------------
-void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
+void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
Mutex::Autolock _l(AudioSystem::gLock);
- AudioSystem::gAudioFlinger.clear();
- for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
- gOutFrameCount[output] = 0;
- gOutSamplingRate[output] = 0;
- gOutLatency[output] = 0;
- }
- AudioSystem::gInBuffSize = 0;
+ AudioSystem::gAudioFlinger.clear();
if (gAudioErrorCallback) {
gAudioErrorCallback(DEAD_OBJECT);
@@ -339,33 +348,82 @@ void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
LOGW("AudioFlinger server died!");
}
-void AudioSystem::AudioFlingerClient::a2dpEnabledChanged(bool enabled) {
- gA2dpEnabled = enabled;
- LOGV("AudioFlinger A2DP enabled status changed! %d", enabled);
-}
+void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, void *param2) {
+ LOGV("ioConfigChanged() event %d", event);
+ OutputDescriptor *desc;
+ uint32_t stream;
+
+ if (ioHandle == 0) return;
-void AudioSystem::setErrorCallback(audio_error_callback cb) {
Mutex::Autolock _l(AudioSystem::gLock);
- gAudioErrorCallback = cb;
-}
-int AudioSystem::getOutput(int streamType)
-{
- // make sure that gA2dpEnabled is valid by calling get_audio_flinger() which in turn
- // will call gAudioFlinger->isA2dpEnabled()
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return NUM_AUDIO_OUTPUT_TYPES;
+ switch (event) {
+ case STREAM_CONFIG_CHANGED:
+ if (param2 == 0) break;
+ stream = *(uint32_t *)param2;
+ LOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %d", stream, ioHandle);
+ if (gStreamOutputMap.indexOfKey(stream) >= 0) {
+ gStreamOutputMap.replaceValueFor(stream, ioHandle);
+ }
+ break;
+ case OUTPUT_OPENED: {
+ if (gOutputs.indexOfKey(ioHandle) >= 0) {
+ LOGV("ioConfigChanged() opening already existing output! %d", ioHandle);
+ break;
+ }
+ if (param2 == 0) break;
+ desc = (OutputDescriptor *)param2;
+
+ OutputDescriptor *outputDesc = new OutputDescriptor(*desc);
+ gOutputs.add(ioHandle, outputDesc);
+ LOGV("ioConfigChanged() new output samplingRate %d, format %d channels %d frameCount %d latency %d",
+ outputDesc->samplingRate, outputDesc->format, outputDesc->channels, outputDesc->frameCount, outputDesc->latency);
+ } break;
+ case OUTPUT_CLOSED: {
+ if (gOutputs.indexOfKey(ioHandle) < 0) {
+ LOGW("ioConfigChanged() closing unknow output! %d", ioHandle);
+ break;
+ }
+ LOGV("ioConfigChanged() output %d closed", ioHandle);
+
+ gOutputs.removeItem(ioHandle);
+ for (int i = gStreamOutputMap.size() - 1; i >= 0 ; i--) {
+ if (gStreamOutputMap.valueAt(i) == ioHandle) {
+ gStreamOutputMap.removeItemsAt(i);
+ }
+ }
+ } break;
+
+ case OUTPUT_CONFIG_CHANGED: {
+ int index = gOutputs.indexOfKey(ioHandle);
+ if (index < 0) {
+ LOGW("ioConfigChanged() modifying unknow output! %d", ioHandle);
+ break;
+ }
+ if (param2 == 0) break;
+ desc = (OutputDescriptor *)param2;
+
+ LOGV("ioConfigChanged() new config for output %d samplingRate %d, format %d channels %d frameCount %d latency %d",
+ ioHandle, desc->samplingRate, desc->format,
+ desc->channels, desc->frameCount, desc->latency);
+ OutputDescriptor *outputDesc = gOutputs.valueAt(index);
+ delete outputDesc;
+ outputDesc = new OutputDescriptor(*desc);
+ gOutputs.replaceValueFor(ioHandle, outputDesc);
+ } break;
+ case INPUT_OPENED:
+ case INPUT_CLOSED:
+ case INPUT_CONFIG_CHANGED:
+ break;
- if (streamType == DEFAULT) {
- streamType = MUSIC;
- }
- if (gA2dpEnabled && routedToA2dpOutput(streamType)) {
- return AUDIO_OUTPUT_A2DP;
- } else {
- return AUDIO_OUTPUT_HARDWARE;
}
}
+void AudioSystem::setErrorCallback(audio_error_callback cb) {
+ Mutex::Autolock _l(gLock);
+ gAudioErrorCallback = cb;
+}
+
bool AudioSystem::routedToA2dpOutput(int streamType) {
switch(streamType) {
case MUSIC:
@@ -379,6 +437,461 @@ bool AudioSystem::routedToA2dpOutput(int streamType) {
}
+// client singleton for AudioPolicyService binder interface
+sp<IAudioPolicyService> AudioSystem::gAudioPolicyService;
+sp<AudioSystem::AudioPolicyServiceClient> AudioSystem::gAudioPolicyServiceClient;
+
+
+// establish binder interface to AudioFlinger service
+const sp<IAudioPolicyService>& AudioSystem::get_audio_policy_service()
+{
+ gLock.lock();
+ if (gAudioPolicyService.get() == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.audio_policy"));
+ if (binder != 0)
+ break;
+ LOGW("AudioPolicyService not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while(true);
+ if (gAudioPolicyServiceClient == NULL) {
+ gAudioPolicyServiceClient = new AudioPolicyServiceClient();
+ }
+ binder->linkToDeath(gAudioPolicyServiceClient);
+ gAudioPolicyService = interface_cast<IAudioPolicyService>(binder);
+ gLock.unlock();
+ } else {
+ gLock.unlock();
+ }
+ return gAudioPolicyService;
+}
+
+status_t AudioSystem::setDeviceConnectionState(audio_devices device,
+ device_connection_state state,
+ const char *device_address)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+
+ return aps->setDeviceConnectionState(device, state, device_address);
+}
+
+AudioSystem::device_connection_state AudioSystem::getDeviceConnectionState(audio_devices device,
+ const char *device_address)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return DEVICE_STATE_UNAVAILABLE;
+
+ return aps->getDeviceConnectionState(device, device_address);
+}
+
+status_t AudioSystem::setPhoneState(int state)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+
+ return aps->setPhoneState(state);
+}
+
+status_t AudioSystem::setRingerMode(uint32_t mode, uint32_t mask)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setRingerMode(mode, mask);
+}
+
+status_t AudioSystem::setForceUse(force_use usage, forced_config config)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setForceUse(usage, config);
+}
+
+AudioSystem::forced_config AudioSystem::getForceUse(force_use usage)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return FORCE_NONE;
+ return aps->getForceUse(usage);
+}
+
+
+audio_io_handle_t AudioSystem::getOutput(stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ output_flags flags)
+{
+ audio_io_handle_t output = 0;
+ if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
+ Mutex::Autolock _l(gLock);
+ output = AudioSystem::gStreamOutputMap.valueFor(stream);
+ LOGV_IF((output != 0), "getOutput() read %d from cache for stream %d", output, stream);
+ }
+ if (output == 0) {
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return 0;
+ output = aps->getOutput(stream, samplingRate, format, channels, flags);
+ if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {
+ Mutex::Autolock _l(gLock);
+ AudioSystem::gStreamOutputMap.add(stream, output);
+ }
+ }
+ return output;
+}
+
+status_t AudioSystem::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->startOutput(output, stream);
+}
+
+status_t AudioSystem::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->stopOutput(output, stream);
+}
+
+void AudioSystem::releaseOutput(audio_io_handle_t output)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return;
+ aps->releaseOutput(output);
+}
+
+audio_io_handle_t AudioSystem::getInput(int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ audio_in_acoustics acoustics)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return 0;
+ return aps->getInput(inputSource, samplingRate, format, channels, acoustics);
+}
+status_t AudioSystem::startInput(audio_io_handle_t input)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->startInput(input);
+}
+
+status_t AudioSystem::stopInput(audio_io_handle_t input)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->stopInput(input);
+}
+
+void AudioSystem::releaseInput(audio_io_handle_t input)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return;
+ aps->releaseInput(input);
+}
+
+status_t AudioSystem::initStreamVolume(stream_type stream,
+ int indexMin,
+ int indexMax)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->initStreamVolume(stream, indexMin, indexMax);
+}
+
+status_t AudioSystem::setStreamVolumeIndex(stream_type stream, int index)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setStreamVolumeIndex(stream, index);
+}
+
+status_t AudioSystem::getStreamVolumeIndex(stream_type stream, int *index)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->getStreamVolumeIndex(stream, index);
+}
+
+// ---------------------------------------------------------------------------
+
+void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ AudioSystem::gAudioPolicyService.clear();
+
+ LOGW("AudioPolicyService server died!");
+}
+
+// ---------------------------------------------------------------------------
+
+
+// use emulated popcount optimization
+// http://www.df.lth.se/~john_e/gems/gem002d.html
+uint32_t AudioSystem::popCount(uint32_t u)
+{
+ u = ((u&0x55555555) + ((u>>1)&0x55555555));
+ u = ((u&0x33333333) + ((u>>2)&0x33333333));
+ u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
+ u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
+ u = ( u&0x0000ffff) + (u>>16);
+ return u;
+}
+
+bool AudioSystem::isOutputDevice(audio_devices device)
+{
+ if ((popCount(device) == 1 ) &&
+ ((device & ~AudioSystem::DEVICE_OUT_ALL) == 0)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isInputDevice(audio_devices device)
+{
+ if ((popCount(device) == 1 ) &&
+ ((device & ~AudioSystem::DEVICE_IN_ALL) == 0)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isA2dpDevice(audio_devices device)
+{
+ if ((popCount(device) == 1 ) &&
+ (device & (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP |
+ AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER))) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isBluetoothScoDevice(audio_devices device)
+{
+ if ((popCount(device) == 1 ) &&
+ (device & (AudioSystem::DEVICE_OUT_BLUETOOTH_SCO |
+ AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT))) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isLowVisibility(stream_type stream)
+{
+ if (stream == AudioSystem::SYSTEM || stream == AudioSystem::NOTIFICATION) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isInputChannel(uint32_t channel)
+{
+ if ((channel & ~AudioSystem::CHANNEL_IN_ALL) == 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isOutputChannel(uint32_t channel)
+{
+ if ((channel & ~AudioSystem::CHANNEL_OUT_ALL) == 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AudioSystem::isValidFormat(uint32_t format)
+{
+ switch (format & MAIN_FORMAT_MASK) {
+ case PCM:
+ case MP3:
+ case AMR_NB:
+ case AMR_WB:
+ case AAC:
+ case HE_AAC_V1:
+ case HE_AAC_V2:
+ case VORBIS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool AudioSystem::isLinearPCM(uint32_t format)
+{
+ switch (format) {
+ case PCM_16_BIT:
+ case PCM_8_BIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+//------------------------- AudioParameter class implementation ---------------
+
+const char *AudioParameter::keyRouting = "routing";
+const char *AudioParameter::keySamplingRate = "sampling_rate";
+const char *AudioParameter::keyFormat = "format";
+const char *AudioParameter::keyChannels = "channels";
+const char *AudioParameter::keyFrameCount = "frame_count";
+
+AudioParameter::AudioParameter(const String8& keyValuePairs)
+{
+ char *str = new char[keyValuePairs.length()+1];
+ mKeyValuePairs = keyValuePairs;
+
+ strcpy(str, keyValuePairs.string());
+ char *pair = strtok(str, ";");
+ while (pair != NULL) {
+ if (strlen(pair) != 0) {
+ size_t eqIdx = strcspn(pair, "=");
+ String8 key = String8(pair, eqIdx);
+ String8 value;
+ if (eqIdx == strlen(pair)) {
+ value = String8("");
+ } else {
+ value = String8(pair + eqIdx + 1);
+ }
+ if (mParameters.indexOfKey(key) < 0) {
+ mParameters.add(key, value);
+ } else {
+ mParameters.replaceValueFor(key, value);
+ }
+ } else {
+ LOGV("AudioParameter() cstor empty key value pair");
+ }
+ pair = strtok(NULL, ";");
+ }
+
+ delete[] str;
+}
+
+AudioParameter::~AudioParameter()
+{
+ mParameters.clear();
+}
+
+String8 AudioParameter::toString()
+{
+ String8 str = String8("");
+
+ size_t size = mParameters.size();
+ for (size_t i = 0; i < size; i++) {
+ str += mParameters.keyAt(i);
+ str += "=";
+ str += mParameters.valueAt(i);
+ if (i < (size - 1)) str += ";";
+ }
+ return str;
+}
+
+status_t AudioParameter::add(const String8& key, const String8& value)
+{
+ if (mParameters.indexOfKey(key) < 0) {
+ mParameters.add(key, value);
+ return NO_ERROR;
+ } else {
+ mParameters.replaceValueFor(key, value);
+ return ALREADY_EXISTS;
+ }
+}
+
+status_t AudioParameter::addInt(const String8& key, const int value)
+{
+ char str[12];
+ if (snprintf(str, 12, "%d", value) > 0) {
+ String8 str8 = String8(str);
+ return add(key, str8);
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::addFloat(const String8& key, const float value)
+{
+ char str[23];
+ if (snprintf(str, 23, "%.10f", value) > 0) {
+ String8 str8 = String8(str);
+ return add(key, str8);
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::remove(const String8& key)
+{
+ if (mParameters.indexOfKey(key) >= 0) {
+ mParameters.removeItem(key);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::get(const String8& key, String8& value)
+{
+ if (mParameters.indexOfKey(key) >= 0) {
+ value = mParameters.valueFor(key);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+status_t AudioParameter::getInt(const String8& key, int& value)
+{
+ String8 str8;
+ status_t result = get(key, str8);
+ value = 0;
+ if (result == NO_ERROR) {
+ int val;
+ if (sscanf(str8.string(), "%d", &val) == 1) {
+ value = val;
+ } else {
+ result = INVALID_OPERATION;
+ }
+ }
+ return result;
+}
+
+status_t AudioParameter::getFloat(const String8& key, float& value)
+{
+ String8 str8;
+ status_t result = get(key, str8);
+ value = 0;
+ if (result == NO_ERROR) {
+ float val;
+ if (sscanf(str8.string(), "%f", &val) == 1) {
+ value = val;
+ } else {
+ result = INVALID_OPERATION;
+ }
+ }
+ return result;
+}
+
+status_t AudioParameter::getAt(size_t index, String8& key, String8& value)
+{
+ if (mParameters.size() > index) {
+ key = mParameters.keyAt(index);
+ value = mParameters.valueAt(index);
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
}; // namespace android
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index b2c067b..4b9d272 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>
@@ -54,7 +54,7 @@ AudioTrack::AudioTrack(
int streamType,
uint32_t sampleRate,
int format,
- int channelCount,
+ int channels,
int frameCount,
uint32_t flags,
callback_t cbf,
@@ -62,7 +62,7 @@ AudioTrack::AudioTrack(
int notificationFrames)
: mStatus(NO_INIT)
{
- mStatus = set(streamType, sampleRate, format, channelCount,
+ mStatus = set(streamType, sampleRate, format, channels,
frameCount, flags, cbf, user, notificationFrames, 0);
}
@@ -70,7 +70,7 @@ AudioTrack::AudioTrack(
int streamType,
uint32_t sampleRate,
int format,
- int channelCount,
+ int channels,
const sp<IMemory>& sharedBuffer,
uint32_t flags,
callback_t cbf,
@@ -78,7 +78,7 @@ AudioTrack::AudioTrack(
int notificationFrames)
: mStatus(NO_INIT)
{
- mStatus = set(streamType, sampleRate, format, channelCount,
+ mStatus = set(streamType, sampleRate, format, channels,
0, flags, cbf, user, notificationFrames, sharedBuffer);
}
@@ -97,6 +97,7 @@ AudioTrack::~AudioTrack()
}
mAudioTrack.clear();
IPCThreadState::self()->flushCommands();
+ AudioSystem::releaseOutput(getOutput());
}
}
@@ -104,7 +105,7 @@ status_t AudioTrack::set(
int streamType,
uint32_t sampleRate,
int format,
- int channelCount,
+ int channels,
int frameCount,
uint32_t flags,
callback_t cbf,
@@ -150,63 +151,84 @@ status_t AudioTrack::set(
if (format == 0) {
format = AudioSystem::PCM_16_BIT;
}
- if (channelCount == 0) {
- channelCount = 2;
+ if (channels == 0) {
+ channels = AudioSystem::CHANNEL_OUT_STEREO;
}
// validate parameters
- if (((format != AudioSystem::PCM_8_BIT) || sharedBuffer != 0) &&
- (format != AudioSystem::PCM_16_BIT)) {
+ if (!AudioSystem::isValidFormat(format)) {
LOGE("Invalid format");
return BAD_VALUE;
}
- if (channelCount != 1 && channelCount != 2) {
- LOGE("Invalid channel number");
+
+ // force direct flag if format is not linear PCM
+ if (!AudioSystem::isLinearPCM(format)) {
+ flags |= AudioSystem::OUTPUT_FLAG_DIRECT;
+ }
+
+ if (!AudioSystem::isOutputChannel(channels)) {
+ LOGE("Invalid channel mask");
return BAD_VALUE;
}
+ uint32_t channelCount = AudioSystem::popCount(channels);
- // Ensure that buffer depth covers at least audio hardware latency
- uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
- if (minBufCount < 2) minBufCount = 2;
+ audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType,
+ sampleRate, format, channels, (AudioSystem::output_flags)flags);
- // When playing from shared buffer, playback will start even if last audioflinger
- // block is partly filled.
- if (sharedBuffer != 0 && minBufCount > 1) {
- minBufCount--;
+ if (output == 0) {
+ LOGE("Could not get audio output for stream type %d", streamType);
+ return BAD_VALUE;
}
- int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
-
- if (sharedBuffer == 0) {
- if (frameCount == 0) {
- frameCount = minFrameCount;
- }
- if (notificationFrames == 0) {
- notificationFrames = frameCount/2;
- }
- // Make sure that application is notified with sufficient margin
- // before underrun
- if (notificationFrames > frameCount/2) {
- notificationFrames = frameCount/2;
+ if (!AudioSystem::isLinearPCM(format)) {
+ if (sharedBuffer != 0) {
+ frameCount = sharedBuffer->size();
}
} else {
- // Ensure that buffer alignment matches channelcount
- if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
- LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
- return BAD_VALUE;
- }
- frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
- }
+ // Ensure that buffer depth covers at least audio hardware latency
+ uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
+ if (minBufCount < 2) minBufCount = 2;
+
+ int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
- if (frameCount < minFrameCount) {
- LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
- return BAD_VALUE;
+ if (sharedBuffer == 0) {
+ if (frameCount == 0) {
+ frameCount = minFrameCount;
+ }
+ if (notificationFrames == 0) {
+ notificationFrames = frameCount/2;
+ }
+ // Make sure that application is notified with sufficient margin
+ // before underrun
+ if (notificationFrames > frameCount/2) {
+ notificationFrames = frameCount/2;
+ }
+ if (frameCount < minFrameCount) {
+ LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
+ return BAD_VALUE;
+ }
+ } else {
+ // Ensure that buffer alignment matches channelcount
+ if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
+ LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
+ return BAD_VALUE;
+ }
+ frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
+ }
}
// create the track
status_t status;
sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
- streamType, sampleRate, format, channelCount, frameCount, flags, sharedBuffer, &status);
+ streamType,
+ sampleRate,
+ format,
+ channelCount,
+ frameCount,
+ ((uint16_t)flags) << 16,
+ sharedBuffer,
+ output,
+ &status);
if (track == 0) {
LOGE("AudioFlinger could not create track, status: %d", status);
@@ -245,6 +267,7 @@ status_t AudioTrack::set(
mVolume[RIGHT] = 1.0f;
mStreamType = streamType;
mFormat = format;
+ mChannels = channels;
mChannelCount = channelCount;
mSharedBuffer = sharedBuffer;
mMuted = false;
@@ -259,6 +282,7 @@ status_t AudioTrack::set(
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
+ mFlags = flags;
return NO_ERROR;
}
@@ -297,7 +321,11 @@ uint32_t AudioTrack::frameCount() const
int AudioTrack::frameSize() const
{
- return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ if (AudioSystem::isLinearPCM(mFormat)) {
+ return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ } else {
+ return sizeof(uint8_t);
+ }
}
sp<IMemory>& AudioTrack::sharedBuffer()
@@ -323,6 +351,7 @@ void AudioTrack::start()
}
if (android_atomic_or(1, &mActive) == 0) {
+ AudioSystem::startOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
mNewPosition = mCblk->server + mUpdatePeriod;
mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
mCblk->waitTimeMs = 0;
@@ -367,6 +396,7 @@ void AudioTrack::stop()
} else {
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
}
+ AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
}
if (t != 0) {
@@ -382,12 +412,12 @@ bool AudioTrack::stopped() const
void AudioTrack::flush()
{
LOGV("flush");
-
+
// clear playback marker and periodic update counter
mMarkerPosition = 0;
mMarkerReached = false;
mUpdatePeriod = 0;
-
+
if (!mActive) {
mAudioTrack->flush();
@@ -403,6 +433,7 @@ void AudioTrack::pause()
if (android_atomic_and(~1, &mActive) == 1) {
mActive = 0;
mAudioTrack->pause();
+ AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
}
}
@@ -455,7 +486,6 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount
{
audio_track_cblk_t* cblk = mCblk;
-
Mutex::Autolock _l(cblk->lock);
if (loopCount == 0) {
@@ -476,7 +506,7 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount
LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
loopStart, loopEnd, mFrameCount);
return BAD_VALUE;
- }
+ }
cblk->loopStart = loopStart;
cblk->loopEnd = loopEnd;
@@ -555,7 +585,7 @@ status_t AudioTrack::setPosition(uint32_t position)
mCblk->server = position;
mCblk->forceReady = 1;
-
+
return NO_ERROR;
}
@@ -571,7 +601,7 @@ status_t AudioTrack::getPosition(uint32_t *position)
status_t AudioTrack::reload()
{
if (!stopped()) return INVALID_OPERATION;
-
+
flush();
mCblk->stepUser(mFrameCount);
@@ -579,6 +609,12 @@ status_t AudioTrack::reload()
return NO_ERROR;
}
+audio_io_handle_t AudioTrack::getOutput()
+{
+ return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType,
+ mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
+}
+
// -------------------------------------------------------------------------
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
@@ -608,7 +644,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
return WOULD_BLOCK;
timeout = 0;
result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
- if (__builtin_expect(result!=NO_ERROR, false)) {
+ if (__builtin_expect(result!=NO_ERROR, false)) {
cblk->waitTimeMs += waitTimeMs;
if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
// timing out when a loop has been set and we have already written upto loop end
@@ -616,7 +652,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
if (cblk->user < cblk->loopEnd) {
LOGW( "obtainBuffer timed out (is the CPU pegged?) %p "
"user=%08x, server=%08x", this, cblk->user, cblk->server);
- //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
+ //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
cblk->lock.unlock();
mAudioTrack->start();
cblk->lock.lock();
@@ -624,7 +660,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
}
cblk->waitTimeMs = 0;
}
-
+
if (--waitCount == 0) {
return TIMED_OUT;
}
@@ -636,7 +672,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
}
cblk->waitTimeMs = 0;
-
+
if (framesReq > framesAvail) {
framesReq = framesAvail;
}
@@ -653,12 +689,16 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
"but didn't need to be locked. We recovered, but "
"this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
- audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
- audioBuffer->channelCount= mChannelCount;
- audioBuffer->format = AudioSystem::PCM_16_BIT;
- audioBuffer->frameCount = framesReq;
- audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
- audioBuffer->raw = (int8_t *)cblk->buffer(u);
+ audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
+ audioBuffer->channelCount = mChannelCount;
+ audioBuffer->frameCount = framesReq;
+ audioBuffer->size = framesReq * cblk->frameSize;
+ if (AudioSystem::isLinearPCM(mFormat)) {
+ audioBuffer->format = AudioSystem::PCM_16_BIT;
+ } else {
+ audioBuffer->format = mFormat;
+ }
+ audioBuffer->raw = (int8_t *)cblk->buffer(u);
active = mActive;
return active ? status_t(NO_ERROR) : status_t(STOPPED);
}
@@ -690,10 +730,8 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
Buffer audioBuffer;
do {
- audioBuffer.frameCount = userSize/mChannelCount;
- if (mFormat == AudioSystem::PCM_16_BIT) {
- audioBuffer.frameCount >>= 1;
- }
+ audioBuffer.frameCount = userSize/frameSize();
+
// Calling obtainBuffer() with a negative wait count causes
// an (almost) infinite wait time.
status_t err = obtainBuffer(&audioBuffer, -1);
@@ -705,7 +743,8 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
}
size_t toWrite;
- if (mFormat == AudioSystem::PCM_8_BIT) {
+
+ if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
// Divide capacity by 2 to take expansion into account
toWrite = audioBuffer.size>>1;
// 8 to 16 bit conversion
@@ -714,7 +753,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
while(count--) {
*dst++ = (int16_t)(*src++^0x80) << 8;
}
- }else {
+ } else {
toWrite = audioBuffer.size;
memcpy(audioBuffer.i8, src, toWrite);
src += toWrite;
@@ -742,13 +781,13 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
if (mCblk->flowControlFlag == 0) {
mCbf(EVENT_UNDERRUN, mUserData, 0);
if (mCblk->server == mCblk->frameCount) {
- mCbf(EVENT_BUFFER_END, mUserData, 0);
+ mCbf(EVENT_BUFFER_END, mUserData, 0);
}
mCblk->flowControlFlag = 1;
if (mSharedBuffer != 0) return false;
}
}
-
+
// Manage loop end callback
while (mLoopCount > mCblk->loopCount) {
int loopCount = -1;
@@ -767,7 +806,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
}
// Manage new position callback
- if(mUpdatePeriod > 0) {
+ if (mUpdatePeriod > 0) {
while (mCblk->server >= mNewPosition) {
mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
mNewPosition += mUpdatePeriod;
@@ -784,10 +823,10 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
do {
audioBuffer.frameCount = frames;
-
- // Calling obtainBuffer() with a wait count of 1
- // limits wait time to WAIT_PERIOD_MS. This prevents from being
- // stuck here not being able to handle timed events (position, markers, loops).
+
+ // Calling obtainBuffer() with a wait count of 1
+ // limits wait time to WAIT_PERIOD_MS. This prevents from being
+ // stuck here not being able to handle timed events (position, markers, loops).
status_t err = obtainBuffer(&audioBuffer, 1);
if (err < NO_ERROR) {
if (err != TIMED_OUT) {
@@ -801,7 +840,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
// Divide buffer size by 2 to take into account the expansion
// due to 8 to 16 bit conversion: the callback must fill only half
// of the destination buffer
- if (mFormat == AudioSystem::PCM_8_BIT) {
+ if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
audioBuffer.size >>= 1;
}
@@ -820,7 +859,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
}
if (writtenSize > reqSize) writtenSize = reqSize;
- if (mFormat == AudioSystem::PCM_8_BIT) {
+ if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
// 8 to 16 bit conversion
const int8_t *src = audioBuffer.i8 + writtenSize-1;
int count = writtenSize;
@@ -832,7 +871,11 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
}
audioBuffer.size = writtenSize;
- audioBuffer.frameCount = writtenSize/mChannelCount/sizeof(int16_t);
+ // NOTE: mCblk->frameSize is not equal to AudioTrack::frameSize() for
+ // 8 bit PCM data: in this case, mCblk->frameSize is based on a sampel size of
+ // 16 bit.
+ audioBuffer.frameCount = writtenSize/mCblk->frameSize;
+
frames -= audioBuffer.frameCount;
releaseBuffer(&audioBuffer);
@@ -891,7 +934,7 @@ void AudioTrack::AudioTrackThread::onFirstRef()
// =========================================================================
audio_track_cblk_t::audio_track_cblk_t()
- : user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
+ : lock(Mutex::SHARED), user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), flowControlFlag(1), forceReady(0)
{
}
@@ -949,7 +992,7 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount)
// we switch to normal obtainBuffer() timeout period
if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
bufferTimeoutMs = MAX_RUN_TIMEOUT_MS - 1;
- }
+ }
// It is possible that we receive a flush()
// while the mixer is processing a block: in this case,
// stepServer() is called After the flush() has reset u & s and
@@ -981,7 +1024,7 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount)
void* audio_track_cblk_t::buffer(uint32_t offset) const
{
- return (int16_t *)this->buffers + (offset-userBase)*this->channels;
+ return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;
}
uint32_t audio_track_cblk_t::framesAvailable()
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index eeaa54f..fc39a46 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -16,12 +16,13 @@
*/
#define LOG_TAG "IAudioFlinger"
+//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IAudioFlinger.h>
@@ -44,17 +45,21 @@ enum {
STREAM_VOLUME,
STREAM_MUTE,
SET_MODE,
- GET_MODE,
- SET_ROUTING,
- GET_ROUTING,
SET_MIC_MUTE,
GET_MIC_MUTE,
IS_MUSIC_ACTIVE,
- SET_PARAMETER,
+ SET_PARAMETERS,
+ GET_PARAMETERS,
REGISTER_CLIENT,
GET_INPUTBUFFERSIZE,
- WAKE_UP,
- IS_A2DP_ENABLED
+ OPEN_OUTPUT,
+ OPEN_DUPLICATE_OUTPUT,
+ CLOSE_OUTPUT,
+ SUSPEND_OUTPUT,
+ RESTORE_OUTPUT,
+ OPEN_INPUT,
+ CLOSE_INPUT,
+ SET_STREAM_OUTPUT
};
class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -74,6 +79,7 @@ public:
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer,
+ int output,
status_t *status)
{
Parcel data, reply;
@@ -86,6 +92,7 @@ public:
data.writeInt32(frameCount);
data.writeInt32(flags);
data.writeStrongBinder(sharedBuffer->asBinder());
+ data.writeInt32(output);
status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
if (lStatus != NO_ERROR) {
LOGE("createTrack error: %s", strerror(-lStatus));
@@ -99,7 +106,7 @@ public:
virtual sp<IAudioRecord> openRecord(
pid_t pid,
- int inputSource,
+ int input,
uint32_t sampleRate,
int format,
int channelCount,
@@ -110,7 +117,7 @@ public:
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(pid);
- data.writeInt32(inputSource);
+ data.writeInt32(input);
data.writeInt32(sampleRate);
data.writeInt32(format);
data.writeInt32(channelCount);
@@ -203,12 +210,13 @@ public:
return reply.readInt32();
}
- virtual status_t setStreamVolume(int stream, float value)
+ virtual status_t setStreamVolume(int stream, float value, int output)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(stream);
data.writeFloat(value);
+ data.writeInt32(output);
remote()->transact(SET_STREAM_VOLUME, data, &reply);
return reply.readInt32();
}
@@ -223,11 +231,12 @@ public:
return reply.readInt32();
}
- virtual float streamVolume(int stream) const
+ virtual float streamVolume(int stream, int output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(stream);
+ data.writeInt32(output);
remote()->transact(STREAM_VOLUME, data, &reply);
return reply.readFloat();
}
@@ -241,111 +250,201 @@ public:
return reply.readInt32();
}
- virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask)
+ virtual status_t setMode(int mode)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(mode);
- data.writeInt32(routes);
- data.writeInt32(mask);
- remote()->transact(SET_ROUTING, data, &reply);
+ remote()->transact(SET_MODE, data, &reply);
return reply.readInt32();
}
- virtual uint32_t getRouting(int mode) const
+ virtual status_t setMicMute(bool state)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(mode);
- remote()->transact(GET_ROUTING, data, &reply);
+ data.writeInt32(state);
+ remote()->transact(SET_MIC_MUTE, data, &reply);
return reply.readInt32();
}
- virtual status_t setMode(int mode)
+ virtual bool getMicMute() const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(mode);
- remote()->transact(SET_MODE, data, &reply);
+ remote()->transact(GET_MIC_MUTE, data, &reply);
return reply.readInt32();
}
- virtual int getMode() const
+ virtual bool isMusicActive() const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- remote()->transact(GET_MODE, data, &reply);
+ remote()->transact(IS_MUSIC_ACTIVE, data, &reply);
return reply.readInt32();
}
- virtual status_t setMicMute(bool state)
+ virtual status_t setParameters(int ioHandle, const String8& keyValuePairs)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(state);
- remote()->transact(SET_MIC_MUTE, data, &reply);
+ data.writeInt32(ioHandle);
+ data.writeString8(keyValuePairs);
+ remote()->transact(SET_PARAMETERS, data, &reply);
return reply.readInt32();
}
- virtual bool getMicMute() const
+ virtual String8 getParameters(int ioHandle, const String8& keys)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- remote()->transact(GET_MIC_MUTE, data, &reply);
+ data.writeInt32(ioHandle);
+ data.writeString8(keys);
+ remote()->transact(GET_PARAMETERS, data, &reply);
+ return reply.readString8();
+ }
+
+ virtual void registerClient(const sp<IAudioFlingerClient>& client)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeStrongBinder(client->asBinder());
+ remote()->transact(REGISTER_CLIENT, data, &reply);
+ }
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(sampleRate);
+ data.writeInt32(format);
+ data.writeInt32(channelCount);
+ remote()->transact(GET_INPUTBUFFERSIZE, data, &reply);
return reply.readInt32();
}
- virtual bool isMusicActive() const
+ virtual int openOutput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pLatencyMs,
+ uint32_t flags)
{
Parcel data, reply;
+ uint32_t devices = pDevices ? *pDevices : 0;
+ uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+ uint32_t format = pFormat ? *pFormat : 0;
+ uint32_t channels = pChannels ? *pChannels : 0;
+ uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
+
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- remote()->transact(IS_MUSIC_ACTIVE, data, &reply);
+ data.writeInt32(devices);
+ data.writeInt32(samplingRate);
+ data.writeInt32(format);
+ data.writeInt32(channels);
+ data.writeInt32(latency);
+ data.writeInt32(flags);
+ remote()->transact(OPEN_OUTPUT, data, &reply);
+ int output = reply.readInt32();
+ LOGV("openOutput() returned output, %p", output);
+ devices = reply.readInt32();
+ if (pDevices) *pDevices = devices;
+ samplingRate = reply.readInt32();
+ if (pSamplingRate) *pSamplingRate = samplingRate;
+ format = reply.readInt32();
+ if (pFormat) *pFormat = format;
+ channels = reply.readInt32();
+ if (pChannels) *pChannels = channels;
+ latency = reply.readInt32();
+ if (pLatencyMs) *pLatencyMs = latency;
+ return output;
+ }
+
+ virtual int openDuplicateOutput(int output1, int output2)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(output1);
+ data.writeInt32(output2);
+ remote()->transact(OPEN_DUPLICATE_OUTPUT, data, &reply);
return reply.readInt32();
}
- virtual status_t setParameter(const char* key, const char* value)
+ virtual status_t closeOutput(int output)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeCString(key);
- data.writeCString(value);
- remote()->transact(SET_PARAMETER, data, &reply);
+ data.writeInt32(output);
+ remote()->transact(CLOSE_OUTPUT, data, &reply);
return reply.readInt32();
}
-
- virtual void registerClient(const sp<IAudioFlingerClient>& client)
+
+ virtual status_t suspendOutput(int output)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeStrongBinder(client->asBinder());
- remote()->transact(REGISTER_CLIENT, data, &reply);
+ data.writeInt32(output);
+ remote()->transact(SUSPEND_OUTPUT, data, &reply);
+ return reply.readInt32();
}
-
- virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+
+ virtual status_t restoreOutput(int output)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(sampleRate);
- data.writeInt32(format);
- data.writeInt32(channelCount);
- remote()->transact(GET_INPUTBUFFERSIZE, data, &reply);
+ data.writeInt32(output);
+ remote()->transact(RESTORE_OUTPUT, data, &reply);
return reply.readInt32();
}
-
- virtual void wakeUp()
+
+ virtual int openInput(uint32_t *pDevices,
+ uint32_t *pSamplingRate,
+ uint32_t *pFormat,
+ uint32_t *pChannels,
+ uint32_t acoustics)
{
Parcel data, reply;
+ uint32_t devices = pDevices ? *pDevices : 0;
+ uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
+ uint32_t format = pFormat ? *pFormat : 0;
+ uint32_t channels = pChannels ? *pChannels : 0;
+
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- remote()->transact(WAKE_UP, data, &reply, IBinder::FLAG_ONEWAY);
- return;
+ data.writeInt32(devices);
+ data.writeInt32(samplingRate);
+ data.writeInt32(format);
+ data.writeInt32(channels);
+ data.writeInt32(acoustics);
+ remote()->transact(OPEN_INPUT, data, &reply);
+ int input = reply.readInt32();
+ devices = reply.readInt32();
+ if (pDevices) *pDevices = devices;
+ samplingRate = reply.readInt32();
+ if (pSamplingRate) *pSamplingRate = samplingRate;
+ format = reply.readInt32();
+ if (pFormat) *pFormat = format;
+ channels = reply.readInt32();
+ if (pChannels) *pChannels = channels;
+ return input;
}
- virtual bool isA2dpEnabled() const
+ virtual status_t closeInput(int input)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- remote()->transact(IS_A2DP_ENABLED, data, &reply);
- return (bool)reply.readInt32();
+ data.writeInt32(input);
+ remote()->transact(CLOSE_INPUT, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setStreamOutput(uint32_t stream, int output)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(stream);
+ data.writeInt32(output);
+ remote()->transact(SET_STREAM_OUTPUT, data, &reply);
+ return reply.readInt32();
}
};
@@ -353,12 +452,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)
{
@@ -373,10 +466,11 @@ status_t BnAudioFlinger::onTransact(
size_t bufferCount = data.readInt32();
uint32_t flags = data.readInt32();
sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
+ int output = data.readInt32();
status_t status;
sp<IAudioTrack> track = createTrack(pid,
streamType, sampleRate, format,
- channelCount, bufferCount, flags, buffer, &status);
+ channelCount, bufferCount, flags, buffer, output, &status);
reply->writeInt32(status);
reply->writeStrongBinder(track->asBinder());
return NO_ERROR;
@@ -384,14 +478,14 @@ status_t BnAudioFlinger::onTransact(
case OPEN_RECORD: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
pid_t pid = data.readInt32();
- int inputSource = data.readInt32();
+ int input = data.readInt32();
uint32_t sampleRate = data.readInt32();
int format = data.readInt32();
int channelCount = data.readInt32();
size_t bufferCount = data.readInt32();
uint32_t flags = data.readInt32();
status_t status;
- sp<IAudioRecord> record = openRecord(pid, inputSource,
+ sp<IAudioRecord> record = openRecord(pid, input,
sampleRate, format, channelCount, bufferCount, flags, &status);
reply->writeInt32(status);
reply->writeStrongBinder(record->asBinder());
@@ -399,32 +493,27 @@ status_t BnAudioFlinger::onTransact(
} break;
case SAMPLE_RATE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
- reply->writeInt32( sampleRate(output) );
+ reply->writeInt32( sampleRate(data.readInt32()) );
return NO_ERROR;
} break;
case CHANNEL_COUNT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
- reply->writeInt32( channelCount(output) );
+ reply->writeInt32( channelCount(data.readInt32()) );
return NO_ERROR;
} break;
case FORMAT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
- reply->writeInt32( format(output) );
+ reply->writeInt32( format(data.readInt32()) );
return NO_ERROR;
} break;
case FRAME_COUNT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
- reply->writeInt32( frameCount(output) );
+ reply->writeInt32( frameCount(data.readInt32()) );
return NO_ERROR;
} break;
case LATENCY: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- int output = data.readInt32();
- reply->writeInt32( latency(output) );
+ reply->writeInt32( latency(data.readInt32()) );
return NO_ERROR;
} break;
case SET_MASTER_VOLUME: {
@@ -450,7 +539,9 @@ status_t BnAudioFlinger::onTransact(
case SET_STREAM_VOLUME: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int stream = data.readInt32();
- reply->writeInt32( setStreamVolume(stream, data.readFloat()) );
+ float volume = data.readFloat();
+ int output = data.readInt32();
+ reply->writeInt32( setStreamVolume(stream, volume, output) );
return NO_ERROR;
} break;
case SET_STREAM_MUTE: {
@@ -462,7 +553,8 @@ status_t BnAudioFlinger::onTransact(
case STREAM_VOLUME: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int stream = data.readInt32();
- reply->writeFloat( streamVolume(stream) );
+ int output = data.readInt32();
+ reply->writeFloat( streamVolume(stream, output) );
return NO_ERROR;
} break;
case STREAM_MUTE: {
@@ -471,31 +563,12 @@ status_t BnAudioFlinger::onTransact(
reply->writeInt32( streamMute(stream) );
return NO_ERROR;
} break;
- case SET_ROUTING: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- int mode = data.readInt32();
- uint32_t routes = data.readInt32();
- uint32_t mask = data.readInt32();
- reply->writeInt32( setRouting(mode, routes, mask) );
- return NO_ERROR;
- } break;
- case GET_ROUTING: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- int mode = data.readInt32();
- reply->writeInt32( getRouting(mode) );
- return NO_ERROR;
- } break;
case SET_MODE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int mode = data.readInt32();
reply->writeInt32( setMode(mode) );
return NO_ERROR;
} break;
- case GET_MODE: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( getMode() );
- return NO_ERROR;
- } break;
case SET_MIC_MUTE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int state = data.readInt32();
@@ -512,13 +585,21 @@ status_t BnAudioFlinger::onTransact(
reply->writeInt32( isMusicActive() );
return NO_ERROR;
} break;
- case SET_PARAMETER: {
+ case SET_PARAMETERS: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- const char *key = data.readCString();
- const char *value = data.readCString();
- reply->writeInt32( setParameter(key, value) );
+ int ioHandle = data.readInt32();
+ String8 keyValuePairs(data.readString8());
+ reply->writeInt32(setParameters(ioHandle, keyValuePairs));
return NO_ERROR;
- } break;
+ } break;
+ case GET_PARAMETERS: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int ioHandle = data.readInt32();
+ String8 keys(data.readString8());
+ reply->writeString8(getParameters(ioHandle, keys));
+ return NO_ERROR;
+ } break;
+
case REGISTER_CLIENT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient>(data.readStrongBinder());
@@ -533,14 +614,81 @@ status_t BnAudioFlinger::onTransact(
reply->writeInt32( getInputBufferSize(sampleRate, format, channelCount) );
return NO_ERROR;
} break;
- case WAKE_UP: {
+ case OPEN_OUTPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- wakeUp();
+ uint32_t devices = data.readInt32();
+ uint32_t samplingRate = data.readInt32();
+ uint32_t format = data.readInt32();
+ uint32_t channels = data.readInt32();
+ uint32_t latency = data.readInt32();
+ uint32_t flags = data.readInt32();
+ int output = openOutput(&devices,
+ &samplingRate,
+ &format,
+ &channels,
+ &latency,
+ flags);
+ LOGV("OPEN_OUTPUT output, %p", output);
+ reply->writeInt32(output);
+ reply->writeInt32(devices);
+ reply->writeInt32(samplingRate);
+ reply->writeInt32(format);
+ reply->writeInt32(channels);
+ reply->writeInt32(latency);
return NO_ERROR;
} break;
- case IS_A2DP_ENABLED: {
+ case OPEN_DUPLICATE_OUTPUT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( (int)isA2dpEnabled() );
+ int output1 = data.readInt32();
+ int output2 = data.readInt32();
+ reply->writeInt32(openDuplicateOutput(output1, output2));
+ return NO_ERROR;
+ } break;
+ case CLOSE_OUTPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32(closeOutput(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case SUSPEND_OUTPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32(suspendOutput(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case RESTORE_OUTPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32(restoreOutput(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case OPEN_INPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ uint32_t devices = data.readInt32();
+ uint32_t samplingRate = data.readInt32();
+ uint32_t format = data.readInt32();
+ uint32_t channels = data.readInt32();
+ uint32_t acoutics = data.readInt32();
+
+ int input = openInput(&devices,
+ &samplingRate,
+ &format,
+ &channels,
+ acoutics);
+ reply->writeInt32(input);
+ reply->writeInt32(devices);
+ reply->writeInt32(samplingRate);
+ reply->writeInt32(format);
+ reply->writeInt32(channels);
+ return NO_ERROR;
+ } break;
+ case CLOSE_INPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32(closeInput(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case SET_STREAM_OUTPUT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ uint32_t stream = data.readInt32();
+ int output = data.readInt32();
+ reply->writeInt32(setStreamOutput(stream, output));
return NO_ERROR;
} break;
default:
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index 9d00aef..3900de4 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -20,14 +20,15 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
+#include <binder/Parcel.h>
#include <media/IAudioFlingerClient.h>
+#include <media/AudioSystem.h>
namespace android {
enum {
- AUDIO_OUTPUT_CHANGED = IBinder::FIRST_CALL_TRANSACTION
+ IO_CONFIG_CHANGED = IBinder::FIRST_CALL_TRANSACTION
};
class BpAudioFlingerClient : public BpInterface<IAudioFlingerClient>
@@ -38,12 +39,25 @@ public:
{
}
- void a2dpEnabledChanged(bool enabled)
+ void ioConfigChanged(int event, int ioHandle, void *param2)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
- data.writeInt32((int)enabled);
- remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+ data.writeInt32(event);
+ data.writeInt32(ioHandle);
+ if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
+ uint32_t stream = *(uint32_t *)param2;
+ LOGV("ioConfigChanged stream %d", stream);
+ data.writeInt32(stream);
+ } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) {
+ AudioSystem::OutputDescriptor *desc = (AudioSystem::OutputDescriptor *)param2;
+ data.writeInt32(desc->samplingRate);
+ data.writeInt32(desc->format);
+ data.writeInt32(desc->channels);
+ data.writeInt32(desc->frameCount);
+ data.writeInt32(desc->latency);
+ }
+ remote()->transact(IO_CONFIG_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
}
};
@@ -51,20 +65,30 @@ 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)
{
switch(code) {
- case AUDIO_OUTPUT_CHANGED: {
+ case IO_CONFIG_CHANGED: {
CHECK_INTERFACE(IAudioFlingerClient, data, reply);
- bool enabled = (bool)data.readInt32();
- a2dpEnabledChanged(enabled);
+ int event = data.readInt32();
+ int ioHandle = data.readInt32();
+ void *param2 = 0;
+ AudioSystem::OutputDescriptor desc;
+ uint32_t stream;
+ if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
+ stream = data.readInt32();
+ param2 = &stream;
+ LOGV("STREAM_CONFIG_CHANGED stream %d", stream);
+ } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) {
+ desc.samplingRate = data.readInt32();
+ desc.format = data.readInt32();
+ desc.channels = data.readInt32();
+ desc.frameCount = data.readInt32();
+ desc.latency = data.readInt32();
+ param2 = &desc;
+ }
+ ioConfigChanged(event, ioHandle, param2);
return NO_ERROR;
} break;
default:
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
new file mode 100644
index 0000000..18dd173
--- /dev/null
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -0,0 +1,413 @@
+/*
+**
+** 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 "IAudioPolicyService"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <media/IAudioPolicyService.h>
+
+namespace android {
+
+enum {
+ SET_DEVICE_CONNECTION_STATE = IBinder::FIRST_CALL_TRANSACTION,
+ GET_DEVICE_CONNECTION_STATE,
+ SET_PHONE_STATE,
+ SET_RINGER_MODE,
+ SET_FORCE_USE,
+ GET_FORCE_USE,
+ GET_OUTPUT,
+ START_OUTPUT,
+ STOP_OUTPUT,
+ RELEASE_OUTPUT,
+ GET_INPUT,
+ START_INPUT,
+ STOP_INPUT,
+ RELEASE_INPUT,
+ INIT_STREAM_VOLUME,
+ SET_STREAM_VOLUME,
+ GET_STREAM_VOLUME
+};
+
+class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
+{
+public:
+ BpAudioPolicyService(const sp<IBinder>& impl)
+ : BpInterface<IAudioPolicyService>(impl)
+ {
+ }
+
+ virtual status_t setDeviceConnectionState(
+ AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(device));
+ data.writeInt32(static_cast <uint32_t>(state));
+ data.writeCString(device_address);
+ remote()->transact(SET_DEVICE_CONNECTION_STATE, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(
+ AudioSystem::audio_devices device,
+ const char *device_address)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(device));
+ data.writeCString(device_address);
+ remote()->transact(GET_DEVICE_CONNECTION_STATE, data, &reply);
+ return static_cast <AudioSystem::device_connection_state>(reply.readInt32());
+ }
+
+ virtual status_t setPhoneState(int state)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(state);
+ remote()->transact(SET_PHONE_STATE, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t setRingerMode(uint32_t mode, uint32_t mask)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ data.writeInt32(mask);
+ remote()->transact(SET_RINGER_MODE, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(usage));
+ data.writeInt32(static_cast <uint32_t>(config));
+ remote()->transact(SET_FORCE_USE, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(usage));
+ remote()->transact(GET_FORCE_USE, data, &reply);
+ return static_cast <AudioSystem::forced_config> (reply.readInt32());
+ }
+
+ virtual audio_io_handle_t getOutput(
+ AudioSystem::stream_type stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::output_flags flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(stream));
+ data.writeInt32(samplingRate);
+ data.writeInt32(static_cast <uint32_t>(format));
+ data.writeInt32(channels);
+ data.writeInt32(static_cast <uint32_t>(flags));
+ remote()->transact(GET_OUTPUT, data, &reply);
+ return static_cast <audio_io_handle_t> (reply.readInt32());
+ }
+
+ virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(output);
+ data.writeInt32(stream);
+ remote()->transact(START_OUTPUT, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(output);
+ data.writeInt32(stream);
+ remote()->transact(STOP_OUTPUT, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual void releaseOutput(audio_io_handle_t output)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(output);
+ remote()->transact(RELEASE_OUTPUT, data, &reply);
+ }
+
+ virtual audio_io_handle_t getInput(
+ int inputSource,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ AudioSystem::audio_in_acoustics acoustics)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(inputSource);
+ data.writeInt32(samplingRate);
+ data.writeInt32(static_cast <uint32_t>(format));
+ data.writeInt32(channels);
+ data.writeInt32(static_cast <uint32_t>(acoustics));
+ remote()->transact(GET_INPUT, data, &reply);
+ return static_cast <audio_io_handle_t> (reply.readInt32());
+ }
+
+ virtual status_t startInput(audio_io_handle_t input)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(input);
+ remote()->transact(START_INPUT, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t stopInput(audio_io_handle_t input)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(input);
+ remote()->transact(STOP_INPUT, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual void releaseInput(audio_io_handle_t input)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(input);
+ remote()->transact(RELEASE_INPUT, data, &reply);
+ }
+
+ virtual status_t initStreamVolume(AudioSystem::stream_type stream,
+ int indexMin,
+ int indexMax)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(stream));
+ data.writeInt32(indexMin);
+ data.writeInt32(indexMax);
+ remote()->transact(INIT_STREAM_VOLUME, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(stream));
+ data.writeInt32(index);
+ remote()->transact(SET_STREAM_VOLUME, data, &reply);
+ return static_cast <status_t> (reply.readInt32());
+ }
+
+ virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast <uint32_t>(stream));
+ remote()->transact(GET_STREAM_VOLUME, data, &reply);
+ int lIndex = reply.readInt32();
+ if (index) *index = lIndex;
+ return static_cast <status_t> (reply.readInt32());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
+
+// ----------------------------------------------------------------------
+
+
+status_t BnAudioPolicyService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case SET_DEVICE_CONNECTION_STATE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32());
+ AudioSystem::device_connection_state state = static_cast <AudioSystem::device_connection_state>(data.readInt32());
+ const char *device_address = data.readCString();
+ reply->writeInt32(static_cast <uint32_t>(setDeviceConnectionState(device, state, device_address)));
+ return NO_ERROR;
+ } break;
+
+ case GET_DEVICE_CONNECTION_STATE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::audio_devices device = static_cast <AudioSystem::audio_devices>(data.readInt32());
+ const char *device_address = data.readCString();
+ reply->writeInt32(static_cast <uint32_t>(getDeviceConnectionState(device, device_address)));
+ return NO_ERROR;
+ } break;
+
+ case SET_PHONE_STATE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ reply->writeInt32(static_cast <uint32_t>(setPhoneState(data.readInt32())));
+ return NO_ERROR;
+ } break;
+
+ case SET_RINGER_MODE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ uint32_t mode = data.readInt32();
+ uint32_t mask = data.readInt32();
+ reply->writeInt32(static_cast <uint32_t>(setRingerMode(mode, mask)));
+ return NO_ERROR;
+ } break;
+
+ case SET_FORCE_USE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::force_use usage = static_cast <AudioSystem::force_use>(data.readInt32());
+ AudioSystem::forced_config config = static_cast <AudioSystem::forced_config>(data.readInt32());
+ reply->writeInt32(static_cast <uint32_t>(setForceUse(usage, config)));
+ return NO_ERROR;
+ } break;
+
+ case GET_FORCE_USE: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::force_use usage = static_cast <AudioSystem::force_use>(data.readInt32());
+ reply->writeInt32(static_cast <uint32_t>(getForceUse(usage)));
+ return NO_ERROR;
+ } break;
+
+ case GET_OUTPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+ uint32_t samplingRate = data.readInt32();
+ uint32_t format = data.readInt32();
+ uint32_t channels = data.readInt32();
+ AudioSystem::output_flags flags = static_cast <AudioSystem::output_flags>(data.readInt32());
+
+ audio_io_handle_t output = getOutput(stream,
+ samplingRate,
+ format,
+ channels,
+ flags);
+ reply->writeInt32(static_cast <int>(output));
+ return NO_ERROR;
+ } break;
+
+ case START_OUTPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
+ uint32_t stream = data.readInt32();
+ reply->writeInt32(static_cast <uint32_t>(startOutput(output, (AudioSystem::stream_type)stream)));
+ return NO_ERROR;
+ } break;
+
+ case STOP_OUTPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
+ uint32_t stream = data.readInt32();
+ reply->writeInt32(static_cast <uint32_t>(stopOutput(output, (AudioSystem::stream_type)stream)));
+ return NO_ERROR;
+ } break;
+
+ case RELEASE_OUTPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
+ releaseOutput(output);
+ return NO_ERROR;
+ } break;
+
+ case GET_INPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ int inputSource = data.readInt32();
+ uint32_t samplingRate = data.readInt32();
+ uint32_t format = data.readInt32();
+ uint32_t channels = data.readInt32();
+ AudioSystem::audio_in_acoustics acoustics = static_cast <AudioSystem::audio_in_acoustics>(data.readInt32());
+ audio_io_handle_t input = getInput(inputSource,
+ samplingRate,
+ format,
+ channels,
+ acoustics);
+ reply->writeInt32(static_cast <int>(input));
+ return NO_ERROR;
+ } break;
+
+ case START_INPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
+ reply->writeInt32(static_cast <uint32_t>(startInput(input)));
+ return NO_ERROR;
+ } break;
+
+ case STOP_INPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
+ reply->writeInt32(static_cast <uint32_t>(stopInput(input)));
+ return NO_ERROR;
+ } break;
+
+ case RELEASE_INPUT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_io_handle_t input = static_cast <audio_io_handle_t>(data.readInt32());
+ releaseInput(input);
+ return NO_ERROR;
+ } break;
+
+ case INIT_STREAM_VOLUME: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+ int indexMin = data.readInt32();
+ int indexMax = data.readInt32();
+ reply->writeInt32(static_cast <uint32_t>(initStreamVolume(stream, indexMin,indexMax)));
+ return NO_ERROR;
+ } break;
+
+ case SET_STREAM_VOLUME: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+ int index = data.readInt32();
+ reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream, index)));
+ return NO_ERROR;
+ } break;
+
+ case GET_STREAM_VOLUME: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ AudioSystem::stream_type stream = static_cast <AudioSystem::stream_type>(data.readInt32());
+ int index;
+ status_t status = getStreamVolumeIndex(stream, &index);
+ reply->writeInt32(index);
+ reply->writeInt32(static_cast <uint32_t>(status));
+ return NO_ERROR;
+ } break;
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
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..397a55b 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>
@@ -126,16 +126,10 @@ public:
}
};
-IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.hardware.IMediaMetadataRetriever");
+IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever");
// ----------------------------------------------------------------------
-#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)
{
@@ -215,4 +209,3 @@ status_t BnMediaMetadataRetriever::onTransact(
// ----------------------------------------------------------------------------
}; // namespace android
-
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index f18765a..5d9db10 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>
@@ -39,7 +39,10 @@ enum {
RESET,
SET_AUDIO_STREAM_TYPE,
SET_LOOPING,
- SET_VOLUME
+ SET_VOLUME,
+ INVOKE,
+ SET_METADATA_FILTER,
+ GET_METADATA,
};
class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -170,18 +173,38 @@ public:
remote()->transact(SET_VOLUME, data, &reply);
return reply.readInt32();
}
+
+ status_t invoke(const Parcel& request, Parcel *reply)
+ { // Avoid doing any extra copy. The interface descriptor should
+ // have been set by MediaPlayer.java.
+ return remote()->transact(INVOKE, request, reply);
+ }
+
+ status_t setMetadataFilter(const Parcel& request)
+ {
+ Parcel reply;
+ // Avoid doing any extra copy of the request. The interface
+ // descriptor should have been set by MediaPlayer.java.
+ remote()->transact(SET_METADATA_FILTER, request, &reply);
+ return reply.readInt32();
+ }
+
+ status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply)
+ {
+ Parcel request;
+ request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here.
+ request.writeInt32(update_only);
+ request.writeInt32(apply_filter);
+ remote()->transact(GET_METADATA, request, reply);
+ return reply->readInt32();
+ }
};
-IMPLEMENT_META_INTERFACE(MediaPlayer, "android.hardware.IMediaPlayer");
+IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.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)
{
@@ -266,6 +289,24 @@ status_t BnMediaPlayer::onTransact(
reply->writeInt32(setVolume(data.readFloat(), data.readFloat()));
return NO_ERROR;
} break;
+ case INVOKE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ invoke(data, reply);
+ return NO_ERROR;
+ } break;
+ case SET_METADATA_FILTER: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(setMetadataFilter(data));
+ return NO_ERROR;
+ } break;
+ case GET_METADATA: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ const status_t retcode = getMetadata(data.readInt32(), data.readInt32(), reply);
+ reply->setDataPosition(0);
+ reply->writeInt32(retcode);
+ reply->setDataPosition(0);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
@@ -274,4 +315,3 @@ status_t BnMediaPlayer::onTransact(
// ----------------------------------------------------------------------------
}; // namespace android
-
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
index 65022cd..bf51829 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>
@@ -46,16 +46,10 @@ public:
}
};
-IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient");
+IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.media.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)
{
@@ -74,4 +68,3 @@ status_t BnMediaPlayerClient::onTransact(
}
}; // namespace android
-
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 01cdb6c..8d2c360 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -17,11 +17,14 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Parcel.h>
-#include <utils/IMemory.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
+#include <media/IOMX.h>
+
+#include <utils/Errors.h> // for status_t
namespace android {
@@ -32,6 +35,7 @@ enum {
DECODE_FD,
CREATE_MEDIA_RECORDER,
CREATE_METADATA_RETRIEVER,
+ CREATE_OMX,
};
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
@@ -109,18 +113,19 @@ public:
*pFormat = reply.readInt32();
return interface_cast<IMemory>(reply.readStrongBinder());
}
+
+ virtual sp<IOMX> createOMX() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ remote()->transact(CREATE_OMX, data, &reply);
+ return interface_cast<IOMX>(reply.readStrongBinder());
+ }
};
-IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService");
+IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
// ----------------------------------------------------------------------
-#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)
{
@@ -187,6 +192,12 @@ status_t BnMediaPlayerService::onTransact(
reply->writeStrongBinder(retriever->asBinder());
return NO_ERROR;
} break;
+ case CREATE_OMX: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ sp<IOMX> omx = createOMX();
+ reply->writeStrongBinder(omx->asBinder());
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 84d08c4..df7d301 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>
@@ -264,16 +264,10 @@ public:
}
};
-IMPLEMENT_META_INTERFACE(MediaRecorder, "android.hardware.IMediaRecorder");
+IMPLEMENT_META_INTERFACE(MediaRecorder, "android.media.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/IOMX.cpp b/media/libmedia/IOMX.cpp
new file mode 100644
index 0000000..10bebd0
--- /dev/null
+++ b/media/libmedia/IOMX.cpp
@@ -0,0 +1,733 @@
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IOMX"
+#include <utils/Log.h>
+
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <media/IOMX.h>
+#include <ui/ISurface.h>
+#include <ui/Surface.h>
+
+namespace android {
+
+enum {
+ CONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ LIST_NODES,
+ ALLOCATE_NODE,
+ FREE_NODE,
+ SEND_COMMAND,
+ GET_PARAMETER,
+ SET_PARAMETER,
+ GET_CONFIG,
+ SET_CONFIG,
+ USE_BUFFER,
+ ALLOC_BUFFER,
+ ALLOC_BUFFER_WITH_BACKUP,
+ FREE_BUFFER,
+ OBSERVE_NODE,
+ FILL_BUFFER,
+ EMPTY_BUFFER,
+ GET_EXTENSION_INDEX,
+ CREATE_RENDERER,
+ OBSERVER_ON_MSG,
+ RENDERER_RENDER,
+};
+
+sp<IOMXRenderer> IOMX::createRenderer(
+ const sp<Surface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight) {
+ return createRenderer(
+ surface->getISurface(),
+ componentName, colorFormat, encodedWidth, encodedHeight,
+ displayWidth, displayHeight);
+}
+
+class BpOMX : public BpInterface<IOMX> {
+public:
+ BpOMX(const sp<IBinder> &impl)
+ : BpInterface<IOMX>(impl) {
+ }
+
+ virtual status_t list_nodes(List<String8> *list) {
+ list->clear();
+
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ remote()->transact(LIST_NODES, data, &reply);
+
+ int32_t n = reply.readInt32();
+ for (int32_t i = 0; i < n; ++i) {
+ String8 s = reply.readString8();
+
+ list->push_back(s);
+ }
+
+ return OK;
+ }
+
+ virtual status_t allocate_node(const char *name, node_id *node) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeCString(name);
+ remote()->transact(ALLOCATE_NODE, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err == OK) {
+ *node = (void*)reply.readIntPtr();
+ } else {
+ *node = 0;
+ }
+
+ return err;
+ }
+
+ virtual status_t free_node(node_id node) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ remote()->transact(FREE_NODE, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t send_command(
+ node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(cmd);
+ data.writeInt32(param);
+ remote()->transact(SEND_COMMAND, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t get_parameter(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(index);
+ data.writeInt32(size);
+ data.write(params, size);
+ remote()->transact(GET_PARAMETER, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ return err;
+ }
+
+ reply.read(params, size);
+
+ return OK;
+ }
+
+ virtual status_t set_parameter(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(index);
+ data.writeInt32(size);
+ data.write(params, size);
+ remote()->transact(SET_PARAMETER, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t get_config(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(index);
+ data.writeInt32(size);
+ data.write(params, size);
+ remote()->transact(GET_CONFIG, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ return err;
+ }
+
+ reply.read(params, size);
+
+ return OK;
+ }
+
+ virtual status_t set_config(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(index);
+ data.writeInt32(size);
+ data.write(params, size);
+ remote()->transact(SET_CONFIG, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t use_buffer(
+ node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+ buffer_id *buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(port_index);
+ data.writeStrongBinder(params->asBinder());
+ remote()->transact(USE_BUFFER, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ *buffer = 0;
+
+ return err;
+ }
+
+ *buffer = (void*)reply.readIntPtr();
+
+ return err;
+ }
+
+ virtual status_t allocate_buffer(
+ node_id node, OMX_U32 port_index, size_t size,
+ buffer_id *buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(port_index);
+ data.writeInt32(size);
+ remote()->transact(ALLOC_BUFFER, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ *buffer = 0;
+
+ return err;
+ }
+
+ *buffer = (void*)reply.readIntPtr();
+
+ return err;
+ }
+
+ virtual status_t allocate_buffer_with_backup(
+ node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+ buffer_id *buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(port_index);
+ data.writeStrongBinder(params->asBinder());
+ remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ *buffer = 0;
+
+ return err;
+ }
+
+ *buffer = (void*)reply.readIntPtr();
+
+ return err;
+ }
+
+ virtual status_t free_buffer(
+ node_id node, OMX_U32 port_index, buffer_id buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(port_index);
+ data.writeIntPtr((intptr_t)buffer);
+ remote()->transact(FREE_BUFFER, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t observe_node(
+ node_id node, const sp<IOMXObserver> &observer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeStrongBinder(observer->asBinder());
+ remote()->transact(OBSERVE_NODE, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual void fill_buffer(node_id node, buffer_id buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeIntPtr((intptr_t)buffer);
+ remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual void empty_buffer(
+ node_id node,
+ buffer_id buffer,
+ OMX_U32 range_offset, OMX_U32 range_length,
+ OMX_U32 flags, OMX_TICKS timestamp) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeIntPtr((intptr_t)buffer);
+ data.writeInt32(range_offset);
+ data.writeInt32(range_length);
+ data.writeInt32(flags);
+ data.writeInt64(timestamp);
+ remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual status_t get_extension_index(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeCString(parameter_name);
+
+ remote()->transact(GET_EXTENSION_INDEX, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err == OK) {
+ *index = static_cast<OMX_INDEXTYPE>(reply.readInt32());
+ } else {
+ *index = OMX_IndexComponentStartUnused;
+ }
+
+ return err;
+ }
+
+ virtual sp<IOMXRenderer> createRenderer(
+ const sp<ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+
+ data.writeStrongBinder(surface->asBinder());
+ data.writeCString(componentName);
+ data.writeInt32(colorFormat);
+ data.writeInt32(encodedWidth);
+ data.writeInt32(encodedHeight);
+ data.writeInt32(displayWidth);
+ data.writeInt32(displayHeight);
+
+ remote()->transact(CREATE_RENDERER, data, &reply);
+
+ return interface_cast<IOMXRenderer>(reply.readStrongBinder());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
+
+////////////////////////////////////////////////////////////////////////////////
+
+#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 BnOMX::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case LIST_NODES:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ List<String8> list;
+ list_nodes(&list);
+
+ reply->writeInt32(list.size());
+ for (List<String8>::iterator it = list.begin();
+ it != list.end(); ++it) {
+ reply->writeString8(*it);
+ }
+
+ return NO_ERROR;
+ }
+
+ case ALLOCATE_NODE:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node;
+ status_t err = allocate_node(data.readCString(), &node);
+ reply->writeInt32(err);
+ if (err == OK) {
+ reply->writeIntPtr((intptr_t)node);
+ }
+
+ return NO_ERROR;
+ }
+
+ case FREE_NODE:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+
+ reply->writeInt32(free_node(node));
+
+ return NO_ERROR;
+ }
+
+ case SEND_COMMAND:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+
+ OMX_COMMANDTYPE cmd =
+ static_cast<OMX_COMMANDTYPE>(data.readInt32());
+
+ OMX_S32 param = data.readInt32();
+ reply->writeInt32(send_command(node, cmd, param));
+
+ return NO_ERROR;
+ }
+
+ case GET_PARAMETER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
+
+ size_t size = data.readInt32();
+
+ // XXX I am not happy with this but Parcel::readInplace didn't work.
+ void *params = malloc(size);
+ data.read(params, size);
+
+ status_t err = get_parameter(node, index, params, size);
+
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->write(params, size);
+ }
+
+ free(params);
+ params = NULL;
+
+ return NO_ERROR;
+ }
+
+ case SET_PARAMETER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
+
+ size_t size = data.readInt32();
+ void *params = const_cast<void *>(data.readInplace(size));
+
+ reply->writeInt32(set_parameter(node, index, params, size));
+
+ return NO_ERROR;
+ }
+
+ case GET_CONFIG:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
+
+ size_t size = data.readInt32();
+
+ // XXX I am not happy with this but Parcel::readInplace didn't work.
+ void *params = malloc(size);
+ data.read(params, size);
+
+ status_t err = get_config(node, index, params, size);
+
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->write(params, size);
+ }
+
+ free(params);
+ params = NULL;
+
+ return NO_ERROR;
+ }
+
+ case SET_CONFIG:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_INDEXTYPE index = static_cast<OMX_INDEXTYPE>(data.readInt32());
+
+ size_t size = data.readInt32();
+ void *params = const_cast<void *>(data.readInplace(size));
+
+ reply->writeInt32(set_config(node, index, params, size));
+
+ return NO_ERROR;
+ }
+
+ case USE_BUFFER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_U32 port_index = data.readInt32();
+ sp<IMemory> params =
+ interface_cast<IMemory>(data.readStrongBinder());
+
+ buffer_id buffer;
+ status_t err = use_buffer(node, port_index, params, &buffer);
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->writeIntPtr((intptr_t)buffer);
+ }
+
+ return NO_ERROR;
+ }
+
+ case ALLOC_BUFFER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_U32 port_index = data.readInt32();
+ size_t size = data.readInt32();
+
+ buffer_id buffer;
+ status_t err = allocate_buffer(node, port_index, size, &buffer);
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->writeIntPtr((intptr_t)buffer);
+ }
+
+ return NO_ERROR;
+ }
+
+ case ALLOC_BUFFER_WITH_BACKUP:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_U32 port_index = data.readInt32();
+ sp<IMemory> params =
+ interface_cast<IMemory>(data.readStrongBinder());
+
+ buffer_id buffer;
+ status_t err = allocate_buffer_with_backup(
+ node, port_index, params, &buffer);
+
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->writeIntPtr((intptr_t)buffer);
+ }
+
+ return NO_ERROR;
+ }
+
+ case FREE_BUFFER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_U32 port_index = data.readInt32();
+ buffer_id buffer = (void*)data.readIntPtr();
+ reply->writeInt32(free_buffer(node, port_index, buffer));
+
+ return NO_ERROR;
+ }
+
+ case OBSERVE_NODE:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ sp<IOMXObserver> observer =
+ interface_cast<IOMXObserver>(data.readStrongBinder());
+ reply->writeInt32(observe_node(node, observer));
+
+ return NO_ERROR;
+ }
+
+ case FILL_BUFFER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ buffer_id buffer = (void*)data.readIntPtr();
+ fill_buffer(node, buffer);
+
+ return NO_ERROR;
+ }
+
+ case EMPTY_BUFFER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ buffer_id buffer = (void*)data.readIntPtr();
+ OMX_U32 range_offset = data.readInt32();
+ OMX_U32 range_length = data.readInt32();
+ OMX_U32 flags = data.readInt32();
+ OMX_TICKS timestamp = data.readInt64();
+
+ empty_buffer(
+ node, buffer, range_offset, range_length,
+ flags, timestamp);
+
+ return NO_ERROR;
+ }
+
+ case GET_EXTENSION_INDEX:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ const char *parameter_name = data.readCString();
+
+ OMX_INDEXTYPE index;
+ status_t err = get_extension_index(node, parameter_name, &index);
+
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->writeInt32(index);
+ }
+
+ return OK;
+ }
+
+ case CREATE_RENDERER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ sp<ISurface> isurface =
+ interface_cast<ISurface>(data.readStrongBinder());
+
+ const char *componentName = data.readCString();
+
+ OMX_COLOR_FORMATTYPE colorFormat =
+ static_cast<OMX_COLOR_FORMATTYPE>(data.readInt32());
+
+ size_t encodedWidth = (size_t)data.readInt32();
+ size_t encodedHeight = (size_t)data.readInt32();
+ size_t displayWidth = (size_t)data.readInt32();
+ size_t displayHeight = (size_t)data.readInt32();
+
+ sp<IOMXRenderer> renderer =
+ createRenderer(isurface, componentName, colorFormat,
+ encodedWidth, encodedHeight,
+ displayWidth, displayHeight);
+
+ reply->writeStrongBinder(renderer->asBinder());
+
+ return OK;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BpOMXObserver : public BpInterface<IOMXObserver> {
+public:
+ BpOMXObserver(const sp<IBinder> &impl)
+ : BpInterface<IOMXObserver>(impl) {
+ }
+
+ virtual void on_message(const omx_message &msg) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());
+ data.write(&msg, sizeof(msg));
+
+ remote()->transact(OBSERVER_ON_MSG, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(OMXObserver, "android.hardware.IOMXObserver");
+
+status_t BnOMXObserver::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case OBSERVER_ON_MSG:
+ {
+ CHECK_INTERFACE(IOMXObserver, data, reply);
+
+ omx_message msg;
+ data.read(&msg, sizeof(msg));
+
+ // XXX Could use readInplace maybe?
+ on_message(msg);
+
+ return NO_ERROR;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BpOMXRenderer : public BpInterface<IOMXRenderer> {
+public:
+ BpOMXRenderer(const sp<IBinder> &impl)
+ : BpInterface<IOMXRenderer>(impl) {
+ }
+
+ virtual void render(IOMX::buffer_id buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMXRenderer::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)buffer);
+
+ // NOTE: Do NOT make this a ONE_WAY call, it must be synchronous
+ // so that the caller knows when to recycle the buffer.
+ remote()->transact(RENDERER_RENDER, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(OMXRenderer, "android.hardware.IOMXRenderer");
+
+status_t BnOMXRenderer::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case RENDERER_RENDER:
+ {
+ CHECK_INTERFACE(IOMXRenderer, data, reply);
+
+ IOMX::buffer_id buffer = (void*)data.readIntPtr();
+
+ render(buffer);
+
+ return NO_ERROR;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace android
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 586aacb..ee9e1d8 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -99,7 +99,7 @@ int JetPlayer::init()
mAudioTrack->set(AudioSystem::MUSIC, //TODO parametrize this
pLibConfig->sampleRate,
1, // format = PCM 16bits per sample,
- pLibConfig->numChannels,
+ (pLibConfig->numChannels == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
mTrackBufferSize,
0);
diff --git a/media/libmedia/Metadata.cpp b/media/libmedia/Metadata.cpp
new file mode 100644
index 0000000..35ec6b3
--- /dev/null
+++ b/media/libmedia/Metadata.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Metadata"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <media/Metadata.h>
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+// This file contains code to serialize Metadata triples (key, type,
+// value) into a parcel. The Parcel is destinated to be decoded by the
+// Metadata.java class.
+
+namespace {
+// All these constants below must be kept in sync with Metadata.java.
+enum MetadataId {
+ FIRST_SYSTEM_ID = 1,
+ LAST_SYSTEM_ID = 31,
+ FIRST_CUSTOM_ID = 8192
+};
+
+// Types
+enum Types {
+ STRING_VAL = 1,
+ INTEGER_VAL,
+ BOOLEAN_VAL,
+ LONG_VAL,
+ DOUBLE_VAL,
+ TIMED_TEXT_VAL,
+ DATE_VAL,
+ BYTE_ARRAY_VAL,
+};
+
+const size_t kRecordHeaderSize = 3 * sizeof(int32_t);
+const int32_t kMetaMarker = 0x4d455441; // 'M' 'E' 'T' 'A'
+
+} // anonymous namespace
+
+namespace android {
+namespace media {
+
+Metadata::Metadata(Parcel *p)
+ :mData(p),
+ mBegin(p->dataPosition()) { }
+
+Metadata::~Metadata() { }
+
+void Metadata::resetParcel()
+{
+ mData->setDataPosition(mBegin);
+}
+
+// Update the 4 bytes int at the beginning of the parcel which holds
+// the number of bytes written so far.
+void Metadata::updateLength()
+{
+ const size_t end = mData->dataPosition();
+
+ mData->setDataPosition(mBegin);
+ mData->writeInt32(end - mBegin);
+ mData->setDataPosition(end);
+}
+
+// Write the header. The java layer will look for the marker.
+bool Metadata::appendHeader()
+{
+ bool ok = true;
+
+ // Placeholder for the length of the metadata
+ ok = ok && mData->writeInt32(-1) == OK;
+ ok = ok && mData->writeInt32(kMetaMarker) == OK;
+ return ok;
+}
+
+bool Metadata::appendBool(int key, bool val)
+{
+ if (!checkKey(key)) {
+ return false;
+ }
+
+ const size_t begin = mData->dataPosition();
+ bool ok = true;
+
+ // 4 int32s: size, key, type, value.
+ ok = ok && mData->writeInt32(4 * sizeof(int32_t)) == OK;
+ ok = ok && mData->writeInt32(key) == OK;
+ ok = ok && mData->writeInt32(BOOLEAN_VAL) == OK;
+ ok = ok && mData->writeInt32(val ? 1 : 0) == OK;
+ if (!ok) {
+ mData->setDataPosition(begin);
+ }
+ return ok;
+}
+
+bool Metadata::appendInt32(int key, int32_t val)
+{
+ if (!checkKey(key)) {
+ return false;
+ }
+
+ const size_t begin = mData->dataPosition();
+ bool ok = true;
+
+ // 4 int32s: size, key, type, value.
+ ok = ok && mData->writeInt32(4 * sizeof(int32_t)) == OK;
+ ok = ok && mData->writeInt32(key) == OK;
+ ok = ok && mData->writeInt32(INTEGER_VAL) == OK;
+ ok = ok && mData->writeInt32(val) == OK;
+ if (!ok) {
+ mData->setDataPosition(begin);
+ }
+ return ok;
+}
+
+// Check the key (i.e metadata id) is valid if it is a system one.
+// Loop over all the exiting ones in the Parcel to check for duplicate
+// (not allowed).
+bool Metadata::checkKey(int key)
+{
+ if (key < FIRST_SYSTEM_ID ||
+ (LAST_SYSTEM_ID < key && key < FIRST_CUSTOM_ID)) {
+ LOGE("Bad key %d", key);
+ return false;
+ }
+ size_t curr = mData->dataPosition();
+ // Loop over the keys to check if it has been used already.
+ mData->setDataPosition(mBegin);
+
+ bool error = false;
+ size_t left = curr - mBegin;
+ while (left > 0) {
+ size_t pos = mData->dataPosition();
+ size_t size = mData->readInt32();
+ if (size < kRecordHeaderSize || size > left) {
+ error = true;
+ break;
+ }
+ if (mData->readInt32() == key) {
+ LOGE("Key exists already %d", key);
+ error = true;
+ break;
+ }
+ mData->setDataPosition(pos + size);
+ left -= size;
+ }
+ mData->setDataPosition(curr);
+ return !error;
+}
+
+} // namespace android::media
+} // namespace android
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 5435da7..799c349 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -914,7 +914,7 @@ bool ToneGenerator::startTone(int toneType) {
}
}
} else {
- mState == TONE_IDLE;
+ mState = TONE_IDLE;
}
} else {
LOGV("Delayed start\n");
@@ -1001,7 +1001,7 @@ bool ToneGenerator::initAudioTrack() {
// Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
mpAudioTrack
- = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, 0, 0, audioCallback, this, 0);
+ = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, AudioSystem::CHANNEL_OUT_MONO, 0, 0, audioCallback, this, 0);
if (mpAudioTrack == 0) {
LOGE("AudioTrack allocation failed");
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 24e3e6f..aeb43c5 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 {
@@ -196,12 +196,47 @@ status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
return err;
}
+status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
+{
+ Mutex::Autolock _l(mLock);
+ if ((mPlayer != NULL) && ( mCurrentState & MEDIA_PLAYER_INITIALIZED ))
+ {
+ LOGV("invoke %d", request.dataSize());
+ return mPlayer->invoke(request, reply);
+ }
+ LOGE("invoke failed: wrong state %X", mCurrentState);
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
+{
+ LOGD("setMetadataFilter");
+ Mutex::Autolock lock(mLock);
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+ return mPlayer->setMetadataFilter(filter);
+}
+
+status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
+{
+ LOGD("getMetadata");
+ Mutex::Autolock lock(mLock);
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+ return mPlayer->getMetadata(update_only, apply_filter, metadata);
+}
+
status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
{
LOGV("setVideoSurface");
Mutex::Autolock _l(mLock);
if (mPlayer == 0) return NO_INIT;
- return mPlayer->setVideoSurface(surface->getISurface());
+ if (surface != NULL)
+ return mPlayer->setVideoSurface(surface->getISurface());
+ else
+ return mPlayer->setVideoSurface(NULL);
}
// must call with lock held
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 5093f0e..6b63931 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..84f858c 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -7,28 +7,39 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- MediaRecorderClient.cpp \
- MediaPlayerService.cpp \
+ MediaRecorderClient.cpp \
+ MediaPlayerService.cpp \
MetadataRetrieverClient.cpp \
- VorbisPlayer.cpp \
+ StagefrightPlayer.cpp \
+ TestPlayerStub.cpp \
+ VorbisPlayer.cpp \
MidiFile.cpp
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
LOCAL_LDLIBS += -ldl -lpthread
endif
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libvorbisidec \
- libsonivox \
- libopencore_player \
- libopencore_author \
- libmedia \
- libandroid_runtime
-
-LOCAL_C_INCLUDES := external/tremor/Tremor \
- $(call include-path-for, graphics corecg)
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libbinder \
+ libvorbisidec \
+ libsonivox \
+ libopencore_player \
+ libopencore_author \
+ libmedia \
+ libandroid_runtime \
+ libstagefright \
+ libstagefright_omx
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_C_INCLUDES := external/tremor/Tremor \
+ $(call include-path-for, graphics corecg) \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+ $(TOP)/frameworks/base/media/libstagefright/omx
LOCAL_MODULE:= libmediaplayerservice
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 31eecac..eeb4e49 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -27,18 +27,27 @@
#include <unistd.h>
#include <string.h>
+
#include <cutils/atomic.h>
+#include <cutils/properties.h> // for property_get
+
+#include <utils/misc.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 <utils/Errors.h> // for status_t
+#include <utils/String8.h>
+#include <utils/Vector.h>
#include <cutils/properties.h>
#include <media/MediaPlayerInterface.h>
#include <media/mediarecorder.h>
#include <media/MediaMetadataRetrieverInterface.h>
+#include <media/Metadata.h>
#include <media/AudioTrack.h>
#include "MediaRecorderClient.h"
@@ -48,6 +57,10 @@
#include "MidiFile.h"
#include "VorbisPlayer.h"
#include <media/PVPlayer.h>
+#include "TestPlayerStub.h"
+#include "StagefrightPlayer.h"
+
+#include <OMX.h>
/* desktop Linux needs a little help with gettid() */
#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
@@ -61,6 +74,111 @@ pid_t gettid() { return syscall(__NR_gettid);}
#undef __KERNEL__
#endif
+namespace {
+using android::media::Metadata;
+using android::status_t;
+using android::OK;
+using android::BAD_VALUE;
+using android::NOT_ENOUGH_DATA;
+using android::Parcel;
+
+// Max number of entries in the filter.
+const int kMaxFilterSize = 64; // I pulled that out of thin air.
+
+// FIXME: Move all the metadata related function in the Metadata.cpp
+
+
+// Unmarshall a filter from a Parcel.
+// Filter format in a parcel:
+//
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | number of entries (n) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | metadata type 1 |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | metadata type 2 |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// ....
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | metadata type n |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// @param p Parcel that should start with a filter.
+// @param[out] filter On exit contains the list of metadata type to be
+// filtered.
+// @param[out] status On exit contains the status code to be returned.
+// @return true if the parcel starts with a valid filter.
+bool unmarshallFilter(const Parcel& p,
+ Metadata::Filter *filter,
+ status_t *status)
+{
+ int32_t val;
+ if (p.readInt32(&val) != OK)
+ {
+ LOGE("Failed to read filter's length");
+ *status = NOT_ENOUGH_DATA;
+ return false;
+ }
+
+ if( val > kMaxFilterSize || val < 0)
+ {
+ LOGE("Invalid filter len %d", val);
+ *status = BAD_VALUE;
+ return false;
+ }
+
+ const size_t num = val;
+
+ filter->clear();
+ filter->setCapacity(num);
+
+ size_t size = num * sizeof(Metadata::Type);
+
+
+ if (p.dataAvail() < size)
+ {
+ LOGE("Filter too short expected %d but got %d", size, p.dataAvail());
+ *status = NOT_ENOUGH_DATA;
+ return false;
+ }
+
+ const Metadata::Type *data =
+ static_cast<const Metadata::Type*>(p.readInplace(size));
+
+ if (NULL == data)
+ {
+ LOGE("Filter had no data");
+ *status = BAD_VALUE;
+ return false;
+ }
+
+ // TODO: The stl impl of vector would be more efficient here
+ // because it degenerates into a memcpy on pod types. Try to
+ // replace later or use stl::set.
+ for (size_t i = 0; i < num; ++i)
+ {
+ filter->add(*data);
+ ++data;
+ }
+ *status = OK;
+ return true;
+}
+
+// @param filter Of metadata type.
+// @param val To be searched.
+// @return true if a match was found.
+bool findMetadata(const Metadata::Filter& filter, const int32_t val)
+{
+ // Deal with empty and ANY right away
+ if (filter.isEmpty()) return false;
+ if (filter[0] == Metadata::kAny) return true;
+
+ return filter.indexOf(val) >= 0;
+}
+
+} // anonymous namespace
+
namespace android {
@@ -105,7 +223,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;
}
@@ -151,6 +273,10 @@ sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClie
return c;
}
+sp<IOMX> MediaPlayerService::createOMX() {
+ return new OMX;
+}
+
status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
{
const size_t SIZE = 256;
@@ -457,6 +583,7 @@ void MediaPlayerService::Client::disconnect()
p = mPlayer;
}
mClient.clear();
+
mPlayer.clear();
// clear the notification to prevent callbacks to dead client
@@ -474,6 +601,16 @@ void MediaPlayerService::Client::disconnect()
IPCThreadState::self()->flushCommands();
}
+static player_type getDefaultPlayerType() {
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.stagefright.enable-player", value, NULL)
+ && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+ return STAGEFRIGHT_PLAYER;
+ }
+
+ return PV_PLAYER;
+}
+
static player_type getPlayerType(int fd, int64_t offset, int64_t length)
{
char buf[20];
@@ -504,12 +641,14 @@ static player_type getPlayerType(int fd, int64_t offset, int64_t length)
EAS_Shutdown(easdata);
}
- // Fall through to PV
- return PV_PLAYER;
+ return getDefaultPlayerType();
}
static player_type getPlayerType(const char* url)
{
+ if (TestPlayerStub::canBeUsed(url)) {
+ return TEST_PLAYER;
+ }
// use MidiFile for MIDI extensions
int lenURL = strlen(url);
@@ -523,8 +662,7 @@ static player_type getPlayerType(const char* url)
}
}
- // Fall through to PV
- return PV_PLAYER;
+ return getDefaultPlayerType();
}
static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
@@ -532,10 +670,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();
@@ -544,6 +684,14 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
LOGV(" create VorbisPlayer");
p = new VorbisPlayer();
break;
+ case STAGEFRIGHT_PLAYER:
+ LOGV(" create StagefrightPlayer");
+ p = new StagefrightPlayer;
+ break;
+ case TEST_PLAYER:
+ LOGV("Create Test Player stub");
+ p = new TestPlayerStub();
+ break;
}
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
@@ -608,7 +756,11 @@ status_t MediaPlayerService::Client::setDataSource(const char *url)
// now set data source
LOGV(" setDataSource");
mStatus = p->setDataSource(url);
- if (mStatus == NO_ERROR) mPlayer = p;
+ if (mStatus == NO_ERROR) {
+ mPlayer = p;
+ } else {
+ LOGE(" error: %d", mStatus);
+ }
return mStatus;
}
}
@@ -665,6 +817,73 @@ status_t MediaPlayerService::Client::setVideoSurface(const sp<ISurface>& surface
return p->setVideoSurface(surface);
}
+status_t MediaPlayerService::Client::invoke(const Parcel& request,
+ Parcel *reply)
+{
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == NULL) return UNKNOWN_ERROR;
+ return p->invoke(request, reply);
+}
+
+// This call doesn't need to access the native player.
+status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter)
+{
+ status_t status;
+ media::Metadata::Filter allow, drop;
+
+ if (unmarshallFilter(filter, &allow, &status) &&
+ unmarshallFilter(filter, &drop, &status)) {
+ Mutex::Autolock lock(mLock);
+
+ mMetadataAllow = allow;
+ mMetadataDrop = drop;
+ }
+ return status;
+}
+
+status_t MediaPlayerService::Client::getMetadata(
+ bool update_only, bool apply_filter, Parcel *reply)
+{
+ sp<MediaPlayerBase> player = getPlayer();
+ if (player == 0) return UNKNOWN_ERROR;
+
+ status_t status;
+ // Placeholder for the return code, updated by the caller.
+ reply->writeInt32(-1);
+
+ media::Metadata::Filter ids;
+
+ // We don't block notifications while we fetch the data. We clear
+ // mMetadataUpdated first so we don't lose notifications happening
+ // during the rest of this call.
+ {
+ Mutex::Autolock lock(mLock);
+ if (update_only) {
+ ids = mMetadataUpdated;
+ }
+ mMetadataUpdated.clear();
+ }
+
+ media::Metadata metadata(reply);
+
+ metadata.appendHeader();
+ status = player->getMetadata(ids, reply);
+
+ if (status != OK) {
+ metadata.resetParcel();
+ LOGE("getMetadata failed %d", status);
+ return status;
+ }
+
+ // FIXME: Implement filtering on the result. Not critical since
+ // filtering takes place on the update notifications already. This
+ // would be when all the metadata are fetch and a filter is set.
+
+ // Everything is fine, update the metadata length.
+ metadata.updateLength();
+ return OK;
+}
+
status_t MediaPlayerService::Client::prepareAsync()
{
LOGV("[%d] prepareAsync", mConnId);
@@ -784,13 +1003,51 @@ status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolu
return NO_ERROR;
}
+
void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
{
Client* client = static_cast<Client*>(cookie);
+
+ if (MEDIA_INFO == msg &&
+ MEDIA_INFO_METADATA_UPDATE == ext1) {
+ const media::Metadata::Type metadata_type = ext2;
+
+ if(client->shouldDropMetadata(metadata_type)) {
+ return;
+ }
+
+ // Update the list of metadata that have changed. getMetadata
+ // also access mMetadataUpdated and clears it.
+ client->addNewMetadataUpdate(metadata_type);
+ }
LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
client->mClient->notify(msg, ext1, ext2);
}
+
+bool MediaPlayerService::Client::shouldDropMetadata(media::Metadata::Type code) const
+{
+ Mutex::Autolock lock(mLock);
+
+ if (findMetadata(mMetadataDrop, code)) {
+ return true;
+ }
+
+ if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+void MediaPlayerService::Client::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
+ Mutex::Autolock lock(mLock);
+ if (mMetadataUpdated.indexOf(metadata_type) < 0) {
+ mMetadataUpdated.add(metadata_type);
+ }
+}
+
#if CALLBACK_ANTAGONIZER
const int Antagonizer::interval = 10000; // 10 msecs
@@ -927,7 +1184,8 @@ Exit:
#undef LOG_TAG
#define LOG_TAG "AudioSink"
MediaPlayerService::AudioOutput::AudioOutput()
-{
+ : mCallback(NULL),
+ mCallbackCookie(NULL) {
mTrack = 0;
mStreamType = AudioSystem::MUSIC;
mLeftVolume = 1.0;
@@ -997,8 +1255,13 @@ float MediaPlayerService::AudioOutput::msecsPerFrame() const
return mMsecsPerFrame;
}
-status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelCount, int format, int bufferCount)
+status_t MediaPlayerService::AudioOutput::open(
+ uint32_t sampleRate, int channelCount, int format, int bufferCount,
+ AudioCallback cb, void *cookie)
{
+ mCallback = cb;
+ mCallbackCookie = cookie;
+
// Check argument "bufferCount" against the mininum buffer count
if (bufferCount < mMinBufferCount) {
LOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
@@ -1019,7 +1282,27 @@ status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelC
}
frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
- AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount);
+
+ AudioTrack *t;
+ if (mCallback != NULL) {
+ t = new AudioTrack(
+ mStreamType,
+ sampleRate,
+ format,
+ (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
+ frameCount,
+ 0 /* flags */,
+ CallbackWrapper,
+ this);
+ } else {
+ t = new AudioTrack(
+ mStreamType,
+ sampleRate,
+ format,
+ (channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
+ frameCount);
+ }
+
if ((t == 0) || (t->initCheck() != NO_ERROR)) {
LOGE("Unable to create audio track");
delete t;
@@ -1045,6 +1328,8 @@ void MediaPlayerService::AudioOutput::start()
ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
{
+ LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
+
//LOGV("write(%p, %u)", buffer, size);
if (mTrack) return mTrack->write(buffer, size);
return NO_INIT;
@@ -1085,6 +1370,20 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right)
}
}
+// static
+void MediaPlayerService::AudioOutput::CallbackWrapper(
+ int event, void *cookie, void *info) {
+ if (event != AudioTrack::EVENT_MORE_DATA) {
+ return;
+ }
+
+ AudioOutput *me = (AudioOutput *)cookie;
+ AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+
+ (*me->mCallback)(
+ me, buffer->raw, buffer->size, me->mCallbackCookie);
+}
+
#undef LOG_TAG
#define LOG_TAG "AudioCache"
MediaPlayerService::AudioCache::AudioCache(const char* name) :
@@ -1105,8 +1404,14 @@ float MediaPlayerService::AudioCache::msecsPerFrame() const
return mMsecsPerFrame;
}
-status_t MediaPlayerService::AudioCache::open(uint32_t sampleRate, int channelCount, int format, int bufferCount)
+status_t MediaPlayerService::AudioCache::open(
+ uint32_t sampleRate, int channelCount, int format, int bufferCount,
+ AudioCallback cb, void *cookie)
{
+ if (cb != NULL) {
+ return UNKNOWN_ERROR; // TODO: implement this.
+ }
+
LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
if (mHeap->getHeapID() < 0) return NO_INIT;
mSampleRate = sampleRate;
@@ -1171,4 +1476,4 @@ void MediaPlayerService::AudioCache::notify(void* cookie, int msg, int ext1, int
p->mSignal.signal();
}
-}; // namespace android
+} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index f138886..a4be414 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -18,17 +18,23 @@
#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 <utils/Vector.h>
#include <ui/SurfaceComposerClient.h>
#include <media/IMediaPlayerService.h>
#include <media/MediaPlayerInterface.h>
+#include <media/Metadata.h>
namespace android {
class IMediaRecorder;
class IMediaMetadataRetriever;
+class IOMX;
#define CALLBACK_ANTAGONIZER 0
#if CALLBACK_ANTAGONIZER
@@ -69,7 +75,12 @@ class MediaPlayerService : public BnMediaPlayerService
virtual ssize_t frameSize() const;
virtual uint32_t latency() const;
virtual float msecsPerFrame() const;
- virtual status_t open(uint32_t sampleRate, int channelCount, int format, int bufferCount=4);
+
+ virtual status_t open(
+ uint32_t sampleRate, int channelCount,
+ int format, int bufferCount,
+ AudioCallback cb, void *cookie);
+
virtual void start();
virtual ssize_t write(const void* buffer, size_t size);
virtual void stop();
@@ -84,8 +95,12 @@ class MediaPlayerService : public BnMediaPlayerService
static int getMinBufferCount();
private:
static void setMinBufferCount();
+ static void CallbackWrapper(
+ int event, void *me, void *info);
AudioTrack* mTrack;
+ AudioCallback mCallback;
+ void * mCallbackCookie;
int mStreamType;
float mLeftVolume;
float mRightVolume;
@@ -113,7 +128,12 @@ class MediaPlayerService : public BnMediaPlayerService
virtual ssize_t frameSize() const { return ssize_t(mChannelCount * ((mFormat == AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); }
virtual uint32_t latency() const;
virtual float msecsPerFrame() const;
- virtual status_t open(uint32_t sampleRate, int channelCount, int format, int bufferCount=1);
+
+ virtual status_t open(
+ uint32_t sampleRate, int channelCount, int format,
+ int bufferCount = 1,
+ AudioCallback cb = NULL, void *cookie = NULL);
+
virtual void start() {}
virtual ssize_t write(const void* buffer, size_t size);
virtual void stop() {}
@@ -140,7 +160,7 @@ class MediaPlayerService : public BnMediaPlayerService
sp<MemoryHeapBase> mHeap;
float mMsecsPerFrame;
uint16_t mChannelCount;
- uint16_t mFormat;
+ uint16_t mFormat;
ssize_t mFrameCount;
uint32_t mSampleRate;
uint32_t mSize;
@@ -160,11 +180,13 @@ public:
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
+ virtual sp<IOMX> createOMX();
virtual status_t dump(int fd, const Vector<String16>& args);
void removeClient(wp<Client> client);
+
private:
class Client : public BnMediaPlayer {
@@ -184,6 +206,11 @@ private:
virtual status_t setAudioStreamType(int type);
virtual status_t setLooping(int loop);
virtual status_t setVolume(float leftVolume, float rightVolume);
+ virtual status_t invoke(const Parcel& request, Parcel *reply);
+ virtual status_t setMetadataFilter(const Parcel& filter);
+ virtual status_t getMetadata(bool update_only,
+ bool apply_filter,
+ Parcel *reply);
sp<MediaPlayerBase> createPlayer(player_type playerType);
status_t setDataSource(const char *url);
@@ -206,6 +233,18 @@ private:
sp<MediaPlayerBase> getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
+
+
+ // @param type Of the metadata to be tested.
+ // @return true if the metadata should be dropped according to
+ // the filters.
+ bool shouldDropMetadata(media::Metadata::Type type) const;
+
+ // Add a new element to the set of metadata updated. Noop if
+ // the element exists already.
+ // @param type Of the metadata to be recorded.
+ void addNewMetadataUpdate(media::Metadata::Type type);
+
mutable Mutex mLock;
sp<MediaPlayerBase> mPlayer;
sp<MediaPlayerService> mService;
@@ -215,6 +254,17 @@ private:
status_t mStatus;
bool mLoop;
int32_t mConnId;
+
+ // Metadata filters.
+ media::Metadata::Filter mMetadataAllow; // protected by mLock
+ media::Metadata::Filter mMetadataDrop; // protected by mLock
+
+ // Metadata updated. For each MEDIA_INFO_METADATA_UPDATE
+ // notification we try to update mMetadataUpdated which is a
+ // set: no duplicate.
+ // getMetadata clears this set.
+ media::Metadata::Filter mMetadataUpdated; // protected by mLock
+
#if CALLBACK_ANTAGONIZER
Antagonizer* mAntagonizer;
#endif
@@ -235,4 +285,3 @@ private:
}; // namespace android
#endif // ANDROID_MEDIAPLAYERSERVICE_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/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
index 302f1cf..25d4a1b 100644
--- a/media/libmediaplayerservice/MidiFile.h
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -46,6 +46,9 @@ public:
virtual status_t reset();
virtual status_t setLooping(int loop);
virtual player_type playerType() { return SONIVOX_PLAYER; }
+ virtual status_t invoke(const Parcel& request, Parcel *reply) {
+ return INVALID_OPERATION;
+ }
private:
status_t createOutputTrack();
@@ -74,4 +77,3 @@ private:
}; // namespace android
#endif // ANDROID_MIDIFILE_H
-
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
new file mode 100644
index 0000000..9a06d13
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -0,0 +1,208 @@
+//#define LOG_NDEBUG 0
+#define LOG_TAG "StagefrightPlayer"
+#include <utils/Log.h>
+
+#include "StagefrightPlayer.h"
+#include <media/stagefright/MediaPlayerImpl.h>
+
+namespace android {
+
+StagefrightPlayer::StagefrightPlayer()
+ : mPlayer(NULL) {
+ LOGV("StagefrightPlayer");
+}
+
+StagefrightPlayer::~StagefrightPlayer() {
+ LOGV("~StagefrightPlayer");
+ reset();
+ LOGV("~StagefrightPlayer done.");
+}
+
+status_t StagefrightPlayer::initCheck() {
+ LOGV("initCheck");
+ return OK;
+}
+
+status_t StagefrightPlayer::setDataSource(const char *url) {
+ LOGV("setDataSource('%s')", url);
+
+ reset();
+ mPlayer = new MediaPlayerImpl(url);
+
+ status_t err = mPlayer->initCheck();
+ if (err != OK) {
+ delete mPlayer;
+ mPlayer = NULL;
+ } else {
+ mPlayer->setAudioSink(mAudioSink);
+ }
+
+ return err;
+}
+
+status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
+ LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+
+ reset();
+ mPlayer = new MediaPlayerImpl(fd, offset, length);
+
+ status_t err = mPlayer->initCheck();
+ if (err != OK) {
+ delete mPlayer;
+ mPlayer = NULL;
+ } else {
+ mPlayer->setAudioSink(mAudioSink);
+ }
+
+ return err;
+}
+
+status_t StagefrightPlayer::setVideoSurface(const sp<ISurface> &surface) {
+ LOGV("setVideoSurface");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ mPlayer->setISurface(surface);
+
+ return OK;
+}
+
+status_t StagefrightPlayer::prepare() {
+ LOGV("prepare");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ sendEvent(
+ MEDIA_SET_VIDEO_SIZE,
+ mPlayer->getWidth(), mPlayer->getHeight());
+
+ return OK;
+}
+
+status_t StagefrightPlayer::prepareAsync() {
+ LOGV("prepareAsync");
+
+ status_t err = prepare();
+
+ if (err != OK) {
+ return err;
+ }
+
+ sendEvent(MEDIA_PREPARED);
+
+ return OK;
+}
+
+status_t StagefrightPlayer::start() {
+ LOGV("start");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ mPlayer->play();
+
+ return OK;
+}
+
+status_t StagefrightPlayer::stop() {
+ LOGV("stop");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ reset();
+
+ return OK;
+}
+
+status_t StagefrightPlayer::pause() {
+ LOGV("pause");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ mPlayer->pause();
+
+ return OK;
+}
+
+bool StagefrightPlayer::isPlaying() {
+ LOGV("isPlaying");
+ return mPlayer != NULL && mPlayer->isPlaying();
+}
+
+status_t StagefrightPlayer::seekTo(int msec) {
+ LOGV("seekTo");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ status_t err = mPlayer->seekTo((int64_t)msec * 1000);
+
+ sendEvent(MEDIA_SEEK_COMPLETE);
+
+ return err;
+}
+
+status_t StagefrightPlayer::getCurrentPosition(int *msec) {
+ LOGV("getCurrentPosition");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ *msec = mPlayer->getPosition() / 1000;
+ return OK;
+}
+
+status_t StagefrightPlayer::getDuration(int *msec) {
+ LOGV("getDuration");
+
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ *msec = mPlayer->getDuration() / 1000;
+ return OK;
+}
+
+status_t StagefrightPlayer::reset() {
+ LOGV("reset");
+
+ delete mPlayer;
+ mPlayer = NULL;
+
+ return OK;
+}
+
+status_t StagefrightPlayer::setLooping(int loop) {
+ LOGV("setLooping");
+ return UNKNOWN_ERROR;
+}
+
+player_type StagefrightPlayer::playerType() {
+ LOGV("playerType");
+ return STAGEFRIGHT_PLAYER;
+}
+
+status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) {
+ return INVALID_OPERATION;
+}
+
+void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) {
+ MediaPlayerInterface::setAudioSink(audioSink);
+
+ if (mPlayer != NULL) {
+ mPlayer->setAudioSink(audioSink);
+ }
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
new file mode 100644
index 0000000..f214872
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -0,0 +1,60 @@
+/*
+**
+** 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.
+*/
+
+#ifndef ANDROID_STAGEFRIGHTPLAYER_H
+#define ANDROID_STAGEFRIGHTPLAYER_H
+
+#include <media/MediaPlayerInterface.h>
+
+namespace android {
+
+class MediaPlayerImpl;
+
+class StagefrightPlayer : public MediaPlayerInterface {
+public:
+ StagefrightPlayer();
+ virtual ~StagefrightPlayer();
+
+ virtual status_t initCheck();
+ virtual status_t setDataSource(const char *url);
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+ virtual status_t setVideoSurface(const sp<ISurface> &surface);
+ virtual status_t prepare();
+ virtual status_t prepareAsync();
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t pause();
+ virtual bool isPlaying();
+ virtual status_t seekTo(int msec);
+ virtual status_t getCurrentPosition(int *msec);
+ virtual status_t getDuration(int *msec);
+ virtual status_t reset();
+ virtual status_t setLooping(int loop);
+ virtual player_type playerType();
+ virtual status_t invoke(const Parcel &request, Parcel *reply);
+ virtual void setAudioSink(const sp<AudioSink> &audioSink);
+
+private:
+ MediaPlayerImpl *mPlayer;
+
+ StagefrightPlayer(const StagefrightPlayer &);
+ StagefrightPlayer &operator=(const StagefrightPlayer &);
+};
+
+} // namespace android
+
+#endif // ANDROID_STAGEFRIGHTPLAYER_H
diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp
new file mode 100644
index 0000000..8627708
--- /dev/null
+++ b/media/libmediaplayerservice/TestPlayerStub.cpp
@@ -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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TestPlayerStub"
+#include "utils/Log.h"
+
+#include "TestPlayerStub.h"
+
+#include <dlfcn.h> // for dlopen/dlclose
+#include <stdlib.h>
+#include <string.h>
+#include <cutils/properties.h>
+#include <utils/Errors.h> // for status_t
+
+#include "media/MediaPlayerInterface.h"
+
+
+namespace {
+using android::status_t;
+using android::MediaPlayerBase;
+
+const char *kTestUrlScheme = "test:";
+const char *kUrlParam = "url=";
+
+const char *kBuildTypePropName = "ro.build.type";
+const char *kEngBuild = "eng";
+const char *kTestBuild = "test";
+
+// @return true if the current build is 'eng' or 'test'.
+bool isTestBuild()
+{
+ char prop[PROPERTY_VALUE_MAX] = { '\0', };
+
+ property_get(kBuildTypePropName, prop, '\0');
+ return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0;
+}
+
+// @return true if the url scheme is 'test:'
+bool isTestUrl(const char *url)
+{
+ return url && strncmp(url, kTestUrlScheme, strlen(kTestUrlScheme)) == 0;
+}
+
+} // anonymous namespace
+
+namespace android {
+
+TestPlayerStub::TestPlayerStub()
+ :mUrl(NULL), mFilename(NULL), mContentUrl(NULL),
+ mHandle(NULL), mNewPlayer(NULL), mDeletePlayer(NULL),
+ mPlayer(NULL) { }
+
+TestPlayerStub::~TestPlayerStub()
+{
+ resetInternal();
+}
+
+status_t TestPlayerStub::initCheck()
+{
+ return isTestBuild() ? OK : INVALID_OPERATION;
+}
+
+// Parse mUrl to get:
+// * The library to be dlopened.
+// * The url to be passed to the real setDataSource impl.
+//
+// mUrl is expected to be in following format:
+//
+// test:<name of the .so>?url=<url for setDataSource>
+//
+// The value of the url parameter is treated as a string (no
+// unescaping of illegal charaters).
+status_t TestPlayerStub::parseUrl()
+{
+ if (strlen(mUrl) < strlen(kTestUrlScheme)) {
+ resetInternal();
+ return BAD_VALUE;
+ }
+
+ char *i = mUrl + strlen(kTestUrlScheme);
+
+ mFilename = i;
+
+ while (*i != '\0' && *i != '?') {
+ ++i;
+ }
+
+ if (*i == '\0' || strncmp(i + 1, kUrlParam, strlen(kUrlParam)) != 0) {
+ resetInternal();
+ return BAD_VALUE;
+ }
+ *i = '\0'; // replace '?' to nul-terminate mFilename
+
+ mContentUrl = i + 1 + strlen(kUrlParam);
+ return OK;
+}
+
+// Load the dynamic library.
+// Create the test player.
+// Call setDataSource on the test player with the url in param.
+status_t TestPlayerStub::setDataSource(const char *url)
+{
+ if (!isTestUrl(url) || NULL != mHandle) {
+ return INVALID_OPERATION;
+ }
+
+ mUrl = strdup(url);
+
+ status_t status = parseUrl();
+
+ if (OK != status) {
+ resetInternal();
+ return status;
+ }
+
+ ::dlerror(); // Clears any pending error.
+
+ // Load the test player from the url. dlopen will fail if the lib
+ // is not there. dls are under /system/lib
+ // None of the entry points should be NULL.
+ mHandle = ::dlopen(mFilename, RTLD_NOW | RTLD_GLOBAL);
+ if (!mHandle) {
+ LOGE("dlopen failed: %s", ::dlerror());
+ resetInternal();
+ return UNKNOWN_ERROR;
+ }
+
+ // Load the 2 entry points to create and delete instances.
+ const char *err;
+ mNewPlayer = reinterpret_cast<NEW_PLAYER>(dlsym(mHandle,
+ "newPlayer"));
+ err = ::dlerror();
+ if (err || mNewPlayer == NULL) {
+ // if err is NULL the string <null> is inserted in the logs =>
+ // mNewPlayer was NULL.
+ LOGE("dlsym for newPlayer failed %s", err);
+ resetInternal();
+ return UNKNOWN_ERROR;
+ }
+
+ mDeletePlayer = reinterpret_cast<DELETE_PLAYER>(dlsym(mHandle,
+ "deletePlayer"));
+ err = ::dlerror();
+ if (err || mDeletePlayer == NULL) {
+ LOGE("dlsym for deletePlayer failed %s", err);
+ resetInternal();
+ return UNKNOWN_ERROR;
+ }
+
+ mPlayer = (*mNewPlayer)();
+ return mPlayer->setDataSource(mContentUrl);
+}
+
+// Internal cleanup.
+status_t TestPlayerStub::resetInternal()
+{
+ if(mUrl) {
+ free(mUrl);
+ mUrl = NULL;
+ }
+ mFilename = NULL;
+ mContentUrl = NULL;
+
+ if (mPlayer) {
+ LOG_ASSERT(mDeletePlayer != NULL);
+ (*mDeletePlayer)(mPlayer);
+ mPlayer = NULL;
+ }
+
+ if (mHandle) {
+ ::dlclose(mHandle);
+ mHandle = NULL;
+ }
+ return OK;
+}
+
+/* static */ bool TestPlayerStub::canBeUsed(const char *url)
+{
+ return isTestBuild() && isTestUrl(url);
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h
new file mode 100644
index 0000000..80d53a8
--- /dev/null
+++ b/media/libmediaplayerservice/TestPlayerStub.h
@@ -0,0 +1,119 @@
+/*
+ * 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_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__
+#define ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__
+
+#include <media/MediaPlayerInterface.h>
+#include <utils/Errors.h>
+
+namespace android {
+class MediaPlayerBase; // in media/MediaPlayerInterface.h
+
+// Wrapper around a test media player that gets dynamically loaded.
+//
+// The URL passed to setDataSource has this format:
+//
+// test:<name of the .so>?url=<url for the real setDataSource impl.>
+//
+// e.g:
+// test:invoke_test_media_player.so?url=http://youtube.com/
+// test:invoke_test_media_player.so?url=speedtest
+//
+// TestPlayerStub::setDataSource loads the library in the test url. 2
+// entry points with C linkage are expected. One to create the test
+// player and one to destroy it.
+//
+// extern "C" android::MediaPlayerBase* newPlayer();
+// extern "C" android::status_t deletePlayer(android::MediaPlayerBase *p);
+//
+// Once the test player has been loaded, its setDataSource
+// implementation is called with the value of the 'url' parameter.
+//
+// typical usage in a java test:
+// ============================
+//
+// MediaPlayer p = new MediaPlayer();
+// p.setDataSource("test:invoke_mock_media_player.so?url=http://youtube.com");
+// p.prepare();
+// ...
+// p.release();
+
+class TestPlayerStub : public MediaPlayerInterface {
+ public:
+ typedef MediaPlayerBase* (*NEW_PLAYER)();
+ typedef status_t (*DELETE_PLAYER)(MediaPlayerBase *);
+
+ TestPlayerStub();
+ virtual ~TestPlayerStub();
+
+ // Called right after the constructor. Check if the current build
+ // allows test players.
+ virtual status_t initCheck();
+
+ // @param url Should be a test url. See class comment.
+ virtual status_t setDataSource(const char* url);
+
+ // Test player for a file descriptor source is not supported.
+ virtual status_t setDataSource(int, int64_t, int64_t) {
+ return INVALID_OPERATION;
+ }
+
+
+ // All the methods below wrap the mPlayer instance.
+ virtual status_t setVideoSurface(const android::sp<android::ISurface>& s) {
+ return mPlayer->setVideoSurface(s);
+ }
+ virtual status_t prepare() {return mPlayer->prepare();}
+ virtual status_t prepareAsync() {return mPlayer->prepareAsync();}
+ virtual status_t start() {return mPlayer->start();}
+ virtual status_t stop() {return mPlayer->stop();}
+ virtual status_t pause() {return mPlayer->pause();}
+ virtual bool isPlaying() {return mPlayer->isPlaying();}
+ virtual status_t seekTo(int msec) {return mPlayer->seekTo(msec);}
+ virtual status_t getCurrentPosition(int *p) {
+ return mPlayer->getCurrentPosition(p);
+ }
+ virtual status_t getDuration(int *d) {return mPlayer->getDuration(d);}
+ virtual status_t reset() {return mPlayer->reset();}
+ virtual status_t setLooping(int b) {return mPlayer->setLooping(b);}
+ virtual player_type playerType() {return mPlayer->playerType();}
+ virtual status_t invoke(const android::Parcel& in, android::Parcel *out) {
+ return mPlayer->invoke(in, out);
+ }
+
+
+ // @return true if the current build is 'eng' or 'test' and the
+ // url's scheme is 'test:'
+ static bool canBeUsed(const char *url);
+
+ private:
+ // Release the player, dlclose the library.
+ status_t resetInternal();
+ status_t parseUrl();
+
+ char *mUrl; // test:foo.so?url=http://bar
+ char *mFilename; // foo.so
+ char *mContentUrl; // http://bar
+ void *mHandle; // returned by dlopen
+ NEW_PLAYER mNewPlayer;
+ DELETE_PLAYER mDeletePlayer;
+ MediaPlayerBase *mPlayer; // wrapped player
+};
+
+} // namespace android
+
+#endif
diff --git a/media/libmediaplayerservice/VorbisPlayer.h b/media/libmediaplayerservice/VorbisPlayer.h
index c30dc1b..4024654 100644
--- a/media/libmediaplayerservice/VorbisPlayer.h
+++ b/media/libmediaplayerservice/VorbisPlayer.h
@@ -53,6 +53,7 @@ public:
virtual status_t reset();
virtual status_t setLooping(int loop);
virtual player_type playerType() { return VORBIS_PLAYER; }
+ virtual status_t invoke(const Parcel& request, Parcel *reply) {return INVALID_OPERATION;}
private:
status_t setdatasource(const char *path, int fd, int64_t offset, int64_t length);
@@ -88,4 +89,3 @@ private:
}; // namespace android
#endif // ANDROID_VORBISPLAYER_H
-
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
new file mode 100644
index 0000000..20b0da2
--- /dev/null
+++ b/media/libstagefright/Android.mk
@@ -0,0 +1,54 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ CachingDataSource.cpp \
+ DataSource.cpp \
+ FileSource.cpp \
+ HTTPDataSource.cpp \
+ HTTPStream.cpp \
+ MP3Extractor.cpp \
+ MPEG4Extractor.cpp \
+ MPEG4Writer.cpp \
+ MediaBuffer.cpp \
+ MediaBufferGroup.cpp \
+ MediaExtractor.cpp \
+ MediaPlayerImpl.cpp \
+ MediaSource.cpp \
+ MetaData.cpp \
+ MmapSource.cpp \
+ OMXCodec.cpp \
+ SampleTable.cpp \
+ ShoutcastSource.cpp \
+ TimeSource.cpp \
+ TimedEventQueue.cpp \
+ Utils.cpp \
+ AudioPlayer.cpp \
+ ESDS.cpp \
+ OMXClient.cpp \
+ string.cpp
+
+LOCAL_C_INCLUDES:= \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+ $(TOP)/external/opencore/android
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libmedia \
+ libutils \
+ libcutils \
+ libui
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+ LOCAL_LDLIBS += -lpthread
+endif
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_PRELINK_MODULE:= false
+
+LOCAL_MODULE:= libstagefright
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
new file mode 100644
index 0000000..140bc68
--- /dev/null
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AudioPlayer"
+#include <utils/Log.h>
+
+#include <media/AudioTrack.h>
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
+ : mAudioTrack(NULL),
+ mInputBuffer(NULL),
+ mSampleRate(0),
+ mLatencyUs(0),
+ mFrameSize(0),
+ mNumFramesPlayed(0),
+ mPositionTimeMediaUs(-1),
+ mPositionTimeRealUs(-1),
+ mSeeking(false),
+ mStarted(false),
+ mAudioSink(audioSink) {
+}
+
+AudioPlayer::~AudioPlayer() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+void AudioPlayer::setSource(const sp<MediaSource> &source) {
+ CHECK_EQ(mSource, NULL);
+ mSource = source;
+}
+
+void AudioPlayer::start() {
+ CHECK(!mStarted);
+ CHECK(mSource != NULL);
+
+ status_t err = mSource->start();
+ CHECK_EQ(err, OK);
+
+ sp<MetaData> format = mSource->getFormat();
+ const char *mime;
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+ CHECK(!strcasecmp(mime, "audio/raw"));
+
+ success = format->findInt32(kKeySampleRate, &mSampleRate);
+ CHECK(success);
+
+ int32_t numChannels;
+ success = format->findInt32(kKeyChannelCount, &numChannels);
+ CHECK(success);
+
+ if (mAudioSink.get() != NULL) {
+ status_t err = mAudioSink->open(
+ mSampleRate, numChannels, AudioSystem::PCM_16_BIT,
+ DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ &AudioPlayer::AudioSinkCallback, this);
+ CHECK_EQ(err, OK);
+
+ mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
+ mFrameSize = mAudioSink->frameSize();
+
+ mAudioSink->start();
+ } else {
+ mAudioTrack = new AudioTrack(
+ AudioSystem::MUSIC, mSampleRate, AudioSystem::PCM_16_BIT,
+ (numChannels == 2)
+ ? AudioSystem::CHANNEL_OUT_STEREO
+ : AudioSystem::CHANNEL_OUT_MONO,
+ 8192, 0, &AudioCallback, this, 0);
+
+ CHECK_EQ(mAudioTrack->initCheck(), OK);
+
+ mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
+ mFrameSize = mAudioTrack->frameSize();
+
+ mAudioTrack->start();
+ }
+
+ mStarted = true;
+}
+
+void AudioPlayer::pause() {
+ CHECK(mStarted);
+
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->pause();
+ } else {
+ mAudioTrack->stop();
+ }
+}
+
+void AudioPlayer::resume() {
+ CHECK(mStarted);
+
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->start();
+ } else {
+ mAudioTrack->start();
+ }
+}
+
+void AudioPlayer::stop() {
+ CHECK(mStarted);
+
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->stop();
+ } else {
+ mAudioTrack->stop();
+
+ delete mAudioTrack;
+ mAudioTrack = NULL;
+ }
+
+ // Make sure to release any buffer we hold onto so that the
+ // source is able to stop().
+ if (mInputBuffer != NULL) {
+ LOGI("AudioPlayer releasing input buffer.");
+
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ mSource->stop();
+
+ mNumFramesPlayed = 0;
+ mPositionTimeMediaUs = -1;
+ mPositionTimeRealUs = -1;
+ mSeeking = false;
+ mStarted = false;
+}
+
+// static
+void AudioPlayer::AudioCallback(int event, void *user, void *info) {
+ static_cast<AudioPlayer *>(user)->AudioCallback(event, info);
+}
+
+// static
+void AudioPlayer::AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *buffer, size_t size, void *cookie) {
+ AudioPlayer *me = (AudioPlayer *)cookie;
+
+ me->fillBuffer(buffer, size);
+}
+
+void AudioPlayer::AudioCallback(int event, void *info) {
+ if (event != AudioTrack::EVENT_MORE_DATA) {
+ return;
+ }
+
+ AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+ fillBuffer(buffer->raw, buffer->size);
+}
+
+void AudioPlayer::fillBuffer(void *data, size_t size) {
+ if (mNumFramesPlayed == 0) {
+ LOGI("AudioCallback");
+ }
+
+ size_t size_done = 0;
+ size_t size_remaining = size;
+ while (size_remaining > 0) {
+ MediaSource::ReadOptions options;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mSeeking) {
+ options.setSeekTo(mSeekTimeUs);
+
+ if (mInputBuffer != NULL) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+ mSeeking = false;
+ }
+ }
+
+ if (mInputBuffer == NULL) {
+ status_t err = mSource->read(&mInputBuffer, &options);
+
+ CHECK((err == OK && mInputBuffer != NULL)
+ || (err != OK && mInputBuffer == NULL));
+
+ if (err != OK) {
+ memset((char *)data + size_done, 0, size_remaining);
+ break;
+ }
+
+ int32_t units, scale;
+ bool success =
+ mInputBuffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+ success = success &&
+ mInputBuffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+ CHECK(success);
+
+ Mutex::Autolock autoLock(mLock);
+ mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
+
+ mPositionTimeRealUs =
+ ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+ / mSampleRate;
+ }
+
+ if (mInputBuffer->range_length() == 0) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+
+ continue;
+ }
+
+ size_t copy = size_remaining;
+ if (copy > mInputBuffer->range_length()) {
+ copy = mInputBuffer->range_length();
+ }
+
+ memcpy((char *)data + size_done,
+ (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
+ copy);
+
+ mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
+ mInputBuffer->range_length() - copy);
+
+ size_done += copy;
+ size_remaining -= copy;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+ mNumFramesPlayed += size / mFrameSize;
+}
+
+int64_t AudioPlayer::getRealTimeUs() {
+ Mutex::Autolock autoLock(mLock);
+ return getRealTimeUsLocked();
+}
+
+int64_t AudioPlayer::getRealTimeUsLocked() const {
+ return -mLatencyUs + (mNumFramesPlayed * 1000000) / mSampleRate;
+}
+
+int64_t AudioPlayer::getMediaTimeUs() {
+ Mutex::Autolock autoLock(mLock);
+
+ return mPositionTimeMediaUs + (getRealTimeUsLocked() - mPositionTimeRealUs);
+}
+
+bool AudioPlayer::getMediaTimeMapping(
+ int64_t *realtime_us, int64_t *mediatime_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ *realtime_us = mPositionTimeRealUs;
+ *mediatime_us = mPositionTimeMediaUs;
+
+ return mPositionTimeRealUs != -1 || mPositionTimeMediaUs != -1;
+}
+
+status_t AudioPlayer::seekTo(int64_t time_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ mSeeking = true;
+ mSeekTimeUs = time_us;
+
+ return OK;
+}
+
+}
diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp
new file mode 100644
index 0000000..fd00576
--- /dev/null
+++ b/media/libstagefright/CachingDataSource.cpp
@@ -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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <media/stagefright/CachingDataSource.h>
+#include <media/stagefright/MediaDebug.h>
+
+namespace android {
+
+CachingDataSource::CachingDataSource(
+ const sp<DataSource> &source, size_t pageSize, int numPages)
+ : mSource(source),
+ mData(malloc(pageSize * numPages)),
+ mPageSize(pageSize),
+ mFirst(NULL),
+ mLast(NULL) {
+ for (int i = 0; i < numPages; ++i) {
+ Page *page = new Page;
+ page->mPrev = mLast;
+ page->mNext = NULL;
+
+ if (mLast == NULL) {
+ mFirst = page;
+ } else {
+ mLast->mNext = page;
+ }
+
+ mLast = page;
+
+ page->mOffset = -1;
+ page->mLength = 0;
+ page->mData = (char *)mData + mPageSize * i;
+ }
+}
+
+CachingDataSource::~CachingDataSource() {
+ Page *page = mFirst;
+ while (page != NULL) {
+ Page *next = page->mNext;
+ delete page;
+ page = next;
+ }
+ mFirst = mLast = NULL;
+
+ free(mData);
+ mData = NULL;
+}
+
+status_t CachingDataSource::InitCheck() const {
+ return OK;
+}
+
+ssize_t CachingDataSource::read_at(off_t offset, void *data, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ size_t total = 0;
+ while (size > 0) {
+ Page *page = mFirst;
+ while (page != NULL) {
+ if (page->mOffset >= 0 && offset >= page->mOffset
+ && offset < page->mOffset + (off_t)page->mLength) {
+ break;
+ }
+ page = page->mNext;
+ }
+
+ if (page == NULL) {
+ page = allocate_page();
+ page->mOffset = offset - offset % mPageSize;
+ ssize_t n = mSource->read_at(page->mOffset, page->mData, mPageSize);
+ if (n < 0) {
+ page->mLength = 0;
+ } else {
+ page->mLength = (size_t)n;
+ }
+ mFirst->mPrev = page;
+ page->mNext = mFirst;
+ page->mPrev = NULL;
+ mFirst = page;
+
+ if (n < 0) {
+ return n;
+ }
+
+ if (offset >= page->mOffset + (off_t)page->mLength) {
+ break;
+ }
+ } else {
+ // Move "page" to the front in LRU order.
+ if (page->mNext != NULL) {
+ page->mNext->mPrev = page->mPrev;
+ } else {
+ mLast = page->mPrev;
+ }
+
+ if (page->mPrev != NULL) {
+ page->mPrev->mNext = page->mNext;
+ } else {
+ mFirst = page->mNext;
+ }
+
+ mFirst->mPrev = page;
+ page->mNext = mFirst;
+ page->mPrev = NULL;
+ mFirst = page;
+ }
+
+ size_t copy = page->mLength - (offset - page->mOffset);
+ if (copy > size) {
+ copy = size;
+ }
+ memcpy(data,(const char *)page->mData + (offset - page->mOffset),
+ copy);
+
+ total += copy;
+
+ if (page->mLength < mPageSize) {
+ // This was the final page. There is no more data beyond it.
+ break;
+ }
+
+ offset += copy;
+ size -= copy;
+ data = (char *)data + copy;
+ }
+
+ return total;
+}
+
+CachingDataSource::Page *CachingDataSource::allocate_page() {
+ // The last page is the least recently used, i.e. oldest.
+
+ Page *page = mLast;
+
+ page->mPrev->mNext = NULL;
+ mLast = page->mPrev;
+ page->mPrev = NULL;
+
+ return page;
+}
+
+} // namespace android
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
new file mode 100644
index 0000000..f75b173
--- /dev/null
+++ b/media/libstagefright/CameraSource.cpp
@@ -0,0 +1,224 @@
+/*
+ * 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 <sys/time.h>
+
+#include <OMX_Component.h>
+
+#include <binder/IServiceManager.h>
+#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <ui/ICameraClient.h>
+#include <ui/ICameraService.h>
+#include <ui/Overlay.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class CameraBuffer : public MediaBuffer {
+public:
+ CameraBuffer(const sp<IMemory> &frame)
+ : MediaBuffer(frame->pointer(), frame->size()),
+ mFrame(frame) {
+ }
+
+ sp<IMemory> releaseFrame() {
+ sp<IMemory> frame = mFrame;
+ mFrame.clear();
+ return frame;
+ }
+
+private:
+ sp<IMemory> mFrame;
+};
+
+class CameraSourceClient : public BnCameraClient {
+public:
+ CameraSourceClient()
+ : mSource(NULL) {
+ }
+
+ virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
+ CHECK(mSource != NULL);
+ mSource->notifyCallback(msgType, ext1, ext2);
+ }
+
+ virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {
+ CHECK(mSource != NULL);
+ mSource->dataCallback(msgType, data);
+ }
+
+ void setCameraSource(CameraSource *source) {
+ mSource = source;
+ }
+
+private:
+ CameraSource *mSource;
+};
+
+class DummySurface : public BnSurface {
+public:
+ DummySurface() {}
+
+ virtual status_t registerBuffers(const BufferHeap &buffers) {
+ return OK;
+ }
+
+ virtual void postBuffer(ssize_t offset) {
+ }
+
+ virtual void unregisterBuffers() {
+ }
+
+ virtual sp<OverlayRef> createOverlay(
+ uint32_t w, uint32_t h, int32_t format) {
+ return NULL;
+ }
+};
+
+// static
+CameraSource *CameraSource::Create() {
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<ICameraService> service =
+ interface_cast<ICameraService>(
+ sm->getService(String16("media.camera")));
+
+ sp<CameraSourceClient> client = new CameraSourceClient;
+ sp<ICamera> camera = service->connect(client);
+
+ CameraSource *source = new CameraSource(camera, client);
+ client->setCameraSource(source);
+
+ return source;
+}
+
+CameraSource::CameraSource(
+ const sp<ICamera> &camera, const sp<ICameraClient> &client)
+ : mCamera(camera),
+ mCameraClient(client),
+ mNumFrames(0),
+ mStarted(false) {
+ printf("params: \"%s\"\n", mCamera->getParameters().string());
+}
+
+CameraSource::~CameraSource() {
+ if (mStarted) {
+ stop();
+ }
+
+ mCamera->disconnect();
+}
+
+status_t CameraSource::start(MetaData *) {
+ CHECK(!mStarted);
+
+ status_t err = mCamera->lock();
+ CHECK_EQ(err, OK);
+
+ err = mCamera->setPreviewDisplay(new DummySurface);
+ CHECK_EQ(err, OK);
+ mCamera->setPreviewCallbackFlag(1);
+ mCamera->startPreview();
+ CHECK_EQ(err, OK);
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t CameraSource::stop() {
+ CHECK(mStarted);
+
+ mCamera->stopPreview();
+ mCamera->unlock();
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> CameraSource::getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, "video/raw");
+ meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420SemiPlanar);
+ meta->setInt32(kKeyWidth, 480);
+ meta->setInt32(kKeyHeight, 320);
+
+ return meta;
+}
+
+status_t CameraSource::read(
+ MediaBuffer **buffer, const ReadOptions *options) {
+ CHECK(mStarted);
+
+ *buffer = NULL;
+
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ sp<IMemory> frame;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ while (mFrames.empty()) {
+ mFrameAvailableCondition.wait(mLock);
+ }
+
+ frame = *mFrames.begin();
+ mFrames.erase(mFrames.begin());
+ }
+
+ int count = mNumFrames++;
+
+ *buffer = new CameraBuffer(frame);
+
+ (*buffer)->meta_data()->clear();
+ (*buffer)->meta_data()->setInt32(kKeyTimeScale, 15);
+ (*buffer)->meta_data()->setInt32(kKeyTimeUnits, count);
+
+ (*buffer)->add_ref();
+ (*buffer)->setObserver(this);
+
+ return OK;
+}
+
+void CameraSource::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
+ printf("notifyCallback %d, %d, %d\n", msgType, ext1, ext2);
+}
+
+void CameraSource::dataCallback(int32_t msgType, const sp<IMemory> &data) {
+ Mutex::Autolock autoLock(mLock);
+
+ mFrames.push_back(data);
+ mFrameAvailableCondition.signal();
+}
+
+void CameraSource::signalBufferReturned(MediaBuffer *_buffer) {
+ CameraBuffer *buffer = static_cast<CameraBuffer *>(_buffer);
+
+ mCamera->releaseRecordingFrame(buffer->releaseFrame());
+
+ buffer->setObserver(NULL);
+ buffer->release();
+ buffer = NULL;
+}
+
+} // namespace android
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
new file mode 100644
index 0000000..02a276b
--- /dev/null
+++ b/media/libstagefright/DataSource.cpp
@@ -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.
+ */
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MP3Extractor.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <utils/String8.h>
+
+namespace android {
+
+bool DataSource::getUInt16(off_t offset, uint16_t *x) {
+ *x = 0;
+
+ uint8_t byte[2];
+ if (read_at(offset, byte, 2) != 2) {
+ return false;
+ }
+
+ *x = (byte[0] << 8) | byte[1];
+
+ return true;
+}
+
+status_t DataSource::getSize(off_t *size) {
+ *size = 0;
+
+ return ERROR_UNSUPPORTED;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Mutex DataSource::gSnifferMutex;
+List<DataSource::SnifferFunc> DataSource::gSniffers;
+
+bool DataSource::sniff(String8 *mimeType, float *confidence) {
+ *mimeType = "";
+ *confidence = 0.0f;
+
+ Mutex::Autolock autoLock(gSnifferMutex);
+ for (List<SnifferFunc>::iterator it = gSniffers.begin();
+ it != gSniffers.end(); ++it) {
+ String8 newMimeType;
+ float newConfidence;
+ if ((*it)(this, &newMimeType, &newConfidence)) {
+ if (newConfidence > *confidence) {
+ *mimeType = newMimeType;
+ *confidence = newConfidence;
+ }
+ }
+ }
+
+ return *confidence > 0.0;
+}
+
+// static
+void DataSource::RegisterSniffer(SnifferFunc func) {
+ Mutex::Autolock autoLock(gSnifferMutex);
+
+ for (List<SnifferFunc>::iterator it = gSniffers.begin();
+ it != gSniffers.end(); ++it) {
+ if (*it == func) {
+ return;
+ }
+ }
+
+ gSniffers.push_back(func);
+}
+
+// static
+void DataSource::RegisterDefaultSniffers() {
+ RegisterSniffer(SniffMP3);
+ RegisterSniffer(SniffMPEG4);
+}
+
+} // namespace android
diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp
new file mode 100644
index 0000000..53b92a0
--- /dev/null
+++ b/media/libstagefright/ESDS.cpp
@@ -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.
+ */
+
+#include <media/stagefright/ESDS.h>
+
+#include <string.h>
+
+namespace android {
+
+ESDS::ESDS(const void *data, size_t size)
+ : mData(new uint8_t[size]),
+ mSize(size),
+ mInitCheck(NO_INIT),
+ mDecoderSpecificOffset(0),
+ mDecoderSpecificLength(0) {
+ memcpy(mData, data, size);
+
+ mInitCheck = parse();
+}
+
+ESDS::~ESDS() {
+ delete[] mData;
+ mData = NULL;
+}
+
+status_t ESDS::InitCheck() const {
+ return mInitCheck;
+}
+
+status_t ESDS::getCodecSpecificInfo(const void **data, size_t *size) const {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ *data = &mData[mDecoderSpecificOffset];
+ *size = mDecoderSpecificLength;
+
+ return OK;
+}
+
+status_t ESDS::skipDescriptorHeader(
+ size_t offset, size_t size,
+ uint8_t *tag, size_t *data_offset, size_t *data_size) const {
+ if (size == 0) {
+ return ERROR_MALFORMED;
+ }
+
+ *tag = mData[offset++];
+ --size;
+
+ *data_size = 0;
+ bool more;
+ do {
+ if (size == 0) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t x = mData[offset++];
+ --size;
+
+ *data_size = (*data_size << 7) | (x & 0x7f);
+ more = (x & 0x80) != 0;
+ }
+ while (more);
+
+ if (*data_size > size) {
+ return ERROR_MALFORMED;
+ }
+
+ *data_offset = offset;
+
+ return OK;
+}
+
+status_t ESDS::parse() {
+ uint8_t tag;
+ size_t data_offset;
+ size_t data_size;
+ status_t err =
+ skipDescriptorHeader(0, mSize, &tag, &data_offset, &data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (tag != kTag_ESDescriptor) {
+ return ERROR_MALFORMED;
+ }
+
+ return parseESDescriptor(data_offset, data_size);
+}
+
+status_t ESDS::parseESDescriptor(size_t offset, size_t size) {
+ if (size < 3) {
+ return ERROR_MALFORMED;
+ }
+
+ offset += 2; // skip ES_ID
+ size -= 2;
+
+ unsigned streamDependenceFlag = mData[offset] & 0x80;
+ unsigned URL_Flag = mData[offset] & 0x40;
+ unsigned OCRstreamFlag = mData[offset] & 0x20;
+
+ ++offset;
+ --size;
+
+ if (streamDependenceFlag) {
+ offset += 2;
+ size -= 2;
+ }
+
+ if (URL_Flag) {
+ if (offset >= size) {
+ return ERROR_MALFORMED;
+ }
+ unsigned URLlength = mData[offset];
+ offset += URLlength + 1;
+ size -= URLlength + 1;
+ }
+
+ if (OCRstreamFlag) {
+ offset += 2;
+ size -= 2;
+ }
+
+ if (offset >= size) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t tag;
+ size_t sub_offset, sub_size;
+ status_t err = skipDescriptorHeader(
+ offset, size, &tag, &sub_offset, &sub_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (tag != kTag_DecoderConfigDescriptor) {
+ return ERROR_MALFORMED;
+ }
+
+ err = parseDecoderConfigDescriptor(sub_offset, sub_size);
+
+ return err;
+}
+
+status_t ESDS::parseDecoderConfigDescriptor(size_t offset, size_t size) {
+ if (size < 13) {
+ return ERROR_MALFORMED;
+ }
+
+ offset += 13;
+ size -= 13;
+
+ if (size == 0) {
+ mDecoderSpecificOffset = 0;
+ mDecoderSpecificLength = 0;
+ return OK;
+ }
+
+ uint8_t tag;
+ size_t sub_offset, sub_size;
+ status_t err = skipDescriptorHeader(
+ offset, size, &tag, &sub_offset, &sub_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (tag != kTag_DecoderSpecificInfo) {
+ return ERROR_MALFORMED;
+ }
+
+ mDecoderSpecificOffset = sub_offset;
+ mDecoderSpecificLength = sub_size;
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
new file mode 100644
index 0000000..f6b90b2
--- /dev/null
+++ b/media/libstagefright/FileSource.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 <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaDebug.h>
+
+namespace android {
+
+FileSource::FileSource(const char *filename)
+ : mFile(fopen(filename, "rb")) {
+}
+
+FileSource::~FileSource() {
+ if (mFile != NULL) {
+ fclose(mFile);
+ mFile = NULL;
+ }
+}
+
+status_t FileSource::InitCheck() const {
+ return mFile != NULL ? OK : NO_INIT;
+}
+
+ssize_t FileSource::read_at(off_t offset, void *data, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ int err = fseeko(mFile, offset, SEEK_SET);
+ CHECK(err != -1);
+
+ ssize_t result = fread(data, 1, size, mFile);
+
+ return result;
+}
+
+} // namespace android
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
new file mode 100644
index 0000000..698223b
--- /dev/null
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -0,0 +1,172 @@
+/*
+ * 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 <stdlib.h>
+
+#include <media/stagefright/HTTPDataSource.h>
+#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/string.h>
+
+namespace android {
+
+HTTPDataSource::HTTPDataSource(const char *uri)
+ : mHost(NULL),
+ mPort(0),
+ mPath(NULL),
+ mBuffer(malloc(kBufferSize)),
+ mBufferLength(0),
+ mBufferOffset(0) {
+ CHECK(!strncasecmp("http://", uri, 7));
+
+ string host;
+ string path;
+ int port;
+
+ char *slash = strchr(uri + 7, '/');
+ if (slash == NULL) {
+ host = uri + 7;
+ path = "/";
+ } else {
+ host = string(uri + 7, slash - (uri + 7));
+ path = slash;
+ }
+
+ char *colon = strchr(host.c_str(), ':');
+ if (colon == NULL) {
+ port = 80;
+ } else {
+ char *end;
+ long tmp = strtol(colon + 1, &end, 10);
+ CHECK(end > colon + 1);
+ CHECK(tmp > 0 && tmp < 65536);
+ port = tmp;
+
+ host = string(host, 0, colon - host.c_str());
+ }
+
+ LOGI("Connecting to host '%s', port %d, path '%s'",
+ host.c_str(), port, path.c_str());
+
+ mHost = strdup(host.c_str());
+ mPort = port;
+ mPath = strdup(path.c_str());
+
+ status_t err = mHttp.connect(mHost, mPort);
+ CHECK_EQ(err, OK);
+}
+
+HTTPDataSource::HTTPDataSource(const char *host, int port, const char *path)
+ : mHost(strdup(host)),
+ mPort(port),
+ mPath(strdup(path)),
+ mBuffer(malloc(kBufferSize)),
+ mBufferLength(0),
+ mBufferOffset(0) {
+ status_t err = mHttp.connect(mHost, mPort);
+ CHECK_EQ(err, OK);
+}
+
+HTTPDataSource::~HTTPDataSource() {
+ mHttp.disconnect();
+
+ free(mBuffer);
+ mBuffer = NULL;
+
+ free(mPath);
+ mPath = NULL;
+}
+
+ssize_t HTTPDataSource::read_at(off_t offset, void *data, size_t size) {
+ if (offset >= mBufferOffset && offset < mBufferOffset + mBufferLength) {
+ size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
+
+ size_t copy = num_bytes_available;
+ if (copy > size) {
+ copy = size;
+ }
+
+ memcpy(data, (const char *)mBuffer + (offset - mBufferOffset), copy);
+
+ return copy;
+ }
+
+ mBufferOffset = offset;
+ mBufferLength = 0;
+
+ char host[128];
+ sprintf(host, "Host: %s\r\n", mHost);
+
+ char range[128];
+ sprintf(range, "Range: bytes=%ld-%ld\r\n\r\n",
+ mBufferOffset, mBufferOffset + kBufferSize - 1);
+
+ int http_status;
+
+ status_t err;
+ int attempt = 1;
+ for (;;) {
+ if ((err = mHttp.send("GET ")) != OK
+ || (err = mHttp.send(mPath)) != OK
+ || (err = mHttp.send(" HTTP/1.1\r\n")) != OK
+ || (err = mHttp.send(host)) != OK
+ || (err = mHttp.send(range)) != OK
+ || (err = mHttp.send("\r\n")) != OK
+ || (err = mHttp.receive_header(&http_status)) != OK) {
+
+ if (attempt == 3) {
+ return err;
+ }
+
+ mHttp.connect(mHost, mPort);
+ ++attempt;
+ } else {
+ break;
+ }
+ }
+
+ if ((http_status / 100) != 2) {
+ return UNKNOWN_ERROR;
+ }
+
+ string value;
+ if (!mHttp.find_header_value("Content-Length", &value)) {
+ return UNKNOWN_ERROR;
+ }
+
+ char *end;
+ unsigned long contentLength = strtoul(value.c_str(), &end, 10);
+
+ ssize_t num_bytes_received = mHttp.receive(mBuffer, contentLength);
+
+ if (num_bytes_received <= 0) {
+ return num_bytes_received;
+ }
+
+ mBufferLength = (size_t)num_bytes_received;
+
+ size_t copy = mBufferLength;
+ if (copy > size) {
+ copy = size;
+ }
+
+ memcpy(data, mBuffer, copy);
+
+ return copy;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
new file mode 100644
index 0000000..098ddbd
--- /dev/null
+++ b/media/libstagefright/HTTPStream.cpp
@@ -0,0 +1,285 @@
+/*
+ * 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 <sys/socket.h>
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/MediaDebug.h>
+
+namespace android {
+
+// static
+const char *HTTPStream::kStatusKey = ":status:";
+
+HTTPStream::HTTPStream()
+ : mState(READY),
+ mSocket(-1) {
+}
+
+HTTPStream::~HTTPStream() {
+ disconnect();
+}
+
+status_t HTTPStream::connect(const char *server, int port) {
+ status_t err = OK;
+
+ if (mState == CONNECTED) {
+ return ERROR_ALREADY_CONNECTED;
+ }
+
+ CHECK_EQ(mSocket, -1);
+ mSocket = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (mSocket < 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ struct hostent *ent = gethostbyname(server);
+ if (ent == NULL) {
+ err = ERROR_UNKNOWN_HOST;
+ goto exit1;
+ }
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
+ memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+
+ if (::connect(mSocket, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ err = ERROR_CANNOT_CONNECT;
+ goto exit1;
+ }
+
+ mState = CONNECTED;
+
+ return OK;
+
+exit1:
+ close(mSocket);
+ mSocket = -1;
+
+ return err;
+}
+
+status_t HTTPStream::disconnect() {
+ if (mState != CONNECTED) {
+ return ERROR_NOT_CONNECTED;
+ }
+
+ CHECK(mSocket >= 0);
+ close(mSocket);
+ mSocket = -1;
+
+ mState = READY;
+
+ return OK;
+}
+
+status_t HTTPStream::send(const char *data, size_t size) {
+ if (mState != CONNECTED) {
+ return ERROR_NOT_CONNECTED;
+ }
+
+ while (size > 0) {
+ ssize_t n = ::send(mSocket, data, size, 0);
+
+ if (n < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ disconnect();
+
+ return ERROR_IO;
+ } else if (n == 0) {
+ disconnect();
+
+ return ERROR_CONNECTION_LOST;
+ }
+
+ size -= (size_t)n;
+ data += (size_t)n;
+ }
+
+ return OK;
+}
+
+status_t HTTPStream::send(const char *data) {
+ return send(data, strlen(data));
+}
+
+status_t HTTPStream::receive_line(char *line, size_t size) {
+ if (mState != CONNECTED) {
+ return ERROR_NOT_CONNECTED;
+ }
+
+ bool saw_CR = false;
+ size_t length = 0;
+
+ for (;;) {
+ char c;
+ ssize_t n = recv(mSocket, &c, 1, 0);
+ if (n < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ disconnect();
+
+ return ERROR_IO;
+ } else if (n == 0) {
+ disconnect();
+
+ return ERROR_CONNECTION_LOST;
+ }
+
+ if (saw_CR && c == '\n') {
+ // We have a complete line.
+
+ line[length - 1] = '\0';
+ return OK;
+ }
+
+ saw_CR = (c == '\r');
+
+ CHECK(length + 1 < size);
+ line[length++] = c;
+ }
+}
+
+status_t HTTPStream::receive_header(int *http_status) {
+ *http_status = -1;
+ mHeaders.clear();
+
+ char line[256];
+ status_t err = receive_line(line, sizeof(line));
+ if (err != OK) {
+ return err;
+ }
+
+ mHeaders.add(string(kStatusKey), string(line));
+
+ char *spacePos = strchr(line, ' ');
+ if (spacePos == NULL) {
+ // Malformed response?
+ return UNKNOWN_ERROR;
+ }
+
+ char *status_start = spacePos + 1;
+ char *status_end = status_start;
+ while (isdigit(*status_end)) {
+ ++status_end;
+ }
+
+ if (status_end == status_start) {
+ // Malformed response, status missing?
+ return UNKNOWN_ERROR;
+ }
+
+ memmove(line, status_start, status_end - status_start);
+ line[status_end - status_start] = '\0';
+
+ long tmp = strtol(line, NULL, 10);
+ if (tmp < 0 || tmp > 999) {
+ return UNKNOWN_ERROR;
+ }
+
+ *http_status = (int)tmp;
+
+ for (;;) {
+ err = receive_line(line, sizeof(line));
+ if (err != OK) {
+ return err;
+ }
+
+ if (*line == '\0') {
+ // Empty line signals the end of the header.
+ break;
+ }
+
+ // puts(line);
+
+ char *colonPos = strchr(line, ':');
+ if (colonPos == NULL) {
+ mHeaders.add(string(line), string());
+ } else {
+ char *end_of_key = colonPos;
+ while (end_of_key > line && isspace(end_of_key[-1])) {
+ --end_of_key;
+ }
+
+ char *start_of_value = colonPos + 1;
+ while (isspace(*start_of_value)) {
+ ++start_of_value;
+ }
+
+ *end_of_key = '\0';
+
+ mHeaders.add(string(line), string(start_of_value));
+ }
+ }
+
+ return OK;
+}
+
+ssize_t HTTPStream::receive(void *data, size_t size) {
+ size_t total = 0;
+ while (total < size) {
+ ssize_t n = recv(mSocket, (char *)data + total, size - total, 0);
+
+ if (n < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ disconnect();
+ return ERROR_IO;
+ } else if (n == 0) {
+ disconnect();
+
+ return ERROR_CONNECTION_LOST;
+ }
+
+ total += (size_t)n;
+ }
+
+ return (ssize_t)total;
+}
+
+bool HTTPStream::find_header_value(const string &key, string *value) const {
+ ssize_t index = mHeaders.indexOfKey(key);
+ if (index < 0) {
+ value->clear();
+ return false;
+ }
+
+ *value = mHeaders.valueAt(index);
+
+ return true;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
new file mode 100644
index 0000000..14f3e0c
--- /dev/null
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -0,0 +1,519 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MP3Extractor"
+#include <utils/Log.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MP3Extractor.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <utils/String8.h>
+
+namespace android {
+
+static bool get_mp3_frame_size(
+ uint32_t header, size_t *frame_size,
+ int *out_sampling_rate = NULL, int *out_channels = NULL,
+ int *out_bitrate = NULL) {
+ *frame_size = 0;
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = 0;
+ }
+
+ if (out_channels) {
+ *out_channels = 0;
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = 0;
+ }
+
+ if ((header & 0xffe00000) != 0xffe00000) {
+ return false;
+ }
+
+ unsigned version = (header >> 19) & 3;
+
+ if (version == 0x01) {
+ return false;
+ }
+
+ unsigned layer = (header >> 17) & 3;
+
+ if (layer == 0x00) {
+ return false;
+ }
+
+ unsigned protection = (header >> 16) & 1;
+
+ unsigned bitrate_index = (header >> 12) & 0x0f;
+
+ if (bitrate_index == 0 || bitrate_index == 0x0f) {
+ // Disallow "free" bitrate.
+ return false;
+ }
+
+ unsigned sampling_rate_index = (header >> 10) & 3;
+
+ if (sampling_rate_index == 3) {
+ return false;
+ }
+
+ static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
+ int sampling_rate = kSamplingRateV1[sampling_rate_index];
+ if (version == 2 /* V2 */) {
+ sampling_rate /= 2;
+ } else if (version == 0 /* V2.5 */) {
+ sampling_rate /= 4;
+ }
+
+ unsigned padding = (header >> 9) & 1;
+
+ if (layer == 3) {
+ // layer I
+
+ static const int kBitrateV1[] = {
+ 32, 64, 96, 128, 160, 192, 224, 256,
+ 288, 320, 352, 384, 416, 448
+ };
+
+ static const int kBitrateV2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 144, 160, 176, 192, 224, 256
+ };
+
+ int bitrate =
+ (version == 3 /* V1 */)
+ ? kBitrateV1[bitrate_index - 1]
+ : kBitrateV2[bitrate_index - 1];
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+ } else {
+ // layer II or III
+
+ static const int kBitrateV1L2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 160, 192, 224, 256, 320, 384
+ };
+
+ static const int kBitrateV1L3[] = {
+ 32, 40, 48, 56, 64, 80, 96, 112,
+ 128, 160, 192, 224, 256, 320
+ };
+
+ static const int kBitrateV2[] = {
+ 8, 16, 24, 32, 40, 48, 56, 64,
+ 80, 96, 112, 128, 144, 160
+ };
+
+ int bitrate;
+ if (version == 3 /* V1 */) {
+ bitrate = (layer == 2 /* L2 */)
+ ? kBitrateV1L2[bitrate_index - 1]
+ : kBitrateV1L3[bitrate_index - 1];
+ } else {
+ // V2 (or 2.5)
+
+ bitrate = kBitrateV2[bitrate_index - 1];
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ *frame_size = 144000 * bitrate / sampling_rate + padding;
+ }
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = sampling_rate;
+ }
+
+ if (out_channels) {
+ int channel_mode = (header >> 6) & 3;
+
+ *out_channels = (channel_mode == 3) ? 1 : 2;
+ }
+
+ return true;
+}
+
+static bool Resync(
+ const sp<DataSource> &source, uint32_t match_header,
+ off_t *inout_pos, uint32_t *out_header) {
+ // Everything must match except for
+ // protection, bitrate, padding, private bits and mode extension.
+ const uint32_t kMask = 0xfffe0ccf;
+
+ const size_t kMaxFrameSize = 4096;
+ uint8_t *buffer = new uint8_t[kMaxFrameSize];
+
+ off_t pos = *inout_pos - kMaxFrameSize;
+ size_t buffer_offset = kMaxFrameSize;
+ size_t buffer_length = kMaxFrameSize;
+ bool valid = false;
+ do {
+ if (buffer_offset + 3 >= buffer_length) {
+ if (buffer_length < kMaxFrameSize) {
+ break;
+ }
+
+ pos += buffer_offset;
+
+ if (pos >= *inout_pos + 128 * 1024) {
+ // Don't scan forever.
+ LOGV("giving up at offset %ld", pos);
+ break;
+ }
+
+ memmove(buffer, &buffer[buffer_offset], buffer_length - buffer_offset);
+ buffer_length = buffer_length - buffer_offset;
+ buffer_offset = 0;
+
+ ssize_t n = source->read_at(
+ pos, &buffer[buffer_length], kMaxFrameSize - buffer_length);
+
+ if (n <= 0) {
+ break;
+ }
+
+ buffer_length += (size_t)n;
+
+ continue;
+ }
+
+ uint32_t header = U32_AT(&buffer[buffer_offset]);
+
+ if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
+ ++buffer_offset;
+ continue;
+ }
+
+ size_t frame_size;
+ int sample_rate, num_channels, bitrate;
+ if (!get_mp3_frame_size(header, &frame_size,
+ &sample_rate, &num_channels, &bitrate)) {
+ ++buffer_offset;
+ continue;
+ }
+
+ LOGV("found possible 1st frame at %ld", pos + buffer_offset);
+
+ // We found what looks like a valid frame,
+ // now find its successors.
+
+ off_t test_pos = pos + buffer_offset + frame_size;
+
+ valid = true;
+ for (int j = 0; j < 3; ++j) {
+ uint8_t tmp[4];
+ if (source->read_at(test_pos, tmp, 4) < 4) {
+ valid = false;
+ break;
+ }
+
+ uint32_t test_header = U32_AT(tmp);
+
+ LOGV("subsequent header is %08x", test_header);
+
+ if ((test_header & kMask) != (header & kMask)) {
+ valid = false;
+ break;
+ }
+
+ size_t test_frame_size;
+ if (!get_mp3_frame_size(test_header, &test_frame_size)) {
+ valid = false;
+ break;
+ }
+
+ LOGV("found subsequent frame #%d at %ld", j + 2, test_pos);
+
+ test_pos += test_frame_size;
+ }
+
+ if (valid) {
+ *inout_pos = pos + buffer_offset;
+
+ if (out_header != NULL) {
+ *out_header = header;
+ }
+ } else {
+ LOGV("no dice, no valid sequence of frames found.");
+ }
+
+ ++buffer_offset;
+
+ } while (!valid);
+
+ delete[] buffer;
+ buffer = NULL;
+
+ return valid;
+}
+
+class MP3Source : public MediaSource {
+public:
+ MP3Source(
+ const sp<MetaData> &meta, const sp<DataSource> &source,
+ off_t first_frame_pos, uint32_t fixed_header);
+
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+ virtual ~MP3Source();
+
+private:
+ sp<MetaData> mMeta;
+ sp<DataSource> mDataSource;
+ off_t mFirstFramePos;
+ uint32_t mFixedHeader;
+ off_t mCurrentPos;
+ int64_t mCurrentTimeUs;
+ bool mStarted;
+
+ MediaBufferGroup *mGroup;
+
+ MP3Source(const MP3Source &);
+ MP3Source &operator=(const MP3Source &);
+};
+
+MP3Extractor::MP3Extractor(const sp<DataSource> &source)
+ : mDataSource(source),
+ mFirstFramePos(-1),
+ mFixedHeader(0) {
+ off_t pos = 0;
+ uint32_t header;
+ bool success = Resync(mDataSource, 0, &pos, &header);
+ CHECK(success);
+
+ if (success) {
+ mFirstFramePos = pos;
+ mFixedHeader = header;
+
+ size_t frame_size;
+ int sample_rate;
+ int num_channels;
+ int bitrate;
+ get_mp3_frame_size(
+ header, &frame_size, &sample_rate, &num_channels, &bitrate);
+
+ mMeta = new MetaData;
+
+ mMeta->setCString(kKeyMIMEType, "audio/mpeg");
+ mMeta->setInt32(kKeySampleRate, sample_rate);
+ mMeta->setInt32(kKeyBitRate, bitrate);
+ mMeta->setInt32(kKeyChannelCount, num_channels);
+
+ off_t fileSize;
+ if (mDataSource->getSize(&fileSize) == OK) {
+ mMeta->setInt32(
+ kKeyDuration,
+ 8 * (fileSize - mFirstFramePos) / bitrate);
+ mMeta->setInt32(kKeyTimeScale, 1000);
+ }
+ }
+}
+
+MP3Extractor::~MP3Extractor() {
+}
+
+size_t MP3Extractor::countTracks() {
+ return (mFirstFramePos < 0) ? 0 : 1;
+}
+
+sp<MediaSource> MP3Extractor::getTrack(size_t index) {
+ if (mFirstFramePos < 0 || index != 0) {
+ return NULL;
+ }
+
+ return new MP3Source(
+ mMeta, mDataSource, mFirstFramePos, mFixedHeader);
+}
+
+sp<MetaData> MP3Extractor::getTrackMetaData(size_t index) {
+ if (mFirstFramePos < 0 || index != 0) {
+ return NULL;
+ }
+
+ return mMeta;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MP3Source::MP3Source(
+ const sp<MetaData> &meta, const sp<DataSource> &source,
+ off_t first_frame_pos, uint32_t fixed_header)
+ : mMeta(meta),
+ mDataSource(source),
+ mFirstFramePos(first_frame_pos),
+ mFixedHeader(fixed_header),
+ mCurrentPos(0),
+ mCurrentTimeUs(0),
+ mStarted(false),
+ mGroup(NULL) {
+}
+
+MP3Source::~MP3Source() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t MP3Source::start(MetaData *) {
+ CHECK(!mStarted);
+
+ mGroup = new MediaBufferGroup;
+
+ const size_t kMaxFrameSize = 32768;
+ mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+
+ mCurrentPos = mFirstFramePos;
+ mCurrentTimeUs = 0;
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t MP3Source::stop() {
+ CHECK(mStarted);
+
+ delete mGroup;
+ mGroup = NULL;
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> MP3Source::getFormat() {
+ return mMeta;
+}
+
+status_t MP3Source::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ *out = NULL;
+
+ int64_t seekTimeUs;
+ if (options != NULL && options->getSeekTo(&seekTimeUs)) {
+ int32_t bitrate;
+ if (!mMeta->findInt32(kKeyBitRate, &bitrate)) {
+ // bitrate is in kbits/sec.
+ LOGI("no bitrate");
+
+ return ERROR_UNSUPPORTED;
+ }
+
+ mCurrentTimeUs = seekTimeUs;
+ mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 1000000 * 125;
+ }
+
+ MediaBuffer *buffer;
+ status_t err = mGroup->acquire_buffer(&buffer);
+ if (err != OK) {
+ return err;
+ }
+
+ size_t frame_size;
+ for (;;) {
+ ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), 4);
+ if (n < 4) {
+ buffer->release();
+ buffer = NULL;
+
+ return ERROR_END_OF_STREAM;
+ }
+
+ uint32_t header = U32_AT((const uint8_t *)buffer->data());
+
+ if (get_mp3_frame_size(header, &frame_size)) {
+ break;
+ }
+
+ // Lost sync.
+ LOGW("lost sync!\n");
+
+ off_t pos = mCurrentPos;
+ if (!Resync(mDataSource, mFixedHeader, &pos, NULL)) {
+ LOGE("Unable to resync. Signalling end of stream.");
+
+ buffer->release();
+ buffer = NULL;
+
+ return ERROR_END_OF_STREAM;
+ }
+
+ mCurrentPos = pos;
+
+ // Try again with the new position.
+ }
+
+ CHECK(frame_size <= buffer->size());
+
+ ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), frame_size);
+ if (n < (ssize_t)frame_size) {
+ buffer->release();
+ buffer = NULL;
+
+ return ERROR_END_OF_STREAM;
+ }
+
+ buffer->set_range(0, frame_size);
+
+ buffer->meta_data()->setInt32(kKeyTimeUnits, mCurrentTimeUs / 1000);
+ buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
+
+ mCurrentPos += frame_size;
+ mCurrentTimeUs += 1152 * 1000000 / 44100;
+
+ *out = buffer;
+
+ return OK;
+}
+
+bool SniffMP3(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ off_t pos = 0;
+ uint32_t header;
+ if (!Resync(source, 0, &pos, &header)) {
+ return false;
+ }
+
+ *mimeType = "audio/mpeg";
+ *confidence = 0.3f;
+
+ return true;
+}
+
+} // namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
new file mode 100644
index 0000000..894d46c
--- /dev/null
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -0,0 +1,978 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MPEG4Extractor"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/SampleTable.h>
+#include <media/stagefright/Utils.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class MPEG4Source : public MediaSource {
+public:
+ // Caller retains ownership of both "dataSource" and "sampleTable".
+ MPEG4Source(const sp<MetaData> &format,
+ const sp<DataSource> &dataSource,
+ const sp<SampleTable> &sampleTable);
+
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+ virtual ~MPEG4Source();
+
+private:
+ sp<MetaData> mFormat;
+ sp<DataSource> mDataSource;
+ int32_t mTimescale;
+ sp<SampleTable> mSampleTable;
+ uint32_t mCurrentSampleIndex;
+
+ bool mIsAVC;
+ bool mStarted;
+
+ MediaBufferGroup *mGroup;
+
+ MediaBuffer *mBuffer;
+
+ bool mWantsNALFragments;
+
+ uint8_t *mSrcBuffer;
+
+ MPEG4Source(const MPEG4Source &);
+ MPEG4Source &operator=(const MPEG4Source &);
+};
+
+static void hexdump(const void *_data, size_t size) {
+ const uint8_t *data = (const uint8_t *)_data;
+ size_t offset = 0;
+ while (offset < size) {
+ printf("0x%04x ", offset);
+
+ size_t n = size - offset;
+ if (n > 16) {
+ n = 16;
+ }
+
+ for (size_t i = 0; i < 16; ++i) {
+ if (i == 8) {
+ printf(" ");
+ }
+
+ if (offset + i < size) {
+ printf("%02x ", data[offset + i]);
+ } else {
+ printf(" ");
+ }
+ }
+
+ printf(" ");
+
+ for (size_t i = 0; i < n; ++i) {
+ if (isprint(data[offset + i])) {
+ printf("%c", data[offset + i]);
+ } else {
+ printf(".");
+ }
+ }
+
+ printf("\n");
+
+ offset += 16;
+ }
+}
+
+static const char *const FourCC2MIME(uint32_t fourcc) {
+ switch (fourcc) {
+ case FOURCC('m', 'p', '4', 'a'):
+ return "audio/mp4a-latm";
+
+ case FOURCC('s', 'a', 'm', 'r'):
+ return "audio/3gpp";
+
+ case FOURCC('m', 'p', '4', 'v'):
+ return "video/mp4v-es";
+
+ case FOURCC('s', '2', '6', '3'):
+ return "video/3gpp";
+
+ case FOURCC('a', 'v', 'c', '1'):
+ return "video/avc";
+
+ default:
+ CHECK(!"should not be here.");
+ return NULL;
+ }
+}
+
+MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
+ : mDataSource(source),
+ mHaveMetadata(false),
+ mFirstTrack(NULL),
+ mLastTrack(NULL) {
+}
+
+MPEG4Extractor::~MPEG4Extractor() {
+ Track *track = mFirstTrack;
+ while (track) {
+ Track *next = track->next;
+
+ delete track;
+ track = next;
+ }
+ mFirstTrack = mLastTrack = NULL;
+}
+
+size_t MPEG4Extractor::countTracks() {
+ status_t err;
+ if ((err = readMetaData()) != OK) {
+ return 0;
+ }
+
+ size_t n = 0;
+ Track *track = mFirstTrack;
+ while (track) {
+ ++n;
+ track = track->next;
+ }
+
+ return n;
+}
+
+sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
+ status_t err;
+ if ((err = readMetaData()) != OK) {
+ return NULL;
+ }
+
+ Track *track = mFirstTrack;
+ while (index > 0) {
+ if (track == NULL) {
+ return NULL;
+ }
+
+ track = track->next;
+ --index;
+ }
+
+ return track->meta;
+}
+
+status_t MPEG4Extractor::readMetaData() {
+ if (mHaveMetadata) {
+ return OK;
+ }
+
+ off_t offset = 0;
+ status_t err;
+ while ((err = parseChunk(&offset, 0)) == OK) {
+ }
+
+ if (mHaveMetadata) {
+ return OK;
+ }
+
+ return err;
+}
+
+static void MakeFourCCString(uint32_t x, char *s) {
+ s[0] = x >> 24;
+ s[1] = (x >> 16) & 0xff;
+ s[2] = (x >> 8) & 0xff;
+ s[3] = x & 0xff;
+ s[4] = '\0';
+}
+
+status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
+ uint32_t hdr[2];
+ if (mDataSource->read_at(*offset, hdr, 8) < 8) {
+ return ERROR_IO;
+ }
+ uint64_t chunk_size = ntohl(hdr[0]);
+ uint32_t chunk_type = ntohl(hdr[1]);
+ off_t data_offset = *offset + 8;
+
+ if (chunk_size == 1) {
+ if (mDataSource->read_at(*offset + 8, &chunk_size, 8) < 8) {
+ return ERROR_IO;
+ }
+ chunk_size = ntoh64(chunk_size);
+ data_offset += 8;
+ }
+
+ char chunk[5];
+ MakeFourCCString(chunk_type, chunk);
+
+#if 0
+ static const char kWhitespace[] = " ";
+ const char *indent = &kWhitespace[sizeof(kWhitespace) - 1 - 2 * depth];
+ printf("%sfound chunk '%s' of size %lld\n", indent, chunk, chunk_size);
+
+ char buffer[256];
+ if (chunk_size <= sizeof(buffer)) {
+ if (mDataSource->read_at(*offset, buffer, chunk_size) < chunk_size) {
+ return ERROR_IO;
+ }
+
+ hexdump(buffer, chunk_size);
+ }
+#endif
+
+ off_t chunk_data_size = *offset + chunk_size - data_offset;
+
+ switch(chunk_type) {
+ case FOURCC('m', 'o', 'o', 'v'):
+ case FOURCC('t', 'r', 'a', 'k'):
+ case FOURCC('m', 'd', 'i', 'a'):
+ case FOURCC('m', 'i', 'n', 'f'):
+ case FOURCC('d', 'i', 'n', 'f'):
+ case FOURCC('s', 't', 'b', 'l'):
+ case FOURCC('m', 'v', 'e', 'x'):
+ case FOURCC('m', 'o', 'o', 'f'):
+ case FOURCC('t', 'r', 'a', 'f'):
+ case FOURCC('m', 'f', 'r', 'a'):
+ case FOURCC('s', 'k', 'i' ,'p'):
+ {
+ off_t stop_offset = *offset + chunk_size;
+ *offset = data_offset;
+ while (*offset < stop_offset) {
+ status_t err = parseChunk(offset, depth + 1);
+ if (err != OK) {
+ return err;
+ }
+ }
+ CHECK_EQ(*offset, stop_offset);
+
+ if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
+ mHaveMetadata = true;
+
+ return UNKNOWN_ERROR; // Return a dummy error.
+ }
+ break;
+ }
+
+ case FOURCC('t', 'k', 'h', 'd'):
+ {
+ CHECK(chunk_data_size >= 4);
+
+ uint8_t version;
+ if (mDataSource->read_at(data_offset, &version, 1) < 1) {
+ return ERROR_IO;
+ }
+
+ uint64_t ctime, mtime, duration;
+ int32_t id;
+ uint32_t width, height;
+
+ if (version == 1) {
+ if (chunk_data_size != 36 + 60) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[36 + 60];
+ if (mDataSource->read_at(
+ data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+
+ ctime = U64_AT(&buffer[4]);
+ mtime = U64_AT(&buffer[12]);
+ id = U32_AT(&buffer[20]);
+ duration = U64_AT(&buffer[28]);
+ width = U32_AT(&buffer[88]);
+ height = U32_AT(&buffer[92]);
+ } else if (version == 0) {
+ if (chunk_data_size != 24 + 60) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[24 + 60];
+ if (mDataSource->read_at(
+ data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+ ctime = U32_AT(&buffer[4]);
+ mtime = U32_AT(&buffer[8]);
+ id = U32_AT(&buffer[12]);
+ duration = U32_AT(&buffer[20]);
+ width = U32_AT(&buffer[76]);
+ height = U32_AT(&buffer[80]);
+ }
+
+ Track *track = new Track;
+ track->next = NULL;
+ if (mLastTrack) {
+ mLastTrack->next = track;
+ } else {
+ mFirstTrack = track;
+ }
+ mLastTrack = track;
+
+ track->meta = new MetaData;
+ track->timescale = 0;
+ track->sampleTable = new SampleTable(mDataSource);
+ track->meta->setCString(kKeyMIMEType, "application/octet-stream");
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('m', 'd', 'h', 'd'):
+ {
+ if (chunk_data_size < 4) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t version;
+ if (mDataSource->read_at(
+ data_offset, &version, sizeof(version))
+ < (ssize_t)sizeof(version)) {
+ return ERROR_IO;
+ }
+
+ off_t timescale_offset;
+
+ if (version == 1) {
+ timescale_offset = data_offset + 4 + 16;
+ } else if (version == 0) {
+ timescale_offset = data_offset + 4 + 8;
+ } else {
+ return ERROR_IO;
+ }
+
+ uint32_t timescale;
+ if (mDataSource->read_at(
+ timescale_offset, &timescale, sizeof(timescale))
+ < (ssize_t)sizeof(timescale)) {
+ return ERROR_IO;
+ }
+
+ mLastTrack->timescale = ntohl(timescale);
+ mLastTrack->meta->setInt32(kKeyTimeScale, mLastTrack->timescale);
+
+ int64_t duration;
+ if (version == 1) {
+ if (mDataSource->read_at(
+ timescale_offset + 4, &duration, sizeof(duration))
+ < (ssize_t)sizeof(duration)) {
+ return ERROR_IO;
+ }
+ duration = ntoh64(duration);
+ } else {
+ int32_t duration32;
+ if (mDataSource->read_at(
+ timescale_offset + 4, &duration32, sizeof(duration32))
+ < (ssize_t)sizeof(duration32)) {
+ return ERROR_IO;
+ }
+ duration = ntohl(duration32);
+ }
+ mLastTrack->meta->setInt32(kKeyDuration, duration);
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('h', 'd', 'l', 'r'):
+ {
+ if (chunk_data_size < 25) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[24];
+ if (mDataSource->read_at(data_offset, buffer, 24) < 24) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(buffer) != 0) {
+ // Should be version 0, flags 0.
+ return ERROR_MALFORMED;
+ }
+
+ if (U32_AT(&buffer[4]) != 0) {
+ // pre_defined should be 0.
+ return ERROR_MALFORMED;
+ }
+
+ mHandlerType = U32_AT(&buffer[8]);
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('s', 't', 's', 'd'):
+ {
+ if (chunk_data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[8];
+ CHECK(chunk_data_size >= (off_t)sizeof(buffer));
+ if (mDataSource->read_at(
+ data_offset, buffer, 8) < 8) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(buffer) != 0) {
+ // Should be version 0, flags 0.
+ return ERROR_MALFORMED;
+ }
+
+ uint32_t entry_count = U32_AT(&buffer[4]);
+
+ if (entry_count > 1) {
+ // For now we only support a single type of media per track.
+ return ERROR_UNSUPPORTED;
+ }
+
+ off_t stop_offset = *offset + chunk_size;
+ *offset = data_offset + 8;
+ for (uint32_t i = 0; i < entry_count; ++i) {
+ status_t err = parseChunk(offset, depth + 1);
+ if (err != OK) {
+ return err;
+ }
+ }
+ CHECK_EQ(*offset, stop_offset);
+ break;
+ }
+
+ case FOURCC('m', 'p', '4', 'a'):
+ case FOURCC('s', 'a', 'm', 'r'):
+ {
+ if (mHandlerType != FOURCC('s', 'o', 'u', 'n')) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[8 + 20];
+ if (chunk_data_size < (ssize_t)sizeof(buffer)) {
+ // Basic AudioSampleEntry size.
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->read_at(
+ data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+
+ uint16_t data_ref_index = U16_AT(&buffer[6]);
+ uint16_t num_channels = U16_AT(&buffer[16]);
+
+ if (!strcasecmp("audio/3gpp", FourCC2MIME(chunk_type))) {
+ // AMR audio is always mono.
+ num_channels = 1;
+ }
+
+ uint16_t sample_size = U16_AT(&buffer[18]);
+ uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
+
+ printf("*** coding='%s' %d channels, size %d, rate %d\n",
+ chunk, num_channels, sample_size, sample_rate);
+
+ mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
+ mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
+ mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
+
+ off_t stop_offset = *offset + chunk_size;
+ *offset = data_offset + sizeof(buffer);
+ while (*offset < stop_offset) {
+ status_t err = parseChunk(offset, depth + 1);
+ if (err != OK) {
+ return err;
+ }
+ }
+ CHECK_EQ(*offset, stop_offset);
+ break;
+ }
+
+ case FOURCC('m', 'p', '4', 'v'):
+ case FOURCC('s', '2', '6', '3'):
+ case FOURCC('a', 'v', 'c', '1'):
+ {
+ if (mHandlerType != FOURCC('v', 'i', 'd', 'e')) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[78];
+ if (chunk_data_size < (ssize_t)sizeof(buffer)) {
+ // Basic VideoSampleEntry size.
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->read_at(
+ data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+
+ uint16_t data_ref_index = U16_AT(&buffer[6]);
+ uint16_t width = U16_AT(&buffer[6 + 18]);
+ uint16_t height = U16_AT(&buffer[6 + 20]);
+
+ printf("*** coding='%s' width=%d height=%d\n",
+ chunk, width, height);
+
+ mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
+ mLastTrack->meta->setInt32(kKeyWidth, width);
+ mLastTrack->meta->setInt32(kKeyHeight, height);
+
+ off_t stop_offset = *offset + chunk_size;
+ *offset = data_offset + sizeof(buffer);
+ while (*offset < stop_offset) {
+ status_t err = parseChunk(offset, depth + 1);
+ if (err != OK) {
+ return err;
+ }
+ }
+ CHECK_EQ(*offset, stop_offset);
+ break;
+ }
+
+ case FOURCC('s', 't', 'c', 'o'):
+ case FOURCC('c', 'o', '6', '4'):
+ {
+ status_t err =
+ mLastTrack->sampleTable->setChunkOffsetParams(
+ chunk_type, data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('s', 't', 's', 'c'):
+ {
+ status_t err =
+ mLastTrack->sampleTable->setSampleToChunkParams(
+ data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('s', 't', 's', 'z'):
+ case FOURCC('s', 't', 'z', '2'):
+ {
+ status_t err =
+ mLastTrack->sampleTable->setSampleSizeParams(
+ chunk_type, data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('s', 't', 't', 's'):
+ {
+ status_t err =
+ mLastTrack->sampleTable->setTimeToSampleParams(
+ data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('s', 't', 's', 's'):
+ {
+ status_t err =
+ mLastTrack->sampleTable->setSyncSampleParams(
+ data_offset, chunk_data_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('e', 's', 'd', 's'):
+ {
+ if (chunk_data_size < 4) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t buffer[256];
+ if (chunk_data_size > (off_t)sizeof(buffer)) {
+ return ERROR_BUFFER_TOO_SMALL;
+ }
+
+ if (mDataSource->read_at(
+ data_offset, buffer, chunk_data_size) < chunk_data_size) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(buffer) != 0) {
+ // Should be version 0, flags 0.
+ return ERROR_MALFORMED;
+ }
+
+ mLastTrack->meta->setData(
+ kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
+
+ *offset += chunk_size;
+ break;
+ }
+
+ case FOURCC('a', 'v', 'c', 'C'):
+ {
+ char buffer[256];
+ if (chunk_data_size > (off_t)sizeof(buffer)) {
+ return ERROR_BUFFER_TOO_SMALL;
+ }
+
+ if (mDataSource->read_at(
+ data_offset, buffer, chunk_data_size) < chunk_data_size) {
+ return ERROR_IO;
+ }
+
+ mLastTrack->meta->setData(
+ kKeyAVCC, kTypeAVCC, buffer, chunk_data_size);
+
+ *offset += chunk_size;
+ break;
+ }
+
+ default:
+ {
+ *offset += chunk_size;
+ break;
+ }
+ }
+
+ return OK;
+}
+
+sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
+ status_t err;
+ if ((err = readMetaData()) != OK) {
+ return NULL;
+ }
+
+ Track *track = mFirstTrack;
+ while (index > 0) {
+ if (track == NULL) {
+ return NULL;
+ }
+
+ track = track->next;
+ --index;
+ }
+
+ return new MPEG4Source(
+ track->meta, mDataSource, track->sampleTable);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG4Source::MPEG4Source(
+ const sp<MetaData> &format,
+ const sp<DataSource> &dataSource,
+ const sp<SampleTable> &sampleTable)
+ : mFormat(format),
+ mDataSource(dataSource),
+ mTimescale(0),
+ mSampleTable(sampleTable),
+ mCurrentSampleIndex(0),
+ mIsAVC(false),
+ mStarted(false),
+ mGroup(NULL),
+ mBuffer(NULL),
+ mWantsNALFragments(false),
+ mSrcBuffer(NULL) {
+ const char *mime;
+ bool success = mFormat->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+
+ success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
+ CHECK(success);
+
+ mIsAVC = !strcasecmp(mime, "video/avc");
+}
+
+MPEG4Source::~MPEG4Source() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t MPEG4Source::start(MetaData *params) {
+ CHECK(!mStarted);
+
+ int32_t val;
+ if (params && params->findInt32(kKeyWantsNALFragments, &val)
+ && val != 0) {
+ mWantsNALFragments = true;
+ } else {
+ mWantsNALFragments = false;
+ }
+
+ mGroup = new MediaBufferGroup;
+
+ size_t max_size;
+ status_t err = mSampleTable->getMaxSampleSize(&max_size);
+ CHECK_EQ(err, OK);
+
+ // Assume that a given buffer only contains at most 10 fragments,
+ // each fragment originally prefixed with a 2 byte length will
+ // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
+ // and thus will grow by 2 bytes per fragment.
+ mGroup->add_buffer(new MediaBuffer(max_size + 10 * 2));
+
+ mSrcBuffer = new uint8_t[max_size];
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t MPEG4Source::stop() {
+ CHECK(mStarted);
+
+ if (mBuffer != NULL) {
+ mBuffer->release();
+ mBuffer = NULL;
+ }
+
+ delete[] mSrcBuffer;
+ mSrcBuffer = NULL;
+
+ delete mGroup;
+ mGroup = NULL;
+
+ mStarted = false;
+ mCurrentSampleIndex = 0;
+
+ return OK;
+}
+
+sp<MetaData> MPEG4Source::getFormat() {
+ return mFormat;
+}
+
+status_t MPEG4Source::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ CHECK(mStarted);
+
+ *out = NULL;
+
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ uint32_t sampleIndex;
+ status_t err = mSampleTable->findClosestSample(
+ seekTimeUs * mTimescale / 1000000,
+ &sampleIndex, SampleTable::kSyncSample_Flag);
+
+ if (err != OK) {
+ return err;
+ }
+
+ mCurrentSampleIndex = sampleIndex;
+ if (mBuffer != NULL) {
+ mBuffer->release();
+ mBuffer = NULL;
+ }
+
+ // fall through
+ }
+
+ off_t offset;
+ size_t size;
+ uint32_t dts;
+ bool newBuffer = false;
+ if (mBuffer == NULL) {
+ newBuffer = true;
+
+ status_t err = mSampleTable->getSampleOffsetAndSize(
+ mCurrentSampleIndex, &offset, &size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+
+ if (err != OK) {
+ return err;
+ }
+
+ err = mGroup->acquire_buffer(&mBuffer);
+ if (err != OK) {
+ CHECK_EQ(mBuffer, NULL);
+ return err;
+ }
+ }
+
+ if (!mIsAVC || mWantsNALFragments) {
+ if (newBuffer) {
+ ssize_t num_bytes_read =
+ mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
+
+ if (num_bytes_read < (ssize_t)size) {
+ mBuffer->release();
+ mBuffer = NULL;
+
+ return ERROR_IO;
+ }
+
+ mBuffer->set_range(0, size);
+ mBuffer->meta_data()->clear();
+ mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+ mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+ ++mCurrentSampleIndex;
+ }
+
+ if (!mIsAVC) {
+ *out = mBuffer;
+ mBuffer = NULL;
+
+ return OK;
+ }
+
+ // Each NAL unit is split up into its constituent fragments and
+ // each one of them returned in its own buffer.
+
+ CHECK(mBuffer->range_length() >= 2);
+
+ const uint8_t *src =
+ (const uint8_t *)mBuffer->data() + mBuffer->range_offset();
+
+ size_t nal_size = U16_AT(src);
+
+ CHECK(mBuffer->range_length() >= 2 + nal_size);
+
+ MediaBuffer *clone = mBuffer->clone();
+ clone->set_range(mBuffer->range_offset() + 2, nal_size);
+
+ mBuffer->set_range(
+ mBuffer->range_offset() + 2 + nal_size,
+ mBuffer->range_length() - 2 - nal_size);
+
+ if (mBuffer->range_length() == 0) {
+ mBuffer->release();
+ mBuffer = NULL;
+ }
+
+ *out = clone;
+
+ return OK;
+ } else {
+ // Whole NAL units are returned but each fragment is prefixed by
+ // the start code (0x00 00 00 01).
+
+ ssize_t num_bytes_read =
+ mDataSource->read_at(offset, mSrcBuffer, size);
+
+ if (num_bytes_read < (ssize_t)size) {
+ mBuffer->release();
+ mBuffer = NULL;
+
+ return ERROR_IO;
+ }
+
+ uint8_t *dstData = (uint8_t *)mBuffer->data();
+ size_t srcOffset = 0;
+ size_t dstOffset = 0;
+ while (srcOffset < size) {
+ CHECK(srcOffset + 1 < size);
+ size_t nalLength =
+ (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1];
+ CHECK(srcOffset + 1 + nalLength < size);
+ srcOffset += 2;
+
+ if (nalLength == 0) {
+ continue;
+ }
+
+ CHECK(dstOffset + 4 <= mBuffer->size());
+
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 0;
+ dstData[dstOffset++] = 1;
+ memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
+ srcOffset += nalLength;
+ dstOffset += nalLength;
+ }
+
+ mBuffer->set_range(0, dstOffset);
+ mBuffer->meta_data()->clear();
+ mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
+ mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+ ++mCurrentSampleIndex;
+
+ *out = mBuffer;
+ mBuffer = NULL;
+
+ return OK;
+ }
+}
+
+bool SniffMPEG4(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ uint8_t header[8];
+
+ ssize_t n = source->read_at(4, header, sizeof(header));
+ if (n < (ssize_t)sizeof(header)) {
+ return false;
+ }
+
+ if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
+ || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)) {
+ *mimeType = "video/mp4";
+ *confidence = 0.1;
+
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
new file mode 100644
index 0000000..90b1b9a
--- /dev/null
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -0,0 +1,647 @@
+/*
+ * 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 <arpa/inet.h>
+
+#include <ctype.h>
+#include <pthread.h>
+
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+class MPEG4Writer::Track {
+public:
+ Track(MPEG4Writer *owner,
+ const sp<MetaData> &meta, const sp<MediaSource> &source);
+ ~Track();
+
+ void start();
+ void stop();
+
+ int64_t getDuration() const;
+ void writeTrackHeader(int32_t trackID);
+
+private:
+ MPEG4Writer *mOwner;
+ sp<MetaData> mMeta;
+ sp<MediaSource> mSource;
+ volatile bool mDone;
+
+ pthread_t mThread;
+
+ struct SampleInfo {
+ size_t size;
+ off_t offset;
+ int64_t timestamp;
+ };
+ List<SampleInfo> mSampleInfos;
+
+ void *mCodecSpecificData;
+ size_t mCodecSpecificDataSize;
+
+ static void *ThreadWrapper(void *me);
+ void threadEntry();
+
+ Track(const Track &);
+ Track &operator=(const Track &);
+};
+
+MPEG4Writer::MPEG4Writer(const char *filename)
+ : mFile(fopen(filename, "wb")),
+ mOffset(0),
+ mMdatOffset(0) {
+ CHECK(mFile != NULL);
+}
+
+MPEG4Writer::~MPEG4Writer() {
+ stop();
+
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it) {
+ delete *it;
+ }
+ mTracks.clear();
+}
+
+void MPEG4Writer::addSource(
+ const sp<MetaData> &meta, const sp<MediaSource> &source) {
+ Track *track = new Track(this, meta, source);
+ mTracks.push_back(track);
+}
+
+void MPEG4Writer::start() {
+ if (mFile == NULL) {
+ return;
+ }
+
+ beginBox("ftyp");
+ writeFourcc("isom");
+ writeInt32(0);
+ writeFourcc("isom");
+ endBox();
+
+ mMdatOffset = mOffset;
+ write("\x00\x00\x00\x01mdat????????", 16);
+
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it) {
+ (*it)->start();
+ }
+}
+
+void MPEG4Writer::stop() {
+ if (mFile == NULL) {
+ return;
+ }
+
+ int64_t max_duration = 0;
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it) {
+ (*it)->stop();
+
+ int64_t duration = (*it)->getDuration();
+ if (duration > max_duration) {
+ max_duration = duration;
+ }
+ }
+
+ // Fix up the size of the 'mdat' chunk.
+ fseek(mFile, mMdatOffset + 8, SEEK_SET);
+ int64_t size = mOffset - mMdatOffset;
+ size = hton64(size);
+ fwrite(&size, 1, 8, mFile);
+ fseek(mFile, mOffset, SEEK_SET);
+
+ time_t now = time(NULL);
+
+ beginBox("moov");
+
+ beginBox("mvhd");
+ writeInt32(0); // version=0, flags=0
+ writeInt32(now); // creation time
+ writeInt32(now); // modification time
+ writeInt32(1000); // timescale
+ writeInt32(max_duration);
+ writeInt32(0x10000); // rate
+ writeInt16(0x100); // volume
+ writeInt16(0); // reserved
+ writeInt32(0); // reserved
+ writeInt32(0); // reserved
+ writeInt32(0x10000); // matrix
+ writeInt32(0);
+ writeInt32(0);
+ writeInt32(0);
+ writeInt32(0x10000);
+ writeInt32(0);
+ writeInt32(0);
+ writeInt32(0);
+ writeInt32(0x40000000);
+ writeInt32(0); // predefined
+ writeInt32(0); // predefined
+ writeInt32(0); // predefined
+ writeInt32(0); // predefined
+ writeInt32(0); // predefined
+ writeInt32(0); // predefined
+ writeInt32(mTracks.size() + 1); // nextTrackID
+ endBox(); // mvhd
+
+ int32_t id = 1;
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it, ++id) {
+ (*it)->writeTrackHeader(id);
+ }
+ endBox(); // moov
+
+ CHECK(mBoxes.empty());
+
+ fclose(mFile);
+ mFile = NULL;
+}
+
+off_t MPEG4Writer::addSample(MediaBuffer *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ off_t old_offset = mOffset;
+
+ fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
+ 1, buffer->range_length(), mFile);
+
+ mOffset += buffer->range_length();
+
+ return old_offset;
+}
+
+void MPEG4Writer::beginBox(const char *fourcc) {
+ CHECK_EQ(strlen(fourcc), 4);
+
+ mBoxes.push_back(mOffset);
+
+ writeInt32(0);
+ writeFourcc(fourcc);
+}
+
+void MPEG4Writer::endBox() {
+ CHECK(!mBoxes.empty());
+
+ off_t offset = *--mBoxes.end();
+ mBoxes.erase(--mBoxes.end());
+
+ fseek(mFile, offset, SEEK_SET);
+ writeInt32(mOffset - offset);
+ mOffset -= 4;
+ fseek(mFile, mOffset, SEEK_SET);
+}
+
+void MPEG4Writer::writeInt8(int8_t x) {
+ fwrite(&x, 1, 1, mFile);
+ ++mOffset;
+}
+
+void MPEG4Writer::writeInt16(int16_t x) {
+ x = htons(x);
+ fwrite(&x, 1, 2, mFile);
+ mOffset += 2;
+}
+
+void MPEG4Writer::writeInt32(int32_t x) {
+ x = htonl(x);
+ fwrite(&x, 1, 4, mFile);
+ mOffset += 4;
+}
+
+void MPEG4Writer::writeInt64(int64_t x) {
+ x = hton64(x);
+ fwrite(&x, 1, 8, mFile);
+ mOffset += 8;
+}
+
+void MPEG4Writer::writeCString(const char *s) {
+ size_t n = strlen(s);
+
+ fwrite(s, 1, n + 1, mFile);
+ mOffset += n + 1;
+}
+
+void MPEG4Writer::writeFourcc(const char *s) {
+ CHECK_EQ(strlen(s), 4);
+ fwrite(s, 1, 4, mFile);
+ mOffset += 4;
+}
+
+void MPEG4Writer::write(const void *data, size_t size) {
+ fwrite(data, 1, size, mFile);
+ mOffset += size;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG4Writer::Track::Track(
+ MPEG4Writer *owner,
+ const sp<MetaData> &meta, const sp<MediaSource> &source)
+ : mOwner(owner),
+ mMeta(meta),
+ mSource(source),
+ mDone(false),
+ mCodecSpecificData(NULL),
+ mCodecSpecificDataSize(0) {
+}
+
+MPEG4Writer::Track::~Track() {
+ stop();
+
+ if (mCodecSpecificData != NULL) {
+ free(mCodecSpecificData);
+ mCodecSpecificData = NULL;
+ }
+}
+
+void MPEG4Writer::Track::start() {
+ mSource->start();
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ mDone = false;
+
+ int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
+ CHECK_EQ(err, 0);
+
+ pthread_attr_destroy(&attr);
+}
+
+void MPEG4Writer::Track::stop() {
+ if (mDone) {
+ return;
+ }
+
+ mDone = true;
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+
+ mSource->stop();
+}
+
+// static
+void *MPEG4Writer::Track::ThreadWrapper(void *me) {
+ Track *track = static_cast<Track *>(me);
+
+ track->threadEntry();
+
+ return NULL;
+}
+
+void MPEG4Writer::Track::threadEntry() {
+ bool is_mpeg4 = false;
+ sp<MetaData> meta = mSource->getFormat();
+ const char *mime;
+ meta->findCString(kKeyMIMEType, &mime);
+ is_mpeg4 = !strcasecmp(mime, "video/mp4v-es");
+
+ MediaBuffer *buffer;
+ while (!mDone && mSource->read(&buffer) == OK) {
+ if (buffer->range_length() == 0) {
+ buffer->release();
+ buffer = NULL;
+
+ continue;
+ }
+
+ if (mCodecSpecificData == NULL && is_mpeg4) {
+ const uint8_t *data =
+ (const uint8_t *)buffer->data() + buffer->range_offset();
+
+ const size_t size = buffer->range_length();
+
+ size_t offset = 0;
+ while (offset + 3 < size) {
+ if (data[offset] == 0x00 && data[offset + 1] == 0x00
+ && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) {
+ break;
+ }
+
+ ++offset;
+ }
+
+ // CHECK(offset + 3 < size);
+ if (offset + 3 >= size) {
+ // XXX assume the entire first chunk of data is the codec specific
+ // data.
+ offset = size;
+ }
+
+ mCodecSpecificDataSize = offset;
+ mCodecSpecificData = malloc(offset);
+ memcpy(mCodecSpecificData, data, offset);
+
+ buffer->set_range(buffer->range_offset() + offset, size - offset);
+ }
+
+ off_t offset = mOwner->addSample(buffer);
+
+ SampleInfo info;
+ info.size = buffer->range_length();
+ info.offset = offset;
+
+ int32_t units, scale;
+ bool success =
+ buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+ CHECK(success);
+ success =
+ buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+ CHECK(success);
+
+ info.timestamp = (int64_t)units * 1000 / scale;
+
+ mSampleInfos.push_back(info);
+
+ buffer->release();
+ buffer = NULL;
+ }
+}
+
+int64_t MPEG4Writer::Track::getDuration() const {
+ return 10000; // XXX
+}
+
+void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
+ const char *mime;
+ bool success = mMeta->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+
+ bool is_audio = !strncasecmp(mime, "audio/", 6);
+
+ time_t now = time(NULL);
+
+ mOwner->beginBox("trak");
+
+ mOwner->beginBox("tkhd");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(now); // creation time
+ mOwner->writeInt32(now); // modification time
+ mOwner->writeInt32(trackID);
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt32(getDuration());
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt16(0); // layer
+ mOwner->writeInt16(0); // alternate group
+ mOwner->writeInt16(is_audio ? 0x100 : 0); // volume
+ mOwner->writeInt16(0); // reserved
+
+ mOwner->writeInt32(0x10000); // matrix
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0x10000);
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0x40000000);
+
+ if (is_audio) {
+ mOwner->writeInt32(0);
+ mOwner->writeInt32(0);
+ } else {
+ int32_t width, height;
+ bool success = mMeta->findInt32(kKeyWidth, &width);
+ success = success && mMeta->findInt32(kKeyHeight, &height);
+ CHECK(success);
+
+ mOwner->writeInt32(width);
+ mOwner->writeInt32(height);
+ }
+ mOwner->endBox(); // tkhd
+
+ mOwner->beginBox("mdia");
+
+ mOwner->beginBox("mdhd");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(now); // creation time
+ mOwner->writeInt32(now); // modification time
+ mOwner->writeInt32(1000); // timescale
+ mOwner->writeInt32(getDuration());
+ mOwner->writeInt16(0); // language code XXX
+ mOwner->writeInt16(0); // predefined
+ mOwner->endBox();
+
+ mOwner->beginBox("hdlr");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(0); // predefined
+ mOwner->writeFourcc(is_audio ? "soun" : "vide");
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeCString(""); // name
+ mOwner->endBox();
+
+ mOwner->beginBox("minf");
+
+ mOwner->beginBox("dinf");
+ mOwner->beginBox("dref");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(1);
+ mOwner->beginBox("url ");
+ mOwner->writeInt32(1); // version=0, flags=1
+ mOwner->endBox(); // url
+ mOwner->endBox(); // dref
+ mOwner->endBox(); // dinf
+
+ if (is_audio) {
+ mOwner->beginBox("smhd");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt16(0); // balance
+ mOwner->writeInt16(0); // reserved
+ mOwner->endBox();
+ } else {
+ mOwner->beginBox("vmhd");
+ mOwner->writeInt32(0x00000001); // version=0, flags=1
+ mOwner->writeInt16(0); // graphics mode
+ mOwner->writeInt16(0); // opcolor
+ mOwner->writeInt16(0);
+ mOwner->writeInt16(0);
+ mOwner->endBox();
+ }
+ mOwner->endBox(); // minf
+
+ mOwner->beginBox("stbl");
+
+ mOwner->beginBox("stsd");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(1); // entry count
+ if (is_audio) {
+ mOwner->beginBox("xxxx"); // audio format XXX
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt16(0); // reserved
+ mOwner->writeInt16(0); // data ref index
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt16(2); // channel count
+ mOwner->writeInt16(16); // sample size
+ mOwner->writeInt16(0); // predefined
+ mOwner->writeInt16(0); // reserved
+
+ int32_t samplerate;
+ bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
+ CHECK(success);
+
+ mOwner->writeInt32(samplerate << 16);
+ mOwner->endBox();
+ } else {
+ if (!strcasecmp("video/mp4v-es", mime)) {
+ mOwner->beginBox("mp4v");
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ mOwner->beginBox("s263");
+ } else {
+ CHECK(!"should not be here, unknown mime type.");
+ }
+
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt16(0); // reserved
+ mOwner->writeInt16(0); // data ref index
+ mOwner->writeInt16(0); // predefined
+ mOwner->writeInt16(0); // reserved
+ mOwner->writeInt32(0); // predefined
+ mOwner->writeInt32(0); // predefined
+ mOwner->writeInt32(0); // predefined
+
+ int32_t width, height;
+ bool success = mMeta->findInt32(kKeyWidth, &width);
+ success = success && mMeta->findInt32(kKeyHeight, &height);
+ CHECK(success);
+
+ mOwner->writeInt16(width);
+ mOwner->writeInt16(height);
+ mOwner->writeInt32(0x480000); // horiz resolution
+ mOwner->writeInt32(0x480000); // vert resolution
+ mOwner->writeInt32(0); // reserved
+ mOwner->writeInt16(1); // frame count
+ mOwner->write(" ", 32);
+ mOwner->writeInt16(0x18); // depth
+ mOwner->writeInt16(-1); // predefined
+
+ CHECK(23 + mCodecSpecificDataSize < 128);
+
+ if (!strcasecmp("video/mp4v-es", mime)) {
+ mOwner->beginBox("esds");
+
+ mOwner->writeInt32(0); // version=0, flags=0
+
+ mOwner->writeInt8(0x03); // ES_DescrTag
+ mOwner->writeInt8(23 + mCodecSpecificDataSize);
+ mOwner->writeInt16(0x0000); // ES_ID
+ mOwner->writeInt8(0x1f);
+
+ mOwner->writeInt8(0x04); // DecoderConfigDescrTag
+ mOwner->writeInt8(15 + mCodecSpecificDataSize);
+ mOwner->writeInt8(0x20); // objectTypeIndication ISO/IEC 14492-2
+ mOwner->writeInt8(0x11); // streamType VisualStream
+
+ static const uint8_t kData[] = {
+ 0x01, 0x77, 0x00,
+ 0x00, 0x03, 0xe8, 0x00,
+ 0x00, 0x03, 0xe8, 0x00
+ };
+ mOwner->write(kData, sizeof(kData));
+
+ mOwner->writeInt8(0x05); // DecoderSpecificInfoTag
+
+ mOwner->writeInt8(mCodecSpecificDataSize);
+ mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
+
+ static const uint8_t kData2[] = {
+ 0x06, // SLConfigDescriptorTag
+ 0x01,
+ 0x02
+ };
+ mOwner->write(kData2, sizeof(kData2));
+
+ mOwner->endBox(); // esds
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ mOwner->beginBox("d263");
+
+ mOwner->writeInt32(0); // vendor
+ mOwner->writeInt8(0); // decoder version
+ mOwner->writeInt8(10); // level: 10
+ mOwner->writeInt8(0); // profile: 0
+
+ mOwner->endBox(); // d263
+ }
+ mOwner->endBox(); // mp4v or s263
+ }
+ mOwner->endBox(); // stsd
+
+ mOwner->beginBox("stts");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(mSampleInfos.size() - 1);
+
+ List<SampleInfo>::iterator it = mSampleInfos.begin();
+ int64_t last = (*it).timestamp;
+ ++it;
+ while (it != mSampleInfos.end()) {
+ mOwner->writeInt32(1);
+ mOwner->writeInt32((*it).timestamp - last);
+
+ last = (*it).timestamp;
+
+ ++it;
+ }
+ mOwner->endBox(); // stts
+
+ mOwner->beginBox("stsz");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(0); // default sample size
+ mOwner->writeInt32(mSampleInfos.size());
+ for (List<SampleInfo>::iterator it = mSampleInfos.begin();
+ it != mSampleInfos.end(); ++it) {
+ mOwner->writeInt32((*it).size);
+ }
+ mOwner->endBox(); // stsz
+
+ mOwner->beginBox("stsc");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(mSampleInfos.size());
+ int32_t n = 1;
+ for (List<SampleInfo>::iterator it = mSampleInfos.begin();
+ it != mSampleInfos.end(); ++it, ++n) {
+ mOwner->writeInt32(n);
+ mOwner->writeInt32(1);
+ mOwner->writeInt32(1);
+ }
+ mOwner->endBox(); // stsc
+
+ mOwner->beginBox("co64");
+ mOwner->writeInt32(0); // version=0, flags=0
+ mOwner->writeInt32(mSampleInfos.size());
+ for (List<SampleInfo>::iterator it = mSampleInfos.begin();
+ it != mSampleInfos.end(); ++it, ++n) {
+ mOwner->writeInt64((*it).offset);
+ }
+ mOwner->endBox(); // co64
+
+ mOwner->endBox(); // stbl
+ mOwner->endBox(); // mdia
+ mOwner->endBox(); // trak
+}
+
+} // namespace android
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
new file mode 100644
index 0000000..f3c0e73
--- /dev/null
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MediaBuffer"
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+// XXX make this truly atomic.
+static int atomic_add(int *value, int delta) {
+ int prev_value = *value;
+ *value += delta;
+
+ return prev_value;
+}
+
+MediaBuffer::MediaBuffer(void *data, size_t size)
+ : mObserver(NULL),
+ mNextBuffer(NULL),
+ mRefCount(0),
+ mData(data),
+ mSize(size),
+ mRangeOffset(0),
+ mRangeLength(size),
+ mOwnsData(false),
+ mMetaData(new MetaData),
+ mOriginal(NULL) {
+}
+
+MediaBuffer::MediaBuffer(size_t size)
+ : mObserver(NULL),
+ mNextBuffer(NULL),
+ mRefCount(0),
+ mData(malloc(size)),
+ mSize(size),
+ mRangeOffset(0),
+ mRangeLength(size),
+ mOwnsData(true),
+ mMetaData(new MetaData),
+ mOriginal(NULL) {
+}
+
+void MediaBuffer::release() {
+ if (mObserver == NULL) {
+ CHECK_EQ(mRefCount, 0);
+ delete this;
+ return;
+ }
+
+ int prevCount = atomic_add(&mRefCount, -1);
+ if (prevCount == 1) {
+ if (mObserver == NULL) {
+ delete this;
+ return;
+ }
+
+ mObserver->signalBufferReturned(this);
+ }
+ CHECK(prevCount > 0);
+}
+
+void MediaBuffer::claim() {
+ CHECK(mObserver != NULL);
+ CHECK_EQ(mRefCount, 1);
+
+ mRefCount = 0;
+}
+
+void MediaBuffer::add_ref() {
+ atomic_add(&mRefCount, 1);
+}
+
+void *MediaBuffer::data() const {
+ return mData;
+}
+
+size_t MediaBuffer::size() const {
+ return mSize;
+}
+
+size_t MediaBuffer::range_offset() const {
+ return mRangeOffset;
+}
+
+size_t MediaBuffer::range_length() const {
+ return mRangeLength;
+}
+
+void MediaBuffer::set_range(size_t offset, size_t length) {
+ if (offset < 0 || offset + length > mSize) {
+ LOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize);
+ }
+ CHECK(offset >= 0 && offset + length <= mSize);
+
+ mRangeOffset = offset;
+ mRangeLength = length;
+}
+
+sp<MetaData> MediaBuffer::meta_data() {
+ return mMetaData;
+}
+
+void MediaBuffer::reset() {
+ mMetaData->clear();
+ set_range(0, mSize);
+}
+
+MediaBuffer::~MediaBuffer() {
+ CHECK_EQ(mObserver, NULL);
+
+ if (mOwnsData && mData != NULL) {
+ free(mData);
+ mData = NULL;
+ }
+
+ if (mOriginal != NULL) {
+ mOriginal->release();
+ mOriginal = NULL;
+ }
+}
+
+void MediaBuffer::setObserver(MediaBufferObserver *observer) {
+ CHECK(observer == NULL || mObserver == NULL);
+ mObserver = observer;
+}
+
+void MediaBuffer::setNextBuffer(MediaBuffer *buffer) {
+ mNextBuffer = buffer;
+}
+
+MediaBuffer *MediaBuffer::nextBuffer() {
+ return mNextBuffer;
+}
+
+int MediaBuffer::refcount() const {
+ return mRefCount;
+}
+
+MediaBuffer *MediaBuffer::clone() {
+ MediaBuffer *buffer = new MediaBuffer(mData, mSize);
+ buffer->set_range(mRangeOffset, mRangeLength);
+ buffer->mMetaData = new MetaData(*mMetaData.get());
+
+ add_ref();
+ buffer->mOriginal = this;
+
+ return buffer;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
new file mode 100644
index 0000000..c8d05f4
--- /dev/null
+++ b/media/libstagefright/MediaBufferGroup.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MediaBufferGroup"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+
+namespace android {
+
+MediaBufferGroup::MediaBufferGroup()
+ : mFirstBuffer(NULL),
+ mLastBuffer(NULL) {
+}
+
+MediaBufferGroup::~MediaBufferGroup() {
+ MediaBuffer *next;
+ for (MediaBuffer *buffer = mFirstBuffer; buffer != NULL;
+ buffer = next) {
+ next = buffer->nextBuffer();
+
+ CHECK_EQ(buffer->refcount(), 0);
+
+ buffer->setObserver(NULL);
+ buffer->release();
+ }
+}
+
+void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ buffer->setObserver(this);
+
+ if (mLastBuffer) {
+ mLastBuffer->setNextBuffer(buffer);
+ } else {
+ mFirstBuffer = buffer;
+ }
+
+ mLastBuffer = buffer;
+}
+
+status_t MediaBufferGroup::acquire_buffer(MediaBuffer **out) {
+ Mutex::Autolock autoLock(mLock);
+
+ for (;;) {
+ for (MediaBuffer *buffer = mFirstBuffer;
+ buffer != NULL; buffer = buffer->nextBuffer()) {
+ if (buffer->refcount() == 0) {
+ buffer->add_ref();
+ buffer->reset();
+
+ *out = buffer;
+ goto exit;
+ }
+ }
+
+ // All buffers are in use. Block until one of them is returned to us.
+ mCondition.wait(mLock);
+ }
+
+exit:
+ return OK;
+}
+
+void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
+ Mutex::Autolock autoLock(mLock);
+ mCondition.signal();
+}
+
+} // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
new file mode 100644
index 0000000..5f78e12
--- /dev/null
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaExtractor"
+#include <utils/Log.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MP3Extractor.h>
+#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// static
+sp<MediaExtractor> MediaExtractor::Create(
+ const sp<DataSource> &source, const char *mime) {
+ String8 tmp;
+ if (mime == NULL) {
+ float confidence;
+ if (!source->sniff(&tmp, &confidence)) {
+ LOGE("FAILED to autodetect media content.");
+
+ return NULL;
+ }
+
+ mime = tmp.string();
+ LOGI("Autodetected media content as '%s' with confidence %.2f",
+ mime, confidence);
+ }
+
+ if (!strcasecmp(mime, "video/mp4") || !strcasecmp(mime, "audio/mp4")) {
+ return new MPEG4Extractor(source);
+ } else if (!strcasecmp(mime, "audio/mpeg")) {
+ return new MP3Extractor(source);
+ }
+
+ return NULL;
+}
+
+} // namespace android
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
new file mode 100644
index 0000000..2e609e3
--- /dev/null
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -0,0 +1,647 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaPlayerImpl"
+#include "utils/Log.h"
+
+#include <OMX_Component.h>
+
+#include <unistd.h>
+
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/CachingDataSource.h>
+// #include <media/stagefright/CameraSource.h>
+#include <media/stagefright/HTTPDataSource.h>
+#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaPlayerImpl.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/ShoutcastSource.h>
+#include <media/stagefright/TimeSource.h>
+#include <ui/PixelFormat.h>
+#include <ui/Surface.h>
+
+namespace android {
+
+MediaPlayerImpl::MediaPlayerImpl(const char *uri)
+ : mInitCheck(NO_INIT),
+ mTimeSource(NULL),
+ mAudioPlayer(NULL),
+ mVideoWidth(0),
+ mVideoHeight(0),
+ mVideoPosition(0),
+ mDuration(0),
+ mPlaying(false),
+ mPaused(false),
+ mSeeking(false) {
+ LOGI("MediaPlayerImpl(%s)", uri);
+ DataSource::RegisterDefaultSniffers();
+
+ status_t err = mClient.connect();
+ if (err != OK) {
+ LOGE("Failed to connect to OMXClient.");
+ return;
+ }
+
+ if (!strncasecmp("shoutcast://", uri, 12)) {
+ setAudioSource(makeShoutcastSource(uri));
+#if 0
+ } else if (!strncasecmp("camera:", uri, 7)) {
+ mVideoWidth = 480;
+ mVideoHeight = 320;
+ mVideoDecoder = CameraSource::Create();
+#endif
+ } else {
+ sp<DataSource> source;
+ if (!strncasecmp("file://", uri, 7)) {
+ source = new MmapSource(uri + 7);
+ } else if (!strncasecmp("http://", uri, 7)) {
+ source = new HTTPDataSource(uri);
+ source = new CachingDataSource(source, 64 * 1024, 10);
+ } else {
+ // Assume it's a filename.
+ source = new MmapSource(uri);
+ }
+
+ mExtractor = MediaExtractor::Create(source);
+
+ if (mExtractor == NULL) {
+ return;
+ }
+ }
+
+ init();
+
+ mInitCheck = OK;
+}
+
+MediaPlayerImpl::MediaPlayerImpl(int fd, int64_t offset, int64_t length)
+ : mInitCheck(NO_INIT),
+ mTimeSource(NULL),
+ mAudioPlayer(NULL),
+ mVideoWidth(0),
+ mVideoHeight(0),
+ mVideoPosition(0),
+ mDuration(0),
+ mPlaying(false),
+ mPaused(false),
+ mSeeking(false) {
+ LOGI("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length);
+ DataSource::RegisterDefaultSniffers();
+
+ status_t err = mClient.connect();
+ if (err != OK) {
+ LOGE("Failed to connect to OMXClient.");
+ return;
+ }
+
+ mExtractor = MediaExtractor::Create(
+ new MmapSource(fd, offset, length));
+
+ if (mExtractor == NULL) {
+ return;
+ }
+
+ init();
+
+ mInitCheck = OK;
+}
+
+status_t MediaPlayerImpl::initCheck() const {
+ return mInitCheck;
+}
+
+MediaPlayerImpl::~MediaPlayerImpl() {
+ stop();
+ setSurface(NULL);
+
+ if (mInitCheck == OK) {
+ mClient.disconnect();
+ }
+
+ LOGV("~MediaPlayerImpl done.");
+}
+
+void MediaPlayerImpl::play() {
+ LOGI("play");
+
+ if (mPlaying) {
+ if (mPaused) {
+ if (mAudioSource != NULL) {
+ mAudioPlayer->resume();
+ }
+ mPaused = false;
+ }
+ return;
+ }
+
+ mPlaying = true;
+
+ if (mAudioSource != NULL) {
+ mAudioPlayer = new AudioPlayer(mAudioSink);
+ mAudioPlayer->setSource(mAudioDecoder);
+ mAudioPlayer->start();
+ mTimeSource = mAudioPlayer;
+ } else {
+ mTimeSource = new SystemTimeSource;
+ }
+
+ if (mVideoDecoder != NULL) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_create(&mVideoThread, &attr, VideoWrapper, this);
+
+ pthread_attr_destroy(&attr);
+ }
+}
+
+void MediaPlayerImpl::pause() {
+ if (!mPlaying || mPaused) {
+ return;
+ }
+
+ if (mAudioSource != NULL) {
+ mAudioPlayer->pause();
+ }
+
+ mPaused = true;
+}
+
+void MediaPlayerImpl::stop() {
+ if (!mPlaying) {
+ return;
+ }
+
+ mPlaying = false;
+
+ if (mVideoDecoder != NULL) {
+ void *dummy;
+ pthread_join(mVideoThread, &dummy);
+ }
+
+ if (mAudioSource != NULL) {
+ mAudioPlayer->stop();
+
+ delete mAudioPlayer;
+ mAudioPlayer = NULL;
+ } else {
+ delete mTimeSource;
+ }
+
+ mTimeSource = NULL;
+}
+
+// static
+void *MediaPlayerImpl::VideoWrapper(void *me) {
+ ((MediaPlayerImpl *)me)->videoEntry();
+
+ return NULL;
+}
+
+void MediaPlayerImpl::videoEntry() {
+ bool firstFrame = true;
+ bool eof = false;
+
+ status_t err = mVideoDecoder->start();
+ CHECK_EQ(err, OK);
+
+ while (mPlaying) {
+ MediaBuffer *buffer;
+
+ MediaSource::ReadOptions options;
+ bool seeking = false;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mSeeking) {
+ LOGI("seek-options to %lld", mSeekTimeUs);
+ options.setSeekTo(mSeekTimeUs);
+
+ mSeeking = false;
+ seeking = true;
+ eof = false;
+ }
+ }
+
+ if (eof || mPaused) {
+ usleep(100000);
+ continue;
+ }
+
+ status_t err = mVideoDecoder->read(&buffer, &options);
+ CHECK((err == OK && buffer != NULL) || (err != OK && buffer == NULL));
+
+ if (err == ERROR_END_OF_STREAM || err != OK) {
+ eof = true;
+ continue;
+ }
+
+ if (buffer->range_length() == 0) {
+ // The final buffer is empty.
+ buffer->release();
+ continue;
+ }
+
+ int32_t units, scale;
+ bool success =
+ buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
+ CHECK(success);
+ success =
+ buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
+ CHECK(success);
+
+ int64_t pts_us = (int64_t)units * 1000000 / scale;
+ {
+ Mutex::Autolock autoLock(mLock);
+ mVideoPosition = pts_us;
+
+ LOGV("now_video = %.2f secs (%lld ms)",
+ pts_us / 1E6, (pts_us + 500) / 1000);
+ }
+
+ if (seeking && mAudioPlayer != NULL) {
+ // Now that we know where exactly video seeked (taking sync-samples
+ // into account), we will seek the audio track to the same time.
+ mAudioPlayer->seekTo(pts_us);
+ }
+
+ if (firstFrame || seeking) {
+ mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - pts_us;
+ firstFrame = false;
+ }
+
+ displayOrDiscardFrame(buffer, pts_us);
+ }
+
+ mVideoDecoder->stop();
+}
+
+void MediaPlayerImpl::displayOrDiscardFrame(
+ MediaBuffer *buffer, int64_t pts_us) {
+ for (;;) {
+ if (!mPlaying || mPaused) {
+ buffer->release();
+ buffer = NULL;
+
+ return;
+ }
+
+ int64_t realtime_us, mediatime_us;
+ if (mAudioPlayer != NULL
+ && mAudioPlayer->getMediaTimeMapping(&realtime_us, &mediatime_us)) {
+ mTimeSourceDeltaUs = realtime_us - mediatime_us;
+ LOGV("mTimeSourceDeltaUs = %.2f secs", mTimeSourceDeltaUs / 1E6);
+ }
+
+ int64_t now_us = mTimeSource->getRealTimeUs();
+ now_us -= mTimeSourceDeltaUs;
+
+ int64_t delay_us = pts_us - now_us;
+
+ if (delay_us < -15000) {
+ // We're late.
+
+ LOGI("we're late by %lld ms, dropping a frame\n",
+ -delay_us / 1000);
+
+ buffer->release();
+ buffer = NULL;
+ return;
+ } else if (delay_us > 100000) {
+ LOGI("we're much too early (by %lld ms)\n",
+ delay_us / 1000);
+ usleep(100000);
+ continue;
+ } else if (delay_us > 0) {
+ usleep(delay_us);
+ }
+
+ break;
+ }
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mVideoRenderer.get() != NULL) {
+ sendFrameToISurface(buffer);
+ }
+ }
+
+ buffer->release();
+ buffer = NULL;
+}
+
+void MediaPlayerImpl::init() {
+ if (mExtractor != NULL) {
+ size_t num_tracks = mExtractor->countTracks();
+
+ mDuration = 0;
+
+ for (size_t i = 0; i < num_tracks; ++i) {
+ const sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+ CHECK(meta != NULL);
+
+ const char *mime;
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ continue;
+ }
+
+ bool is_audio = false;
+ bool is_acceptable = false;
+ if (!strncasecmp(mime, "audio/", 6)) {
+ is_audio = true;
+ is_acceptable = (mAudioSource == NULL);
+ } else if (!strncasecmp(mime, "video/", 6)) {
+ is_acceptable = (mVideoSource == NULL);
+ }
+
+ if (!is_acceptable) {
+ continue;
+ }
+
+ sp<MediaSource> source = mExtractor->getTrack(i);
+
+ int32_t units, scale;
+ if (meta->findInt32(kKeyDuration, &units)
+ && meta->findInt32(kKeyTimeScale, &scale)) {
+ int64_t duration_us = (int64_t)units * 1000000 / scale;
+ if (duration_us > mDuration) {
+ mDuration = duration_us;
+ }
+ }
+
+ if (is_audio) {
+ setAudioSource(source);
+ } else {
+ setVideoSource(source);
+ }
+ }
+ }
+}
+
+void MediaPlayerImpl::setAudioSource(const sp<MediaSource> &source) {
+ LOGI("setAudioSource");
+ mAudioSource = source;
+
+ sp<MetaData> meta = source->getFormat();
+
+ mAudioDecoder = OMXCodec::Create(
+ mClient.interface(), meta, false /* createEncoder */, source);
+}
+
+void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) {
+ LOGI("setVideoSource");
+ mVideoSource = source;
+
+ sp<MetaData> meta = source->getFormat();
+
+ bool success = meta->findInt32(kKeyWidth, &mVideoWidth);
+ CHECK(success);
+
+ success = meta->findInt32(kKeyHeight, &mVideoHeight);
+ CHECK(success);
+
+ mVideoDecoder = OMXCodec::Create(
+ mClient.interface(), meta, false /* createEncoder */, source);
+
+ if (mISurface.get() != NULL || mSurface.get() != NULL) {
+ depopulateISurface();
+ populateISurface();
+ }
+}
+
+void MediaPlayerImpl::setSurface(const sp<Surface> &surface) {
+ LOGI("setSurface %p", surface.get());
+ Mutex::Autolock autoLock(mLock);
+
+ depopulateISurface();
+
+ mSurface = surface;
+ mISurface = NULL;
+
+ if (mSurface.get() != NULL) {
+ populateISurface();
+ }
+}
+
+void MediaPlayerImpl::setISurface(const sp<ISurface> &isurface) {
+ LOGI("setISurface %p", isurface.get());
+ Mutex::Autolock autoLock(mLock);
+
+ depopulateISurface();
+
+ mSurface = NULL;
+ mISurface = isurface;
+
+ if (mISurface.get() != NULL) {
+ populateISurface();
+ }
+}
+
+MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) {
+ if (strncasecmp(uri, "shoutcast://", 12)) {
+ return NULL;
+ }
+
+ string host;
+ string path;
+ int port;
+
+ char *slash = strchr(uri + 12, '/');
+ if (slash == NULL) {
+ host = uri + 12;
+ path = "/";
+ } else {
+ host = string(uri + 12, slash - (uri + 12));
+ path = slash;
+ }
+
+ char *colon = strchr(host.c_str(), ':');
+ if (colon == NULL) {
+ port = 80;
+ } else {
+ char *end;
+ long tmp = strtol(colon + 1, &end, 10);
+ CHECK(end > colon + 1);
+ CHECK(tmp > 0 && tmp < 65536);
+ port = tmp;
+
+ host = string(host, 0, colon - host.c_str());
+ }
+
+ LOGI("Connecting to host '%s', port %d, path '%s'",
+ host.c_str(), port, path.c_str());
+
+ HTTPStream *http = new HTTPStream;
+ int http_status;
+
+ for (;;) {
+ status_t err = http->connect(host.c_str(), port);
+ CHECK_EQ(err, OK);
+
+ err = http->send("GET ");
+ err = http->send(path.c_str());
+ err = http->send(" HTTP/1.1\r\n");
+ err = http->send("Host: ");
+ err = http->send(host.c_str());
+ err = http->send("\r\n");
+ err = http->send("Icy-MetaData: 1\r\n\r\n");
+
+ CHECK_EQ(OK, http->receive_header(&http_status));
+
+ if (http_status == 301 || http_status == 302) {
+ string location;
+ CHECK(http->find_header_value("Location", &location));
+
+ CHECK(string(location, 0, 7) == "http://");
+ location.erase(0, 7);
+ string::size_type slashPos = location.find('/');
+ if (slashPos == string::npos) {
+ slashPos = location.size();
+ location += '/';
+ }
+
+ http->disconnect();
+
+ LOGI("Redirecting to %s\n", location.c_str());
+
+ host = string(location, 0, slashPos);
+
+ string::size_type colonPos = host.find(':');
+ if (colonPos != string::npos) {
+ const char *start = host.c_str() + colonPos + 1;
+ char *end;
+ long tmp = strtol(start, &end, 10);
+ CHECK(end > start && (*end == '\0'));
+
+ port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80;
+ } else {
+ port = 80;
+ }
+
+ path = string(location, slashPos);
+
+ continue;
+ }
+
+ break;
+ }
+
+ if (http_status != 200) {
+ LOGE("Connection failed: http_status = %d", http_status);
+ return NULL;
+ }
+
+ MediaSource *source = new ShoutcastSource(http);
+
+ return source;
+}
+
+bool MediaPlayerImpl::isPlaying() const {
+ return mPlaying && !mPaused;
+}
+
+int64_t MediaPlayerImpl::getDuration() {
+ return mDuration;
+}
+
+int64_t MediaPlayerImpl::getPosition() {
+ int64_t position = 0;
+ if (mVideoSource != NULL) {
+ Mutex::Autolock autoLock(mLock);
+ position = mVideoPosition;
+ } else if (mAudioPlayer != NULL) {
+ position = mAudioPlayer->getMediaTimeUs();
+ }
+
+ return position;
+}
+
+status_t MediaPlayerImpl::seekTo(int64_t time) {
+ LOGI("seekTo %lld", time);
+
+ if (mPaused) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (mVideoSource == NULL && mAudioPlayer != NULL) {
+ mAudioPlayer->seekTo(time);
+ } else {
+ Mutex::Autolock autoLock(mLock);
+ mSeekTimeUs = time;
+ mSeeking = true;
+ }
+
+ return OK;
+}
+
+void MediaPlayerImpl::populateISurface() {
+ if (mVideoSource == NULL) {
+ return;
+ }
+
+ sp<MetaData> meta = mVideoDecoder->getFormat();
+
+ int32_t format;
+ const char *component;
+ int32_t decodedWidth, decodedHeight;
+ bool success = meta->findInt32(kKeyColorFormat, &format);
+ success = success && meta->findCString(kKeyDecoderComponent, &component);
+ success = success && meta->findInt32(kKeyWidth, &decodedWidth);
+ success = success && meta->findInt32(kKeyHeight, &decodedHeight);
+ CHECK(success);
+
+ if (mSurface.get() != NULL) {
+ mVideoRenderer =
+ mClient.interface()->createRenderer(
+ mSurface, component,
+ (OMX_COLOR_FORMATTYPE)format,
+ decodedWidth, decodedHeight,
+ mVideoWidth, mVideoHeight);
+ } else {
+ mVideoRenderer =
+ mClient.interface()->createRenderer(
+ mISurface, component,
+ (OMX_COLOR_FORMATTYPE)format,
+ decodedWidth, decodedHeight,
+ mVideoWidth, mVideoHeight);
+ }
+}
+
+void MediaPlayerImpl::depopulateISurface() {
+ mVideoRenderer.clear();
+}
+
+void MediaPlayerImpl::sendFrameToISurface(MediaBuffer *buffer) {
+ void *id;
+ if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
+ mVideoRenderer->render((IOMX::buffer_id)id);
+ }
+}
+
+void MediaPlayerImpl::setAudioSink(
+ const sp<MediaPlayerBase::AudioSink> &audioSink) {
+ LOGI("setAudioSink %p", audioSink.get());
+ mAudioSink = audioSink;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
new file mode 100644
index 0000000..ec89b74
--- /dev/null
+++ b/media/libstagefright/MediaSource.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 <media/stagefright/MediaSource.h>
+
+namespace android {
+
+MediaSource::MediaSource() {}
+
+MediaSource::~MediaSource() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MediaSource::ReadOptions::ReadOptions() {
+ reset();
+}
+
+void MediaSource::ReadOptions::reset() {
+ mOptions = 0;
+ mSeekTimeUs = 0;
+ mLatenessUs = 0;
+}
+
+void MediaSource::ReadOptions::setSeekTo(int64_t time_us) {
+ mOptions |= kSeekTo_Option;
+ mSeekTimeUs = time_us;
+}
+
+void MediaSource::ReadOptions::clearSeekTo() {
+ mOptions &= ~kSeekTo_Option;
+ mSeekTimeUs = 0;
+}
+
+bool MediaSource::ReadOptions::getSeekTo(int64_t *time_us) const {
+ *time_us = mSeekTimeUs;
+ return (mOptions & kSeekTo_Option) != 0;
+}
+
+void MediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+ mLatenessUs = lateness_us;
+}
+
+int64_t MediaSource::ReadOptions::getLateBy() const {
+ return mLatenessUs;
+}
+
+} // namespace android
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
new file mode 100644
index 0000000..6b067cb
--- /dev/null
+++ b/media/libstagefright/MetaData.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+MetaData::MetaData() {
+}
+
+MetaData::MetaData(const MetaData &from)
+ : RefBase(),
+ mItems(from.mItems) {
+}
+
+MetaData::~MetaData() {
+ clear();
+}
+
+void MetaData::clear() {
+ mItems.clear();
+}
+
+bool MetaData::remove(uint32_t key) {
+ ssize_t i = mItems.indexOfKey(key);
+
+ if (i < 0) {
+ return false;
+ }
+
+ mItems.removeItemsAt(i);
+
+ return true;
+}
+
+bool MetaData::setCString(uint32_t key, const char *value) {
+ return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
+}
+
+bool MetaData::setInt32(uint32_t key, int32_t value) {
+ return setData(key, TYPE_INT32, &value, sizeof(value));
+}
+
+bool MetaData::setFloat(uint32_t key, float value) {
+ return setData(key, TYPE_FLOAT, &value, sizeof(value));
+}
+
+bool MetaData::setPointer(uint32_t key, void *value) {
+ return setData(key, TYPE_POINTER, &value, sizeof(value));
+}
+
+bool MetaData::findCString(uint32_t key, const char **value) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
+ return false;
+ }
+
+ *value = (const char *)data;
+
+ return true;
+}
+
+bool MetaData::findInt32(uint32_t key, int32_t *value) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
+ return false;
+ }
+
+ CHECK_EQ(size, sizeof(*value));
+
+ *value = *(int32_t *)data;
+
+ return true;
+}
+
+bool MetaData::findFloat(uint32_t key, float *value) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
+ return false;
+ }
+
+ CHECK_EQ(size, sizeof(*value));
+
+ *value = *(float *)data;
+
+ return true;
+}
+
+bool MetaData::findPointer(uint32_t key, void **value) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
+ return false;
+ }
+
+ CHECK_EQ(size, sizeof(*value));
+
+ *value = *(void **)data;
+
+ return true;
+}
+
+bool MetaData::setData(
+ uint32_t key, uint32_t type, const void *data, size_t size) {
+ bool overwrote_existing = true;
+
+ ssize_t i = mItems.indexOfKey(key);
+ if (i < 0) {
+ typed_data item;
+ i = mItems.add(key, item);
+
+ overwrote_existing = false;
+ }
+
+ typed_data &item = mItems.editValueAt(i);
+
+ item.setData(type, data, size);
+
+ return overwrote_existing;
+}
+
+bool MetaData::findData(uint32_t key, uint32_t *type,
+ const void **data, size_t *size) const {
+ ssize_t i = mItems.indexOfKey(key);
+
+ if (i < 0) {
+ return false;
+ }
+
+ const typed_data &item = mItems.valueAt(i);
+
+ item.getData(type, data, size);
+
+ return true;
+}
+
+MetaData::typed_data::typed_data()
+ : mType(0),
+ mSize(0) {
+}
+
+MetaData::typed_data::~typed_data() {
+ clear();
+}
+
+MetaData::typed_data::typed_data(const typed_data &from)
+ : mType(from.mType),
+ mSize(0) {
+ allocateStorage(from.mSize);
+ memcpy(storage(), from.storage(), mSize);
+}
+
+MetaData::typed_data &MetaData::typed_data::operator=(
+ const MetaData::typed_data &from) {
+ if (this != &from) {
+ clear();
+ mType = from.mType;
+ allocateStorage(from.mSize);
+ memcpy(storage(), from.storage(), mSize);
+ }
+
+ return *this;
+}
+
+void MetaData::typed_data::clear() {
+ freeStorage();
+
+ mType = 0;
+}
+
+void MetaData::typed_data::setData(
+ uint32_t type, const void *data, size_t size) {
+ clear();
+
+ mType = type;
+ allocateStorage(size);
+ memcpy(storage(), data, size);
+}
+
+void MetaData::typed_data::getData(
+ uint32_t *type, const void **data, size_t *size) const {
+ *type = mType;
+ *size = mSize;
+ *data = storage();
+}
+
+void MetaData::typed_data::allocateStorage(size_t size) {
+ mSize = size;
+
+ if (usesReservoir()) {
+ return;
+ }
+
+ u.ext_data = malloc(mSize);
+}
+
+void MetaData::typed_data::freeStorage() {
+ if (!usesReservoir()) {
+ if (u.ext_data) {
+ free(u.ext_data);
+ }
+ }
+
+ mSize = 0;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/MmapSource.cpp b/media/libstagefright/MmapSource.cpp
new file mode 100644
index 0000000..47d95f9
--- /dev/null
+++ b/media/libstagefright/MmapSource.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MmapSource"
+#include <utils/Log.h>
+
+#include <sys/mman.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MmapSource.h>
+
+namespace android {
+
+MmapSource::MmapSource(const char *filename)
+ : mFd(open(filename, O_RDONLY)),
+ mBase(NULL),
+ mSize(0) {
+ LOGV("MmapSource '%s'", filename);
+ CHECK(mFd >= 0);
+
+ off_t size = lseek(mFd, 0, SEEK_END);
+ mSize = (size_t)size;
+
+ mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, 0);
+
+ if (mBase == (void *)-1) {
+ mBase = NULL;
+
+ close(mFd);
+ mFd = -1;
+ }
+}
+
+MmapSource::MmapSource(int fd, int64_t offset, int64_t length)
+ : mFd(fd),
+ mBase(NULL),
+ mSize(length) {
+ LOGV("MmapSource fd:%d offset:%lld length:%lld", fd, offset, length);
+ CHECK(fd >= 0);
+
+ mBase = mmap(0, mSize, PROT_READ, MAP_FILE | MAP_SHARED, mFd, offset);
+
+ if (mBase == (void *)-1) {
+ mBase = NULL;
+
+ close(mFd);
+ mFd = -1;
+ }
+
+}
+
+MmapSource::~MmapSource() {
+ if (mFd != -1) {
+ munmap(mBase, mSize);
+ mBase = NULL;
+ mSize = 0;
+
+ close(mFd);
+ mFd = -1;
+ }
+}
+
+status_t MmapSource::InitCheck() const {
+ return mFd == -1 ? NO_INIT : OK;
+}
+
+ssize_t MmapSource::read_at(off_t offset, void *data, size_t size) {
+ LOGV("read_at offset:%ld data:%p size:%d", offset, data, size);
+ CHECK(offset >= 0);
+
+ size_t avail = 0;
+ if (offset >= 0 && offset < (off_t)mSize) {
+ avail = mSize - offset;
+ }
+
+ if (size > avail) {
+ size = avail;
+ }
+
+ memcpy(data, (const uint8_t *)mBase + offset, size);
+
+ return (ssize_t)size;
+}
+
+status_t MmapSource::getSize(off_t *size) {
+ *size = mSize;
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
new file mode 100644
index 0000000..dba7a2a
--- /dev/null
+++ b/media/libstagefright/OMXClient.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "OMXClient"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/OMXClient.h>
+
+namespace android {
+
+OMXClient::OMXClient() {
+}
+
+status_t OMXClient::connect() {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+
+ CHECK(service.get() != NULL);
+
+ mOMX = service->createOMX();
+ CHECK(mOMX.get() != NULL);
+
+ return OK;
+}
+
+void OMXClient::disconnect() {
+}
+
+} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
new file mode 100644
index 0000000..3a065ae
--- /dev/null
+++ b/media/libstagefright/OMXCodec.cpp
@@ -0,0 +1,2171 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "OMXCodec"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+#include <binder/ProcessState.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/ESDS.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/Utils.h>
+#include <utils/Vector.h>
+
+#include <OMX_Audio.h>
+#include <OMX_Component.h>
+
+namespace android {
+
+struct CodecInfo {
+ const char *mime;
+ const char *codec;
+};
+
+static const CodecInfo kDecoderInfo[] = {
+ { "image/jpeg", "OMX.TI.JPEG.decode" },
+ { "audio/mpeg", "OMX.TI.MP3.decode" },
+ { "audio/mpeg", "OMX.PV.mp3dec" },
+ { "audio/3gpp", "OMX.TI.AMR.decode" },
+ { "audio/3gpp", "OMX.PV.amrdec" },
+ { "audio/mp4a-latm", "OMX.TI.AAC.decode" },
+ { "audio/mp4a-latm", "OMX.PV.aacdec" },
+ { "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
+ { "video/mp4v-es", "OMX.TI.Video.Decoder" },
+ { "video/mp4v-es", "OMX.PV.mpeg4dec" },
+ { "video/3gpp", "OMX.qcom.video.decoder.h263" },
+ { "video/3gpp", "OMX.TI.Video.Decoder" },
+ { "video/3gpp", "OMX.PV.h263dec" },
+ { "video/avc", "OMX.qcom.video.decoder.avc" },
+ { "video/avc", "OMX.TI.Video.Decoder" },
+ { "video/avc", "OMX.PV.avcdec" },
+};
+
+static const CodecInfo kEncoderInfo[] = {
+ { "audio/3gpp", "OMX.TI.AMR.encode" },
+ { "audio/3gpp", "OMX.PV.amrencnb" },
+ { "audio/mp4a-latm", "OMX.TI.AAC.encode" },
+ { "audio/mp4a-latm", "OMX.PV.aacenc" },
+ { "video/mp4v-es", "OMX.qcom.video.encoder.mpeg4" },
+ { "video/mp4v-es", "OMX.TI.Video.encoder" },
+ { "video/mp4v-es", "OMX.PV.mpeg4enc" },
+ { "video/3gpp", "OMX.qcom.video.encoder.h263" },
+ { "video/3gpp", "OMX.TI.Video.encoder" },
+ { "video/3gpp", "OMX.PV.h263enc" },
+ { "video/avc", "OMX.TI.Video.encoder" },
+ { "video/avc", "OMX.PV.avcenc" },
+};
+
+struct OMXCodecObserver : public BnOMXObserver {
+ OMXCodecObserver(const wp<OMXCodec> &target)
+ : mTarget(target) {
+ }
+
+ // from IOMXObserver
+ virtual void on_message(const omx_message &msg) {
+ sp<OMXCodec> codec = mTarget.promote();
+
+ if (codec.get() != NULL) {
+ codec->on_message(msg);
+ }
+ }
+
+protected:
+ virtual ~OMXCodecObserver() {}
+
+private:
+ wp<OMXCodec> mTarget;
+
+ OMXCodecObserver(const OMXCodecObserver &);
+ OMXCodecObserver &operator=(const OMXCodecObserver &);
+};
+
+static const char *GetCodec(const CodecInfo *info, size_t numInfos,
+ const char *mime, int index) {
+ CHECK(index >= 0);
+ for(size_t i = 0; i < numInfos; ++i) {
+ if (!strcasecmp(mime, info[i].mime)) {
+ if (index == 0) {
+ return info[i].codec;
+ }
+
+ --index;
+ }
+ }
+
+ return NULL;
+}
+
+enum {
+ kAVCProfileBaseline = 0x42,
+ kAVCProfileMain = 0x4d,
+ kAVCProfileExtended = 0x58,
+ kAVCProfileHigh = 0x64,
+ kAVCProfileHigh10 = 0x6e,
+ kAVCProfileHigh422 = 0x7a,
+ kAVCProfileHigh444 = 0xf4,
+ kAVCProfileCAVLC444Intra = 0x2c
+};
+
+static const char *AVCProfileToString(uint8_t profile) {
+ switch (profile) {
+ case kAVCProfileBaseline:
+ return "Baseline";
+ case kAVCProfileMain:
+ return "Main";
+ case kAVCProfileExtended:
+ return "Extended";
+ case kAVCProfileHigh:
+ return "High";
+ case kAVCProfileHigh10:
+ return "High 10";
+ case kAVCProfileHigh422:
+ return "High 422";
+ case kAVCProfileHigh444:
+ return "High 444";
+ case kAVCProfileCAVLC444Intra:
+ return "CAVLC 444 Intra";
+ default: return "Unknown";
+ }
+}
+
+// static
+sp<OMXCodec> OMXCodec::Create(
+ const sp<IOMX> &omx,
+ const sp<MetaData> &meta, bool createEncoder,
+ const sp<MediaSource> &source) {
+ const char *mime;
+ bool success = meta->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+
+ const char *componentName = NULL;
+ IOMX::node_id node = 0;
+ for (int index = 0;; ++index) {
+ if (createEncoder) {
+ componentName = GetCodec(
+ kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+ mime, index);
+ } else {
+ componentName = GetCodec(
+ kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+ mime, index);
+ }
+
+ if (!componentName) {
+ return NULL;
+ }
+
+ LOGV("Attempting to allocate OMX node '%s'", componentName);
+
+ status_t err = omx->allocate_node(componentName, &node);
+ if (err == OK) {
+ break;
+ }
+ }
+
+ uint32_t quirks = 0;
+ if (!strcmp(componentName, "OMX.PV.avcdec")) {
+ quirks |= kWantsNALFragments;
+ }
+ if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
+ quirks |= kNeedsFlushBeforeDisable;
+ }
+ if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
+ quirks |= kNeedsFlushBeforeDisable;
+ quirks |= kRequiresFlushCompleteEmulation;
+
+ // The following is currently necessary for proper shutdown
+ // behaviour, but NOT enabled by default in order to make the
+ // bug reproducible...
+ // quirks |= kRequiresFlushBeforeShutdown;
+ }
+ if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
+ quirks |= kRequiresLoadedToIdleAfterAllocation;
+ quirks |= kRequiresAllocateBufferOnInputPorts;
+ }
+
+ sp<OMXCodec> codec = new OMXCodec(
+ omx, node, quirks, createEncoder, mime, componentName,
+ source);
+
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (meta->findData(kKeyESDS, &type, &data, &size)) {
+ ESDS esds((const char *)data, size);
+ CHECK_EQ(esds.InitCheck(), OK);
+
+ const void *codec_specific_data;
+ size_t codec_specific_data_size;
+ esds.getCodecSpecificInfo(
+ &codec_specific_data, &codec_specific_data_size);
+
+ printf("found codec-specific data of size %d\n",
+ codec_specific_data_size);
+
+ codec->addCodecSpecificData(
+ codec_specific_data, codec_specific_data_size);
+ } else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
+ printf("found avcc of size %d\n", size);
+
+ // Parse the AVCDecoderConfigurationRecord
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ CHECK(size >= 7);
+ CHECK_EQ(ptr[0], 1); // configurationVersion == 1
+ uint8_t profile = ptr[1];
+ uint8_t level = ptr[3];
+
+ CHECK((ptr[4] >> 2) == 0x3f); // reserved
+
+ size_t lengthSize = 1 + (ptr[4] & 3);
+
+ // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
+ // violates it...
+ // CHECK((ptr[5] >> 5) == 7); // reserved
+
+ size_t numSeqParameterSets = ptr[5] & 31;
+
+ ptr += 6;
+ size -= 6;
+
+ for (size_t i = 0; i < numSeqParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
+
+ ptr += 2;
+ size -= 2;
+
+ CHECK(size >= length);
+
+ codec->addCodecSpecificData(ptr, length);
+
+ ptr += length;
+ size -= length;
+ }
+
+ CHECK(size >= 1);
+ size_t numPictureParameterSets = *ptr;
+ ++ptr;
+ --size;
+
+ for (size_t i = 0; i < numPictureParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
+
+ ptr += 2;
+ size -= 2;
+
+ CHECK(size >= length);
+
+ codec->addCodecSpecificData(ptr, length);
+
+ ptr += length;
+ size -= length;
+ }
+
+ LOGI("AVC profile = %d (%s), level = %d",
+ (int)profile, AVCProfileToString(profile), (int)level / 10);
+
+ if (!strcmp(componentName, "OMX.TI.Video.Decoder")
+ && (profile != kAVCProfileBaseline || level > 39)) {
+ // This stream exceeds the decoder's capabilities.
+
+ LOGE("Profile and/or level exceed the decoder's capabilities.");
+ return NULL;
+ }
+ }
+
+ if (!strcasecmp("audio/3gpp", mime)) {
+ codec->setAMRFormat();
+ }
+ if (!createEncoder && !strcasecmp("audio/mp4a-latm", mime)) {
+ codec->setAACFormat();
+ }
+ if (!strncasecmp(mime, "video/", 6)) {
+ int32_t width, height;
+ bool success = meta->findInt32(kKeyWidth, &width);
+ success = success && meta->findInt32(kKeyHeight, &height);
+ CHECK(success);
+
+ if (createEncoder) {
+ codec->setVideoInputFormat(mime, width, height);
+ } else {
+ codec->setVideoOutputFormat(mime, width, height);
+ }
+ }
+ if (!strcasecmp(mime, "image/jpeg")
+ && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
+ OMX_COLOR_FORMATTYPE format =
+ OMX_COLOR_Format32bitARGB8888;
+ // OMX_COLOR_FormatYUV420PackedPlanar;
+ // OMX_COLOR_FormatCbYCrY;
+ // OMX_COLOR_FormatYUV411Planar;
+
+ int32_t width, height;
+ bool success = meta->findInt32(kKeyWidth, &width);
+ success = success && meta->findInt32(kKeyHeight, &height);
+
+ int32_t compressedSize;
+ success = success && meta->findInt32(
+ kKeyCompressedSize, &compressedSize);
+
+ CHECK(success);
+ CHECK(compressedSize > 0);
+
+ codec->setImageOutputFormat(format, width, height);
+ codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
+ }
+
+ codec->initOutputFormat(meta);
+
+ return codec;
+}
+
+status_t OMXCodec::setVideoPortFormatType(
+ OMX_U32 portIndex,
+ OMX_VIDEO_CODINGTYPE compressionFormat,
+ OMX_COLOR_FORMATTYPE colorFormat) {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ format.nSize = sizeof(format);
+ format.nVersion.s.nVersionMajor = 1;
+ format.nVersion.s.nVersionMinor = 1;
+ format.nPortIndex = portIndex;
+ format.nIndex = 0;
+ bool found = false;
+
+ OMX_U32 index = 0;
+ for (;;) {
+ format.nIndex = index;
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+
+ if (err != OK) {
+ return err;
+ }
+
+ // The following assertion is violated by TI's video decoder.
+ // CHECK_EQ(format.nIndex, index);
+
+#if 1
+ LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
+ portIndex,
+ index, format.eCompressionFormat, format.eColorFormat);
+#endif
+
+ if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
+ if (portIndex == kPortIndexInput
+ && colorFormat == format.eColorFormat) {
+ // eCompressionFormat does not seem right.
+ found = true;
+ break;
+ }
+ if (portIndex == kPortIndexOutput
+ && compressionFormat == format.eCompressionFormat) {
+ // eColorFormat does not seem right.
+ found = true;
+ break;
+ }
+ }
+
+ if (format.eCompressionFormat == compressionFormat
+ && format.eColorFormat == colorFormat) {
+ found = true;
+ break;
+ }
+
+ ++index;
+ }
+
+ if (!found) {
+ return UNKNOWN_ERROR;
+ }
+
+ LOGI("found a match.");
+ status_t err = mOMX->set_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+
+ return err;
+}
+
+void OMXCodec::setVideoInputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height) {
+ LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
+
+ OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
+ if (!strcasecmp("video/avc", mime)) {
+ compressionFormat = OMX_VIDEO_CodingAVC;
+ } else if (!strcasecmp("video/mp4v-es", mime)) {
+ compressionFormat = OMX_VIDEO_CodingMPEG4;
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ compressionFormat = OMX_VIDEO_CodingH263;
+ } else {
+ LOGE("Not a supported video mime type: %s", mime);
+ CHECK(!"Should not be here. Not a supported video mime type.");
+ }
+
+ OMX_COLOR_FORMATTYPE colorFormat =
+ 0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;
+
+ if (!strncmp("OMX.qcom.video.encoder.", mComponentName, 23)) {
+ colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+ }
+
+ setVideoPortFormatType(
+ kPortIndexInput, OMX_VIDEO_CodingUnused,
+ colorFormat);
+
+ setVideoPortFormatType(
+ kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexOutput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ CHECK_EQ(err, OK);
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+
+ video_def->eCompressionFormat = compressionFormat;
+ video_def->eColorFormat = OMX_COLOR_FormatUnused;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
+ LOGI("setting nBufferSize = %ld", def.nBufferSize);
+
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+ video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
+ video_def->eColorFormat = colorFormat;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+}
+
+void OMXCodec::setVideoOutputFormat(
+ const char *mime, OMX_U32 width, OMX_U32 height) {
+ LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+
+ // Enabling this code appears to be the right thing(tm), but,...
+ // the TI decoder then loses the ability to output YUV420 and only outputs
+ // YCbYCr (16bit)
+
+#if 1
+ if (!strcmp("OMX.TI.Video.Decoder", mComponentName)) {
+ OMX_PARAM_COMPONENTROLETYPE role;
+ role.nSize = sizeof(role);
+ role.nVersion.s.nVersionMajor = 1;
+ role.nVersion.s.nVersionMinor = 1;
+
+ if (!strcasecmp("video/avc", mime)) {
+ strncpy((char *)role.cRole, "video_decoder.avc",
+ OMX_MAX_STRINGNAME_SIZE - 1);
+ } else if (!strcasecmp("video/mp4v-es", mime)) {
+ strncpy((char *)role.cRole, "video_decoder.mpeg4",
+ OMX_MAX_STRINGNAME_SIZE - 1);
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ strncpy((char *)role.cRole, "video_decoder.h263",
+ OMX_MAX_STRINGNAME_SIZE - 1);
+ }
+
+ role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+ status_t err = mOMX->set_parameter(
+ mNode, OMX_IndexParamStandardComponentRole,
+ &role, sizeof(role));
+ CHECK_EQ(err, OK);
+ }
+#endif
+
+ OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
+ if (!strcasecmp("video/avc", mime)) {
+ compressionFormat = OMX_VIDEO_CodingAVC;
+ } else if (!strcasecmp("video/mp4v-es", mime)) {
+ compressionFormat = OMX_VIDEO_CodingMPEG4;
+ } else if (!strcasecmp("video/3gpp", mime)) {
+ compressionFormat = OMX_VIDEO_CodingH263;
+ } else {
+ LOGE("Not a supported video mime type: %s", mime);
+ CHECK(!"Should not be here. Not a supported video mime type.");
+ }
+
+ setVideoPortFormatType(
+ kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
+
+#if 1
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+ format.nSize = sizeof(format);
+ format.nVersion.s.nVersionMajor = 1;
+ format.nVersion.s.nVersionMinor = 1;
+ format.nPortIndex = kPortIndexOutput;
+ format.nIndex = 0;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ CHECK_EQ(err, OK);
+ CHECK_EQ(format.eCompressionFormat, OMX_VIDEO_CodingUnused);
+
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+ || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+ || format.eColorFormat == OMX_COLOR_FormatCbYCrY
+ || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamVideoPortFormat,
+ &format, sizeof(format));
+ CHECK_EQ(err, OK);
+ }
+#endif
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ CHECK_EQ(err, OK);
+
+#if 1
+ // XXX Need a (much) better heuristic to compute input buffer sizes.
+ const size_t X = 64 * 1024;
+ if (def.nBufferSize < X) {
+ def.nBufferSize = X;
+ }
+#endif
+
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+
+ video_def->eColorFormat = OMX_COLOR_FormatUnused;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexOutput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+ CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+#if 0
+ def.nBufferSize =
+ (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420
+#endif
+
+ video_def->nFrameWidth = width;
+ video_def->nFrameHeight = height;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+}
+
+
+OMXCodec::OMXCodec(
+ const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
+ bool isEncoder,
+ const char *mime,
+ const char *componentName,
+ const sp<MediaSource> &source)
+ : mOMX(omx),
+ mNode(node),
+ mQuirks(quirks),
+ mIsEncoder(isEncoder),
+ mMIME(strdup(mime)),
+ mComponentName(strdup(componentName)),
+ mSource(source),
+ mCodecSpecificDataIndex(0),
+ mState(LOADED),
+ mInitialBufferSubmit(true),
+ mSignalledEOS(false),
+ mNoMoreOutputData(false),
+ mSeekTimeUs(-1) {
+ mPortStatus[kPortIndexInput] = ENABLED;
+ mPortStatus[kPortIndexOutput] = ENABLED;
+
+ mObserver = new OMXCodecObserver(this);
+ mOMX->observe_node(mNode, mObserver);
+}
+
+OMXCodec::~OMXCodec() {
+ CHECK(mState == LOADED || mState == ERROR);
+
+ status_t err = mOMX->observe_node(mNode, NULL);
+ CHECK_EQ(err, OK);
+
+ err = mOMX->free_node(mNode);
+ CHECK_EQ(err, OK);
+
+ mNode = NULL;
+ setState(DEAD);
+
+ clearCodecSpecificData();
+
+ free(mComponentName);
+ mComponentName = NULL;
+
+ free(mMIME);
+ mMIME = NULL;
+}
+
+status_t OMXCodec::init() {
+ // mLock is held.
+
+ CHECK_EQ(mState, LOADED);
+
+ status_t err;
+ if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
+ err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ CHECK_EQ(err, OK);
+
+ setState(LOADED_TO_IDLE);
+ }
+
+ err = allocateBuffers();
+ CHECK_EQ(err, OK);
+
+ if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
+ err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ CHECK_EQ(err, OK);
+
+ setState(LOADED_TO_IDLE);
+ }
+
+ while (mState != EXECUTING && mState != ERROR) {
+ mAsyncCompletion.wait(mLock);
+ }
+
+ return mState == ERROR ? UNKNOWN_ERROR : OK;
+}
+
+// static
+bool OMXCodec::isIntermediateState(State state) {
+ return state == LOADED_TO_IDLE
+ || state == IDLE_TO_EXECUTING
+ || state == EXECUTING_TO_IDLE
+ || state == IDLE_TO_LOADED
+ || state == RECONFIGURING;
+}
+
+status_t OMXCodec::allocateBuffers() {
+ status_t err = allocateBuffersOnPort(kPortIndexInput);
+
+ if (err != OK) {
+ return err;
+ }
+
+ return allocateBuffersOnPort(kPortIndexOutput);
+}
+
+status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nVersion.s.nRevision = 0;
+ def.nVersion.s.nStep = 0;
+ def.nPortIndex = portIndex;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ if (err != OK) {
+ return err;
+ }
+
+ size_t totalSize = def.nBufferCountActual * def.nBufferSize;
+ mDealer[portIndex] = new MemoryDealer(totalSize);
+
+ for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
+ sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
+ CHECK(mem.get() != NULL);
+
+ IOMX::buffer_id buffer;
+ if (portIndex == kPortIndexInput
+ && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
+ err = mOMX->allocate_buffer_with_backup(
+ mNode, portIndex, mem, &buffer);
+ } else if (portIndex == kPortIndexOutput
+ && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
+ err = mOMX->allocate_buffer(
+ mNode, portIndex, def.nBufferSize, &buffer);
+ } else {
+ err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
+ }
+
+ if (err != OK) {
+ LOGE("allocate_buffer_with_backup failed");
+ return err;
+ }
+
+ BufferInfo info;
+ info.mBuffer = buffer;
+ info.mOwnedByComponent = false;
+ info.mMem = mem;
+ info.mMediaBuffer = NULL;
+
+ if (portIndex == kPortIndexOutput) {
+ info.mMediaBuffer = new MediaBuffer(mem->pointer(), mem->size());
+ info.mMediaBuffer->setObserver(this);
+ }
+
+ mPortBuffers[portIndex].push(info);
+
+ LOGV("allocated buffer %p on %s port", buffer,
+ portIndex == kPortIndexInput ? "input" : "output");
+ }
+
+ dumpPortStatus(portIndex);
+
+ return OK;
+}
+
+void OMXCodec::on_message(const omx_message &msg) {
+ Mutex::Autolock autoLock(mLock);
+
+ switch (msg.type) {
+ case omx_message::EVENT:
+ {
+ onEvent(
+ msg.u.event_data.event, msg.u.event_data.data1,
+ msg.u.event_data.data2);
+
+ break;
+ }
+
+ case omx_message::EMPTY_BUFFER_DONE:
+ {
+ IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
+
+ LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
+
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+ size_t i = 0;
+ while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
+ ++i;
+ }
+
+ CHECK(i < buffers->size());
+ if (!(*buffers)[i].mOwnedByComponent) {
+ LOGW("We already own input buffer %p, yet received "
+ "an EMPTY_BUFFER_DONE.", buffer);
+ }
+
+ buffers->editItemAt(i).mOwnedByComponent = false;
+
+ if (mPortStatus[kPortIndexInput] == DISABLING) {
+ LOGV("Port is disabled, freeing buffer %p", buffer);
+
+ status_t err =
+ mOMX->free_buffer(mNode, kPortIndexInput, buffer);
+ CHECK_EQ(err, OK);
+
+ buffers->removeAt(i);
+ } else if (mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
+ CHECK_EQ(mPortStatus[kPortIndexInput], ENABLED);
+ drainInputBuffer(&buffers->editItemAt(i));
+ }
+
+ break;
+ }
+
+ case omx_message::FILL_BUFFER_DONE:
+ {
+ IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
+ OMX_U32 flags = msg.u.extended_buffer_data.flags;
+
+ LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
+ buffer,
+ msg.u.extended_buffer_data.range_length,
+ flags);
+
+ LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
+ msg.u.extended_buffer_data.timestamp,
+ msg.u.extended_buffer_data.timestamp / 1E6);
+
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+ size_t i = 0;
+ while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) {
+ ++i;
+ }
+
+ CHECK(i < buffers->size());
+ BufferInfo *info = &buffers->editItemAt(i);
+
+ if (!info->mOwnedByComponent) {
+ LOGW("We already own output buffer %p, yet received "
+ "a FILL_BUFFER_DONE.", buffer);
+ }
+
+ info->mOwnedByComponent = false;
+
+ if (mPortStatus[kPortIndexOutput] == DISABLING) {
+ LOGV("Port is disabled, freeing buffer %p", buffer);
+
+ status_t err =
+ mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
+ CHECK_EQ(err, OK);
+
+ buffers->removeAt(i);
+ } else if (mPortStatus[kPortIndexOutput] == ENABLED
+ && (flags & OMX_BUFFERFLAG_EOS)) {
+ LOGV("No more output data.");
+ mNoMoreOutputData = true;
+ mBufferFilled.signal();
+ } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
+ CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
+
+ MediaBuffer *buffer = info->mMediaBuffer;
+
+ buffer->set_range(
+ msg.u.extended_buffer_data.range_offset,
+ msg.u.extended_buffer_data.range_length);
+
+ buffer->meta_data()->clear();
+
+ buffer->meta_data()->setInt32(
+ kKeyTimeUnits,
+ (msg.u.extended_buffer_data.timestamp + 500) / 1000);
+
+ buffer->meta_data()->setInt32(
+ kKeyTimeScale, 1000);
+
+ if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
+ buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
+ }
+
+ buffer->meta_data()->setPointer(
+ kKeyPlatformPrivate,
+ msg.u.extended_buffer_data.platform_private);
+
+ buffer->meta_data()->setPointer(
+ kKeyBufferID,
+ msg.u.extended_buffer_data.buffer);
+
+ mFilledBuffers.push_back(i);
+ mBufferFilled.signal();
+ }
+
+ break;
+ }
+
+ default:
+ {
+ CHECK(!"should not be here.");
+ break;
+ }
+ }
+}
+
+void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
+ switch (event) {
+ case OMX_EventCmdComplete:
+ {
+ onCmdComplete((OMX_COMMANDTYPE)data1, data2);
+ break;
+ }
+
+ case OMX_EventError:
+ {
+ LOGE("ERROR(%ld, %ld)", data1, data2);
+
+ setState(ERROR);
+ break;
+ }
+
+ case OMX_EventPortSettingsChanged:
+ {
+ onPortSettingsChanged(data1);
+ break;
+ }
+
+ case OMX_EventBufferFlag:
+ {
+ LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
+
+ if (data1 == kPortIndexOutput) {
+ mNoMoreOutputData = true;
+ }
+ break;
+ }
+
+ default:
+ {
+ LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
+ break;
+ }
+ }
+}
+
+void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
+ switch (cmd) {
+ case OMX_CommandStateSet:
+ {
+ onStateChange((OMX_STATETYPE)data);
+ break;
+ }
+
+ case OMX_CommandPortDisable:
+ {
+ OMX_U32 portIndex = data;
+ LOGV("PORT_DISABLED(%ld)", portIndex);
+
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+ CHECK_EQ(mPortStatus[portIndex], DISABLING);
+ CHECK_EQ(mPortBuffers[portIndex].size(), 0);
+
+ mPortStatus[portIndex] = DISABLED;
+
+ if (mState == RECONFIGURING) {
+ CHECK_EQ(portIndex, kPortIndexOutput);
+
+ enablePortAsync(portIndex);
+
+ status_t err = allocateBuffersOnPort(portIndex);
+ CHECK_EQ(err, OK);
+ }
+ break;
+ }
+
+ case OMX_CommandPortEnable:
+ {
+ OMX_U32 portIndex = data;
+ LOGV("PORT_ENABLED(%ld)", portIndex);
+
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+ CHECK_EQ(mPortStatus[portIndex], ENABLING);
+
+ mPortStatus[portIndex] = ENABLED;
+
+ if (mState == RECONFIGURING) {
+ CHECK_EQ(portIndex, kPortIndexOutput);
+
+ setState(EXECUTING);
+
+ fillOutputBuffers();
+ }
+ break;
+ }
+
+ case OMX_CommandFlush:
+ {
+ OMX_U32 portIndex = data;
+
+ LOGV("FLUSH_DONE(%ld)", portIndex);
+
+ CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
+ mPortStatus[portIndex] = ENABLED;
+
+ CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
+ mPortBuffers[portIndex].size());
+
+ if (mState == RECONFIGURING) {
+ CHECK_EQ(portIndex, kPortIndexOutput);
+
+ disablePortAsync(portIndex);
+ } else if (mState == EXECUTING_TO_IDLE) {
+ if (mPortStatus[kPortIndexInput] == ENABLED
+ && mPortStatus[kPortIndexOutput] == ENABLED) {
+ LOGV("Finished flushing both ports, now completing "
+ "transition from EXECUTING to IDLE.");
+
+ mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
+ mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ CHECK_EQ(err, OK);
+ }
+ } else {
+ // We're flushing both ports in preparation for seeking.
+
+ if (mPortStatus[kPortIndexInput] == ENABLED
+ && mPortStatus[kPortIndexOutput] == ENABLED) {
+ LOGV("Finished flushing both ports, now continuing from"
+ " seek-time.");
+
+ drainInputBuffers();
+ fillOutputBuffers();
+ }
+ }
+
+ break;
+ }
+
+ default:
+ {
+ LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
+ break;
+ }
+ }
+}
+
+void OMXCodec::onStateChange(OMX_STATETYPE newState) {
+ switch (newState) {
+ case OMX_StateIdle:
+ {
+ LOGV("Now Idle.");
+ if (mState == LOADED_TO_IDLE) {
+ status_t err = mOMX->send_command(
+ mNode, OMX_CommandStateSet, OMX_StateExecuting);
+
+ CHECK_EQ(err, OK);
+
+ setState(IDLE_TO_EXECUTING);
+ } else {
+ CHECK_EQ(mState, EXECUTING_TO_IDLE);
+
+ CHECK_EQ(
+ countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
+ mPortBuffers[kPortIndexInput].size());
+
+ CHECK_EQ(
+ countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
+ mPortBuffers[kPortIndexOutput].size());
+
+ status_t err = mOMX->send_command(
+ mNode, OMX_CommandStateSet, OMX_StateLoaded);
+
+ CHECK_EQ(err, OK);
+
+ err = freeBuffersOnPort(kPortIndexInput);
+ CHECK_EQ(err, OK);
+
+ err = freeBuffersOnPort(kPortIndexOutput);
+ CHECK_EQ(err, OK);
+
+ mPortStatus[kPortIndexInput] = ENABLED;
+ mPortStatus[kPortIndexOutput] = ENABLED;
+
+ setState(IDLE_TO_LOADED);
+ }
+ break;
+ }
+
+ case OMX_StateExecuting:
+ {
+ CHECK_EQ(mState, IDLE_TO_EXECUTING);
+
+ LOGV("Now Executing.");
+
+ setState(EXECUTING);
+
+ // Buffers will be submitted to the component in the first
+ // call to OMXCodec::read as mInitialBufferSubmit is true at
+ // this point. This ensures that this on_message call returns,
+ // releases the lock and ::init can notice the state change and
+ // itself return.
+ break;
+ }
+
+ case OMX_StateLoaded:
+ {
+ CHECK_EQ(mState, IDLE_TO_LOADED);
+
+ LOGV("Now Loaded.");
+
+ setState(LOADED);
+ break;
+ }
+
+ default:
+ {
+ CHECK(!"should not be here.");
+ break;
+ }
+ }
+}
+
+// static
+size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) {
+ size_t n = 0;
+ for (size_t i = 0; i < buffers.size(); ++i) {
+ if (!buffers[i].mOwnedByComponent) {
+ ++n;
+ }
+ }
+
+ return n;
+}
+
+status_t OMXCodec::freeBuffersOnPort(
+ OMX_U32 portIndex, bool onlyThoseWeOwn) {
+ Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
+
+ status_t stickyErr = OK;
+
+ for (size_t i = buffers->size(); i-- > 0;) {
+ BufferInfo *info = &buffers->editItemAt(i);
+
+ if (onlyThoseWeOwn && info->mOwnedByComponent) {
+ continue;
+ }
+
+ CHECK_EQ(info->mOwnedByComponent, false);
+
+ status_t err =
+ mOMX->free_buffer(mNode, portIndex, info->mBuffer);
+
+ if (err != OK) {
+ stickyErr = err;
+ }
+
+ if (info->mMediaBuffer != NULL) {
+ info->mMediaBuffer->setObserver(NULL);
+
+ // Make sure nobody but us owns this buffer at this point.
+ CHECK_EQ(info->mMediaBuffer->refcount(), 0);
+
+ info->mMediaBuffer->release();
+ }
+
+ buffers->removeAt(i);
+ }
+
+ CHECK(onlyThoseWeOwn || buffers->isEmpty());
+
+ return stickyErr;
+}
+
+void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
+ LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
+
+ CHECK_EQ(mState, EXECUTING);
+ CHECK_EQ(portIndex, kPortIndexOutput);
+ setState(RECONFIGURING);
+
+ if (mQuirks & kNeedsFlushBeforeDisable) {
+ if (!flushPortAsync(portIndex)) {
+ onCmdComplete(OMX_CommandFlush, portIndex);
+ }
+ } else {
+ disablePortAsync(portIndex);
+ }
+}
+
+bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
+ CHECK(mState == EXECUTING || mState == RECONFIGURING
+ || mState == EXECUTING_TO_IDLE);
+
+ LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
+ portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
+ mPortBuffers[portIndex].size());
+
+ CHECK_EQ(mPortStatus[portIndex], ENABLED);
+ mPortStatus[portIndex] = SHUTTING_DOWN;
+
+ if ((mQuirks & kRequiresFlushCompleteEmulation)
+ && countBuffersWeOwn(mPortBuffers[portIndex])
+ == mPortBuffers[portIndex].size()) {
+ // No flush is necessary and this component fails to send a
+ // flush-complete event in this case.
+
+ return false;
+ }
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
+ CHECK_EQ(err, OK);
+
+ return true;
+}
+
+void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+
+ CHECK_EQ(mPortStatus[portIndex], ENABLED);
+ mPortStatus[portIndex] = DISABLING;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
+ CHECK_EQ(err, OK);
+
+ freeBuffersOnPort(portIndex, true);
+}
+
+void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+
+ CHECK_EQ(mPortStatus[portIndex], DISABLED);
+ mPortStatus[portIndex] = ENABLING;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
+ CHECK_EQ(err, OK);
+}
+
+void OMXCodec::fillOutputBuffers() {
+ CHECK_EQ(mState, EXECUTING);
+
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ fillOutputBuffer(&buffers->editItemAt(i));
+ }
+}
+
+void OMXCodec::drainInputBuffers() {
+ CHECK(mState == EXECUTING || mState == RECONFIGURING);
+
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ drainInputBuffer(&buffers->editItemAt(i));
+ }
+}
+
+void OMXCodec::drainInputBuffer(BufferInfo *info) {
+ CHECK_EQ(info->mOwnedByComponent, false);
+
+ if (mSignalledEOS) {
+ return;
+ }
+
+ if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
+ const CodecSpecificData *specific =
+ mCodecSpecificData[mCodecSpecificDataIndex];
+
+ size_t size = specific->mSize;
+
+ if (!strcasecmp("video/avc", mMIME)
+ && !(mQuirks & kWantsNALFragments)) {
+ static const uint8_t kNALStartCode[4] =
+ { 0x00, 0x00, 0x00, 0x01 };
+
+ CHECK(info->mMem->size() >= specific->mSize + 4);
+
+ size += 4;
+
+ memcpy(info->mMem->pointer(), kNALStartCode, 4);
+ memcpy((uint8_t *)info->mMem->pointer() + 4,
+ specific->mData, specific->mSize);
+ } else {
+ CHECK(info->mMem->size() >= specific->mSize);
+ memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
+ }
+
+ mOMX->empty_buffer(
+ mNode, info->mBuffer, 0, size,
+ OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
+ 0);
+
+ info->mOwnedByComponent = true;
+
+ ++mCodecSpecificDataIndex;
+ return;
+ }
+
+ // We're going to temporarily give up the lock while reading data
+ // from the source. A certain client unfortunately chose to have the
+ // thread supplying input data and reading output data be the same...
+
+ MediaBuffer *srcBuffer;
+ status_t err;
+ if (mSeekTimeUs >= 0) {
+ MediaSource::ReadOptions options;
+ options.setSeekTo(mSeekTimeUs);
+ mSeekTimeUs = -1;
+
+ mLock.unlock();
+ err = mSource->read(&srcBuffer, &options);
+ } else {
+ mLock.unlock();
+ err = mSource->read(&srcBuffer);
+ }
+ mLock.lock();
+
+ OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
+ OMX_TICKS timestamp = 0;
+ size_t srcLength = 0;
+
+ if (err != OK) {
+ LOGV("signalling end of input stream.");
+ flags |= OMX_BUFFERFLAG_EOS;
+
+ mSignalledEOS = true;
+ } else {
+ srcLength = srcBuffer->range_length();
+
+ if (info->mMem->size() < srcLength) {
+ LOGE("info->mMem->size() = %d, srcLength = %d",
+ info->mMem->size(), srcLength);
+ }
+ CHECK(info->mMem->size() >= srcLength);
+ memcpy(info->mMem->pointer(),
+ (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
+ srcLength);
+
+ int32_t units, scale;
+ if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
+ && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
+ timestamp = ((OMX_TICKS)units * 1000000) / scale;
+
+ LOGV("Calling empty_buffer on buffer %p (length %d)",
+ info->mBuffer, srcLength);
+ LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
+ timestamp, timestamp / 1E6);
+ }
+ }
+
+ mOMX->empty_buffer(
+ mNode, info->mBuffer, 0, srcLength,
+ flags, timestamp);
+
+ info->mOwnedByComponent = true;
+
+ if (srcBuffer != NULL) {
+ srcBuffer->release();
+ srcBuffer = NULL;
+ }
+}
+
+void OMXCodec::fillOutputBuffer(BufferInfo *info) {
+ CHECK_EQ(info->mOwnedByComponent, false);
+
+ if (mNoMoreOutputData) {
+ LOGV("There is no more output data available, not "
+ "calling fillOutputBuffer");
+ return;
+ }
+
+ LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
+ mOMX->fill_buffer(mNode, info->mBuffer);
+
+ info->mOwnedByComponent = true;
+}
+
+void OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) {
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ if ((*buffers)[i].mBuffer == buffer) {
+ drainInputBuffer(&buffers->editItemAt(i));
+ return;
+ }
+ }
+
+ CHECK(!"should not be here.");
+}
+
+void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) {
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ if ((*buffers)[i].mBuffer == buffer) {
+ fillOutputBuffer(&buffers->editItemAt(i));
+ return;
+ }
+ }
+
+ CHECK(!"should not be here.");
+}
+
+void OMXCodec::setState(State newState) {
+ mState = newState;
+ mAsyncCompletion.signal();
+
+ // This may cause some spurious wakeups but is necessary to
+ // unblock the reader if we enter ERROR state.
+ mBufferFilled.signal();
+}
+
+void OMXCodec::setAMRFormat() {
+ if (!mIsEncoder) {
+ OMX_AUDIO_PARAM_AMRTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ status_t err =
+ mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+
+ CHECK_EQ(err, OK);
+
+ def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+ def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
+
+ err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+ }
+
+ ////////////////////////
+
+ if (mIsEncoder) {
+ sp<MetaData> format = mSource->getFormat();
+ int32_t sampleRate;
+ int32_t numChannels;
+ CHECK(format->findInt32(kKeySampleRate, &sampleRate));
+ CHECK(format->findInt32(kKeyChannelCount, &numChannels));
+
+ OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
+ pcmParams.nSize = sizeof(pcmParams);
+ pcmParams.nVersion.s.nVersionMajor = 1;
+ pcmParams.nVersion.s.nVersionMinor = 1;
+ pcmParams.nPortIndex = kPortIndexInput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+
+ CHECK_EQ(err, OK);
+
+ pcmParams.nChannels = numChannels;
+ pcmParams.eNumData = OMX_NumericalDataSigned;
+ pcmParams.bInterleaved = OMX_TRUE;
+ pcmParams.nBitPerSample = 16;
+ pcmParams.nSamplingRate = sampleRate;
+ pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
+
+ if (numChannels == 1) {
+ pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+ } else {
+ CHECK_EQ(numChannels, 2);
+
+ pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+ }
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+
+ CHECK_EQ(err, OK);
+ }
+}
+
+void OMXCodec::setAACFormat() {
+ OMX_AUDIO_PARAM_AACPROFILETYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ status_t err =
+ mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ def.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+ err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+}
+
+void OMXCodec::setImageOutputFormat(
+ OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
+ LOGV("setImageOutputFormat(%ld, %ld)", width, height);
+
+#if 0
+ OMX_INDEXTYPE index;
+ status_t err = mOMX->get_extension_index(
+ mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index);
+ CHECK_EQ(err, OK);
+
+ err = mOMX->set_config(mNode, index, &format, sizeof(format));
+ CHECK_EQ(err, OK);
+#endif
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexOutput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ CHECK_EQ(def.eDomain, OMX_PortDomainImage);
+
+ OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+
+ CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
+ imageDef->eColorFormat = format;
+ imageDef->nFrameWidth = width;
+ imageDef->nFrameHeight = height;
+
+ switch (format) {
+ case OMX_COLOR_FormatYUV420PackedPlanar:
+ case OMX_COLOR_FormatYUV411Planar:
+ {
+ def.nBufferSize = (width * height * 3) / 2;
+ break;
+ }
+
+ case OMX_COLOR_FormatCbYCrY:
+ {
+ def.nBufferSize = width * height * 2;
+ break;
+ }
+
+ case OMX_COLOR_Format32bitARGB8888:
+ {
+ def.nBufferSize = width * height * 4;
+ break;
+ }
+
+ default:
+ CHECK(!"Should not be here. Unknown color format.");
+ break;
+ }
+
+ def.nBufferCountActual = def.nBufferCountMin;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+}
+
+void OMXCodec::setJPEGInputFormat(
+ OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexInput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ CHECK_EQ(def.eDomain, OMX_PortDomainImage);
+ OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+
+ CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingJPEG);
+ imageDef->nFrameWidth = width;
+ imageDef->nFrameHeight = height;
+
+ def.nBufferSize = compressedSize;
+ def.nBufferCountActual = def.nBufferCountMin;
+
+ err = mOMX->set_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+}
+
+void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
+ CodecSpecificData *specific =
+ (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
+
+ specific->mSize = size;
+ memcpy(specific->mData, data, size);
+
+ mCodecSpecificData.push(specific);
+}
+
+void OMXCodec::clearCodecSpecificData() {
+ for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
+ free(mCodecSpecificData.editItemAt(i));
+ }
+ mCodecSpecificData.clear();
+ mCodecSpecificDataIndex = 0;
+}
+
+status_t OMXCodec::start(MetaData *) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mState != LOADED) {
+ return UNKNOWN_ERROR;
+ }
+
+ sp<MetaData> params = new MetaData;
+ if (mQuirks & kWantsNALFragments) {
+ params->setInt32(kKeyWantsNALFragments, true);
+ }
+ status_t err = mSource->start(params.get());
+
+ if (err != OK) {
+ return err;
+ }
+
+ mCodecSpecificDataIndex = 0;
+ mInitialBufferSubmit = true;
+ mSignalledEOS = false;
+ mNoMoreOutputData = false;
+ mSeekTimeUs = -1;
+ mFilledBuffers.clear();
+
+ return init();
+}
+
+status_t OMXCodec::stop() {
+ LOGV("stop");
+
+ Mutex::Autolock autoLock(mLock);
+
+ while (isIntermediateState(mState)) {
+ mAsyncCompletion.wait(mLock);
+ }
+
+ switch (mState) {
+ case LOADED:
+ case ERROR:
+ break;
+
+ case EXECUTING:
+ {
+ setState(EXECUTING_TO_IDLE);
+
+ if (mQuirks & kRequiresFlushBeforeShutdown) {
+ LOGV("This component requires a flush before transitioning "
+ "from EXECUTING to IDLE...");
+
+ bool emulateInputFlushCompletion =
+ !flushPortAsync(kPortIndexInput);
+
+ bool emulateOutputFlushCompletion =
+ !flushPortAsync(kPortIndexOutput);
+
+ if (emulateInputFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexInput);
+ }
+
+ if (emulateOutputFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
+ }
+ } else {
+ mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
+ mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
+
+ status_t err =
+ mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ CHECK_EQ(err, OK);
+ }
+
+ while (mState != LOADED && mState != ERROR) {
+ mAsyncCompletion.wait(mLock);
+ }
+
+ break;
+ }
+
+ default:
+ {
+ CHECK(!"should not be here.");
+ break;
+ }
+ }
+
+ mSource->stop();
+
+ return OK;
+}
+
+sp<MetaData> OMXCodec::getFormat() {
+ return mOutputFormat;
+}
+
+status_t OMXCodec::read(
+ MediaBuffer **buffer, const ReadOptions *options) {
+ *buffer = NULL;
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (mState != EXECUTING && mState != RECONFIGURING) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (mInitialBufferSubmit) {
+ mInitialBufferSubmit = false;
+
+ drainInputBuffers();
+
+ if (mState == EXECUTING) {
+ // Otherwise mState == RECONFIGURING and this code will trigger
+ // after the output port is reenabled.
+ fillOutputBuffers();
+ }
+ }
+
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
+
+ mSignalledEOS = false;
+ mNoMoreOutputData = false;
+
+ CHECK(seekTimeUs >= 0);
+ mSeekTimeUs = seekTimeUs;
+
+ mFilledBuffers.clear();
+
+ CHECK_EQ(mState, EXECUTING);
+
+ bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
+ bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
+
+ if (emulateInputFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexInput);
+ }
+
+ if (emulateOutputFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
+ }
+ }
+
+ while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
+ mBufferFilled.wait(mLock);
+ }
+
+ if (mState == ERROR) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (mFilledBuffers.empty()) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ size_t index = *mFilledBuffers.begin();
+ mFilledBuffers.erase(mFilledBuffers.begin());
+
+ BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
+ info->mMediaBuffer->add_ref();
+ *buffer = info->mMediaBuffer;
+
+ return OK;
+}
+
+void OMXCodec::signalBufferReturned(MediaBuffer *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ BufferInfo *info = &buffers->editItemAt(i);
+
+ if (info->mMediaBuffer == buffer) {
+ CHECK_EQ(mPortStatus[kPortIndexOutput], ENABLED);
+ fillOutputBuffer(info);
+ return;
+ }
+ }
+
+ CHECK(!"should not be here.");
+}
+
+static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
+ static const char *kNames[] = {
+ "OMX_IMAGE_CodingUnused",
+ "OMX_IMAGE_CodingAutoDetect",
+ "OMX_IMAGE_CodingJPEG",
+ "OMX_IMAGE_CodingJPEG2K",
+ "OMX_IMAGE_CodingEXIF",
+ "OMX_IMAGE_CodingTIFF",
+ "OMX_IMAGE_CodingGIF",
+ "OMX_IMAGE_CodingPNG",
+ "OMX_IMAGE_CodingLZW",
+ "OMX_IMAGE_CodingBMP",
+ };
+
+ size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+ if (type < 0 || (size_t)type >= numNames) {
+ return "UNKNOWN";
+ } else {
+ return kNames[type];
+ }
+}
+
+static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
+ static const char *kNames[] = {
+ "OMX_COLOR_FormatUnused",
+ "OMX_COLOR_FormatMonochrome",
+ "OMX_COLOR_Format8bitRGB332",
+ "OMX_COLOR_Format12bitRGB444",
+ "OMX_COLOR_Format16bitARGB4444",
+ "OMX_COLOR_Format16bitARGB1555",
+ "OMX_COLOR_Format16bitRGB565",
+ "OMX_COLOR_Format16bitBGR565",
+ "OMX_COLOR_Format18bitRGB666",
+ "OMX_COLOR_Format18bitARGB1665",
+ "OMX_COLOR_Format19bitARGB1666",
+ "OMX_COLOR_Format24bitRGB888",
+ "OMX_COLOR_Format24bitBGR888",
+ "OMX_COLOR_Format24bitARGB1887",
+ "OMX_COLOR_Format25bitARGB1888",
+ "OMX_COLOR_Format32bitBGRA8888",
+ "OMX_COLOR_Format32bitARGB8888",
+ "OMX_COLOR_FormatYUV411Planar",
+ "OMX_COLOR_FormatYUV411PackedPlanar",
+ "OMX_COLOR_FormatYUV420Planar",
+ "OMX_COLOR_FormatYUV420PackedPlanar",
+ "OMX_COLOR_FormatYUV420SemiPlanar",
+ "OMX_COLOR_FormatYUV422Planar",
+ "OMX_COLOR_FormatYUV422PackedPlanar",
+ "OMX_COLOR_FormatYUV422SemiPlanar",
+ "OMX_COLOR_FormatYCbYCr",
+ "OMX_COLOR_FormatYCrYCb",
+ "OMX_COLOR_FormatCbYCrY",
+ "OMX_COLOR_FormatCrYCbY",
+ "OMX_COLOR_FormatYUV444Interleaved",
+ "OMX_COLOR_FormatRawBayer8bit",
+ "OMX_COLOR_FormatRawBayer10bit",
+ "OMX_COLOR_FormatRawBayer8bitcompressed",
+ "OMX_COLOR_FormatL2",
+ "OMX_COLOR_FormatL4",
+ "OMX_COLOR_FormatL8",
+ "OMX_COLOR_FormatL16",
+ "OMX_COLOR_FormatL24",
+ "OMX_COLOR_FormatL32",
+ "OMX_COLOR_FormatYUV420PackedSemiPlanar",
+ "OMX_COLOR_FormatYUV422PackedSemiPlanar",
+ "OMX_COLOR_Format18BitBGR666",
+ "OMX_COLOR_Format24BitARGB6666",
+ "OMX_COLOR_Format24BitABGR6666",
+ };
+
+ size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
+ return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
+ } else if (type < 0 || (size_t)type >= numNames) {
+ return "UNKNOWN";
+ } else {
+ return kNames[type];
+ }
+}
+
+static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
+ static const char *kNames[] = {
+ "OMX_VIDEO_CodingUnused",
+ "OMX_VIDEO_CodingAutoDetect",
+ "OMX_VIDEO_CodingMPEG2",
+ "OMX_VIDEO_CodingH263",
+ "OMX_VIDEO_CodingMPEG4",
+ "OMX_VIDEO_CodingWMV",
+ "OMX_VIDEO_CodingRV",
+ "OMX_VIDEO_CodingAVC",
+ "OMX_VIDEO_CodingMJPEG",
+ };
+
+ size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+ if (type < 0 || (size_t)type >= numNames) {
+ return "UNKNOWN";
+ } else {
+ return kNames[type];
+ }
+}
+
+static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
+ static const char *kNames[] = {
+ "OMX_AUDIO_CodingUnused",
+ "OMX_AUDIO_CodingAutoDetect",
+ "OMX_AUDIO_CodingPCM",
+ "OMX_AUDIO_CodingADPCM",
+ "OMX_AUDIO_CodingAMR",
+ "OMX_AUDIO_CodingGSMFR",
+ "OMX_AUDIO_CodingGSMEFR",
+ "OMX_AUDIO_CodingGSMHR",
+ "OMX_AUDIO_CodingPDCFR",
+ "OMX_AUDIO_CodingPDCEFR",
+ "OMX_AUDIO_CodingPDCHR",
+ "OMX_AUDIO_CodingTDMAFR",
+ "OMX_AUDIO_CodingTDMAEFR",
+ "OMX_AUDIO_CodingQCELP8",
+ "OMX_AUDIO_CodingQCELP13",
+ "OMX_AUDIO_CodingEVRC",
+ "OMX_AUDIO_CodingSMV",
+ "OMX_AUDIO_CodingG711",
+ "OMX_AUDIO_CodingG723",
+ "OMX_AUDIO_CodingG726",
+ "OMX_AUDIO_CodingG729",
+ "OMX_AUDIO_CodingAAC",
+ "OMX_AUDIO_CodingMP3",
+ "OMX_AUDIO_CodingSBC",
+ "OMX_AUDIO_CodingVORBIS",
+ "OMX_AUDIO_CodingWMA",
+ "OMX_AUDIO_CodingRA",
+ "OMX_AUDIO_CodingMIDI",
+ };
+
+ size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+ if (type < 0 || (size_t)type >= numNames) {
+ return "UNKNOWN";
+ } else {
+ return kNames[type];
+ }
+}
+
+static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
+ static const char *kNames[] = {
+ "OMX_AUDIO_PCMModeLinear",
+ "OMX_AUDIO_PCMModeALaw",
+ "OMX_AUDIO_PCMModeMULaw",
+ };
+
+ size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+ if (type < 0 || (size_t)type >= numNames) {
+ return "UNKNOWN";
+ } else {
+ return kNames[type];
+ }
+}
+
+
+void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = portIndex;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output");
+
+ CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput)
+ || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput));
+
+ printf(" nBufferCountActual = %ld\n", def.nBufferCountActual);
+ printf(" nBufferCountMin = %ld\n", def.nBufferCountMin);
+ printf(" nBufferSize = %ld\n", def.nBufferSize);
+
+ switch (def.eDomain) {
+ case OMX_PortDomainImage:
+ {
+ const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+
+ printf("\n");
+ printf(" // Image\n");
+ printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth);
+ printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight);
+ printf(" nStride = %ld\n", imageDef->nStride);
+
+ printf(" eCompressionFormat = %s\n",
+ imageCompressionFormatString(imageDef->eCompressionFormat));
+
+ printf(" eColorFormat = %s\n",
+ colorFormatString(imageDef->eColorFormat));
+
+ break;
+ }
+
+ case OMX_PortDomainVideo:
+ {
+ OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
+
+ printf("\n");
+ printf(" // Video\n");
+ printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth);
+ printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight);
+ printf(" nStride = %ld\n", videoDef->nStride);
+
+ printf(" eCompressionFormat = %s\n",
+ videoCompressionFormatString(videoDef->eCompressionFormat));
+
+ printf(" eColorFormat = %s\n",
+ colorFormatString(videoDef->eColorFormat));
+
+ break;
+ }
+
+ case OMX_PortDomainAudio:
+ {
+ OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
+
+ printf("\n");
+ printf(" // Audio\n");
+ printf(" eEncoding = %s\n",
+ audioCodingTypeString(audioDef->eEncoding));
+
+ if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
+ OMX_AUDIO_PARAM_PCMMODETYPE params;
+ params.nSize = sizeof(params);
+ params.nVersion.s.nVersionMajor = 1;
+ params.nVersion.s.nVersionMinor = 1;
+ params.nPortIndex = portIndex;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
+ CHECK_EQ(err, OK);
+
+ printf(" nSamplingRate = %ld\n", params.nSamplingRate);
+ printf(" nChannels = %ld\n", params.nChannels);
+ printf(" bInterleaved = %d\n", params.bInterleaved);
+ printf(" nBitPerSample = %ld\n", params.nBitPerSample);
+
+ printf(" eNumData = %s\n",
+ params.eNumData == OMX_NumericalDataSigned
+ ? "signed" : "unsigned");
+
+ printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
+ }
+
+ break;
+ }
+
+ default:
+ {
+ printf(" // Unknown\n");
+ break;
+ }
+ }
+
+ printf("}\n");
+}
+
+void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
+ mOutputFormat = new MetaData;
+ mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
+
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ def.nSize = sizeof(def);
+ def.nVersion.s.nVersionMajor = 1;
+ def.nVersion.s.nVersionMinor = 1;
+ def.nPortIndex = kPortIndexOutput;
+
+ status_t err = mOMX->get_parameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ CHECK_EQ(err, OK);
+
+ switch (def.eDomain) {
+ case OMX_PortDomainImage:
+ {
+ OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
+ CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
+
+ mOutputFormat->setCString(kKeyMIMEType, "image/raw");
+ mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
+ mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
+ mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
+ break;
+ }
+
+ case OMX_PortDomainAudio:
+ {
+ OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
+
+ CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM);
+
+ OMX_AUDIO_PARAM_PCMMODETYPE params;
+ params.nSize = sizeof(params);
+ params.nVersion.s.nVersionMajor = 1;
+ params.nVersion.s.nVersionMinor = 1;
+ params.nPortIndex = kPortIndexOutput;
+
+ err = mOMX->get_parameter(
+ mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
+ CHECK_EQ(err, OK);
+
+ CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
+ CHECK_EQ(params.nBitPerSample, 16);
+ CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
+
+ int32_t numChannels, sampleRate;
+ inputFormat->findInt32(kKeyChannelCount, &numChannels);
+ inputFormat->findInt32(kKeySampleRate, &sampleRate);
+
+ mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
+ mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+ mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+ break;
+ }
+
+ case OMX_PortDomainVideo:
+ {
+ OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+ if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
+ mOutputFormat->setCString(kKeyMIMEType, "video/raw");
+ } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
+ mOutputFormat->setCString(kKeyMIMEType, "video/mp4v-es");
+ } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
+ mOutputFormat->setCString(kKeyMIMEType, "video/3gpp");
+ } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
+ mOutputFormat->setCString(kKeyMIMEType, "video/avc");
+ } else {
+ CHECK(!"Unknown compression format.");
+ }
+
+ if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
+ // This component appears to be lying to me.
+ mOutputFormat->setInt32(
+ kKeyWidth, (video_def->nFrameWidth + 15) & -16);
+ mOutputFormat->setInt32(
+ kKeyHeight, (video_def->nFrameHeight + 15) & -16);
+ } else {
+ mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
+ mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
+ }
+
+ mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
+ break;
+ }
+
+ default:
+ {
+ CHECK(!"should not be here, neither audio nor video.");
+ break;
+ }
+ }
+}
+
+} // namespace android
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
new file mode 100644
index 0000000..8efa7c7
--- /dev/null
+++ b/media/libstagefright/SampleTable.cpp
@@ -0,0 +1,578 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SampleTable"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/SampleTable.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+static const uint32_t kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
+static const uint32_t kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
+static const uint32_t kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
+static const uint32_t kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
+
+SampleTable::SampleTable(const sp<DataSource> &source)
+ : mDataSource(source),
+ mChunkOffsetOffset(-1),
+ mChunkOffsetType(0),
+ mNumChunkOffsets(0),
+ mSampleToChunkOffset(-1),
+ mNumSampleToChunkOffsets(0),
+ mSampleSizeOffset(-1),
+ mSampleSizeFieldSize(0),
+ mDefaultSampleSize(0),
+ mNumSampleSizes(0),
+ mTimeToSampleCount(0),
+ mTimeToSample(NULL),
+ mSyncSampleOffset(-1),
+ mNumSyncSamples(0) {
+}
+
+SampleTable::~SampleTable() {
+ delete[] mTimeToSample;
+ mTimeToSample = NULL;
+}
+
+status_t SampleTable::setChunkOffsetParams(
+ uint32_t type, off_t data_offset, off_t data_size) {
+ if (mChunkOffsetOffset >= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
+
+ mChunkOffsetOffset = data_offset;
+ mChunkOffsetType = type;
+
+ if (data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t header[8];
+ if (mDataSource->read_at(
+ data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(header) != 0) {
+ // Expected version = 0, flags = 0.
+ return ERROR_MALFORMED;
+ }
+
+ mNumChunkOffsets = U32_AT(&header[4]);
+
+ if (mChunkOffsetType == kChunkOffsetType32) {
+ if (data_size < 8 + mNumChunkOffsets * 4) {
+ return ERROR_MALFORMED;
+ }
+ } else {
+ if (data_size < 8 + mNumChunkOffsets * 8) {
+ return ERROR_MALFORMED;
+ }
+ }
+
+ return OK;
+}
+
+status_t SampleTable::setSampleToChunkParams(
+ off_t data_offset, off_t data_size) {
+ if (mSampleToChunkOffset >= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ mSampleToChunkOffset = data_offset;
+
+ if (data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t header[8];
+ if (mDataSource->read_at(
+ data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(header) != 0) {
+ // Expected version = 0, flags = 0.
+ return ERROR_MALFORMED;
+ }
+
+ mNumSampleToChunkOffsets = U32_AT(&header[4]);
+
+ if (data_size < 8 + mNumSampleToChunkOffsets * 12) {
+ return ERROR_MALFORMED;
+ }
+
+ return OK;
+}
+
+status_t SampleTable::setSampleSizeParams(
+ uint32_t type, off_t data_offset, off_t data_size) {
+ if (mSampleSizeOffset >= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
+
+ mSampleSizeOffset = data_offset;
+
+ if (data_size < 12) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t header[12];
+ if (mDataSource->read_at(
+ data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(header) != 0) {
+ // Expected version = 0, flags = 0.
+ return ERROR_MALFORMED;
+ }
+
+ mDefaultSampleSize = U32_AT(&header[4]);
+ mNumSampleSizes = U32_AT(&header[8]);
+
+ if (type == kSampleSizeType32) {
+ mSampleSizeFieldSize = 32;
+
+ if (mDefaultSampleSize != 0) {
+ return OK;
+ }
+
+ if (data_size < 12 + mNumSampleSizes * 4) {
+ return ERROR_MALFORMED;
+ }
+ } else {
+ if ((mDefaultSampleSize & 0xffffff00) != 0) {
+ // The high 24 bits are reserved and must be 0.
+ return ERROR_MALFORMED;
+ }
+
+ mSampleSizeFieldSize = mDefaultSampleSize & 0xf;
+ mDefaultSampleSize = 0;
+
+ if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
+ && mSampleSizeFieldSize != 16) {
+ return ERROR_MALFORMED;
+ }
+
+ if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
+ return ERROR_MALFORMED;
+ }
+ }
+
+ return OK;
+}
+
+status_t SampleTable::setTimeToSampleParams(
+ off_t data_offset, off_t data_size) {
+ if (mTimeToSample != NULL || data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ uint8_t header[8];
+ if (mDataSource->read_at(
+ data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(header) != 0) {
+ // Expected version = 0, flags = 0.
+ return ERROR_MALFORMED;
+ }
+
+ mTimeToSampleCount = U32_AT(&header[4]);
+ mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
+
+ size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
+ if (mDataSource->read_at(
+ data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
+ return ERROR_IO;
+ }
+
+ for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
+ mTimeToSample[i] = ntohl(mTimeToSample[i]);
+ }
+
+ return OK;
+}
+
+status_t SampleTable::setSyncSampleParams(off_t data_offset, off_t data_size) {
+ if (mSyncSampleOffset >= 0 || data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ mSyncSampleOffset = data_offset;
+
+ uint8_t header[8];
+ if (mDataSource->read_at(
+ data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return ERROR_IO;
+ }
+
+ if (U32_AT(header) != 0) {
+ // Expected version = 0, flags = 0.
+ return ERROR_MALFORMED;
+ }
+
+ mNumSyncSamples = U32_AT(&header[4]);
+
+ if (mNumSyncSamples < 2) {
+ LOGW("Table of sync samples is empty or has only a single entry!");
+ }
+ return OK;
+}
+
+uint32_t SampleTable::countChunkOffsets() const {
+ return mNumChunkOffsets;
+}
+
+status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) {
+ *offset = 0;
+
+ if (mChunkOffsetOffset < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ if (chunk_index >= mNumChunkOffsets) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ if (mChunkOffsetType == kChunkOffsetType32) {
+ uint32_t offset32;
+
+ if (mDataSource->read_at(
+ mChunkOffsetOffset + 8 + 4 * chunk_index,
+ &offset32,
+ sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
+ return ERROR_IO;
+ }
+
+ *offset = ntohl(offset32);
+ } else {
+ CHECK_EQ(mChunkOffsetType, kChunkOffsetType64);
+
+ uint64_t offset64;
+ if (mDataSource->read_at(
+ mChunkOffsetOffset + 8 + 8 * chunk_index,
+ &offset64,
+ sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
+ return ERROR_IO;
+ }
+
+ *offset = ntoh64(offset64);
+ }
+
+ return OK;
+}
+
+status_t SampleTable::getChunkForSample(
+ uint32_t sample_index,
+ uint32_t *chunk_index,
+ uint32_t *chunk_relative_sample_index,
+ uint32_t *desc_index) {
+ *chunk_index = 0;
+ *chunk_relative_sample_index = 0;
+ *desc_index = 0;
+
+ if (mSampleToChunkOffset < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ if (sample_index >= countSamples()) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ uint32_t first_chunk = 0;
+ uint32_t samples_per_chunk = 0;
+ uint32_t chunk_desc_index = 0;
+
+ uint32_t index = 0;
+ while (index < mNumSampleToChunkOffsets) {
+ uint8_t buffer[12];
+ if (mDataSource->read_at(mSampleToChunkOffset + 8 + index * 12,
+ buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
+ return ERROR_IO;
+ }
+
+ uint32_t stop_chunk = U32_AT(buffer);
+ if (sample_index < (stop_chunk - first_chunk) * samples_per_chunk) {
+ break;
+ }
+
+ sample_index -= (stop_chunk - first_chunk) * samples_per_chunk;
+ first_chunk = stop_chunk;
+ samples_per_chunk = U32_AT(&buffer[4]);
+ chunk_desc_index = U32_AT(&buffer[8]);
+
+ ++index;
+ }
+
+ *chunk_index = sample_index / samples_per_chunk + first_chunk - 1;
+ *chunk_relative_sample_index = sample_index % samples_per_chunk;
+ *desc_index = chunk_desc_index;
+
+ return OK;
+}
+
+uint32_t SampleTable::countSamples() const {
+ return mNumSampleSizes;
+}
+
+status_t SampleTable::getSampleSize(
+ uint32_t sample_index, size_t *sample_size) {
+ *sample_size = 0;
+
+ if (mSampleSizeOffset < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ if (sample_index >= mNumSampleSizes) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ if (mDefaultSampleSize > 0) {
+ *sample_size = mDefaultSampleSize;
+ return OK;
+ }
+
+ switch (mSampleSizeFieldSize) {
+ case 32:
+ {
+ if (mDataSource->read_at(
+ mSampleSizeOffset + 12 + 4 * sample_index,
+ sample_size, sizeof(*sample_size)) < (ssize_t)sizeof(*sample_size)) {
+ return ERROR_IO;
+ }
+
+ *sample_size = ntohl(*sample_size);
+ break;
+ }
+
+ case 16:
+ {
+ uint16_t x;
+ if (mDataSource->read_at(
+ mSampleSizeOffset + 12 + 2 * sample_index,
+ &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+ return ERROR_IO;
+ }
+
+ *sample_size = ntohs(x);
+ break;
+ }
+
+ case 8:
+ {
+ uint8_t x;
+ if (mDataSource->read_at(
+ mSampleSizeOffset + 12 + sample_index,
+ &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+ return ERROR_IO;
+ }
+
+ *sample_size = x;
+ break;
+ }
+
+ default:
+ {
+ CHECK_EQ(mSampleSizeFieldSize, 4);
+
+ uint8_t x;
+ if (mDataSource->read_at(
+ mSampleSizeOffset + 12 + sample_index / 2,
+ &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+ return ERROR_IO;
+ }
+
+ *sample_size = (sample_index & 1) ? x & 0x0f : x >> 4;
+ break;
+ }
+ }
+
+ return OK;
+}
+
+status_t SampleTable::getSampleOffsetAndSize(
+ uint32_t sample_index, off_t *offset, size_t *size) {
+ Mutex::Autolock autoLock(mLock);
+
+ *offset = 0;
+ *size = 0;
+
+ uint32_t chunk_index;
+ uint32_t chunk_relative_sample_index;
+ uint32_t desc_index;
+ status_t err = getChunkForSample(
+ sample_index, &chunk_index, &chunk_relative_sample_index,
+ &desc_index);
+
+ if (err != OK) {
+ return err;
+ }
+
+ err = getChunkOffset(chunk_index, offset);
+
+ if (err != OK) {
+ return err;
+ }
+
+ for (uint32_t j = 0; j < chunk_relative_sample_index; ++j) {
+ size_t sample_size;
+ err = getSampleSize(sample_index - j - 1, &sample_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ *offset += sample_size;
+ }
+
+ err = getSampleSize(sample_index, size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ return OK;
+}
+
+status_t SampleTable::getMaxSampleSize(size_t *max_size) {
+ Mutex::Autolock autoLock(mLock);
+
+ *max_size = 0;
+
+ for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
+ size_t sample_size;
+ status_t err = getSampleSize(i, &sample_size);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (sample_size > *max_size) {
+ *max_size = sample_size;
+ }
+ }
+
+ return OK;
+}
+
+status_t SampleTable::getDecodingTime(uint32_t sample_index, uint32_t *time) {
+ // XXX FIXME idiotic (for the common use-case) O(n) algorithm below...
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (sample_index >= mNumSampleSizes) {
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ uint32_t cur_sample = 0;
+ *time = 0;
+ for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
+ uint32_t n = mTimeToSample[2 * i];
+ uint32_t delta = mTimeToSample[2 * i + 1];
+
+ if (sample_index < cur_sample + n) {
+ *time += delta * (sample_index - cur_sample);
+
+ return OK;
+ }
+
+ *time += delta * n;
+ cur_sample += n;
+ }
+
+ return ERROR_OUT_OF_RANGE;
+}
+
+status_t SampleTable::findClosestSample(
+ uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
+ Mutex::Autolock autoLock(mLock);
+
+ uint32_t cur_sample = 0;
+ uint32_t time = 0;
+ for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
+ uint32_t n = mTimeToSample[2 * i];
+ uint32_t delta = mTimeToSample[2 * i + 1];
+
+ if (req_time < time + n * delta) {
+ int j = (req_time - time) / delta;
+
+ *sample_index = cur_sample + j;
+
+ if (flags & kSyncSample_Flag) {
+ return findClosestSyncSample(*sample_index, sample_index);
+ }
+
+ return OK;
+ }
+
+ time += delta * n;
+ cur_sample += n;
+ }
+
+ return ERROR_OUT_OF_RANGE;
+}
+
+status_t SampleTable::findClosestSyncSample(
+ uint32_t start_sample_index, uint32_t *sample_index) {
+ *sample_index = 0;
+
+ if (mSyncSampleOffset < 0) {
+ // All samples are sync-samples.
+ *sample_index = start_sample_index;
+ return OK;
+ }
+
+ uint32_t x;
+ uint32_t left = 0;
+ uint32_t right = mNumSyncSamples;
+ while (left < right) {
+ uint32_t mid = (left + right) / 2;
+ if (mDataSource->read_at(
+ mSyncSampleOffset + 8 + (mid - 1) * 4, &x, 4) != 4) {
+ return ERROR_IO;
+ }
+
+ x = ntohl(x);
+
+ if (x < (start_sample_index + 1)) {
+ left = mid + 1;
+ } else if (x > (start_sample_index + 1)) {
+ right = mid;
+ } else {
+ break;
+ }
+ }
+
+ *sample_index = x - 1;
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
new file mode 100644
index 0000000..4375f38
--- /dev/null
+++ b/media/libstagefright/ShoutcastSource.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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 <stdlib.h>
+
+#include <media/stagefright/HTTPStream.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/ShoutcastSource.h>
+#include <media/stagefright/string.h>
+
+namespace android {
+
+ShoutcastSource::ShoutcastSource(HTTPStream *http)
+ : mHttp(http),
+ mMetaDataOffset(0),
+ mBytesUntilMetaData(0),
+ mGroup(NULL),
+ mStarted(false) {
+ string metaint;
+ if (mHttp->find_header_value("icy-metaint", &metaint)) {
+ char *end;
+ const char *start = metaint.c_str();
+ mMetaDataOffset = strtol(start, &end, 10);
+ CHECK(end > start && *end == '\0');
+ CHECK(mMetaDataOffset > 0);
+
+ mBytesUntilMetaData = mMetaDataOffset;
+ }
+}
+
+ShoutcastSource::~ShoutcastSource() {
+ if (mStarted) {
+ stop();
+ }
+
+ delete mHttp;
+ mHttp = NULL;
+}
+
+status_t ShoutcastSource::start(MetaData *) {
+ CHECK(!mStarted);
+
+ mGroup = new MediaBufferGroup;
+ mGroup->add_buffer(new MediaBuffer(4096)); // XXX
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t ShoutcastSource::stop() {
+ CHECK(mStarted);
+
+ delete mGroup;
+ mGroup = NULL;
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> ShoutcastSource::getFormat() {
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, "audio/mpeg");
+ meta->setInt32(kKeySampleRate, 44100);
+ meta->setInt32(kKeyChannelCount, 2); // XXX
+
+ return meta;
+}
+
+status_t ShoutcastSource::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ CHECK(mStarted);
+
+ *out = NULL;
+
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ MediaBuffer *buffer;
+ status_t err = mGroup->acquire_buffer(&buffer);
+ if (err != OK) {
+ return err;
+ }
+
+ *out = buffer;
+
+ size_t num_bytes = buffer->size();
+ if (mMetaDataOffset > 0 && num_bytes > mBytesUntilMetaData) {
+ num_bytes = mBytesUntilMetaData;
+ }
+
+ ssize_t n = mHttp->receive(buffer->data(), num_bytes);
+
+ if (n <= 0) {
+ return (status_t)n;
+ }
+
+ buffer->set_range(0, n);
+
+ mBytesUntilMetaData -= (size_t)n;
+
+ if (mBytesUntilMetaData == 0) {
+ unsigned char num_16_byte_blocks = 0;
+ n = mHttp->receive((char *)&num_16_byte_blocks, 1);
+ CHECK_EQ(n, 1);
+
+ char meta[255 * 16];
+ size_t meta_size = num_16_byte_blocks * 16;
+ size_t meta_length = 0;
+ while (meta_length < meta_size) {
+ n = mHttp->receive(&meta[meta_length], meta_size - meta_length);
+ if (n <= 0) {
+ return (status_t)n;
+ }
+
+ meta_length += (size_t) n;
+ }
+
+ while (meta_length > 0 && meta[meta_length - 1] == '\0') {
+ --meta_length;
+ }
+
+ if (meta_length > 0) {
+ // Technically we should probably attach this meta data to the
+ // next buffer. XXX
+ buffer->meta_data()->setData('shou', 'shou', meta, meta_length);
+ }
+
+ mBytesUntilMetaData = mMetaDataOffset;
+ }
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/TimeSource.cpp b/media/libstagefright/TimeSource.cpp
new file mode 100644
index 0000000..d987fbf
--- /dev/null
+++ b/media/libstagefright/TimeSource.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 <stddef.h>
+#include <sys/time.h>
+
+#include <media/stagefright/TimeSource.h>
+
+namespace android {
+
+SystemTimeSource::SystemTimeSource()
+ : mStartTimeUs(GetSystemTimeUs()) {
+}
+
+int64_t SystemTimeSource::getRealTimeUs() {
+ return GetSystemTimeUs() - mStartTimeUs;
+}
+
+// static
+int64_t SystemTimeSource::GetSystemTimeUs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
new file mode 100644
index 0000000..3d85f75
--- /dev/null
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+#undef __STRICT_ANSI__
+#define __STDINT_LIMITS
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
+#define LOG_TAG "TimedEventQueue"
+#include <utils/Log.h>
+
+#include <sys/time.h>
+
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/TimedEventQueue.h>
+
+namespace android {
+
+TimedEventQueue::TimedEventQueue()
+ : mRunning(false),
+ mStopped(false) {
+}
+
+TimedEventQueue::~TimedEventQueue() {
+ stop();
+}
+
+void TimedEventQueue::start() {
+ if (mRunning) {
+ return;
+ }
+
+ mStopped = false;
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_create(&mThread, &attr, ThreadWrapper, this);
+
+ pthread_attr_destroy(&attr);
+
+ mRunning = true;
+}
+
+void TimedEventQueue::stop(bool flush) {
+ if (!mRunning) {
+ return;
+ }
+
+ if (flush) {
+ postEventToBack(new StopEvent);
+ } else {
+ postTimedEvent(new StopEvent, INT64_MIN);
+ }
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+
+ mQueue.clear();
+
+ mRunning = false;
+}
+
+void TimedEventQueue::postEvent(const sp<Event> &event) {
+ // Reserve an earlier timeslot an INT64_MIN to be able to post
+ // the StopEvent to the absolute head of the queue.
+ postTimedEvent(event, INT64_MIN + 1);
+}
+
+void TimedEventQueue::postEventToBack(const sp<Event> &event) {
+ postTimedEvent(event, INT64_MAX);
+}
+
+void TimedEventQueue::postEventWithDelay(
+ const sp<Event> &event, int64_t delay_us) {
+ CHECK(delay_us >= 0);
+ postTimedEvent(event, getRealTimeUs() + delay_us);
+}
+
+void TimedEventQueue::postTimedEvent(
+ const sp<Event> &event, int64_t realtime_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ List<QueueItem>::iterator it = mQueue.begin();
+ while (it != mQueue.end() && realtime_us >= (*it).realtime_us) {
+ ++it;
+ }
+
+ QueueItem item;
+ item.event = event;
+ item.realtime_us = realtime_us;
+
+ if (it == mQueue.begin()) {
+ mQueueHeadChangedCondition.signal();
+ }
+
+ mQueue.insert(it, item);
+
+ mQueueNotEmptyCondition.signal();
+}
+
+bool TimedEventQueue::cancelEvent(const sp<Event> &event) {
+ Mutex::Autolock autoLock(mLock);
+
+ List<QueueItem>::iterator it = mQueue.begin();
+ while (it != mQueue.end() && (*it).event != event) {
+ ++it;
+ }
+
+ if (it == mQueue.end()) {
+ return false;
+ }
+
+ if (it == mQueue.begin()) {
+ mQueueHeadChangedCondition.signal();
+ }
+
+ mQueue.erase(it);
+
+ return true;
+}
+
+// static
+int64_t TimedEventQueue::getRealTimeUs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+// static
+void *TimedEventQueue::ThreadWrapper(void *me) {
+ static_cast<TimedEventQueue *>(me)->threadEntry();
+
+ return NULL;
+}
+
+void TimedEventQueue::threadEntry() {
+ for (;;) {
+ int64_t now_us;
+ sp<Event> event;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mStopped) {
+ break;
+ }
+
+ while (mQueue.empty()) {
+ mQueueNotEmptyCondition.wait(mLock);
+ }
+
+ List<QueueItem>::iterator it;
+ for (;;) {
+ it = mQueue.begin();
+
+ now_us = getRealTimeUs();
+ int64_t when_us = (*it).realtime_us;
+
+ int64_t delay_us;
+ if (when_us < 0 || when_us == INT64_MAX) {
+ delay_us = 0;
+ } else {
+ delay_us = when_us - now_us;
+ }
+
+ if (delay_us <= 0) {
+ break;
+ }
+
+ status_t err = mQueueHeadChangedCondition.waitRelative(
+ mLock, delay_us * 1000);
+
+ if (err == -ETIMEDOUT) {
+ now_us = getRealTimeUs();
+ break;
+ }
+ }
+
+ event = (*it).event;
+ mQueue.erase(it);
+ }
+
+ // Fire event with the lock NOT held.
+ event->fire(this, now_us);
+ }
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
new file mode 100644
index 0000000..2720f93
--- /dev/null
+++ b/media/libstagefright/Utils.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 <arpa/inet.h>
+
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+uint16_t U16_AT(const uint8_t *ptr) {
+ return ptr[0] << 8 | ptr[1];
+}
+
+uint32_t U32_AT(const uint8_t *ptr) {
+ return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+}
+
+uint64_t U64_AT(const uint8_t *ptr) {
+ return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4);
+}
+
+// XXX warning: these won't work on big-endian host.
+uint64_t ntoh64(uint64_t x) {
+ return ((uint64_t)ntohl(x & 0xffffffff) << 32) | ntohl(x >> 32);
+}
+
+uint64_t hton64(uint64_t x) {
+ return ((uint64_t)htonl(x & 0xffffffff) << 32) | htonl(x >> 32);
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
new file mode 100644
index 0000000..77e42be
--- /dev/null
+++ b/media/libstagefright/omx/Android.mk
@@ -0,0 +1,33 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# Set up the OpenCore variables.
+include external/opencore/Config.mk
+LOCAL_C_INCLUDES := $(PV_INCLUDES)
+LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY)
+
+LOCAL_C_INCLUDES += $(TOP)/hardware/ti/omap3/liboverlay
+
+LOCAL_SRC_FILES:= \
+ OMX.cpp \
+ QComHardwareRenderer.cpp \
+ SoftwareRenderer.cpp \
+ TIHardwareRenderer.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libmedia \
+ libutils \
+ libui \
+ libcutils \
+ libopencore_common
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+ LOCAL_LDLIBS += -lpthread
+endif
+
+LOCAL_PRELINK_MODULE:= false
+
+LOCAL_MODULE:= libstagefright_omx
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
new file mode 100644
index 0000000..1e59b52
--- /dev/null
+++ b/media/libstagefright/omx/OMX.cpp
@@ -0,0 +1,639 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "OMX"
+#include <utils/Log.h>
+
+#include <sys/socket.h>
+
+#include "OMX.h"
+#include "OMXRenderer.h"
+
+#include "pv_omxcore.h"
+
+#include <binder/IMemory.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/QComHardwareRenderer.h>
+#include <media/stagefright/SoftwareRenderer.h>
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <media/stagefright/VideoRenderer.h>
+
+#include <OMX_Component.h>
+
+namespace android {
+
+class NodeMeta {
+public:
+ NodeMeta(OMX *owner)
+ : mOwner(owner),
+ mHandle(NULL) {
+ }
+
+ OMX *owner() const {
+ return mOwner;
+ }
+
+ void setHandle(OMX_HANDLETYPE handle) {
+ CHECK_EQ(mHandle, NULL);
+ mHandle = handle;
+ }
+
+ OMX_HANDLETYPE handle() const {
+ return mHandle;
+ }
+
+ void setObserver(const sp<IOMXObserver> &observer) {
+ mObserver = observer;
+ }
+
+ sp<IOMXObserver> observer() {
+ return mObserver;
+ }
+
+private:
+ OMX *mOwner;
+ OMX_HANDLETYPE mHandle;
+ sp<IOMXObserver> mObserver;
+
+ NodeMeta(const NodeMeta &);
+ NodeMeta &operator=(const NodeMeta &);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct OMX::CallbackDispatcher : public RefBase {
+ CallbackDispatcher();
+
+ void post(const omx_message &msg);
+
+protected:
+ virtual ~CallbackDispatcher();
+
+private:
+ Mutex mLock;
+ bool mDone;
+ Condition mQueueChanged;
+ List<omx_message> mQueue;
+
+ pthread_t mThread;
+
+ void dispatch(const omx_message &msg);
+
+ static void *ThreadWrapper(void *me);
+ void threadEntry();
+
+ CallbackDispatcher(const CallbackDispatcher &);
+ CallbackDispatcher &operator=(const CallbackDispatcher &);
+};
+
+OMX::CallbackDispatcher::CallbackDispatcher()
+ : mDone(false) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_create(&mThread, &attr, ThreadWrapper, this);
+
+ pthread_attr_destroy(&attr);
+}
+
+OMX::CallbackDispatcher::~CallbackDispatcher() {
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ mDone = true;
+ mQueueChanged.signal();
+ }
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+}
+
+void OMX::CallbackDispatcher::post(const omx_message &msg) {
+ Mutex::Autolock autoLock(mLock);
+ mQueue.push_back(msg);
+ mQueueChanged.signal();
+}
+
+void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
+ NodeMeta *meta = static_cast<NodeMeta *>(msg.node);
+
+ sp<IOMXObserver> observer = meta->observer();
+ if (observer.get() != NULL) {
+ observer->on_message(msg);
+ }
+}
+
+// static
+void *OMX::CallbackDispatcher::ThreadWrapper(void *me) {
+ static_cast<CallbackDispatcher *>(me)->threadEntry();
+
+ return NULL;
+}
+
+void OMX::CallbackDispatcher::threadEntry() {
+ for (;;) {
+ omx_message msg;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ while (!mDone && mQueue.empty()) {
+ mQueueChanged.wait(mLock);
+ }
+
+ if (mDone) {
+ break;
+ }
+
+ msg = *mQueue.begin();
+ mQueue.erase(mQueue.begin());
+ }
+
+ dispatch(msg);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BufferMeta {
+public:
+ BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false)
+ : mOwner(owner),
+ mMem(mem),
+ mIsBackup(is_backup) {
+ }
+
+ BufferMeta(OMX *owner, size_t size)
+ : mOwner(owner),
+ mSize(size),
+ mIsBackup(false) {
+ }
+
+ void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
+ if (!mIsBackup) {
+ return;
+ }
+
+ memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
+ header->pBuffer + header->nOffset,
+ header->nFilledLen);
+ }
+
+ void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
+ if (!mIsBackup) {
+ return;
+ }
+
+ memcpy(header->pBuffer + header->nOffset,
+ (const OMX_U8 *)mMem->pointer() + header->nOffset,
+ header->nFilledLen);
+ }
+
+private:
+ OMX *mOwner;
+ sp<IMemory> mMem;
+ size_t mSize;
+ bool mIsBackup;
+
+ BufferMeta(const BufferMeta &);
+ BufferMeta &operator=(const BufferMeta &);
+};
+
+// static
+OMX_CALLBACKTYPE OMX::kCallbacks = {
+ &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
+};
+
+// static
+OMX_ERRORTYPE OMX::OnEvent(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1,
+ OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData) {
+ NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
+ return meta->owner()->OnEvent(meta, eEvent, nData1, nData2, pEventData);
+}
+
+// static
+OMX_ERRORTYPE OMX::OnEmptyBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
+ return meta->owner()->OnEmptyBufferDone(meta, pBuffer);
+}
+
+// static
+OMX_ERRORTYPE OMX::OnFillBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
+ return meta->owner()->OnFillBufferDone(meta, pBuffer);
+}
+
+OMX::OMX()
+ : mDispatcher(new CallbackDispatcher) {
+}
+
+status_t OMX::list_nodes(List<String8> *list) {
+ OMX_MasterInit(); // XXX Put this somewhere else.
+
+ list->clear();
+
+ OMX_U32 index = 0;
+ char componentName[256];
+ while (OMX_MasterComponentNameEnum(componentName, sizeof(componentName), index)
+ == OMX_ErrorNone) {
+ list->push_back(String8(componentName));
+
+ ++index;
+ }
+
+ return OK;
+}
+
+status_t OMX::allocate_node(const char *name, node_id *node) {
+ Mutex::Autolock autoLock(mLock);
+
+ *node = 0;
+
+ OMX_MasterInit(); // XXX Put this somewhere else.
+
+ NodeMeta *meta = new NodeMeta(this);
+
+ OMX_HANDLETYPE handle;
+ OMX_ERRORTYPE err = OMX_MasterGetHandle(
+ &handle, const_cast<char *>(name), meta, &kCallbacks);
+
+ if (err != OMX_ErrorNone) {
+ LOGE("FAILED to allocate omx component '%s'", name);
+
+ delete meta;
+ meta = NULL;
+
+ return UNKNOWN_ERROR;
+ }
+
+ meta->setHandle(handle);
+
+ *node = meta;
+
+ return OK;
+}
+
+status_t OMX::free_node(node_id node) {
+ Mutex::Autolock autoLock(mLock);
+
+ NodeMeta *meta = static_cast<NodeMeta *>(node);
+
+ OMX_ERRORTYPE err = OMX_MasterFreeHandle(meta->handle());
+
+ delete meta;
+ meta = NULL;
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::send_command(
+ node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
+ Mutex::Autolock autoLock(mLock);
+
+ NodeMeta *meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL);
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::get_parameter(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ NodeMeta *meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err = OMX_GetParameter(meta->handle(), index, params);
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::set_parameter(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ NodeMeta *meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_SetParameter(meta->handle(), index, const_cast<void *>(params));
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::get_config(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ NodeMeta *meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err = OMX_GetConfig(meta->handle(), index, params);
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::set_config(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ NodeMeta *meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_SetConfig(meta->handle(), index, const_cast<void *>(params));
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+status_t OMX::use_buffer(
+ node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+ buffer_id *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ BufferMeta *buffer_meta = new BufferMeta(this, params);
+
+ OMX_BUFFERHEADERTYPE *header;
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_UseBuffer(node_meta->handle(), &header, port_index, buffer_meta,
+ params->size(), static_cast<OMX_U8 *>(params->pointer()));
+
+ if (err != OMX_ErrorNone) {
+ LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
+
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ *buffer = 0;
+ return UNKNOWN_ERROR;
+ }
+
+ *buffer = header;
+
+ return OK;
+}
+
+status_t OMX::allocate_buffer(
+ node_id node, OMX_U32 port_index, size_t size,
+ buffer_id *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ BufferMeta *buffer_meta = new BufferMeta(this, size);
+
+ OMX_BUFFERHEADERTYPE *header;
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_AllocateBuffer(node_meta->handle(), &header, port_index,
+ buffer_meta, size);
+
+ if (err != OMX_ErrorNone) {
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ *buffer = 0;
+ return UNKNOWN_ERROR;
+ }
+
+ *buffer = header;
+
+ return OK;
+}
+
+status_t OMX::allocate_buffer_with_backup(
+ node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+ buffer_id *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ BufferMeta *buffer_meta = new BufferMeta(this, params, true);
+
+ OMX_BUFFERHEADERTYPE *header;
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_AllocateBuffer(
+ node_meta->handle(), &header, port_index, buffer_meta,
+ params->size());
+
+ if (err != OMX_ErrorNone) {
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ *buffer = 0;
+ return UNKNOWN_ERROR;
+ }
+
+ *buffer = header;
+
+ return OK;
+}
+
+status_t OMX::free_buffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+ BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+ OMX_ERRORTYPE err =
+ OMX_FreeBuffer(node_meta->handle(), port_index, header);
+
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+}
+
+OMX_ERRORTYPE OMX::OnEvent(
+ NodeMeta *meta,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1,
+ OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData) {
+ LOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
+
+ omx_message msg;
+ msg.type = omx_message::EVENT;
+ msg.node = meta;
+ msg.u.event_data.event = eEvent;
+ msg.u.event_data.data1 = nData1;
+ msg.u.event_data.data2 = nData2;
+
+ mDispatcher->post(msg);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE OMX::OnEmptyBufferDone(
+ NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+ LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
+
+ omx_message msg;
+ msg.type = omx_message::EMPTY_BUFFER_DONE;
+ msg.node = meta;
+ msg.u.buffer_data.buffer = pBuffer;
+
+ mDispatcher->post(msg);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE OMX::OnFillBufferDone(
+ NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+ LOGV("OnFillBufferDone buffer=%p", pBuffer);
+ BufferMeta *buffer_meta = static_cast<BufferMeta *>(pBuffer->pAppPrivate);
+ buffer_meta->CopyFromOMX(pBuffer);
+
+ omx_message msg;
+ msg.type = omx_message::FILL_BUFFER_DONE;
+ msg.node = meta;
+ msg.u.extended_buffer_data.buffer = pBuffer;
+ msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
+ msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
+ msg.u.extended_buffer_data.flags = pBuffer->nFlags;
+ msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
+ msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;
+
+ mDispatcher->post(msg);
+
+ return OMX_ErrorNone;
+}
+
+status_t OMX::observe_node(
+ node_id node, const sp<IOMXObserver> &observer) {
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+ node_meta->setObserver(observer);
+
+ return OK;
+}
+
+void OMX::fill_buffer(node_id node, buffer_id buffer) {
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+ header->nFilledLen = 0;
+ header->nOffset = 0;
+ header->nFlags = 0;
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+ OMX_ERRORTYPE err =
+ OMX_FillThisBuffer(node_meta->handle(), header);
+ CHECK_EQ(err, OMX_ErrorNone);
+}
+
+void OMX::empty_buffer(
+ node_id node,
+ buffer_id buffer,
+ OMX_U32 range_offset, OMX_U32 range_length,
+ OMX_U32 flags, OMX_TICKS timestamp) {
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+ header->nFilledLen = range_length;
+ header->nOffset = range_offset;
+ header->nFlags = flags;
+ header->nTimeStamp = timestamp;
+
+ BufferMeta *buffer_meta =
+ static_cast<BufferMeta *>(header->pAppPrivate);
+ buffer_meta->CopyToOMX(header);
+
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+ OMX_ERRORTYPE err =
+ OMX_EmptyThisBuffer(node_meta->handle(), header);
+ CHECK_EQ(err, OMX_ErrorNone);
+}
+
+status_t OMX::get_extension_index(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index) {
+ NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+
+ OMX_ERRORTYPE err =
+ OMX_GetExtensionIndex(
+ node_meta->handle(),
+ const_cast<char *>(parameter_name), index);
+
+ return err == OMX_ErrorNone ? OK : UNKNOWN_ERROR;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+sp<IOMXRenderer> OMX::createRenderer(
+ const sp<ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight) {
+ VideoRenderer *impl = NULL;
+
+ static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+ && !strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
+ LOGW("Using QComHardwareRenderer.");
+ impl =
+ new QComHardwareRenderer(
+ surface,
+ displayWidth, displayHeight,
+ encodedWidth, encodedHeight);
+ } else if (colorFormat == OMX_COLOR_FormatCbYCrY
+ && !strcmp(componentName, "OMX.TI.Video.Decoder")) {
+ LOGW("Using TIHardwareRenderer.");
+ impl =
+ new TIHardwareRenderer(
+ surface,
+ displayWidth, displayHeight,
+ encodedWidth, encodedHeight);
+ } else {
+ LOGW("Using software renderer.");
+ impl = new SoftwareRenderer(
+ surface,
+ displayWidth, displayHeight,
+ encodedWidth, encodedHeight);
+ }
+
+ return new OMXRenderer(impl);
+}
+
+OMXRenderer::OMXRenderer(VideoRenderer *impl)
+ : mImpl(impl) {
+}
+
+OMXRenderer::~OMXRenderer() {
+ delete mImpl;
+ mImpl = NULL;
+}
+
+void OMXRenderer::render(IOMX::buffer_id buffer) {
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+
+ mImpl->render(
+ header->pBuffer + header->nOffset,
+ header->nFilledLen,
+ header->pPlatformPrivate);
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/omx/OMX.h b/media/libstagefright/omx/OMX.h
new file mode 100644
index 0000000..6325f79
--- /dev/null
+++ b/media/libstagefright/omx/OMX.h
@@ -0,0 +1,138 @@
+/*
+ * 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_OMX_H_
+#define ANDROID_OMX_H_
+
+#include <media/IOMX.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class NodeMeta;
+
+class OMX : public BnOMX {
+public:
+ OMX();
+
+ virtual status_t list_nodes(List<String8> *list);
+
+ virtual status_t allocate_node(const char *name, node_id *node);
+ virtual status_t free_node(node_id node);
+
+ virtual status_t send_command(
+ node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
+
+ virtual status_t get_parameter(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size);
+
+ virtual status_t set_parameter(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size);
+
+ virtual status_t get_config(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size);
+
+ virtual status_t set_config(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size);
+
+ virtual status_t use_buffer(
+ node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+ buffer_id *buffer);
+
+ virtual status_t allocate_buffer(
+ node_id node, OMX_U32 port_index, size_t size,
+ buffer_id *buffer);
+
+ virtual status_t allocate_buffer_with_backup(
+ node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+ buffer_id *buffer);
+
+ virtual status_t free_buffer(
+ node_id node, OMX_U32 port_index, buffer_id buffer);
+
+ virtual status_t observe_node(
+ node_id node, const sp<IOMXObserver> &observer);
+
+ virtual void fill_buffer(node_id node, buffer_id buffer);
+
+ virtual void empty_buffer(
+ node_id node,
+ buffer_id buffer,
+ OMX_U32 range_offset, OMX_U32 range_length,
+ OMX_U32 flags, OMX_TICKS timestamp);
+
+ virtual status_t get_extension_index(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index);
+
+ virtual sp<IOMXRenderer> createRenderer(
+ const sp<ISurface> &surface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight);
+
+private:
+ static OMX_CALLBACKTYPE kCallbacks;
+
+ Mutex mLock;
+
+ struct CallbackDispatcher;
+ sp<CallbackDispatcher> mDispatcher;
+
+ static OMX_ERRORTYPE OnEvent(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1,
+ OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+
+ static OMX_ERRORTYPE OnEmptyBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+ static OMX_ERRORTYPE OnFillBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+ OMX_ERRORTYPE OnEvent(
+ NodeMeta *meta,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1,
+ OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+
+ OMX_ERRORTYPE OnEmptyBufferDone(
+ NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+ OMX_ERRORTYPE OnFillBufferDone(
+ NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+ OMX(const OMX &);
+ OMX &operator=(const OMX &);
+};
+
+} // namespace android
+
+#endif // ANDROID_OMX_H_
diff --git a/media/libstagefright/omx/OMXRenderer.h b/media/libstagefright/omx/OMXRenderer.h
new file mode 100644
index 0000000..4d194ce
--- /dev/null
+++ b/media/libstagefright/omx/OMXRenderer.h
@@ -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.
+ */
+
+#ifndef OMX_RENDERER_H_
+
+#define OMX_RENDERER_H_
+
+#include <media/IOMX.h>
+
+namespace android {
+
+class VideoRenderer;
+
+class OMXRenderer : public BnOMXRenderer {
+public:
+ // Assumes ownership of "impl".
+ OMXRenderer(VideoRenderer *impl);
+ virtual ~OMXRenderer();
+
+ virtual void render(IOMX::buffer_id buffer);
+
+private:
+ VideoRenderer *mImpl;
+
+ OMXRenderer(const OMXRenderer &);
+ OMXRenderer &operator=(const OMXRenderer &);
+};
+
+} // namespace android
+
+#endif // OMX_RENDERER_H_
diff --git a/media/libstagefright/omx/QComHardwareRenderer.cpp b/media/libstagefright/omx/QComHardwareRenderer.cpp
new file mode 100644
index 0000000..e9930be
--- /dev/null
+++ b/media/libstagefright/omx/QComHardwareRenderer.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 <binder/MemoryHeapBase.h>
+#include <binder/MemoryHeapPmem.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/QComHardwareRenderer.h>
+#include <ui/ISurface.h>
+
+namespace android {
+
+////////////////////////////////////////////////////////////////////////////////
+
+typedef struct PLATFORM_PRIVATE_ENTRY
+{
+ /* Entry type */
+ uint32_t type;
+
+ /* Pointer to platform specific entry */
+ void *entry;
+
+} PLATFORM_PRIVATE_ENTRY;
+
+typedef struct PLATFORM_PRIVATE_LIST
+{
+ /* Number of entries */
+ uint32_t nEntries;
+
+ /* Pointer to array of platform specific entries *
+ * Contiguous block of PLATFORM_PRIVATE_ENTRY elements */
+ PLATFORM_PRIVATE_ENTRY *entryList;
+
+} PLATFORM_PRIVATE_LIST;
+
+// data structures for tunneling buffers
+typedef struct PLATFORM_PRIVATE_PMEM_INFO
+{
+ /* pmem file descriptor */
+ uint32_t pmem_fd;
+ uint32_t offset;
+
+} PLATFORM_PRIVATE_PMEM_INFO;
+
+#define PLATFORM_PRIVATE_PMEM 1
+
+QComHardwareRenderer::QComHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight)
+ : mISurface(surface),
+ mDisplayWidth(displayWidth),
+ mDisplayHeight(displayHeight),
+ mDecodedWidth(decodedWidth),
+ mDecodedHeight(decodedHeight),
+ mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2) {
+ CHECK(mISurface.get() != NULL);
+ CHECK(mDecodedWidth > 0);
+ CHECK(mDecodedHeight > 0);
+}
+
+QComHardwareRenderer::~QComHardwareRenderer() {
+ mISurface->unregisterBuffers();
+}
+
+void QComHardwareRenderer::render(
+ const void *data, size_t size, void *platformPrivate) {
+ size_t offset;
+ if (!getOffset(platformPrivate, &offset)) {
+ return;
+ }
+
+ mISurface->postBuffer(offset);
+}
+
+bool QComHardwareRenderer::getOffset(void *platformPrivate, size_t *offset) {
+ *offset = 0;
+
+ PLATFORM_PRIVATE_LIST *list = (PLATFORM_PRIVATE_LIST *)platformPrivate;
+ for (uint32_t i = 0; i < list->nEntries; ++i) {
+ if (list->entryList[i].type != PLATFORM_PRIVATE_PMEM) {
+ continue;
+ }
+
+ PLATFORM_PRIVATE_PMEM_INFO *info =
+ (PLATFORM_PRIVATE_PMEM_INFO *)list->entryList[i].entry;
+
+ if (info != NULL) {
+ if (mMemoryHeap.get() == NULL) {
+ publishBuffers(info->pmem_fd);
+ }
+
+ if (mMemoryHeap.get() == NULL) {
+ return false;
+ }
+
+ *offset = info->offset;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void QComHardwareRenderer::publishBuffers(uint32_t pmem_fd) {
+ sp<MemoryHeapBase> master =
+ reinterpret_cast<MemoryHeapBase *>(pmem_fd);
+
+ master->setDevice("/dev/pmem");
+
+ mMemoryHeap = new MemoryHeapPmem(master, 0);
+ mMemoryHeap->slap();
+
+ ISurface::BufferHeap bufferHeap(
+ mDisplayWidth, mDisplayHeight,
+ mDecodedWidth, mDecodedHeight,
+ PIXEL_FORMAT_YCbCr_420_SP,
+ mMemoryHeap);
+
+ status_t err = mISurface->registerBuffers(bufferHeap);
+ CHECK_EQ(err, OK);
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
new file mode 100644
index 0000000..da97d55
--- /dev/null
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SoftwareRenderer"
+#include <utils/Log.h>
+
+#include <binder/MemoryHeapBase.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/SoftwareRenderer.h>
+#include <ui/ISurface.h>
+
+namespace android {
+
+#define QCOM_YUV 0
+
+SoftwareRenderer::SoftwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight)
+ : mISurface(surface),
+ mDisplayWidth(displayWidth),
+ mDisplayHeight(displayHeight),
+ mDecodedWidth(decodedWidth),
+ mDecodedHeight(decodedHeight),
+ mFrameSize(mDecodedWidth * mDecodedHeight * 2), // RGB565
+ mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)),
+ mIndex(0) {
+ CHECK(mISurface.get() != NULL);
+ CHECK(mDecodedWidth > 0);
+ CHECK(mDecodedHeight > 0);
+ CHECK(mMemoryHeap->heapID() >= 0);
+
+ ISurface::BufferHeap bufferHeap(
+ mDisplayWidth, mDisplayHeight,
+ mDecodedWidth, mDecodedHeight,
+ PIXEL_FORMAT_RGB_565,
+ mMemoryHeap);
+
+ status_t err = mISurface->registerBuffers(bufferHeap);
+ CHECK_EQ(err, OK);
+}
+
+SoftwareRenderer::~SoftwareRenderer() {
+ mISurface->unregisterBuffers();
+}
+
+void SoftwareRenderer::render(
+ const void *data, size_t size, void *platformPrivate) {
+ if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
+ LOGE("size is %d, expected %d",
+ size, (mDecodedHeight * mDecodedWidth * 3) / 2);
+ }
+ CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
+
+ static const signed kClipMin = -278;
+ static const signed kClipMax = 535;
+ static uint8_t kClip[kClipMax - kClipMin + 1];
+ static uint8_t *kAdjustedClip = &kClip[-kClipMin];
+
+ static bool clipInitialized = false;
+
+ if (!clipInitialized) {
+ for (signed i = kClipMin; i <= kClipMax; ++i) {
+ kClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
+ }
+ clipInitialized = true;
+ }
+
+ size_t offset = mIndex * mFrameSize;
+
+ void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
+
+ uint32_t *dst_ptr = (uint32_t *)dst;
+
+ const uint8_t *src_y = (const uint8_t *)data;
+
+ const uint8_t *src_u =
+ (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
+
+#if !QCOM_YUV
+ const uint8_t *src_v =
+ (const uint8_t *)src_u + (mDecodedWidth / 2) * (mDecodedHeight / 2);
+#endif
+
+ for (size_t y = 0; y < mDecodedHeight; ++y) {
+ for (size_t x = 0; x < mDecodedWidth; x += 2) {
+ // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
+ // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
+ // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
+
+ // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
+ // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
+ // R = .................. + 409/256 * (V - 128)
+
+ // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
+ // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
+ // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
+
+ // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
+ // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
+ // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
+
+ // clip range -278 .. 535
+
+ signed y1 = (signed)src_y[x] - 16;
+ signed y2 = (signed)src_y[x + 1] - 16;
+
+#if QCOM_YUV
+ signed u = (signed)src_u[x & ~1] - 128;
+ signed v = (signed)src_u[(x & ~1) + 1] - 128;
+#else
+ signed u = (signed)src_u[x / 2] - 128;
+ signed v = (signed)src_v[x / 2] - 128;
+#endif
+
+ signed u_b = u * 517;
+ signed u_g = -u * 100;
+ signed v_g = -v * 208;
+ signed v_r = v * 409;
+
+ signed tmp1 = y1 * 298;
+ signed b1 = (tmp1 + u_b) / 256;
+ signed g1 = (tmp1 + v_g + u_g) / 256;
+ signed r1 = (tmp1 + v_r) / 256;
+
+ signed tmp2 = y2 * 298;
+ signed b2 = (tmp2 + u_b) / 256;
+ signed g2 = (tmp2 + v_g + u_g) / 256;
+ signed r2 = (tmp2 + v_r) / 256;
+
+ uint32_t rgb1 =
+ ((kAdjustedClip[r1] >> 3) << 11)
+ | ((kAdjustedClip[g1] >> 2) << 5)
+ | (kAdjustedClip[b1] >> 3);
+
+ uint32_t rgb2 =
+ ((kAdjustedClip[r2] >> 3) << 11)
+ | ((kAdjustedClip[g2] >> 2) << 5)
+ | (kAdjustedClip[b2] >> 3);
+
+ dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+ }
+
+ src_y += mDecodedWidth;
+
+ if (y & 1) {
+#if QCOM_YUV
+ src_u += mDecodedWidth;
+#else
+ src_u += mDecodedWidth / 2;
+ src_v += mDecodedWidth / 2;
+#endif
+ }
+
+ dst_ptr += mDecodedWidth / 2;
+ }
+
+ mISurface->postBuffer(offset);
+ mIndex = 1 - mIndex;
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/TIHardwareRenderer.cpp b/media/libstagefright/omx/TIHardwareRenderer.cpp
new file mode 100644
index 0000000..ebade4a
--- /dev/null
+++ b/media/libstagefright/omx/TIHardwareRenderer.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "TIHardwareRenderer"
+#include <utils/Log.h>
+
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <media/stagefright/MediaDebug.h>
+#include <ui/ISurface.h>
+#include <ui/Overlay.h>
+
+#include "v4l2_utils.h"
+
+#define CACHEABLE_BUFFERS 0x1
+
+namespace android {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TIHardwareRenderer::TIHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight)
+ : mISurface(surface),
+ mDisplayWidth(displayWidth),
+ mDisplayHeight(displayHeight),
+ mDecodedWidth(decodedWidth),
+ mDecodedHeight(decodedHeight),
+ mFrameSize(mDecodedWidth * mDecodedHeight * 2),
+ mIsFirstFrame(true),
+ mIndex(0) {
+ CHECK(mISurface.get() != NULL);
+ CHECK(mDecodedWidth > 0);
+ CHECK(mDecodedHeight > 0);
+
+ sp<OverlayRef> ref = mISurface->createOverlay(
+ mDisplayWidth, mDisplayHeight, OVERLAY_FORMAT_CbYCrY_422_I);
+
+ if (ref.get() == NULL) {
+ LOGE("Unable to create the overlay!");
+ return;
+ }
+
+ mOverlay = new Overlay(ref);
+ mOverlay->setParameter(CACHEABLE_BUFFERS, 0);
+
+ for (size_t i = 0; i < (size_t)mOverlay->getBufferCount(); ++i) {
+ mapping_data_t *data =
+ (mapping_data_t *)mOverlay->getBufferAddress((void *)i);
+
+ mOverlayAddresses.push(data->ptr);
+ }
+}
+
+TIHardwareRenderer::~TIHardwareRenderer() {
+ if (mOverlay.get() != NULL) {
+ mOverlay->destroy();
+ mOverlay.clear();
+
+ // XXX apparently destroying an overlay is an asynchronous process...
+ sleep(1);
+ }
+}
+
+void TIHardwareRenderer::render(
+ const void *data, size_t size, void *platformPrivate) {
+ // CHECK_EQ(size, mFrameSize);
+
+ if (mOverlay.get() == NULL) {
+ return;
+ }
+
+#if 0
+ size_t i = 0;
+ for (; i < mOverlayAddresses.size(); ++i) {
+ if (mOverlayAddresses[i] == data) {
+ break;
+ }
+
+ if (mIsFirstFrame) {
+ LOGI("overlay buffer #%d: %p", i, mOverlayAddresses[i]);
+ }
+ }
+
+ if (i == mOverlayAddresses.size()) {
+ LOGE("No suitable overlay buffer found.");
+ return;
+ }
+
+ mOverlay->queueBuffer((void *)i);
+
+ overlay_buffer_t overlay_buffer;
+ if (!mIsFirstFrame) {
+ CHECK_EQ(mOverlay->dequeueBuffer(&overlay_buffer), OK);
+ } else {
+ mIsFirstFrame = false;
+ }
+#else
+ memcpy(mOverlayAddresses[mIndex], data, size);
+
+ mOverlay->queueBuffer((void *)mIndex);
+
+ if (++mIndex == mOverlayAddresses.size()) {
+ mIndex = 0;
+ }
+
+ overlay_buffer_t overlay_buffer;
+ if (!mIsFirstFrame) {
+ CHECK_EQ(mOverlay->dequeueBuffer(&overlay_buffer), OK);
+ } else {
+ mIsFirstFrame = false;
+ }
+#endif
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/string.cpp b/media/libstagefright/string.cpp
new file mode 100644
index 0000000..5b16784
--- /dev/null
+++ b/media/libstagefright/string.cpp
@@ -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.
+ */
+
+#include <media/stagefright/string.h>
+
+namespace android {
+
+// static
+string::size_type string::npos = (string::size_type)-1;
+
+string::string() {
+}
+
+string::string(const char *s, size_t length)
+ : mString(s, length) {
+}
+
+string::string(const string &from, size_type start, size_type length)
+ : mString(from.c_str() + start, length) {
+}
+
+string::string(const char *s)
+ : mString(s) {
+}
+
+const char *string::c_str() const {
+ return mString.string();
+}
+
+string::size_type string::size() const {
+ return mString.length();
+}
+
+void string::clear() {
+ mString = String8();
+}
+
+string::size_type string::find(char c) const {
+ char s[2];
+ s[0] = c;
+ s[1] = '\0';
+
+ ssize_t index = mString.find(s);
+
+ return index < 0 ? npos : (size_type)index;
+}
+
+bool string::operator<(const string &other) const {
+ return mString < other.mString;
+}
+
+bool string::operator==(const string &other) const {
+ return mString == other.mString;
+}
+
+string &string::operator+=(char c) {
+ mString.append(&c, 1);
+
+ return *this;
+}
+
+void string::erase(size_t from, size_t length) {
+ String8 s(mString.string(), from);
+ s.append(mString.string() + from + length);
+
+ mString = s;
+}
+
+} // namespace android
+
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..7094cfa 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -20,14 +20,15 @@
#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>
#include <CameraService.h>
#include <MediaPlayerService.h>
+#include <AudioPolicyService.h>
#include <private/android_filesystem_config.h>
using namespace android;
@@ -40,6 +41,7 @@ int main(int argc, char** argv)
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
+ AudioPolicyService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
diff --git a/media/sdutils/sdutil.cpp b/media/sdutils/sdutil.cpp
index 06120f5..fe11878 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/res/drawable-hdpi/icon.png b/media/tests/MediaFrameworkTest/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..a02138e
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/drawable/icon.png b/media/tests/MediaFrameworkTest/res/drawable-mdpi/icon.png
index 64e3601..64e3601 100644
--- a/media/tests/MediaFrameworkTest/res/drawable/icon.png
+++ b/media/tests/MediaFrameworkTest/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/layout/surface_view.xml b/media/tests/MediaFrameworkTest/res/layout/surface_view.xml
index c25e476..cbd1ff8 100644
--- a/media/tests/MediaFrameworkTest/res/layout/surface_view.xml
+++ b/media/tests/MediaFrameworkTest/res/layout/surface_view.xml
@@ -21,13 +21,12 @@
<FrameLayout
android:layout_width="fill_parent"
- android:layout_height="0px"
- android:layout_weight="1">
+ android:layout_height="fill_parent">
<SurfaceView
android:id="@+id/surface_view"
- android:layout_width="320dip"
- android:layout_height="240dip"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
android:layout_centerInParent="true"
/>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
index e65cf41..5e830a8 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
@@ -69,10 +69,6 @@ public class MediaFrameworkTest extends Activity {
setContentView(R.layout.surface_view);
mSurfaceView = (SurfaceView)findViewById(R.id.surface_view);
ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
- lp.width = 320;
- lp.height = 240;
- mSurfaceView.setLayoutParams(lp);
- mSurfaceView.getHolder().setFixedSize(320, 240);
mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//Get the midi fd
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
index 6edc2cc..2a4e9a0 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
@@ -23,6 +23,7 @@ import com.android.mediaframeworktest.functional.MediaMimeTest;
import com.android.mediaframeworktest.functional.MediaPlayerApiTest;
import com.android.mediaframeworktest.functional.MediaRecorderTest;
import com.android.mediaframeworktest.functional.SimTonesTest;
+import com.android.mediaframeworktest.functional.MediaPlayerInvokeTest;
import junit.framework.TestSuite;
@@ -32,7 +33,7 @@ import android.test.InstrumentationTestSuite;
/**
* Instrumentation Test Runner for all MediaPlayer tests.
- *
+ *
* Running all tests:
*
* adb shell am instrument \
@@ -52,6 +53,7 @@ public class MediaFrameworkTestRunner extends InstrumentationTestRunner {
suite.addTestSuite(MediaRecorderTest.class);
suite.addTestSuite(MediaAudioTrackTest.class);
suite.addTestSuite(MediaMimeTest.class);
+ suite.addTestSuite(MediaPlayerInvokeTest.class);
return suite;
}
@@ -60,5 +62,3 @@ public class MediaFrameworkTestRunner extends InstrumentationTestRunner {
return MediaFrameworkTestRunner.class.getClassLoader();
}
}
-
-
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index 81d59da..a203adc 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -24,16 +24,16 @@ import junit.framework.TestSuite;
/**
* Instrumentation Test Runner for all media framework unit tests.
- *
+ *
* Make sure that MediaFrameworkUnitTestRunner has been added to
* AndroidManifest.xml file, and then "make -j4 mediaframeworktest; adb sync"
* to build and upload mediaframeworktest to the phone or emulator.
- *
+ *
* Example on running all unit tests for a single class:
* adb shell am instrument -e class \
- * com.android.mediaframeworktest.unit.MediaMetadataRetrieverUnitTest \
+ * com.android.mediaframeworktest.unit.MediaMetadataRetrieverUnitTest \
* -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
- *
+ *
* Example on running all unit tests for the media framework:
* adb shell am instrument \
* -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
@@ -54,12 +54,12 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
public ClassLoader getLoader() {
return MediaFrameworkUnitTestRunner.class.getClassLoader();
}
-
+
// Running all unit tests checking the state machine may be time-consuming.
private void addMediaMetadataRetrieverStateUnitTests(TestSuite suite) {
suite.addTestSuite(MediaMetadataRetrieverTest.class);
}
-
+
// Running all unit tests checking the state machine may be time-consuming.
private void addMediaRecorderStateUnitTests(TestSuite suite) {
suite.addTestSuite(MediaRecorderPrepareStateUnitTest.class);
@@ -87,5 +87,6 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
suite.addTestSuite(MediaPlayerSetLoopingStateUnitTest.class);
suite.addTestSuite(MediaPlayerSetAudioStreamTypeStateUnitTest.class);
suite.addTestSuite(MediaPlayerSetVolumeStateUnitTest.class);
+ suite.addTestSuite(MediaPlayerMetadataParserTest.class);
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index e76967d..3f2bc39 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -372,81 +372,81 @@ public class MediaNames {
public static final String META_DATA_MP3 [][] = {
{"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1_ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist",
"ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues",
- "ID3V2.3 Title", "1234", "295", "1"},
+ "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist",
"ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues",
- "ID3V2.3 Title", "1234", "287", "1"},
+ "ID3V2.3 Title", "1234", "287", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1.mp3", "1", "test ID3V1 Album", "test ID3V1 Artist",
- null, null, null, "255", "test ID3V1 Title", "1234", "231332", "1"},
+ null, null, null, "255", "test ID3V1 Title", "1234", "231332", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V1.mp3" , null, null, null,
- null, null, null, null, null, null, "231330", "1"},
+ null, null, null, null, null, null, "231330", "1", null},
//The corrupted TALB field in id3v2 would not switch to id3v1 tag automatically
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TALB.mp3", "01", null, "ID3V2.3 Artist",
"ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
- "Blues", "ID3V2.3 Title", "1234", "295", "1"},
+ "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM.mp3", "01", "ID3V2.3 Album",
"ID3V2.3 Artist", "ID3V2.3 Lyricist", null, null,
- "Blues", "ID3V2.3 Title", "1234", "295", "1"},
+ "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM_2.mp3", "01", "ID3V2.3 Album",
- "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "295", "1"},
+ "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK.mp3", "dd", "ID3V2.3 Album",
"ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
- "Blues", "ID3V2.3 Title", "1234", "295", "1"},
+ "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album",
- "ID3V2.3 Artist", null, null, null, "255", "ID3V2.3 Title", "1234", "295", "1"},
+ "ID3V2.3 Artist", null, null, null, "255", "ID3V2.3 Title", "1234", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album",
- "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "295", "1"},
+ "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER_2.mp3", "01", "ID3V2.3 Album",
"ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
- "Blues", "ID3V2.3 Title", null, "295", "1"},
+ "Blues", "ID3V2.3 Title", null, "295", "1", null},
{"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TIT.mp3", null, null, null,
- null, null, null, null, null, null, "295", "1"}
+ null, null, null, null, null, null, "295", "1", null}
};
public static final String META_DATA_OTHERS [][] = {
{"/sdcard/media_api/metaDataTestMedias/3GP/cat.3gp", null, null, null,
null, null, "20080309T002415.000Z", null,
- null, null, "1404928", "2"},
+ null, null, "1404928", "2", null},
{"/sdcard/media_api/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null,
null, null, null, null,
- null, null, "126540", "1"},
+ null, null, "126540", "1", null},
{"/sdcard/media_api/metaDataTestMedias/AMRWB/AMR_WB.amr", null, null, null,
null, null, null, null,
- null, null, "231180", "1"},
- {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", null, "Suspended Animation",
+ null, null, "231180", "1", null},
+ {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", "1/8", "Suspended Animation",
"John Petrucci", null, null, "20070510T125223.000Z",
- null, null, "2005", "231180", "1"},
+ "13", "Jaws Of Life", "2005", "19815424", "1", "m4a composer"},
{"/sdcard/media_api/metaDataTestMedias/M4V/sample_iPod.m4v", null, null,
null, null, null, "20051220T202015.000Z",
- null, null, null, "3771392", "2"},
+ null, null, null, "3771392", "2", null},
{"/sdcard/media_api/metaDataTestMedias/MIDI/MIDI.mid", null, "Suspended Animation",
"John Petrucci", null, null, "20070510T125223.000Z",
- null, null, "2005", "231180", "1"},
- {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", null, "mp4 album Kung Fu Panda",
+ null, null, "2005", "231180", "1", null},
+ {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", "2/0", "mp4 album Kung Fu Panda",
"mp4 artist Kung Fu Panda", null, null, "20080517T091451.000Z",
- "41", "Kung Fu Panda", "2008", "5667840", "2"},
+ "41", "Kung Fu Panda", "2008", "5667840", "2", "mp4 composer"},
{"/sdcard/media_api/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation",
"John Petrucci", null, null, "20070510T125223.000Z",
- null, null, "2005", "231180", "1"},
+ null, null, "2005", "231180", "1", null},
{"/sdcard/media_api/metaDataTestMedias/OGG/When You Say Nothing At All.ogg",
null, "Suspended Animation", "John Petrucci",
- null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1"},
+ null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1", null},
{"/sdcard/media_api/metaDataTestMedias/WAV/Im With You.wav", null, null,
null, null, null, null,
- null, null, null, "224000", "1"},
+ null, null, null, "224000", "1", null},
{"/sdcard/media_api/metaDataTestMedias/WMA/WMA9.wma", "6", "Ten Songs in the Key of Betrayal",
"Alien Crime Syndicate", "Alien Crime Syndicate",
"wma 9 Composer", "20040521T175729.483Z",
- "Rock", "Run for the Money", "2004", "134479", "1"},
+ "Rock", "Run for the Money", "2004", "134479", "1", null},
{"/sdcard/media_api/metaDataTestMedias/WMA/WMA10.wma", "09", "wma 10 Album",
"wma 10 Album Artist", "wma 10 Artist", "wma 10 Composer", "20070705T063625.097Z",
- "Acid Jazz", "wma 10 Title", "2010", "126574", "1"},
+ "Acid Jazz", "wma 10 Title", "2010", "126574", "1", null},
{"/sdcard/media_api/metaDataTestMedias/WMV/bugs.wmv", "8", "wmv 9 Album",
null, "wmv 9 Artist ", null, "20051122T155247.540Z",
- null, "Looney Tunes - Hare-Breadth Hurry", "2005", "193482", "2"},
+ null, "Looney Tunes - Hare-Breadth Hurry", "2005", "193482", "2", null},
{"/sdcard/media_api/metaDataTestMedias/WMV/clips_ver7.wmv", "50", "wmv 7 Album",
null, "Hallau Shoots & Company", null, "20020226T170045.891Z",
- null, "CODEC Shootout", "1986", "43709", "2"}
+ null, "CODEC Shootout", "1986", "43709", "2", null}
};
//output recorded video
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
index aefedc3..cea3a5a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
@@ -140,7 +140,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
- AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.STATE_INITIALIZED);
assertTrue("testConstructorMono16MusicStream: " + res.mResultLog, res.mResult);
@@ -153,7 +153,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.STATE_INITIALIZED);
assertTrue("testConstructorStereo16MusicStream: " + res.mResultLog, res.mResult);
@@ -166,7 +166,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
- AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.STATE_NO_STATIC_DATA);
assertTrue("testConstructorMono16MusicStatic: " + res.mResultLog, res.mResult);
@@ -179,7 +179,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.STATE_NO_STATIC_DATA);
assertTrue("testConstructorStereo16MusicStatic: " + res.mResultLog, res.mResult);
@@ -196,7 +196,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
- AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_8BIT,
AudioTrack.STATE_INITIALIZED);
assertTrue("testConstructorMono8MusicStream: " + res.mResultLog, res.mResult);
@@ -208,7 +208,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_8BIT,
AudioTrack.STATE_INITIALIZED);
assertTrue("testConstructorStereo8MusicStream: " + res.mResultLog, res.mResult);
@@ -220,7 +220,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
- AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_8BIT,
AudioTrack.STATE_NO_STATIC_DATA);
assertTrue("testConstructorMono8MusicStatic: " + res.mResultLog, res.mResult);
@@ -232,7 +232,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
TestResults res = constructorTestMultiSampleRate(
AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_8BIT,
AudioTrack.STATE_NO_STATIC_DATA);
assertTrue("testConstructorStereo8MusicStatic: " + res.mResultLog, res.mResult);
@@ -248,15 +248,15 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
public void testConstructorStreamType() throws Exception {
// constants for test
final int TYPE_TEST_SR = 22050;
- final int TYPE_TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TYPE_TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TYPE_TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TYPE_TEST_MODE = AudioTrack.MODE_STREAM;
final int[] STREAM_TYPES = { AudioManager.STREAM_ALARM, AudioManager.STREAM_BLUETOOTH_SCO,
AudioManager.STREAM_MUSIC, AudioManager.STREAM_NOTIFICATION,
AudioManager.STREAM_RING, AudioManager.STREAM_SYSTEM,
- AudioManager.STREAM_VOICE_CALL };
+ AudioManager.STREAM_VOICE_CALL, AudioManager.STREAM_DTMF, };
final String[] STREAM_NAMES = { "STREAM_ALARM", "STREAM_BLUETOOTH_SCO", "STREAM_MUSIC",
- "STREAM_NOTIFICATION", "STREAM_RING", "STREAM_SYSTEM", "STREAM_VOICE_CALL" };
+ "STREAM_NOTIFICATION", "STREAM_RING", "STREAM_SYSTEM", "STREAM_VOICE_CALL", "STREAM_DTMF" };
boolean localTestRes = true;
AudioTrack track = null;
@@ -303,7 +303,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testPlaybackHeadPositionAfterInit";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -324,7 +324,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testPlaybackHeadPositionIncrease";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -352,7 +352,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testPlaybackHeadPositionAfterFlush";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -382,7 +382,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testPlaybackHeadPositionAfterStop";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -413,7 +413,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testPlaybackHeadPositionAfterPause";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -448,7 +448,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetStereoVolumeMax";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -474,7 +474,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetStereoVolumeMin";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -500,7 +500,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetStereoVolumeMid";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -526,7 +526,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetPlaybackRate";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -552,7 +552,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetPlaybackRateZero";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -574,7 +574,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetPlaybackRateTwiceOutputSR";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -601,7 +601,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetGetPlaybackRate";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -628,7 +628,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetPlaybackRateUninit";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -655,7 +655,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetPlaybackHeadPositionPlaying";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -682,7 +682,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetPlaybackHeadPositionStopped";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -710,7 +710,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetPlaybackHeadPositionPaused";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -738,7 +738,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetPlaybackHeadPositionTooFar";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -770,7 +770,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetLoopPointsStream";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -794,7 +794,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetLoopPointsStartAfterEnd";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -818,7 +818,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetLoopPointsSuccess";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -842,7 +842,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetLoopPointsLoopTooLong";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -868,7 +868,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetLoopPointsStartTooFar";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -896,7 +896,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testSetLoopPointsEndTooFar";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STATIC;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -929,7 +929,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteByteOffsetTooBig";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -953,7 +953,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteShortOffsetTooBig";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -977,7 +977,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteByteSizeTooBig";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1001,7 +1001,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteShortSizeTooBig";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1025,7 +1025,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteByteNegativeOffset";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1049,7 +1049,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteShortNegativeOffset";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1073,7 +1073,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteByteNegativeSize";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1097,7 +1097,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteShortNegativeSize";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1121,7 +1121,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteByte";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1145,7 +1145,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteShort";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1169,7 +1169,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteByte8bit";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1193,7 +1193,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constants for test
final String TEST_NAME = "testWriteShort8bit";
final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1221,7 +1221,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constant for test
final String TEST_NAME = "testGetMinBufferSizeTooLowSR";
final int TEST_SR = 3999;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
@@ -1238,7 +1238,7 @@ public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaF
// constant for testg
final String TEST_NAME = "testGetMinBufferSizeTooHighSR";
final int TEST_SR = 48001;
- final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_CONF = AudioFormat.CHANNEL_OUT_MONO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
index 3715913..1bf4958 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
@@ -36,7 +36,7 @@ public class MediaMetadataTest extends AndroidTestCase {
FILE_PATH,CD_TRACK, ALBUM,
ARTIST, AUTHOR, COMPOSER,
DATE, GENRE, TITLE,
- YEAR, DURATION, NUM_TRACKS
+ YEAR, DURATION, NUM_TRACKS, WRITER
}
public static enum MP3_TEST_FILE{
@@ -130,8 +130,6 @@ public class MediaMetadataTest extends AndroidTestCase {
validateMetatData(non_mp3_test_file.AMRWB.ordinal(), MediaNames.META_DATA_OTHERS);
}
- //Bug# 1440173 - skip this test case now
- @Suppress
@MediumTest
public static void testM4A1_Metadata() throws Exception {
validateMetatData(non_mp3_test_file.M4A1.ordinal(), MediaNames.META_DATA_OTHERS);
@@ -254,6 +252,10 @@ public class MediaMetadataTest extends AndroidTestCase {
Log.v(TAG, "Track : "+ value);
assertEquals(TAG,meta_data_file[fileIndex][meta.NUM_TRACKS.ordinal()], value);
+ value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_WRITER);
+ Log.v(TAG, "Writer : "+ value);
+ assertEquals(TAG,meta_data_file[fileIndex][meta.WRITER.ordinal()], value);
+
retriever.release();
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index ea42f53..30e2d6c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -435,9 +435,16 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra
@LargeTest
public void testLocalMp3PrepareAsyncCallback() throws Exception {
boolean onPrepareSuccess =
- CodecTest.prepareAsyncCallback(MediaNames.VIDEO_H263_AMR, false);
+ CodecTest.prepareAsyncCallback(MediaNames.MP3CBR, false);
assertTrue("LocalMp3prepareAsyncCallback", onPrepareSuccess);
}
+
+ @LargeTest
+ public void testLocalH263AMRPrepareAsyncCallback() throws Exception {
+ boolean onPrepareSuccess =
+ CodecTest.prepareAsyncCallback(MediaNames.VIDEO_H263_AMR, false);
+ assertTrue("testLocalH263AMRPrepareAsyncCallback", onPrepareSuccess);
+ }
@LargeTest
public void testStreamPrepareAsyncCallback() throws Exception {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java
new file mode 100644
index 0000000..ab8b311
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerInvokeTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.mediaframeworktest.functional;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+import android.media.MediaPlayer;
+import android.os.Parcel;
+
+import java.util.Calendar;
+import java.util.Random;
+
+// Tests for the invoke method in the MediaPlayer.
+public class MediaPlayerInvokeTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+ private static final String TAG = "MediaPlayerInvokeTest";
+ private MediaPlayer mPlayer;
+ private Random rnd;
+
+ public MediaPlayerInvokeTest() {
+ super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+ rnd = new Random(Calendar.getInstance().getTimeInMillis());
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mPlayer = new MediaPlayer();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mPlayer.release();
+ super.tearDown();
+ }
+
+ // Generate a random number, sends it to the ping test player.
+ @MediumTest
+ public void testPing() throws Exception {
+ mPlayer.setDataSource("test:invoke_mock_media_player.so?url=ping");
+
+ Parcel request = mPlayer.newRequest();
+ Parcel reply = Parcel.obtain();
+
+ int val = rnd.nextInt();
+ request.writeInt(val);
+ assertEquals(0, mPlayer.invoke(request, reply));
+ assertEquals(val, reply.readInt());
+ }
+}
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 442c35b..01c0920 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;
@@ -76,9 +76,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) {
@@ -137,6 +139,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/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java
new file mode 100644
index 0000000..38f598a
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java
@@ -0,0 +1,432 @@
+/*
+ * 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.mediaframeworktest.unit;
+import android.media.Metadata;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import java.util.Calendar;
+import java.util.Date;
+
+/*
+ * Check the Java layer that parses serialized metadata in Parcel
+ * works as expected.
+ *
+ */
+
+public class MediaPlayerMetadataParserTest extends AndroidTestCase {
+ private static final String TAG = "MediaPlayerMetadataTest";
+ private static final int kMarker = 0x4d455441; // 'M' 'E' 'T' 'A'
+ private static final int kHeaderSize = 8;
+
+ private Metadata mMetadata = null;
+ private Parcel mParcel = null;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mMetadata = new Metadata();
+ mParcel = Parcel.obtain();
+
+ resetParcel();
+ }
+
+ // Check parsing of the parcel fails. Make sure the parser rewind
+ // the parcel properly.
+ private void assertParseFail() throws Exception {
+ mParcel.setDataPosition(0);
+ assertFalse(mMetadata.parse(mParcel));
+ assertEquals(0, mParcel.dataPosition());
+ }
+
+ // Check parsing of the parcel is successful.
+ private void assertParse() throws Exception {
+ mParcel.setDataPosition(0);
+ assertTrue(mMetadata.parse(mParcel));
+ }
+
+ // Write the number of bytes from the start of the parcel to the
+ // current position at the beginning of the parcel (offset 0).
+ private void adjustSize() {
+ adjustSize(0);
+ }
+
+ // Write the number of bytes from the offset to the current
+ // position at position pointed by offset.
+ private void adjustSize(int offset) {
+ final int pos = mParcel.dataPosition();
+
+ mParcel.setDataPosition(offset);
+ mParcel.writeInt(pos - offset);
+ mParcel.setDataPosition(pos);
+ }
+
+ // Rewind the parcel and insert the header.
+ private void resetParcel() {
+ mParcel.setDataPosition(0);
+ // Most tests will use a properly formed parcel with a size
+ // and the meta marker so we add them by default.
+ mParcel.writeInt(-1); // Placeholder for the size
+ mParcel.writeInt(kMarker);
+ }
+
+ // ----------------------------------------------------------------------
+ // START OF THE TESTS
+
+
+ // There should be at least 8 bytes in the parcel, 4 for the size
+ // and 4 for the 'M' 'E' 'T' 'A' marker.
+ @SmallTest
+ public void testMissingSizeAndMarker() throws Exception {
+ for (int i = 0; i < kHeaderSize; ++i) {
+ mParcel.setDataPosition(0);
+ mParcel.setDataSize(i);
+
+ assertEquals(i, mParcel.dataAvail());
+ assertParseFail();
+ }
+ }
+
+ // There should be at least 'size' bytes in the parcel.
+ @SmallTest
+ public void testMissingData() throws Exception {
+ final int size = 20;
+
+ mParcel.writeInt(size);
+ mParcel.setDataSize(size - 1);
+ assertParseFail();
+ }
+
+ // Empty parcel is fine
+ @SmallTest
+ public void testEmptyIsOk() throws Exception {
+ adjustSize();
+ assertParse();
+ }
+
+ // ----------------------------------------------------------------------
+ // RECORDS
+ // ----------------------------------------------------------------------
+
+ // A record header should be at least 12 bytes long
+ @SmallTest
+ public void testRecordMissingId() throws Exception {
+ mParcel.writeInt(13); // record length
+ // misses metadata id and metadata type.
+ adjustSize();
+ assertParseFail();
+ }
+
+ @SmallTest
+ public void testRecordMissingType() throws Exception {
+ mParcel.writeInt(13); // record length lies
+ mParcel.writeInt(Metadata.TITLE);
+ // misses metadata type
+ adjustSize();
+ assertParseFail();
+ }
+
+ @SmallTest
+ public void testRecordWithZeroPayload() throws Exception {
+ mParcel.writeInt(0);
+ adjustSize();
+ assertParseFail();
+ }
+
+ // A record cannot be empty.
+ @SmallTest
+ public void testRecordMissingPayload() throws Exception {
+ mParcel.writeInt(12);
+ mParcel.writeInt(Metadata.TITLE);
+ mParcel.writeInt(Metadata.STRING_VAL);
+ // misses payload
+ adjustSize();
+ assertParseFail();
+ }
+
+ // Check records can be found.
+ @SmallTest
+ public void testRecordsFound() throws Exception {
+ writeStringRecord(Metadata.TITLE, "a title");
+ writeStringRecord(Metadata.GENRE, "comedy");
+ writeStringRecord(Metadata.firstCustomId(), "custom");
+ adjustSize();
+ assertParse();
+ assertTrue(mMetadata.has(Metadata.TITLE));
+ assertTrue(mMetadata.has(Metadata.GENRE));
+ assertTrue(mMetadata.has(Metadata.firstCustomId()));
+ assertFalse(mMetadata.has(Metadata.DRM_CRIPPLED));
+ assertEquals(3, mMetadata.keySet().size());
+ }
+
+ // Detects bad metadata type
+ @SmallTest
+ public void testBadMetadataType() throws Exception {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(Metadata.TITLE);
+ mParcel.writeInt(0); // Invalid type.
+ mParcel.writeString("dummy");
+ adjustSize(start);
+
+ adjustSize();
+ assertParseFail();
+ }
+
+ // Check a Metadata instance can be reused, i.e the parse method
+ // wipes out the existing states/keys.
+ @SmallTest
+ public void testParseClearState() throws Exception {
+ writeStringRecord(Metadata.TITLE, "a title");
+ writeStringRecord(Metadata.GENRE, "comedy");
+ writeStringRecord(Metadata.firstCustomId(), "custom");
+ adjustSize();
+ assertParse();
+
+ resetParcel();
+ writeStringRecord(Metadata.MIME_TYPE, "audio/mpg");
+ adjustSize();
+ assertParse();
+
+ // Only the mime type metadata should be present.
+ assertEquals(1, mMetadata.keySet().size());
+ assertTrue(mMetadata.has(Metadata.MIME_TYPE));
+
+ assertFalse(mMetadata.has(Metadata.TITLE));
+ assertFalse(mMetadata.has(Metadata.GENRE));
+ assertFalse(mMetadata.has(Metadata.firstCustomId()));
+ }
+
+ // ----------------------------------------------------------------------
+ // GETTERS
+ // ----------------------------------------------------------------------
+
+ // getString
+ @SmallTest
+ public void testGetString() throws Exception {
+ writeStringRecord(Metadata.TITLE, "a title");
+ writeStringRecord(Metadata.GENRE, "comedy");
+ adjustSize();
+ assertParse();
+
+ assertEquals("a title", mMetadata.getString(Metadata.TITLE));
+ assertEquals("comedy", mMetadata.getString(Metadata.GENRE));
+ }
+
+ // get an empty string.
+ @SmallTest
+ public void testGetEmptyString() throws Exception {
+ writeStringRecord(Metadata.TITLE, "");
+ adjustSize();
+ assertParse();
+
+ assertEquals("", mMetadata.getString(Metadata.TITLE));
+ }
+
+ // get a string when a NULL value was in the parcel
+ @SmallTest
+ public void testGetNullString() throws Exception {
+ writeStringRecord(Metadata.TITLE, null);
+ adjustSize();
+ assertParse();
+
+ assertEquals(null, mMetadata.getString(Metadata.TITLE));
+ }
+
+ // get a string when an integer is actually present
+ @SmallTest
+ public void testWrongType() throws Exception {
+ writeIntRecord(Metadata.DURATION, 5);
+ adjustSize();
+ assertParse();
+
+ try {
+ mMetadata.getString(Metadata.DURATION);
+ } catch (IllegalStateException ise) {
+ return;
+ }
+ fail("Exception was not thrown");
+ }
+
+ // getInt
+ @SmallTest
+ public void testGetInt() throws Exception {
+ writeIntRecord(Metadata.CD_TRACK_NUM, 1);
+ adjustSize();
+ assertParse();
+
+ assertEquals(1, mMetadata.getInt(Metadata.CD_TRACK_NUM));
+ }
+
+ // getBoolean
+ @SmallTest
+ public void testGetBoolean() throws Exception {
+ writeBooleanRecord(Metadata.DRM_CRIPPLED, true);
+ adjustSize();
+ assertParse();
+
+ assertEquals(true, mMetadata.getBoolean(Metadata.DRM_CRIPPLED));
+ }
+
+ // getLong
+ @SmallTest
+ public void testGetLong() throws Exception {
+ writeLongRecord(Metadata.DURATION, 1L);
+ adjustSize();
+ assertParse();
+
+ assertEquals(1L, mMetadata.getLong(Metadata.DURATION));
+ }
+
+ // getDouble
+ @SmallTest
+ public void testGetDouble() throws Exception {
+ writeDoubleRecord(Metadata.VIDEO_FRAME_RATE, 29.97);
+ adjustSize();
+ assertParse();
+
+ assertEquals(29.97, mMetadata.getDouble(Metadata.VIDEO_FRAME_RATE));
+ }
+
+ // getByteArray
+ @SmallTest
+ public void testGetByteArray() throws Exception {
+ byte data[] = new byte[]{1,2,3,4,5};
+
+ writeByteArrayRecord(Metadata.ALBUM_ART, data);
+ adjustSize();
+ assertParse();
+
+ byte res[] = mMetadata.getByteArray(Metadata.ALBUM_ART);
+ for (int i = 0; i < data.length; ++i) {
+ assertEquals(data[i], res[i]);
+ }
+ }
+
+ // getDate
+ @SmallTest
+ public void testGetDate() throws Exception {
+ writeDateRecord(Metadata.DATE, 0, "PST");
+ adjustSize();
+ assertParse();
+
+ assertEquals(new Date(0), mMetadata.getDate(Metadata.DATE));
+ }
+
+ // getTimedText
+ @SmallTest
+ public void testGetTimedText() throws Exception {
+ Date now = Calendar.getInstance().getTime();
+ writeTimedTextRecord(Metadata.CAPTION, now.getTime(),
+ 10, "Some caption");
+ adjustSize();
+ assertParse();
+
+ Metadata.TimedText caption = mMetadata.getTimedText(Metadata.CAPTION);
+ assertEquals("" + now + "-" + 10 + ":Some caption", caption.toString());
+ }
+
+ // ----------------------------------------------------------------------
+ // HELPERS TO APPEND RECORDS
+ // ----------------------------------------------------------------------
+
+ // Insert a string record at the current position.
+ private void writeStringRecord(int metadataId, String val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.STRING_VAL);
+ mParcel.writeString(val);
+ adjustSize(start);
+ }
+
+ // Insert an int record at the current position.
+ private void writeIntRecord(int metadataId, int val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.INTEGER_VAL);
+ mParcel.writeInt(val);
+ adjustSize(start);
+ }
+
+ // Insert a boolean record at the current position.
+ private void writeBooleanRecord(int metadataId, boolean val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.BOOLEAN_VAL);
+ mParcel.writeInt(val ? 1 : 0);
+ adjustSize(start);
+ }
+
+ // Insert a Long record at the current position.
+ private void writeLongRecord(int metadataId, long val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.LONG_VAL);
+ mParcel.writeLong(val);
+ adjustSize(start);
+ }
+
+ // Insert a Double record at the current position.
+ private void writeDoubleRecord(int metadataId, double val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.DOUBLE_VAL);
+ mParcel.writeDouble(val);
+ adjustSize(start);
+ }
+
+ // Insert a ByteArray record at the current position.
+ private void writeByteArrayRecord(int metadataId, byte[] val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.BYTE_ARRAY_VAL);
+ mParcel.writeByteArray(val);
+ adjustSize(start);
+ }
+
+ // Insert a Date record at the current position.
+ private void writeDateRecord(int metadataId, long time, String tz) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.DATE_VAL);
+ mParcel.writeLong(time);
+ mParcel.writeString(tz);
+ adjustSize(start);
+ }
+
+ // Insert a TimedText record at the current position.
+ private void writeTimedTextRecord(int metadataId, long begin,
+ int duration, String text) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.TIMED_TEXT_VAL);
+ mParcel.writeLong(begin);
+ mParcel.writeInt(duration);
+ mParcel.writeString(text);
+ adjustSize(start);
+ }
+}
diff --git a/media/tests/players/Android.mk b/media/tests/players/Android.mk
new file mode 100644
index 0000000..eb50a51
--- /dev/null
+++ b/media/tests/players/Android.mk
@@ -0,0 +1,29 @@
+# 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)
+
+LOCAL_SRC_FILES:= invoke_mock_media_player.cpp
+
+LOCAL_SHARED_LIBRARIES:= \
+ libbinder \
+ libutils
+
+LOCAL_MODULE:= invoke_mock_media_player
+LOCAL_MODULE_TAGS := test eng
+LOCAL_PRELINK_MODULE:= false
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/tests/players/README b/media/tests/players/README
new file mode 100644
index 0000000..edf9bd6
--- /dev/null
+++ b/media/tests/players/README
@@ -0,0 +1,8 @@
+Native test players for system tests.
+
+For functional/system/performance tests, a native test player can be used.
+This directory contains the sources of such players.
+The class TestPlayerStub uses the dynamic loader to load any of them.
+
+
+
diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp
new file mode 100644
index 0000000..77bb5b2
--- /dev/null
+++ b/media/tests/players/invoke_mock_media_player.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TestPlayerStub"
+#include "utils/Log.h"
+
+#include <string.h>
+
+#include <binder/Parcel.h>
+#include <media/MediaPlayerInterface.h>
+#include <utils/Errors.h>
+
+using android::INVALID_OPERATION;
+using android::ISurface;
+using android::MediaPlayerBase;
+using android::OK;
+using android::Parcel;
+using android::SortedVector;
+using android::TEST_PLAYER;
+using android::UNKNOWN_ERROR;
+using android::player_type;
+using android::sp;
+using android::status_t;
+
+// This file contains a test player that is loaded via the
+// TestPlayerStub class. The player contains various implementation
+// of the invoke method that java tests can use.
+
+namespace {
+const char *kPing = "ping";
+
+class Player: public MediaPlayerBase
+{
+ public:
+ enum TestType {TEST_UNKNOWN, PING};
+ Player() {}
+ virtual ~Player() {}
+
+ virtual status_t initCheck() {return OK;}
+ virtual bool hardwareOutput() {return true;}
+
+ virtual status_t setDataSource(const char *url) {
+ LOGV("setDataSource %s", url);
+ mTest = TEST_UNKNOWN;
+ if (strncmp(url, kPing, strlen(kPing)) == 0) {
+ mTest = PING;
+ }
+ return OK;
+ }
+
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length) {return OK;}
+ virtual status_t setVideoSurface(const sp<ISurface>& surface) {return OK;}
+ virtual status_t prepare() {return OK;}
+ virtual status_t prepareAsync() {return OK;}
+ virtual status_t start() {return OK;}
+ virtual status_t stop() {return OK;}
+ virtual status_t pause() {return OK;}
+ virtual bool isPlaying() {return true;}
+ virtual status_t seekTo(int msec) {return OK;}
+ virtual status_t getCurrentPosition(int *msec) {return OK;}
+ virtual status_t getDuration(int *msec) {return OK;}
+ virtual status_t reset() {return OK;}
+ virtual status_t setLooping(int loop) {return OK;}
+ virtual player_type playerType() {return TEST_PLAYER;}
+ virtual status_t invoke(const Parcel& request, Parcel *reply);
+
+ private:
+ // Take a request, copy it to the reply.
+ void ping(const Parcel& request, Parcel *reply);
+
+ status_t mStatus;
+ TestType mTest;
+};
+
+status_t Player::invoke(const Parcel& request, Parcel *reply)
+{
+ switch (mTest) {
+ case PING:
+ ping(request, reply);
+ break;
+ default: mStatus = UNKNOWN_ERROR;
+ }
+ return mStatus;
+}
+
+void Player::ping(const Parcel& request, Parcel *reply)
+{
+ const size_t len = request.dataAvail();
+
+ reply->setData(static_cast<const uint8_t*>(request.readInplace(len)), len);
+ mStatus = OK;
+}
+
+}
+
+extern "C" android::MediaPlayerBase* newPlayer()
+{
+ LOGD("New invoke test player");
+ return new Player();
+}
+
+extern "C" android::status_t deletePlayer(android::MediaPlayerBase *player)
+{
+ LOGD("Delete invoke test player");
+ delete player;
+ return OK;
+}
diff --git a/obex/Android.mk b/obex/Android.mk
new file mode 100644
index 0000000..fbfe9be
--- /dev/null
+++ b/obex/Android.mk
@@ -0,0 +1,9 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE:= javax.obex
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/obex/javax/obex/ApplicationParameter.java b/obex/javax/obex/ApplicationParameter.java
new file mode 100644
index 0000000..a62210f
--- /dev/null
+++ b/obex/javax/obex/ApplicationParameter.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+/**
+ * @hide
+ */
+public final class ApplicationParameter {
+
+ private byte[] mArray;
+
+ private int mLength;
+
+ private int mMaxLength = 1000;
+
+ public static class TRIPLET_TAGID {
+ public static final byte ORDER_TAGID = 0x01;
+
+ public static final byte SEARCH_VALUE_TAGID = 0x02;
+
+ public static final byte SEARCH_ATTRIBUTE_TAGID = 0x03;
+
+ // if equals to "0", PSE only reply number of contacts
+ public static final byte MAXLISTCOUNT_TAGID = 0x04;
+
+ public static final byte LISTSTARTOFFSET_TAGID = 0x05;
+
+ public static final byte FILTER_TAGID = 0x06;
+
+ public static final byte FORMAT_TAGID = 0x07;
+
+ // only used if max list count = 0
+ public static final byte PHONEBOOKSIZE_TAGID = 0x08;
+
+ // only used in "mch" in response
+ public static final byte NEWMISSEDCALLS_TAGID = 0x09;
+ }
+
+ public static class TRIPLET_VALUE {
+ public static class ORDER {
+ public static final byte ORDER_BY_INDEX = 0x00;
+
+ public static final byte ORDER_BY_ALPHANUMERIC = 0x01;
+
+ public static final byte ORDER_BY_PHONETIC = 0x02;
+ }
+
+ public static class SEARCHATTRIBUTE {
+ public static final byte SEARCH_BY_NAME = 0x00;
+
+ public static final byte SEARCH_BY_NUMBER = 0x01;
+
+ public static final byte SEARCH_BY_SOUND = 0x02;
+ }
+
+ public static class FORMAT {
+ public static final byte VCARD_VERSION_21 = 0x00;
+
+ public static final byte VCARD_VERSION_30 = 0x01;
+ }
+ }
+
+ public static class TRIPLET_LENGTH {
+ public static final byte ORDER_LENGTH = 1;
+
+ public static final byte SEARCH_ATTRIBUTE_LENGTH = 1;
+
+ public static final byte MAXLISTCOUNT_LENGTH = 2;
+
+ public static final byte LISTSTARTOFFSET_LENGTH = 2;
+
+ public static final byte FILTER_LENGTH = 8;
+
+ public static final byte FORMAT_LENGTH = 1;
+
+ public static final byte PHONEBOOKSIZE_LENGTH = 2;
+
+ public static final byte NEWMISSEDCALLS_LENGTH = 1;
+ }
+
+ public ApplicationParameter() {
+ mArray = new byte[mMaxLength];
+ mLength = 0;
+ }
+
+ public void addAPPHeader(byte tag, byte len, byte[] value) {
+ if ((mLength + len + 2) > mMaxLength) {
+ byte[] array_tmp = new byte[mLength + 4 * len];
+ System.arraycopy(mArray, 0, array_tmp, 0, mLength);
+ mArray = array_tmp;
+ mMaxLength = mLength + 4 * len;
+ }
+ mArray[mLength++] = tag;
+ mArray[mLength++] = len;
+ System.arraycopy(value, 0, mArray, mLength, len);
+ mLength += len;
+ }
+
+ public byte[] getAPPparam() {
+ byte[] para = new byte[mLength];
+ System.arraycopy(mArray, 0, para, 0, mLength);
+ return para;
+ }
+}
diff --git a/obex/javax/obex/Authenticator.java b/obex/javax/obex/Authenticator.java
new file mode 100644
index 0000000..ec226fb
--- /dev/null
+++ b/obex/javax/obex/Authenticator.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+/**
+ * This interface provides a way to respond to authentication challenge and
+ * authentication response headers. When a client or server receives an
+ * authentication challenge or authentication response header, the
+ * <code>onAuthenticationChallenge()</code> or
+ * <code>onAuthenticationResponse()</code> will be called, respectively, by the
+ * implementation.
+ * <P>
+ * For more information on how the authentication procedure works in OBEX,
+ * please review the IrOBEX specification at <A
+ * HREF="http://www.irda.org">http://www.irda.org</A>.
+ * <P>
+ * <STRONG>Authentication Challenges</STRONG>
+ * <P>
+ * When a client or server receives an authentication challenge header, the
+ * <code>onAuthenticationChallenge()</code> method will be invoked by the OBEX
+ * API implementation. The application will then return the user name (if
+ * needed) and password via a <code>PasswordAuthentication</code> object. The
+ * password in this object is not sent in the authentication response. Instead,
+ * the 16-byte challenge received in the authentication challenge is combined
+ * with the password returned from the <code>onAuthenticationChallenge()</code>
+ * method and passed through the MD5 hash algorithm. The resulting value is sent
+ * in the authentication response along with the user name if it was provided.
+ * <P>
+ * <STRONG>Authentication Responses</STRONG>
+ * <P>
+ * When a client or server receives an authentication response header, the
+ * <code>onAuthenticationResponse()</code> method is invoked by the API
+ * implementation with the user name received in the authentication response
+ * header. (The user name will be <code>null</code> if no user name was provided
+ * in the authentication response header.) The application must determine the
+ * correct password. This value should be returned from the
+ * <code>onAuthenticationResponse()</code> method. If the authentication request
+ * should fail without the implementation checking the password,
+ * <code>null</code> should be returned by the application. (This is needed for
+ * reasons like not recognizing the user name, etc.) If the returned value is
+ * not <code>null</code>, the OBEX API implementation will combine the password
+ * returned from the <code>onAuthenticationResponse()</code> method and
+ * challenge sent via the authentication challenge, apply the MD5 hash
+ * algorithm, and compare the result to the response hash received in the
+ * authentication response header. If the values are not equal, an
+ * <code>IOException</code> will be thrown if the client requested
+ * authentication. If the server requested authentication, the
+ * <code>onAuthenticationFailure()</code> method will be called on the
+ * <code>ServerRequestHandler</code> that failed authentication. The connection
+ * is <B>not</B> closed if authentication failed.
+ * @hide
+ */
+public interface Authenticator {
+
+ /**
+ * Called when a client or a server receives an authentication challenge
+ * header. It should respond to the challenge with a
+ * <code>PasswordAuthentication</code> that contains the correct user name
+ * and password for the challenge.
+ * @param description the description of which user name and password should
+ * be used; if no description is provided in the authentication
+ * challenge or the description is encoded in an encoding scheme that
+ * is not supported, an empty string will be provided
+ * @param isUserIdRequired <code>true</code> if the user ID is required;
+ * <code>false</code> if the user ID is not required
+ * @param isFullAccess <code>true</code> if full access to the server will
+ * be granted; <code>false</code> if read only access will be granted
+ * @return a <code>PasswordAuthentication</code> object containing the user
+ * name and password used for authentication
+ */
+ PasswordAuthentication onAuthenticationChallenge(String description, boolean isUserIdRequired,
+ boolean isFullAccess);
+
+ /**
+ * Called when a client or server receives an authentication response
+ * header. This method will provide the user name and expect the correct
+ * password to be returned.
+ * @param userName the user name provided in the authentication response; may
+ * be <code>null</code>
+ * @return the correct password for the user name provided; if
+ * <code>null</code> is returned then the authentication request
+ * failed
+ */
+ byte[] onAuthenticationResponse(byte[] userName);
+}
diff --git a/obex/javax/obex/BaseStream.java b/obex/javax/obex/BaseStream.java
new file mode 100644
index 0000000..022ad4f
--- /dev/null
+++ b/obex/javax/obex/BaseStream.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+
+/**
+ * This interface defines the methods needed by a parent that uses the
+ * PrivateInputStream and PrivateOutputStream objects defined in this package.
+ * @hide
+ */
+public interface BaseStream {
+
+ /**
+ * Verifies that this object is still open.
+ * @throws IOException if the object is closed
+ */
+ void ensureOpen() throws IOException;
+
+ /**
+ * Verifies that additional information may be sent. In other words, the
+ * operation is not done.
+ * @throws IOException if the operation is completed
+ */
+ void ensureNotDone() throws IOException;
+
+ /**
+ * Continues the operation since there is no data to read.
+ * @param sendEmpty <code>true</code> if the operation should send an empty
+ * packet or not send anything if there is no data to send
+ * @param inStream <code>true</code> if the stream is input stream or is
+ * output stream
+ * @return <code>true</code> if the operation was completed;
+ * <code>false</code> if no operation took place
+ * @throws IOException if an IO error occurs
+ */
+ boolean continueOperation(boolean sendEmpty, boolean inStream) throws IOException;
+
+ /**
+ * Called when the output or input stream is closed.
+ * @param inStream <code>true</code> if the input stream is closed;
+ * <code>false</code> if the output stream is closed
+ * @throws IOException if an IO error occurs
+ */
+ void streamClosed(boolean inStream) throws IOException;
+}
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
new file mode 100644
index 0000000..65663b1
--- /dev/null
+++ b/obex/javax/obex/ClientOperation.java
@@ -0,0 +1,720 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * This class implements the <code>Operation</code> interface. It will read and
+ * write data via puts and gets.
+ * @hide
+ */
+public final class ClientOperation implements Operation, BaseStream {
+
+ private ClientSession mParent;
+
+ private boolean mInputOpen;
+
+ private PrivateInputStream mPrivateInput;
+
+ private boolean mPrivateInputOpen;
+
+ private PrivateOutputStream mPrivateOutput;
+
+ private boolean mPrivateOutputOpen;
+
+ private String mExceptionMessage;
+
+ private int mMaxPacketSize;
+
+ private boolean mOperationDone;
+
+ private boolean mGetOperation;
+
+ private HeaderSet mRequestHeader;
+
+ private HeaderSet mReplyHeader;
+
+ private boolean mEndOfBodySent;
+
+ /**
+ * Creates new OperationImpl to read and write data to a server
+ * @param maxSize the maximum packet size
+ * @param p the parent to this object
+ * @param type <code>true</code> if this is a get request;
+ * <code>false</code. if this is a put request
+ * @param header the header to set in the initial request
+ * @throws IOException if the an IO error occurred
+ */
+ public ClientOperation(int maxSize, ClientSession p, HeaderSet header, boolean type)
+ throws IOException {
+
+ mParent = p;
+ mEndOfBodySent = false;
+ mInputOpen = true;
+ mOperationDone = false;
+ mMaxPacketSize = maxSize;
+ mGetOperation = type;
+
+ mPrivateInputOpen = false;
+ mPrivateOutputOpen = false;
+ mPrivateInput = null;
+ mPrivateOutput = null;
+
+ mReplyHeader = new HeaderSet();
+
+ mRequestHeader = new HeaderSet();
+
+ int[] headerList = header.getHeaderList();
+
+ if (headerList != null) {
+
+ for (int i = 0; i < headerList.length; i++) {
+ mRequestHeader.setHeader(headerList[i], header.getHeader(headerList[i]));
+ }
+ }
+
+ if ((header).mAuthChall != null) {
+ mRequestHeader.mAuthChall = new byte[(header).mAuthChall.length];
+ System.arraycopy((header).mAuthChall, 0, mRequestHeader.mAuthChall, 0,
+ (header).mAuthChall.length);
+ }
+
+ if ((header).mAuthResp != null) {
+ mRequestHeader.mAuthResp = new byte[(header).mAuthResp.length];
+ System.arraycopy((header).mAuthResp, 0, mRequestHeader.mAuthResp, 0,
+ (header).mAuthResp.length);
+
+ }
+ }
+
+ /**
+ * Sends an ABORT message to the server. By calling this method, the
+ * corresponding input and output streams will be closed along with this
+ * object.
+ * @throws IOException if the transaction has already ended or if an OBEX
+ * server called this method
+ */
+ public synchronized void abort() throws IOException {
+ ensureOpen();
+ //no compatible with sun-ri
+ if ((mOperationDone) && (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ throw new IOException("Operation has already ended");
+ }
+
+ mExceptionMessage = "Operation aborted";
+ if ((!mOperationDone) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ mOperationDone = true;
+ /*
+ * Since we are not sending any headers or returning any headers then
+ * we just need to write and read the same bytes
+ */
+ mParent.sendRequest(ObexHelper.OBEX_OPCODE_ABORT, null, mReplyHeader, null);
+
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_OK) {
+ throw new IOException("Invalid response code from server");
+ }
+
+ mExceptionMessage = null;
+ }
+
+ close();
+ }
+
+ /**
+ * Retrieves the response code retrieved from the server. Response codes are
+ * defined in the <code>ResponseCodes</code> interface.
+ * @return the response code retrieved from the server
+ * @throws IOException if an error occurred in the transport layer during
+ * the transaction; if this method is called on a
+ * <code>HeaderSet</code> object created by calling
+ * <code>createHeaderSet</code> in a <code>ClientSession</code>
+ * object
+ */
+ public synchronized int getResponseCode() throws IOException {
+ //avoid dup validateConnection
+ if ((mReplyHeader.responseCode == -1)
+ || (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ validateConnection();
+ }
+
+ return mReplyHeader.responseCode;
+ }
+
+ /**
+ * This method will always return <code>null</code>
+ * @return <code>null</code>
+ */
+ public String getEncoding() {
+ return null;
+ }
+
+ /**
+ * Returns the type of content that the resource connected to is providing.
+ * E.g. if the connection is via HTTP, then the value of the content-type
+ * header field is returned.
+ * @return the content type of the resource that the URL references, or
+ * <code>null</code> if not known
+ */
+ public String getType() {
+ try {
+ return (String)mReplyHeader.getHeader(HeaderSet.TYPE);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the length of the content which is being provided. E.g. if the
+ * connection is via HTTP, then the value of the content-length header field
+ * is returned.
+ * @return the content length of the resource that this connection's URL
+ * references, or -1 if the content length is not known
+ */
+ public long getLength() {
+ try {
+ Long temp = (Long)mReplyHeader.getHeader(HeaderSet.LENGTH);
+
+ if (temp == null) {
+ return -1;
+ } else {
+ return temp.longValue();
+ }
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ /**
+ * Open and return an input stream for a connection.
+ * @return an input stream
+ * @throws IOException if an I/O error occurs
+ */
+ public InputStream openInputStream() throws IOException {
+
+ ensureOpen();
+
+ if (mPrivateInputOpen)
+ throw new IOException("no more input streams available");
+ if (mGetOperation) {
+ // send the GET request here
+ validateConnection();
+ } else {
+ if (mPrivateInput == null) {
+ mPrivateInput = new PrivateInputStream(this);
+ }
+ }
+
+ mPrivateInputOpen = true;
+
+ return mPrivateInput;
+ }
+
+ /**
+ * Open and return a data input stream for a connection.
+ * @return an input stream
+ * @throws IOException if an I/O error occurs
+ */
+ public DataInputStream openDataInputStream() throws IOException {
+ return new DataInputStream(openInputStream());
+ }
+
+ /**
+ * Open and return an output stream for a connection.
+ * @return an output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public OutputStream openOutputStream() throws IOException {
+
+ ensureOpen();
+ ensureNotDone();
+
+ if (mPrivateOutputOpen)
+ throw new IOException("no more output streams available");
+
+ if (mPrivateOutput == null) {
+ // there are 3 bytes operation headers and 3 bytes body headers //
+ mPrivateOutput = new PrivateOutputStream(this, mMaxPacketSize - 6);
+ }
+
+ mPrivateOutputOpen = true;
+
+ return mPrivateOutput;
+ }
+
+ public int getMaxPacketSize() {
+ return mMaxPacketSize - 6;
+ }
+
+ /**
+ * Open and return a data output stream for a connection.
+ * @return an output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public DataOutputStream openDataOutputStream() throws IOException {
+ return new DataOutputStream(openOutputStream());
+ }
+
+ /**
+ * Closes the connection and ends the transaction
+ * @throws IOException if the operation has already ended or is closed
+ */
+ public void close() throws IOException {
+ mInputOpen = false;
+ mPrivateInputOpen = false;
+ mPrivateOutputOpen = false;
+ mParent.setRequestInactive();
+ }
+
+ /**
+ * Returns the headers that have been received during the operation.
+ * Modifying the object returned has no effect on the headers that are sent
+ * or retrieved.
+ * @return the headers received during this <code>Operation</code>
+ * @throws IOException if this <code>Operation</code> has been closed
+ */
+ public HeaderSet getReceivedHeader() throws IOException {
+ ensureOpen();
+
+ return mReplyHeader;
+ }
+
+ /**
+ * Specifies the headers that should be sent in the next OBEX message that
+ * is sent.
+ * @param headers the headers to send in the next message
+ * @throws IOException if this <code>Operation</code> has been closed or the
+ * transaction has ended and no further messages will be exchanged
+ * @throws IllegalArgumentException if <code>headers</code> was not created
+ * by a call to <code>ServerRequestHandler.createHeaderSet()</code>
+ * @throws NullPointerException if <code>headers</code> is <code>null</code>
+ */
+ public void sendHeaders(HeaderSet headers) throws IOException {
+ ensureOpen();
+ if (mOperationDone) {
+ throw new IOException("Operation has already exchanged all data");
+ }
+
+ if (headers == null) {
+ throw new IOException("Headers may not be null");
+ }
+
+ int[] headerList = headers.getHeaderList();
+ if (headerList != null) {
+ for (int i = 0; i < headerList.length; i++) {
+ mRequestHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
+ }
+ }
+ }
+
+ /**
+ * Verifies that additional information may be sent. In other words, the
+ * operation is not done.
+ * @throws IOException if the operation is completed
+ */
+ public void ensureNotDone() throws IOException {
+ if (mOperationDone) {
+ throw new IOException("Operation has completed");
+ }
+ }
+
+ /**
+ * Verifies that the connection is open and no exceptions should be thrown.
+ * @throws IOException if an exception needs to be thrown
+ */
+ public void ensureOpen() throws IOException {
+ mParent.ensureOpen();
+
+ if (mExceptionMessage != null) {
+ throw new IOException(mExceptionMessage);
+ }
+ if (!mInputOpen) {
+ throw new IOException("Operation has already ended");
+ }
+ }
+
+ /**
+ * Verifies that the connection is open and the proper data has been read.
+ * @throws IOException if an IO error occurs
+ */
+ private void validateConnection() throws IOException {
+ ensureOpen();
+
+ // to sure only one privateInput object exist.
+ if (mPrivateInput == null) {
+ startProcessing();
+ }
+ }
+
+ /**
+ * Sends a request to the client of the specified type
+ * @param opCode the request code to send to the client
+ * @return <code>true</code> if there is more data to send;
+ * <code>false</code> if there is no more data to send
+ * @throws IOException if an IO error occurs
+ */
+ private boolean sendRequest(int opCode) throws IOException {
+ boolean returnValue = false;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int bodyLength = -1;
+ byte[] headerArray = ObexHelper.createHeader(mRequestHeader, true);
+ if (mPrivateOutput != null) {
+ bodyLength = mPrivateOutput.size();
+ }
+
+ /*
+ * Determine if there is space to add a body request. At present
+ * this method checks to see if there is room for at least a 17
+ * byte body header. This number needs to be at least 6 so that
+ * there is room for the header ID and length and the reply ID and
+ * length, but it is a waste of resources if we can't send much of
+ * the body.
+ */
+ if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketSize) {
+ int end = 0;
+ int start = 0;
+ // split & send the headerArray in multiple packets.
+
+ while (end != headerArray.length) {
+ //split the headerArray
+ end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
+ - ObexHelper.BASE_PACKET_LENGTH);
+ // can not split
+ if (end == -1) {
+ mOperationDone = true;
+ abort();
+ mExceptionMessage = "Header larger then can be sent in a packet";
+ mInputOpen = false;
+
+ if (mPrivateInput != null) {
+ mPrivateInput.close();
+ }
+
+ if (mPrivateOutput != null) {
+ mPrivateOutput.close();
+ }
+ throw new IOException("OBEX Packet exceeds max packet size");
+ }
+
+ byte[] sendHeader = new byte[end - start];
+ System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
+ if (!mParent.sendRequest(opCode, sendHeader, mReplyHeader, mPrivateInput)) {
+ return false;
+ }
+
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ return false;
+ }
+
+ start = end;
+ }
+
+ if (bodyLength > 0) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ out.write(headerArray);
+ }
+
+ if (bodyLength > 0) {
+ /*
+ * Determine if we can send the whole body or just part of
+ * the body. Remember that there is the 3 bytes for the
+ * response message and 3 bytes for the header ID and length
+ */
+ if (bodyLength > (mMaxPacketSize - headerArray.length - 6)) {
+ returnValue = true;
+
+ bodyLength = mMaxPacketSize - headerArray.length - 6;
+ }
+
+ byte[] body = mPrivateOutput.readBytes(bodyLength);
+
+ /*
+ * Since this is a put request if the final bit is set or
+ * the output stream is closed we need to send the 0x49
+ * (End of Body) otherwise, we need to send 0x48 (Body)
+ */
+ if ((mPrivateOutput.isClosed()) && (!returnValue) && (!mEndOfBodySent)
+ && ((opCode & 0x80) != 0)) {
+ out.write(0x49);
+ mEndOfBodySent = true;
+ } else {
+ out.write(0x48);
+ }
+
+ bodyLength += 3;
+ out.write((byte)(bodyLength >> 8));
+ out.write((byte)bodyLength);
+
+ if (body != null) {
+ out.write(body);
+ }
+ }
+
+ if (mPrivateOutputOpen && bodyLength <= 0 && !mEndOfBodySent) {
+ // only 0x82 or 0x83 can send 0x49
+ if ((opCode & 0x80) == 0) {
+ out.write(0x48);
+ } else {
+ out.write(0x49);
+ mEndOfBodySent = true;
+
+ }
+
+ bodyLength = 3;
+ out.write((byte)(bodyLength >> 8));
+ out.write((byte)bodyLength);
+ }
+
+ if (out.size() == 0) {
+ if (!mParent.sendRequest(opCode, null, mReplyHeader, mPrivateInput)) {
+ return false;
+ }
+ return returnValue;
+ }
+ if ((out.size() > 0)
+ && (!mParent.sendRequest(opCode, out.toByteArray(), mReplyHeader, mPrivateInput))) {
+ return false;
+ }
+
+ // send all of the output data in 0x48,
+ // send 0x49 with empty body
+ if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
+ returnValue = true;
+
+ return returnValue;
+ }
+
+ /**
+ * This method starts the processing thread results. It will send the
+ * initial request. If the response takes more then one packet, a thread
+ * will be started to handle additional requests
+ * @throws IOException if an IO error occurs
+ */
+ private synchronized void startProcessing() throws IOException {
+
+ if (mPrivateInput == null) {
+ mPrivateInput = new PrivateInputStream(this);
+ }
+ boolean more = true;
+
+ if (mGetOperation) {
+ if (!mOperationDone) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ more = sendRequest(0x03);
+ }
+
+ if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
+ }
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
+ }
+ } else {
+
+ if (!mOperationDone) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ more = sendRequest(0x02);
+
+ }
+ }
+
+ if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mParent.sendRequest(0x82, null, mReplyHeader, mPrivateInput);
+ }
+
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
+ }
+ }
+
+ /**
+ * Continues the operation since there is no data to read.
+ * @param sendEmpty <code>true</code> if the operation should send an empty
+ * packet or not send anything if there is no data to send
+ * @param inStream <code>true</code> if the stream is input stream or is
+ * output stream
+ * @throws IOException if an IO error occurs
+ */
+ public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
+ throws IOException {
+
+ if (mGetOperation) {
+ if ((inStream) && (!mOperationDone)) {
+ // to deal with inputstream in get operation
+ mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
+ /*
+ * Determine if that was not the last packet in the operation
+ */
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
+
+ return true;
+
+ } else if ((!inStream) && (!mOperationDone)) {
+ // to deal with outputstream in get operation
+
+ if (mPrivateInput == null) {
+ mPrivateInput = new PrivateInputStream(this);
+ }
+ sendRequest(0x03);
+ return true;
+
+ } else if (mOperationDone) {
+ return false;
+ }
+
+ } else {
+ if ((!inStream) && (!mOperationDone)) {
+ // to deal with outputstream in put operation
+ if (mReplyHeader.responseCode == -1) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ }
+ sendRequest(0x02);
+ return true;
+ } else if ((inStream) && (!mOperationDone)) {
+ // How to deal with inputstream in put operation ?
+ return false;
+
+ } else if (mOperationDone) {
+ return false;
+ }
+
+ }
+ return false;
+ }
+
+ /**
+ * Called when the output or input stream is closed.
+ * @param inStream <code>true</code> if the input stream is closed;
+ * <code>false</code> if the output stream is closed
+ * @throws IOException if an IO error occurs
+ */
+ public void streamClosed(boolean inStream) throws IOException {
+ if (!mGetOperation) {
+ if ((!inStream) && (!mOperationDone)) {
+ // to deal with outputstream in put operation
+
+ boolean more = true;
+
+ if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
+ byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
+ if (headerArray.length <= 0)
+ more = false;
+ }
+ // If have not sent any data so send all now
+ if (mReplyHeader.responseCode == -1) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ }
+
+ while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ more = sendRequest(0x02);
+ }
+
+ /*
+ * According to the IrOBEX specification, after the final put, you
+ * only have a single reply to send. so we don't need the while
+ * loop.
+ */
+ while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+
+ sendRequest(0x82);
+ }
+ mOperationDone = true;
+ } else if ((inStream) && (mOperationDone)) {
+ // how to deal with input stream in put stream ?
+ mOperationDone = true;
+ }
+ } else {
+ if ((inStream) && (!mOperationDone)) {
+
+ // to deal with inputstream in get operation
+ // Have not sent any data so send it all now
+
+ if (mReplyHeader.responseCode == -1) {
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ }
+
+ while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ if (!sendRequest(0x83)) {
+ break;
+ }
+ }
+ while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
+ }
+ mOperationDone = true;
+ } else if ((!inStream) && (!mOperationDone)) {
+ // to deal with outputstream in get operation
+ // part of the data may have been sent in continueOperation.
+
+ boolean more = true;
+
+ if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
+ byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
+ if (headerArray.length <= 0)
+ more = false;
+ }
+
+ if (mPrivateInput == null) {
+ mPrivateInput = new PrivateInputStream(this);
+ }
+ if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0))
+ more = false;
+
+ mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
+ while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
+ more = sendRequest(0x03);
+ }
+ sendRequest(0x83);
+ // parent.sendRequest(0x83, null, replyHeaders, privateInput);
+ if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
+ mOperationDone = true;
+ }
+ }
+ }
+ }
+}
diff --git a/obex/javax/obex/ClientSession.java b/obex/javax/obex/ClientSession.java
new file mode 100644
index 0000000..0935383
--- /dev/null
+++ b/obex/javax/obex/ClientSession.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * This class in an implementation of the OBEX ClientSession.
+ * @hide
+ */
+public final class ClientSession extends ObexSession {
+
+ private boolean mOpen;
+
+ // Determines if an OBEX layer connection has been established
+ private boolean mObexConnected;
+
+ private byte[] mConnectionId = null;
+
+ /*
+ * The max Packet size must be at least 256 according to the OBEX
+ * specification.
+ */
+ private int maxPacketSize = 256;
+
+ private boolean mRequestActive;
+
+ private final InputStream mInput;
+
+ private final OutputStream mOutput;
+
+ public ClientSession(final ObexTransport trans) throws IOException {
+ mInput = trans.openInputStream();
+ mOutput = trans.openOutputStream();
+ mOpen = true;
+ mRequestActive = false;
+ }
+
+ public HeaderSet connect(final HeaderSet header) throws IOException {
+ ensureOpen();
+ if (mObexConnected) {
+ throw new IOException("Already connected to server");
+ }
+ setRequestActive();
+
+ int totalLength = 4;
+ byte[] head = null;
+
+ // Determine the header byte array
+ if (header != null) {
+ if (header.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
+ }
+ head = ObexHelper.createHeader(header, false);
+ totalLength += head.length;
+ }
+ /*
+ * Write the OBEX CONNECT packet to the server.
+ * Byte 0: 0x80
+ * Byte 1&2: Connect Packet Length
+ * Byte 3: OBEX Version Number (Presently, 0x10)
+ * Byte 4: Flags (For TCP 0x00)
+ * Byte 5&6: Max OBEX Packet Length (Defined in MAX_PACKET_SIZE)
+ * Byte 7 to n: headers
+ */
+ byte[] requestPacket = new byte[totalLength];
+ // We just need to start at byte 3 since the sendRequest() method will
+ // handle the length and 0x80.
+ requestPacket[0] = (byte)0x10;
+ requestPacket[1] = (byte)0x00;
+ requestPacket[2] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT >> 8);
+ requestPacket[3] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT & 0xFF);
+ if (head != null) {
+ System.arraycopy(head, 0, requestPacket, 4, head.length);
+ }
+
+ // check with local max packet size
+ if ((requestPacket.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
+ throw new IOException("Packet size exceeds max packet size");
+ }
+
+ HeaderSet returnHeaderSet = new HeaderSet();
+ sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null);
+
+ /*
+ * Read the response from the OBEX server.
+ * Byte 0: Response Code (If successful then OBEX_HTTP_OK)
+ * Byte 1&2: Packet Length
+ * Byte 3: OBEX Version Number
+ * Byte 4: Flags3
+ * Byte 5&6: Max OBEX packet Length
+ * Byte 7 to n: Optional HeaderSet
+ */
+ if (returnHeaderSet.responseCode == ResponseCodes.OBEX_HTTP_OK) {
+ mObexConnected = true;
+ }
+ setRequestInactive();
+
+ return returnHeaderSet;
+ }
+
+ public Operation get(HeaderSet header) throws IOException {
+
+ if (!mObexConnected) {
+ throw new IOException("Not connected to the server");
+ }
+ setRequestActive();
+
+ ensureOpen();
+
+ HeaderSet head;
+ if (header == null) {
+ head = new HeaderSet();
+ } else {
+ head = header;
+ if (head.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
+ }
+ }
+ // Add the connection ID if one exists
+ if (mConnectionId != null) {
+ head.mConnectionID = new byte[4];
+ System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
+ }
+
+ return new ClientOperation(maxPacketSize, this, head, true);
+ }
+
+ /**
+ * 0xCB Connection Id an identifier used for OBEX connection multiplexing
+ */
+ public void setConnectionID(long id) {
+ if ((id < 0) || (id > 0xFFFFFFFFL)) {
+ throw new IllegalArgumentException("Connection ID is not in a valid range");
+ }
+ mConnectionId = ObexHelper.convertToByteArray(id);
+ }
+
+ public HeaderSet delete(HeaderSet header) throws IOException {
+
+ Operation op = put(header);
+ op.getResponseCode();
+ HeaderSet returnValue = op.getReceivedHeader();
+ op.close();
+
+ return returnValue;
+ }
+
+ public HeaderSet disconnect(HeaderSet header) throws IOException {
+ if (!mObexConnected) {
+ throw new IOException("Not connected to the server");
+ }
+ setRequestActive();
+
+ ensureOpen();
+ // Determine the header byte array
+ byte[] head = null;
+ if (header != null) {
+ if (header.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
+ }
+ // Add the connection ID if one exists
+ if (mConnectionId != null) {
+ header.mConnectionID = new byte[4];
+ System.arraycopy(mConnectionId, 0, header.mConnectionID, 0, 4);
+ }
+ head = ObexHelper.createHeader(header, false);
+
+ if ((head.length + 3) > maxPacketSize) {
+ throw new IOException("Packet size exceeds max packet size");
+ }
+ } else {
+ // Add the connection ID if one exists
+ if (mConnectionId != null) {
+ head = new byte[5];
+ head[0] = (byte)HeaderSet.CONNECTION_ID;
+ System.arraycopy(mConnectionId, 0, head, 1, 4);
+ }
+ }
+
+ HeaderSet returnHeaderSet = new HeaderSet();
+ sendRequest(ObexHelper.OBEX_OPCODE_DISCONNECT, head, returnHeaderSet, null);
+
+ /*
+ * An OBEX DISCONNECT reply from the server:
+ * Byte 1: Response code
+ * Bytes 2 & 3: packet size
+ * Bytes 4 & up: headers
+ */
+
+ /* response code , and header are ignored
+ * */
+
+ synchronized (this) {
+ mObexConnected = false;
+ setRequestInactive();
+ }
+
+ return returnHeaderSet;
+ }
+
+ public long getConnectionID() {
+
+ if (mConnectionId == null) {
+ return -1;
+ }
+ return ObexHelper.convertToLong(mConnectionId);
+ }
+
+ public Operation put(HeaderSet header) throws IOException {
+ if (!mObexConnected) {
+ throw new IOException("Not connected to the server");
+ }
+ setRequestActive();
+
+ ensureOpen();
+ HeaderSet head;
+ if (header == null) {
+ head = new HeaderSet();
+ } else {
+ head = header;
+ // when auth is initiated by client ,save the digest
+ if (head.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
+ }
+ }
+
+ // Add the connection ID if one exists
+ if (mConnectionId != null) {
+
+ head.mConnectionID = new byte[4];
+ System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
+ }
+
+ return new ClientOperation(maxPacketSize, this, head, false);
+ }
+
+ public void setAuthenticator(Authenticator auth) throws IOException {
+ if (auth == null) {
+ throw new IOException("Authenticator may not be null");
+ }
+ mAuthenticator = auth;
+ }
+
+ public HeaderSet setPath(HeaderSet header, boolean backup, boolean create) throws IOException {
+ if (!mObexConnected) {
+ throw new IOException("Not connected to the server");
+ }
+ setRequestActive();
+ ensureOpen();
+
+ int totalLength = 2;
+ byte[] head = null;
+ HeaderSet headset;
+ if (header == null) {
+ headset = new HeaderSet();
+ } else {
+ headset = header;
+ if (headset.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
+ }
+ }
+
+ // when auth is initiated by client ,save the digest
+ if (headset.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
+ }
+
+ // Add the connection ID if one exists
+ if (mConnectionId != null) {
+ headset.mConnectionID = new byte[4];
+ System.arraycopy(mConnectionId, 0, headset.mConnectionID, 0, 4);
+ }
+
+ head = ObexHelper.createHeader(headset, false);
+ totalLength += head.length;
+
+ if (totalLength > maxPacketSize) {
+ throw new IOException("Packet size exceeds max packet size");
+ }
+
+ int flags = 0;
+ /*
+ * The backup flag bit is bit 0 so if we add 1, this will set that bit
+ */
+ if (backup) {
+ flags++;
+ }
+ /*
+ * The create bit is bit 1 so if we or with 2 the bit will be set.
+ */
+ if (!create) {
+ flags |= 2;
+ }
+
+ /*
+ * An OBEX SETPATH packet to the server:
+ * Byte 1: 0x85
+ * Byte 2 & 3: packet size
+ * Byte 4: flags
+ * Byte 5: constants
+ * Byte 6 & up: headers
+ */
+ byte[] packet = new byte[totalLength];
+ packet[0] = (byte)flags;
+ packet[1] = (byte)0x00;
+ if (headset != null) {
+ System.arraycopy(head, 0, packet, 2, head.length);
+ }
+
+ HeaderSet returnHeaderSet = new HeaderSet();
+ sendRequest(ObexHelper.OBEX_OPCODE_SETPATH, packet, returnHeaderSet, null);
+
+ /*
+ * An OBEX SETPATH reply from the server:
+ * Byte 1: Response code
+ * Bytes 2 & 3: packet size
+ * Bytes 4 & up: headers
+ */
+
+ setRequestInactive();
+
+ return returnHeaderSet;
+ }
+
+ /**
+ * Verifies that the connection is open.
+ * @throws IOException if the connection is closed
+ */
+ public synchronized void ensureOpen() throws IOException {
+ if (!mOpen) {
+ throw new IOException("Connection closed");
+ }
+ }
+
+ /**
+ * Set request inactive. Allows Put and get operation objects to tell this
+ * object when they are done.
+ */
+ /*package*/synchronized void setRequestInactive() {
+ mRequestActive = false;
+ }
+
+ /**
+ * Set request to active.
+ * @throws IOException if already active
+ */
+ private synchronized void setRequestActive() throws IOException {
+ if (mRequestActive) {
+ throw new IOException("OBEX request is already being performed");
+ }
+ mRequestActive = true;
+ }
+
+ /**
+ * Sends a standard request to the client. It will then wait for the reply
+ * and update the header set object provided. If any authentication headers
+ * (i.e. authentication challenge or authentication response) are received,
+ * they will be processed.
+ * @param opCode the type of request to send to the client
+ * @param head the headers to send to the client
+ * @param header the header object to update with the response
+ * @param privateInput the input stream used by the Operation object; null
+ * if this is called on a CONNECT, SETPATH or DISCONNECT return
+ * <code>true</code> if the operation completed successfully;
+ * <code>false</code> if an authentication response failed to pass
+ * @throws IOException if an IO error occurs
+ */
+ public boolean sendRequest(int opCode, byte[] head, HeaderSet header,
+ PrivateInputStream privateInput) throws IOException {
+ //check header length with local max size
+ if (head != null) {
+ if ((head.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
+ throw new IOException("header too large ");
+ }
+ }
+
+ int bytesReceived;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ out.write((byte)opCode);
+
+ // Determine if there are any headers to send
+ if (head == null) {
+ out.write(0x00);
+ out.write(0x03);
+ } else {
+ out.write((byte)((head.length + 3) >> 8));
+ out.write((byte)(head.length + 3));
+ out.write(head);
+ }
+
+ // Write the request to the output stream and flush the stream
+ mOutput.write(out.toByteArray());
+ mOutput.flush();
+
+ header.responseCode = mInput.read();
+
+ int length = ((mInput.read() << 8) | (mInput.read()));
+
+ if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+ throw new IOException("Packet received exceeds packet size limit");
+ }
+ if (length > ObexHelper.BASE_PACKET_LENGTH) {
+ byte[] data = null;
+ if (opCode == ObexHelper.OBEX_OPCODE_CONNECT) {
+ @SuppressWarnings("unused")
+ int version = mInput.read();
+ @SuppressWarnings("unused")
+ int flags = mInput.read();
+ maxPacketSize = (mInput.read() << 8) + mInput.read();
+
+ //check with local max size
+ if (maxPacketSize > ObexHelper.MAX_PACKET_SIZE_INT) {
+ maxPacketSize = ObexHelper.MAX_PACKET_SIZE_INT;
+ }
+
+ if (length > 7) {
+ data = new byte[length - 7];
+
+ bytesReceived = mInput.read(data);
+ while (bytesReceived != (length - 7)) {
+ bytesReceived += mInput.read(data, bytesReceived, data.length
+ - bytesReceived);
+ }
+ } else {
+ return true;
+ }
+ } else {
+ data = new byte[length - 3];
+ bytesReceived = mInput.read(data);
+
+ while (bytesReceived != (length - 3)) {
+ bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived);
+ }
+ if (opCode == ObexHelper.OBEX_OPCODE_ABORT) {
+ return true;
+ }
+ }
+
+ byte[] body = ObexHelper.updateHeaderSet(header, data);
+ if ((privateInput != null) && (body != null)) {
+ privateInput.writeBytes(body, 1);
+ }
+
+ if (header.mConnectionID != null) {
+ mConnectionId = new byte[4];
+ System.arraycopy(header.mConnectionID, 0, mConnectionId, 0, 4);
+ }
+
+ if (header.mAuthResp != null) {
+ if (!handleAuthResp(header.mAuthResp)) {
+ setRequestInactive();
+ throw new IOException("Authentication Failed");
+ }
+ }
+
+ if ((header.responseCode == ResponseCodes.OBEX_HTTP_UNAUTHORIZED)
+ && (header.mAuthChall != null)) {
+
+ if (handleAuthChall(header)) {
+ out.write((byte)HeaderSet.AUTH_RESPONSE);
+ out.write((byte)((header.mAuthResp.length + 3) >> 8));
+ out.write((byte)(header.mAuthResp.length + 3));
+ out.write(header.mAuthResp);
+ header.mAuthChall = null;
+ header.mAuthResp = null;
+
+ byte[] sendHeaders = new byte[out.size() - 3];
+ System.arraycopy(out.toByteArray(), 3, sendHeaders, 0, sendHeaders.length);
+
+ return sendRequest(opCode, sendHeaders, header, privateInput);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public void close() throws IOException {
+ mOpen = false;
+ mInput.close();
+ mOutput.close();
+ }
+}
diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java
new file mode 100644
index 0000000..8b457f6
--- /dev/null
+++ b/obex/javax/obex/HeaderSet.java
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Random;
+
+/**
+ * This class implements the javax.obex.HeaderSet interface for OBEX over
+ * RFCOMM.
+ * @hide
+ */
+public final class HeaderSet {
+
+ /**
+ * Represents the OBEX Count header. This allows the connection statement to
+ * tell the server how many objects it plans to send or retrieve.
+ * <P>
+ * The value of <code>COUNT</code> is 0xC0 (192).
+ */
+ public static final int COUNT = 0xC0;
+
+ /**
+ * Represents the OBEX Name header. This specifies the name of the object.
+ * <P>
+ * The value of <code>NAME</code> is 0x01 (1).
+ */
+ public static final int NAME = 0x01;
+
+ /**
+ * Represents the OBEX Type header. This allows a request to specify the
+ * type of the object (e.g. text, html, binary, etc.).
+ * <P>
+ * The value of <code>TYPE</code> is 0x42 (66).
+ */
+ public static final int TYPE = 0x42;
+
+ /**
+ * Represents the OBEX Length header. This is the length of the object in
+ * bytes.
+ * <P>
+ * The value of <code>LENGTH</code> is 0xC3 (195).
+ */
+ public static final int LENGTH = 0xC3;
+
+ /**
+ * Represents the OBEX Time header using the ISO 8601 standards. This is the
+ * preferred time header.
+ * <P>
+ * The value of <code>TIME_ISO_8601</code> is 0x44 (68).
+ */
+ public static final int TIME_ISO_8601 = 0x44;
+
+ /**
+ * Represents the OBEX Time header using the 4 byte representation. This is
+ * only included for backwards compatibility. It represents the number of
+ * seconds since January 1, 1970.
+ * <P>
+ * The value of <code>TIME_4_BYTE</code> is 0xC4 (196).
+ */
+ public static final int TIME_4_BYTE = 0xC4;
+
+ /**
+ * Represents the OBEX Description header. This is a text description of the
+ * object.
+ * <P>
+ * The value of <code>DESCRIPTION</code> is 0x05 (5).
+ */
+ public static final int DESCRIPTION = 0x05;
+
+ /**
+ * Represents the OBEX Target header. This is the name of the service an
+ * operation is targeted to.
+ * <P>
+ * The value of <code>TARGET</code> is 0x46 (70).
+ */
+ public static final int TARGET = 0x46;
+
+ /**
+ * Represents the OBEX HTTP header. This allows an HTTP 1.X header to be
+ * included in a request or reply.
+ * <P>
+ * The value of <code>HTTP</code> is 0x47 (71).
+ */
+ public static final int HTTP = 0x47;
+
+ /**
+ * Represents the OBEX BODY header.
+ * <P>
+ * The value of <code>BODY</code> is 0x48 (72).
+ */
+ public static final int BODY = 0x48;
+
+ /**
+ * Represents the OBEX End of BODY header.
+ * <P>
+ * The value of <code>BODY</code> is 0x49 (73).
+ */
+ public static final int END_OF_BODY = 0x49;
+
+ /**
+ * Represents the OBEX Who header. Identifies the OBEX application to
+ * determine if the two peers are talking to each other.
+ * <P>
+ * The value of <code>WHO</code> is 0x4A (74).
+ */
+ public static final int WHO = 0x4A;
+
+ /**
+ * Represents the OBEX Connection ID header. Identifies used for OBEX
+ * connection multiplexing.
+ * <P>
+ * The value of <code>CONNECTION_ID</code> is 0xCB (203).
+ */
+
+ public static final int CONNECTION_ID = 0xCB;
+
+ /**
+ * Represents the OBEX Application Parameter header. This header specifies
+ * additional application request and response information.
+ * <P>
+ * The value of <code>APPLICATION_PARAMETER</code> is 0x4C (76).
+ */
+ public static final int APPLICATION_PARAMETER = 0x4C;
+
+ /**
+ * Represents the OBEX authentication digest-challenge.
+ * <P>
+ * The value of <code>AUTH_CHALLENGE</code> is 0x4D (77).
+ */
+ public static final int AUTH_CHALLENGE = 0x4D;
+
+ /**
+ * Represents the OBEX authentication digest-response.
+ * <P>
+ * The value of <code>AUTH_RESPONSE</code> is 0x4E (78).
+ */
+ public static final int AUTH_RESPONSE = 0x4E;
+
+ /**
+ * Represents the OBEX Object Class header. This header specifies the OBEX
+ * object class of the object.
+ * <P>
+ * The value of <code>OBJECT_CLASS</code> is 0x4F (79).
+ */
+ public static final int OBJECT_CLASS = 0x4F;
+
+ private Long mCount; // 4 byte unsigned integer
+
+ private String mName; // null terminated Unicode text string
+
+ private String mType; // null terminated ASCII text string
+
+ private Long mLength; // 4 byte unsigend integer
+
+ private Calendar mIsoTime; // String of the form YYYYMMDDTHHMMSSZ
+
+ private Calendar mByteTime; // 4 byte unsigned integer
+
+ private String mDescription; // null terminated Unicode text String
+
+ private byte[] mTarget; // byte sequence
+
+ private byte[] mHttpHeader; // byte sequence
+
+ private byte[] mWho; // length prefixed byte sequence
+
+ private byte[] mAppParam; // byte sequence of the form tag length value
+
+ private byte[] mObjectClass; // byte sequence
+
+ private String[] mUnicodeUserDefined; //null terminated unicode string
+
+ private byte[][] mSequenceUserDefined; // byte sequence user defined
+
+ private Byte[] mByteUserDefined; // 1 byte
+
+ private Long[] mIntegerUserDefined; // 4 byte unsigned integer
+
+ private final Random mRandom;
+
+ /*package*/ byte[] nonce;
+
+ public byte[] mAuthChall; // The authentication challenge header
+
+ public byte[] mAuthResp; // The authentication response header
+
+ public byte[] mConnectionID; // THe connection ID
+
+ public int responseCode;
+
+ /**
+ * Creates new <code>HeaderSet</code> object.
+ * @param size the max packet size for this connection
+ */
+ public HeaderSet() {
+ mUnicodeUserDefined = new String[16];
+ mSequenceUserDefined = new byte[16][];
+ mByteUserDefined = new Byte[16];
+ mIntegerUserDefined = new Long[16];
+ responseCode = -1;
+ mRandom = new Random();
+ }
+
+ /**
+ * Sets the value of the header identifier to the value provided. The type
+ * of object must correspond to the Java type defined in the description of
+ * this interface. If <code>null</code> is passed as the
+ * <code>headerValue</code> then the header will be removed from the set of
+ * headers to include in the next request.
+ * @param headerID the identifier to include in the message
+ * @param headerValue the value of the header identifier
+ * @throws IllegalArgumentException if the header identifier provided is not
+ * one defined in this interface or a user-defined header; if the
+ * type of <code>headerValue</code> is not the correct Java type as
+ * defined in the description of this interface\
+ */
+ public void setHeader(int headerID, Object headerValue) {
+ long temp = -1;
+
+ switch (headerID) {
+ case COUNT:
+ if (!(headerValue instanceof Long)) {
+ if (headerValue == null) {
+ mCount = null;
+ break;
+ }
+ throw new IllegalArgumentException("Count must be a Long");
+ }
+ temp = ((Long)headerValue).longValue();
+ if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
+ throw new IllegalArgumentException("Count must be between 0 and 0xFFFFFFFF");
+ }
+ mCount = (Long)headerValue;
+ break;
+ case NAME:
+ if ((headerValue != null) && (!(headerValue instanceof String))) {
+ throw new IllegalArgumentException("Name must be a String");
+ }
+ mName = (String)headerValue;
+ break;
+ case TYPE:
+ if ((headerValue != null) && (!(headerValue instanceof String))) {
+ throw new IllegalArgumentException("Type must be a String");
+ }
+ mType = (String)headerValue;
+ break;
+ case LENGTH:
+ if (!(headerValue instanceof Long)) {
+ if (headerValue == null) {
+ mLength = null;
+ break;
+ }
+ throw new IllegalArgumentException("Length must be a Long");
+ }
+ temp = ((Long)headerValue).longValue();
+ if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
+ throw new IllegalArgumentException("Length must be between 0 and 0xFFFFFFFF");
+ }
+ mLength = (Long)headerValue;
+ break;
+ case TIME_ISO_8601:
+ if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
+ throw new IllegalArgumentException("Time ISO 8601 must be a Calendar");
+ }
+ mIsoTime = (Calendar)headerValue;
+ break;
+ case TIME_4_BYTE:
+ if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
+ throw new IllegalArgumentException("Time 4 Byte must be a Calendar");
+ }
+ mByteTime = (Calendar)headerValue;
+ break;
+ case DESCRIPTION:
+ if ((headerValue != null) && (!(headerValue instanceof String))) {
+ throw new IllegalArgumentException("Description must be a String");
+ }
+ mDescription = (String)headerValue;
+ break;
+ case TARGET:
+ if (headerValue == null) {
+ mTarget = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException("Target must be a byte array");
+ } else {
+ mTarget = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mTarget, 0, mTarget.length);
+ }
+ }
+ break;
+ case HTTP:
+ if (headerValue == null) {
+ mHttpHeader = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException("HTTP must be a byte array");
+ } else {
+ mHttpHeader = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mHttpHeader, 0, mHttpHeader.length);
+ }
+ }
+ break;
+ case WHO:
+ if (headerValue == null) {
+ mWho = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException("WHO must be a byte array");
+ } else {
+ mWho = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mWho, 0, mWho.length);
+ }
+ }
+ break;
+ case OBJECT_CLASS:
+ if (headerValue == null) {
+ mObjectClass = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException("Object Class must be a byte array");
+ } else {
+ mObjectClass = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mObjectClass, 0, mObjectClass.length);
+ }
+ }
+ break;
+ case APPLICATION_PARAMETER:
+ if (headerValue == null) {
+ mAppParam = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException(
+ "Application Parameter must be a byte array");
+ } else {
+ mAppParam = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mAppParam, 0, mAppParam.length);
+ }
+ }
+ break;
+ default:
+ // Verify that it was not a Unicode String user Defined
+ if ((headerID >= 0x30) && (headerID <= 0x3F)) {
+ if ((headerValue != null) && (!(headerValue instanceof String))) {
+ throw new IllegalArgumentException(
+ "Unicode String User Defined must be a String");
+ }
+ mUnicodeUserDefined[headerID - 0x30] = (String)headerValue;
+
+ break;
+ }
+ // Verify that it was not a byte sequence user defined value
+ if ((headerID >= 0x70) && (headerID <= 0x7F)) {
+
+ if (headerValue == null) {
+ mSequenceUserDefined[headerID - 0x70] = null;
+ } else {
+ if (!(headerValue instanceof byte[])) {
+ throw new IllegalArgumentException(
+ "Byte Sequence User Defined must be a byte array");
+ } else {
+ mSequenceUserDefined[headerID - 0x70] = new byte[((byte[])headerValue).length];
+ System.arraycopy(headerValue, 0, mSequenceUserDefined[headerID - 0x70],
+ 0, mSequenceUserDefined[headerID - 0x70].length);
+ }
+ }
+ break;
+ }
+ // Verify that it was not a Byte user Defined
+ if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
+ if ((headerValue != null) && (!(headerValue instanceof Byte))) {
+ throw new IllegalArgumentException("ByteUser Defined must be a Byte");
+ }
+ mByteUserDefined[headerID - 0xB0] = (Byte)headerValue;
+
+ break;
+ }
+ // Verify that is was not the 4 byte unsigned integer user
+ // defined header
+ if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
+ if (!(headerValue instanceof Long)) {
+ if (headerValue == null) {
+ mIntegerUserDefined[headerID - 0xF0] = null;
+ break;
+ }
+ throw new IllegalArgumentException("Integer User Defined must be a Long");
+ }
+ temp = ((Long)headerValue).longValue();
+ if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
+ throw new IllegalArgumentException(
+ "Integer User Defined must be between 0 and 0xFFFFFFFF");
+ }
+ mIntegerUserDefined[headerID - 0xF0] = (Long)headerValue;
+ break;
+ }
+ throw new IllegalArgumentException("Invalid Header Identifier");
+ }
+ }
+
+ /**
+ * Retrieves the value of the header identifier provided. The type of the
+ * Object returned is defined in the description of this interface.
+ * @param headerID the header identifier whose value is to be returned
+ * @return the value of the header provided or <code>null</code> if the
+ * header identifier specified is not part of this
+ * <code>HeaderSet</code> object
+ * @throws IllegalArgumentException if the <code>headerID</code> is not one
+ * defined in this interface or any of the user-defined headers
+ * @throws IOException if an error occurred in the transport layer during
+ * the operation or if the connection has been closed
+ */
+ public Object getHeader(int headerID) throws IOException {
+
+ switch (headerID) {
+ case COUNT:
+ return mCount;
+ case NAME:
+ return mName;
+ case TYPE:
+ return mType;
+ case LENGTH:
+ return mLength;
+ case TIME_ISO_8601:
+ return mIsoTime;
+ case TIME_4_BYTE:
+ return mByteTime;
+ case DESCRIPTION:
+ return mDescription;
+ case TARGET:
+ return mTarget;
+ case HTTP:
+ return mHttpHeader;
+ case WHO:
+ return mWho;
+ case OBJECT_CLASS:
+ return mObjectClass;
+ case APPLICATION_PARAMETER:
+ return mAppParam;
+ default:
+ // Verify that it was not a Unicode String user Defined
+ if ((headerID >= 0x30) && (headerID <= 0x3F)) {
+ return mUnicodeUserDefined[headerID - 0x30];
+ }
+ // Verify that it was not a byte sequence user defined header
+ if ((headerID >= 0x70) && (headerID <= 0x7F)) {
+ return mSequenceUserDefined[headerID - 0x70];
+ }
+ // Verify that it was not a byte user defined header
+ if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
+ return mByteUserDefined[headerID - 0xB0];
+ }
+ // Verify that it was not a integer user defined header
+ if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
+ return mIntegerUserDefined[headerID - 0xF0];
+ }
+ throw new IllegalArgumentException("Invalid Header Identifier");
+ }
+ }
+
+ /**
+ * Retrieves the list of headers that may be retrieved via the
+ * <code>getHeader</code> method that will not return <code>null</code>. In
+ * other words, this method returns all the headers that are available in
+ * this object.
+ * @see #getHeader
+ * @return the array of headers that are set in this object or
+ * <code>null</code> if no headers are available
+ * @throws IOException if an error occurred in the transport layer during
+ * the operation or the connection has been closed
+ */
+ public int[] getHeaderList() throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ if (mCount != null) {
+ out.write(COUNT);
+ }
+ if (mName != null) {
+ out.write(NAME);
+ }
+ if (mType != null) {
+ out.write(TYPE);
+ }
+ if (mLength != null) {
+ out.write(LENGTH);
+ }
+ if (mIsoTime != null) {
+ out.write(TIME_ISO_8601);
+ }
+ if (mByteTime != null) {
+ out.write(TIME_4_BYTE);
+ }
+ if (mDescription != null) {
+ out.write(DESCRIPTION);
+ }
+ if (mTarget != null) {
+ out.write(TARGET);
+ }
+ if (mHttpHeader != null) {
+ out.write(HTTP);
+ }
+ if (mWho != null) {
+ out.write(WHO);
+ }
+ if (mAppParam != null) {
+ out.write(APPLICATION_PARAMETER);
+ }
+ if (mObjectClass != null) {
+ out.write(OBJECT_CLASS);
+ }
+
+ for (int i = 0x30; i < 0x40; i++) {
+ if (mUnicodeUserDefined[i - 0x30] != null) {
+ out.write(i);
+ }
+ }
+
+ for (int i = 0x70; i < 0x80; i++) {
+ if (mSequenceUserDefined[i - 0x70] != null) {
+ out.write(i);
+ }
+ }
+
+ for (int i = 0xB0; i < 0xC0; i++) {
+ if (mByteUserDefined[i - 0xB0] != null) {
+ out.write(i);
+ }
+ }
+
+ for (int i = 0xF0; i < 0x100; i++) {
+ if (mIntegerUserDefined[i - 0xF0] != null) {
+ out.write(i);
+ }
+ }
+
+ byte[] headers = out.toByteArray();
+ out.close();
+
+ if ((headers == null) || (headers.length == 0)) {
+ return null;
+ }
+
+ int[] result = new int[headers.length];
+ for (int i = 0; i < headers.length; i++) {
+ // Convert the byte to a positive integer. That is, an integer
+ // between 0 and 256.
+ result[i] = headers[i] & 0xFF;
+ }
+
+ return result;
+ }
+
+ /**
+ * Sets the authentication challenge header. The <code>realm</code> will be
+ * encoded based upon the default encoding scheme used by the implementation
+ * to encode strings. Therefore, the encoding scheme used to encode the
+ * <code>realm</code> is application dependent.
+ * @param realm a short description that describes what password to use; if
+ * <code>null</code> no realm will be sent in the authentication
+ * challenge header
+ * @param userID if <code>true</code>, a user ID is required in the reply;
+ * if <code>false</code>, no user ID is required
+ * @param access if <code>true</code> then full access will be granted if
+ * successful; if <code>false</code> then read-only access will be
+ * granted if successful
+ * @throws IOException
+ */
+ public void createAuthenticationChallenge(String realm, boolean userID, boolean access)
+ throws IOException {
+
+ nonce = new byte[16];
+ for (int i = 0; i < 16; i++) {
+ nonce[i] = (byte)mRandom.nextInt();
+ }
+
+ mAuthChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
+ }
+
+ /**
+ * Returns the response code received from the server. Response codes are
+ * defined in the <code>ResponseCodes</code> class.
+ * @see ResponseCodes
+ * @return the response code retrieved from the server
+ * @throws IOException if an error occurred in the transport layer during
+ * the transaction; if this method is called on a
+ * <code>HeaderSet</code> object created by calling
+ * <code>createHeaderSet()</code> in a <code>ClientSession</code>
+ * object; if this object was created by an OBEX server
+ */
+ public int getResponseCode() throws IOException {
+ if (responseCode == -1) {
+ throw new IOException("May not be called on a server");
+ } else {
+ return responseCode;
+ }
+ }
+}
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
new file mode 100644
index 0000000..1b66662
--- /dev/null
+++ b/obex/javax/obex/ObexHelper.java
@@ -0,0 +1,995 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import android.security.Md5MessageDigest;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * This class defines a set of helper methods for the implementation of Obex.
+ * @hide
+ */
+public final class ObexHelper {
+
+ /**
+ * Defines the basic packet length used by OBEX. Every OBEX packet has the
+ * same basic format:<BR>
+ * Byte 0: Request or Response Code Byte 1&2: Length of the packet.
+ */
+ public static final int BASE_PACKET_LENGTH = 3;
+
+ /** Prevent object construction of helper class */
+ private ObexHelper() {
+ }
+
+ /**
+ * The maximum packet size for OBEX packets that this client can handle. At
+ * present, this must be changed for each port. TODO: The max packet size
+ * should be the Max incoming MTU minus TODO: L2CAP package headers and
+ * RFCOMM package headers. TODO: Retrieve the max incoming MTU from TODO:
+ * LocalDevice.getProperty().
+ */
+ /*
+ * android note set as 0xFFFE to match remote MPS
+ */
+ public static final int MAX_PACKET_SIZE_INT = 0xFFFE;
+
+ public static final int OBEX_OPCODE_CONNECT = 0x80;
+
+ public static final int OBEX_OPCODE_DISCONNECT = 0x81;
+
+ public static final int OBEX_OPCODE_PUT = 0x02;
+
+ public static final int OBEX_OPCODE_PUT_FINAL = 0x82;
+
+ public static final int OBEX_OPCODE_GET = 0x03;
+
+ public static final int OBEX_OPCODE_GET_FINAL = 0x83;
+
+ public static final int OBEX_OPCODE_RESERVED = 0x04;
+
+ public static final int OBEX_OPCODE_RESERVED_FINAL = 0x84;
+
+ public static final int OBEX_OPCODE_SETPATH = 0x85;
+
+ public static final int OBEX_OPCODE_ABORT = 0xFF;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ASCII = 0x00;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_1 = 0x01;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_2 = 0x02;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_3 = 0x03;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_4 = 0x04;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_5 = 0x05;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_6 = 0x06;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_7 = 0x07;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_8 = 0x08;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_ISO_8859_9 = 0x09;
+
+ public static final int OBEX_AUTH_REALM_CHARSET_UNICODE = 0xFF;
+
+ /**
+ * Updates the HeaderSet with the headers received in the byte array
+ * provided. Invalid headers are ignored.
+ * <P>
+ * The first two bits of an OBEX Header specifies the type of object that is
+ * being sent. The table below specifies the meaning of the high bits.
+ * <TABLE>
+ * <TR>
+ * <TH>Bits 8 and 7</TH>
+ * <TH>Value</TH>
+ * <TH>Description</TH>
+ * </TR>
+ * <TR>
+ * <TD>00</TD>
+ * <TD>0x00</TD>
+ * <TD>Null Terminated Unicode text, prefixed with 2 byte unsigned integer</TD>
+ * </TR>
+ * <TR>
+ * <TD>01</TD>
+ * <TD>0x40</TD>
+ * <TD>Byte Sequence, length prefixed with 2 byte unsigned integer</TD>
+ * </TR>
+ * <TR>
+ * <TD>10</TD>
+ * <TD>0x80</TD>
+ * <TD>1 byte quantity</TD>
+ * </TR>
+ * <TR>
+ * <TD>11</TD>
+ * <TD>0xC0</TD>
+ * <TD>4 byte quantity - transmitted in network byte order (high byte first</TD>
+ * </TR>
+ * </TABLE>
+ * This method uses the information in this table to determine the type of
+ * Java object to create and passes that object with the full header to
+ * setHeader() to update the HeaderSet object. Invalid headers will cause an
+ * exception to be thrown. When it is thrown, it is ignored.
+ * @param header the HeaderSet to update
+ * @param headerArray the byte array containing headers
+ * @return the result of the last start body or end body header provided;
+ * the first byte in the result will specify if a body or end of
+ * body is received
+ * @throws IOException if an invalid header was found
+ */
+ public static byte[] updateHeaderSet(HeaderSet header, byte[] headerArray) throws IOException {
+ int index = 0;
+ int length = 0;
+ int headerID;
+ byte[] value = null;
+ byte[] body = null;
+ HeaderSet headerImpl = header;
+ try {
+ while (index < headerArray.length) {
+ headerID = 0xFF & headerArray[index];
+ switch (headerID & (0xC0)) {
+
+ /*
+ * 0x00 is a unicode null terminate string with the first
+ * two bytes after the header identifier being the length
+ */
+ case 0x00:
+ // Fall through
+ /*
+ * 0x40 is a byte sequence with the first
+ * two bytes after the header identifier being the length
+ */
+ case 0x40:
+ boolean trimTail = true;
+ index++;
+ length = 0xFF & headerArray[index];
+ length = length << 8;
+ index++;
+ length += 0xFF & headerArray[index];
+ length -= 3;
+ index++;
+ value = new byte[length];
+ System.arraycopy(headerArray, index, value, 0, length);
+ if (length == 0 || (length > 0 && (value[length - 1] != 0))) {
+ trimTail = false;
+ }
+ switch (headerID) {
+ case HeaderSet.TYPE:
+ try {
+ // Remove trailing null
+ if (trimTail == false) {
+ headerImpl.setHeader(headerID, new String(value, 0,
+ value.length, "ISO8859_1"));
+ } else {
+ headerImpl.setHeader(headerID, new String(value, 0,
+ value.length - 1, "ISO8859_1"));
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw e;
+ }
+ break;
+
+ case HeaderSet.AUTH_CHALLENGE:
+ headerImpl.mAuthChall = new byte[length];
+ System.arraycopy(headerArray, index, headerImpl.mAuthChall, 0,
+ length);
+ break;
+
+ case HeaderSet.AUTH_RESPONSE:
+ headerImpl.mAuthResp = new byte[length];
+ System.arraycopy(headerArray, index, headerImpl.mAuthResp, 0,
+ length);
+ break;
+
+ case HeaderSet.BODY:
+ /* Fall Through */
+ case HeaderSet.END_OF_BODY:
+ body = new byte[length + 1];
+ body[0] = (byte)headerID;
+ System.arraycopy(headerArray, index, body, 1, length);
+ break;
+
+ case HeaderSet.TIME_ISO_8601:
+ try {
+ String dateString = new String(value, "ISO8859_1");
+ Calendar temp = Calendar.getInstance();
+ if ((dateString.length() == 16)
+ && (dateString.charAt(15) == 'Z')) {
+ temp.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+ temp.set(Calendar.YEAR, Integer.parseInt(dateString.substring(
+ 0, 4)));
+ temp.set(Calendar.MONTH, Integer.parseInt(dateString.substring(
+ 4, 6)));
+ temp.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateString
+ .substring(6, 8)));
+ temp.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dateString
+ .substring(9, 11)));
+ temp.set(Calendar.MINUTE, Integer.parseInt(dateString
+ .substring(11, 13)));
+ temp.set(Calendar.SECOND, Integer.parseInt(dateString
+ .substring(13, 15)));
+ headerImpl.setHeader(HeaderSet.TIME_ISO_8601, temp);
+ } catch (UnsupportedEncodingException e) {
+ throw e;
+ }
+ break;
+
+ default:
+ if ((headerID & 0xC0) == 0x00) {
+ headerImpl.setHeader(headerID, ObexHelper.convertToUnicode(
+ value, true));
+ } else {
+ headerImpl.setHeader(headerID, value);
+ }
+ }
+
+ index += length;
+ break;
+
+ /*
+ * 0x80 is a byte header. The only valid byte headers are
+ * the 16 user defined byte headers.
+ */
+ case 0x80:
+ index++;
+ try {
+ headerImpl.setHeader(headerID, Byte.valueOf(headerArray[index]));
+ } catch (Exception e) {
+ // Not a valid header so ignore
+ }
+ index++;
+ break;
+
+ /*
+ * 0xC0 is a 4 byte unsigned integer header and with the
+ * exception of TIME_4_BYTE will be converted to a Long
+ * and added.
+ */
+ case 0xC0:
+ index++;
+ value = new byte[4];
+ System.arraycopy(headerArray, index, value, 0, 4);
+ try {
+ if (headerID != HeaderSet.TIME_4_BYTE) {
+ // Determine if it is a connection ID. These
+ // need to be handled differently
+ if (headerID == HeaderSet.CONNECTION_ID) {
+ headerImpl.mConnectionID = new byte[4];
+ System.arraycopy(value, 0, headerImpl.mConnectionID, 0, 4);
+ } else {
+ headerImpl.setHeader(headerID, Long
+ .valueOf(convertToLong(value)));
+ }
+ } else {
+ Calendar temp = Calendar.getInstance();
+ temp.setTime(new Date(convertToLong(value) * 1000L));
+ headerImpl.setHeader(HeaderSet.TIME_4_BYTE, temp);
+ }
+ } catch (Exception e) {
+ // Not a valid header so ignore
+ throw new IOException("Header was not formatted properly");
+ }
+ index += 4;
+ break;
+ }
+
+ }
+ } catch (IOException e) {
+ throw new IOException("Header was not formatted properly");
+ }
+
+ return body;
+ }
+
+ /**
+ * Creates the header part of OBEX packet based on the header provided.
+ * TODO: Could use getHeaderList() to get the array of headers to include
+ * and then use the high two bits to determine the the type of the object
+ * and construct the byte array from that. This will make the size smaller.
+ * @param head the header used to construct the byte array
+ * @param nullOut <code>true</code> if the header should be set to
+ * <code>null</code> once it is added to the array or
+ * <code>false</code> if it should not be nulled out
+ * @return the header of an OBEX packet
+ */
+ public static byte[] createHeader(HeaderSet head, boolean nullOut) {
+ Long intHeader = null;
+ String stringHeader = null;
+ Calendar dateHeader = null;
+ Byte byteHeader = null;
+ StringBuffer buffer = null;
+ byte[] value = null;
+ byte[] result = null;
+ byte[] lengthArray = new byte[2];
+ int length;
+ HeaderSet headImpl = null;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ headImpl = head;
+
+ try {
+ /*
+ * Determine if there is a connection ID to send. If there is,
+ * then it should be the first header in the packet.
+ */
+ if ((headImpl.mConnectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
+
+ out.write((byte)HeaderSet.CONNECTION_ID);
+ out.write(headImpl.mConnectionID);
+ }
+
+ // Count Header
+ intHeader = (Long)headImpl.getHeader(HeaderSet.COUNT);
+ if (intHeader != null) {
+ out.write((byte)HeaderSet.COUNT);
+ value = ObexHelper.convertToByteArray(intHeader.longValue());
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.COUNT, null);
+ }
+ }
+
+ // Name Header
+ stringHeader = (String)headImpl.getHeader(HeaderSet.NAME);
+ if (stringHeader != null) {
+ out.write((byte)HeaderSet.NAME);
+ value = ObexHelper.convertToUnicodeByteArray(stringHeader);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(0xFF & (length >> 8));
+ lengthArray[1] = (byte)(0xFF & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.NAME, null);
+ }
+ }
+
+ // Type Header
+ stringHeader = (String)headImpl.getHeader(HeaderSet.TYPE);
+ if (stringHeader != null) {
+ out.write((byte)HeaderSet.TYPE);
+ try {
+ value = stringHeader.getBytes("ISO8859_1");
+ } catch (UnsupportedEncodingException e) {
+ throw e;
+ }
+
+ length = value.length + 4;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ out.write(0x00);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.TYPE, null);
+ }
+ }
+
+ // Length Header
+ intHeader = (Long)headImpl.getHeader(HeaderSet.LENGTH);
+ if (intHeader != null) {
+ out.write((byte)HeaderSet.LENGTH);
+ value = ObexHelper.convertToByteArray(intHeader.longValue());
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.LENGTH, null);
+ }
+ }
+
+ // Time ISO Header
+ dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_ISO_8601);
+ if (dateHeader != null) {
+
+ /*
+ * The ISO Header should take the form YYYYMMDDTHHMMSSZ. The
+ * 'Z' will only be included if it is a UTC time.
+ */
+ buffer = new StringBuffer();
+ int temp = dateHeader.get(Calendar.YEAR);
+ for (int i = temp; i < 1000; i = i * 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+ temp = dateHeader.get(Calendar.MONTH);
+ if (temp < 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+ temp = dateHeader.get(Calendar.DAY_OF_MONTH);
+ if (temp < 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+ buffer.append("T");
+ temp = dateHeader.get(Calendar.HOUR_OF_DAY);
+ if (temp < 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+ temp = dateHeader.get(Calendar.MINUTE);
+ if (temp < 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+ temp = dateHeader.get(Calendar.SECOND);
+ if (temp < 10) {
+ buffer.append("0");
+ }
+ buffer.append(temp);
+
+ if (dateHeader.getTimeZone().getID().equals("UTC")) {
+ buffer.append("Z");
+ }
+
+ try {
+ value = buffer.toString().getBytes("ISO8859_1");
+ } catch (UnsupportedEncodingException e) {
+ throw e;
+ }
+
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(HeaderSet.TIME_ISO_8601);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.TIME_ISO_8601, null);
+ }
+ }
+
+ // Time 4 Byte Header
+ dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_4_BYTE);
+ if (dateHeader != null) {
+ out.write(HeaderSet.TIME_4_BYTE);
+
+ /*
+ * Need to call getTime() twice. The first call will return
+ * a java.util.Date object. The second call returns the number
+ * of milliseconds since January 1, 1970. We need to convert
+ * it to seconds since the TIME_4_BYTE expects the number of
+ * seconds since January 1, 1970.
+ */
+ value = ObexHelper.convertToByteArray(dateHeader.getTime().getTime() / 1000L);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.TIME_4_BYTE, null);
+ }
+ }
+
+ // Description Header
+ stringHeader = (String)headImpl.getHeader(HeaderSet.DESCRIPTION);
+ if (stringHeader != null) {
+ out.write((byte)HeaderSet.DESCRIPTION);
+ value = ObexHelper.convertToUnicodeByteArray(stringHeader);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.DESCRIPTION, null);
+ }
+ }
+
+ // Target Header
+ value = (byte[])headImpl.getHeader(HeaderSet.TARGET);
+ if (value != null) {
+ out.write((byte)HeaderSet.TARGET);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.TARGET, null);
+ }
+ }
+
+ // HTTP Header
+ value = (byte[])headImpl.getHeader(HeaderSet.HTTP);
+ if (value != null) {
+ out.write((byte)HeaderSet.HTTP);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.HTTP, null);
+ }
+ }
+
+ // Who Header
+ value = (byte[])headImpl.getHeader(HeaderSet.WHO);
+ if (value != null) {
+ out.write((byte)HeaderSet.WHO);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.WHO, null);
+ }
+ }
+
+ // Connection ID Header
+ value = (byte[])headImpl.getHeader(HeaderSet.APPLICATION_PARAMETER);
+ if (value != null) {
+ out.write((byte)HeaderSet.APPLICATION_PARAMETER);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.APPLICATION_PARAMETER, null);
+ }
+ }
+
+ // Object Class Header
+ value = (byte[])headImpl.getHeader(HeaderSet.OBJECT_CLASS);
+ if (value != null) {
+ out.write((byte)HeaderSet.OBJECT_CLASS);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(HeaderSet.OBJECT_CLASS, null);
+ }
+ }
+
+ // Check User Defined Headers
+ for (int i = 0; i < 16; i++) {
+
+ //Unicode String Header
+ stringHeader = (String)headImpl.getHeader(i + 0x30);
+ if (stringHeader != null) {
+ out.write((byte)i + 0x30);
+ value = ObexHelper.convertToUnicodeByteArray(stringHeader);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(i + 0x30, null);
+ }
+ }
+
+ // Byte Sequence Header
+ value = (byte[])headImpl.getHeader(i + 0x70);
+ if (value != null) {
+ out.write((byte)i + 0x70);
+ length = value.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(value);
+ if (nullOut) {
+ headImpl.setHeader(i + 0x70, null);
+ }
+ }
+
+ // Byte Header
+ byteHeader = (Byte)headImpl.getHeader(i + 0xB0);
+ if (byteHeader != null) {
+ out.write((byte)i + 0xB0);
+ out.write(byteHeader.byteValue());
+ if (nullOut) {
+ headImpl.setHeader(i + 0xB0, null);
+ }
+ }
+
+ // Integer header
+ intHeader = (Long)headImpl.getHeader(i + 0xF0);
+ if (intHeader != null) {
+ out.write((byte)i + 0xF0);
+ out.write(ObexHelper.convertToByteArray(intHeader.longValue()));
+ if (nullOut) {
+ headImpl.setHeader(i + 0xF0, null);
+ }
+ }
+ }
+
+ // Add the authentication challenge header
+ if (headImpl.mAuthChall != null) {
+ out.write((byte)HeaderSet.AUTH_CHALLENGE);
+ length = headImpl.mAuthChall.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(headImpl.mAuthChall);
+ if (nullOut) {
+ headImpl.mAuthChall = null;
+ }
+ }
+
+ // Add the authentication response header
+ if (headImpl.mAuthResp != null) {
+ out.write((byte)HeaderSet.AUTH_RESPONSE);
+ length = headImpl.mAuthResp.length + 3;
+ lengthArray[0] = (byte)(255 & (length >> 8));
+ lengthArray[1] = (byte)(255 & length);
+ out.write(lengthArray);
+ out.write(headImpl.mAuthResp);
+ if (nullOut) {
+ headImpl.mAuthResp = null;
+ }
+ }
+
+ } catch (IOException e) {
+ } finally {
+ result = out.toByteArray();
+ try {
+ out.close();
+ } catch (Exception ex) {
+ }
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Determines where the maximum divide is between headers. This method is
+ * used by put and get operations to separate headers to a size that meets
+ * the max packet size allowed.
+ * @param headerArray the headers to separate
+ * @param start the starting index to search
+ * @param maxSize the maximum size of a packet
+ * @return the index of the end of the header block to send or -1 if the
+ * header could not be divided because the header is too large
+ */
+ public static int findHeaderEnd(byte[] headerArray, int start, int maxSize) {
+
+ int fullLength = 0;
+ int lastLength = -1;
+ int index = start;
+ int length = 0;
+
+ while ((fullLength < maxSize) && (index < headerArray.length)) {
+ int headerID = (headerArray[index] < 0 ? headerArray[index] + 256 : headerArray[index]);
+ lastLength = fullLength;
+
+ switch (headerID & (0xC0)) {
+
+ case 0x00:
+ // Fall through
+ case 0x40:
+
+ index++;
+ length = (headerArray[index] < 0 ? headerArray[index] + 256
+ : headerArray[index]);
+ length = length << 8;
+ index++;
+ length += (headerArray[index] < 0 ? headerArray[index] + 256
+ : headerArray[index]);
+ length -= 3;
+ index++;
+ index += length;
+ fullLength += length + 3;
+ break;
+
+ case 0x80:
+
+ index++;
+ index++;
+ fullLength += 2;
+ break;
+
+ case 0xC0:
+
+ index += 5;
+ fullLength += 5;
+ break;
+
+ }
+
+ }
+
+ /*
+ * Determine if this is the last header or not
+ */
+ if (lastLength == 0) {
+ /*
+ * Since this is the last header, check to see if the size of this
+ * header is less then maxSize. If it is, return the length of the
+ * header, otherwise return -1. The length of the header is
+ * returned since it would be the start of the next header
+ */
+ if (fullLength < maxSize) {
+ return headerArray.length;
+ } else {
+ return -1;
+ }
+ } else {
+ return lastLength + start;
+ }
+ }
+
+ /**
+ * Converts the byte array to a long.
+ * @param b the byte array to convert to a long
+ * @return the byte array as a long
+ */
+ public static long convertToLong(byte[] b) {
+ long result = 0;
+ long value = 0;
+ long power = 0;
+
+ for (int i = (b.length - 1); i >= 0; i--) {
+ value = b[i];
+ if (value < 0) {
+ value += 256;
+ }
+
+ result = result | (value << power);
+ power += 8;
+ }
+
+ return result;
+ }
+
+ /**
+ * Converts the long to a 4 byte array. The long must be non negative.
+ * @param l the long to convert
+ * @return a byte array that is the same as the long
+ */
+ public static byte[] convertToByteArray(long l) {
+ byte[] b = new byte[4];
+
+ b[0] = (byte)(255 & (l >> 24));
+ b[1] = (byte)(255 & (l >> 16));
+ b[2] = (byte)(255 & (l >> 8));
+ b[3] = (byte)(255 & l);
+
+ return b;
+ }
+
+ /**
+ * Converts the String to a UNICODE byte array. It will also add the ending
+ * null characters to the end of the string.
+ * @param s the string to convert
+ * @return the unicode byte array of the string
+ */
+ public static byte[] convertToUnicodeByteArray(String s) {
+ if (s == null) {
+ return null;
+ }
+
+ char c[] = s.toCharArray();
+ byte[] result = new byte[(c.length * 2) + 2];
+ for (int i = 0; i < c.length; i++) {
+ result[(i * 2)] = (byte)(c[i] >> 8);
+ result[((i * 2) + 1)] = (byte)c[i];
+ }
+
+ // Add the UNICODE null character
+ result[result.length - 2] = 0;
+ result[result.length - 1] = 0;
+
+ return result;
+ }
+
+ /**
+ * Retrieves the value from the byte array for the tag value specified. The
+ * array should be of the form Tag - Length - Value triplet.
+ * @param tag the tag to retrieve from the byte array
+ * @param triplet the byte sequence containing the tag length value form
+ * @return the value of the specified tag
+ */
+ public static byte[] getTagValue(byte tag, byte[] triplet) {
+
+ int index = findTag(tag, triplet);
+ if (index == -1) {
+ return null;
+ }
+
+ index++;
+ int length = triplet[index] & 0xFF;
+
+ byte[] result = new byte[length];
+ index++;
+ System.arraycopy(triplet, index, result, 0, length);
+
+ return result;
+ }
+
+ /**
+ * Finds the index that starts the tag value pair in the byte array provide.
+ * @param tag the tag to look for
+ * @param value the byte array to search
+ * @return the starting index of the tag or -1 if the tag could not be found
+ */
+ public static int findTag(byte tag, byte[] value) {
+ int length = 0;
+
+ if (value == null) {
+ return -1;
+ }
+
+ int index = 0;
+
+ while ((index < value.length) && (value[index] != tag)) {
+ length = value[index + 1] & 0xFF;
+ index += length + 2;
+ }
+
+ if (index >= value.length) {
+ return -1;
+ }
+
+ return index;
+ }
+
+ /**
+ * Converts the byte array provided to a unicode string.
+ * @param b the byte array to convert to a string
+ * @param includesNull determine if the byte string provided contains the
+ * UNICODE null character at the end or not; if it does, it will be
+ * removed
+ * @return a Unicode string
+ * @throws IllegalArgumentException if the byte array has an odd length
+ */
+ public static String convertToUnicode(byte[] b, boolean includesNull) {
+ if (b == null || b.length == 0) {
+ return null;
+ }
+ int arrayLength = b.length;
+ if (!((arrayLength % 2) == 0)) {
+ throw new IllegalArgumentException("Byte array not of a valid form");
+ }
+ arrayLength = (arrayLength >> 1);
+ if (includesNull) {
+ arrayLength -= 1;
+ }
+
+ char[] c = new char[arrayLength];
+ for (int i = 0; i < arrayLength; i++) {
+ int upper = b[2 * i];
+ int lower = b[(2 * i) + 1];
+ if (upper < 0) {
+ upper += 256;
+ }
+ if (lower < 0) {
+ lower += 256;
+ }
+ // If upper and lower both equal 0, it should be the end of string.
+ // Ignore left bytes from array to avoid potential issues
+ if (upper == 0 && lower == 0) {
+ return new String(c, 0, i);
+ }
+
+ c[i] = (char)((upper << 8) | lower);
+ }
+
+ return new String(c);
+ }
+
+ /**
+ * Compute the MD5 hash of the byte array provided. Does not accumulate
+ * input.
+ * @param in the byte array to hash
+ * @return the MD5 hash of the byte array
+ */
+ public static byte[] computeMd5Hash(byte[] in) {
+ Md5MessageDigest md5 = new Md5MessageDigest();
+ return md5.digest(in);
+ }
+
+ /**
+ * Computes an authentication challenge header.
+ * @param nonce the challenge that will be provided to the peer; the
+ * challenge must be 16 bytes long
+ * @param realm a short description that describes what password to use
+ * @param access if <code>true</code> then full access will be granted if
+ * successful; if <code>false</code> then read only access will be
+ * granted if successful
+ * @param userID if <code>true</code>, a user ID is required in the reply;
+ * if <code>false</code>, no user ID is required
+ * @throws IllegalArgumentException if the challenge is not 16 bytes long;
+ * if the realm can not be encoded in less then 255 bytes
+ * @throws IOException if the encoding scheme ISO 8859-1 is not supported
+ */
+ public static byte[] computeAuthenticationChallenge(byte[] nonce, String realm, boolean access,
+ boolean userID) throws IOException {
+ byte[] authChall = null;
+
+ if (nonce.length != 16) {
+ throw new IllegalArgumentException("Nonce must be 16 bytes long");
+ }
+
+ /*
+ * The authentication challenge is a byte sequence of the following form
+ * byte 0: 0x00 - the tag for the challenge
+ * byte 1: 0x10 - the length of the challenge; must be 16
+ * byte 2-17: the authentication challenge
+ * byte 18: 0x01 - the options tag; this is optional in the spec, but
+ * we are going to include it in every message
+ * byte 19: 0x01 - length of the options; must be 1
+ * byte 20: the value of the options; bit 0 is set if user ID is
+ * required; bit 1 is set if access mode is read only
+ * byte 21: 0x02 - the tag for authentication realm; only included if
+ * an authentication realm is specified
+ * byte 22: the length of the authentication realm; only included if
+ * the authentication realm is specified
+ * byte 23: the encoding scheme of the authentication realm; we will use
+ * the ISO 8859-1 encoding scheme since it is part of the KVM
+ * byte 24 & up: the realm if one is specified.
+ */
+ if (realm == null) {
+ authChall = new byte[21];
+ } else {
+ if (realm.length() >= 255) {
+ throw new IllegalArgumentException("Realm must be less then 255 bytes");
+ }
+ authChall = new byte[24 + realm.length()];
+ authChall[21] = 0x02;
+ authChall[22] = (byte)(realm.length() + 1);
+ authChall[23] = 0x01; // ISO 8859-1 Encoding
+ System.arraycopy(realm.getBytes("ISO8859_1"), 0, authChall, 24, realm.length());
+ }
+
+ // Include the nonce field in the header
+ authChall[0] = 0x00;
+ authChall[1] = 0x10;
+ System.arraycopy(nonce, 0, authChall, 2, 16);
+
+ // Include the options header
+ authChall[18] = 0x01;
+ authChall[19] = 0x01;
+ authChall[20] = 0x00;
+
+ if (!access) {
+ authChall[20] = (byte)(authChall[20] | 0x02);
+ }
+ if (userID) {
+ authChall[20] = (byte)(authChall[20] | 0x01);
+ }
+
+ return authChall;
+ }
+}
diff --git a/obex/javax/obex/ObexSession.java b/obex/javax/obex/ObexSession.java
new file mode 100644
index 0000000..a7daeb5
--- /dev/null
+++ b/obex/javax/obex/ObexSession.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+
+/**
+ * The <code>ObexSession</code> interface characterizes the term
+ * "OBEX Connection" as defined in the IrDA Object Exchange Protocol v1.2, which
+ * could be the server-side view of an OBEX connection, or the client-side view
+ * of the same connection, which is established by server's accepting of a
+ * client issued "CONNECT".
+ * <P>
+ * This interface serves as the common super class for
+ * <CODE>ClientSession</CODE> and <CODE>ServerSession</CODE>.
+ * @hide
+ */
+public class ObexSession {
+
+ protected Authenticator mAuthenticator;
+
+ protected byte[] mChallengeDigest;
+
+ /**
+ * Called when the server received an authentication challenge header. This
+ * will cause the authenticator to handle the authentication challenge.
+ * @param header the header with the authentication challenge
+ * @return <code>true</code> if the last request should be resent;
+ * <code>false</code> if the last request should not be resent
+ * @throws IOException
+ */
+ public boolean handleAuthChall(HeaderSet header) throws IOException {
+ if (mAuthenticator == null) {
+ return false;
+ }
+
+ /*
+ * An authentication challenge is made up of one required and two
+ * optional tag length value triplets. The tag 0x00 is required to be in
+ * the authentication challenge and it represents the challenge digest
+ * that was received. The tag 0x01 is the options tag. This tag tracks
+ * if user ID is required and if full access will be granted. The tag
+ * 0x02 is the realm, which provides a description of which user name
+ * and password to use.
+ */
+ byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.mAuthChall);
+ byte[] option = ObexHelper.getTagValue((byte)0x01, header.mAuthChall);
+ byte[] description = ObexHelper.getTagValue((byte)0x02, header.mAuthChall);
+
+ String realm = null;
+ if (description != null) {
+ byte[] realmString = new byte[description.length - 1];
+ System.arraycopy(description, 1, realmString, 0, realmString.length);
+
+ switch (description[0] & 0xFF) {
+
+ case ObexHelper.OBEX_AUTH_REALM_CHARSET_ASCII:
+ // ASCII encoding
+ // Fall through
+ case ObexHelper.OBEX_AUTH_REALM_CHARSET_ISO_8859_1:
+ // ISO-8859-1 encoding
+ try {
+ realm = new String(realmString, "ISO8859_1");
+ } catch (Exception e) {
+ throw new IOException("Unsupported Encoding Scheme");
+ }
+ break;
+
+ case ObexHelper.OBEX_AUTH_REALM_CHARSET_UNICODE:
+ // UNICODE Encoding
+ realm = ObexHelper.convertToUnicode(realmString, false);
+ break;
+
+ default:
+ throw new IOException("Unsupported Encoding Scheme");
+ }
+ }
+
+ boolean isUserIDRequired = false;
+ boolean isFullAccess = true;
+ if (option != null) {
+ if ((option[0] & 0x01) != 0) {
+ isUserIDRequired = true;
+ }
+
+ if ((option[0] & 0x02) != 0) {
+ isFullAccess = false;
+ }
+ }
+
+ PasswordAuthentication result = null;
+ header.mAuthChall = null;
+
+ try {
+ result = mAuthenticator
+ .onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
+ } catch (Exception e) {
+ return false;
+ }
+
+ /*
+ * If no password is provided then we not resent the request
+ */
+ if (result == null) {
+ return false;
+ }
+
+ byte[] password = result.getPassword();
+ if (password == null) {
+ return false;
+ }
+
+ byte[] userName = result.getUserName();
+
+ /*
+ * Create the authentication response header. It includes 1 required and
+ * 2 option tag length value triples. The required triple has a tag of
+ * 0x00 and is the response digest. The first optional tag is 0x01 and
+ * represents the user ID. If no user ID is provided, then no user ID
+ * will be sent. The second optional tag is 0x02 and is the challenge
+ * that was received. This will always be sent
+ */
+ if (userName != null) {
+ header.mAuthResp = new byte[38 + userName.length];
+ header.mAuthResp[36] = (byte)0x01;
+ header.mAuthResp[37] = (byte)userName.length;
+ System.arraycopy(userName, 0, header.mAuthResp, 38, userName.length);
+ } else {
+ header.mAuthResp = new byte[36];
+ }
+
+ // Create the secret String
+ byte[] digest = new byte[challenge.length + password.length + 1];
+ System.arraycopy(challenge, 0, digest, 0, challenge.length);
+ // Insert colon between challenge and password
+ digest[challenge.length] = (byte)0x3A;
+ System.arraycopy(password, 0, digest, challenge.length + 1, password.length);
+
+ // Add the Response Digest
+ header.mAuthResp[0] = (byte)0x00;
+ header.mAuthResp[1] = (byte)0x10;
+
+ System.arraycopy(ObexHelper.computeMd5Hash(digest), 0, header.mAuthResp, 2, 16);
+
+ // Add the challenge
+ header.mAuthResp[18] = (byte)0x02;
+ header.mAuthResp[19] = (byte)0x10;
+ System.arraycopy(challenge, 0, header.mAuthResp, 20, 16);
+
+ return true;
+ }
+
+ /**
+ * Called when the server received an authentication response header. This
+ * will cause the authenticator to handle the authentication response.
+ * @param authResp the authentication response
+ * @return <code>true</code> if the response passed; <code>false</code> if
+ * the response failed
+ */
+ public boolean handleAuthResp(byte[] authResp) {
+ if (mAuthenticator == null) {
+ return false;
+ }
+ // get the correct password from the application
+ byte[] correctPassword = mAuthenticator.onAuthenticationResponse(ObexHelper.getTagValue(
+ (byte)0x01, authResp));
+ if (correctPassword == null) {
+ return false;
+ }
+
+ byte[] temp = new byte[correctPassword.length + 16];
+
+ System.arraycopy(mChallengeDigest, 0, temp, 0, 16);
+ System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
+
+ byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
+ byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
+
+ // compare the MD5 hash array .
+ for (int i = 0; i < 16; i++) {
+ if (correctResponse[i] != actualResponse[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/obex/javax/obex/ObexTransport.java b/obex/javax/obex/ObexTransport.java
new file mode 100644
index 0000000..445e267
--- /dev/null
+++ b/obex/javax/obex/ObexTransport.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * The <code>ObexTransport</code> interface defines the underlying transport
+ * connection which carries the OBEX protocol( such as TCP, RFCOMM device file
+ * exposed by Bluetooth or USB in kernel, RFCOMM socket emulated in Android
+ * platform, Irda). This interface provides an abstract layer to be used by the
+ * <code>ObexConnection</code>. Each kind of medium shall have its own
+ * implementation to wrap and follow the same interface.
+ * <P>
+ * See section 1.2.2 of IrDA Object Exchange Protocol specification.
+ * <P>
+ * Different kind of medium may have different construction - for example, the
+ * RFCOMM device file medium may be constructed from a file descriptor or simply
+ * a string while the TCP medium usually from a socket.
+ * @hide
+ */
+public interface ObexTransport {
+
+ void create() throws IOException;
+
+ void listen() throws IOException;
+
+ void close() throws IOException;
+
+ void connect() throws IOException;
+
+ void disconnect() throws IOException;
+
+ InputStream openInputStream() throws IOException;
+
+ OutputStream openOutputStream() throws IOException;
+
+ DataInputStream openDataInputStream() throws IOException;
+
+ DataOutputStream openDataOutputStream() throws IOException;
+
+}
diff --git a/obex/javax/obex/Operation.java b/obex/javax/obex/Operation.java
new file mode 100644
index 0000000..20653f2
--- /dev/null
+++ b/obex/javax/obex/Operation.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * The <code>Operation</code> interface provides ways to manipulate a single
+ * OBEX PUT or GET operation. The implementation of this interface sends OBEX
+ * packets as they are built. If during the operation the peer in the operation
+ * ends the operation, an <code>IOException</code> is thrown on the next read
+ * from the input stream, write to the output stream, or call to
+ * <code>sendHeaders()</code>.
+ * <P>
+ * <STRONG>Definition of methods inherited from <code>ContentConnection</code>
+ * </STRONG>
+ * <P>
+ * <code>getEncoding()</code> will always return <code>null</code>. <BR>
+ * <code>getLength()</code> will return the length specified by the OBEX Length
+ * header or -1 if the OBEX Length header was not included. <BR>
+ * <code>getType()</code> will return the value specified in the OBEX Type
+ * header or <code>null</code> if the OBEX Type header was not included.<BR>
+ * <P>
+ * <STRONG>How Headers are Handled</STRONG>
+ * <P>
+ * As headers are received, they may be retrieved through the
+ * <code>getReceivedHeaders()</code> method. If new headers are set during the
+ * operation, the new headers will be sent during the next packet exchange.
+ * <P>
+ * <STRONG>PUT example</STRONG>
+ * <P>
+ * <PRE>
+ * void putObjectViaOBEX(ClientSession conn, HeaderSet head, byte[] obj) throws IOException {
+ * // Include the length header
+ * head.setHeader(head.LENGTH, new Long(obj.length));
+ * // Initiate the PUT request
+ * Operation op = conn.put(head);
+ * // Open the output stream to put the object to it
+ * DataOutputStream out = op.openDataOutputStream();
+ * // Send the object to the server
+ * out.write(obj);
+ * // End the transaction
+ * out.close();
+ * op.close();
+ * }
+ * </PRE>
+ * <P>
+ * <STRONG>GET example</STRONG>
+ * <P>
+ * <PRE>
+ * byte[] getObjectViaOBEX(ClientSession conn, HeaderSet head) throws IOException {
+ * // Send the initial GET request to the server
+ * Operation op = conn.get(head);
+ * // Retrieve the length of the object being sent back
+ * int length = op.getLength();
+ * // Create space for the object
+ * byte[] obj = new byte[length];
+ * // Get the object from the input stream
+ * DataInputStream in = trans.openDataInputStream();
+ * in.read(obj);
+ * // End the transaction
+ * in.close();
+ * op.close();
+ * return obj;
+ * }
+ * </PRE>
+ *
+ * <H3>Client PUT Operation Flow</H3> For PUT operations, a call to
+ * <code>close()</code> the <code>OutputStream</code> returned from
+ * <code>openOutputStream()</code> or <code>openDataOutputStream()</code> will
+ * signal that the request is done. (In OBEX terms, the End-Of-Body header
+ * should be sent and the final bit in the request will be set.) At this point,
+ * the reply from the server may begin to be processed. A call to
+ * <code>getResponseCode()</code> will do an implicit close on the
+ * <code>OutputStream</code> and therefore signal that the request is done.
+ * <H3>Client GET Operation Flow</H3> For GET operation, a call to
+ * <code>openInputStream()</code> or <code>openDataInputStream()</code> will
+ * signal that the request is done. (In OBEX terms, the final bit in the request
+ * will be set.) A call to <code>getResponseCode()</code> will cause an implicit
+ * close on the <code>InputStream</code>. No further data may be read at this
+ * point.
+ * @hide
+ */
+public interface Operation {
+
+ /**
+ * Sends an ABORT message to the server. By calling this method, the
+ * corresponding input and output streams will be closed along with this
+ * object. No headers are sent in the abort request. This will end the
+ * operation since <code>close()</code> will be called by this method.
+ * @throws IOException if the transaction has already ended or if an OBEX
+ * server calls this method
+ */
+ void abort() throws IOException;
+
+ /**
+ * Returns the headers that have been received during the operation.
+ * Modifying the object returned has no effect on the headers that are sent
+ * or retrieved.
+ * @return the headers received during this <code>Operation</code>
+ * @throws IOException if this <code>Operation</code> has been closed
+ */
+ HeaderSet getReceivedHeader() throws IOException;
+
+ /**
+ * Specifies the headers that should be sent in the next OBEX message that
+ * is sent.
+ * @param headers the headers to send in the next message
+ * @throws IOException if this <code>Operation</code> has been closed or the
+ * transaction has ended and no further messages will be exchanged
+ * @throws IllegalArgumentException if <code>headers</code> was not created
+ * by a call to <code>ServerRequestHandler.createHeaderSet()</code>
+ * or <code>ClientSession.createHeaderSet()</code>
+ * @throws NullPointerException if <code>headers</code> if <code>null</code>
+ */
+ void sendHeaders(HeaderSet headers) throws IOException;
+
+ /**
+ * Returns the response code received from the server. Response codes are
+ * defined in the <code>ResponseCodes</code> class.
+ * @see ResponseCodes
+ * @return the response code retrieved from the server
+ * @throws IOException if an error occurred in the transport layer during
+ * the transaction; if this object was created by an OBEX server
+ */
+ int getResponseCode() throws IOException;
+
+ String getEncoding();
+
+ long getLength();
+
+ String getType();
+
+ InputStream openInputStream() throws IOException;
+
+ DataInputStream openDataInputStream() throws IOException;
+
+ OutputStream openOutputStream() throws IOException;
+
+ DataOutputStream openDataOutputStream() throws IOException;
+
+ void close() throws IOException;
+
+ int getMaxPacketSize();
+}
diff --git a/obex/javax/obex/PasswordAuthentication.java b/obex/javax/obex/PasswordAuthentication.java
new file mode 100644
index 0000000..326b1ff
--- /dev/null
+++ b/obex/javax/obex/PasswordAuthentication.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+/**
+ * This class holds user name and password combinations.
+ * @hide
+ */
+public final class PasswordAuthentication {
+
+ private byte[] mUserName;
+
+ private final byte[] mPassword;
+
+ /**
+ * Creates a new <code>PasswordAuthentication</code> with the user name and
+ * password provided.
+ * @param userName the user name to include; this may be <code>null</code>
+ * @param password the password to include in the response
+ * @throws NullPointerException if <code>password</code> is
+ * <code>null</code>
+ */
+ public PasswordAuthentication(final byte[] userName, final byte[] password) {
+ if (userName != null) {
+ mUserName = new byte[userName.length];
+ System.arraycopy(userName, 0, mUserName, 0, userName.length);
+ }
+
+ mPassword = new byte[password.length];
+ System.arraycopy(password, 0, mPassword, 0, password.length);
+ }
+
+ /**
+ * Retrieves the user name that was specified in the constructor. The user
+ * name may be <code>null</code>.
+ * @return the user name
+ */
+ public byte[] getUserName() {
+ return mUserName;
+ }
+
+ /**
+ * Retrieves the password.
+ * @return the password
+ */
+ public byte[] getPassword() {
+ return mPassword;
+ }
+}
diff --git a/obex/javax/obex/PrivateInputStream.java b/obex/javax/obex/PrivateInputStream.java
new file mode 100644
index 0000000..5daee72
--- /dev/null
+++ b/obex/javax/obex/PrivateInputStream.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This object provides an input stream to the Operation objects used in this
+ * package.
+ * @hide
+ */
+public final class PrivateInputStream extends InputStream {
+
+ private BaseStream mParent;
+
+ private byte[] mData;
+
+ private int mIndex;
+
+ private boolean mOpen;
+
+ /**
+ * Creates an input stream for the <code>Operation</code> to read from
+ * @param p the connection this input stream is for
+ */
+ public PrivateInputStream(BaseStream p) {
+ mParent = p;
+ mData = new byte[0];
+ mIndex = 0;
+ mOpen = true;
+ }
+
+ /**
+ * Returns the number of bytes that can be read (or skipped over) from this
+ * input stream without blocking by the next caller of a method for this
+ * input stream. The next caller might be the same thread or or another
+ * thread.
+ * @return the number of bytes that can be read from this input stream
+ * without blocking
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public synchronized int available() throws IOException {
+ ensureOpen();
+ return mData.length - mIndex;
+ }
+
+ /**
+ * Reads the next byte of data from the input stream. The value byte is
+ * returned as an int in the range 0 to 255. If no byte is available because
+ * the end of the stream has been reached, the value -1 is returned. This
+ * method blocks until input data is available, the end of the stream is
+ * detected, or an exception is thrown.
+ * @return the byte read from the input stream or -1 if it reaches the end of
+ * stream
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public synchronized int read() throws IOException {
+ ensureOpen();
+ while (mData.length == mIndex) {
+ if (!mParent.continueOperation(true, true)) {
+ return -1;
+ }
+ }
+ return (mData[mIndex++] & 0xFF);
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ @Override
+ public synchronized int read(byte[] b, int offset, int length) throws IOException {
+
+ if (b == null) {
+ throw new IOException("buffer is null");
+ }
+ if ((offset | length) < 0 || length > b.length - offset) {
+ throw new ArrayIndexOutOfBoundsException("index outof bound");
+ }
+ ensureOpen();
+
+ int currentDataLength = mData.length - mIndex;
+ int remainReadLength = length;
+ int offset1 = offset;
+ int result = 0;
+
+ while (currentDataLength <= remainReadLength) {
+ System.arraycopy(mData, mIndex, b, offset1, currentDataLength);
+ mIndex += currentDataLength;
+ offset1 += currentDataLength;
+ result += currentDataLength;
+ remainReadLength -= currentDataLength;
+
+ if (!mParent.continueOperation(true, true)) {
+ return result == 0 ? -1 : result;
+ }
+ currentDataLength = mData.length - mIndex;
+ }
+ if (remainReadLength > 0) {
+ System.arraycopy(mData, mIndex, b, offset1, remainReadLength);
+ mIndex += remainReadLength;
+ result += remainReadLength;
+ }
+ return result;
+ }
+
+ /**
+ * Allows the <code>OperationImpl</code> thread to add body data to the
+ * input stream.
+ * @param body the data to add to the stream
+ * @param start the start of the body to array to copy
+ */
+ public synchronized void writeBytes(byte[] body, int start) {
+
+ int length = (body.length - start) + (mData.length - mIndex);
+ byte[] temp = new byte[length];
+
+ System.arraycopy(mData, mIndex, temp, 0, mData.length - mIndex);
+ System.arraycopy(body, start, temp, mData.length - mIndex, body.length - start);
+
+ mData = temp;
+ mIndex = 0;
+ notifyAll();
+ }
+
+ /**
+ * Verifies that this stream is open
+ * @throws IOException if the stream is not open
+ */
+ private void ensureOpen() throws IOException {
+ mParent.ensureOpen();
+ if (!mOpen) {
+ throw new IOException("Input stream is closed");
+ }
+ }
+
+ /**
+ * Closes the input stream. If the input stream is already closed, do
+ * nothing.
+ * @throws IOException this will never happen
+ */
+ @Override
+ public void close() throws IOException {
+ mOpen = false;
+ mParent.streamClosed(true);
+ }
+}
diff --git a/obex/javax/obex/PrivateOutputStream.java b/obex/javax/obex/PrivateOutputStream.java
new file mode 100644
index 0000000..ca420af
--- /dev/null
+++ b/obex/javax/obex/PrivateOutputStream.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * This object provides an output stream to the Operation objects used in this
+ * package.
+ * @hide
+ */
+public final class PrivateOutputStream extends OutputStream {
+
+ private BaseStream mParent;
+
+ private ByteArrayOutputStream mArray;
+
+ private boolean mOpen;
+
+ private int mMaxPacketSize;
+
+ /**
+ * Creates an empty <code>PrivateOutputStream</code> to write to.
+ * @param p the connection that this stream runs over
+ */
+ public PrivateOutputStream(BaseStream p, int maxSize) {
+ mParent = p;
+ mArray = new ByteArrayOutputStream();
+ mMaxPacketSize = maxSize;
+ mOpen = true;
+ }
+
+ /**
+ * Determines how many bytes have been written to the output stream.
+ * @return the number of bytes written to the output stream
+ */
+ public int size() {
+ return mArray.size();
+ }
+
+ /**
+ * Writes the specified byte to this output stream. The general contract for
+ * write is that one byte is written to the output stream. The byte to be
+ * written is the eight low-order bits of the argument b. The 24 high-order
+ * bits of b are ignored.
+ * @param b the byte to write
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public synchronized void write(int b) throws IOException {
+ ensureOpen();
+ mParent.ensureNotDone();
+ mArray.write(b);
+ if (mArray.size() == mMaxPacketSize) {
+ mParent.continueOperation(true, false);
+ }
+ }
+
+ @Override
+ public void write(byte[] buffer) throws IOException {
+ write(buffer, 0, buffer.length);
+ }
+
+ @Override
+ public synchronized void write(byte[] buffer, int offset, int count) throws IOException {
+ int offset1 = offset;
+ int remainLength = count;
+
+ if (buffer == null) {
+ throw new IOException("buffer is null");
+ }
+ if ((offset | count) < 0 || count > buffer.length - offset) {
+ throw new IndexOutOfBoundsException("index outof bound");
+ }
+
+ ensureOpen();
+ mParent.ensureNotDone();
+ if (count < mMaxPacketSize) {
+ mArray.write(buffer, offset, count);
+ } else {
+ while (remainLength >= mMaxPacketSize) {
+ mArray.write(buffer, offset1, mMaxPacketSize);
+ offset1 += mMaxPacketSize;
+ remainLength = count - offset1;
+ mParent.continueOperation(true, false);
+ }
+ if (remainLength > 0) {
+ mArray.write(buffer, offset1, remainLength);
+ }
+ }
+ }
+
+ /**
+ * Reads the bytes that have been written to this stream.
+ * @param size the size of the array to return
+ * @return the byte array that is written
+ */
+ public synchronized byte[] readBytes(int size) {
+ if (mArray.size() > 0) {
+ byte[] temp = mArray.toByteArray();
+ mArray.reset();
+ byte[] result = new byte[size];
+ System.arraycopy(temp, 0, result, 0, size);
+ if (temp.length != size) {
+ mArray.write(temp, size, temp.length - size);
+ }
+ return result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Verifies that this stream is open
+ * @throws IOException if the stream is not open
+ */
+ private void ensureOpen() throws IOException {
+ mParent.ensureOpen();
+ if (!mOpen) {
+ throw new IOException("Output stream is closed");
+ }
+ }
+
+ /**
+ * Closes the output stream. If the input stream is already closed, do
+ * nothing.
+ * @throws IOException this will never happen
+ */
+ @Override
+ public void close() throws IOException {
+ mOpen = false;
+ mParent.streamClosed(false);
+ }
+
+ /**
+ * Determines if the connection is closed
+ * @return <code>true</code> if the connection is closed; <code>false</code>
+ * if the connection is open
+ */
+ public boolean isClosed() {
+ return !mOpen;
+ }
+}
diff --git a/obex/javax/obex/ResponseCodes.java b/obex/javax/obex/ResponseCodes.java
new file mode 100644
index 0000000..a2b9a37
--- /dev/null
+++ b/obex/javax/obex/ResponseCodes.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+/**
+ * The <code>ResponseCodes</code> class contains the list of valid response
+ * codes a server may send to a client.
+ * <P>
+ * <STRONG>IMPORTANT NOTE</STRONG>
+ * <P>
+ * The values in this interface represent the values defined in the IrOBEX
+ * specification, which is different with the HTTP specification.
+ * <P>
+ * <code>OBEX_DATABASE_FULL</code> and <code>OBEX_DATABASE_LOCKED</code> require
+ * further description since they are not defined in HTTP. The server will send
+ * an <code>OBEX_DATABASE_FULL</code> message when the client requests that
+ * something be placed into a database but the database is full (cannot take
+ * more data). <code>OBEX_DATABASE_LOCKED</code> will be returned when the
+ * client wishes to access a database, database table, or database record that
+ * has been locked.
+ * @hide
+ */
+public final class ResponseCodes {
+
+ /**
+ * Defines the OBEX CONTINUE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_CONTINUE</code> is 0x90 (144).
+ */
+ public static final int OBEX_HTTP_CONTINUE = 0x90;
+
+ /**
+ * Defines the OBEX SUCCESS response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_OK</code> is 0xA0 (160).
+ */
+ public static final int OBEX_HTTP_OK = 0xA0;
+
+ /**
+ * Defines the OBEX CREATED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_CREATED</code> is 0xA1 (161).
+ */
+ public static final int OBEX_HTTP_CREATED = 0xA1;
+
+ /**
+ * Defines the OBEX ACCEPTED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_ACCEPTED</code> is 0xA2 (162).
+ */
+ public static final int OBEX_HTTP_ACCEPTED = 0xA2;
+
+ /**
+ * Defines the OBEX NON-AUTHORITATIVE INFORMATION response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NOT_AUTHORITATIVE</code> is 0xA3 (163).
+ */
+ public static final int OBEX_HTTP_NOT_AUTHORITATIVE = 0xA3;
+
+ /**
+ * Defines the OBEX NO CONTENT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NO_CONTENT</code> is 0xA4 (164).
+ */
+ public static final int OBEX_HTTP_NO_CONTENT = 0xA4;
+
+ /**
+ * Defines the OBEX RESET CONTENT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_RESET</code> is 0xA5 (165).
+ */
+ public static final int OBEX_HTTP_RESET = 0xA5;
+
+ /**
+ * Defines the OBEX PARTIAL CONTENT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_PARTIAL</code> is 0xA6 (166).
+ */
+ public static final int OBEX_HTTP_PARTIAL = 0xA6;
+
+ /**
+ * Defines the OBEX MULTIPLE_CHOICES response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_MULT_CHOICE</code> is 0xB0 (176).
+ */
+ public static final int OBEX_HTTP_MULT_CHOICE = 0xB0;
+
+ /**
+ * Defines the OBEX MOVED PERMANENTLY response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_MOVED_PERM</code> is 0xB1 (177).
+ */
+ public static final int OBEX_HTTP_MOVED_PERM = 0xB1;
+
+ /**
+ * Defines the OBEX MOVED TEMPORARILY response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_MOVED_TEMP</code> is 0xB2 (178).
+ */
+ public static final int OBEX_HTTP_MOVED_TEMP = 0xB2;
+
+ /**
+ * Defines the OBEX SEE OTHER response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_SEE_OTHER</code> is 0xB3 (179).
+ */
+ public static final int OBEX_HTTP_SEE_OTHER = 0xB3;
+
+ /**
+ * Defines the OBEX NOT MODIFIED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NOT_MODIFIED</code> is 0xB4 (180).
+ */
+ public static final int OBEX_HTTP_NOT_MODIFIED = 0xB4;
+
+ /**
+ * Defines the OBEX USE PROXY response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_USE_PROXY</code> is 0xB5 (181).
+ */
+ public static final int OBEX_HTTP_USE_PROXY = 0xB5;
+
+ /**
+ * Defines the OBEX BAD REQUEST response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_BAD_REQUEST</code> is 0xC0 (192).
+ */
+ public static final int OBEX_HTTP_BAD_REQUEST = 0xC0;
+
+ /**
+ * Defines the OBEX UNAUTHORIZED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_UNAUTHORIZED</code> is 0xC1 (193).
+ */
+ public static final int OBEX_HTTP_UNAUTHORIZED = 0xC1;
+
+ /**
+ * Defines the OBEX PAYMENT REQUIRED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_PAYMENT_REQUIRED</code> is 0xC2 (194).
+ */
+ public static final int OBEX_HTTP_PAYMENT_REQUIRED = 0xC2;
+
+ /**
+ * Defines the OBEX FORBIDDEN response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_FORBIDDEN</code> is 0xC3 (195).
+ */
+ public static final int OBEX_HTTP_FORBIDDEN = 0xC3;
+
+ /**
+ * Defines the OBEX NOT FOUND response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NOT_FOUND</code> is 0xC4 (196).
+ */
+ public static final int OBEX_HTTP_NOT_FOUND = 0xC4;
+
+ /**
+ * Defines the OBEX METHOD NOT ALLOWED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_BAD_METHOD</code> is 0xC5 (197).
+ */
+ public static final int OBEX_HTTP_BAD_METHOD = 0xC5;
+
+ /**
+ * Defines the OBEX NOT ACCEPTABLE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NOT_ACCEPTABLE</code> is 0xC6 (198).
+ */
+ public static final int OBEX_HTTP_NOT_ACCEPTABLE = 0xC6;
+
+ /**
+ * Defines the OBEX PROXY AUTHENTICATION REQUIRED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_PROXY_AUTH</code> is 0xC7 (199).
+ */
+ public static final int OBEX_HTTP_PROXY_AUTH = 0xC7;
+
+ /**
+ * Defines the OBEX REQUEST TIME OUT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_TIMEOUT</code> is 0xC8 (200).
+ */
+ public static final int OBEX_HTTP_TIMEOUT = 0xC8;
+
+ /**
+ * Defines the OBEX METHOD CONFLICT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_CONFLICT</code> is 0xC9 (201).
+ */
+ public static final int OBEX_HTTP_CONFLICT = 0xC9;
+
+ /**
+ * Defines the OBEX METHOD GONE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_GONE</code> is 0xCA (202).
+ */
+ public static final int OBEX_HTTP_GONE = 0xCA;
+
+ /**
+ * Defines the OBEX METHOD LENGTH REQUIRED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_LENGTH_REQUIRED</code> is 0xCB (203).
+ */
+ public static final int OBEX_HTTP_LENGTH_REQUIRED = 0xCB;
+
+ /**
+ * Defines the OBEX PRECONDITION FAILED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_PRECON_FAILED</code> is 0xCC (204).
+ */
+ public static final int OBEX_HTTP_PRECON_FAILED = 0xCC;
+
+ /**
+ * Defines the OBEX REQUESTED ENTITY TOO LARGE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_ENTITY_TOO_LARGE</code> is 0xCD (205).
+ */
+ public static final int OBEX_HTTP_ENTITY_TOO_LARGE = 0xCD;
+
+ /**
+ * Defines the OBEX REQUESTED URL TOO LARGE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_REQ_TOO_LARGE</code> is 0xCE (206).
+ */
+ public static final int OBEX_HTTP_REQ_TOO_LARGE = 0xCE;
+
+ /**
+ * Defines the OBEX UNSUPPORTED MEDIA TYPE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_UNSUPPORTED_TYPE</code> is 0xCF (207).
+ */
+ public static final int OBEX_HTTP_UNSUPPORTED_TYPE = 0xCF;
+
+ /**
+ * Defines the OBEX INTERNAL SERVER ERROR response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_INTERNAL_ERROR</code> is 0xD0 (208).
+ */
+ public static final int OBEX_HTTP_INTERNAL_ERROR = 0xD0;
+
+ /**
+ * Defines the OBEX NOT IMPLEMENTED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_NOT_IMPLEMENTED</code> is 0xD1 (209).
+ */
+ public static final int OBEX_HTTP_NOT_IMPLEMENTED = 0xD1;
+
+ /**
+ * Defines the OBEX BAD GATEWAY response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_BAD_GATEWAY</code> is 0xD2 (210).
+ */
+ public static final int OBEX_HTTP_BAD_GATEWAY = 0xD2;
+
+ /**
+ * Defines the OBEX SERVICE UNAVAILABLE response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_UNAVAILABLE</code> is 0xD3 (211).
+ */
+ public static final int OBEX_HTTP_UNAVAILABLE = 0xD3;
+
+ /**
+ * Defines the OBEX GATEWAY TIMEOUT response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_GATEWAY_TIMEOUT</code> is 0xD4 (212).
+ */
+ public static final int OBEX_HTTP_GATEWAY_TIMEOUT = 0xD4;
+
+ /**
+ * Defines the OBEX HTTP VERSION NOT SUPPORTED response code.
+ * <P>
+ * The value of <code>OBEX_HTTP_VERSION</code> is 0xD5 (213).
+ */
+ public static final int OBEX_HTTP_VERSION = 0xD5;
+
+ /**
+ * Defines the OBEX DATABASE FULL response code.
+ * <P>
+ * The value of <code>OBEX_DATABASE_FULL</code> is 0xE0 (224).
+ */
+ public static final int OBEX_DATABASE_FULL = 0xE0;
+
+ /**
+ * Defines the OBEX DATABASE LOCKED response code.
+ * <P>
+ * The value of <code>OBEX_DATABASE_LOCKED</code> is 0xE1 (225).
+ */
+ public static final int OBEX_DATABASE_LOCKED = 0xE1;
+
+ /**
+ * Constructor does nothing.
+ */
+ private ResponseCodes() {
+ }
+}
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
new file mode 100644
index 0000000..8710c64
--- /dev/null
+++ b/obex/javax/obex/ServerOperation.java
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.DataInputStream;
+import java.io.OutputStream;
+import java.io.DataOutputStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * This class implements the Operation interface for server side connections.
+ * <P>
+ * <STRONG>Request Codes</STRONG> There are four different request codes that
+ * are in this class. 0x02 is a PUT request that signals that the request is not
+ * complete and requires an additional OBEX packet. 0x82 is a PUT request that
+ * says that request is complete. In this case, the server can begin sending the
+ * response. The 0x03 is a GET request that signals that the request is not
+ * finished. When the server receives a 0x83, the client is signaling the server
+ * that it is done with its request. TODO: Extend the ClientOperation and reuse
+ * the methods defined TODO: in that class.
+ * @hide
+ */
+public final class ServerOperation implements Operation, BaseStream {
+
+ public boolean isAborted;
+
+ public HeaderSet requestHeader;
+
+ public HeaderSet replyHeader;
+
+ public boolean finalBitSet;
+
+ private InputStream mInput;
+
+ private ServerSession mParent;
+
+ private int mMaxPacketLength;
+
+ private int mResponseSize;
+
+ private boolean mClosed;
+
+ private boolean mGetOperation;
+
+ private PrivateInputStream mPrivateInput;
+
+ private PrivateOutputStream mPrivateOutput;
+
+ private boolean mPrivateOutputOpen;
+
+ private String mExceptionString;
+
+ private ServerRequestHandler mListener;
+
+ private boolean mRequestFinished;
+
+ private boolean mHasBody;
+
+ /**
+ * Creates new ServerOperation
+ * @param p the parent that created this object
+ * @param in the input stream to read from
+ * @param out the output stream to write to
+ * @param request the initial request that was received from the client
+ * @param maxSize the max packet size that the client will accept
+ * @param listen the listener that is responding to the request
+ * @throws IOException if an IO error occurs
+ */
+ public ServerOperation(ServerSession p, InputStream in, int request, int maxSize,
+ ServerRequestHandler listen) throws IOException {
+
+ isAborted = false;
+ mParent = p;
+ mInput = in;
+ mMaxPacketLength = maxSize;
+ mClosed = false;
+ requestHeader = new HeaderSet();
+ replyHeader = new HeaderSet();
+ mPrivateInput = new PrivateInputStream(this);
+ mResponseSize = 3;
+ mListener = listen;
+ mRequestFinished = false;
+ mPrivateOutputOpen = false;
+ mHasBody = false;
+ int bytesReceived;
+
+ /*
+ * Determine if this is a PUT request
+ */
+ if ((request == 0x02) || (request == 0x82)) {
+ /*
+ * It is a PUT request.
+ */
+ mGetOperation = false;
+ } else {
+ /*
+ * It is a GET request.
+ */
+ mGetOperation = true;
+ }
+
+ /*
+ * Determine if the final bit is set
+ */
+ if ((request & 0x80) == 0) {
+ finalBitSet = false;
+ } else {
+ finalBitSet = true;
+ mRequestFinished = true;
+ }
+
+ int length = in.read();
+ length = (length << 8) + in.read();
+
+ /*
+ * Determine if the packet length is larger than this device can receive
+ */
+ if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
+ throw new IOException("Packet received was too large");
+ }
+
+ /*
+ * Determine if any headers were sent in the initial request
+ */
+ if (length > 3) {
+ byte[] data = new byte[length - 3];
+ bytesReceived = in.read(data);
+
+ while (bytesReceived != data.length) {
+ bytesReceived += in.read(data, bytesReceived, data.length - bytesReceived);
+ }
+
+ byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
+
+ if (body != null) {
+ mHasBody = true;
+ }
+
+ if (requestHeader.mConnectionID != null) {
+ mListener.setConnectionId(ObexHelper.convertToLong(requestHeader.mConnectionID));
+ } else {
+ mListener.setConnectionId(0);
+ }
+
+ if (requestHeader.mAuthResp != null) {
+ if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
+ mExceptionString = "Authentication Failed";
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
+ mClosed = true;
+ requestHeader.mAuthResp = null;
+ return;
+ }
+ }
+
+ if (requestHeader.mAuthChall != null) {
+ mParent.handleAuthChall(requestHeader);
+ // send the authResp to the client
+ replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
+ System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
+ replyHeader.mAuthResp.length);
+ requestHeader.mAuthResp = null;
+ requestHeader.mAuthChall = null;
+
+ }
+
+ if (body != null) {
+ mPrivateInput.writeBytes(body, 1);
+ } else {
+ while ((!mGetOperation) && (!finalBitSet)) {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ if (mPrivateInput.available() > 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ if (mPrivateInput.available() > 0) {
+ break;
+ }
+ }
+
+ // wait for get request finished !!!!
+ while (mGetOperation && !finalBitSet) {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ }
+ if (finalBitSet && mGetOperation) {
+ mRequestFinished = true;
+ }
+ }
+
+ public boolean isValidBody() {
+ return mHasBody;
+ }
+
+ /**
+ * Determines if the operation should continue or should wait. If it should
+ * continue, this method will continue the operation.
+ * @param sendEmpty if <code>true</code> then this will continue the
+ * operation even if no headers will be sent; if <code>false</code>
+ * then this method will only continue the operation if there are
+ * headers to send
+ * @param inStream if<code>true</code> the stream is input stream, otherwise
+ * output stream
+ * @return <code>true</code> if the operation was completed;
+ * <code>false</code> if no operation took place
+ */
+ public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
+ throws IOException {
+ if (!mGetOperation) {
+ if (!finalBitSet) {
+ if (sendEmpty) {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ return true;
+ } else {
+ if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ } else {
+ sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ return true;
+ }
+ }
+
+ /**
+ * Sends a reply to the client. If the reply is a OBEX_HTTP_CONTINUE, it
+ * will wait for a response from the client before ending.
+ * @param type the response code to send back to the client
+ * @return <code>true</code> if the final bit was not set on the reply;
+ * <code>false</code> if no reply was received because the operation
+ * ended, an abort was received, or the final bit was set in the
+ * reply
+ * @throws IOException if an IO error occurs
+ */
+ public synchronized boolean sendReply(int type) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int bytesReceived;
+
+ long id = mListener.getConnectionId();
+ if (id == -1) {
+ replyHeader.mConnectionID = null;
+ } else {
+ replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
+ }
+
+ byte[] headerArray = ObexHelper.createHeader(replyHeader, true);
+ int bodyLength = -1;
+ int orginalBodyLength = -1;
+
+ if (mPrivateOutput != null) {
+ bodyLength = mPrivateOutput.size();
+ orginalBodyLength = bodyLength;
+ }
+
+ if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {
+
+ int end = 0;
+ int start = 0;
+
+ while (end != headerArray.length) {
+ end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketLength
+ - ObexHelper.BASE_PACKET_LENGTH);
+ if (end == -1) {
+
+ mClosed = true;
+
+ if (mPrivateInput != null) {
+ mPrivateInput.close();
+ }
+
+ if (mPrivateOutput != null) {
+ mPrivateOutput.close();
+ }
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+ throw new IOException("OBEX Packet exceeds max packet size");
+ }
+ byte[] sendHeader = new byte[end - start];
+ System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
+
+ mParent.sendResponse(type, sendHeader);
+ start = end;
+ }
+
+ if (bodyLength > 0) {
+ return true;
+ } else {
+ return false;
+ }
+
+ } else {
+ out.write(headerArray);
+ }
+
+ if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
+ if (bodyLength > 0) {
+ /*
+ * Determine if I can send the whole body or just part of
+ * the body. Remember that there is the 3 bytes for the
+ * response message and 3 bytes for the header ID and length
+ */
+ if (bodyLength > (mMaxPacketLength - headerArray.length - 6)) {
+ bodyLength = mMaxPacketLength - headerArray.length - 6;
+ }
+
+ byte[] body = mPrivateOutput.readBytes(bodyLength);
+
+ /*
+ * Since this is a put request if the final bit is set or
+ * the output stream is closed we need to send the 0x49
+ * (End of Body) otherwise, we need to send 0x48 (Body)
+ */
+ if ((finalBitSet) || (mPrivateOutput.isClosed())) {
+ out.write(0x49);
+ } else {
+ out.write(0x48);
+ }
+
+ bodyLength += 3;
+ out.write((byte)(bodyLength >> 8));
+ out.write((byte)bodyLength);
+ out.write(body);
+ }
+ }
+
+ if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) {
+ out.write(0x49);
+ orginalBodyLength = 3;
+ out.write((byte)(orginalBodyLength >> 8));
+ out.write((byte)orginalBodyLength);
+
+ }
+
+ mResponseSize = 3;
+ mParent.sendResponse(type, out.toByteArray());
+
+ if (type == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ int headerID = mInput.read();
+ int length = mInput.read();
+ length = (length << 8) + mInput.read();
+ if ((headerID != ObexHelper.OBEX_OPCODE_PUT)
+ && (headerID != ObexHelper.OBEX_OPCODE_PUT_FINAL)
+ && (headerID != ObexHelper.OBEX_OPCODE_GET)
+ && (headerID != ObexHelper.OBEX_OPCODE_GET_FINAL)) {
+
+ if (length > 3) {
+ byte[] temp = new byte[length];
+ bytesReceived = mInput.read(temp);
+
+ while (bytesReceived != length) {
+ bytesReceived += mInput.read(temp, bytesReceived, length - bytesReceived);
+ }
+ }
+
+ /*
+ * Determine if an ABORT was sent as the reply
+ */
+ if (headerID == ObexHelper.OBEX_OPCODE_ABORT) {
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
+ mClosed = true;
+ isAborted = true;
+ mExceptionString = "Abort Received";
+ throw new IOException("Abort Received");
+ } else {
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
+ mClosed = true;
+ mExceptionString = "Bad Request Received";
+ throw new IOException("Bad Request Received");
+ }
+ } else {
+
+ if ((headerID == ObexHelper.OBEX_OPCODE_PUT_FINAL)
+ || (headerID == ObexHelper.OBEX_OPCODE_GET_FINAL)) {
+ finalBitSet = true;
+ }
+
+ /*
+ * Determine if the packet length is larger then this device can receive
+ */
+ if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
+ throw new IOException("Packet received was too large");
+ }
+
+ /*
+ * Determine if any headers were sent in the initial request
+ */
+ if (length > 3) {
+ byte[] data = new byte[length - 3];
+ bytesReceived = mInput.read(data);
+
+ while (bytesReceived != data.length) {
+ bytesReceived += mInput.read(data, bytesReceived, data.length
+ - bytesReceived);
+ }
+ byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
+ if (body != null) {
+ mHasBody = true;
+ }
+ if (requestHeader.mConnectionID != null) {
+ mListener.setConnectionId(ObexHelper
+ .convertToLong(requestHeader.mConnectionID));
+ } else {
+ mListener.setConnectionId(1);
+ }
+
+ if (requestHeader.mAuthResp != null) {
+ if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
+ mExceptionString = "Authentication Failed";
+ mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
+ mClosed = true;
+ requestHeader.mAuthResp = null;
+ return false;
+ }
+ requestHeader.mAuthResp = null;
+ }
+
+ if (requestHeader.mAuthChall != null) {
+ mParent.handleAuthChall(requestHeader);
+ // send the auhtResp to the client
+ replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
+ System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
+ replyHeader.mAuthResp.length);
+ requestHeader.mAuthResp = null;
+ requestHeader.mAuthChall = null;
+ }
+
+ if (body != null) {
+ mPrivateInput.writeBytes(body, 1);
+ }
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Sends an ABORT message to the server. By calling this method, the
+ * corresponding input and output streams will be closed along with this
+ * object.
+ * @throws IOException if the transaction has already ended or if an OBEX
+ * server called this method
+ */
+ public void abort() throws IOException {
+ throw new IOException("Called from a server");
+ }
+
+ /**
+ * Returns the headers that have been received during the operation.
+ * Modifying the object returned has no effect on the headers that are sent
+ * or retrieved.
+ * @return the headers received during this <code>Operation</code>
+ * @throws IOException if this <code>Operation</code> has been closed
+ */
+ public HeaderSet getReceivedHeader() throws IOException {
+ ensureOpen();
+ return requestHeader;
+ }
+
+ /**
+ * Specifies the headers that should be sent in the next OBEX message that
+ * is sent.
+ * @param headers the headers to send in the next message
+ * @throws IOException if this <code>Operation</code> has been closed or the
+ * transaction has ended and no further messages will be exchanged
+ * @throws IllegalArgumentException if <code>headers</code> was not created
+ * by a call to <code>ServerRequestHandler.createHeaderSet()</code>
+ */
+ public void sendHeaders(HeaderSet headers) throws IOException {
+ ensureOpen();
+
+ if (headers == null) {
+ throw new IOException("Headers may not be null");
+ }
+
+ int[] headerList = headers.getHeaderList();
+ if (headerList != null) {
+ for (int i = 0; i < headerList.length; i++) {
+ replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
+ }
+
+ }
+ }
+
+ /**
+ * Retrieves the response code retrieved from the server. Response codes are
+ * defined in the <code>ResponseCodes</code> interface.
+ * @return the response code retrieved from the server
+ * @throws IOException if an error occurred in the transport layer during
+ * the transaction; if this method is called on a
+ * <code>HeaderSet</code> object created by calling
+ * <code>createHeaderSet</code> in a <code>ClientSession</code>
+ * object; if this is called from a server
+ */
+ public int getResponseCode() throws IOException {
+ throw new IOException("Called from a server");
+ }
+
+ /**
+ * Always returns <code>null</code>
+ * @return <code>null</code>
+ */
+ public String getEncoding() {
+ return null;
+ }
+
+ /**
+ * Returns the type of content that the resource connected to is providing.
+ * E.g. if the connection is via HTTP, then the value of the content-type
+ * header field is returned.
+ * @return the content type of the resource that the URL references, or
+ * <code>null</code> if not known
+ */
+ public String getType() {
+ try {
+ return (String)requestHeader.getHeader(HeaderSet.TYPE);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the length of the content which is being provided. E.g. if the
+ * connection is via HTTP, then the value of the content-length header field
+ * is returned.
+ * @return the content length of the resource that this connection's URL
+ * references, or -1 if the content length is not known
+ */
+ public long getLength() {
+ try {
+ Long temp = (Long)requestHeader.getHeader(HeaderSet.LENGTH);
+
+ if (temp == null) {
+ return -1;
+ } else {
+ return temp.longValue();
+ }
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ public int getMaxPacketSize() {
+ return mMaxPacketLength - 6;
+ }
+
+ /**
+ * Open and return an input stream for a connection.
+ * @return an input stream
+ * @throws IOException if an I/O error occurs
+ */
+ public InputStream openInputStream() throws IOException {
+ ensureOpen();
+ return mPrivateInput;
+ }
+
+ /**
+ * Open and return a data input stream for a connection.
+ * @return an input stream
+ * @throws IOException if an I/O error occurs
+ */
+ public DataInputStream openDataInputStream() throws IOException {
+ return new DataInputStream(openInputStream());
+ }
+
+ /**
+ * Open and return an output stream for a connection.
+ * @return an output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public OutputStream openOutputStream() throws IOException {
+ ensureOpen();
+
+ if (mPrivateOutputOpen) {
+ throw new IOException("no more input streams available, stream already opened");
+ }
+
+ if (!mRequestFinished) {
+ throw new IOException("no output streams available ,request not finished");
+ }
+
+ if (mPrivateOutput == null) {
+ mPrivateOutput = new PrivateOutputStream(this, mMaxPacketLength - 6);
+ }
+ mPrivateOutputOpen = true;
+ return mPrivateOutput;
+ }
+
+ /**
+ * Open and return a data output stream for a connection.
+ * @return an output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public DataOutputStream openDataOutputStream() throws IOException {
+ return new DataOutputStream(openOutputStream());
+ }
+
+ /**
+ * Closes the connection and ends the transaction
+ * @throws IOException if the operation has already ended or is closed
+ */
+ public void close() throws IOException {
+ ensureOpen();
+ mClosed = true;
+ }
+
+ /**
+ * Verifies that the connection is open and no exceptions should be thrown.
+ * @throws IOException if an exception needs to be thrown
+ */
+ public void ensureOpen() throws IOException {
+ if (mExceptionString != null) {
+ throw new IOException(mExceptionString);
+ }
+ if (mClosed) {
+ throw new IOException("Operation has already ended");
+ }
+ }
+
+ /**
+ * Verifies that additional information may be sent. In other words, the
+ * operation is not done.
+ * <P>
+ * Included to implement the BaseStream interface only. It does not do
+ * anything on the server side since the operation of the Operation object
+ * is not done until after the handler returns from its method.
+ * @throws IOException if the operation is completed
+ */
+ public void ensureNotDone() throws IOException {
+ }
+
+ /**
+ * Called when the output or input stream is closed. It does not do anything
+ * on the server side since the operation of the Operation object is not
+ * done until after the handler returns from its method.
+ * @param inStream <code>true</code> if the input stream is closed;
+ * <code>false</code> if the output stream is closed
+ * @throws IOException if an IO error occurs
+ */
+ public void streamClosed(boolean inStream) throws IOException {
+
+ }
+}
diff --git a/obex/javax/obex/ServerRequestHandler.java b/obex/javax/obex/ServerRequestHandler.java
new file mode 100644
index 0000000..d93e5b6
--- /dev/null
+++ b/obex/javax/obex/ServerRequestHandler.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+/**
+ * The <code>ServerRequestHandler</code> class defines an event listener that
+ * will respond to OBEX requests made to the server.
+ * <P>
+ * The <code>onConnect()</code>, <code>onSetPath()</code>,
+ * <code>onDelete()</code>, <code>onGet()</code>, and <code>onPut()</code>
+ * methods may return any response code defined in the
+ * <code>ResponseCodes</code> class except for <code>OBEX_HTTP_CONTINUE</code>.
+ * If <code>OBEX_HTTP_CONTINUE</code> or a value not defined in the
+ * <code>ResponseCodes</code> class is returned, the server implementation will
+ * send an <code>OBEX_HTTP_INTERNAL_ERROR</code> response to the client.
+ * <P>
+ * <STRONG>Connection ID and Target Headers</STRONG>
+ * <P>
+ * According to the IrOBEX specification, a packet may not contain a Connection
+ * ID and Target header. Since the Connection ID header is managed by the
+ * implementation, it will not send a Connection ID header, if a Connection ID
+ * was specified, in a packet that has a Target header. In other words, if an
+ * application adds a Target header to a <code>HeaderSet</code> object used in
+ * an OBEX operation and a Connection ID was specified, no Connection ID will be
+ * sent in the packet containing the Target header.
+ * <P>
+ * <STRONG>CREATE-EMPTY Requests</STRONG>
+ * <P>
+ * A CREATE-EMPTY request allows clients to create empty objects on the server.
+ * When a CREATE-EMPTY request is received, the <code>onPut()</code> method will
+ * be called by the implementation. To differentiate between a normal PUT
+ * request and a CREATE-EMPTY request, an application must open the
+ * <code>InputStream</code> from the <code>Operation</code> object passed to the
+ * <code>onPut()</code> method. For a PUT request, the application will be able
+ * to read Body data from this <code>InputStream</code>. For a CREATE-EMPTY
+ * request, there will be no Body data to read. Therefore, a call to
+ * <code>InputStream.read()</code> will return -1.
+ * @hide
+ */
+public class ServerRequestHandler {
+
+ private long mConnectionId;
+
+ /**
+ * Creates a <code>ServerRequestHandler</code>.
+ */
+ protected ServerRequestHandler() {
+ /*
+ * A connection ID of -1 implies there is no conenction ID
+ */
+ mConnectionId = -1;
+ }
+
+ /**
+ * Sets the connection ID header to include in the reply packets.
+ * @param connectionId the connection ID to use; -1 if no connection ID
+ * should be sent
+ * @throws IllegalArgumentException if <code>id</code> is not in the range
+ * -1 to 2<sup>32</sup>-1
+ */
+ public void setConnectionId(final long connectionId) {
+ if ((connectionId < -1) || (connectionId > 0xFFFFFFFFL)) {
+ throw new IllegalArgumentException("Illegal Connection ID");
+ }
+ mConnectionId = connectionId;
+ }
+
+ /**
+ * Retrieves the connection ID that is being used in the present connection.
+ * This method will return -1 if no connection ID is being used.
+ * @return the connection id being used or -1 if no connection ID is being
+ * used
+ */
+ public long getConnectionId() {
+ return mConnectionId;
+ }
+
+ /**
+ * Called when a CONNECT request is received.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * <code>onConnect()</code> will always return an <code>OBEX_HTTP_OK</code>
+ * response code.
+ * <P>
+ * The headers received in the request can be retrieved from the
+ * <code>request</code> argument. The headers that should be sent in the
+ * reply must be specified in the <code>reply</code> argument.
+ * @param request contains the headers sent by the client;
+ * <code>request</code> will never be <code>null</code>
+ * @param reply the headers that should be sent in the reply;
+ * <code>reply</code> will never be <code>null</code>
+ * @return a response code defined in <code>ResponseCodes</code> that will
+ * be returned to the client; if an invalid response code is
+ * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+ * will be used
+ */
+ public int onConnect(HeaderSet request, HeaderSet reply) {
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+ /**
+ * Called when a DISCONNECT request is received.
+ * <P>
+ * The headers received in the request can be retrieved from the
+ * <code>request</code> argument. The headers that should be sent in the
+ * reply must be specified in the <code>reply</code> argument.
+ * @param request contains the headers sent by the client;
+ * <code>request</code> will never be <code>null</code>
+ * @param reply the headers that should be sent in the reply;
+ * <code>reply</code> will never be <code>null</code>
+ */
+ public void onDisconnect(HeaderSet request, HeaderSet reply) {
+ }
+
+ /**
+ * Called when a SETPATH request is received.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * <code>onSetPath()</code> will always return an
+ * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+ * <P>
+ * The headers received in the request can be retrieved from the
+ * <code>request</code> argument. The headers that should be sent in the
+ * reply must be specified in the <code>reply</code> argument.
+ * @param request contains the headers sent by the client;
+ * <code>request</code> will never be <code>null</code>
+ * @param reply the headers that should be sent in the reply;
+ * <code>reply</code> will never be <code>null</code>
+ * @param backup <code>true</code> if the client requests that the server
+ * back up one directory before changing to the path described by
+ * <code>name</code>; <code>false</code> to apply the request to the
+ * present path
+ * @param create <code>true</code> if the path should be created if it does
+ * not already exist; <code>false</code> if the path should not be
+ * created if it does not exist and an error code should be returned
+ * @return a response code defined in <code>ResponseCodes</code> that will
+ * be returned to the client; if an invalid response code is
+ * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+ * will be used
+ */
+ public int onSetPath(HeaderSet request, HeaderSet reply, boolean backup, boolean create) {
+
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ /**
+ * Called when a DELETE request is received.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * <code>onDelete()</code> will always return an
+ * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+ * <P>
+ * The headers received in the request can be retrieved from the
+ * <code>request</code> argument. The headers that should be sent in the
+ * reply must be specified in the <code>reply</code> argument.
+ * @param request contains the headers sent by the client;
+ * <code>request</code> will never be <code>null</code>
+ * @param reply the headers that should be sent in the reply;
+ * <code>reply</code> will never be <code>null</code>
+ * @return a response code defined in <code>ResponseCodes</code> that will
+ * be returned to the client; if an invalid response code is
+ * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+ * will be used
+ */
+ public int onDelete(HeaderSet request, HeaderSet reply) {
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ /**
+ * Called when a PUT request is received.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * <code>onPut()</code> will always return an
+ * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+ * <P>
+ * If an ABORT request is received during the processing of a PUT request,
+ * <code>op</code> will be closed by the implementation.
+ * @param operation contains the headers sent by the client and allows new
+ * headers to be sent in the reply; <code>op</code> will never be
+ * <code>null</code>
+ * @return a response code defined in <code>ResponseCodes</code> that will
+ * be returned to the client; if an invalid response code is
+ * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+ * will be used
+ */
+ public int onPut(Operation operation) {
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ /**
+ * Called when a GET request is received.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * <code>onGet()</code> will always return an
+ * <code>OBEX_HTTP_NOT_IMPLEMENTED</code> response code.
+ * <P>
+ * If an ABORT request is received during the processing of a GET request,
+ * <code>op</code> will be closed by the implementation.
+ * @param operation contains the headers sent by the client and allows new
+ * headers to be sent in the reply; <code>op</code> will never be
+ * <code>null</code>
+ * @return a response code defined in <code>ResponseCodes</code> that will
+ * be returned to the client; if an invalid response code is
+ * provided, the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code
+ * will be used
+ */
+ public int onGet(Operation operation) {
+ return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
+ }
+
+ /**
+ * Called when this object attempts to authenticate a client and the
+ * authentication request fails because the response digest in the
+ * authentication response header was wrong.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * this method will do nothing.
+ * @param userName the user name returned in the authentication response;
+ * <code>null</code> if no user name was provided in the response
+ */
+ public void onAuthenticationFailure(byte[] userName) {
+ }
+
+ /**
+ * Called by ServerSession to update the status of current transaction
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * this method will do nothing.
+ */
+ public void updateStatus(String message) {
+ }
+
+ /**
+ * Called when session is closed.
+ * <P>
+ * If this method is not implemented by the class that extends this class,
+ * this method will do nothing.
+ */
+ public void onClose() {
+ }
+}
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
new file mode 100644
index 0000000..675272d
--- /dev/null
+++ b/obex/javax/obex/ServerSession.java
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import android.util.Log;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * This class in an implementation of the OBEX ServerSession.
+ * @hide
+ */
+public final class ServerSession extends ObexSession implements Runnable {
+
+ private static final String TAG = "Obex ServerSession";
+
+ private ObexTransport mTransport;
+
+ private InputStream mInput;
+
+ private OutputStream mOutput;
+
+ private ServerRequestHandler mListener;
+
+ private Thread mProcessThread;
+
+ private int mMaxPacketLength;
+
+ private boolean mClosed;
+
+ /**
+ * Creates new ServerSession.
+ * @param trans the connection to the client
+ * @param handler the event listener that will process requests
+ * @param auth the authenticator to use with this connection
+ * @throws IOException if an error occurred while opening the input and
+ * output streams
+ */
+ public ServerSession(ObexTransport trans, ServerRequestHandler handler, Authenticator auth)
+ throws IOException {
+ mAuthenticator = auth;
+ mTransport = trans;
+ mInput = mTransport.openInputStream();
+ mOutput = mTransport.openOutputStream();
+ mListener = handler;
+ mMaxPacketLength = 256;
+
+ mClosed = false;
+ mProcessThread = new Thread(this);
+ mProcessThread.start();
+ }
+
+ /**
+ * Processes requests made to the server and forwards them to the
+ * appropriate event listener.
+ */
+ public void run() {
+ try {
+
+ boolean done = false;
+ while (!done && !mClosed) {
+ int requestType = mInput.read();
+ switch (requestType) {
+ case ObexHelper.OBEX_OPCODE_CONNECT:
+ handleConnectRequest();
+ break;
+
+ case ObexHelper.OBEX_OPCODE_DISCONNECT:
+ handleDisconnectRequest();
+ done = true;
+ break;
+
+ case ObexHelper.OBEX_OPCODE_GET:
+ case ObexHelper.OBEX_OPCODE_GET_FINAL:
+ handleGetRequest(requestType);
+ break;
+
+ case ObexHelper.OBEX_OPCODE_PUT:
+ case ObexHelper.OBEX_OPCODE_PUT_FINAL:
+ handlePutRequest(requestType);
+ break;
+
+ case ObexHelper.OBEX_OPCODE_SETPATH:
+ handleSetPathRequest();
+ break;
+
+ case -1:
+ done = true;
+ break;
+
+ default:
+
+ /*
+ * Received a request type that is not recognized so I am
+ * just going to read the packet and send a not implemented
+ * to the client
+ */
+ int length = mInput.read();
+ length = (length << 8) + mInput.read();
+ for (int i = 3; i < length; i++) {
+ mInput.read();
+ }
+ sendResponse(ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED, null);
+ }
+ }
+
+ } catch (NullPointerException e) {
+ Log.d(TAG, e.toString());
+ } catch (Exception e) {
+ Log.d(TAG, e.toString());
+ }
+ close();
+ }
+
+ /**
+ * Handles a PUT request from a client. This method will provide a
+ * <code>ServerOperation</code> object to the request handler. The
+ * <code>ServerOperation</code> object will handle the rest of the request.
+ * It will also send replies and receive requests until the final reply
+ * should be sent. When the final reply should be sent, this method will get
+ * the response code to use and send the reply. The
+ * <code>ServerOperation</code> object will always reply with a
+ * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
+ * needed.
+ * @param type the type of request received; either 0x02 or 0x82
+ * @throws IOException if an error occurred at the transport layer
+ */
+ private void handlePutRequest(int type) throws IOException {
+ ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
+ try {
+ int response = -1;
+
+ if ((op.finalBitSet) && !op.isValidBody()) {
+ response = validateResponseCode(mListener
+ .onDelete(op.requestHeader, op.replyHeader));
+ } else {
+ response = validateResponseCode(mListener.onPut(op));
+ }
+ if (response != ResponseCodes.OBEX_HTTP_OK && !op.isAborted) {
+ op.sendReply(response);
+ } else if (!op.isAborted) {
+ // wait for the final bit
+ while (!op.finalBitSet) {
+ op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ }
+ op.sendReply(response);
+ }
+ } catch (Exception e) {
+ /*To fix bugs in aborted cases,
+ *(client abort file transfer prior to the last packet which has the end of body header,
+ *internal error should not be sent because server has already replied with
+ *OK response in "sendReply")
+ */
+ if (!op.isAborted) {
+ sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+ }
+ }
+ }
+
+ /**
+ * Handles a GET request from a client. This method will provide a
+ * <code>ServerOperation</code> object to the request handler. The
+ * <code>ServerOperation</code> object will handle the rest of the request.
+ * It will also send replies and receive requests until the final reply
+ * should be sent. When the final reply should be sent, this method will get
+ * the response code to use and send the reply. The
+ * <code>ServerOperation</code> object will always reply with a
+ * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
+ * needed.
+ * @param type the type of request received; either 0x03 or 0x83
+ * @throws IOException if an error occurred at the transport layer
+ */
+ private void handleGetRequest(int type) throws IOException {
+ ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
+ try {
+ int response = validateResponseCode(mListener.onGet(op));
+
+ if (!op.isAborted) {
+ op.sendReply(response);
+ }
+ } catch (Exception e) {
+ sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+ }
+ }
+
+ /**
+ * Send standard response.
+ * @param code the response code to send
+ * @param header the headers to include in the response
+ * @throws IOException if an IO error occurs
+ */
+ public void sendResponse(int code, byte[] header) throws IOException {
+ int totalLength = 3;
+ byte[] data = null;
+
+ if (header != null) {
+ totalLength += header.length;
+ data = new byte[totalLength];
+ data[0] = (byte)code;
+ data[1] = (byte)(totalLength >> 8);
+ data[2] = (byte)totalLength;
+ System.arraycopy(header, 0, data, 3, header.length);
+ } else {
+ data = new byte[totalLength];
+ data[0] = (byte)code;
+ data[1] = (byte)0x00;
+ data[2] = (byte)totalLength;
+ }
+ mOutput.write(data);
+ mOutput.flush();
+ }
+
+ /**
+ * Handles a SETPATH request from a client. This method will read the rest
+ * of the request from the client. Assuming the request is valid, it will
+ * create a <code>HeaderSet</code> object to pass to the
+ * <code>ServerRequestHandler</code> object. After the handler processes the
+ * request, this method will create a reply message to send to the server
+ * with the response code provided.
+ * @throws IOException if an error occurred at the transport layer
+ */
+ private void handleSetPathRequest() throws IOException {
+ int length;
+ int flags;
+ @SuppressWarnings("unused")
+ int constants;
+ int totalLength = 3;
+ byte[] head = null;
+ int code = -1;
+ int bytesReceived;
+ HeaderSet request = new HeaderSet();
+ HeaderSet reply = new HeaderSet();
+
+ length = mInput.read();
+ length = (length << 8) + mInput.read();
+ flags = mInput.read();
+ constants = mInput.read();
+
+ if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+ code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
+ totalLength = 3;
+ } else {
+ if (length > 5) {
+ byte[] headers = new byte[length - 5];
+ bytesReceived = mInput.read(headers);
+
+ while (bytesReceived != headers.length) {
+ bytesReceived += mInput.read(headers, bytesReceived, headers.length
+ - bytesReceived);
+ }
+
+ ObexHelper.updateHeaderSet(request, headers);
+
+ if (request.mConnectionID != null) {
+ mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
+ } else {
+ mListener.setConnectionId(-1);
+ }
+ // the Auth chan is initiated by the server, client sent back the authResp .
+ if (request.mAuthResp != null) {
+ if (!handleAuthResp(request.mAuthResp)) {
+ code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
+ mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+ request.mAuthResp));
+ }
+ request.mAuthResp = null;
+ }
+ }
+
+ if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
+ // the Auth challenge is initiated by the client
+ // the server will send back the authResp to the client
+ if (request.mAuthChall != null) {
+ handleAuthChall(request);
+ reply.mAuthResp = new byte[request.mAuthResp.length];
+ System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
+ reply.mAuthResp.length);
+ request.mAuthChall = null;
+ request.mAuthResp = null;
+ }
+ boolean backup = false;
+ boolean create = true;
+ if (!((flags & 1) == 0)) {
+ backup = true;
+ }
+ if ((flags & 2) == 0) {
+ create = false;
+ }
+
+ try {
+ code = mListener.onSetPath(request, reply, backup, create);
+ } catch (Exception e) {
+ sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+ return;
+ }
+
+ code = validateResponseCode(code);
+
+ if (reply.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
+ } else {
+ mChallengeDigest = null;
+ }
+
+ long id = mListener.getConnectionId();
+ if (id == -1) {
+ reply.mConnectionID = null;
+ } else {
+ reply.mConnectionID = ObexHelper.convertToByteArray(id);
+ }
+
+ head = ObexHelper.createHeader(reply, false);
+ totalLength += head.length;
+
+ if (totalLength > mMaxPacketLength) {
+ totalLength = 3;
+ head = null;
+ code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ // Compute Length of OBEX SETPATH packet
+ byte[] replyData = new byte[totalLength];
+ replyData[0] = (byte)code;
+ replyData[1] = (byte)(totalLength >> 8);
+ replyData[2] = (byte)totalLength;
+ if (head != null) {
+ System.arraycopy(head, 0, replyData, 3, head.length);
+ }
+ /*
+ * Write the OBEX SETPATH packet to the server. Byte 0: response code
+ * Byte 1&2: Connect Packet Length Byte 3 to n: headers
+ */
+ mOutput.write(replyData);
+ mOutput.flush();
+ }
+
+ /**
+ * Handles a disconnect request from a client. This method will read the
+ * rest of the request from the client. Assuming the request is valid, it
+ * will create a <code>HeaderSet</code> object to pass to the
+ * <code>ServerRequestHandler</code> object. After the handler processes the
+ * request, this method will create a reply message to send to the server.
+ * @throws IOException if an error occurred at the transport layer
+ */
+ private void handleDisconnectRequest() throws IOException {
+ int length;
+ int code = ResponseCodes.OBEX_HTTP_OK;
+ int totalLength = 3;
+ byte[] head = null;
+ int bytesReceived;
+ HeaderSet request = new HeaderSet();
+ HeaderSet reply = new HeaderSet();
+
+ length = mInput.read();
+ length = (length << 8) + mInput.read();
+
+ if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
+ code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
+ totalLength = 3;
+ } else {
+ if (length > 3) {
+ byte[] headers = new byte[length - 3];
+ bytesReceived = mInput.read(headers);
+
+ while (bytesReceived != headers.length) {
+ bytesReceived += mInput.read(headers, bytesReceived, headers.length
+ - bytesReceived);
+ }
+
+ ObexHelper.updateHeaderSet(request, headers);
+ }
+
+ if (request.mConnectionID != null) {
+ mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
+ } else {
+ mListener.setConnectionId(1);
+ }
+
+ if (request.mAuthResp != null) {
+ if (!handleAuthResp(request.mAuthResp)) {
+ code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
+ mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+ request.mAuthResp));
+ }
+ request.mAuthResp = null;
+ }
+
+ if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
+
+ if (request.mAuthChall != null) {
+ handleAuthChall(request);
+ request.mAuthChall = null;
+ }
+
+ try {
+ mListener.onDisconnect(request, reply);
+ } catch (Exception e) {
+ sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
+ return;
+ }
+
+ long id = mListener.getConnectionId();
+ if (id == -1) {
+ reply.mConnectionID = null;
+ } else {
+ reply.mConnectionID = ObexHelper.convertToByteArray(id);
+ }
+
+ head = ObexHelper.createHeader(reply, false);
+ totalLength += head.length;
+
+ if (totalLength > mMaxPacketLength) {
+ totalLength = 3;
+ head = null;
+ code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ // Compute Length of OBEX CONNECT packet
+ byte[] replyData;
+ if (head != null) {
+ replyData = new byte[3 + head.length];
+ } else {
+ replyData = new byte[3];
+ }
+ replyData[0] = (byte)code;
+ replyData[1] = (byte)(totalLength >> 8);
+ replyData[2] = (byte)totalLength;
+ if (head != null) {
+ System.arraycopy(head, 0, replyData, 3, head.length);
+ }
+ /*
+ * Write the OBEX DISCONNECT packet to the server. Byte 0: response code
+ * Byte 1&2: Connect Packet Length Byte 3 to n: headers
+ */
+ mOutput.write(replyData);
+ mOutput.flush();
+ }
+
+ /**
+ * Handles a connect request from a client. This method will read the rest
+ * of the request from the client. Assuming the request is valid, it will
+ * create a <code>HeaderSet</code> object to pass to the
+ * <code>ServerRequestHandler</code> object. After the handler processes the
+ * request, this method will create a reply message to send to the server
+ * with the response code provided.
+ * @throws IOException if an error occurred at the transport layer
+ */
+ private void handleConnectRequest() throws IOException {
+ int packetLength;
+ @SuppressWarnings("unused")
+ int version;
+ @SuppressWarnings("unused")
+ int flags;
+ int totalLength = 7;
+ byte[] head = null;
+ int code = -1;
+ HeaderSet request = new HeaderSet();
+ HeaderSet reply = new HeaderSet();
+ int bytesReceived;
+
+ /*
+ * Read in the length of the OBEX packet, OBEX version, flags, and max
+ * packet length
+ */
+ packetLength = mInput.read();
+ packetLength = (packetLength << 8) + mInput.read();
+ version = mInput.read();
+ flags = mInput.read();
+ mMaxPacketLength = mInput.read();
+ mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read();
+
+ // should we check it?
+ if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
+ mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
+ }
+
+ if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) {
+ code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
+ totalLength = 7;
+ } else {
+ if (packetLength > 7) {
+ byte[] headers = new byte[packetLength - 7];
+ bytesReceived = mInput.read(headers);
+
+ while (bytesReceived != headers.length) {
+ bytesReceived += mInput.read(headers, bytesReceived, headers.length
+ - bytesReceived);
+ }
+
+ ObexHelper.updateHeaderSet(request, headers);
+ }
+
+ if (request.mConnectionID != null) {
+ mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
+ } else {
+ mListener.setConnectionId(1);
+ }
+
+ if (request.mAuthResp != null) {
+ if (!handleAuthResp(request.mAuthResp)) {
+ code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
+ mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
+ request.mAuthResp));
+ }
+ request.mAuthResp = null;
+ }
+
+ if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
+ if (request.mAuthChall != null) {
+ handleAuthChall(request);
+ reply.mAuthResp = new byte[request.mAuthResp.length];
+ System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
+ reply.mAuthResp.length);
+ request.mAuthChall = null;
+ request.mAuthResp = null;
+ }
+
+ try {
+ code = mListener.onConnect(request, reply);
+ code = validateResponseCode(code);
+
+ if (reply.nonce != null) {
+ mChallengeDigest = new byte[16];
+ System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
+ } else {
+ mChallengeDigest = null;
+ }
+ long id = mListener.getConnectionId();
+ if (id == -1) {
+ reply.mConnectionID = null;
+ } else {
+ reply.mConnectionID = ObexHelper.convertToByteArray(id);
+ }
+
+ head = ObexHelper.createHeader(reply, false);
+ totalLength += head.length;
+
+ if (totalLength > mMaxPacketLength) {
+ totalLength = 7;
+ head = null;
+ code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ totalLength = 7;
+ head = null;
+ code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+
+ }
+ }
+
+ // Compute Length of OBEX CONNECT packet
+ byte[] length = ObexHelper.convertToByteArray(totalLength);
+
+ /*
+ * Write the OBEX CONNECT packet to the server. Byte 0: response code
+ * Byte 1&2: Connect Packet Length Byte 3: OBEX Version Number
+ * (Presently, 0x10) Byte 4: Flags (For TCP 0x00) Byte 5&6: Max OBEX
+ * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers
+ */
+ byte[] sendData = new byte[totalLength];
+ sendData[0] = (byte)code;
+ sendData[1] = length[2];
+ sendData[2] = length[3];
+ sendData[3] = (byte)0x10;
+ sendData[4] = (byte)0x00;
+ sendData[5] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT >> 8);
+ sendData[6] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT & 0xFF);
+
+ if (head != null) {
+ System.arraycopy(head, 0, sendData, 7, head.length);
+ }
+
+ mOutput.write(sendData);
+ mOutput.flush();
+ }
+
+ /**
+ * Closes the server session - in detail close I/O streams and the
+ * underlying transport layer. Internal flag is also set so that later
+ * attempt to read/write will throw an exception.
+ */
+ public synchronized void close() {
+ if (mListener != null) {
+ mListener.onClose();
+ }
+ try {
+ mInput.close();
+ mOutput.close();
+ mTransport.close();
+ mClosed = true;
+ } catch (Exception e) {
+ }
+ mTransport = null;
+ mInput = null;
+ mOutput = null;
+ mListener = null;
+ }
+
+ /**
+ * Verifies that the response code is valid. If it is not valid, it will
+ * return the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code.
+ * @param code the response code to check
+ * @return the valid response code or <code>OBEX_HTTP_INTERNAL_ERROR</code>
+ * if <code>code</code> is not valid
+ */
+ private int validateResponseCode(int code) {
+
+ if ((code >= ResponseCodes.OBEX_HTTP_OK) && (code <= ResponseCodes.OBEX_HTTP_PARTIAL)) {
+ return code;
+ }
+ if ((code >= ResponseCodes.OBEX_HTTP_MULT_CHOICE)
+ && (code <= ResponseCodes.OBEX_HTTP_USE_PROXY)) {
+ return code;
+ }
+ if ((code >= ResponseCodes.OBEX_HTTP_BAD_REQUEST)
+ && (code <= ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE)) {
+ return code;
+ }
+ if ((code >= ResponseCodes.OBEX_HTTP_INTERNAL_ERROR)
+ && (code <= ResponseCodes.OBEX_HTTP_VERSION)) {
+ return code;
+ }
+ if ((code >= ResponseCodes.OBEX_DATABASE_FULL)
+ && (code <= ResponseCodes.OBEX_DATABASE_LOCKED)) {
+ return code;
+ }
+ return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+
+}
diff --git a/obex/javax/obex/SessionNotifier.java b/obex/javax/obex/SessionNotifier.java
new file mode 100644
index 0000000..9836dd6
--- /dev/null
+++ b/obex/javax/obex/SessionNotifier.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2008-2009, Motorola, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Motorola, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package javax.obex;
+
+import java.io.IOException;
+
+/**
+ * The <code>SessionNotifier</code> interface defines a connection notifier for
+ * server-side OBEX connections. When a <code>SessionNotifier</code> is created
+ * and calls <code>acceptAndOpen()</code>, it will begin listening for clients
+ * to create a connection at the transport layer. When the transport layer
+ * connection is received, the <code>acceptAndOpen()</code> method will return a
+ * <code>javax.microedition.io.Connection</code> that is the connection to the
+ * client. The <code>acceptAndOpen()</code> method also takes a
+ * <code>ServerRequestHandler</code> argument that will process the requests
+ * from the client that connects to the server.
+ * @hide
+ */
+public interface SessionNotifier {
+
+ /**
+ * Waits for a transport layer connection to be established and specifies
+ * the handler to handle the requests from the client. No authenticator is
+ * associated with this connection, therefore, it is implementation
+ * dependent as to how an authentication challenge and authentication
+ * response header will be received and processed.
+ * <P>
+ * <H4>Additional Note for OBEX over Bluetooth</H4> If this method is called
+ * on a <code>SessionNotifier</code> object that does not have a
+ * <code>ServiceRecord</code> in the SDDB, the <code>ServiceRecord</code>
+ * for this object will be added to the SDDB. This method requests the BCC
+ * to put the local device in connectable mode so that it will respond to
+ * connection attempts by clients.
+ * <P>
+ * The following checks are done to verify that the service record provided
+ * is valid. If any of these checks fail, then a
+ * <code>ServiceRegistrationException</code> is thrown.
+ * <UL>
+ * <LI>ServiceClassIDList and ProtocolDescriptorList, the mandatory service
+ * attributes for a <code>btgoep</code> service record, must be present in
+ * the <code>ServiceRecord</code> associated with this notifier.
+ * <LI>L2CAP, RFCOMM and OBEX must all be in the ProtocolDescriptorList
+ * <LI>The <code>ServiceRecord</code> associated with this notifier must not
+ * have changed the RFCOMM server channel number
+ * </UL>
+ * <P>
+ * This method will not ensure that <code>ServiceRecord</code> associated
+ * with this notifier is a completely valid service record. It is the
+ * responsibility of the application to ensure that the service record
+ * follows all of the applicable syntactic and semantic rules for service
+ * record correctness.
+ * @param handler the request handler that will respond to OBEX requests
+ * @return the connection to the client
+ * @throws IOException if an error occurs in the transport layer
+ * @throws NullPointerException if <code>handler</code> is <code>null</code>
+ */
+ ObexSession acceptAndOpen(ServerRequestHandler handler) throws IOException;
+
+ /**
+ * Waits for a transport layer connection to be established and specifies
+ * the handler to handle the requests from the client and the
+ * <code>Authenticator</code> to use to respond to authentication challenge
+ * and authentication response headers.
+ * <P>
+ * <H4>Additional Note for OBEX over Bluetooth</H4> If this method is called
+ * on a <code>SessionNotifier</code> object that does not have a
+ * <code>ServiceRecord</code> in the SDDB, the <code>ServiceRecord</code>
+ * for this object will be added to the SDDB. This method requests the BCC
+ * to put the local device in connectable mode so that it will respond to
+ * connection attempts by clients.
+ * <P>
+ * The following checks are done to verify that the service record provided
+ * is valid. If any of these checks fail, then a
+ * <code>ServiceRegistrationException</code> is thrown.
+ * <UL>
+ * <LI>ServiceClassIDList and ProtocolDescriptorList, the mandatory service
+ * attributes for a <code>btgoep</code> service record, must be present in
+ * the <code>ServiceRecord</code> associated with this notifier.
+ * <LI>L2CAP, RFCOMM and OBEX must all be in the ProtocolDescriptorList
+ * <LI>The <code>ServiceRecord</code> associated with this notifier must not
+ * have changed the RFCOMM server channel number
+ * </UL>
+ * <P>
+ * This method will not ensure that <code>ServiceRecord</code> associated
+ * with this notifier is a completely valid service record. It is the
+ * responsibility of the application to ensure that the service record
+ * follows all of the applicable syntactic and semantic rules for service
+ * record correctness.
+ * @param handler the request handler that will respond to OBEX requests
+ * @param auth the <code>Authenticator</code> to use with this connection;
+ * if <code>null</code> then no <code>Authenticator</code> will be
+ * used
+ * @return the connection to the client
+ * @throws IOException if an error occurs in the transport layer
+ * @throws NullPointerException if <code>handler</code> is <code>null</code>
+ */
+ ObexSession acceptAndOpen(ServerRequestHandler handler, Authenticator auth) throws IOException;
+}
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 25cfcb8..545fd0e 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -131,6 +131,30 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGL
/* Interfaces defined by EGL_KHR_image above */
#endif
+
+#ifndef EGL_ANDROID_image_native_buffer
+#define EGL_ANDROID_image_native_buffer 1
+struct android_native_buffer_t;
+#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_ANDROID_get_render_buffer
+#define EGL_ANDROID_get_render_buffer 1
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer EGLAPIENTRY eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw);
+#endif
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETRENDERBUFFERANDROIDPROC) (EGLDisplay dpy, EGLSurface draw);
+#endif
+
+#ifndef EGL_ANDROID_swap_rectangle
+#define EGL_ANDROID_swap_rectangle 1
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSetSwapRectangleANDROID (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
+#endif
+
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/include/EGL/eglnatives.h b/opengl/include/EGL/eglnatives.h
deleted file mode 100644
index 21622dc..0000000
--- a/opengl/include/EGL/eglnatives.h
+++ /dev/null
@@ -1,271 +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_EGLNATIVES_H
-#define ANDROID_EGLNATIVES_H
-
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*****************************************************************************/
-
-/* flags returned from swapBuffer */
-#define EGL_NATIVES_FLAG_SIZE_CHANGED 0x00000001
-
-/* surface flags */
-#define EGL_NATIVES_FLAG_DESTROY_BACKBUFFER 0x00000001
-
-enum native_pixel_format_t
-{
- NATIVE_PIXEL_FORMAT_RGBA_8888 = 1,
- NATIVE_PIXEL_FORMAT_RGB_565 = 4,
- NATIVE_PIXEL_FORMAT_BGRA_8888 = 5,
- NATIVE_PIXEL_FORMAT_RGBA_5551 = 6,
- NATIVE_PIXEL_FORMAT_RGBA_4444 = 7,
- NATIVE_PIXEL_FORMAT_YCbCr_422_SP= 0x10,
- NATIVE_PIXEL_FORMAT_YCbCr_420_SP= 0x11,
-};
-
-enum native_memory_type_t
-{
- NATIVE_MEMORY_TYPE_PMEM = 0,
- NATIVE_MEMORY_TYPE_GPU = 1,
- NATIVE_MEMORY_TYPE_FB = 2,
- NATIVE_MEMORY_TYPE_HEAP = 128
-};
-
-
-struct egl_native_window_t
-{
- /*
- * magic must be set to 0x600913
- */
- uint32_t magic;
-
- /*
- * must be sizeof(egl_native_window_t)
- */
- uint32_t version;
-
- /*
- * ident is reserved for the Android platform
- */
- uint32_t ident;
-
- /*
- * width, height and stride of the window in pixels
- * Any of these value can be nul in which case GL commands are
- * accepted and processed as usual, but not rendering occurs.
- */
- int width; // w=h=0 is legal
- int height;
- int stride;
-
- /*
- * format of the native window (see ui/PixelFormat.h)
- */
- int format;
-
- /*
- * Offset of the bits in the VRAM
- */
- intptr_t offset;
-
- /*
- * flags describing some attributes of this surface
- * EGL_NATIVES_FLAG_DESTROY_BACKBUFFER: backbuffer not preserved after
- * eglSwapBuffers
- */
- uint32_t flags;
-
- /*
- * horizontal and vertical resolution in DPI
- */
- float xdpi;
- float ydpi;
-
- /*
- * refresh rate in frames per second (Hz)
- */
- float fps;
-
-
- /*
- * Base memory virtual address of the surface in the CPU side
- */
- intptr_t base;
-
- /*
- * Heap the offset above is based from
- */
- int fd;
-
- /*
- * Memory type the surface resides into
- */
- uint8_t memory_type;
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- uint8_t reserved_pad[3];
- int reserved[8];
-
- /*
- * Vertical stride (only relevant with planar formats)
- */
-
- int vstride;
-
- /*
- * Hook called by EGL to hold a reference on this structure
- */
- void (*incRef)(struct egl_native_window_t* window);
-
- /*
- * Hook called by EGL to release a reference on this structure
- */
- void (*decRef)(struct egl_native_window_t* window);
-
- /*
- * Hook called by EGL to perform a page flip. This function
- * may update the size attributes above, in which case it returns
- * the EGL_NATIVES_FLAG_SIZE_CHANGED bit set.
- */
- uint32_t (*swapBuffers)(struct egl_native_window_t* window);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc_0)(void);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc_1)(void);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc_2)(void);
-
-
- /*
- * Hook called by EGL when the native surface is associated to EGL
- * (eglCreateWindowSurface). Can be NULL.
- */
- void (*connect)(struct egl_native_window_t* window);
-
- /*
- * Hook called by EGL when eglDestroySurface is called. Can be NULL.
- */
- void (*disconnect)(struct egl_native_window_t* window);
-
- /*
- * Reserved for future use. MUST BE ZERO.
- */
- void (*reserved_proc[11])(void);
-
- /*
- * Some storage reserved for the oem driver.
- */
- intptr_t oem[4];
-};
-
-
-struct egl_native_pixmap_t
-{
- int32_t version; /* must be 32 */
- int32_t width;
- int32_t height;
- int32_t stride;
- uint8_t* data;
- uint8_t format;
- uint8_t rfu[3];
- union {
- uint32_t compressedFormat;
- int32_t vstride;
- };
- int32_t reserved;
-};
-
-/*****************************************************************************/
-
-/*
- * This a convenience function to create a NativeWindowType surface
- * that maps to the whole screen
- * This function is actually implemented in libui.so
- */
-
-struct egl_native_window_t* android_createDisplaySurface();
-
-/*****************************************************************************/
-
-
-/*
- * OEM's egl's library (libhgl.so) must imlement these hooks to allocate
- * the GPU memory they need
- */
-
-
-typedef struct
-{
- // for internal use
- void* user;
- // virtual address of this area
- void* base;
- // size of this area in bytes
- size_t size;
- // physical address of this area
- void* phys;
- // offset in this area available to the GPU
- size_t offset;
- // fd of this area
- int fd;
-} gpu_area_t;
-
-typedef struct
-{
- // area where GPU registers are mapped
- gpu_area_t regs;
- // number of extra areas (currently limited to 2)
- int32_t count;
- // extra GPU areas (currently limited to 2)
- gpu_area_t gpu[2];
-} request_gpu_t;
-
-
-typedef request_gpu_t* (*OEM_EGL_acquire_gpu_t)(void* user);
-typedef int (*OEM_EGL_release_gpu_t)(void* user, request_gpu_t* handle);
-typedef void (*register_gpu_t)
- (void* user, OEM_EGL_acquire_gpu_t, OEM_EGL_release_gpu_t);
-
-void oem_register_gpu(
- void* user,
- OEM_EGL_acquire_gpu_t acquire,
- OEM_EGL_release_gpu_t release);
-
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ANDROID_EGLNATIVES_H */
diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h
index ac00901..53e9e6116 100644
--- a/opengl/include/EGL/eglplatform.h
+++ b/opengl/include/EGL/eglplatform.h
@@ -89,9 +89,10 @@ typedef Window EGLNativeWindowType;
#elif defined(ANDROID)
-#include <EGL/eglnatives.h>
+struct android_native_window_t;
+struct egl_native_pixmap_t;
-typedef struct egl_native_window_t* EGLNativeWindowType;
+typedef struct android_native_window_t* EGLNativeWindowType;
typedef struct egl_native_pixmap_t* EGLNativePixmapType;
typedef void* EGLNativeDisplayType;
diff --git a/opengl/include/GLES/glplatform.h b/opengl/include/GLES/glplatform.h
index 0924cae..198e679 100644
--- a/opengl/include/GLES/glplatform.h
+++ b/opengl/include/GLES/glplatform.h
@@ -28,12 +28,6 @@
#define GL_APIENTRY KHRONOS_APIENTRY
-// XXX: this should probably not be here
-#define GL_DIRECT_TEXTURE_2D_QUALCOMM 0x7E80
-
-// XXX: not sure how this is intended to be used
-#define GL_GLEXT_PROTOTYPES
-
#endif
#endif /* __glplatform_h_ */
diff --git a/opengl/include/GLES2/gl2.h b/opengl/include/GLES2/gl2.h
new file mode 100644
index 0000000..0182a67
--- /dev/null
+++ b/opengl/include/GLES2/gl2.h
@@ -0,0 +1,620 @@
+#ifndef __gl2_h_
+#define __gl2_h_
+
+/* $Revision: 7173 $ on $Date:: 2009-01-09 11:18:21 -0800 #$ */
+
+#include <GLES2/gl2platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+typedef void GLvoid;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef khronos_int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLfixed;
+
+/* GL types for handling large vertex buffer objects */
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_2_0 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* AlphaFunction (not supported in ES20) */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD 0x8006
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH 0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VIEWPORT 0x0BA2
+#define GL_SCISSOR_BOX 0x0C10
+/* GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+/* GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_DELETE_STATUS 0x8B80
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_INVERT 0x150A
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+#define GL_TEXTURE 0x1702
+
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MIRRORED_REPEAT 0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_COMPILER 0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGB565 0x8D62
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_STENCIL_INDEX 0x1901
+#define GL_STENCIL_INDEX8 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+
+#define GL_NONE 0
+
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+/*-------------------------------------------------------------------------
+ * GL core functions.
+ *-----------------------------------------------------------------------*/
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const char* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const char* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, char* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, char* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const char* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const char** string, const GLint* length);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2_h_ */
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
new file mode 100644
index 0000000..72f1ae7
--- /dev/null
+++ b/opengl/include/GLES2/gl2ext.h
@@ -0,0 +1,518 @@
+#ifndef __gl2ext_h_
+#define __gl2ext_h_
+
+/* $Revision: 8271 $ on $Date:: 2009-05-21 09:33:40 -0700 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+# define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES 0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#endif
+
+/* GL_OES_depth_texture */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES 0x88B9
+#define GL_BUFFER_ACCESS_OES 0x88BB
+#define GL_BUFFER_MAPPED_OES 0x88BC
+#define GL_BUFFER_MAP_POINTER_OES 0x88BD
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES 0x8051
+#define GL_RGBA8_OES 0x8058
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES 0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES 0x8D47
+#endif
+
+/* GL_OES_texture3D */
+#ifndef GL_OES_texture3D
+#define GL_TEXTURE_WRAP_R_OES 0x8072
+#define GL_TEXTURE_3D_OES 0x806F
+#define GL_TEXTURE_BINDING_3D_OES 0x806A
+#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073
+#define GL_SAMPLER_3D_OES 0x8B5F
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_HALF_FLOAT_OES 0x8D61
+#endif
+
+/* GL_OES_vertex_half_float */
+/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6
+#define GL_INT_10_10_10_2_OES 0x8DF7
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD 0x87F9
+#define GL_3DC_XY_AMD 0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_Z400_BINARY_AMD 0x8740
+#endif
+
+/* GL_AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_COUNTER_TYPE_AMD 0x8BC0
+#define GL_COUNTER_RANGE_AMD 0x8BC1
+#define GL_UNSIGNED_INT64_AMD 0x8BC2
+#define GL_PERCENTAGE_AMD 0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5
+#define GL_PERFMON_RESULT_AMD 0x8BC6
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_BGRA 0x80E1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_BGRA 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_driver_control */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
+#endif
+
+/*------------------------------------------------------------------------*
+ * End of extension tokens, start of corresponding extension functions
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 1
+#endif
+
+/* GL_OES_depth_texture */
+#ifndef GL_OES_depth_texture
+#define GL_OES_depth_texture 1
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 1
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 1
+#endif
+
+/* GL_OES_fragment_precision_high */
+#ifndef GL_OES_fragment_precision_high
+#define GL_OES_fragment_precision_high 1
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_OES_get_program_binary 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, void** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void** params);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 1
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_OES_standard_derivatives 1
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 1
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 1
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_OES_texture_3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
+typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+
+/* GL_OES_texture_float_linear */
+#ifndef GL_OES_texture_float_linear
+#define GL_OES_texture_float_linear 1
+#endif
+
+/* GL_OES_texture_half_float_linear */
+#ifndef GL_OES_texture_half_float_linear
+#define GL_OES_texture_half_float_linear 1
+#endif
+
+/* GL_OES_texture_float */
+#ifndef GL_OES_texture_float
+#define GL_OES_texture_float 1
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_OES_texture_half_float 1
+#endif
+
+/* GL_OES_texture_npot */
+#ifndef GL_OES_texture_npot
+#define GL_OES_texture_npot 1
+#endif
+
+/* GL_OES_vertex_half_float */
+#ifndef GL_OES_vertex_half_float
+#define GL_OES_vertex_half_float 1
+#endif
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_OES_vertex_type_10_10_10_2 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 1
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 1
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_AMD_program_binary_Z400 1
+#endif
+
+/* AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, char *groupString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data);
+GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, char *groupString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data);
+typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_EXT_texture_type_2_10_10_10_REV 1
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_EXT_texture_format_BGRA8888 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 1
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences);
+GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei n, GLuint *fences);
+GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint fence);
+GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint fence);
+GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint fence);
+GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint fence, GLenum condition);
+#endif
+typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_driver_control */
+#ifndef GL_QCOM_driver_control
+#define GL_QCOM_driver_control 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
+GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString);
+GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
+GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+#endif
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_QCOM_perfmon_global_mode 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2ext_h_ */
diff --git a/opengl/include/GLES2/gl2platform.h b/opengl/include/GLES2/gl2platform.h
new file mode 100644
index 0000000..3e9036c
--- /dev/null
+++ b/opengl/include/GLES2/gl2platform.h
@@ -0,0 +1,29 @@
+#ifndef __gl2platform_h_
+#define __gl2platform_h_
+
+/* $Revision: 7173 $ on $Date:: 2009-01-09 11:18:21 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
+ * Last modified on 2008/12/19
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+#ifndef GL_APICALL
+#define GL_APICALL KHRONOS_APICALL
+#endif
+
+#define GL_APIENTRY KHRONOS_APIENTRY
+
+#endif /* __gl2platform_h_ */
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index ccb27cc..022da0c 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -204,7 +204,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
// underlying surface is created and destroyed
SurfaceHolder holder = getHolder();
holder.addCallback(this);
- holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
}
/**
@@ -656,25 +655,27 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
EGLConfig closestConfig = null;
int closestDistance = 1000;
for(EGLConfig config : configs) {
- int r = findConfigAttrib(egl, display, config,
- EGL10.EGL_RED_SIZE, 0);
- int g = findConfigAttrib(egl, display, config,
- EGL10.EGL_GREEN_SIZE, 0);
- int b = findConfigAttrib(egl, display, config,
- EGL10.EGL_BLUE_SIZE, 0);
- int a = findConfigAttrib(egl, display, config,
- EGL10.EGL_ALPHA_SIZE, 0);
int d = findConfigAttrib(egl, display, config,
EGL10.EGL_DEPTH_SIZE, 0);
int s = findConfigAttrib(egl, display, config,
EGL10.EGL_STENCIL_SIZE, 0);
- int distance = Math.abs(r - mRedSize)
- + Math.abs(g - mGreenSize)
- + Math.abs(b - mBlueSize) + Math.abs(a - mAlphaSize)
- + Math.abs(d - mDepthSize) + Math.abs(s - mStencilSize);
- if (distance < closestDistance) {
- closestDistance = distance;
- closestConfig = config;
+ if (d >= mDepthSize && s>= mStencilSize) {
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+ int distance = Math.abs(r - mRedSize)
+ + Math.abs(g - mGreenSize)
+ + Math.abs(b - mBlueSize)
+ + Math.abs(a - mAlphaSize);
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestConfig = config;
+ }
}
}
return closestConfig;
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 3ce0414..2522656 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -6,6 +6,9 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+# Set to 1 to use gralloc and copybits
+LIBAGL_USE_GRALLOC_COPYBITS := 1
+
LOCAL_SRC_FILES:= \
egl.cpp \
state.cpp \
@@ -29,13 +32,23 @@ endif
ifneq ($(TARGET_SIMULATOR),true)
# we need to access the private Bionic header <bionic_tls.h>
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+ LOCAL_C_INCLUDES += bionic/libc/private
+endif
+
+ifeq ($(LIBAGL_USE_GRALLOC_COPYBITS),1)
+ LOCAL_CFLAGS += -DLIBAGL_USE_GRALLOC_COPYBITS
+ LOCAL_SRC_FILES += copybit.cpp
endif
-LOCAL_SHARED_LIBRARIES := libcutils libutils libpixelflinger
+LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger
LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_LDLIBS := -lpthread -ldl
-LOCAL_MODULE:= libagl
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
+LOCAL_MODULE:= libGLES_android
include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
index ce31854..255ccac 100644
--- a/opengl/libagl/TextureObjectManager.cpp
+++ b/opengl/libagl/TextureObjectManager.cpp
@@ -1,16 +1,16 @@
/*
** Copyright 2006, The Android Open Source Project
**
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
**
- ** http://www.apache.org/licenses/LICENSE-2.0
+ ** http://www.apache.org/licenses/LICENSE-2.0
**
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -19,11 +19,13 @@
#include "context.h"
#include "TextureObjectManager.h"
+#include <private/ui/android_natives_priv.h>
+
namespace android {
// ----------------------------------------------------------------------------
EGLTextureObject::EGLTextureObject()
- : mCount(0), mSize(0)
+ : mSize(0)
{
init();
}
@@ -53,6 +55,10 @@ void EGLTextureObject::init()
memset(crop_rect, 0, sizeof(crop_rect));
generate_mipmap = GL_FALSE;
direct = GL_FALSE;
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ try_copybit = false;
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+ buffer = 0;
}
void EGLTextureObject::copyParameters(const sp<EGLTextureObject>& old)
@@ -123,6 +129,7 @@ status_t EGLTextureObject::setSurface(GGLSurface const* s)
}
surface = *s;
internalformat = 0;
+ buffer = 0;
// we should keep the crop_rect, but it's delicate because
// the new size of the surface could make it invalid.
@@ -141,12 +148,26 @@ status_t EGLTextureObject::setSurface(GGLSurface const* s)
return NO_ERROR;
}
+status_t EGLTextureObject::setImage(android_native_buffer_t* native_buffer)
+{
+ GGLSurface sur;
+ sur.version = sizeof(GGLSurface);
+ sur.width = native_buffer->width;
+ sur.height= native_buffer->height;
+ sur.stride= native_buffer->stride;
+ sur.format= native_buffer->format;
+ sur.data = 0;
+ setSurface(&sur);
+ buffer = native_buffer;
+ return NO_ERROR;
+}
+
status_t EGLTextureObject::reallocate(
GLint level, int w, int h, int s,
int format, int compressedFormat, int bpr)
{
const size_t size = h * bpr;
- if (level == 0)
+ if (level == 0)
{
if (size!=mSize || !surface.data) {
if (mSize && surface.data) {
@@ -177,9 +198,9 @@ status_t EGLTextureObject::reallocate(
return NO_MEMORY;
}
- LOGW_IF(level-1 >= mNumExtraLod,
+ LOGW_IF(level-1 >= mNumExtraLod,
"specifying mipmap level %d, but # of level is %d",
- level, mNumExtraLod+1);
+ level, mNumExtraLod+1);
GGLSurface& mipmap = editMip(level);
if (mipmap.data)
@@ -224,7 +245,7 @@ status_t EGLTextureObject::reallocate(
// ----------------------------------------------------------------------------
EGLSurfaceManager::EGLSurfaceManager()
- : TokenManager(), mCount(0)
+ : TokenManager()
{
}
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
index 74ed1a4..279e040 100644
--- a/opengl/libagl/TextureObjectManager.h
+++ b/opengl/libagl/TextureObjectManager.h
@@ -1,16 +1,16 @@
/*
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -30,6 +30,8 @@
#include <private/pixelflinger/ggl_context.h>
#include <GLES/gl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
#include "Tokenizer.h"
#include "TokenManager.h"
@@ -39,22 +41,20 @@ namespace android {
// ----------------------------------------------------------------------------
-class EGLTextureObject
+class EGLTextureObject : public LightRefBase<EGLTextureObject>
{
public:
EGLTextureObject();
~EGLTextureObject();
- // protocol for sp<>
- inline void incStrong(const void* id) const;
- inline void decStrong(const void* id) const;
- inline uint32_t getStrongCount() const;
+ status_t setSurface(GGLSurface const* s);
+ status_t setImage(android_native_buffer_t* buffer);
+ void setImageBits(void* vaddr) { surface.data = (GGLubyte*)vaddr; }
- status_t setSurface(GGLSurface const* s);
status_t reallocate(GLint level,
int w, int h, int s,
int format, int compressedFormat, int bpr);
- inline size_t size() const;
+ inline size_t size() const { return mSize; }
const GGLSurface& mip(int lod) const;
GGLSurface& editMip(int lod);
bool hasMipmaps() const { return mMipmaps!=0; }
@@ -65,7 +65,6 @@ private:
status_t allocateMipmaps();
void freeMipmaps();
void init();
- mutable int32_t mCount;
size_t mSize;
GGLSurface *mMipmaps;
int mNumExtraLod;
@@ -81,36 +80,22 @@ public:
GLint crop_rect[4];
GLint generate_mipmap;
GLint direct;
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ bool try_copybit;
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+ android_native_buffer_t* buffer;
};
-void EGLTextureObject::incStrong(const void* id) const {
- android_atomic_inc(&mCount);
-}
-void EGLTextureObject::decStrong(const void* id) const {
- if (android_atomic_dec(&mCount) == 1) {
- delete this;
- }
-}
-uint32_t EGLTextureObject::getStrongCount() const {
- return mCount;
-}
-size_t EGLTextureObject::size() const {
- return mSize;
-}
-
// ----------------------------------------------------------------------------
-class EGLSurfaceManager : public TokenManager
+class EGLSurfaceManager :
+ public LightRefBase<EGLSurfaceManager>,
+ public TokenManager
{
public:
EGLSurfaceManager();
~EGLSurfaceManager();
- // protocol for sp<>
- inline void incStrong(const void* id) const;
- inline void decStrong(const void* id) const;
- typedef void weakref_type;
-
sp<EGLTextureObject> createTexture(GLuint name);
sp<EGLTextureObject> removeTexture(GLuint name);
sp<EGLTextureObject> replaceTexture(GLuint name);
@@ -118,21 +103,10 @@ public:
sp<EGLTextureObject> texture(GLuint name);
private:
- mutable int32_t mCount;
mutable Mutex mLock;
KeyedVector< GLuint, sp<EGLTextureObject> > mTextures;
};
-void EGLSurfaceManager::incStrong(const void* id) const {
- android_atomic_inc(&mCount);
-}
-void EGLSurfaceManager::decStrong(const void* id) const {
- if (android_atomic_dec(&mCount) == 1) {
- delete this;
- }
-}
-
-
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
index 3e9c6a5..f414ee5 100644
--- a/opengl/libagl/array.cpp
+++ b/opengl/libagl/array.cpp
@@ -1,16 +1,16 @@
-/*
+/*
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -26,6 +26,9 @@
#include "primitives.h"
#include "texture.h"
#include "BufferObjectManager.h"
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+#include "copybit.h"
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
// ----------------------------------------------------------------------------
@@ -250,7 +253,7 @@ static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
v[2] = GGL_S_TO_X(p[2]);
}
-typedef array_t::fetcher_t fn_t;
+typedef array_t::fetcher_t fn_t;
static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x}
{ 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
@@ -334,7 +337,7 @@ void array_t::init(
this->bounds = count;
}
-inline void array_t::resolve()
+inline void array_t::resolve()
{
physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer;
}
@@ -465,7 +468,7 @@ vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index)
// We compute directly the index of a "free" entry from the locked
// state of v[2] and v[3].
v = c->vc.vBuffer + 2;
- v += v[0].locked | (v[1].locked<<1);
+ v += v[0].locked | (v[1].locked<<1);
}
// note: compileElement clears v->flags
c->arrays.compileElement(c, v, index);
@@ -480,7 +483,7 @@ vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
#if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
- vertex_t* const v = c->vc.vCache +
+ vertex_t* const v = c->vc.vCache +
(index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
if (ggl_likely(v->index == index)) {
@@ -491,7 +494,7 @@ vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
#elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
- vertex_t* v = c->vc.vCache +
+ vertex_t* v = c->vc.vCache +
(index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
// always record LRU in v[0]
@@ -532,12 +535,12 @@ void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count)
return;
// vertex cache size must be multiple of 1
- const GLsizei vcs =
+ const GLsizei vcs =
(vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE);
do {
vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.cull = vertex_t::CLIP_ALL;
c->arrays.compileElements(c, v, first, num);
first += num;
@@ -569,13 +572,13 @@ void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count)
count -= 1;
// vertex cache size must be multiple of 1
- const GLsizei vcs =
+ const GLsizei vcs =
(vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE - 1);
do {
- v0 = c->vc.vBuffer + 0;
+ v0 = c->vc.vBuffer + 0;
v = c->vc.vBuffer + 1;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.compileElements(c, v, first, num);
first += num;
count -= num;
@@ -602,7 +605,7 @@ void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count)
return;
drawPrimitivesLineStrip(c, first, count);
if (ggl_likely(count >= 3)) {
- vertex_t* v0 = c->vc.vBuffer;
+ vertex_t* v0 = c->vc.vBuffer;
vertex_t* v1 = c->vc.vBuffer + 1;
c->arrays.compileElement(c, v1, first);
const uint32_t cc = v0->flags & v1->flags;
@@ -617,12 +620,12 @@ void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count)
return;
// vertex cache size must be multiple of 2
- const GLsizei vcs =
+ const GLsizei vcs =
((vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
do {
vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.cull = vertex_t::CLIP_ALL;
c->arrays.compileElements(c, v, first, num);
first += num;
@@ -662,14 +665,14 @@ static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
// because it allows us to preserve the same winding when the whole
// batch is culled. We also need 2 extra vertices in the array, because
// we always keep the two first ones.
- const GLsizei vcs =
+ const GLsizei vcs =
((vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
do {
- v0 = c->vc.vBuffer + 0;
- v1 = c->vc.vBuffer + 1;
+ v0 = c->vc.vBuffer + 0;
+ v1 = c->vc.vBuffer + 1;
v = c->vc.vBuffer + 2;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.compileElements(c, v, first, num);
first += num;
count -= num;
@@ -697,13 +700,19 @@ static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
} while (count > 0);
}
-void drawPrimitivesTriangleStrip(ogles_context_t* c,
+void drawPrimitivesTriangleStrip(ogles_context_t* c,
GLint first, GLsizei count) {
drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
}
void drawPrimitivesTriangleFan(ogles_context_t* c,
GLint first, GLsizei count) {
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (drawTriangleFanWithCopybit(c, first, count)) {
+ return;
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
}
@@ -713,12 +722,12 @@ void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count)
return;
// vertex cache size must be multiple of 3
- const GLsizei vcs =
+ const GLsizei vcs =
((vertex_cache_t::VERTEX_BUFFER_SIZE +
vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
do {
vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
+ GLsizei num = count > vcs ? vcs : count;
c->arrays.cull = vertex_t::CLIP_ALL;
c->arrays.compileElements(c, v, first, num);
first += num;
@@ -779,11 +788,11 @@ void drawIndexedPrimitivesLineStrip(ogles_context_t* c,
{
if (ggl_unlikely(count < 2))
return;
-
+
vertex_t * const v = c->vc.vBuffer;
vertex_t* v0 = v;
vertex_t* v1;
-
+
const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
c->arrays.compileElement(c, v0, read_index(type, indices));
count -= 1;
@@ -806,11 +815,11 @@ void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
drawIndexedPrimitivesLines(c, count, indices);
return;
}
-
+
vertex_t * const v = c->vc.vBuffer;
vertex_t* v0 = v;
vertex_t* v1;
-
+
const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
c->arrays.compileElement(c, v0, read_index(type, indices));
count -= 1;
@@ -825,7 +834,7 @@ void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
} while (count);
v1->locked = 0;
- v1 = c->vc.vBuffer;
+ v1 = c->vc.vBuffer;
const uint32_t cc = v0->flags & v1->flags;
if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
c->prims.renderLine(c, v0, v1);
@@ -861,7 +870,7 @@ static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c,
if (ggl_unlikely(count < 3))
return;
-
+
vertex_t * const v = c->vc.vBuffer;
vertex_t* v0 = v;
vertex_t* v1 = v+1;
@@ -985,17 +994,17 @@ void compileElements__3x_full(ogles_context_t* c,
const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
const size_t stride = c->arrays.vertex.stride / 4;
// const GLfixed* const& m = c->transforms.mvp.matrix.m;
-
+
GLfixed m[16];
memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
-
+
do {
const GLfixed rx = vp[0];
const GLfixed ry = vp[1];
const GLfixed rz = vp[2];
vp += stride;
v->index = first++;
- v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
+ v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
@@ -1023,7 +1032,7 @@ void compileElements__3x_full(ogles_context_t* c,
#pragma mark clippers
#endif
-static void clipVec4(vec4_t& nv,
+static void clipVec4(vec4_t& nv,
GLfixed t, const vec4_t& s, const vec4_t& p)
{
for (int i=0; i<4 ; i++)
@@ -1086,10 +1095,10 @@ void validate_arrays(ogles_context_t* c, GLenum mode)
// automatically turn it off (in fact we could when the 4th coordinate
// is not spcified in the vertex array).
// W interpolation is never needed for points.
- GLboolean perspective =
+ GLboolean perspective =
c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
-
+
// set anti-aliasing
GLboolean smooth = GL_FALSE;
switch (mode) {
@@ -1120,7 +1129,7 @@ void validate_arrays(ogles_context_t* c, GLenum mode)
if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
want |= transform_state_t::TEXTURE;
}
- if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
+ if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
want |= transform_state_t::MODELVIEW; // needs eye coords
}
ogles_validate_transform(c, want);
@@ -1139,18 +1148,18 @@ void validate_arrays(ogles_context_t* c, GLenum mode)
c->arrays.mv_transform =
c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
-
+
/*
* ***********************************************************************
* pick fetchers
* ***********************************************************************
*/
-
+
array_machine_t& am = c->arrays;
am.vertex.fetch = fetchNop;
am.normal.fetch = currentNormal;
am.color.fetch = currentColor;
-
+
if (am.vertex.enable) {
am.vertex.resolve();
if (am.vertex.bo || am.vertex.pointer) {
@@ -1366,9 +1375,18 @@ void glDrawArrays(GLenum mode, GLint first, GLsizei count)
if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
return; // all triangles are culled
+
validate_arrays(c, mode);
+
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_lock_textures(c);
+
drawArraysPrims[mode](c, first, count);
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_unlock_textures(c);
+
#if VC_CACHE_STATISTICS
c->vc.total = count;
c->vc.dump_stats(mode);
@@ -1413,15 +1431,23 @@ void glDrawElements(
// clear the vertex-cache
c->vc.clear();
validate_arrays(c, mode);
-
+
// if indices are in a buffer object, the pointer is treated as an
// offset in that buffer.
if (c->arrays.element_array_buffer) {
indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
}
+ const uint32_t enables = c->rasterizer.state.enables;
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_lock_textures(c);
+
drawElementsPrims[mode](c, count, indices);
+
+ if (enables & GGL_ENABLE_TMUS)
+ ogles_unlock_textures(c);
+
#if VC_CACHE_STATISTICS
c->vc.total = count;
c->vc.dump_stats(mode);
@@ -1448,7 +1474,7 @@ void glBindBuffer(GLenum target, GLuint buffer)
return;
}
}
- ((target == GL_ARRAY_BUFFER) ?
+ ((target == GL_ARRAY_BUFFER) ?
c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
}
@@ -1467,7 +1493,7 @@ void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usa
ogles_error(c, GL_INVALID_ENUM);
return;
}
- buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
+ buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
c->arrays.array_buffer : c->arrays.element_array_buffer);
if (bo == 0) {
@@ -1497,7 +1523,7 @@ void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvo
ogles_error(c, GL_INVALID_VALUE);
return;
}
- buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
+ buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
c->arrays.array_buffer : c->arrays.element_array_buffer);
if (bo == 0) {
@@ -1545,7 +1571,7 @@ void glDeleteBuffers(GLsizei n, const GLuint* buffers)
}
}
}
- }
+ }
c->bufferObjectManager->deleteBuffers(n, buffers);
c->bufferObjectManager->recycleTokens(n, buffers);
}
diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp
new file mode 100644
index 0000000..867459d
--- /dev/null
+++ b/opengl/libagl/copybit.cpp
@@ -0,0 +1,460 @@
+/*
+**
+** 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.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "context.h"
+#include "fp.h"
+#include "state.h"
+#include "matrix.h"
+#include "vertex.h"
+#include "light.h"
+#include "primitives.h"
+#include "texture.h"
+#include "BufferObjectManager.h"
+#include "TextureObjectManager.h"
+
+#include <hardware/gralloc.h>
+#include <hardware/copybit.h>
+#include <private/ui/android_natives_priv.h>
+
+
+#define DEBUG_COPYBIT true
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static void textureToCopyBitImage(
+ const GGLSurface* surface, buffer_handle_t buffer, copybit_image_t* img)
+{
+ img->w = surface->stride;
+ img->h = surface->height;
+ img->format = surface->format;
+ img->base = surface->data;
+ img->handle = (native_handle_t *)buffer;
+}
+
+struct clipRectRegion : public copybit_region_t {
+ clipRectRegion(ogles_context_t* c)
+ {
+ scissor_t const* scissor = &c->rasterizer.state.scissor;
+ r.l = scissor->left;
+ r.t = scissor->top;
+ r.r = scissor->right;
+ r.b = scissor->bottom;
+ next = iterate;
+ }
+private:
+ static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
+ *rect = static_cast<clipRectRegion const*>(self)->r;
+ const_cast<copybit_region_t *>(self)->next = iterate_done;
+ return 1;
+ }
+ static int iterate_done(copybit_region_t const *, copybit_rect_t*) {
+ return 0;
+ }
+ copybit_rect_t r;
+};
+
+static bool supportedCopybitsFormat(int format) {
+ switch (format) {
+ case COPYBIT_FORMAT_RGBA_8888:
+ case COPYBIT_FORMAT_RGBX_8888:
+ case COPYBIT_FORMAT_RGB_888:
+ case COPYBIT_FORMAT_RGB_565:
+ case COPYBIT_FORMAT_BGRA_8888:
+ case COPYBIT_FORMAT_RGBA_5551:
+ case COPYBIT_FORMAT_RGBA_4444:
+ case COPYBIT_FORMAT_YCbCr_422_SP:
+ case COPYBIT_FORMAT_YCbCr_420_SP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool hasAlpha(int format) {
+ switch (format) {
+ case COPYBIT_FORMAT_RGBA_8888:
+ case COPYBIT_FORMAT_BGRA_8888:
+ case COPYBIT_FORMAT_RGBA_5551:
+ case COPYBIT_FORMAT_RGBA_4444:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline int fixedToByte(GGLfixed val) {
+ return (val - (val >> 8)) >> 8;
+}
+
+/**
+ * Performs a quick check of the rendering state. If this function returns
+ * false we cannot use the copybit driver.
+ */
+
+static bool checkContext(ogles_context_t* c) {
+
+ // By convention copybitQuickCheckContext() has already returned true.
+ // avoid checking the same information again.
+
+ if (c->copybits.blitEngine == NULL) {
+ LOGD_IF(DEBUG_COPYBIT, "no copybit hal");
+ return false;
+ }
+
+ if (c->rasterizer.state.enables
+ & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
+ LOGD_IF(DEBUG_COPYBIT, "depth test and/or fog");
+ return false;
+ }
+
+ // Note: The drawSurfaceBuffer is only set for destination
+ // surfaces types that are supported by the hardware and
+ // do not have an alpha channel. So we don't have to re-check that here.
+
+ static const int tmu = 0;
+ texture_unit_t& u(c->textures.tmu[tmu]);
+ EGLTextureObject* textureObject = u.texture;
+
+ if (!supportedCopybitsFormat(textureObject->surface.format)) {
+ LOGD_IF(DEBUG_COPYBIT, "texture format not supported");
+ return false;
+ }
+ return true;
+}
+
+
+static bool copybit(GLint x, GLint y,
+ GLint w, GLint h,
+ EGLTextureObject* textureObject,
+ const GLint* crop_rect,
+ int transform,
+ ogles_context_t* c)
+{
+ // We assume checkContext has already been called and has already
+ // returned true.
+
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+
+ y = cbSurface.height - (y + h);
+
+ const GLint Ucr = crop_rect[0];
+ const GLint Vcr = crop_rect[1];
+ const GLint Wcr = crop_rect[2];
+ const GLint Hcr = crop_rect[3];
+
+ GLint screen_w = w;
+ GLint screen_h = h;
+ int32_t dsdx = Wcr << 16; // dsdx = ((Wcr/screen_w)/Wt)*Wt
+ int32_t dtdy = Hcr << 16; // dtdy = -((Hcr/screen_h)/Ht)*Ht
+ if (transform & COPYBIT_TRANSFORM_ROT_90) {
+ swap(screen_w, screen_h);
+ }
+ if (dsdx!=screen_w || dtdy!=screen_h) {
+ // in most cases the divide is not needed
+ dsdx /= screen_w;
+ dtdy /= screen_h;
+ }
+ dtdy = -dtdy; // see equation of dtdy above
+ if (dsdx < c->copybits.minScale || dsdx > c->copybits.maxScale
+ || dtdy < c->copybits.minScale || dtdy > c->copybits.maxScale) {
+ // The requested scale is out of the range the hardware
+ // can support.
+ LOGD_IF(DEBUG_COPYBIT,
+ "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
+ "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
+ dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
+ return false;
+ }
+
+ // copybit doesn't say anything about filtering, so we can't
+ // discriminate. On msm7k, copybit will always filter.
+ // the code below handles min/mag filters, we keep it as a reference.
+
+#ifdef MIN_MAG_FILTER
+ int32_t texelArea = gglMulx(dtdy, dsdx);
+ if (texelArea < FIXED_ONE && textureObject->mag_filter != GL_LINEAR) {
+ // Non-linear filtering on a texture enlargement.
+ LOGD_IF(DEBUG_COPYBIT, "mag filter is not GL_LINEAR");
+ return false;
+ }
+ if (texelArea > FIXED_ONE && textureObject->min_filter != GL_LINEAR) {
+ // Non-linear filtering on an texture shrink.
+ LOGD_IF(DEBUG_COPYBIT, "min filter is not GL_LINEAR");
+ return false;
+ }
+#endif
+
+ const uint32_t enables = c->rasterizer.state.enables;
+ int planeAlpha = 255;
+ static const int tmu = 0;
+ texture_t& tev(c->rasterizer.state.texture[tmu]);
+ bool srcTextureHasAlpha = hasAlpha(textureObject->surface.format);
+ if (!srcTextureHasAlpha) {
+ planeAlpha = fixedToByte(c->currentColorClamped.a);
+ }
+
+ switch (tev.env) {
+ case GGL_REPLACE:
+ break;
+ case GGL_MODULATE:
+ if (! (c->currentColorClamped.r == FIXED_ONE &&
+ c->currentColorClamped.g == FIXED_ONE &&
+ c->currentColorClamped.b == FIXED_ONE)) {
+ LOGD_IF(DEBUG_COPYBIT,
+ "MODULATE and non white color (%08x, %08x, %08x)",
+ c->currentColorClamped.r,
+ c->currentColorClamped.g,
+ c->currentColorClamped.b);
+ return false;
+ }
+ if (srcTextureHasAlpha && c->currentColorClamped.a < FIXED_ONE) {
+ LOGD_IF(DEBUG_COPYBIT,
+ "MODULATE and texture w/alpha and alpha=%08x)",
+ c->currentColorClamped.a);
+ return false;
+ }
+ break;
+
+ default:
+ // Incompatible texture environment.
+ LOGD_IF(DEBUG_COPYBIT, "incompatible texture environment");
+ return false;
+ }
+
+ bool blending = false;
+ if ((enables & GGL_ENABLE_BLENDING)
+ && !(c->rasterizer.state.blend.src == GL_ONE
+ && c->rasterizer.state.blend.dst == GL_ZERO)) {
+ // Blending is OK if it is
+ // the exact kind of blending that the copybits hardware supports.
+ // Note: The hardware only supports
+ // GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA,
+ // But the surface flinger uses GL_ONE / GL_ONE_MINUS_SRC_ALPHA.
+ // We substitute GL_SRC_ALPHA / GL_ONE_MINUS_SRC_ALPHA in that case,
+ // because the performance is worth it, even if the results are
+ // not correct.
+ if (!((c->rasterizer.state.blend.src == GL_SRC_ALPHA
+ || c->rasterizer.state.blend.src == GL_ONE)
+ && c->rasterizer.state.blend.dst == GL_ONE_MINUS_SRC_ALPHA
+ && c->rasterizer.state.blend.alpha_separate == 0)) {
+ // Incompatible blend mode.
+ LOGD_IF(DEBUG_COPYBIT, "incompatible blend mode");
+ return false;
+ }
+ blending = true;
+ } else {
+ // No blending is OK if we are not using alpha.
+ if (srcTextureHasAlpha || planeAlpha != 255) {
+ // Incompatible alpha
+ LOGD_IF(DEBUG_COPYBIT, "incompatible alpha");
+ return false;
+ }
+ }
+
+ if (srcTextureHasAlpha && planeAlpha != 255) {
+ // Can't do two types of alpha at once.
+ LOGD_IF(DEBUG_COPYBIT, "src alpha and plane alpha");
+ return false;
+ }
+
+ // LOGW("calling copybits");
+
+ copybit_device_t* copybit = c->copybits.blitEngine;
+
+ copybit_image_t dst;
+ buffer_handle_t target_hnd = c->copybits.drawSurfaceBuffer;
+ textureToCopyBitImage(&cbSurface, target_hnd, &dst);
+ copybit_rect_t drect = {x, y, x+w, y+h};
+
+ copybit_image_t src;
+ buffer_handle_t source_hnd = textureObject->buffer->handle;
+ textureToCopyBitImage(&textureObject->surface, source_hnd, &src);
+ copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
+
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ (enables & GGL_ENABLE_DITHER) ? COPYBIT_ENABLE : COPYBIT_DISABLE);
+
+ clipRectRegion it(c);
+ status_t err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ if (err != NO_ERROR) {
+ c->textures.tmu[0].texture->try_copybit = false;
+ }
+ return err == NO_ERROR ? true : false;
+}
+
+/*
+ * Try to draw a triangle fan with copybit, return false if we fail.
+ */
+bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first, GLsizei count)
+{
+ if (!checkContext(c)) {
+ return false;
+ }
+
+ // FIXME: we should handle culling here
+ c->arrays.compileElements(c, c->vc.vBuffer, 0, 4);
+
+ // we detect if we're dealing with a rectangle, by comparing the
+ // rectangles {v0,v2} and {v1,v3} which should be identical.
+
+ // NOTE: we should check that the rectangle is window aligned, however
+ // if we do that, the optimization won't be taken in a lot of cases.
+ // Since this code is intended to be used with SurfaceFlinger only,
+ // so it's okay...
+
+ const vec4_t& v0 = c->vc.vBuffer[0].window;
+ const vec4_t& v1 = c->vc.vBuffer[1].window;
+ const vec4_t& v2 = c->vc.vBuffer[2].window;
+ const vec4_t& v3 = c->vc.vBuffer[3].window;
+ int l = min(v0.x, v2.x);
+ int b = min(v0.y, v2.y);
+ int r = max(v0.x, v2.x);
+ int t = max(v0.y, v2.y);
+ if ((l != min(v1.x, v3.x)) || (b != min(v1.y, v3.y)) ||
+ (r != max(v1.x, v3.x)) || (t != max(v1.y, v3.y))) {
+ LOGD_IF(DEBUG_COPYBIT, "geometry not a rectangle");
+ return false;
+ }
+
+ // fetch and transform texture coordinates
+ // NOTE: maybe it would be better to have a "compileElementsAll" method
+ // that would ensure all vertex data are fetched and transformed
+ const transform_t& tr = c->transforms.texture[0].transform;
+ for (size_t i=0 ; i<4 ; i++) {
+ const GLubyte* tp = c->arrays.texture[0].element(i);
+ vertex_t* const v = &c->vc.vBuffer[i];
+ c->arrays.texture[0].fetch(c, v->texture[0].v, tp);
+ // FIXME: we should bail if q!=1
+ c->arrays.tex_transform[0](&tr, &v->texture[0], &v->texture[0]);
+ }
+
+ const vec4_t& t0 = c->vc.vBuffer[0].texture[0];
+ const vec4_t& t1 = c->vc.vBuffer[1].texture[0];
+ const vec4_t& t2 = c->vc.vBuffer[2].texture[0];
+ const vec4_t& t3 = c->vc.vBuffer[3].texture[0];
+ int txl = min(t0.x, t2.x);
+ int txb = min(t0.y, t2.y);
+ int txr = max(t0.x, t2.x);
+ int txt = max(t0.y, t2.y);
+ if ((txl != min(t1.x, t3.x)) || (txb != min(t1.y, t3.y)) ||
+ (txr != max(t1.x, t3.x)) || (txt != max(t1.y, t3.y))) {
+ LOGD_IF(DEBUG_COPYBIT, "texcoord not a rectangle");
+ return false;
+ }
+ if ((txl != 0) || (txb != 0) ||
+ (txr != FIXED_ONE) || (txt != FIXED_ONE)) {
+ // we could probably handle this case, if we wanted to
+ LOGD_IF(DEBUG_COPYBIT, "texture is cropped: %08x,%08x,%08x,%08x",
+ txl, txb, txr, txt);
+ return false;
+ }
+
+ // at this point, we know we are dealing with a rectangle, so we
+ // only need to consider 3 vertices for computing the jacobians
+
+ const int dx01 = v1.x - v0.x;
+ const int dx02 = v2.x - v0.x;
+ const int dy01 = v1.y - v0.y;
+ const int dy02 = v2.y - v0.y;
+ const int ds01 = t1.S - t0.S;
+ const int ds02 = t2.S - t0.S;
+ const int dt01 = t1.T - t0.T;
+ const int dt02 = t2.T - t0.T;
+ const int area = dx01*dy02 - dy01*dx02;
+ int dsdx, dsdy, dtdx, dtdy;
+ if (area >= 0) {
+ dsdx = ds01*dy02 - ds02*dy01;
+ dtdx = dt01*dy02 - dt02*dy01;
+ dsdy = ds02*dx01 - ds01*dx02;
+ dtdy = dt02*dx01 - dt01*dx02;
+ } else {
+ dsdx = ds02*dy01 - ds01*dy02;
+ dtdx = dt02*dy01 - dt01*dy02;
+ dsdy = ds01*dx02 - ds02*dx01;
+ dtdy = dt01*dx02 - dt02*dx01;
+ }
+
+ // here we rely on the fact that we know the transform is
+ // a rigid-body transform AND that it can only rotate in 90 degrees
+ // increments
+
+ int transform = 0;
+ if (dsdx == 0) {
+ // 90 deg rotation case
+ // [ 0 dtdx ]
+ // [ dsdx 0 ]
+ transform |= COPYBIT_TRANSFORM_ROT_90;
+ // FIXME: not sure if FLIP_H and FLIP_V shouldn't be inverted
+ if (dtdx > 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_H;
+ if (dsdy < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_V;
+ } else {
+ // [ dsdx 0 ]
+ // [ 0 dtdy ]
+ if (dsdx < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_H;
+ if (dtdy < 0)
+ transform |= COPYBIT_TRANSFORM_FLIP_V;
+ }
+
+ //LOGD("l=%d, b=%d, w=%d, h=%d, tr=%d", x, y, w, h, transform);
+ //LOGD("A=%f\tB=%f\nC=%f\tD=%f",
+ // dsdx/65536.0, dtdx/65536.0, dsdy/65536.0, dtdy/65536.0);
+
+ int x = l >> 4;
+ int y = b >> 4;
+ int w = (r-l) >> 4;
+ int h = (t-b) >> 4;
+ texture_unit_t& u(c->textures.tmu[0]);
+ EGLTextureObject* textureObject = u.texture;
+ GLint tWidth = textureObject->surface.width;
+ GLint tHeight = textureObject->surface.height;
+ GLint crop_rect[4] = {0, tHeight, tWidth, -tHeight};
+ const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
+ y = cbSurface.height - (y + h);
+ return copybit(x, y, w, h, textureObject, crop_rect, transform, c);
+}
+
+/*
+ * Try to drawTexiOESWithCopybit, return false if we fail.
+ */
+
+bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
+ GLint w, GLint h, ogles_context_t* c)
+{
+ // quickly process empty rects
+ if ((w|h) <= 0) {
+ return true;
+ }
+ if (!checkContext(c)) {
+ return false;
+ }
+ texture_unit_t& u(c->textures.tmu[0]);
+ EGLTextureObject* textureObject = u.texture;
+ return copybit(x, y, w, h, textureObject, textureObject->crop_rect, 0, c);
+}
+
+} // namespace android
+
diff --git a/opengl/libagl/copybit.h b/opengl/libagl/copybit.h
new file mode 100644
index 0000000..b8b5afd
--- /dev/null
+++ b/opengl/libagl/copybit.h
@@ -0,0 +1,75 @@
+/*
+**
+** 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.
+*/
+
+#ifndef ANDROID_OPENGLES_COPYBIT_H
+#define ANDROID_OPENGLES_COPYBIT_H
+
+#include <stdlib.h>
+
+#include <GLES/gl.h>
+
+#include "TextureObjectManager.h"
+namespace android {
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+
+bool drawTexiOESWithCopybit_impl(GLint x, GLint y, GLint z,
+ GLint w, GLint h, ogles_context_t* c);
+
+bool drawTriangleFanWithCopybit_impl(ogles_context_t* c, GLint first,
+ GLsizei count);
+
+inline bool copybitQuickCheckContext(ogles_context_t* c) {
+ return c->copybits.drawSurfaceBuffer != 0
+ && c->rasterizer.state.enabled_tmu == 1
+ && c->textures.tmu[0].texture->try_copybit;
+}
+
+/*
+ * Tries to draw a drawTexiOES using copybit hardware.
+ * Returns true if successful.
+ */
+inline bool drawTexiOESWithCopybit(GLint x, GLint y, GLint z,
+ GLint w, GLint h, ogles_context_t* c) {
+ if (!copybitQuickCheckContext(c)) {
+ return false;
+ }
+
+ return drawTexiOESWithCopybit_impl(x, y, z, w, h, c);
+}
+
+/*
+ * Tries to draw a triangle fan using copybit hardware.
+ * Returns true if successful.
+ */
+inline bool drawTriangleFanWithCopybit(ogles_context_t* c, GLint first,
+ GLsizei count) {
+ /*
+ * We are looking for the glDrawArrays call made by SurfaceFlinger.
+ */
+
+ if ((count!=4) || first || !copybitQuickCheckContext(c))
+ return false;
+
+ return drawTriangleFanWithCopybit_impl(c, first, count);
+}
+
+
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
+} // namespace android
+
+#endif // ANDROID_OPENGLES_COPYBIT_H
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 4461567..9c0f7fd 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -15,8 +15,6 @@
** limitations under the License.
*/
-#define LOG_TAG "EGL"
-
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
@@ -41,6 +39,10 @@
#include <pixelflinger/format.h>
#include <pixelflinger/pixelflinger.h>
+#include <private/ui/android_natives_priv.h>
+
+#include <hardware/copybit.h>
+
#include "context.h"
#include "state.h"
#include "texture.h"
@@ -89,9 +91,9 @@ static GLint getError() {
struct egl_display_t
{
egl_display_t() : type(0), initialized(0) { }
-
+
static egl_display_t& get_display(EGLDisplay dpy);
-
+
static EGLBoolean is_valid(EGLDisplay dpy) {
return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
}
@@ -139,19 +141,23 @@ struct egl_surface_t
egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
virtual ~egl_surface_t();
- virtual bool isValid() const = 0;
-
+ bool isValid() const;
+ virtual bool initCheck() const = 0;
+
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0;
virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0;
+ virtual EGLBoolean connect() { return EGL_TRUE; }
+ virtual void disconnect() {}
virtual EGLint getWidth() const = 0;
virtual EGLint getHeight() const = 0;
- virtual void* getBits() const = 0;
virtual EGLint getHorizontalResolution() const;
virtual EGLint getVerticalResolution() const;
virtual EGLint getRefreshRate() const;
virtual EGLint getSwapBehavior() const;
virtual EGLBoolean swapBuffers();
+ virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+ virtual EGLClientBuffer getRenderBuffer() const;
protected:
GGLSurface depth;
};
@@ -170,6 +176,11 @@ egl_surface_t::~egl_surface_t()
magic = 0;
free(depth.data);
}
+bool egl_surface_t::isValid() const {
+ LOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
+ return magic == MAGIC;
+}
+
EGLBoolean egl_surface_t::swapBuffers() {
return EGL_FALSE;
}
@@ -185,119 +196,507 @@ EGLint egl_surface_t::getRefreshRate() const {
EGLint egl_surface_t::getSwapBehavior() const {
return EGL_BUFFER_PRESERVED;
}
+EGLBoolean egl_surface_t::setSwapRectangle(
+ EGLint l, EGLint t, EGLint w, EGLint h)
+{
+ return EGL_FALSE;
+}
+EGLClientBuffer egl_surface_t::getRenderBuffer() const {
+ return 0;
+}
// ----------------------------------------------------------------------------
-struct egl_window_surface_t : public egl_surface_t
+struct egl_window_surface_v2_t : public egl_surface_t
{
- egl_window_surface_t(
+ egl_window_surface_v2_t(
EGLDisplay dpy, EGLConfig config,
int32_t depthFormat,
- egl_native_window_t* window);
+ android_native_window_t* window);
- ~egl_window_surface_t();
+ ~egl_window_surface_v2_t();
- virtual bool isValid() const { return nativeWindow->magic == 0x600913; }
+ virtual bool initCheck() const { return true; } // TODO: report failure if ctor fails
virtual EGLBoolean swapBuffers();
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
- virtual EGLint getWidth() const { return nativeWindow->width; }
- virtual EGLint getHeight() const { return nativeWindow->height; }
- virtual void* getBits() const;
+ virtual EGLBoolean connect();
+ virtual void disconnect();
+ virtual EGLint getWidth() const { return width; }
+ virtual EGLint getHeight() const { return height; }
virtual EGLint getHorizontalResolution() const;
virtual EGLint getVerticalResolution() const;
virtual EGLint getRefreshRate() const;
virtual EGLint getSwapBehavior() const;
+ virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
+ virtual EGLClientBuffer getRenderBuffer() const;
+
private:
- egl_native_window_t* nativeWindow;
+ status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
+ status_t unlock(android_native_buffer_t* buf);
+ android_native_window_t* nativeWindow;
+ android_native_buffer_t* buffer;
+ android_native_buffer_t* previousBuffer;
+ gralloc_module_t const* module;
+ copybit_device_t* blitengine;
+ int width;
+ int height;
+ void* bits;
+ GGLFormat const* pixelFormatTable;
+
+ struct Rect {
+ inline Rect() { };
+ inline Rect(int32_t w, int32_t h)
+ : left(0), top(0), right(w), bottom(h) { }
+ inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
+ : left(l), top(t), right(r), bottom(b) { }
+ Rect& andSelf(const Rect& r) {
+ left = max(left, r.left);
+ top = max(top, r.top);
+ right = min(right, r.right);
+ bottom = min(bottom, r.bottom);
+ return *this;
+ }
+ bool isEmpty() const {
+ return (left>=right || top>=bottom);
+ }
+ void dump(char const* what) {
+ LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
+ what, left, top, right-left, bottom-top);
+ }
+
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+ };
+
+ struct Region {
+ inline Region() : count(0) { }
+ typedef Rect const* const_iterator;
+ const_iterator begin() const { return storage; }
+ const_iterator end() const { return storage+count; }
+ static Region subtract(const Rect& lhs, const Rect& rhs) {
+ Region reg;
+ Rect* storage = reg.storage;
+ if (!lhs.isEmpty()) {
+ if (lhs.top < rhs.top) { // top rect
+ storage->left = lhs.left;
+ storage->top = lhs.top;
+ storage->right = lhs.right;
+ storage->bottom = rhs.top;
+ storage++;
+ }
+ const int32_t top = max(lhs.top, rhs.top);
+ const int32_t bot = min(lhs.bottom, rhs.bottom);
+ if (top < bot) {
+ if (lhs.left < rhs.left) { // left-side rect
+ storage->left = lhs.left;
+ storage->top = top;
+ storage->right = rhs.left;
+ storage->bottom = bot;
+ storage++;
+ }
+ if (lhs.right > rhs.right) { // right-side rect
+ storage->left = rhs.right;
+ storage->top = top;
+ storage->right = lhs.right;
+ storage->bottom = bot;
+ storage++;
+ }
+ }
+ if (lhs.bottom > rhs.bottom) { // bottom rect
+ storage->left = lhs.left;
+ storage->top = rhs.bottom;
+ storage->right = lhs.right;
+ storage->bottom = lhs.bottom;
+ storage++;
+ }
+ reg.count = storage - reg.storage;
+ }
+ return reg;
+ }
+ bool isEmpty() const {
+ return count<=0;
+ }
+ private:
+ Rect storage[4];
+ ssize_t count;
+ };
+
+ struct region_iterator : public copybit_region_t {
+ region_iterator(const Region& region)
+ : b(region.begin()), e(region.end()) {
+ this->next = iterate;
+ }
+ private:
+ static int iterate(copybit_region_t const * self, copybit_rect_t* rect) {
+ region_iterator const* me = static_cast<region_iterator const*>(self);
+ if (me->b != me->e) {
+ *reinterpret_cast<Rect*>(rect) = *me->b++;
+ return 1;
+ }
+ return 0;
+ }
+ mutable Region::const_iterator b;
+ Region::const_iterator const e;
+ };
+
+ void copyBlt(
+ android_native_buffer_t* dst, void* dst_vaddr,
+ android_native_buffer_t* src, void const* src_vaddr,
+ const Region& clip);
+
+ Rect dirtyRegion;
+ Rect oldDirtyRegion;
};
-egl_window_surface_t::egl_window_surface_t(EGLDisplay dpy,
+egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
EGLConfig config,
int32_t depthFormat,
- egl_native_window_t* window)
- : egl_surface_t(dpy, config, depthFormat), nativeWindow(window)
+ android_native_window_t* window)
+ : egl_surface_t(dpy, config, depthFormat),
+ nativeWindow(window), buffer(0), previousBuffer(0), module(0),
+ blitengine(0), bits(NULL)
{
- if (depthFormat) {
- depth.width = window->width;
- depth.height = window->height;
+ hw_module_t const* pModule;
+ hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule);
+ module = reinterpret_cast<gralloc_module_t const*>(pModule);
+
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &pModule) == 0) {
+ copybit_open(pModule, &blitengine);
+ }
+
+ pixelFormatTable = gglGetPixelFormatTable();
+
+ // keep a reference on the window
+ nativeWindow->common.incRef(&nativeWindow->common);
+ nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
+ nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
+}
+
+egl_window_surface_v2_t::~egl_window_surface_v2_t() {
+ if (buffer) {
+ buffer->common.decRef(&buffer->common);
+ }
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ }
+ nativeWindow->common.decRef(&nativeWindow->common);
+ if (blitengine) {
+ copybit_close(blitengine);
+ }
+}
+
+EGLBoolean egl_window_surface_v2_t::connect()
+{
+ // we're intending to do software rendering
+ native_window_set_usage(nativeWindow,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ // dequeue a buffer
+ if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ // allocate a corresponding depth-buffer
+ width = buffer->width;
+ height = buffer->height;
+ if (depth.format) {
+ depth.width = width;
+ depth.height = height;
depth.stride = depth.width; // use the width here
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- return;
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
}
}
- nativeWindow->incRef(nativeWindow);
+
+ // keep a reference on the buffer
+ buffer->common.incRef(&buffer->common);
+
+ // Lock the buffer
+ nativeWindow->lockBuffer(nativeWindow, buffer);
+ // pin the buffer down
+ if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
+ LOGE("connect() failed to lock buffer %p (%ux%u)",
+ buffer, buffer->width, buffer->height);
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ // FIXME: we should make sure we're not accessing the buffer anymore
+ }
+ return EGL_TRUE;
+}
+
+void egl_window_surface_v2_t::disconnect()
+{
+ if (buffer && bits) {
+ bits = NULL;
+ unlock(buffer);
+ }
+ // enqueue the last frame
+ nativeWindow->queueBuffer(nativeWindow, buffer);
+ if (buffer) {
+ buffer->common.decRef(&buffer->common);
+ buffer = 0;
+ }
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ previousBuffer = 0;
+ }
+}
+
+status_t egl_window_surface_v2_t::lock(
+ android_native_buffer_t* buf, int usage, void** vaddr)
+{
+ int err = module->lock(module, buf->handle,
+ usage, 0, 0, buf->width, buf->height, vaddr);
+ return err;
}
-egl_window_surface_t::~egl_window_surface_t() {
- nativeWindow->decRef(nativeWindow);
+
+status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
+{
+ if (!buf) return BAD_VALUE;
+ int err = module->unlock(module, buf->handle);
+ return err;
+}
+
+void egl_window_surface_v2_t::copyBlt(
+ android_native_buffer_t* dst, void* dst_vaddr,
+ android_native_buffer_t* src, void const* src_vaddr,
+ const Region& clip)
+{
+ // FIXME: use copybit if possible
+ // NOTE: dst and src must be the same format
+
+ status_t err = NO_ERROR;
+ copybit_device_t* const copybit = blitengine;
+ if (copybit) {
+ copybit_image_t simg;
+ simg.w = src->width;
+ simg.h = src->height;
+ simg.format = src->format;
+ simg.handle = const_cast<native_handle_t*>(src->handle);
+
+ copybit_image_t dimg;
+ dimg.w = dst->width;
+ dimg.h = dst->height;
+ dimg.format = dst->format;
+ dimg.handle = const_cast<native_handle_t*>(dst->handle);
+
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+ region_iterator it(clip);
+ err = copybit->blit(copybit, &dimg, &simg, &it);
+ if (err != NO_ERROR) {
+ LOGE("copybit failed (%s)", strerror(err));
+ }
+ }
+
+ if (!copybit || err) {
+ Region::const_iterator cur = clip.begin();
+ Region::const_iterator end = clip.end();
+
+ const size_t bpp = pixelFormatTable[src->format].size;
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
+ uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
+
+ while (cur != end) {
+ const Rect& r(*cur++);
+ ssize_t w = r.right - r.left;
+ ssize_t h = r.bottom - r.top;
+ if (w <= 0 || h<=0) continue;
+ size_t size = w * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
}
-EGLBoolean egl_window_surface_t::swapBuffers()
+EGLBoolean egl_window_surface_v2_t::swapBuffers()
{
- uint32_t flags = nativeWindow->swapBuffers(nativeWindow);
- if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
+ if (!buffer) {
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ }
+
+ /*
+ * Handle eglSetSwapRectangleANDROID()
+ * We copyback from the front buffer
+ */
+ if (!dirtyRegion.isEmpty()) {
+ dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
+ if (previousBuffer) {
+ const Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
+ if (!copyBack.isEmpty()) {
+ void* prevBits;
+ if (lock(previousBuffer,
+ GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
+ // copy from previousBuffer to buffer
+ copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
+ unlock(previousBuffer);
+ }
+ }
+ }
+ oldDirtyRegion = dirtyRegion;
+ }
+
+ if (previousBuffer) {
+ previousBuffer->common.decRef(&previousBuffer->common);
+ previousBuffer = 0;
+ }
+
+ unlock(buffer);
+ previousBuffer = buffer;
+ nativeWindow->queueBuffer(nativeWindow, buffer);
+ buffer = 0;
+
+ // dequeue a new buffer
+ nativeWindow->dequeueBuffer(nativeWindow, &buffer);
+
+ // TODO: lockBuffer should rather be executed when the very first
+ // direct rendering occurs.
+ nativeWindow->lockBuffer(nativeWindow, buffer);
+
+ // reallocate the depth-buffer if needed
+ if ((width != buffer->width) || (height != buffer->height)) {
// TODO: we probably should reset the swap rect here
// if the window size has changed
+ width = buffer->width;
+ height = buffer->height;
if (depth.data) {
free(depth.data);
- depth.width = nativeWindow->width;
- depth.height = nativeWindow->height;
- depth.stride = nativeWindow->stride;
+ depth.width = width;
+ depth.height = height;
+ depth.stride = buffer->stride;
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ setError(EGL_BAD_ALLOC, EGL_FALSE);
return EGL_FALSE;
}
}
}
+
+ // keep a reference on the buffer
+ buffer->common.incRef(&buffer->common);
+
+ // finally pin the buffer down
+ if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
+ LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
+ buffer, buffer->width, buffer->height);
+ return setError(EGL_BAD_ACCESS, EGL_FALSE);
+ // FIXME: we should make sure we're not accessing the buffer anymore
+ }
+
return EGL_TRUE;
}
-EGLBoolean egl_window_surface_t::bindDrawSurface(ogles_context_t* gl)
+EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
+ EGLint l, EGLint t, EGLint w, EGLint h)
+{
+ dirtyRegion = Rect(l, t, l+w, t+h);
+ return EGL_TRUE;
+}
+
+EGLClientBuffer egl_window_surface_v2_t::getRenderBuffer() const
+{
+ return buffer;
+}
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+
+static bool supportedCopybitsDestinationFormat(int format) {
+ // Hardware supported
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBA_4444:
+ case HAL_PIXEL_FORMAT_RGBA_5551:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return true;
+ }
+ return false;
+}
+#endif
+
+EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
{
GGLSurface buffer;
buffer.version = sizeof(GGLSurface);
- buffer.width = nativeWindow->width;
- buffer.height = nativeWindow->height;
- buffer.stride = nativeWindow->stride;
- buffer.data = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
- buffer.format = nativeWindow->format;
+ buffer.width = this->buffer->width;
+ buffer.height = this->buffer->height;
+ buffer.stride = this->buffer->stride;
+ buffer.data = (GGLubyte*)bits;
+ buffer.format = this->buffer->format;
gl->rasterizer.procs.colorBuffer(gl, &buffer);
if (depth.data != gl->rasterizer.state.buffers.depth.data)
gl->rasterizer.procs.depthBuffer(gl, &depth);
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ gl->copybits.drawSurfaceBuffer = 0;
+ if (gl->copybits.blitEngine != NULL) {
+ if (supportedCopybitsDestinationFormat(buffer.format)) {
+ buffer_handle_t handle = this->buffer->handle;
+ if (handle != NULL) {
+ gl->copybits.drawSurfaceBuffer = handle;
+ }
+ }
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
return EGL_TRUE;
}
-EGLBoolean egl_window_surface_t::bindReadSurface(ogles_context_t* gl)
+EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl)
{
GGLSurface buffer;
buffer.version = sizeof(GGLSurface);
- buffer.width = nativeWindow->width;
- buffer.height = nativeWindow->height;
- buffer.stride = nativeWindow->stride;
- buffer.data = (GGLubyte*)nativeWindow->base + nativeWindow->offset;
- buffer.format = nativeWindow->format;
+ buffer.width = this->buffer->width;
+ buffer.height = this->buffer->height;
+ buffer.stride = this->buffer->stride;
+ buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
+ buffer.format = this->buffer->format;
gl->rasterizer.procs.readBuffer(gl, &buffer);
return EGL_TRUE;
}
-void* egl_window_surface_t::getBits() const {
- return (GGLubyte*)nativeWindow->base + nativeWindow->offset;
-}
-EGLint egl_window_surface_t::getHorizontalResolution() const {
+EGLint egl_window_surface_v2_t::getHorizontalResolution() const {
return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
-EGLint egl_window_surface_t::getVerticalResolution() const {
+EGLint egl_window_surface_v2_t::getVerticalResolution() const {
return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
-EGLint egl_window_surface_t::getRefreshRate() const {
- return (nativeWindow->fps * EGL_DISPLAY_SCALING);
+EGLint egl_window_surface_v2_t::getRefreshRate() const {
+ return (60 * EGL_DISPLAY_SCALING); // FIXME
}
-EGLint egl_window_surface_t::getSwapBehavior() const {
- uint32_t flags = nativeWindow->flags;
- if (flags & EGL_NATIVES_FLAG_DESTROY_BACKBUFFER)
- return EGL_BUFFER_DESTROYED;
- return EGL_BUFFER_PRESERVED;
+EGLint egl_window_surface_v2_t::getSwapBehavior() const
+{
+ /*
+ * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
+ * the content of the swapped buffer.
+ *
+ * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
+ *
+ * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
+ * only applies to the area specified by eglSetSwapRectangleANDROID(), that
+ * is, everything outside of this area is preserved.
+ *
+ * This implementation of EGL assumes the later case.
+ *
+ */
+
+ return EGL_BUFFER_DESTROYED;
}
// ----------------------------------------------------------------------------
@@ -311,12 +710,11 @@ struct egl_pixmap_surface_t : public egl_surface_t
virtual ~egl_pixmap_surface_t() { }
- virtual bool isValid() const { return nativePixmap.version == sizeof(egl_native_pixmap_t); }
+ virtual bool initCheck() const { return !depth.format || depth.data!=0; }
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
virtual EGLint getWidth() const { return nativePixmap.width; }
virtual EGLint getHeight() const { return nativePixmap.height; }
- virtual void* getBits() const { return nativePixmap.data; }
private:
egl_native_pixmap_t nativePixmap;
};
@@ -334,7 +732,6 @@ egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2);
if (depth.data == 0) {
setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- return;
}
}
}
@@ -347,7 +744,7 @@ EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
buffer.stride = nativePixmap.stride;
buffer.data = nativePixmap.data;
buffer.format = nativePixmap.format;
-
+
gl->rasterizer.procs.colorBuffer(gl, &buffer);
if (depth.data != gl->rasterizer.state.buffers.depth.data)
gl->rasterizer.procs.depthBuffer(gl, &depth);
@@ -376,12 +773,11 @@ struct egl_pbuffer_surface_t : public egl_surface_t
virtual ~egl_pbuffer_surface_t();
- virtual bool isValid() const { return pbuffer.data != 0; }
+ virtual bool initCheck() const { return pbuffer.data != 0; }
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
virtual EGLint getWidth() const { return pbuffer.width; }
virtual EGLint getHeight() const { return pbuffer.height; }
- virtual void* getBits() const { return pbuffer.data; }
private:
GGLSurface pbuffer;
};
@@ -407,7 +803,7 @@ egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
pbuffer.stride = w;
pbuffer.data = (GGLubyte*)malloc(size);
pbuffer.format = f;
-
+
if (depthFormat) {
depth.width = pbuffer.width;
depth.height = pbuffer.height;
@@ -468,7 +864,13 @@ struct config_management_t {
static char const * const gVendorString = "Google Inc.";
static char const * const gVersionString = "1.2 Android Driver";
static char const * const gClientApiString = "OpenGL ES";
-static char const * const gExtensionsString = "";
+static char const * const gExtensionsString =
+ "EGL_KHR_image_base "
+ // "KHR_image_pixmap "
+ "EGL_ANDROID_image_native_buffer "
+ "EGL_ANDROID_swap_rectangle "
+ "EGL_ANDROID_get_render_buffer "
+ ;
// ----------------------------------------------------------------------------
@@ -496,6 +898,10 @@ static const extention_map_t gExtentionMap[] = {
(__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
{ "glQueryMatrixxOES",
(__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
+ { "glEGLImageTargetTexture2DOES",
+ (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
+ { "glEGLImageTargetRenderbufferStorageOES",
+ (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
{ "glClipPlanef",
(__eglMustCastToProperFunctionPointerType)&glClipPlanef },
{ "glClipPlanex",
@@ -510,9 +916,17 @@ static const extention_map_t gExtentionMap[] = {
(__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
{ "glGenBuffers",
(__eglMustCastToProperFunctionPointerType)&glGenBuffers },
+ { "eglCreateImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
+ { "eglDestroyImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
+ { "eglSetSwapRectangleANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
+ { "eglGetRenderBufferANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
};
-/*
+/*
* In the lists below, attributes names MUST be sorted.
* Additionally, all configs must be sorted according to
* the EGL specification.
@@ -523,7 +937,7 @@ static config_pair_t const config_base_attribute_list[] = {
{ EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
{ EGL_LEVEL, 0 },
{ EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
- { EGL_MAX_PBUFFER_PIXELS,
+ { EGL_MAX_PBUFFER_PIXELS,
GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
{ EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
{ EGL_NATIVE_RENDERABLE, EGL_TRUE },
@@ -660,9 +1074,9 @@ static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
{
while (first <= last) {
int mid = (first + last) / 2;
- if (key > sortedArray[mid].key) {
+ if (key > sortedArray[mid].key) {
first = mid + 1;
- } else if (key < sortedArray[mid].key) {
+ } else if (key < sortedArray[mid].key) {
last = mid - 1;
} else {
return mid;
@@ -674,13 +1088,13 @@ static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
static int isAttributeMatching(int i, EGLint attr, EGLint val)
{
// look for the attribute in all of our configs
- config_pair_t const* configFound = gConfigs[i].array;
+ config_pair_t const* configFound = gConfigs[i].array;
int index = binarySearch<config_pair_t>(
gConfigs[i].array,
0, gConfigs[i].size-1,
attr);
if (index < 0) {
- configFound = config_base_attribute_list;
+ configFound = config_base_attribute_list;
index = binarySearch<config_pair_t>(
config_base_attribute_list,
0, NELEM(config_base_attribute_list)-1,
@@ -787,6 +1201,11 @@ static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
if (!(surfaceType & EGL_WINDOW_BIT))
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (static_cast<android_native_window_t*>(window)->common.magic !=
+ ANDROID_NATIVE_WINDOW_MAGIC) {
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
EGLint configID;
if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
return EGL_FALSE;
@@ -794,28 +1213,28 @@ static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
int32_t depthFormat;
int32_t pixelFormat;
switch(configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = 0;
break;
case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = 0;
break;
case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 4:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = 0;
break;
case 5:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
default:
@@ -828,11 +1247,11 @@ static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
//if (EGLint(info.format) != pixelFormat)
// return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- egl_surface_t* surface =
- new egl_window_surface_t(dpy, config, depthFormat,
- static_cast<egl_native_window_t*>(window));
+ egl_surface_t* surface;
+ surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
+ static_cast<android_native_window_t*>(window));
- if (!surface->isValid()) {
+ if (!surface->initCheck()) {
// there was a problem in the ctor, the error
// flag has been set.
delete surface;
@@ -856,6 +1275,11 @@ static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
if (!(surfaceType & EGL_PIXMAP_BIT))
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ if (static_cast<egl_native_pixmap_t*>(pixmap)->version !=
+ sizeof(egl_native_pixmap_t)) {
+ return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
+ }
+
EGLint configID;
if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
return EGL_FALSE;
@@ -863,28 +1287,28 @@ static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
int32_t depthFormat;
int32_t pixelFormat;
switch(configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = 0;
break;
case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = 0;
break;
case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 4:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = 0;
break;
case 5:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
default:
@@ -898,7 +1322,7 @@ static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
new egl_pixmap_surface_t(dpy, config, depthFormat,
static_cast<egl_native_pixmap_t*>(pixmap));
- if (!surface->isValid()) {
+ if (!surface->initCheck()) {
// there was a problem in the ctor, the error
// flag has been set.
delete surface;
@@ -916,10 +1340,10 @@ static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
EGLint surfaceType;
if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
return EGL_FALSE;
-
+
if (!(surfaceType & EGL_PBUFFER_BIT))
return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
+
EGLint configID;
if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
return EGL_FALSE;
@@ -927,28 +1351,28 @@ static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
int32_t depthFormat;
int32_t pixelFormat;
switch(configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ case 0:
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = 0;
break;
case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
+ pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = 0;
break;
case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
+ pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
case 4:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = 0;
break;
case 5:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
+ pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
default:
@@ -966,7 +1390,7 @@ static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
egl_surface_t* surface =
new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
- if (!surface->isValid()) {
+ if (!surface->initCheck()) {
// there was a problem in the ctor, the error
// flag has been set.
delete surface;
@@ -1001,7 +1425,7 @@ EGLDisplay eglGetDisplay(NativeDisplayType display)
egl_display_t& d = egl_display_t::get_display(dpy);
d.type = display;
return dpy;
- }
+ }
return EGL_NO_DISPLAY;
}
@@ -1009,10 +1433,10 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
+
EGLBoolean res = EGL_TRUE;
egl_display_t& d = egl_display_t::get_display(dpy);
-
+
if (android_atomic_inc(&d.initialized) == 0) {
// initialize stuff here if needed
//pthread_mutex_lock(&gInitMutex);
@@ -1080,7 +1504,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
*num_config = 0;
return EGL_TRUE;
}
-
+
int numAttributes = 0;
int numConfigs = NELEM(gConfigs);
uint32_t possibleMatch = (1<<numConfigs)-1;
@@ -1161,7 +1585,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
{
return createWindowSurface(dpy, config, window, attrib_list);
}
-
+
EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
NativePixmapType pixmap,
const EGLint *attrib_list)
@@ -1174,17 +1598,22 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
{
return createPbufferSurface(dpy, config, attrib_list);
}
-
+
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (eglSurface != EGL_NO_SURFACE) {
egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
- if (surface->magic != egl_surface_t::MAGIC)
+ if (!surface->isValid())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (surface->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (surface->ctx) {
+ // FIXME: this surface is current check what the spec says
+ surface->disconnect();
+ surface->ctx = 0;
+ }
delete surface;
}
return EGL_TRUE;
@@ -1196,6 +1625,8 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
+ if (!surface->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (surface->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1244,7 +1675,7 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
*value = (wr * EGL_DISPLAY_SCALING) / hr;
} break;
case EGL_SWAP_BEHAVIOR:
- *value = surface->getSwapBehavior();
+ *value = surface->getSwapBehavior();
break;
default:
ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
@@ -1288,13 +1719,23 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (draw) {
egl_surface_t* s = (egl_surface_t*)draw;
+ if (!s->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (s->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: check that draw and read are compatible with the context
+ // TODO: check that draw is compatible with the context
+ }
+ if (read && read!=draw) {
+ egl_surface_t* s = (egl_surface_t*)read;
+ if (!s->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (s->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ // TODO: check that read is compatible with the context
}
EGLContext current_ctx = EGL_NO_CONTEXT;
-
+
if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
return setError(EGL_BAD_MATCH, EGL_FALSE);
@@ -1310,21 +1751,29 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
egl_surface_t* r = (egl_surface_t*)read;
if ((d && d->ctx && d->ctx != ctx) ||
(r && r->ctx && r->ctx != ctx)) {
- // once of the surface is bound to a context in another thread
+ // one of the surface is bound to a context in another thread
return setError(EGL_BAD_ACCESS, EGL_FALSE);
}
}
- // TODO: call connect / disconnect on the surface
-
ogles_context_t* gl = (ogles_context_t*)ctx;
if (makeCurrent(gl) == 0) {
if (ctx) {
egl_context_t* c = egl_context_t::context(ctx);
egl_surface_t* d = (egl_surface_t*)draw;
egl_surface_t* r = (egl_surface_t*)read;
- c->read = read;
+
+ if (c->draw) {
+ egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
+ s->disconnect();
+ }
+ if (c->read) {
+ // FIXME: unlock/disconnect the read surface too
+ }
+
c->draw = draw;
+ c->read = read;
+
if (c->flags & egl_context_t::NEVER_CURRENT) {
c->flags &= ~egl_context_t::NEVER_CURRENT;
GLint w = 0;
@@ -1338,10 +1787,14 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
ogles_scissor(gl, 0, 0, w, h);
}
if (d) {
+ if (d->connect() == EGL_FALSE) {
+ return EGL_FALSE;
+ }
d->ctx = ctx;
d->bindDrawSurface(gl);
}
if (r) {
+ // FIXME: lock/connect the read surface too
r->ctx = ctx;
r->bindReadSurface(gl);
}
@@ -1352,8 +1805,16 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
egl_context_t* c = egl_context_t::context(current_ctx);
egl_surface_t* d = (egl_surface_t*)c->draw;
egl_surface_t* r = (egl_surface_t*)c->read;
- if (d) d->ctx = EGL_NO_CONTEXT;
- if (r) r->ctx = EGL_NO_CONTEXT;
+ if (d) {
+ c->draw = 0;
+ d->ctx = EGL_NO_CONTEXT;
+ d->disconnect();
+ }
+ if (r) {
+ c->read = 0;
+ r->ctx = EGL_NO_CONTEXT;
+ // FIXME: unlock/disconnect the read surface too
+ }
}
}
return EGL_TRUE;
@@ -1425,8 +1886,10 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
+
egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
if (d->dpy != dpy)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
@@ -1558,7 +2021,7 @@ EGLSurface eglCreatePbufferFromClientBuffer(
}
// ----------------------------------------------------------------------------
-// Android extensions
+// EGL_EGLEXT_VERSION 3
// ----------------------------------------------------------------------------
void (*eglGetProcAddress (const char *procname))()
@@ -1571,3 +2034,97 @@ void (*eglGetProcAddress (const char *procname))()
}
return NULL;
}
+
+EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
+ const EGLint *attrib_list)
+{
+ EGLBoolean result = EGL_FALSE;
+ return result;
+}
+
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+{
+ EGLBoolean result = EGL_FALSE;
+ return result;
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint *attrib_list)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
+ return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
+ }
+ if (ctx != EGL_NO_CONTEXT) {
+ return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
+ }
+ if (target != EGL_NATIVE_BUFFER_ANDROID) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+ }
+
+ android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
+
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+
+ if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
+
+ native_buffer->common.incRef(&native_buffer->common);
+ return (EGLImageKHR)native_buffer;
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
+
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ native_buffer->common.decRef(&native_buffer->common);
+
+ return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// ANDROID extensions
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+ EGLint left, EGLint top, EGLint width, EGLint height)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+ if (d->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ // post the surface
+ d->setSwapRectangle(left, top, width, height);
+
+ return EGL_TRUE;
+}
+
+EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
+{
+ if (egl_display_t::is_valid(dpy) == EGL_FALSE)
+ return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
+
+ egl_surface_t* d = static_cast<egl_surface_t*>(draw);
+ if (!d->isValid())
+ return setError(EGL_BAD_SURFACE, (EGLClientBuffer)0);
+ if (d->dpy != dpy)
+ return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
+
+ // post the surface
+ return d->getRenderBuffer();
+}
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
index 8ae32cc0f..f211bca 100644
--- a/opengl/libagl/light.cpp
+++ b/opengl/libagl/light.cpp
@@ -216,6 +216,8 @@ static inline void light_picker(ogles_context_t* c)
static inline void validate_light_mvi(ogles_context_t* c)
{
uint32_t en = c->lighting.enabledLights;
+ // Vector from object to viewer, in eye coordinates
+ const vec4_t eyeViewer = { 0, 0, 0x1000, 0 };
while (en) {
const int i = 31 - gglClz(en);
en &= ~(1<<i);
@@ -223,6 +225,9 @@ static inline void validate_light_mvi(ogles_context_t* c)
c->transforms.mvui.point4(&c->transforms.mvui,
&l.objPosition, &l.position);
vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
+ c->transforms.mvui.point4(&c->transforms.mvui,
+ &l.objViewer, &eyeViewer);
+ vnorm3(l.objViewer.v, l.objViewer.v);
}
}
@@ -379,9 +384,9 @@ void lightVertex(ogles_context_t* c, vertex_t* v)
// specular
if (ggl_unlikely(s && l.implicitSpecular.v[3])) {
vec4_t h;
- h.x = d.x;
- h.y = d.y;
- h.z = d.z + 0x10000;
+ h.x = d.x + l.objViewer.x;
+ h.y = d.y + l.objViewer.y;
+ h.z = d.z + l.objViewer.z;
vnorm3(h.v, h.v);
s = dot3(n.v, h.v);
s = (s<0) ? (twoSide?(-s):0) : s;
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
index 0b68dc0..21ef50e 100644
--- a/opengl/libagl/matrix.cpp
+++ b/opengl/libagl/matrix.cpp
@@ -696,6 +696,8 @@ void ogles_viewport(ogles_context_t* c,
f[2] = 0; f[6] = 0; f[10] = A; f[14] = B;
f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1;
c->transforms.dirty |= transform_state_t::VIEWPORT;
+ if (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)
+ c->transforms.dirty |= transform_state_t::MVP;
}
// ----------------------------------------------------------------------------
diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp
index f164c02..769ec40 100644
--- a/opengl/libagl/primitives.cpp
+++ b/opengl/libagl/primitives.cpp
@@ -369,7 +369,7 @@ void compute_iterators_t::iterators0032(int32_t* it,
int32_t c0, int32_t c1, int32_t c2) const
{
int64_t it64[3];
- iterators0032(it, c0, c1, c2);
+ iterators0032(it64, c0, c1, c2);
it[0] = it64[0];
it[1] = it64[1];
it[2] = it64[2];
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
index 5cbabea..a59b3b0 100644
--- a/opengl/libagl/state.cpp
+++ b/opengl/libagl/state.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -28,12 +28,16 @@
#include "BufferObjectManager.h"
#include "TextureObjectManager.h"
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+#include <hardware/copybit.h>
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
namespace android {
// ----------------------------------------------------------------------------
static char const * const gVendorString = "Android";
-static char const * const gRendererString = "Android PixelFlinger 1.0";
+static char const * const gRendererString = "Android PixelFlinger 1.1";
static char const * const gVersionString = "OpenGL ES-CM 1.0";
static char const * const gExtensionsString =
"GL_OES_byte_coordinates " // OK
@@ -46,9 +50,9 @@ static char const * const gExtensionsString =
"GL_OES_query_matrix " // OK
// "GL_OES_point_size_array " // TODO
// "GL_OES_point_sprite " // TODO
+ "GL_OES_EGL_image " // OK
"GL_ARB_texture_compression " // OK
"GL_ARB_texture_non_power_of_two " // OK
- "GL_ANDROID_direct_texture " // OK
"GL_ANDROID_user_clip_plane " // OK
"GL_ANDROID_vertex_buffer_object " // OK
"GL_ANDROID_generate_mipmap " // OK
@@ -62,13 +66,13 @@ static char const * const gExtensionsString =
ogles_context_t *ogles_init(size_t extra)
{
void* const base = malloc(extra + sizeof(ogles_context_t) + 32);
- if (!base) return 0;
+ if (!base) return 0;
ogles_context_t *c =
(ogles_context_t *)((ptrdiff_t(base) + extra + 31) & ~0x1FL);
memset(c, 0, sizeof(ogles_context_t));
ggl_init_context(&(c->rasterizer));
-
+
// XXX: this should be passed as an argument
sp<EGLSurfaceManager> smgr(new EGLSurfaceManager());
c->surfaceManager = smgr.get();
@@ -87,13 +91,42 @@ ogles_context_t *ogles_init(size_t extra)
c->rasterizer.base = base;
c->point.size = TRI_ONE;
c->line.width = TRI_ONE;
-
+
// in OpenGL, writing to the depth buffer is enabled by default.
c->rasterizer.procs.depthMask(c, 1);
-
+
// OpenGL enables dithering by default
c->rasterizer.procs.enable(c, GL_DITHER);
+ c->copybits.blitEngine = NULL;
+ c->copybits.minScale = 0;
+ c->copybits.maxScale = 0;
+ c->copybits.drawSurfaceBuffer = 0;
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ hw_module_t const* module;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ struct copybit_device_t* copyBits;
+ if (copybit_open(module, &copyBits) == 0) {
+ c->copybits.blitEngine = copyBits;
+ {
+ int minLim = copyBits->get(copyBits,
+ COPYBIT_MINIFICATION_LIMIT);
+ if (minLim != -EINVAL && minLim > 0) {
+ c->copybits.minScale = (1 << 16) / minLim;
+ }
+ }
+ {
+ int magLim = copyBits->get(copyBits,
+ COPYBIT_MAGNIFICATION_LIMIT);
+ if (magLim != -EINVAL && magLim > 0) {
+ c->copybits.maxScale = min(32*1024-1, magLim) << 16;
+ }
+ }
+ }
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
return c;
}
@@ -107,7 +140,12 @@ void ogles_uninit(ogles_context_t* c)
c->surfaceManager->decStrong(c);
c->bufferObjectManager->decStrong(c);
ggl_uninit_context(&(c->rasterizer));
- free(c->rasterizer.base);
+ free(c->rasterizer.base);
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (c->copybits.blitEngine != NULL) {
+ copybit_close((struct copybit_device_t*) c->copybits.blitEngine);
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
}
void _ogles_error(ogles_context_t* c, GLenum error)
@@ -188,7 +226,7 @@ static void enable_disable(ogles_context_t* c, GLenum cap, int enabled)
// these need to fall through into the rasterizer
c->rasterizer.procs.enableDisable(c, cap, enabled);
break;
-
+
case GL_MULTISAMPLE:
case GL_SAMPLE_ALPHA_TO_COVERAGE:
case GL_SAMPLE_ALPHA_TO_ONE:
@@ -281,7 +319,7 @@ void glHint(GLenum target, GLenum mode)
case GL_LINE_SMOOTH_HINT:
break;
case GL_POINT_SMOOTH_HINT:
- c->rasterizer.procs.enableDisable(c,
+ c->rasterizer.procs.enableDisable(c,
GGL_POINT_SMOOTH_NICE, mode==GL_NICEST);
break;
case GL_PERSPECTIVE_CORRECTION_HINT:
@@ -323,7 +361,7 @@ GLenum glGetError()
c->error = 0;
return ret;
}
-
+
if (c->rasterizer.error) {
const GLenum ret(c->rasterizer.error);
c->rasterizer.error = 0;
@@ -362,25 +400,25 @@ void glGetIntegerv(GLenum pname, GLint *params)
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].ah - formats[index].al;
- break;
+ break;
}
case GL_RED_BITS: {
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].rh - formats[index].rl;
- break;
+ break;
}
case GL_GREEN_BITS: {
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].gh - formats[index].gl;
- break;
+ break;
}
case GL_BLUE_BITS: {
int index = c->rasterizer.state.buffers.color.format;
GGLFormat const * formats = gglGetPixelFormatTable();
params[0] = formats[index].bh - formats[index].bl;
- break;
+ break;
}
case GL_COMPRESSED_TEXTURE_FORMATS:
params[ 0] = GL_PALETTE4_RGB8_OES;
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 14a910c..4d3c2f4 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -23,6 +23,12 @@
#include "texture.h"
#include "TextureObjectManager.h"
+#include <private/ui/android_natives_priv.h>
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+#include "copybit.h"
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+
namespace android {
// ----------------------------------------------------------------------------
@@ -48,7 +54,7 @@ void ogles_init_texture(ogles_context_t* c)
// each context has a default named (0) texture (not shared)
c->textures.defaultTexture = new EGLTextureObject();
c->textures.defaultTexture->incStrong(c);
-
+
// bind the default texture to each texture unit
for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
bindTextureTmu(c, i, 0, c->textures.defaultTexture);
@@ -96,7 +102,7 @@ void validate_tmu(ogles_context_t* c, int i)
}
}
-void ogles_validate_texture_impl(ogles_context_t* c)
+void ogles_validate_texture(ogles_context_t* c)
{
for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
if (c->rasterizer.state.texture[i].enable)
@@ -110,6 +116,66 @@ void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
c->textures.tmu[tmu].dirty = flags;
}
+/*
+ * If the active textures are EGLImage, they need to be locked before
+ * they can be used.
+ *
+ * FIXME: code below is far from being optimal
+ *
+ */
+
+void ogles_lock_textures(ogles_context_t* c)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->rasterizer.state.texture[i].enable) {
+ texture_unit_t& u(c->textures.tmu[i]);
+ android_native_buffer_t* native_buffer = u.texture->buffer;
+ if (native_buffer) {
+ c->rasterizer.procs.activeTexture(c, i);
+ hw_module_t const* pModule;
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
+ continue;
+
+ gralloc_module_t const* module =
+ reinterpret_cast<gralloc_module_t const*>(pModule);
+
+ void* vaddr;
+ int err = module->lock(module, native_buffer->handle,
+ GRALLOC_USAGE_SW_READ_OFTEN,
+ 0, 0, native_buffer->width, native_buffer->height,
+ &vaddr);
+
+ u.texture->setImageBits(vaddr);
+ c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+ }
+ }
+ }
+}
+
+void ogles_unlock_textures(ogles_context_t* c)
+{
+ for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
+ if (c->rasterizer.state.texture[i].enable) {
+ texture_unit_t& u(c->textures.tmu[i]);
+ android_native_buffer_t* native_buffer = u.texture->buffer;
+ if (native_buffer) {
+ c->rasterizer.procs.activeTexture(c, i);
+ hw_module_t const* pModule;
+ if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &pModule))
+ continue;
+
+ gralloc_module_t const* module =
+ reinterpret_cast<gralloc_module_t const*>(pModule);
+
+ module->unlock(module, native_buffer->handle);
+ u.texture->setImageBits(NULL);
+ c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
+ }
+ }
+ }
+ c->rasterizer.procs.activeTexture(c, c->textures.active);
+}
+
// ----------------------------------------------------------------------------
#if 0
#pragma mark -
@@ -255,7 +321,7 @@ sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
u.texture->decStrong(c);
if (name == 0) {
- // 0 is our local texture object, not shared with anyone.
+ // 0 is our local texture object, not shared with anyone.
// But it affects all bound TMUs immediately.
// (we need to invalidate all units bound to this texture object)
tex = c->textures.defaultTexture;
@@ -273,7 +339,7 @@ sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
u.texture = tex.get();
u.texture->incStrong(c);
u.name = name;
- invalidate_texture(c, active);
+ invalidate_texture(c, active);
return tex;
}
@@ -282,7 +348,7 @@ void bindTextureTmu(
{
if (tex.get() == c->textures.tmu[tmu].texture)
return;
-
+
// free the reference to the previously bound object
texture_unit_t& u(c->textures.tmu[tmu]);
if (u.texture)
@@ -310,7 +376,7 @@ int createTextureSurface(ogles_context_t* c,
if (formatIdx == 0) { // we don't know what to do with this
return GL_INVALID_OPERATION;
}
-
+
// figure out the size we need as well as the stride
const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
const int32_t align = c->textures.unpackAlignment-1;
@@ -530,8 +596,8 @@ static void texParameterx(
ogles_error(c, GL_INVALID_ENUM);
return;
}
-
- EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
+
+ EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
switch (pname) {
case GL_TEXTURE_WRAP_S:
if ((param == GL_REPEAT) ||
@@ -581,13 +647,12 @@ invalid_enum:
}
-static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
+
+static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
ogles_context_t* c)
{
- // quickly reject empty rects
- if ((w|h) <= 0)
- return;
-
+ ogles_lock_textures(c);
+
const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
y = gglIntToFixed(cbSurface.height) - (y + h);
w >>= FIXED_BITS;
@@ -610,7 +675,7 @@ static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
u.dirty = 0xFF; // XXX: should be more subtle
- EGLTextureObject* textureObject = u.texture;
+ EGLTextureObject* textureObject = u.texture;
const GLint Ucr = textureObject->crop_rect[0] << 16;
const GLint Vcr = textureObject->crop_rect[1] << 16;
const GLint Wcr = textureObject->crop_rect[2] << 16;
@@ -641,11 +706,30 @@ static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
c->rasterizer.procs.disable(c, GGL_W_LERP);
c->rasterizer.procs.disable(c, GGL_AA);
c->rasterizer.procs.shadeModel(c, GL_FLAT);
- c->rasterizer.procs.recti(c,
+ c->rasterizer.procs.recti(c,
gglFixedToIntRound(x),
gglFixedToIntRound(y),
gglFixedToIntRound(x)+w,
gglFixedToIntRound(y)+h);
+
+ ogles_unlock_textures(c);
+}
+
+static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
+ ogles_context_t* c)
+{
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (drawTexiOESWithCopybit(gglFixedToIntRound(x),
+ gglFixedToIntRound(y), gglFixedToIntRound(z),
+ gglFixedToIntRound(w), gglFixedToIntRound(h), c)) {
+ return;
+ }
+#else
+ // quickly reject empty rects
+ if ((w|h) <= 0)
+ return;
+#endif
+ drawTexxOESImp(x, y, z, w, h, c);
}
static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
@@ -656,14 +740,21 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte
// which is a lot faster.
if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ if (drawTexiOESWithCopybit(x, y, z, w, h, c)) {
+ return;
+ }
+#endif
const int tmu = 0;
texture_unit_t& u(c->textures.tmu[tmu]);
- EGLTextureObject* textureObject = u.texture;
+ EGLTextureObject* textureObject = u.texture;
const GLint Wcr = textureObject->crop_rect[2];
const GLint Hcr = textureObject->crop_rect[3];
if ((w == Wcr) && (h == -Hcr)) {
+#ifndef LIBAGL_USE_GRALLOC_COPYBITS
if ((w|h) <= 0) return; // quickly reject empty rects
+#endif
if (u.dirty) {
c->rasterizer.procs.activeTexture(c, tmu);
@@ -679,14 +770,14 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte
GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
u.dirty = 0xFF; // XXX: should be more subtle
c->rasterizer.procs.activeTexture(c, c->textures.active);
-
+
const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
y = cbSurface.height - (y + h);
const GLint Ucr = textureObject->crop_rect[0];
const GLint Vcr = textureObject->crop_rect[1];
const GLint s0 = Ucr - x;
const GLint t0 = (Vcr + Hcr) - y;
-
+
const GLuint tw = textureObject->surface.width;
const GLuint th = textureObject->surface.height;
if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
@@ -694,7 +785,9 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte
// in this case, so we just use the slow case, which
// at least won't crash
goto slow_case;
- }
+ }
+
+ ogles_lock_textures(c);
c->rasterizer.procs.texCoord2i(c, s0, t0);
const uint32_t enables = c->rasterizer.state.enables;
@@ -706,12 +799,15 @@ static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_conte
c->rasterizer.procs.disable(c, GGL_AA);
c->rasterizer.procs.shadeModel(c, GL_FLAT);
c->rasterizer.procs.recti(c, x, y, x+w, y+h);
+
+ ogles_unlock_textures(c);
+
return;
}
}
slow_case:
- drawTexxOES(
+ drawTexxOESImp(
gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
gglIntToFixed(w), gglIntToFixed(h),
c);
@@ -749,7 +845,7 @@ void glBindTexture(GLenum target, GLuint texture)
}
// Bind or create a texture
- sp<EGLTextureObject> tex;
+ sp<EGLTextureObject> tex;
if (texture == 0) {
// 0 is our local texture object
tex = c->textures.defaultTexture;
@@ -837,7 +933,7 @@ void glPixelStorei(GLenum pname, GLint param)
if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
ogles_error(c, GL_INVALID_ENUM);
return;
- }
+ }
if ((param<=0 || param>8) || (param & (param-1))) {
ogles_error(c, GL_INVALID_VALUE);
return;
@@ -952,7 +1048,7 @@ void glCompressedTexImage2D(
}
// "uncompress" the texture since pixelflinger doesn't support
- // any compressed texture format natively.
+ // any compressed texture format natively.
GLenum format;
GLenum type;
switch (internalformat) {
@@ -1016,7 +1112,7 @@ void glTexImage2D(
GLenum format, GLenum type, const GLvoid *pixels)
{
ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D && target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
+ if (target != GL_TEXTURE_2D) {
ogles_error(c, GL_INVALID_ENUM);
return;
}
@@ -1024,7 +1120,7 @@ void glTexImage2D(
ogles_error(c, GL_INVALID_VALUE);
return;
}
- if (format != internalformat) {
+ if (format != (GLenum)internalformat) {
ogles_error(c, GL_INVALID_OPERATION);
return;
}
@@ -1034,16 +1130,10 @@ void glTexImage2D(
int32_t size = 0;
GGLSurface* surface = 0;
- if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
- int error = createTextureSurface(c, &surface, &size,
- level, format, type, width, height);
- if (error) {
- ogles_error(c, error);
- return;
- }
- } else if (pixels == 0 || level != 0) {
- // pixel can't be null for direct texture
- ogles_error(c, GL_INVALID_OPERATION);
+ int error = createTextureSurface(c, &surface, &size,
+ level, format, type, width, height);
+ if (error) {
+ ogles_error(c, error);
return;
}
@@ -1064,18 +1154,12 @@ void glTexImage2D(
userSurface.compressedFormat = 0;
userSurface.data = (GLubyte*)pixels;
- if (target != GL_DIRECT_TEXTURE_2D_QUALCOMM) {
- int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
- if (err) {
- ogles_error(c, err);
- return;
- }
- generateMipmap(c, level);
- } else {
- // bind it to the texture unit
- sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
- tex->setSurface(&userSurface);
+ int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
+ if (err) {
+ ogles_error(c, err);
+ return;
}
+ generateMipmap(c, level);
}
}
@@ -1150,7 +1234,7 @@ void glTexSubImage2D(
int err = copyPixels(c,
surface, xoffset, yoffset,
- userSurface, 0, 0, width, height);
+ userSurface, 0, 0, width, height);
if (err) {
ogles_error(c, err);
return;
@@ -1203,7 +1287,7 @@ void glCopyTexImage2D(
case GL_LUMINANCE_ALPHA:
case GL_LUMINANCE:
type = GL_UNSIGNED_BYTE;
- break;
+ break;
}
// figure out the format to use for the new texture
@@ -1213,7 +1297,7 @@ void glCopyTexImage2D(
case GGL_PIXEL_FORMAT_RGBA_5551:
case GGL_PIXEL_FORMAT_RGBA_4444:
format = internalformat;
- break;
+ break;
case GGL_PIXEL_FORMAT_RGBX_8888:
case GGL_PIXEL_FORMAT_RGB_888:
case GGL_PIXEL_FORMAT_RGB_565:
@@ -1222,7 +1306,7 @@ void glCopyTexImage2D(
case GL_LUMINANCE:
case GL_RGB:
format = internalformat;
- break;
+ break;
}
break;
}
@@ -1242,7 +1326,7 @@ void glCopyTexImage2D(
ogles_error(c, error);
return;
}
-
+
// The bottom row is stored first in textures
GGLSurface txSurface(*surface);
txSurface.stride = -txSurface.stride;
@@ -1252,7 +1336,7 @@ void glCopyTexImage2D(
int err = copyPixels(c,
txSurface, 0, 0,
- cbSurface, x, y, cbSurface.width, cbSurface.height);
+ cbSurface, x, y, cbSurface.width, cbSurface.height);
if (err) {
ogles_error(c, err);
}
@@ -1302,7 +1386,7 @@ void glCopyTexSubImage2D(
int err = copyPixels(c,
surface, xoffset, yoffset,
- cbSurface, x, y, width, height);
+ cbSurface, x, y, width, height);
if (err) {
ogles_error(c, err);
return;
@@ -1372,7 +1456,7 @@ void glReadPixels(
return;
}
- ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
+ ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
ggl->bindTexture(ggl, &readSurface); // source is read-buffer
ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
ggl->recti(ggl, 0, 0, width, height);
@@ -1426,3 +1510,43 @@ void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
ogles_context_t* c = ogles_context_t::get();
drawTexxOES(x, y, z, w, h, c);
}
+
+// ----------------------------------------------------------------------------
+#if 0
+#pragma mark -
+#pragma mark EGL Image Extension
+#endif
+
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+ ogles_context_t* c = ogles_context_t::get();
+ if (target != GL_TEXTURE_2D) {
+ ogles_error(c, GL_INVALID_ENUM);
+ return;
+ }
+
+ android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
+ if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+ if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
+ ogles_error(c, GL_INVALID_VALUE);
+ return;
+ }
+
+ // bind it to the texture unit
+ sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
+ tex->setImage(native_buffer);
+
+#ifdef LIBAGL_USE_GRALLOC_COPYBITS
+ tex->try_copybit = false;
+ if (c->copybits.blitEngine != NULL) {
+ tex->try_copybit = true;
+ }
+#endif // LIBAGL_USE_GRALLOC_COPYBITS
+}
+
+void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
+{
+}
diff --git a/opengl/libagl/texture.h b/opengl/libagl/texture.h
index 5c57948..98f7550 100644
--- a/opengl/libagl/texture.h
+++ b/opengl/libagl/texture.h
@@ -32,13 +32,9 @@ namespace android {
void ogles_init_texture(ogles_context_t* c);
void ogles_uninit_texture(ogles_context_t* c);
-void ogles_validate_texture_impl(ogles_context_t* c);
-
-inline void ogles_validate_texture(ogles_context_t* c) {
- if (c->rasterizer.state.enables & GGL_ENABLE_TMUS)
- ogles_validate_texture_impl(c);
-}
-
+void ogles_validate_texture(ogles_context_t* c);
+void ogles_lock_textures(ogles_context_t* c);
+void ogles_unlock_textures(ogles_context_t* c);
}; // namespace android
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 23304d5..9578452 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -1,17 +1,18 @@
LOCAL_PATH:= $(call my-dir)
-#
+###############################################################################
# Build META EGL library
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- EGL/egl.cpp \
- EGL/gpu.cpp \
+ EGL/egl.cpp \
+ EGL/hooks.cpp \
+ EGL/Loader.cpp \
#
-LOCAL_SHARED_LIBRARIES += libcutils libutils libui
+LOCAL_SHARED_LIBRARIES += libcutils libutils
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libEGL
@@ -19,24 +20,46 @@ LOCAL_MODULE:= libEGL
ifeq ($(TARGET_SIMULATOR),true)
else
LOCAL_SHARED_LIBRARIES += libdl
- # we need to access the Bionic private header <bionic_tls.h>
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+ # we need to access the private Bionic header <bionic_tls.h>
+ LOCAL_C_INCLUDES += bionic/libc/private
endif
+LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
+ifeq ($(TARGET_BOARD_PLATFORM),msm7k)
+LOCAL_CFLAGS += -DADRENO130=1
+endif
+
include $(BUILD_SHARED_LIBRARY)
+installed_libEGL := $(LOCAL_INSTALLED_MODULE)
+# OpenGL drivers config file
+ifneq ($(BOARD_EGL_CFG),)
-#
-# Build the wrapper OpenGL ES library
+include $(CLEAR_VARS)
+LOCAL_MODULE := egl.cfg
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/egl
+LOCAL_SRC_FILES := ../../../../$(BOARD_EGL_CFG)
+include $(BUILD_PREBUILT)
+
+# make sure we depend on egl.cfg, so it gets installed
+$(installed_libEGL): | egl.cfg
+
+endif
+
+###############################################################################
+# Build the wrapper OpenGL ES 1.x library
#
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
- GLES_CM/gl.cpp.arm \
+LOCAL_SRC_FILES:= \
+ GLES_CM/gl.cpp.arm \
#
LOCAL_SHARED_LIBRARIES += libcutils libEGL
@@ -47,10 +70,41 @@ LOCAL_MODULE:= libGLESv1_CM
ifeq ($(TARGET_SIMULATOR),true)
else
LOCAL_SHARED_LIBRARIES += libdl
- # we need to access the Bionic private header <bionic_tls.h>
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+ # we need to access the private Bionic header <bionic_tls.h>
+ LOCAL_C_INCLUDES += bionic/libc/private
+endif
+
+LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv1\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+###############################################################################
+# Build the wrapper OpenGL ES 2.x library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ GLES2/gl2.cpp.arm \
+#
+
+LOCAL_SHARED_LIBRARIES += libcutils libEGL
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libGLESv2
+
+# needed on sim build because of weird logging issues
+ifeq ($(TARGET_SIMULATOR),true)
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+ # we need to access the private Bionic header <bionic_tls.h>
+ LOCAL_C_INCLUDES += bionic/libc/private
endif
+LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv2\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
new file mode 100644
index 0000000..d51b333
--- /dev/null
+++ b/opengl/libs/EGL/Loader.cpp
@@ -0,0 +1,276 @@
+/*
+ ** 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.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <limits.h>
+
+#include <cutils/log.h>
+
+#include <EGL/egl.h>
+
+#include "hooks.h"
+#include "egl_impl.h"
+
+#include "Loader.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+
+/*
+ * EGL drivers are called
+ *
+ * /system/lib/egl/lib{[EGL|GLESv1_CM|GLESv2] | GLES}_$TAG.so
+ *
+ */
+
+ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
+
+// ----------------------------------------------------------------------------
+
+Loader::driver_t::driver_t(void* gles)
+{
+ dso[0] = gles;
+ for (size_t i=1 ; i<NELEM(dso) ; i++)
+ dso[i] = 0;
+}
+
+Loader::driver_t::~driver_t()
+{
+ for (size_t i=0 ; i<NELEM(dso) ; i++) {
+ if (dso[i]) {
+ dlclose(dso[i]);
+ dso[i] = 0;
+ }
+ }
+}
+
+status_t Loader::driver_t::set(void* hnd, int32_t api)
+{
+ switch (api) {
+ case EGL:
+ dso[0] = hnd;
+ break;
+ case GLESv1_CM:
+ dso[1] = hnd;
+ break;
+ case GLESv2:
+ dso[2] = hnd;
+ break;
+ default:
+ return BAD_INDEX;
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+Loader::entry_t::entry_t(int dpy, int impl, const char* tag)
+ : dpy(dpy), impl(impl), tag(tag) {
+}
+
+// ----------------------------------------------------------------------------
+
+Loader::Loader()
+{
+ char line[256];
+ char tag[256];
+ FILE* cfg = fopen("/system/lib/egl/egl.cfg", "r");
+ if (cfg == NULL) {
+ // default config
+ LOGD("egl.cfg not found, using default config");
+ gConfig.add( entry_t(0, 0, "android") );
+ } else {
+ while (fgets(line, 256, cfg)) {
+ int dpy;
+ int impl;
+ if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) {
+ //LOGD(">>> %u %u %s", dpy, impl, tag);
+ gConfig.add( entry_t(dpy, impl, tag) );
+ }
+ }
+ fclose(cfg);
+ }
+}
+
+Loader::~Loader()
+{
+}
+
+const char* Loader::getTag(int dpy, int impl)
+{
+ const Vector<entry_t>& cfgs(gConfig);
+ const size_t c = cfgs.size();
+ for (size_t i=0 ; i<c ; i++) {
+ if (dpy == cfgs[i].dpy)
+ if (impl == cfgs[i].impl)
+ return cfgs[i].tag.string();
+ }
+ return 0;
+}
+
+void* Loader::open(EGLNativeDisplayType display, int impl, gl_hooks_t* hooks)
+{
+ /*
+ * TODO: if we don't find display/0, then use 0/0
+ * (0/0 should always work)
+ */
+
+ void* dso;
+ char path[PATH_MAX];
+ int index = int(display);
+ driver_t* hnd = 0;
+ const char* const format = "/system/lib/egl/lib%s_%s.so";
+
+ char const* tag = getTag(index, impl);
+ if (tag) {
+ snprintf(path, PATH_MAX, format, "GLES", tag);
+ dso = load_driver(path, hooks, EGL | GLESv1_CM | GLESv2);
+ if (dso) {
+ hnd = new driver_t(dso);
+ } else {
+ // Always load EGL first
+ snprintf(path, PATH_MAX, format, "EGL", tag);
+ dso = load_driver(path, hooks, EGL);
+ if (dso) {
+ hnd = new driver_t(dso);
+
+ // TODO: make this more automated
+ snprintf(path, PATH_MAX, format, "GLESv1_CM", tag);
+ hnd->set( load_driver(path, hooks, GLESv1_CM), GLESv1_CM );
+
+ snprintf(path, PATH_MAX, format, "GLESv2", tag);
+ hnd->set( load_driver(path, hooks, GLESv2), GLESv2 );
+ }
+ }
+ }
+
+ LOG_FATAL_IF(!index && !impl && !hnd,
+ "couldn't find the default OpenGL ES implementation "
+ "for default display");
+
+ return (void*)hnd;
+}
+
+status_t Loader::close(void* driver)
+{
+ driver_t* hnd = (driver_t*)driver;
+ delete hnd;
+ return NO_ERROR;
+}
+
+void Loader::init_api(void* dso,
+ char const * const * api,
+ __eglMustCastToProperFunctionPointerType* curr,
+ getProcAddressType getProcAddress)
+{
+ char scrap[256];
+ while (*api) {
+ char const * name = *api;
+ __eglMustCastToProperFunctionPointerType f =
+ (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
+ if (f == NULL) {
+ // couldn't find the entry-point, use eglGetProcAddress()
+ f = getProcAddress(name);
+ }
+ if (f == NULL) {
+ // Try without the OES postfix
+ ssize_t index = ssize_t(strlen(name)) - 3;
+ if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
+ strncpy(scrap, name, index);
+ scrap[index] = 0;
+ f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
+ //LOGD_IF(f, "found <%s> instead", scrap);
+ }
+ }
+ if (f == NULL) {
+ // Try with the OES postfix
+ ssize_t index = ssize_t(strlen(name)) - 3;
+ if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
+ strncpy(scrap, name, index);
+ scrap[index] = 0;
+ strcat(scrap, "OES");
+ f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
+ //LOGD_IF(f, "found <%s> instead", scrap);
+ }
+ }
+ if (f == NULL) {
+ //LOGD("%s", name);
+ f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
+ }
+ *curr++ = f;
+ api++;
+ }
+}
+
+void *Loader::load_driver(const char* driver, gl_hooks_t* hooks, uint32_t mask)
+{
+ void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
+ if (dso == 0)
+ return 0;
+
+ LOGD("loaded %s", driver);
+
+ if (mask & EGL) {
+ getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
+
+ LOGE_IF(!getProcAddress,
+ "can't find eglGetProcAddress() in %s", driver);
+
+ gl_hooks_t::egl_t* egl = &hooks->egl;
+ __eglMustCastToProperFunctionPointerType* curr =
+ (__eglMustCastToProperFunctionPointerType*)egl;
+ char const * const * api = egl_names;
+ while (*api) {
+ char const * name = *api;
+ __eglMustCastToProperFunctionPointerType f =
+ (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
+ if (f == NULL) {
+ // couldn't find the entry-point, use eglGetProcAddress()
+ f = getProcAddress(name);
+ if (f == NULL) {
+ f = (__eglMustCastToProperFunctionPointerType)0;
+ }
+ }
+ *curr++ = f;
+ api++;
+ }
+ }
+
+ if (mask & GLESv1_CM) {
+ init_api(dso, gl_names,
+ (__eglMustCastToProperFunctionPointerType*)&hooks->gl,
+ getProcAddress);
+ }
+
+ if (mask & GLESv2) {
+ init_api(dso, gl2_names,
+ (__eglMustCastToProperFunctionPointerType*)&hooks->gl2,
+ getProcAddress);
+ }
+
+ return dso;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
new file mode 100644
index 0000000..69f6dd5
--- /dev/null
+++ b/opengl/libs/EGL/Loader.h
@@ -0,0 +1,90 @@
+/*
+ ** 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.
+ */
+
+#ifndef ANDROID_EGL_LOADER_H
+#define ANDROID_EGL_LOADER_H
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <EGL/egl.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+struct gl_hooks_t;
+
+class Loader : public Singleton<Loader>
+{
+ friend class Singleton<Loader>;
+
+ typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
+ const char*);
+
+ enum {
+ EGL = 0x01,
+ GLESv1_CM = 0x02,
+ GLESv2 = 0x04
+ };
+ struct driver_t {
+ driver_t(void* gles);
+ ~driver_t();
+ status_t set(void* hnd, int32_t api);
+ void* dso[3];
+ };
+
+ struct entry_t {
+ entry_t() { }
+ entry_t(int dpy, int impl, const char* tag);
+ int dpy;
+ int impl;
+ String8 tag;
+ };
+
+ Vector<entry_t> gConfig;
+ getProcAddressType getProcAddress;
+
+ const char* getTag(int dpy, int impl);
+
+public:
+ ~Loader();
+
+ void* open(EGLNativeDisplayType display, int impl, gl_hooks_t* hooks);
+ status_t close(void* driver);
+
+private:
+ Loader();
+ void *load_driver(const char* driver, gl_hooks_t* hooks, uint32_t mask);
+
+ static __attribute__((noinline))
+ void init_api(void* dso,
+ char const * const * api,
+ __eglMustCastToProperFunctionPointerType* curr,
+ getProcAddressType getProcAddress);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_EGL_LOADER_H */
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index c6e0f50..d1ddcd3 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -14,9 +14,8 @@
** limitations under the License.
*/
-#define LOG_TAG "libEGL"
-
#include <ctype.h>
+#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dlfcn.h>
@@ -37,11 +36,11 @@
#include <cutils/properties.h>
#include <cutils/memory.h>
-#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
#include "hooks.h"
#include "egl_impl.h"
-
+#include "Loader.h"
#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
@@ -53,61 +52,148 @@ namespace android {
#define VERSION_MAJOR 1
#define VERSION_MINOR 4
static char const * const gVendorString = "Android";
-static char const * const gVersionString = "1.31 Android META-EGL";
+static char const * const gVersionString = "1.4 Android META-EGL";
static char const * const gClientApiString = "OpenGL ES";
-static char const * const gExtensionString = "";
+static char const * const gExtensionString =
+ "EGL_KHR_image "
+ "EGL_KHR_image_base "
+ "EGL_KHR_image_pixmap "
+ "EGL_ANDROID_image_native_buffer "
+ "EGL_ANDROID_swap_rectangle "
+ "EGL_ANDROID_get_render_buffer "
+ ;
+
+// ----------------------------------------------------------------------------
+
+class egl_object_t {
+ static SortedVector<egl_object_t*> sObjects;
+ static Mutex sLock;
+
+ volatile int32_t terminated;
+ mutable volatile int32_t count;
+
+public:
+ egl_object_t() : terminated(0), count(1) {
+ Mutex::Autolock _l(sLock);
+ sObjects.add(this);
+ }
+
+ inline bool isAlive() const { return !terminated; }
-template <int MAGIC>
-struct egl_object_t
-{
- egl_object_t() : magic(MAGIC) { }
- ~egl_object_t() { magic = 0; }
- bool isValid() const { return magic == MAGIC; }
private:
- uint32_t magic;
+ bool get() {
+ Mutex::Autolock _l(sLock);
+ if (egl_object_t::sObjects.indexOf(this) >= 0) {
+ android_atomic_inc(&count);
+ return true;
+ }
+ return false;
+ }
+
+ bool put() {
+ Mutex::Autolock _l(sLock);
+ if (android_atomic_dec(&count) == 1) {
+ sObjects.remove(this);
+ return true;
+ }
+ return false;
+ }
+
+public:
+ template <typename N, typename T>
+ struct LocalRef {
+ N* ref;
+ LocalRef(T o) : ref(0) {
+ N* native = reinterpret_cast<N*>(o);
+ if (o && native->get()) {
+ ref = native;
+ }
+ }
+ ~LocalRef() {
+ if (ref && ref->put()) {
+ delete ref;
+ }
+ }
+ inline N* get() {
+ return ref;
+ }
+ void acquire() const {
+ if (ref) {
+ android_atomic_inc(&ref->count);
+ }
+ }
+ void release() const {
+ if (ref) {
+ int32_t c = android_atomic_dec(&ref->count);
+ // ref->count cannot be 1 prior atomic_dec because we have
+ // a reference, and if we have one, it means there was
+ // already one before us.
+ LOGE_IF(c==1, "refcount is now 0 in release()");
+ }
+ }
+ void terminate() {
+ if (ref) {
+ ref->terminated = 1;
+ release();
+ }
+ }
+ };
};
-struct egl_display_t : public egl_object_t<'_dpy'>
-{
- EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
- EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
- EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
- EGLint numTotalConfigs;
- char const* extensionsString;
- volatile int32_t refs;
+SortedVector<egl_object_t*> egl_object_t::sObjects;
+Mutex egl_object_t::sLock;
+
+struct egl_display_t {
+ enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
+
struct strings_t {
char const * vendor;
char const * version;
char const * clientApi;
char const * extensions;
};
- strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+
+ struct DisplayImpl {
+ DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
+ state(NOT_INITIALIZED), numConfigs(0) { }
+ EGLDisplay dpy;
+ EGLConfig* config;
+ EGLint state;
+ EGLint numConfigs;
+ strings_t queryString;
+ };
+
+ uint32_t magic;
+ DisplayImpl disp[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+ EGLint numTotalConfigs;
+ volatile int32_t refs;
+
+ egl_display_t() : magic('_dpy'), numTotalConfigs(0) { }
+ ~egl_display_t() { magic = 0; }
+ inline bool isValid() const { return magic == '_dpy'; }
+ inline bool isAlive() const { return isValid(); }
};
-struct egl_surface_t : public egl_object_t<'_srf'>
+struct egl_surface_t : public egl_object_t
{
+ typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
+
egl_surface_t(EGLDisplay dpy, EGLSurface surface,
- NativeWindowType window, int impl, egl_connection_t const* cnx)
- : dpy(dpy), surface(surface), window(window), impl(impl), cnx(cnx)
- {
- // NOTE: window must be incRef'ed and connected already
+ int impl, egl_connection_t const* cnx)
+ : dpy(dpy), surface(surface), impl(impl), cnx(cnx) {
}
~egl_surface_t() {
- if (window) {
- if (window->disconnect)
- window->disconnect(window);
- window->decRef(window);
- }
}
EGLDisplay dpy;
EGLSurface surface;
- NativeWindowType window;
int impl;
egl_connection_t const* cnx;
};
-struct egl_context_t : public egl_object_t<'_ctx'>
+struct egl_context_t : public egl_object_t
{
+ typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
+
egl_context_t(EGLDisplay dpy, EGLContext context,
int impl, egl_connection_t const* cnx)
: dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
@@ -121,39 +207,32 @@ struct egl_context_t : public egl_object_t<'_ctx'>
egl_connection_t const* cnx;
};
-struct tls_t
+struct egl_image_t : public egl_object_t
{
- tls_t() : error(EGL_SUCCESS), ctx(0) { }
- EGLint error;
- EGLContext ctx;
-};
-
-static void gl_unimplemented() {
- LOGE("called unimplemented OpenGL ES API");
-}
+ typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
-// ----------------------------------------------------------------------------
-// GL / EGL hooks
-// ----------------------------------------------------------------------------
-
-#undef GL_ENTRY
-#undef EGL_ENTRY
-#define GL_ENTRY(_r, _api, ...) #_api,
-#define EGL_ENTRY(_r, _api, ...) #_api,
-
-static char const * const gl_names[] = {
- #include "gl_entries.in"
- #include "glext_entries.in"
- NULL
+ egl_image_t(EGLDisplay dpy, EGLContext context)
+ : dpy(dpy), context(context)
+ {
+ memset(images, 0, sizeof(images));
+ }
+ EGLDisplay dpy;
+ EGLConfig context;
+ EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
};
-static char const * const egl_names[] = {
- #include "egl_entries.in"
- NULL
+typedef egl_surface_t::Ref SurfaceRef;
+typedef egl_context_t::Ref ContextRef;
+typedef egl_image_t::Ref ImageRef;
+
+struct tls_t
+{
+ tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
+ EGLint error;
+ EGLContext ctx;
+ EGLBoolean logCallWithNoContext;
};
-#undef GL_ENTRY
-#undef EGL_ENTRY
// ----------------------------------------------------------------------------
@@ -262,110 +341,8 @@ EGLContext getContext() {
return tls->ctx;
}
-
/*****************************************************************************/
-class ISurfaceComposer;
-const sp<ISurfaceComposer>& getSurfaceFlinger();
-request_gpu_t* gpu_acquire(void* user);
-int gpu_release(void*, request_gpu_t* gpu);
-
-static __attribute__((noinline))
-void *load_driver(const char* driver, gl_hooks_t* hooks)
-{
- //LOGD("%s", driver);
- char scrap[256];
- void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
- LOGE_IF(!dso,
- "couldn't load <%s> library (%s)",
- driver, dlerror());
-
- if (dso) {
- // first find the symbol for eglGetProcAddress
-
- typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
- const char*);
-
- getProcAddressType getProcAddress =
- (getProcAddressType)dlsym(dso, "eglGetProcAddress");
-
- LOGE_IF(!getProcAddress,
- "can't find eglGetProcAddress() in %s", driver);
-
- __eglMustCastToProperFunctionPointerType* curr;
- char const * const * api;
-
- gl_hooks_t::egl_t* egl = &hooks->egl;
- curr = (__eglMustCastToProperFunctionPointerType*)egl;
- api = egl_names;
- while (*api) {
- char const * name = *api;
- __eglMustCastToProperFunctionPointerType f =
- (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
- if (f == NULL) {
- // couldn't find the entry-point, use eglGetProcAddress()
- f = getProcAddress(name);
- if (f == NULL) {
- f = (__eglMustCastToProperFunctionPointerType)0;
- }
- }
- *curr++ = f;
- api++;
- }
-
- gl_hooks_t::gl_t* gl = &hooks->gl;
- curr = (__eglMustCastToProperFunctionPointerType*)gl;
- api = gl_names;
- while (*api) {
- char const * name = *api;
- __eglMustCastToProperFunctionPointerType f =
- (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
- if (f == NULL) {
- // couldn't find the entry-point, use eglGetProcAddress()
- f = getProcAddress(name);
- }
- if (f == NULL) {
- // Try without the OES postfix
- ssize_t index = ssize_t(strlen(name)) - 3;
- if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
- strncpy(scrap, name, index);
- scrap[index] = 0;
- f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
- //LOGD_IF(f, "found <%s> instead", scrap);
- }
- }
- if (f == NULL) {
- // Try with the OES postfix
- ssize_t index = ssize_t(strlen(name)) - 3;
- if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
- strncpy(scrap, name, index);
- scrap[index] = 0;
- strcat(scrap, "OES");
- f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
- //LOGD_IF(f, "found <%s> instead", scrap);
- }
- }
- if (f == NULL) {
- //LOGD("%s", name);
- f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
- }
- *curr++ = f;
- api++;
- }
-
- // hook this driver up with surfaceflinger if needed
- register_gpu_t register_gpu =
- (register_gpu_t)dlsym(dso, "oem_register_gpu");
-
- if (register_gpu != NULL) {
- if (getSurfaceFlinger() != 0) {
- register_gpu(dso, gpu_acquire, gpu_release);
- }
- }
- }
- return dso;
-}
-
template<typename T>
static __attribute__((noinline))
int binarySearch(
@@ -387,14 +364,14 @@ int binarySearch(
static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
{
// NOTE: this mapping works only if we have no more than two EGLimpl
- return (i>0 ? dp->numConfigs[0] : 0) + index;
+ return (i>0 ? dp->disp[0].numConfigs : 0) + index;
}
static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
int& i, int& index)
{
// NOTE: this mapping works only if we have no more than two EGLimpl
- size_t numConfigs = dp->numConfigs[0];
+ size_t numConfigs = dp->disp[0].numConfigs;
i = configId / numConfigs;
index = configId % numConfigs;
}
@@ -412,6 +389,18 @@ struct extention_map_t {
};
static const extention_map_t gExtentionMap[] = {
+ { "eglLockSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
+ { "eglUnlockSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
+ { "eglCreateImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
+ { "eglDestroyImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
+ { "eglSetSwapRectangleANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
+ { "eglGetRenderBufferANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
};
static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
@@ -429,29 +418,15 @@ static void(*findProcAddress(const char* name,
// ----------------------------------------------------------------------------
-static int gl_context_lost() {
- setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
- return 0;
-}
-static int egl_context_lost() {
- setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
- return EGL_FALSE;
-}
-static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
- usleep(100000); // don't use all the CPU
- setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
- return EGL_FALSE;
-}
-static GLint egl_context_lost_get_error() {
- return EGL_CONTEXT_LOST;
-}
-static int ext_context_lost() {
- return 0;
-}
-
static void gl_no_context() {
- LOGE("call to OpenGL ES API with no current context");
+ tls_t* tls = getTLS();
+ if (tls->logCallWithNoContext == EGL_TRUE) {
+ tls->logCallWithNoContext = EGL_FALSE;
+ LOGE("call to OpenGL ES API with no current context "
+ "(logged once per thread)");
+ }
}
+
static void early_egl_init(void)
{
#if !USE_FAST_TLS_KEY
@@ -491,6 +466,11 @@ egl_context_t* get_context(EGLContext context) {
return egl_to_native_cast<egl_context_t>(context);
}
+static inline
+egl_image_t* get_image(EGLImageKHR image) {
+ return egl_to_native_cast<egl_image_t>(image);
+}
+
static egl_connection_t* validate_display_config(
EGLDisplay dpy, EGLConfig config,
egl_display_t const*& dp, int& impl, int& index)
@@ -503,7 +483,7 @@ static egl_connection_t* validate_display_config(
return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
}
index = uintptr_t(config) & 0xFFFFFF;
- if (index >= dp->numConfigs[impl]) {
+ if (index >= dp->disp[impl].numConfigs) {
return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
}
egl_connection_t* const cnx = &gEGLImpl[impl];
@@ -517,11 +497,9 @@ static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
{
if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!get_display(dpy)->isValid())
+ if (!get_display(dpy)->isAlive())
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!ctx) // TODO: make sure context is a valid object
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (!get_context(ctx)->isValid())
+ if (!get_context(ctx)->isAlive())
return setError(EGL_BAD_CONTEXT, EGL_FALSE);
return EGL_TRUE;
}
@@ -530,92 +508,106 @@ static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
{
if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!get_display(dpy)->isValid())
+ if (!get_display(dpy)->isAlive())
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!surface) // TODO: make sure surface is a valid object
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (!get_surface(surface)->isValid())
+ if (!get_surface(surface)->isAlive())
return setError(EGL_BAD_SURFACE, EGL_FALSE);
return EGL_TRUE;
}
+EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
+{
+ ImageRef _i(image);
+ if (!_i.get()) return EGL_NO_IMAGE_KHR;
+
+ EGLContext context = getContext();
+ if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
+ return EGL_NO_IMAGE_KHR;
+
+ egl_context_t const * const c = get_context(context);
+ if (!c->isAlive())
+ return EGL_NO_IMAGE_KHR;
+
+ egl_image_t const * const i = get_image(image);
+ return i->images[c->impl];
+}
-EGLDisplay egl_init_displays(NativeDisplayType display)
+// ----------------------------------------------------------------------------
+
+// this mutex protects:
+// d->disp[]
+// egl_init_drivers_locked()
+//
+static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
+
+EGLBoolean egl_init_drivers_locked()
{
if (sEarlyInitState) {
- return EGL_NO_DISPLAY;
+ // initialized by static ctor. should be set here.
+ return EGL_FALSE;
}
- uint32_t index = uint32_t(display);
- if (index >= NUM_DISPLAYS) {
- return EGL_NO_DISPLAY;
- }
+ // get our driver loader
+ Loader& loader(Loader::getInstance());
- EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
- egl_display_t* d = &gDisplay[index];
-
- // dynamically load all our EGL implementations for that display
- // and call into the real eglGetGisplay()
- egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
+ // dynamically load all our EGL implementations for all displays
+ // and retrieve the corresponding EGLDisplay
+ // if that fails, don't use this driver.
+ // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
+ egl_connection_t* cnx;
+ egl_display_t* d = &gDisplay[0];
+
+ cnx = &gEGLImpl[IMPL_SOFTWARE];
if (cnx->dso == 0) {
cnx->hooks = &gHooks[IMPL_SOFTWARE];
- cnx->dso = load_driver("libagl.so", cnx->hooks);
- }
- if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
- d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
- LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
- "No EGLDisplay for software EGL!");
+ cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx->hooks);
+ if (cnx->dso) {
+ EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
+ d->disp[IMPL_SOFTWARE].dpy = dpy;
+ if (dpy == EGL_NO_DISPLAY) {
+ loader.close(cnx->dso);
+ cnx->dso = NULL;
+ }
+ }
}
cnx = &gEGLImpl[IMPL_HARDWARE];
- if (cnx->dso == 0 && cnx->unavailable == 0) {
+ if (cnx->dso == 0) {
char value[PROPERTY_VALUE_MAX];
property_get("debug.egl.hw", value, "1");
if (atoi(value) != 0) {
cnx->hooks = &gHooks[IMPL_HARDWARE];
- cnx->dso = load_driver("libhgl.so", cnx->hooks);
+ cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx->hooks);
+ if (cnx->dso) {
+ EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
+ d->disp[IMPL_HARDWARE].dpy = dpy;
+ if (dpy == EGL_NO_DISPLAY) {
+ loader.close(cnx->dso);
+ cnx->dso = NULL;
+ }
+ }
} else {
LOGD("3D hardware acceleration is disabled");
}
}
- if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
- android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
- (uint32_t)((void*)gl_context_lost),
- sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
- android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
- (uint32_t)((void*)egl_context_lost),
- sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
- android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
- (uint32_t)((void*)ext_context_lost),
- sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
-
- gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
- egl_context_lost_swap_buffers;
-
- gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
- egl_context_lost_get_error;
- gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
- gHooks[IMPL_HARDWARE].egl.eglTerminate;
-
- d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
- if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
- LOGE("h/w accelerated eglGetDisplay() failed (%s)",
- egl_strerror(cnx->hooks->egl.eglGetError()));
- dlclose((void*)cnx->dso);
- cnx->dso = 0;
- // in case of failure, we want to make sure we don't try again
- // as it's expensive.
- cnx->unavailable = 1;
- }
+ if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
+ return EGL_FALSE;
}
- return dpy;
+ return EGL_TRUE;
}
+EGLBoolean egl_init_drivers()
+{
+ EGLBoolean res;
+ pthread_mutex_lock(&gInitDriverMutex);
+ res = egl_init_drivers_locked();
+ pthread_mutex_unlock(&gInitDriverMutex);
+ return res;
+}
// ----------------------------------------------------------------------------
}; // namespace android
@@ -625,7 +617,17 @@ using namespace android;
EGLDisplay eglGetDisplay(NativeDisplayType display)
{
- return egl_init_displays(display);
+ uint32_t index = uint32_t(display);
+ if (index >= NUM_DISPLAYS) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
+ EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
+ return dpy;
}
// ----------------------------------------------------------------------------
@@ -648,7 +650,6 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
// initialize each EGL and
// build our own extension string first, based on the extension we know
// and the extension supported by our client implementation
- dp->extensionsString = strdup(gExtensionString);
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
cnx->major = -1;
@@ -656,25 +657,43 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
if (!cnx->dso)
continue;
- if (cnx->hooks->egl.eglInitialize(
- dp->dpys[i], &cnx->major, &cnx->minor)) {
+#if defined(ADRENO130)
+#warning "Adreno-130 eglInitialize() workaround"
+ /*
+ * The ADRENO 130 driver returns a different EGLDisplay each time
+ * eglGetDisplay() is called, but also makes the EGLDisplay invalid
+ * after eglTerminate() has been called, so that eglInitialize()
+ * cannot be called again. Therefore, we need to make sure to call
+ * eglGetDisplay() before calling eglInitialize();
+ */
+ if (i == IMPL_HARDWARE) {
+ dp->disp[i].dpy =
+ cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+#endif
+
+ EGLDisplay idpy = dp->disp[i].dpy;
+ if (cnx->hooks->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
//LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
- // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
+ // i, idpy, cnx->major, cnx->minor, cnx);
+
+ // display is now initialized
+ dp->disp[i].state = egl_display_t::INITIALIZED;
// get the query-strings for this display for each implementation
- dp->queryString[i].vendor =
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
- dp->queryString[i].version =
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
- dp->queryString[i].extensions = strdup(
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
- dp->queryString[i].clientApi =
- cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
+ dp->disp[i].queryString.vendor =
+ cnx->hooks->egl.eglQueryString(idpy, EGL_VENDOR);
+ dp->disp[i].queryString.version =
+ cnx->hooks->egl.eglQueryString(idpy, EGL_VERSION);
+ dp->disp[i].queryString.extensions =
+ cnx->hooks->egl.eglQueryString(idpy, EGL_EXTENSIONS);
+ dp->disp[i].queryString.clientApi =
+ cnx->hooks->egl.eglQueryString(idpy, EGL_CLIENT_APIS);
} else {
- LOGD("%d: eglInitialize() failed (%s)",
- i, egl_strerror(cnx->hooks->egl.eglGetError()));
+ LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
+ egl_strerror(cnx->hooks->egl.eglGetError()));
}
}
@@ -683,15 +702,16 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
EGLint n;
- if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
- dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
- if (dp->configs[i]) {
+ if (cnx->hooks->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) {
+ dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
+ if (dp->disp[i].config) {
if (cnx->hooks->egl.eglGetConfigs(
- dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
+ dp->disp[i].dpy, dp->disp[i].config, n,
+ &dp->disp[i].numConfigs))
{
// sort the configurations so we can do binary searches
- qsort( dp->configs[i],
- dp->numConfigs[i],
+ qsort( dp->disp[i].config,
+ dp->disp[i].numConfigs,
sizeof(EGLConfig), cmp_configs);
dp->numTotalConfigs += n;
@@ -712,33 +732,36 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
EGLBoolean eglTerminate(EGLDisplay dpy)
{
+ // NOTE: don't unload the drivers b/c some APIs can be called
+ // after eglTerminate() has been called. eglTerminate() only
+ // terminates an EGLDisplay, not a EGL itself.
+
egl_display_t* const dp = get_display(dpy);
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (android_atomic_dec(&dp->refs) != 1)
return EGL_TRUE;
-
+
EGLBoolean res = EGL_FALSE;
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- cnx->hooks->egl.eglTerminate(dp->dpys[i]);
-
- /* REVISIT: it's unclear what to do if eglTerminate() fails,
- * on one end we shouldn't care, on the other end if it fails
- * it might not be safe to call dlclose() (there could be some
- * threads around). */
-
- free(dp->configs[i]);
- free((void*)dp->queryString[i].extensions);
- dp->numConfigs[i] = 0;
- dp->dpys[i] = EGL_NO_DISPLAY;
- dlclose((void*)cnx->dso);
- cnx->dso = 0;
+ if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) {
+ if (cnx->hooks->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) {
+ LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy,
+ egl_strerror(cnx->hooks->egl.eglGetError()));
+ }
+ // REVISIT: it's unclear what to do if eglTerminate() fails
+ free(dp->disp[i].config);
+
+ dp->disp[i].numConfigs = 0;
+ dp->disp[i].config = 0;
+ dp->disp[i].state = egl_display_t::TERMINATED;
+
res = EGL_TRUE;
}
}
- free((void*)dp->extensionsString);
- dp->extensionsString = 0;
+
+ // TODO: all egl_object_t should be marked for termination
+
dp->numTotalConfigs = 0;
clearTLS();
return res;
@@ -762,7 +785,7 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy,
}
GLint n = 0;
for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
- for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
+ for (int i=0 ; i<dp->disp[j].numConfigs && config_size ; i++) {
*configs++ = MAKE_CONFIG(j, i);
config_size--;
n++;
@@ -819,7 +842,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
cnx->hooks->egl.eglGetConfigAttrib(
- dp->dpys[i], dp->configs[i][index],
+ dp->disp[i].dpy, dp->disp[i].config[index],
EGL_CONFIG_ID, &configId);
// and switch to the new list
@@ -834,7 +857,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
// which one.
res = cnx->hooks->egl.eglChooseConfig(
- dp->dpys[i], attrib_list, configs, config_size, &n);
+ dp->disp[i].dpy, attrib_list, configs, config_size, &n);
if (res && n>0) {
// n has to be 0 or 1, by construction, and we already know
// which config it will return (since there can be only one).
@@ -853,13 +876,14 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
if (cnx->hooks->egl.eglChooseConfig(
- dp->dpys[i], attrib_list, configs, config_size, &n)) {
+ dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
if (configs) {
// now we need to convert these client EGLConfig to our
// internal EGLConfig format. This is done in O(n log n).
for (int j=0 ; j<n ; j++) {
int index = binarySearch<EGLConfig>(
- dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
+ dp->disp[i].config, 0,
+ dp->disp[i].numConfigs-1, configs[j]);
if (index >= 0) {
if (configs) {
configs[j] = MAKE_CONFIG(i, index);
@@ -894,7 +918,7 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
return EGL_TRUE;
}
return cnx->hooks->egl.eglGetConfigAttrib(
- dp->dpys[i], dp->configs[i][index], attribute, value);
+ dp->disp[i].dpy, dp->disp[i].config[index], attribute, value);
}
// ----------------------------------------------------------------------------
@@ -909,26 +933,12 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
int i=0, index=0;
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
- // window must be connected upon calling underlying
- // eglCreateWindowSurface
- if (window) {
- window->incRef(window);
- if (window->connect)
- window->connect(window);
- }
-
EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
- dp->dpys[i], dp->configs[i][index], window, attrib_list);
+ dp->disp[i].dpy, dp->disp[i].config[index], window, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
}
-
- // something went wrong, disconnect and free window
- // (will disconnect() automatically)
- if (window) {
- window->decRef(window);
- }
}
return EGL_NO_SURFACE;
}
@@ -942,9 +952,9 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
- dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
+ dp->disp[i].dpy, dp->disp[i].config[index], pixmap, attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
}
}
@@ -959,9 +969,9 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
- dp->dpys[i], dp->configs[i][index], attrib_list);
+ dp->disp[i].dpy, dp->disp[i].config[index], attrib_list);
if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
+ egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
return s;
}
}
@@ -970,28 +980,35 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
- egl_surface_t const * const s = get_surface(surface);
+ egl_surface_t * const s = get_surface(surface);
EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
- dp->dpys[s->impl], s->surface);
-
- delete s;
+ dp->disp[s->impl].dpy, s->surface);
+ if (result == EGL_TRUE) {
+ _s.terminate();
+ }
return result;
}
EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
EGLint attribute, EGLint *value)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
return s->cnx->hooks->egl.eglQuerySurface(
- dp->dpys[s->impl], s->surface, attribute, value);
+ dp->disp[s->impl].dpy, s->surface, attribute, value);
}
// ----------------------------------------------------------------------------
@@ -1006,7 +1023,8 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
if (cnx) {
EGLContext context = cnx->hooks->egl.eglCreateContext(
- dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
+ dp->disp[i].dpy, dp->disp[i].config[index],
+ share_list, attrib_list);
if (context != EGL_NO_CONTEXT) {
egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
return c;
@@ -1017,66 +1035,125 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
{
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
if (!validate_display_context(dpy, ctx))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_context_t * const c = get_context(ctx);
EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
- dp->dpys[c->impl], c->context);
- delete c;
+ dp->disp[c->impl].dpy, c->context);
+ if (result == EGL_TRUE) {
+ _c.terminate();
+ }
return result;
}
EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
EGLSurface read, EGLContext ctx)
{
+ // get a reference to the object passed in
+ ContextRef _c(ctx);
+ SurfaceRef _d(draw);
+ SurfaceRef _r(read);
+
+ // validate the display and the context (if not EGL_NO_CONTEXT)
egl_display_t const * const dp = get_display(dpy);
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
+ // EGL_NO_CONTEXT is valid
+ return EGL_FALSE;
+ }
- if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
- ctx == EGL_NO_CONTEXT)
- {
- EGLBoolean result = EGL_TRUE;
- ctx = getContext();
- if (ctx) {
- egl_context_t * const c = get_context(ctx);
- result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
- if (result == EGL_TRUE) {
- setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
- setContext(EGL_NO_CONTEXT);
+ // these are the underlying implementation's object
+ EGLContext impl_ctx = EGL_NO_CONTEXT;
+ EGLSurface impl_draw = EGL_NO_SURFACE;
+ EGLSurface impl_read = EGL_NO_SURFACE;
+
+ // these are our objects structs passed in
+ egl_context_t * c = NULL;
+ egl_surface_t const * d = NULL;
+ egl_surface_t const * r = NULL;
+
+ // these are the current objects structs
+ egl_context_t * cur_c = get_context(getContext());
+ egl_surface_t * cur_r = NULL;
+ egl_surface_t * cur_d = NULL;
+
+ if (ctx != EGL_NO_CONTEXT) {
+ c = get_context(ctx);
+ cur_r = get_surface(c->read);
+ cur_d = get_surface(c->draw);
+ impl_ctx = c->context;
+ } else {
+ // no context given, use the implementation of the current context
+ if (cur_c == NULL) {
+ // no current context
+ if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
+ // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0);
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
+ // not an error, there is just not current context.
+ return EGL_TRUE;
}
- return result;
}
- if (!validate_display_context(dpy, ctx))
- return EGL_FALSE;
-
- EGLSurface impl_draw = EGL_NO_SURFACE;
- EGLSurface impl_read = EGL_NO_SURFACE;
- egl_context_t * const c = get_context(ctx);
+ // retrieve the underlying implementation's draw EGLSurface
if (draw != EGL_NO_SURFACE) {
- egl_surface_t const * d = get_surface(draw);
- if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (d->impl != c->impl)
+ d = get_surface(draw);
+ // make sure the EGLContext and EGLSurface passed in are for
+ // the same driver
+ if (c && d->impl != c->impl)
return setError(EGL_BAD_MATCH, EGL_FALSE);
impl_draw = d->surface;
}
+
+ // retrieve the underlying implementation's read EGLSurface
if (read != EGL_NO_SURFACE) {
- egl_surface_t const * r = get_surface(read);
- if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (r->impl != c->impl)
+ r = get_surface(read);
+ // make sure the EGLContext and EGLSurface passed in are for
+ // the same driver
+ if (c && r->impl != c->impl)
return setError(EGL_BAD_MATCH, EGL_FALSE);
impl_read = r->surface;
}
- EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
- dp->dpys[c->impl], impl_draw, impl_read, c->context);
+
+ EGLBoolean result;
+
+ if (c) {
+ result = c->cnx->hooks->egl.eglMakeCurrent(
+ dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ } else {
+ result = cur_c->cnx->hooks->egl.eglMakeCurrent(
+ dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ }
if (result == EGL_TRUE) {
- setGlThreadSpecific(c->cnx->hooks);
- setContext(ctx);
- c->read = read;
- c->draw = draw;
+ // by construction, these are either 0 or valid (possibly terminated)
+ // it should be impossible for these to be invalid
+ ContextRef _cur_c(cur_c);
+ SurfaceRef _cur_r(cur_r);
+ SurfaceRef _cur_d(cur_d);
+
+ // cur_c has to be valid here (but could be terminated)
+ if (ctx != EGL_NO_CONTEXT) {
+ setGlThreadSpecific(c->cnx->hooks);
+ setContext(ctx);
+ _c.acquire();
+ } else {
+ setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
+ setContext(EGL_NO_CONTEXT);
+ }
+ _cur_c.release();
+
+ _r.acquire();
+ _cur_r.release();
+ if (c) c->read = read;
+
+ _d.acquire();
+ _cur_d.release();
+ if (c) c->draw = draw;
}
return result;
}
@@ -1085,6 +1162,9 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
EGLint attribute, EGLint *value)
{
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
if (!validate_display_context(dpy, ctx))
return EGL_FALSE;
@@ -1092,17 +1172,23 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
egl_context_t * const c = get_context(ctx);
return c->cnx->hooks->egl.eglQueryContext(
- dp->dpys[c->impl], c->context, attribute, value);
+ dp->disp[c->impl].dpy, c->context, attribute, value);
}
EGLContext eglGetCurrentContext(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_CONTEXT.
+
EGLContext ctx = getContext();
return ctx;
}
EGLSurface eglGetCurrentSurface(EGLint readdraw)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_SURFACE.
+
EGLContext ctx = getContext();
if (ctx) {
egl_context_t const * const c = get_context(ctx);
@@ -1118,6 +1204,9 @@ EGLSurface eglGetCurrentSurface(EGLint readdraw)
EGLDisplay eglGetCurrentDisplay(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_DISPLAY.
+
EGLContext ctx = getContext();
if (ctx) {
egl_context_t const * const c = get_context(ctx);
@@ -1129,6 +1218,9 @@ EGLDisplay eglGetCurrentDisplay(void)
EGLBoolean eglWaitGL(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
+
EGLBoolean res = EGL_TRUE;
EGLContext ctx = getContext();
if (ctx) {
@@ -1146,6 +1238,9 @@ EGLBoolean eglWaitGL(void)
EGLBoolean eglWaitNative(EGLint engine)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
+
EGLBoolean res = EGL_TRUE;
EGLContext ctx = getContext();
if (ctx) {
@@ -1182,9 +1277,11 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
// eglGetProcAddress() could be the very first function called
// in which case we must make sure we've initialized ourselves, this
// happens the first time egl_get_display() is called.
-
- if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
- return NULL;
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ setError(EGL_BAD_PARAMETER, NULL);
+ return NULL;
+ }
__eglMustCastToProperFunctionPointerType addr;
addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
@@ -1243,22 +1340,28 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
+ SurfaceRef _s(draw);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, draw))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(draw);
- return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
+ return s->cnx->hooks->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
}
EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
NativePixmapType target)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
return s->cnx->hooks->egl.eglCopyBuffers(
- dp->dpys[s->impl], s->surface, target);
+ dp->disp[s->impl].dpy, s->surface, target);
}
const char* eglQueryString(EGLDisplay dpy, EGLint name)
@@ -1285,13 +1388,16 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name)
EGLBoolean eglSurfaceAttrib(
EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->hooks->egl.eglSurfaceAttrib) {
return s->cnx->hooks->egl.eglSurfaceAttrib(
- dp->dpys[s->impl], s->surface, attribute, value);
+ dp->disp[s->impl].dpy, s->surface, attribute, value);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1299,13 +1405,16 @@ EGLBoolean eglSurfaceAttrib(
EGLBoolean eglBindTexImage(
EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->hooks->egl.eglBindTexImage) {
return s->cnx->hooks->egl.eglBindTexImage(
- dp->dpys[s->impl], s->surface, buffer);
+ dp->disp[s->impl].dpy, s->surface, buffer);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1313,13 +1422,16 @@ EGLBoolean eglBindTexImage(
EGLBoolean eglReleaseTexImage(
EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
if (!validate_display_surface(dpy, surface))
return EGL_FALSE;
egl_display_t const * const dp = get_display(dpy);
egl_surface_t const * const s = get_surface(surface);
if (s->cnx->hooks->egl.eglReleaseTexImage) {
return s->cnx->hooks->egl.eglReleaseTexImage(
- dp->dpys[s->impl], s->surface, buffer);
+ dp->disp[s->impl].dpy, s->surface, buffer);
}
return setError(EGL_BAD_SURFACE, EGL_FALSE);
}
@@ -1334,7 +1446,8 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
if (cnx->hooks->egl.eglSwapInterval) {
- if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
+ if (cnx->hooks->egl.eglSwapInterval(
+ dp->disp[i].dpy, interval) == EGL_FALSE) {
res = EGL_FALSE;
}
}
@@ -1350,6 +1463,8 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
EGLBoolean eglWaitClient(void)
{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
EGLBoolean res = EGL_TRUE;
EGLContext ctx = getContext();
if (ctx) {
@@ -1371,6 +1486,10 @@ EGLBoolean eglWaitClient(void)
EGLBoolean eglBindAPI(EGLenum api)
{
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
// bind this API on all EGLs
EGLBoolean res = EGL_TRUE;
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
@@ -1388,6 +1507,10 @@ EGLBoolean eglBindAPI(EGLenum api)
EGLenum eglQueryAPI(void)
{
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso) {
@@ -1426,7 +1549,172 @@ EGLSurface eglCreatePbufferFromClientBuffer(
if (!cnx) return EGL_FALSE;
if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
- dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
+ dp->disp[i].dpy, buftype, buffer,
+ dp->disp[i].config[index], attrib_list);
}
return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
}
+
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 3
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
+ const EGLint *attrib_list)
+{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ if (!validate_display_surface(dpy, surface))
+ return EGL_FALSE;
+
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(surface);
+
+ if (s->cnx->hooks->egl.eglLockSurfaceKHR) {
+ return s->cnx->hooks->egl.eglLockSurfaceKHR(
+ dp->disp[s->impl].dpy, s->surface, attrib_list);
+ }
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+}
+
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+{
+ SurfaceRef _s(surface);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ if (!validate_display_surface(dpy, surface))
+ return EGL_FALSE;
+
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(surface);
+
+ if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) {
+ return s->cnx->hooks->egl.eglUnlockSurfaceKHR(
+ dp->disp[s->impl].dpy, s->surface);
+ }
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint *attrib_list)
+{
+ if (ctx != EGL_NO_CONTEXT) {
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
+ if (!validate_display_context(dpy, ctx))
+ return EGL_NO_IMAGE_KHR;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_context_t * const c = get_context(ctx);
+ // since we have an EGLContext, we know which implementation to use
+ EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR(
+ dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
+ if (image == EGL_NO_IMAGE_KHR)
+ return image;
+
+ egl_image_t* result = new egl_image_t(dpy, ctx);
+ result->images[c->impl] = image;
+ return (EGLImageKHR)result;
+ } else {
+ // EGL_NO_CONTEXT is a valid parameter
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
+ }
+ // since we don't have a way to know which implementation to call,
+ // we're calling all of them
+
+ EGLImageKHR implImages[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
+ bool success = false;
+ for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ implImages[i] = EGL_NO_IMAGE_KHR;
+ if (cnx->dso) {
+ if (cnx->hooks->egl.eglCreateImageKHR) {
+ implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
+ dp->disp[i].dpy, ctx, target, buffer, attrib_list);
+ if (implImages[i] != EGL_NO_IMAGE_KHR) {
+ success = true;
+ }
+ }
+ }
+ }
+ if (!success)
+ return EGL_NO_IMAGE_KHR;
+
+ egl_image_t* result = new egl_image_t(dpy, ctx);
+ memcpy(result->images, implImages, sizeof(implImages));
+ return (EGLImageKHR)result;
+ }
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
+{
+ egl_display_t const * const dp = get_display(dpy);
+ if (dp == 0) {
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ ImageRef _i(img);
+ if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ egl_image_t* image = get_image(img);
+ bool success = false;
+ for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (image->images[i] != EGL_NO_IMAGE_KHR) {
+ if (cnx->dso) {
+ if (cnx->hooks->egl.eglCreateImageKHR) {
+ if (cnx->hooks->egl.eglDestroyImageKHR(
+ dp->disp[i].dpy, image->images[i])) {
+ success = true;
+ }
+ }
+ }
+ }
+ }
+ if (!success)
+ return EGL_FALSE;
+
+ _i.terminate();
+
+ return EGL_TRUE;
+}
+
+
+// ----------------------------------------------------------------------------
+// ANDROID extensions
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+ EGLint left, EGLint top, EGLint width, EGLint height)
+{
+ SurfaceRef _s(draw);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ if (!validate_display_surface(dpy, draw))
+ return EGL_FALSE;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(draw);
+ if (s->cnx->hooks->egl.eglSetSwapRectangleANDROID) {
+ return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(
+ dp->disp[s->impl].dpy, s->surface, left, top, width, height);
+ }
+ return setError(EGL_BAD_DISPLAY, NULL);
+}
+
+EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
+{
+ SurfaceRef _s(draw);
+ if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0);
+
+ if (!validate_display_surface(dpy, draw))
+ return 0;
+ egl_display_t const * const dp = get_display(dpy);
+ egl_surface_t const * const s = get_surface(draw);
+ if (s->cnx->hooks->egl.eglGetRenderBufferANDROID) {
+ return s->cnx->hooks->egl.eglGetRenderBufferANDROID(
+ dp->disp[s->impl].dpy, s->surface);
+ }
+ return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
+}
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
new file mode 100644
index 0000000..5d89287
--- /dev/null
+++ b/opengl/libs/EGL/egl_entries.in
@@ -0,0 +1,57 @@
+EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType)
+EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
+EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
+EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)
+EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)
+
+EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint *)
+EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint *)
+EGL_ENTRY(EGLSurface, eglCreatePbufferSurface, EGLDisplay, EGLConfig, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLBoolean, eglQuerySurface, EGLDisplay, EGLSurface, EGLint, EGLint *)
+EGL_ENTRY(EGLContext, eglCreateContext, EGLDisplay, EGLConfig, EGLContext, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroyContext, EGLDisplay, EGLContext)
+EGL_ENTRY(EGLBoolean, eglMakeCurrent, EGLDisplay, EGLSurface, EGLSurface, EGLContext)
+EGL_ENTRY(EGLContext, eglGetCurrentContext, void)
+EGL_ENTRY(EGLSurface, eglGetCurrentSurface, EGLint)
+EGL_ENTRY(EGLDisplay, eglGetCurrentDisplay, void)
+EGL_ENTRY(EGLBoolean, eglQueryContext, EGLDisplay, EGLContext, EGLint, EGLint *)
+EGL_ENTRY(EGLBoolean, eglWaitGL, void)
+EGL_ENTRY(EGLBoolean, eglWaitNative, EGLint)
+EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType)
+EGL_ENTRY(EGLint, eglGetError, void)
+EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint)
+EGL_ENTRY(__eglMustCastToProperFunctionPointerType, eglGetProcAddress, const char *)
+
+/* EGL 1.1 */
+
+EGL_ENTRY(EGLBoolean, eglSurfaceAttrib, EGLDisplay, EGLSurface, EGLint, EGLint)
+EGL_ENTRY(EGLBoolean, eglBindTexImage, EGLDisplay, EGLSurface, EGLint)
+EGL_ENTRY(EGLBoolean, eglReleaseTexImage, EGLDisplay, EGLSurface, EGLint)
+EGL_ENTRY(EGLBoolean, eglSwapInterval, EGLDisplay, EGLint)
+
+/* EGL 1.2 */
+
+EGL_ENTRY(EGLBoolean, eglBindAPI, EGLenum)
+EGL_ENTRY(EGLenum, eglQueryAPI, void)
+EGL_ENTRY(EGLBoolean, eglWaitClient, void)
+EGL_ENTRY(EGLBoolean, eglReleaseThread, void)
+EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint *)
+
+/* EGL 1.3 */
+
+/* EGL 1.4 */
+
+/* EGL_EGLEXT_VERSION 3 */
+
+EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglUnlockSurfaceKHR, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *)
+EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR)
+
+/* ANDROID extensions */
+
+EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint)
+EGL_ENTRY(EGLClientBuffer, eglGetRenderBufferANDROID, EGLDisplay, EGLSurface)
diff --git a/opengl/libs/EGL/gpu.cpp b/opengl/libs/EGL/gpu.cpp
deleted file mode 100644
index 4c902c8..0000000
--- a/opengl/libs/EGL/gpu.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- ** 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.
- */
-
-#define LOG_TAG "EGL"
-
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/ioctl.h>
-
-#if HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
-
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
-#include <utils/IMemory.h>
-#include <utils/threads.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/Parcel.h>
-
-#include <ui/EGLDisplaySurface.h>
-#include <ui/ISurfaceComposer.h>
-
-#include "hooks.h"
-#include "egl_impl.h"
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-/*
- * we provide our own allocators for the GPU regions, these
- * allocators go through surfaceflinger
- */
-
-static Mutex gRegionsLock;
-static request_gpu_t gRegions;
-static sp<ISurfaceComposer> gSurfaceManager;
-GL_API ISurfaceComposer* GLES_localSurfaceManager = 0;
-
-extern egl_connection_t gEGLImpl[2];
-
-const sp<ISurfaceComposer>& getSurfaceFlinger()
-{
- Mutex::Autolock _l(gRegionsLock);
-
- /*
- * There is a little bit of voodoo magic here. We want to access
- * surfaceflinger for allocating GPU regions, however, when we are
- * running as part of surfaceflinger, we want to bypass the
- * service manager because surfaceflinger might not be registered yet.
- * SurfaceFlinger will populate "GLES_localSurfaceManager" with its
- * own address, so we can just use that.
- */
- if (gSurfaceManager == 0) {
- if (GLES_localSurfaceManager) {
- // we're running in SurfaceFlinger's context
- gSurfaceManager = GLES_localSurfaceManager;
- } else {
- // we're a remote process or not part of surfaceflinger,
- // go through the service manager
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm != NULL) {
- sp<IBinder> binder = sm->getService(String16("SurfaceFlinger"));
- gSurfaceManager = interface_cast<ISurfaceComposer>(binder);
- }
- }
- }
- return gSurfaceManager;
-}
-
-class GPURevokeRequester : public BnGPUCallback
-{
-public:
- virtual void gpuLost() {
- LOGD("CONTEXT_LOST: Releasing GPU upon request from SurfaceFlinger.");
- gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
- }
-};
-
-static sp<GPURevokeRequester> gRevokerCallback;
-
-
-request_gpu_t* gpu_acquire(void* user)
-{
- sp<ISurfaceComposer> server( getSurfaceFlinger() );
-
- Mutex::Autolock _l(gRegionsLock);
- if (server == NULL) {
- return 0;
- }
-
- ISurfaceComposer::gpu_info_t info;
-
- if (gRevokerCallback == 0)
- gRevokerCallback = new GPURevokeRequester();
-
- status_t err = server->requestGPU(gRevokerCallback, &info);
- if (err != NO_ERROR) {
- LOGD("requestGPU returned %d", err);
- return 0;
- }
-
- if (info.regs == 0) {
- LOGD("requestGPU() failed");
- return 0;
- }
-
- bool failed = false;
- request_gpu_t* gpu = &gRegions;
- memset(gpu, 0, sizeof(*gpu));
-
- if (info.regs != 0) {
- sp<IMemoryHeap> heap(info.regs->getMemory());
- if (heap != 0) {
- int fd = heap->heapID();
- gpu->regs.fd = fd;
- gpu->regs.base = info.regs->pointer();
- gpu->regs.size = info.regs->size();
- gpu->regs.user = info.regs.get();
-#if HAVE_ANDROID_OS
- struct pmem_region region;
- if (ioctl(fd, PMEM_GET_PHYS, &region) >= 0)
- gpu->regs.phys = (void*)region.offset;
-#endif
- info.regs->incStrong(gpu);
- } else {
- LOGE("GPU register handle %p is invalid!", info.regs.get());
- failed = true;
- }
- }
-
- for (size_t i=0 ; i<info.count && !failed ; i++) {
- sp<IMemory>& region(info.regions[i].region);
- if (region != 0) {
- sp<IMemoryHeap> heap(region->getMemory());
- if (heap != 0) {
- const int fd = heap->heapID();
- gpu->gpu[i].fd = fd;
- gpu->gpu[i].base = region->pointer();
- gpu->gpu[i].size = region->size();
- gpu->gpu[i].user = region.get();
- gpu->gpu[i].offset = info.regions[i].reserved;
-#if HAVE_ANDROID_OS
- struct pmem_region reg;
- if (ioctl(fd, PMEM_GET_PHYS, &reg) >= 0)
- gpu->gpu[i].phys = (void*)reg.offset;
-#endif
- region->incStrong(gpu);
- } else {
- LOGE("GPU region handle [%d, %p] is invalid!", i, region.get());
- failed = true;
- }
- }
- }
-
- if (failed) {
- // something went wrong, clean up everything!
- if (gpu->regs.user) {
- static_cast<IMemory*>(gpu->regs.user)->decStrong(gpu);
- for (size_t i=0 ; i<info.count ; i++) {
- if (gpu->gpu[i].user) {
- static_cast<IMemory*>(gpu->gpu[i].user)->decStrong(gpu);
- }
- }
- }
- }
-
- gpu->count = info.count;
- return gpu;
-}
-
-int gpu_release(void*, request_gpu_t* gpu)
-{
- sp<IMemory> regs;
-
- { // scope for lock
- Mutex::Autolock _l(gRegionsLock);
- regs = static_cast<IMemory*>(gpu->regs.user);
- gpu->regs.user = 0;
- if (regs != 0) regs->decStrong(gpu);
-
- for (int i=0 ; i<gpu->count ; i++) {
- sp<IMemory> r(static_cast<IMemory*>(gpu->gpu[i].user));
- gpu->gpu[i].user = 0;
- if (r != 0) r->decStrong(gpu);
- }
- }
-
- // there is a special transaction to relinquish the GPU
- // (it will happen automatically anyway if we don't do this)
- Parcel data, reply;
- // NOTE: this transaction does not require an interface token
- regs->asBinder()->transact(1000, data, &reply);
- return 1;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/hooks.cpp b/opengl/libs/EGL/hooks.cpp
new file mode 100644
index 0000000..2246366
--- /dev/null
+++ b/opengl/libs/EGL/hooks.cpp
@@ -0,0 +1,67 @@
+/*
+ ** 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.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+void gl_unimplemented() {
+ LOGE("called unimplemented OpenGL ES API");
+}
+
+
+// ----------------------------------------------------------------------------
+// GL / EGL hooks
+// ----------------------------------------------------------------------------
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+#define GL_ENTRY(_r, _api, ...) #_api,
+#define EGL_ENTRY(_r, _api, ...) #_api,
+
+char const * const gl_names[] = {
+ #include "GLES_CM/gl_entries.in"
+ #include "GLES_CM/glext_entries.in"
+ NULL
+};
+
+char const * const gl2_names[] = {
+ #include "GLES2/gl2_entries.in"
+ #include "GLES2/gl2ext_entries.in"
+ NULL
+};
+
+char const * const egl_names[] = {
+ #include "egl_entries.in"
+ NULL
+};
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
new file mode 100644
index 0000000..e5358c3
--- /dev/null
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -0,0 +1,111 @@
+/*
+ ** 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.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "hooks.h"
+#include "egl_impl.h"
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// Actual GL entry-points
+// ----------------------------------------------------------------------------
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
+#if USE_FAST_TLS_KEY
+
+ #define API_ENTRY(_api) __attribute__((naked)) _api
+
+ #define CALL_GL_API(_api, ...) \
+ asm volatile( \
+ "mov r12, #0xFFFF0FFF \n" \
+ "ldr r12, [r12, #-15] \n" \
+ "ldr r12, [r12, %[tls]] \n" \
+ "cmp r12, #0 \n" \
+ "ldrne pc, [r12, %[api]] \n" \
+ "bx lr \n" \
+ : \
+ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
+ [api] "J"(__builtin_offsetof(gl_hooks_t, gl2._api)) \
+ : \
+ );
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ CALL_GL_API(_api, __VA_ARGS__) \
+ return 0; // placate gcc's warnings. never reached.
+
+#else
+
+ #define API_ENTRY(_api) _api
+
+ #define CALL_GL_API(_api, ...) \
+ gl_hooks_t::gl2_t const * const _c = &getGlThreadSpecific()->gl2; \
+ _c->_api(__VA_ARGS__)
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ gl_hooks_t::gl2_t const * const _c = &getGlThreadSpecific()->gl2; \
+ return _c->_api(__VA_ARGS__)
+
+#endif
+
+
+extern "C" {
+#include "gl2_api.in"
+#include "gl2ext_api.in"
+}
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
+
+/*
+ * These GL calls are special because they need to EGL to retrieve some
+ * informations before they can execute.
+ */
+
+extern "C" void __glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
+extern "C" void __glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
+
+
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
+{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetTexture2DOES(target, implImage);
+}
+
+void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
+{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetRenderbufferStorageOES(target, image);
+}
+
diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in
new file mode 100644
index 0000000..9c2e69a
--- /dev/null
+++ b/opengl/libs/GLES2/gl2_api.in
@@ -0,0 +1,426 @@
+void API_ENTRY(glActiveTexture)(GLenum texture) {
+ CALL_GL_API(glActiveTexture, texture);
+}
+void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) {
+ CALL_GL_API(glAttachShader, program, shader);
+}
+void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const char* name) {
+ CALL_GL_API(glBindAttribLocation, program, index, name);
+}
+void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
+ CALL_GL_API(glBindBuffer, target, buffer);
+}
+void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer) {
+ CALL_GL_API(glBindFramebuffer, target, framebuffer);
+}
+void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer) {
+ CALL_GL_API(glBindRenderbuffer, target, renderbuffer);
+}
+void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
+ CALL_GL_API(glBindTexture, target, texture);
+}
+void API_ENTRY(glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ CALL_GL_API(glBlendColor, red, green, blue, alpha);
+}
+void API_ENTRY(glBlendEquation)( GLenum mode ) {
+ CALL_GL_API(glBlendEquation, mode);
+}
+void API_ENTRY(glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha) {
+ CALL_GL_API(glBlendEquationSeparate, modeRGB, modeAlpha);
+}
+void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
+ CALL_GL_API(glBlendFunc, sfactor, dfactor);
+}
+void API_ENTRY(glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
+ CALL_GL_API(glBlendFuncSeparate, srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
+ CALL_GL_API(glBufferData, target, size, data, usage);
+}
+void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
+ CALL_GL_API(glBufferSubData, target, offset, size, data);
+}
+GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) {
+ CALL_GL_API_RETURN(glCheckFramebufferStatus, target);
+}
+void API_ENTRY(glClear)(GLbitfield mask) {
+ CALL_GL_API(glClear, mask);
+}
+void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ CALL_GL_API(glClearColor, red, green, blue, alpha);
+}
+void API_ENTRY(glClearDepthf)(GLclampf depth) {
+ CALL_GL_API(glClearDepthf, depth);
+}
+void API_ENTRY(glClearStencil)(GLint s) {
+ CALL_GL_API(glClearStencil, s);
+}
+void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+ CALL_GL_API(glColorMask, red, green, blue, alpha);
+}
+void API_ENTRY(glCompileShader)(GLuint shader) {
+ CALL_GL_API(glCompileShader, shader);
+}
+void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);
+}
+void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
+ CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border);
+}
+void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height);
+}
+GLuint API_ENTRY(glCreateProgram)(void) {
+ CALL_GL_API_RETURN(glCreateProgram);
+}
+GLuint API_ENTRY(glCreateShader)(GLenum type) {
+ CALL_GL_API_RETURN(glCreateShader, type);
+}
+void API_ENTRY(glCullFace)(GLenum mode) {
+ CALL_GL_API(glCullFace, mode);
+}
+void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint* buffers) {
+ CALL_GL_API(glDeleteBuffers, n, buffers);
+}
+void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers) {
+ CALL_GL_API(glDeleteFramebuffers, n, framebuffers);
+}
+void API_ENTRY(glDeleteProgram)(GLuint program) {
+ CALL_GL_API(glDeleteProgram, program);
+}
+void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers) {
+ CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers);
+}
+void API_ENTRY(glDeleteShader)(GLuint shader) {
+ CALL_GL_API(glDeleteShader, shader);
+}
+void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint* textures) {
+ CALL_GL_API(glDeleteTextures, n, textures);
+}
+void API_ENTRY(glDepthFunc)(GLenum func) {
+ CALL_GL_API(glDepthFunc, func);
+}
+void API_ENTRY(glDepthMask)(GLboolean flag) {
+ CALL_GL_API(glDepthMask, flag);
+}
+void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
+ CALL_GL_API(glDepthRangef, zNear, zFar);
+}
+void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) {
+ CALL_GL_API(glDetachShader, program, shader);
+}
+void API_ENTRY(glDisable)(GLenum cap) {
+ CALL_GL_API(glDisable, cap);
+}
+void API_ENTRY(glDisableVertexAttribArray)(GLuint index) {
+ CALL_GL_API(glDisableVertexAttribArray, index);
+}
+void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
+ CALL_GL_API(glDrawArrays, mode, first, count);
+}
+void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void* indices) {
+ CALL_GL_API(glDrawElements, mode, count, type, indices);
+}
+void API_ENTRY(glEnable)(GLenum cap) {
+ CALL_GL_API(glEnable, cap);
+}
+void API_ENTRY(glEnableVertexAttribArray)(GLuint index) {
+ CALL_GL_API(glEnableVertexAttribArray, index);
+}
+void API_ENTRY(glFinish)(void) {
+ CALL_GL_API(glFinish);
+}
+void API_ENTRY(glFlush)(void) {
+ CALL_GL_API(glFlush);
+}
+void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
+ CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer);
+}
+void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
+ CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level);
+}
+void API_ENTRY(glFrontFace)(GLenum mode) {
+ CALL_GL_API(glFrontFace, mode);
+}
+void API_ENTRY(glGenBuffers)(GLsizei n, GLuint* buffers) {
+ CALL_GL_API(glGenBuffers, n, buffers);
+}
+void API_ENTRY(glGenerateMipmap)(GLenum target) {
+ CALL_GL_API(glGenerateMipmap, target);
+}
+void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint* framebuffers) {
+ CALL_GL_API(glGenFramebuffers, n, framebuffers);
+}
+void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers) {
+ CALL_GL_API(glGenRenderbuffers, n, renderbuffers);
+}
+void API_ENTRY(glGenTextures)(GLsizei n, GLuint* textures) {
+ CALL_GL_API(glGenTextures, n, textures);
+}
+void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) {
+ CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name);
+}
+void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) {
+ CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name);
+}
+void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
+ CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders);
+}
+int API_ENTRY(glGetAttribLocation)(GLuint program, const char* name) {
+ CALL_GL_API_RETURN(glGetAttribLocation, program, name);
+}
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params) {
+ CALL_GL_API(glGetBooleanv, pname, params);
+}
+void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetBufferParameteriv, target, pname, params);
+}
+GLenum API_ENTRY(glGetError)(void) {
+ CALL_GL_API_RETURN(glGetError);
+}
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat* params) {
+ CALL_GL_API(glGetFloatv, pname, params);
+}
+void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
+}
+void API_ENTRY(glGetIntegerv)(GLenum pname, GLint* params) {
+ CALL_GL_API(glGetIntegerv, pname, params);
+}
+void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetProgramiv, program, pname, params);
+}
+void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) {
+ CALL_GL_API(glGetProgramInfoLog, program, bufsize, length, infolog);
+}
+void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetShaderiv)(GLuint shader, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetShaderiv, shader, pname, params);
+}
+void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) {
+ CALL_GL_API(glGetShaderInfoLog, shader, bufsize, length, infolog);
+}
+void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+ CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision);
+}
+void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, char* source) {
+ CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
+}
+const GLubyte* API_ENTRY(glGetString)(GLenum name) {
+ CALL_GL_API_RETURN(glGetString, name);
+}
+void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) {
+ CALL_GL_API(glGetTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetTexParameteriv, target, pname, params);
+}
+void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params) {
+ CALL_GL_API(glGetUniformfv, program, location, params);
+}
+void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params) {
+ CALL_GL_API(glGetUniformiv, program, location, params);
+}
+int API_ENTRY(glGetUniformLocation)(GLuint program, const char* name) {
+ CALL_GL_API_RETURN(glGetUniformLocation, program, name);
+}
+void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params) {
+ CALL_GL_API(glGetVertexAttribfv, index, pname, params);
+}
+void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params) {
+ CALL_GL_API(glGetVertexAttribiv, index, pname, params);
+}
+void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, void** pointer) {
+ CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer);
+}
+void API_ENTRY(glHint)(GLenum target, GLenum mode) {
+ CALL_GL_API(glHint, target, mode);
+}
+GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
+ CALL_GL_API_RETURN(glIsBuffer, buffer);
+}
+GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
+ CALL_GL_API_RETURN(glIsEnabled, cap);
+}
+GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer) {
+ CALL_GL_API_RETURN(glIsFramebuffer, framebuffer);
+}
+GLboolean API_ENTRY(glIsProgram)(GLuint program) {
+ CALL_GL_API_RETURN(glIsProgram, program);
+}
+GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer) {
+ CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer);
+}
+GLboolean API_ENTRY(glIsShader)(GLuint shader) {
+ CALL_GL_API_RETURN(glIsShader, shader);
+}
+GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
+ CALL_GL_API_RETURN(glIsTexture, texture);
+}
+void API_ENTRY(glLineWidth)(GLfloat width) {
+ CALL_GL_API(glLineWidth, width);
+}
+void API_ENTRY(glLinkProgram)(GLuint program) {
+ CALL_GL_API(glLinkProgram, program);
+}
+void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
+ CALL_GL_API(glPixelStorei, pname, param);
+}
+void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
+ CALL_GL_API(glPolygonOffset, factor, units);
+}
+void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
+ CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
+}
+void API_ENTRY(glReleaseShaderCompiler)(void) {
+ CALL_GL_API(glReleaseShaderCompiler);
+}
+void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height);
+}
+void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
+ CALL_GL_API(glSampleCoverage, value, invert);
+}
+void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glScissor, x, y, width, height);
+}
+void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length) {
+ CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length);
+}
+void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const char** string, const GLint* length) {
+ CALL_GL_API(glShaderSource, shader, count, string, length);
+}
+void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
+ CALL_GL_API(glStencilFunc, func, ref, mask);
+}
+void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) {
+ CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask);
+}
+void API_ENTRY(glStencilMask)(GLuint mask) {
+ CALL_GL_API(glStencilMask, mask);
+}
+void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask) {
+ CALL_GL_API(glStencilMaskSeparate, face, mask);
+}
+void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
+ CALL_GL_API(glStencilOp, fail, zfail, zpass);
+}
+void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
+ CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass);
+}
+void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) {
+ CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels);
+}
+void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
+ CALL_GL_API(glTexParameterf, target, pname, param);
+}
+void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params) {
+ CALL_GL_API(glTexParameterfv, target, pname, params);
+}
+void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
+ CALL_GL_API(glTexParameteri, target, pname, param);
+}
+void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params) {
+ CALL_GL_API(glTexParameteriv, target, pname, params);
+}
+void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) {
+ CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+void API_ENTRY(glUniform1f)(GLint location, GLfloat x) {
+ CALL_GL_API(glUniform1f, location, x);
+}
+void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform1fv, location, count, v);
+}
+void API_ENTRY(glUniform1i)(GLint location, GLint x) {
+ CALL_GL_API(glUniform1i, location, x);
+}
+void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform1iv, location, count, v);
+}
+void API_ENTRY(glUniform2f)(GLint location, GLfloat x, GLfloat y) {
+ CALL_GL_API(glUniform2f, location, x, y);
+}
+void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform2fv, location, count, v);
+}
+void API_ENTRY(glUniform2i)(GLint location, GLint x, GLint y) {
+ CALL_GL_API(glUniform2i, location, x, y);
+}
+void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform2iv, location, count, v);
+}
+void API_ENTRY(glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glUniform3f, location, x, y, z);
+}
+void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform3fv, location, count, v);
+}
+void API_ENTRY(glUniform3i)(GLint location, GLint x, GLint y, GLint z) {
+ CALL_GL_API(glUniform3i, location, x, y, z);
+}
+void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform3iv, location, count, v);
+}
+void API_ENTRY(glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ CALL_GL_API(glUniform4f, location, x, y, z, w);
+}
+void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat* v) {
+ CALL_GL_API(glUniform4fv, location, count, v);
+}
+void API_ENTRY(glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w) {
+ CALL_GL_API(glUniform4i, location, x, y, z, w);
+}
+void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint* v) {
+ CALL_GL_API(glUniform4iv, location, count, v);
+}
+void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value);
+}
+void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value);
+}
+void API_ENTRY(glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ CALL_GL_API(glUniformMatrix4fv, location, count, transpose, value);
+}
+void API_ENTRY(glUseProgram)(GLuint program) {
+ CALL_GL_API(glUseProgram, program);
+}
+void API_ENTRY(glValidateProgram)(GLuint program) {
+ CALL_GL_API(glValidateProgram, program);
+}
+void API_ENTRY(glVertexAttrib1f)(GLuint indx, GLfloat x) {
+ CALL_GL_API(glVertexAttrib1f, indx, x);
+}
+void API_ENTRY(glVertexAttrib1fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib1fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y) {
+ CALL_GL_API(glVertexAttrib2f, indx, x, y);
+}
+void API_ENTRY(glVertexAttrib2fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib2fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glVertexAttrib3f, indx, x, y, z);
+}
+void API_ENTRY(glVertexAttrib3fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib3fv, indx, values);
+}
+void API_ENTRY(glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ CALL_GL_API(glVertexAttrib4f, indx, x, y, z, w);
+}
+void API_ENTRY(glVertexAttrib4fv)(GLuint indx, const GLfloat* values) {
+ CALL_GL_API(glVertexAttrib4fv, indx, values);
+}
+void API_ENTRY(glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr) {
+ CALL_GL_API(glVertexAttribPointer, indx, size, type, normalized, stride, ptr);
+}
+void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glViewport, x, y, width, height);
+}
diff --git a/opengl/libs/GLES2/gl2_entries.in b/opengl/libs/GLES2/gl2_entries.in
new file mode 100644
index 0000000..6a41b94
--- /dev/null
+++ b/opengl/libs/GLES2/gl2_entries.in
@@ -0,0 +1,142 @@
+GL_ENTRY(void, glActiveTexture, GLenum texture)
+GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader)
+GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const char* name)
+GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
+GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
+GL_ENTRY(void, glBlendColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glBlendEquation, GLenum mode )
+GL_ENTRY(void, glBlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glBlendFuncSeparate, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const void* data, GLenum usage)
+GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void* data)
+GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+GL_ENTRY(void, glClearDepthf, GLclampf depth)
+GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+GL_ENTRY(void, glCompileShader, GLuint shader)
+GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
+GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(GLuint, glCreateProgram, void)
+GL_ENTRY(GLuint, glCreateShader, GLenum type)
+GL_ENTRY(void, glCullFace, GLenum mode)
+GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint* buffers)
+GL_ENTRY(void, glDeleteFramebuffers, GLsizei n, const GLuint* framebuffers)
+GL_ENTRY(void, glDeleteProgram, GLuint program)
+GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint* renderbuffers)
+GL_ENTRY(void, glDeleteShader, GLuint shader)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint* textures)
+GL_ENTRY(void, glDepthFunc, GLenum func)
+GL_ENTRY(void, glDepthMask, GLboolean flag)
+GL_ENTRY(void, glDepthRangef, GLclampf zNear, GLclampf zFar)
+GL_ENTRY(void, glDetachShader, GLuint program, GLuint shader)
+GL_ENTRY(void, glDisable, GLenum cap)
+GL_ENTRY(void, glDisableVertexAttribArray, GLuint index)
+GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const void* indices)
+GL_ENTRY(void, glEnable, GLenum cap)
+GL_ENTRY(void, glEnableVertexAttribArray, GLuint index)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFrontFace, GLenum mode)
+GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint* buffers)
+GL_ENTRY(void, glGenerateMipmap, GLenum target)
+GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint* framebuffers)
+GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint* renderbuffers)
+GL_ENTRY(void, glGenTextures, GLsizei n, GLuint* textures)
+GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+GL_ENTRY(void, glGetAttachedShaders, GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+GL_ENTRY(int, glGetAttribLocation, GLuint program, const char* name)
+GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean* params)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
+GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetShaderiv, GLuint shader, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+GL_ENTRY(const GLubyte*, glGetString, GLenum name)
+GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat* params)
+GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint* params)
+GL_ENTRY(int, glGetUniformLocation, GLuint program, const char* name)
+GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params)
+GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, void** pointer)
+GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
+GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer)
+GL_ENTRY(GLboolean, glIsProgram, GLuint program)
+GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer)
+GL_ENTRY(GLboolean, glIsShader, GLuint shader)
+GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLinkProgram, GLuint program)
+GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
+GL_ENTRY(void, glReleaseShaderCompiler, void)
+GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glSampleCoverage, GLclampf value, GLboolean invert)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glShaderBinary, GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length)
+GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const char** string, const GLint* length)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilFuncSeparate, GLenum face, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilMask, GLuint mask)
+GL_ENTRY(void, glStencilMaskSeparate, GLenum face, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glStencilOpSeparate, GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat* params)
+GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint* params)
+GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels)
+GL_ENTRY(void, glUniform1f, GLint location, GLfloat x)
+GL_ENTRY(void, glUniform1fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform1i, GLint location, GLint x)
+GL_ENTRY(void, glUniform1iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform2f, GLint location, GLfloat x, GLfloat y)
+GL_ENTRY(void, glUniform2fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform2i, GLint location, GLint x, GLint y)
+GL_ENTRY(void, glUniform2iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform3f, GLint location, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glUniform3fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform3i, GLint location, GLint x, GLint y, GLint z)
+GL_ENTRY(void, glUniform3iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniform4f, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glUniform4fv, GLint location, GLsizei count, const GLfloat* v)
+GL_ENTRY(void, glUniform4i, GLint location, GLint x, GLint y, GLint z, GLint w)
+GL_ENTRY(void, glUniform4iv, GLint location, GLsizei count, const GLint* v)
+GL_ENTRY(void, glUniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+GL_ENTRY(void, glUseProgram, GLuint program)
+GL_ENTRY(void, glValidateProgram, GLuint program)
+GL_ENTRY(void, glVertexAttrib1f, GLuint indx, GLfloat x)
+GL_ENTRY(void, glVertexAttrib1fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib2f, GLuint indx, GLfloat x, GLfloat y)
+GL_ENTRY(void, glVertexAttrib2fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib3f, GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glVertexAttrib3fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttrib4f, GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glVertexAttrib4fv, GLuint indx, const GLfloat* values)
+GL_ENTRY(void, glVertexAttribPointer, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
+GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
diff --git a/opengl/libs/GLES2/gl2ext_api.in b/opengl/libs/GLES2/gl2ext_api.in
new file mode 100644
index 0000000..6eeecb3
--- /dev/null
+++ b/opengl/libs/GLES2/gl2ext_api.in
@@ -0,0 +1,105 @@
+void API_ENTRY(__glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) {
+ CALL_GL_API(glEGLImageTargetTexture2DOES, target, image);
+}
+void API_ENTRY(__glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) {
+ CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image);
+}
+void API_ENTRY(glGetProgramBinaryOES)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) {
+ CALL_GL_API(glGetProgramBinaryOES, program, bufSize, length, binaryFormat, binary);
+}
+void API_ENTRY(glProgramBinaryOES)(GLuint program, GLenum binaryFormat, const void *binary, GLint length) {
+ CALL_GL_API(glProgramBinaryOES, program, binaryFormat, binary, length);
+}
+void* API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) {
+ CALL_GL_API_RETURN(glMapBufferOES, target, access);
+}
+GLboolean API_ENTRY(glUnmapBufferOES)(GLenum target) {
+ CALL_GL_API_RETURN(glUnmapBufferOES, target);
+}
+void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, void** params) {
+ CALL_GL_API(glGetBufferPointervOES, target, pname, params);
+}
+void API_ENTRY(glTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels) {
+ CALL_GL_API(glTexImage3DOES, target, level, internalformat, width, height, depth, border, format, type, pixels);
+}
+void API_ENTRY(glTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) {
+ CALL_GL_API(glTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
+}
+void API_ENTRY(glCopyTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
+ CALL_GL_API(glCopyTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, x, y, width, height);
+}
+void API_ENTRY(glCompressedTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexImage3DOES, target, level, internalformat, width, height, depth, border, imageSize, data);
+}
+void API_ENTRY(glCompressedTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data) {
+ CALL_GL_API(glCompressedTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
+}
+void API_ENTRY(glFramebufferTexture3DOES)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) {
+ CALL_GL_API(glFramebufferTexture3DOES, target, attachment, textarget, texture, level, zoffset);
+}
+void API_ENTRY(glGetPerfMonitorGroupsAMD)(GLint *numGroups, GLsizei groupsSize, GLuint *groups) {
+ CALL_GL_API(glGetPerfMonitorGroupsAMD, numGroups, groupsSize, groups);
+}
+void API_ENTRY(glGetPerfMonitorCountersAMD)(GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters) {
+ CALL_GL_API(glGetPerfMonitorCountersAMD, group, numCounters, maxActiveCounters, counterSize, counters);
+}
+void API_ENTRY(glGetPerfMonitorGroupStringAMD)(GLuint group, GLsizei bufSize, GLsizei *length, char *groupString) {
+ CALL_GL_API(glGetPerfMonitorGroupStringAMD, group, bufSize, length, groupString);
+}
+void API_ENTRY(glGetPerfMonitorCounterStringAMD)(GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString) {
+ CALL_GL_API(glGetPerfMonitorCounterStringAMD, group, counter, bufSize, length, counterString);
+}
+void API_ENTRY(glGetPerfMonitorCounterInfoAMD)(GLuint group, GLuint counter, GLenum pname, void *data) {
+ CALL_GL_API(glGetPerfMonitorCounterInfoAMD, group, counter, pname, data);
+}
+void API_ENTRY(glGenPerfMonitorsAMD)(GLsizei n, GLuint *monitors) {
+ CALL_GL_API(glGenPerfMonitorsAMD, n, monitors);
+}
+void API_ENTRY(glDeletePerfMonitorsAMD)(GLsizei n, GLuint *monitors) {
+ CALL_GL_API(glDeletePerfMonitorsAMD, n, monitors);
+}
+void API_ENTRY(glSelectPerfMonitorCountersAMD)(GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList) {
+ CALL_GL_API(glSelectPerfMonitorCountersAMD, monitor, enable, group, numCounters, countersList);
+}
+void API_ENTRY(glBeginPerfMonitorAMD)(GLuint monitor) {
+ CALL_GL_API(glBeginPerfMonitorAMD, monitor);
+}
+void API_ENTRY(glEndPerfMonitorAMD)(GLuint monitor) {
+ CALL_GL_API(glEndPerfMonitorAMD, monitor);
+}
+void API_ENTRY(glGetPerfMonitorCounterDataAMD)(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) {
+ CALL_GL_API(glGetPerfMonitorCounterDataAMD, monitor, pname, dataSize, data, bytesWritten);
+}
+void API_ENTRY(glDeleteFencesNV)(GLsizei n, const GLuint *fences) {
+ CALL_GL_API(glDeleteFencesNV, n, fences);
+}
+void API_ENTRY(glGenFencesNV)(GLsizei n, GLuint *fences) {
+ CALL_GL_API(glGenFencesNV, n, fences);
+}
+GLboolean API_ENTRY(glIsFenceNV)(GLuint fence) {
+ CALL_GL_API_RETURN(glIsFenceNV, fence);
+}
+GLboolean API_ENTRY(glTestFenceNV)(GLuint fence) {
+ CALL_GL_API_RETURN(glTestFenceNV, fence);
+}
+void API_ENTRY(glGetFenceivNV)(GLuint fence, GLenum pname, GLint *params) {
+ CALL_GL_API(glGetFenceivNV, fence, pname, params);
+}
+void API_ENTRY(glFinishFenceNV)(GLuint fence) {
+ CALL_GL_API(glFinishFenceNV, fence);
+}
+void API_ENTRY(glSetFenceNV)(GLuint fence, GLenum condition) {
+ CALL_GL_API(glSetFenceNV, fence, condition);
+}
+void API_ENTRY(glGetDriverControlsQCOM)(GLint *num, GLsizei size, GLuint *driverControls) {
+ CALL_GL_API(glGetDriverControlsQCOM, num, size, driverControls);
+}
+void API_ENTRY(glGetDriverControlStringQCOM)(GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString) {
+ CALL_GL_API(glGetDriverControlStringQCOM, driverControl, bufSize, length, driverControlString);
+}
+void API_ENTRY(glEnableDriverControlQCOM)(GLuint driverControl) {
+ CALL_GL_API(glEnableDriverControlQCOM, driverControl);
+}
+void API_ENTRY(glDisableDriverControlQCOM)(GLuint driverControl) {
+ CALL_GL_API(glDisableDriverControlQCOM, driverControl);
+}
diff --git a/opengl/libs/GLES2/gl2ext_entries.in b/opengl/libs/GLES2/gl2ext_entries.in
new file mode 100644
index 0000000..e608f5d
--- /dev/null
+++ b/opengl/libs/GLES2/gl2ext_entries.in
@@ -0,0 +1,35 @@
+GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
+GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const void *binary, GLint length)
+GL_ENTRY(void*, glMapBufferOES, GLenum target, GLenum access)
+GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
+GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void** params)
+GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels)
+GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels)
+GL_ENTRY(void, glCopyTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data)
+GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data)
+GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
+GL_ENTRY(void, glGetPerfMonitorGroupsAMD, GLint *numGroups, GLsizei groupsSize, GLuint *groups)
+GL_ENTRY(void, glGetPerfMonitorCountersAMD, GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters)
+GL_ENTRY(void, glGetPerfMonitorGroupStringAMD, GLuint group, GLsizei bufSize, GLsizei *length, char *groupString)
+GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString)
+GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, void *data)
+GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glSelectPerfMonitorCountersAMD, GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList)
+GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten)
+GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences)
+GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences)
+GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence)
+GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence)
+GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params)
+GL_ENTRY(void, glFinishFenceNV, GLuint fence)
+GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition)
+GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls)
+GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString)
+GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl)
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index 384b59a..3204d9a 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -14,8 +14,6 @@
** limitations under the License.
*/
-#define LOG_TAG "GLES_CM"
-
#include <ctype.h>
#include <string.h>
#include <errno.h>
@@ -121,16 +119,25 @@ extern "C" {
/*
- * These GL calls are special because they need to call into EGL to retrieve
- * some informations before they can execute.
+ * These GL calls are special because they need to EGL to retrieve some
+ * informations before they can execute.
*/
+extern "C" void __glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
+extern "C" void __glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
+
void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetTexture2DOES(target, implImage);
}
void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ __glEGLImageTargetRenderbufferStorageOES(target, image);
}
diff --git a/opengl/libs/gl_entries.in b/opengl/libs/GLES_CM/gl_entries.in
index d7cc5da..d7cc5da 100644
--- a/opengl/libs/gl_entries.in
+++ b/opengl/libs/GLES_CM/gl_entries.in
diff --git a/opengl/libs/glext_entries.in b/opengl/libs/GLES_CM/glext_entries.in
index dd09c71..dd09c71 100644
--- a/opengl/libs/glext_entries.in
+++ b/opengl/libs/GLES_CM/glext_entries.in
diff --git a/opengl/libs/egl_entries.in b/opengl/libs/egl_entries.in
deleted file mode 100644
index 3b4551b..0000000
--- a/opengl/libs/egl_entries.in
+++ /dev/null
@@ -1,52 +0,0 @@
-EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType)
-EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
-EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
-EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)
-EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)
-
-EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint *)
-EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint *)
-EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint *)
-EGL_ENTRY(EGLSurface, eglCreatePbufferSurface, EGLDisplay, EGLConfig, const EGLint *)
-EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface)
-EGL_ENTRY(EGLBoolean, eglQuerySurface, EGLDisplay, EGLSurface, EGLint, EGLint *)
-EGL_ENTRY(EGLContext, eglCreateContext, EGLDisplay, EGLConfig, EGLContext, const EGLint *)
-EGL_ENTRY(EGLBoolean, eglDestroyContext, EGLDisplay, EGLContext)
-EGL_ENTRY(EGLBoolean, eglMakeCurrent, EGLDisplay, EGLSurface, EGLSurface, EGLContext)
-EGL_ENTRY(EGLContext, eglGetCurrentContext, void)
-EGL_ENTRY(EGLSurface, eglGetCurrentSurface, EGLint)
-EGL_ENTRY(EGLDisplay, eglGetCurrentDisplay, void)
-EGL_ENTRY(EGLBoolean, eglQueryContext, EGLDisplay, EGLContext, EGLint, EGLint *)
-EGL_ENTRY(EGLBoolean, eglWaitGL, void)
-EGL_ENTRY(EGLBoolean, eglWaitNative, EGLint)
-EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface)
-EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType)
-EGL_ENTRY(EGLint, eglGetError, void)
-EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint)
-EGL_ENTRY(__eglMustCastToProperFunctionPointerType, eglGetProcAddress, const char *)
-
-/* EGL 1.1 */
-
-EGL_ENTRY(EGLBoolean, eglSurfaceAttrib, EGLDisplay, EGLSurface, EGLint, EGLint)
-EGL_ENTRY(EGLBoolean, eglBindTexImage, EGLDisplay, EGLSurface, EGLint)
-EGL_ENTRY(EGLBoolean, eglReleaseTexImage, EGLDisplay, EGLSurface, EGLint)
-EGL_ENTRY(EGLBoolean, eglSwapInterval, EGLDisplay, EGLint)
-
-/* EGL 1.2 */
-
-EGL_ENTRY(EGLBoolean, eglBindAPI, EGLenum)
-EGL_ENTRY(EGLenum, eglQueryAPI, void)
-EGL_ENTRY(EGLBoolean, eglWaitClient, void)
-EGL_ENTRY(EGLBoolean, eglReleaseThread, void)
-EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint *)
-
-/* EGL 1.3 */
-
-/* EGL 1.4 */
-
-/* EGL_EGLEXT_VERSION 3 */
-
-EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint *)
-EGL_ENTRY(EGLBoolean, eglUnlockSurfaceKHR, EGLDisplay, EGLSurface)
-EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *)
-EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR)
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index 312b176..ac286cb 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -31,13 +31,14 @@ struct gl_hooks_t;
struct egl_connection_t
{
- void volatile * dso;
+ void * dso;
gl_hooks_t * hooks;
EGLint major;
EGLint minor;
- int unavailable;
};
+EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
+
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/gl_enums.in b/opengl/libs/gl_enums.in
deleted file mode 100644
index ffc2fad..0000000
--- a/opengl/libs/gl_enums.in
+++ /dev/null
@@ -1,261 +0,0 @@
-GLENUM(GL_POINTS, 0x0000)
-GLENUM(GL_LINES, 0x0001)
-GLENUM(GL_LINE_LOOP, 0x0002)
-GLENUM(GL_LINE_STRIP, 0x0003)
-GLENUM(GL_TRIANGLES, 0x0004)
-GLENUM(GL_TRIANGLE_STRIP, 0x0005)
-GLENUM(GL_TRIANGLE_FAN, 0x0006)
-GLENUM(GL_ADD, 0x0104)
-GLENUM(GL_NEVER, 0x0200)
-GLENUM(GL_LESS, 0x0201)
-GLENUM(GL_EQUAL, 0x0202)
-GLENUM(GL_LEQUAL, 0x0203)
-GLENUM(GL_GREATER, 0x0204)
-GLENUM(GL_NOTEQUAL, 0x0205)
-GLENUM(GL_GEQUAL, 0x0206)
-GLENUM(GL_ALWAYS, 0x0207)
-GLENUM(GL_SRC_COLOR, 0x0300)
-GLENUM(GL_ONE_MINUS_SRC_COLOR, 0x0301)
-GLENUM(GL_SRC_ALPHA, 0x0302)
-GLENUM(GL_ONE_MINUS_SRC_ALPHA, 0x0303)
-GLENUM(GL_DST_ALPHA, 0x0304)
-GLENUM(GL_ONE_MINUS_DST_ALPHA, 0x0305)
-GLENUM(GL_DST_COLOR, 0x0306)
-GLENUM(GL_ONE_MINUS_DST_COLOR, 0x0307)
-GLENUM(GL_SRC_ALPHA_SATURATE, 0x0308)
-GLENUM(GL_FRONT, 0x0404)
-GLENUM(GL_BACK, 0x0405)
-GLENUM(GL_FRONT_AND_BACK, 0x0408)
-GLENUM(GL_INVALID_ENUM, 0x0500)
-GLENUM(GL_INVALID_VALUE, 0x0501)
-GLENUM(GL_INVALID_OPERATION, 0x0502)
-GLENUM(GL_STACK_OVERFLOW, 0x0503)
-GLENUM(GL_STACK_UNDERFLOW, 0x0504)
-GLENUM(GL_OUT_OF_MEMORY, 0x0505)
-GLENUM(GL_EXP, 0x0800)
-GLENUM(GL_EXP2, 0x0801)
-GLENUM(GL_CW, 0x0900)
-GLENUM(GL_CCW, 0x0901)
-GLENUM(GL_POINT_SMOOTH, 0x0B10)
-GLENUM(GL_SMOOTH_POINT_SIZE_RANGE, 0x0B12)
-GLENUM(GL_LINE_SMOOTH, 0x0B20)
-GLENUM(GL_SMOOTH_LINE_WIDTH_RANGE, 0x0B22)
-GLENUM(GL_CULL_FACE, 0x0B44)
-GLENUM(GL_LIGHTING, 0x0B50)
-GLENUM(GL_LIGHT_MODEL_TWO_SIDE, 0x0B52)
-GLENUM(GL_LIGHT_MODEL_AMBIENT, 0x0B53)
-GLENUM(GL_COLOR_MATERIAL, 0x0B57)
-GLENUM(GL_FOG, 0x0B60)
-GLENUM(GL_FOG_DENSITY, 0x0B62)
-GLENUM(GL_FOG_START, 0x0B63)
-GLENUM(GL_FOG_END, 0x0B64)
-GLENUM(GL_FOG_MODE, 0x0B65)
-GLENUM(GL_FOG_COLOR, 0x0B66)
-GLENUM(GL_DEPTH_TEST, 0x0B71)
-GLENUM(GL_STENCIL_TEST, 0x0B90)
-GLENUM(GL_NORMALIZE, 0x0BA1)
-GLENUM(GL_ALPHA_TEST, 0x0BC0)
-GLENUM(GL_DITHER, 0x0BD0)
-GLENUM(GL_BLEND, 0x0BE2)
-GLENUM(GL_COLOR_LOGIC_OP, 0x0BF2)
-GLENUM(GL_SCISSOR_TEST, 0x0C11)
-GLENUM(GL_PERSPECTIVE_CORRECTION_HINT, 0x0C50)
-GLENUM(GL_POINT_SMOOTH_HINT, 0x0C51)
-GLENUM(GL_LINE_SMOOTH_HINT, 0x0C52)
-GLENUM(GL_POLYGON_SMOOTH_HINT, 0x0C53)
-GLENUM(GL_FOG_HINT, 0x0C54)
-GLENUM(GL_UNPACK_ALIGNMENT, 0x0CF5)
-GLENUM(GL_PACK_ALIGNMENT, 0x0D05)
-GLENUM(GL_MAX_LIGHTS, 0x0D31)
-GLENUM(GL_MAX_CLIP_PLANES, 0x0D32)
-GLENUM(GL_MAX_TEXTURE_SIZE, 0x0D33)
-GLENUM(GL_MAX_MODELVIEW_STACK_DEPTH, 0x0D36)
-GLENUM(GL_MAX_PROJECTION_STACK_DEPTH, 0x0D38)
-GLENUM(GL_MAX_TEXTURE_STACK_DEPTH, 0x0D39)
-GLENUM(GL_MAX_VIEWPORT_DIMS, 0x0D3A)
-GLENUM(GL_RED_BITS, 0x0D52)
-GLENUM(GL_GREEN_BITS, 0x0D53)
-GLENUM(GL_BLUE_BITS, 0x0D54)
-GLENUM(GL_ALPHA_BITS, 0x0D55)
-GLENUM(GL_DEPTH_BITS, 0x0D56)
-GLENUM(GL_STENCIL_BITS, 0x0D57)
-GLENUM(GL_TEXTURE_2D, 0x0DE1)
-GLENUM(GL_DONT_CARE, 0x1100)
-GLENUM(GL_FASTEST, 0x1101)
-GLENUM(GL_NICEST, 0x1102)
-GLENUM(GL_AMBIENT, 0x1200)
-GLENUM(GL_DIFFUSE, 0x1201)
-GLENUM(GL_SPECULAR, 0x1202)
-GLENUM(GL_POSITION, 0x1203)
-GLENUM(GL_SPOT_DIRECTION, 0x1204)
-GLENUM(GL_SPOT_EXPONENT, 0x1205)
-GLENUM(GL_SPOT_CUTOFF, 0x1206)
-GLENUM(GL_CONSTANT_ATTENUATION, 0x1207)
-GLENUM(GL_LINEAR_ATTENUATION, 0x1208)
-GLENUM(GL_QUADRATIC_ATTENUATION, 0x1209)
-GLENUM(GL_BYTE, 0x1400)
-GLENUM(GL_UNSIGNED_BYTE, 0x1401)
-GLENUM(GL_SHORT, 0x1402)
-GLENUM(GL_UNSIGNED_SHORT, 0x1403)
-GLENUM(GL_FLOAT, 0x1406)
-GLENUM(GL_FIXED, 0x140C)
-GLENUM(GL_CLEAR, 0x1500)
-GLENUM(GL_AND, 0x1501)
-GLENUM(GL_AND_REVERSE, 0x1502)
-GLENUM(GL_COPY, 0x1503)
-GLENUM(GL_AND_INVERTED, 0x1504)
-GLENUM(GL_NOOP, 0x1505)
-GLENUM(GL_XOR, 0x1506)
-GLENUM(GL_OR, 0x1507)
-GLENUM(GL_NOR, 0x1508)
-GLENUM(GL_EQUIV, 0x1509)
-GLENUM(GL_INVERT, 0x150A)
-GLENUM(GL_OR_REVERSE, 0x150B)
-GLENUM(GL_COPY_INVERTED, 0x150C)
-GLENUM(GL_OR_INVERTED, 0x150D)
-GLENUM(GL_NAND, 0x150E)
-GLENUM(GL_SET, 0x150F)
-GLENUM(GL_EMISSION, 0x1600)
-GLENUM(GL_SHININESS, 0x1601)
-GLENUM(GL_AMBIENT_AND_DIFFUSE, 0x1602)
-GLENUM(GL_MODELVIEW, 0x1700)
-GLENUM(GL_PROJECTION, 0x1701)
-GLENUM(GL_TEXTURE, 0x1702)
-GLENUM(GL_ALPHA, 0x1906)
-GLENUM(GL_RGB, 0x1907)
-GLENUM(GL_RGBA, 0x1908)
-GLENUM(GL_LUMINANCE, 0x1909)
-GLENUM(GL_LUMINANCE_ALPHA, 0x190A)
-GLENUM(GL_FLAT, 0x1D00)
-GLENUM(GL_SMOOTH, 0x1D01)
-GLENUM(GL_KEEP, 0x1E00)
-GLENUM(GL_REPLACE, 0x1E01)
-GLENUM(GL_REPLACE, 0x1E01)
-GLENUM(GL_INCR, 0x1E02)
-GLENUM(GL_DECR, 0x1E03)
-GLENUM(GL_VENDOR, 0x1F00)
-GLENUM(GL_RENDERER, 0x1F01)
-GLENUM(GL_VERSION, 0x1F02)
-GLENUM(GL_EXTENSIONS, 0x1F03)
-GLENUM(GL_MODULATE, 0x2100)
-GLENUM(GL_DECAL, 0x2101)
-GLENUM(GL_TEXTURE_ENV_MODE, 0x2200)
-GLENUM(GL_TEXTURE_ENV_COLOR, 0x2201)
-GLENUM(GL_TEXTURE_ENV, 0x2300)
-GLENUM(GL_NEAREST, 0x2600)
-GLENUM(GL_LINEAR, 0x2601)
-GLENUM(GL_NEAREST_MIPMAP_NEAREST, 0x2700)
-GLENUM(GL_LINEAR_MIPMAP_NEAREST, 0x2701)
-GLENUM(GL_NEAREST_MIPMAP_LINEAR, 0x2702)
-GLENUM(GL_LINEAR_MIPMAP_LINEAR, 0x2703)
-GLENUM(GL_TEXTURE_MAG_FILTER, 0x2800)
-GLENUM(GL_TEXTURE_MIN_FILTER, 0x2801)
-GLENUM(GL_TEXTURE_WRAP_S, 0x2802)
-GLENUM(GL_TEXTURE_WRAP_T, 0x2803)
-GLENUM(GL_CLAMP, 0x2900)
-GLENUM(GL_REPEAT, 0x2901)
-GLENUM(GL_CLIP_PLANE0, 0x3000)
-GLENUM(GL_CLIP_PLANE1, 0x3001)
-GLENUM(GL_CLIP_PLANE2, 0x3002)
-GLENUM(GL_CLIP_PLANE3, 0x3003)
-GLENUM(GL_CLIP_PLANE4, 0x3004)
-GLENUM(GL_CLIP_PLANE5, 0x3005)
-GLENUM(GL_LIGHT0, 0x4000)
-GLENUM(GL_LIGHT1, 0x4001)
-GLENUM(GL_LIGHT2, 0x4002)
-GLENUM(GL_LIGHT3, 0x4003)
-GLENUM(GL_LIGHT4, 0x4004)
-GLENUM(GL_LIGHT5, 0x4005)
-GLENUM(GL_LIGHT6, 0x4006)
-GLENUM(GL_LIGHT7, 0x4007)
-GLENUM(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0x7E80)
-GLENUM(GL_UNSIGNED_SHORT_4_4_4_4, 0x8033)
-GLENUM(GL_UNSIGNED_SHORT_5_5_5_1, 0x8034)
-GLENUM(GL_POLYGON_OFFSET_FILL, 0x8037)
-GLENUM(GL_RESCALE_NORMAL, 0x803A)
-GLENUM(GL_VERTEX_ARRAY, 0x8074)
-GLENUM(GL_NORMAL_ARRAY, 0x8075)
-GLENUM(GL_COLOR_ARRAY, 0x8076)
-GLENUM(GL_TEXTURE_COORD_ARRAY, 0x8078)
-GLENUM(GL_MULTISAMPLE, 0x809D)
-GLENUM(GL_SAMPLE_ALPHA_TO_COVERAGE, 0x809E)
-GLENUM(GL_SAMPLE_ALPHA_TO_ONE, 0x809F)
-GLENUM(GL_SAMPLE_COVERAGE, 0x80A0)
-GLENUM(GL_MAX_ELEMENTS_VERTICES, 0x80E8)
-GLENUM(GL_MAX_ELEMENTS_INDICES, 0x80E9)
-GLENUM(GL_CLAMP_TO_EDGE, 0x812F)
-GLENUM(GL_GENERATE_MIPMAP, 0x8191)
-GLENUM(GL_GENERATE_MIPMAP_HINT, 0x8192)
-GLENUM(GL_UNSIGNED_SHORT_5_6_5, 0x8363)
-GLENUM(GL_ALIASED_POINT_SIZE_RANGE, 0x846D)
-GLENUM(GL_ALIASED_LINE_WIDTH_RANGE, 0x846E)
-GLENUM(GL_TEXTURE0, 0x84C0)
-GLENUM(GL_TEXTURE1, 0x84C1)
-GLENUM(GL_TEXTURE2, 0x84C2)
-GLENUM(GL_TEXTURE3, 0x84C3)
-GLENUM(GL_TEXTURE4, 0x84C4)
-GLENUM(GL_TEXTURE5, 0x84C5)
-GLENUM(GL_TEXTURE6, 0x84C6)
-GLENUM(GL_TEXTURE7, 0x84C7)
-GLENUM(GL_TEXTURE8, 0x84C8)
-GLENUM(GL_TEXTURE9, 0x84C9)
-GLENUM(GL_TEXTURE10, 0x84CA)
-GLENUM(GL_TEXTURE11, 0x84CB)
-GLENUM(GL_TEXTURE12, 0x84CC)
-GLENUM(GL_TEXTURE13, 0x84CD)
-GLENUM(GL_TEXTURE14, 0x84CE)
-GLENUM(GL_TEXTURE15, 0x84CF)
-GLENUM(GL_TEXTURE16, 0x84D0)
-GLENUM(GL_TEXTURE17, 0x84D1)
-GLENUM(GL_TEXTURE18, 0x84D2)
-GLENUM(GL_TEXTURE19, 0x84D3)
-GLENUM(GL_TEXTURE20, 0x84D4)
-GLENUM(GL_TEXTURE21, 0x84D5)
-GLENUM(GL_TEXTURE22, 0x84D6)
-GLENUM(GL_TEXTURE23, 0x84D7)
-GLENUM(GL_TEXTURE24, 0x84D8)
-GLENUM(GL_TEXTURE25, 0x84D9)
-GLENUM(GL_TEXTURE26, 0x84DA)
-GLENUM(GL_TEXTURE27, 0x84DB)
-GLENUM(GL_TEXTURE28, 0x84DC)
-GLENUM(GL_TEXTURE29, 0x84DD)
-GLENUM(GL_TEXTURE30, 0x84DE)
-GLENUM(GL_TEXTURE31, 0x84DF)
-GLENUM(GL_MAX_TEXTURE_UNITS, 0x84E2)
-GLENUM(GL_NUM_COMPRESSED_TEXTURE_FORMATS, 0x86A2)
-GLENUM(GL_COMPRESSED_TEXTURE_FORMATS, 0x86A3)
-GLENUM(GL_BUFFER_SIZE, 0x8764)
-GLENUM(GL_BUFFER_USAGE, 0x8765)
-GLENUM(GL_POINT_SPRITE_OES, 0x8861)
-GLENUM(GL_COORD_REPLACE_OES, 0x8862)
-GLENUM(GL_ARRAY_BUFFER, 0x8892)
-GLENUM(GL_ELEMENT_ARRAY_BUFFER, 0x8893)
-GLENUM(GL_ARRAY_BUFFER_BINDING, 0x8894)
-GLENUM(GL_ELEMENT_ARRAY_BUFFER_BINDING, 0x8895)
-GLENUM(GL_VERTEX_ARRAY_BUFFER_BINDING, 0x8896)
-GLENUM(GL_NORMAL_ARRAY_BUFFER_BINDING, 0x8897)
-GLENUM(GL_COLOR_ARRAY_BUFFER_BINDING, 0x8898)
-GLENUM(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, 0x889A)
-GLENUM(GL_STATIC_DRAW, 0x88E4)
-GLENUM(GL_DYNAMIC_DRAW, 0x88E8)
-GLENUM(GL_POINT_SIZE_ARRAY_TYPE_OES, 0x898A)
-GLENUM(GL_POINT_SIZE_ARRAY_STRIDE_OES, 0x898B)
-GLENUM(GL_POINT_SIZE_ARRAY_POINTER_OES, 0x898C)
-GLENUM(GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898D)
-GLENUM(GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898E)
-GLENUM(GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES, 0x898F)
-GLENUM(GL_PALETTE4_RGB8_OES, 0x8B90)
-GLENUM(GL_PALETTE4_RGBA8_OES, 0x8B91)
-GLENUM(GL_PALETTE4_R5_G6_B5_OES, 0x8B92)
-GLENUM(GL_PALETTE4_RGBA4_OES, 0x8B93)
-GLENUM(GL_PALETTE4_RGB5_A1_OES, 0x8B94)
-GLENUM(GL_PALETTE8_RGB8_OES, 0x8B95)
-GLENUM(GL_PALETTE8_RGBA8_OES, 0x8B96)
-GLENUM(GL_PALETTE8_R5_G6_B5_OES, 0x8B97)
-GLENUM(GL_PALETTE8_RGBA4_OES, 0x8B98)
-GLENUM(GL_PALETTE8_RGB5_A1_OES, 0x8B99)
-GLENUM(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, 0x8B9A)
-GLENUM(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, 0x8B9B)
-GLENUM(GL_POINT_SIZE_ARRAY_OES, 0x8B9C)
-GLENUM(GL_TEXTURE_CROP_RECT_OES, 0x8B9D)
-GLENUM(GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES, 0x8B9F)
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index fd97254..8c0357e 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -21,10 +21,14 @@
#include <string.h>
#include <errno.h>
+#include <pthread.h>
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
#if !defined(__arm__)
#define USE_SLOW_BINDING 1
@@ -56,12 +60,8 @@ const unsigned int NUM_DISPLAYS = 1;
enum {
IMPL_HARDWARE = 0,
IMPL_SOFTWARE,
-
IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
-
- IMPL_CONTEXT_LOST = IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
- IMPL_NO_CONTEXT,
-
+ IMPL_NO_CONTEXT = IMPL_NUM_DRIVERS_IMPLEMENTATIONS,
IMPL_NUM_IMPLEMENTATIONS
};
@@ -76,11 +76,15 @@ enum {
struct gl_hooks_t {
struct gl_t {
- #include "gl_entries.in"
- #include "glext_entries.in"
+ #include "GLES_CM/gl_entries.in"
+ #include "GLES_CM/glext_entries.in"
} gl;
+ struct gl2_t {
+ #include "GLES2/gl2_entries.in"
+ #include "GLES2/gl2ext_entries.in"
+ } gl2;
struct egl_t {
- #include "egl_entries.in"
+ #include "EGL/egl_entries.in"
} egl;
struct gl_ext_t {
void (*extensions[MAX_NUMBER_OF_GL_EXTENSIONS])(void);
@@ -94,6 +98,13 @@ struct gl_hooks_t {
extern gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
extern pthread_key_t gGLWrapperKey;
+extern "C" void gl_unimplemented();
+
+extern char const * const gl_names[];
+extern char const * const gl2_names[];
+extern char const * const egl_names[];
+
+// ----------------------------------------------------------------------------
#if USE_FAST_TLS_KEY
diff --git a/opengl/libs/tools/enumextract.sh b/opengl/libs/tools/enumextract.sh
deleted file mode 100644
index 5707302..0000000
--- a/opengl/libs/tools/enumextract.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-
-awk '
-/^#define GL_/ {
- names[count] = $2;
- values[count] = $3;
- sort[count] = $3 + 0;
- count++;
-}
-END {
- for (i = 1; i < count; i++) {
- for (j = 0; j < i; j++) {
- if (sort[i] < sort[j]) {
- tn = names[i];
- tv = values[i];
- ts = sort[i];
- names[i] = names[j];
- values[i] = values[j];
- sort[i] = sort[j];
- names[j] = tn;
- values[j] = tv;
- sort[j] = ts;
- }
- }
- }
-
- for (i = 0; i < count; i++) {
- printf("GLENUM(%s, %s)\n", names[i], values[i]);
- }
-}
-' < $1
-
diff --git a/opengl/libs/tools/genfiles b/opengl/libs/tools/genfiles
index 107768b..4f8eda4 100755
--- a/opengl/libs/tools/genfiles
+++ b/opengl/libs/tools/genfiles
@@ -15,6 +15,13 @@
# limitations under the License.
./glapigen ../../include/GLES/gl.h > ../GLES_CM/gl_api.in
-./glentrygen ../../include/GLES/gl.h > ../gl_entries.in
+./glentrygen ../../include/GLES/gl.h > ../GLES_CM/gl_entries.in
+
./glapigen ../../include/GLES/glext.h > ../GLES_CM/glext_api.in
-./glentrygen ../../include/GLES/glext.h > ../glext_entries.in
+./glentrygen ../../include/GLES/glext.h > ../GLES_CM/glext_entries.in
+
+./glapigen ../../include/GLES2/gl2.h > ../GLES2/gl2_api.in
+./glentrygen ../../include/GLES2/gl2.h > ../GLES2/gl2_entries.in
+
+./glapigen ../../include/GLES2/gl2ext.h > ../GLES2/gl2ext_api.in
+./glentrygen ../../include/GLES2/gl2ext.h > ../GLES2/gl2ext_entries.in
diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen
index a2c3a7b..bd8dda3 100755
--- a/opengl/libs/tools/glapigen
+++ b/opengl/libs/tools/glapigen
@@ -16,16 +16,23 @@
use strict;
+sub rtrim($)
+{
+ my $string = shift;
+ $string =~ s/\s+$//;
+ return $string;
+}
+
while (my $line = <>) {
next if $line =~ /^\//;
next if $line =~ /^#/;
next if $line =~ /^\s*$/;
- if ($line !~ /^GL_API\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
+ if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
next;
}
- my $type = $1;
- my $name = $2;
- my $args = $3;
+ my $type = rtrim($2);
+ my $name = $3;
+ my $args = $4;
#printf("%s", $line);
diff --git a/opengl/libs/tools/glentrygen b/opengl/libs/tools/glentrygen
index 5e0f7b6..170f041 100755
--- a/opengl/libs/tools/glentrygen
+++ b/opengl/libs/tools/glentrygen
@@ -16,16 +16,23 @@
use strict;
+sub rtrim($)
+{
+ my $string = shift;
+ $string =~ s/\s+$//;
+ return $string;
+}
+
while (my $line = <>) {
next if $line =~ /^\//;
next if $line =~ /^#/;
next if $line =~ /^\s*$/;
- if ($line !~ /^GL_API\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
+ if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
next;
}
- my $type = $1;
- my $name = $2;
- my $args = $3;
+ my $type = rtrim($2);
+ my $name = $3;
+ my $args = $4;
printf("GL_ENTRY(%s, %s, %s)\n", $type, $name, $args);
}
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
index e193483..d0c3221 100644
--- a/opengl/tests/angeles/Android.mk
+++ b/opengl/tests/angeles/Android.mk
@@ -2,7 +2,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= app-linux.c demo.c.arm
+LOCAL_SRC_FILES:= app-linux.cpp demo.c.arm
LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui
LOCAL_MODULE:= angeles
LOCAL_MODULE_TAGS := optional
diff --git a/opengl/tests/angeles/app-linux.c b/opengl/tests/angeles/app-linux.c
deleted file mode 100644
index 7d0d320..0000000
--- a/opengl/tests/angeles/app-linux.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/* San Angeles Observation OpenGL ES version example
- * Copyright 2004-2005 Jetro Lauha
- * All rights reserved.
- * Web: http://iki.fi/jetro/
- *
- * This source is free software; you can redistribute it and/or
- * modify it under the terms of EITHER:
- * (1) The GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at
- * your option) any later version. The text of the GNU Lesser
- * General Public License is included with this source in the
- * file LICENSE-LGPL.txt.
- * (2) The BSD-style license that is included with this source in
- * the file LICENSE-BSD.txt.
- *
- * This source is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
- * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
- *
- * $Id: app-linux.c,v 1.4 2005/02/08 18:42:48 tonic Exp $
- * $Revision: 1.4 $
- *
- * Parts of this source file is based on test/example code from
- * GLESonGL implementation by David Blythe. Here is copy of the
- * license notice from that source:
- *
- * Copyright (C) 2003 David Blythe All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * DAVID BLYTHE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/time.h>
-
-#include <EGL/egl.h>
-#include <GLES/gl.h>
-
-#include "app.h"
-
-
-int gAppAlive = 1;
-
-static const char sAppName[] =
- "San Angeles Observation OpenGL ES version example (Linux)";
-
-static int sWindowWidth = WINDOW_DEFAULT_WIDTH;
-static int sWindowHeight = WINDOW_DEFAULT_HEIGHT;
-static EGLDisplay sEglDisplay = EGL_NO_DISPLAY;
-static EGLContext sEglContext = EGL_NO_CONTEXT;
-static EGLSurface sEglSurface = EGL_NO_SURFACE;
-
-const char *egl_strerror(unsigned err)
-{
- switch(err){
- case EGL_SUCCESS: return "SUCCESS";
- case EGL_NOT_INITIALIZED: return "NOT INITIALIZED";
- case EGL_BAD_ACCESS: return "BAD ACCESS";
- case EGL_BAD_ALLOC: return "BAD ALLOC";
- case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE";
- case EGL_BAD_CONFIG: return "BAD CONFIG";
- case EGL_BAD_CONTEXT: return "BAD CONTEXT";
- case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE";
- case EGL_BAD_DISPLAY: return "BAD DISPLAY";
- case EGL_BAD_MATCH: return "BAD MATCH";
- case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP";
- case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW";
- case EGL_BAD_PARAMETER: return "BAD PARAMETER";
- case EGL_BAD_SURFACE: return "BAD_SURFACE";
-// case EGL_CONTEXT_LOST: return "CONTEXT LOST";
- default: return "UNKNOWN";
- }
-}
-
-void egl_error(const char *name)
-{
- unsigned err = eglGetError();
- if(err != EGL_SUCCESS) {
- fprintf(stderr,"%s(): egl error 0x%x (%s)\n",
- name, err, egl_strerror(err));
- }
-}
-
-static void checkGLErrors()
-{
- GLenum error = glGetError();
- if (error != GL_NO_ERROR)
- fprintf(stderr, "GL Error: 0x%04x\n", (int)error);
-}
-
-
-static void checkEGLErrors()
-{
- EGLint error = eglGetError();
- // GLESonGL seems to be returning 0 when there is no errors?
- if (error && error != EGL_SUCCESS)
- fprintf(stderr, "EGL Error: 0x%04x\n", (int)error);
-}
-
-static int initGraphics()
-{
- EGLint s_configAttribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- #if 1
- EGL_DEPTH_SIZE, 16,
- EGL_STENCIL_SIZE, 0,
- #else
- EGL_ALPHA_SIZE, EGL_DONT_CARE,
- EGL_DEPTH_SIZE, EGL_DONT_CARE,
- EGL_STENCIL_SIZE, EGL_DONT_CARE,
- EGL_SURFACE_TYPE, EGL_DONT_CARE,
- #endif
- EGL_NONE
- };
-
- EGLint numConfigs = -1;
- EGLint majorVersion;
- EGLint minorVersion;
- EGLConfig config;
- EGLContext context;
- EGLSurface surface;
-
- EGLDisplay dpy;
-
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- egl_error("eglGetDisplay");
- fprintf(stderr,"dpy = 0x%08x\n", (unsigned) dpy);
-
- eglInitialize(dpy, &majorVersion, &minorVersion);
- egl_error("eglInitialize");
-
- eglGetConfigs(dpy, NULL, 0, &numConfigs);
- egl_error("eglGetConfigs");
- fprintf(stderr,"num configs %d\n", numConfigs);
-
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- egl_error("eglChooseConfig");
-
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
- egl_error("eglMapWindowSurface");
-
- fprintf(stderr,"surface = %p\n", surface);
-
- context = eglCreateContext(dpy, config, NULL, NULL);
- egl_error("eglCreateContext");
- fprintf(stderr,"context = %p\n", context);
-
- eglMakeCurrent(dpy, surface, surface, context);
- egl_error("eglMakeCurrent");
-
- eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth);
- eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight);
-
- sEglDisplay = dpy;
- sEglSurface = surface;
- sEglContext = context;
-
- return EGL_TRUE;
-}
-
-
-static void deinitGraphics()
-{
- eglMakeCurrent(sEglDisplay, NULL, NULL, NULL);
- eglDestroyContext(sEglDisplay, sEglContext);
- eglDestroySurface(sEglDisplay, sEglSurface);
- eglTerminate(sEglDisplay);
-}
-
-
-int main(int argc, char *argv[])
-{
- // not referenced:
- argc = argc;
- argv = argv;
-
- if (!initGraphics())
- {
- fprintf(stderr, "Graphics initialization failed.\n");
- return EXIT_FAILURE;
- }
-
- appInit();
-
- while (gAppAlive)
- {
- struct timeval timeNow;
-
- if (gAppAlive)
- {
- gettimeofday(&timeNow, NULL);
- appRender(timeNow.tv_sec * 1000 + timeNow.tv_usec / 1000,
- sWindowWidth, sWindowHeight);
- checkGLErrors();
- eglSwapBuffers(sEglDisplay, sEglSurface);
- checkEGLErrors();
- }
- }
-
- appDeinit();
- deinitGraphics();
-
- return EXIT_SUCCESS;
-}
diff --git a/opengl/tests/angeles/app-linux.cpp b/opengl/tests/angeles/app-linux.cpp
new file mode 100644
index 0000000..06fa0c2
--- /dev/null
+++ b/opengl/tests/angeles/app-linux.cpp
@@ -0,0 +1,213 @@
+/* San Angeles Observation OpenGL ES version example
+ * Copyright 2004-2005 Jetro Lauha
+ * All rights reserved.
+ * Web: http://iki.fi/jetro/
+ *
+ * This source is free software; you can redistribute it and/or
+ * modify it under the terms of EITHER:
+ * (1) The GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version. The text of the GNU Lesser
+ * General Public License is included with this source in the
+ * file LICENSE-LGPL.txt.
+ * (2) The BSD-style license that is included with this source in
+ * the file LICENSE-BSD.txt.
+ *
+ * This source is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
+ * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
+ *
+ * $Id: app-linux.c,v 1.4 2005/02/08 18:42:48 tonic Exp $
+ * $Revision: 1.4 $
+ *
+ * Parts of this source file is based on test/example code from
+ * GLESonGL implementation by David Blythe. Here is copy of the
+ * license notice from that source:
+ *
+ * Copyright (C) 2003 David Blythe All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * DAVID BLYTHE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+#include "app.h"
+
+
+int gAppAlive = 1;
+
+static const char sAppName[] =
+ "San Angeles Observation OpenGL ES version example (Linux)";
+
+static int sWindowWidth = WINDOW_DEFAULT_WIDTH;
+static int sWindowHeight = WINDOW_DEFAULT_HEIGHT;
+static EGLDisplay sEglDisplay = EGL_NO_DISPLAY;
+static EGLContext sEglContext = EGL_NO_CONTEXT;
+static EGLSurface sEglSurface = EGL_NO_SURFACE;
+
+const char *egl_strerror(unsigned err)
+{
+ switch(err){
+ case EGL_SUCCESS: return "SUCCESS";
+ case EGL_NOT_INITIALIZED: return "NOT INITIALIZED";
+ case EGL_BAD_ACCESS: return "BAD ACCESS";
+ case EGL_BAD_ALLOC: return "BAD ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "BAD_ATTRIBUTE";
+ case EGL_BAD_CONFIG: return "BAD CONFIG";
+ case EGL_BAD_CONTEXT: return "BAD CONTEXT";
+ case EGL_BAD_CURRENT_SURFACE: return "BAD CURRENT SURFACE";
+ case EGL_BAD_DISPLAY: return "BAD DISPLAY";
+ case EGL_BAD_MATCH: return "BAD MATCH";
+ case EGL_BAD_NATIVE_PIXMAP: return "BAD NATIVE PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "BAD NATIVE WINDOW";
+ case EGL_BAD_PARAMETER: return "BAD PARAMETER";
+ case EGL_BAD_SURFACE: return "BAD_SURFACE";
+// case EGL_CONTEXT_LOST: return "CONTEXT LOST";
+ default: return "UNKNOWN";
+ }
+}
+
+void egl_error(const char *name)
+{
+ unsigned err = eglGetError();
+ if(err != EGL_SUCCESS) {
+ fprintf(stderr,"%s(): egl error 0x%x (%s)\n",
+ name, err, egl_strerror(err));
+ }
+}
+
+static void checkGLErrors()
+{
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR)
+ fprintf(stderr, "GL Error: 0x%04x\n", (int)error);
+}
+
+
+static void checkEGLErrors()
+{
+ EGLint error = eglGetError();
+ // GLESonGL seems to be returning 0 when there is no errors?
+ if (error && error != EGL_SUCCESS)
+ fprintf(stderr, "EGL Error: 0x%04x\n", (int)error);
+}
+
+static int initGraphics()
+{
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 16,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ egl_error("eglCreateWindowSurface");
+
+ fprintf(stderr,"surface = %p\n", surface);
+
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ egl_error("eglCreateContext");
+ fprintf(stderr,"context = %p\n", context);
+
+ eglMakeCurrent(dpy, surface, surface, context);
+ egl_error("eglMakeCurrent");
+
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &sWindowWidth);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &sWindowHeight);
+
+ sEglDisplay = dpy;
+ sEglSurface = surface;
+ sEglContext = context;
+
+ return EGL_TRUE;
+}
+
+
+static void deinitGraphics()
+{
+ eglMakeCurrent(sEglDisplay, NULL, NULL, NULL);
+ eglDestroyContext(sEglDisplay, sEglContext);
+ eglDestroySurface(sEglDisplay, sEglSurface);
+ eglTerminate(sEglDisplay);
+}
+
+
+int main(int argc, char *argv[])
+{
+ // not referenced:
+ argc = argc;
+ argv = argv;
+
+ if (!initGraphics())
+ {
+ fprintf(stderr, "Graphics initialization failed.\n");
+ return EXIT_FAILURE;
+ }
+
+ appInit();
+
+ while (gAppAlive)
+ {
+ struct timeval timeNow;
+
+ if (gAppAlive)
+ {
+ gettimeofday(&timeNow, NULL);
+ appRender(timeNow.tv_sec * 1000 + timeNow.tv_usec / 1000,
+ sWindowWidth, sWindowHeight);
+ checkGLErrors();
+ eglSwapBuffers(sEglDisplay, sEglSurface);
+ checkEGLErrors();
+ }
+ }
+
+ appDeinit();
+ deinitGraphics();
+
+ return EXIT_SUCCESS;
+}
diff --git a/opengl/tests/copybits/Android.mk b/opengl/tests/copybits/Android.mk
new file mode 100644
index 0000000..d5ded42
--- /dev/null
+++ b/opengl/tests/copybits/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ copybits.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-copybits
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/opengl/tests/copybits/copybits.cpp b/opengl/tests/copybits/copybits.cpp
new file mode 100644
index 0000000..11dfb6e
--- /dev/null
+++ b/opengl/tests/copybits/copybits.cpp
@@ -0,0 +1,726 @@
+// Test software OpenGL hardware accelleration using copybits.
+
+#define LOG_TAG "copybits_test"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <ui/PixelFormat.h>
+
+#include <cutils/log.h>
+#include <cutils/native_handle.h>
+
+#include <utils/Atomic.h>
+
+#include <private/ui/SurfaceBuffer.h>
+#include <pixelflinger/pixelflinger.h>
+
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+#define EGL_EGLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+using namespace android;
+
+EGLDisplay eglDisplay;
+EGLSurface eglSurface;
+EGLContext eglContext;
+GLuint texture;
+
+hw_module_t const* gralloc_module;
+alloc_device_t *sAllocDev;
+
+#define FIXED_ONE 0x10000 /* 1.0 in 16.16 fixed point. */
+
+int init_gl_surface();
+void free_gl_surface();
+void init_scene();
+
+int create_physical_texture();
+int readTimer();
+
+// ===========================================================================
+// Buffer an implementation of android_native_buffer_t
+// ===========================================================================
+
+class NativeBuffer;
+
+class Buffer : public android::SurfaceBuffer
+{
+public:
+ // creates w * h buffer
+ Buffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
+
+ // return status
+ status_t initCheck() const;
+
+ uint32_t getWidth() const { return width; }
+ uint32_t getHeight() const { return height; }
+ uint32_t getStride() const { return stride; }
+ uint32_t getUsage() const { return usage; }
+ PixelFormat getPixelFormat() const { return format; }
+
+
+ android_native_buffer_t* getNativeBuffer() const;
+
+ void setPixel(int x, int y, int r, int g, int b, int a);
+
+ status_t lock(GGLSurface* surface, uint32_t usage);
+ void lock() {
+ GGLSurface s;
+ lock(&s, GRALLOC_USAGE_SW_WRITE_OFTEN);
+ mData = (void*)s.data;
+ }
+
+private:
+ friend class LightRefBase<Buffer>;
+ Buffer(const Buffer& rhs);
+ virtual ~Buffer();
+ Buffer& operator = (const Buffer& rhs);
+ const Buffer& operator = (const Buffer& rhs) const;
+
+ status_t initSize(uint32_t w, uint32_t h);
+
+ ssize_t mInitCheck;
+ void* mData;
+};
+
+Buffer::Buffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage)
+ : SurfaceBuffer(), mInitCheck(NO_INIT)
+{
+ this->usage = usage;
+ this->format = format;
+ if (w>0 && h>0) {
+ mInitCheck = initSize(w, h);
+ }
+}
+
+Buffer::~Buffer()
+{
+ if (handle) {
+ sAllocDev->free(sAllocDev, handle);
+ }
+}
+
+status_t Buffer::initCheck() const {
+ return mInitCheck;
+}
+
+android_native_buffer_t* Buffer::getNativeBuffer() const
+{
+ return static_cast<android_native_buffer_t*>(const_cast<Buffer*>(this));
+}
+
+status_t Buffer::initSize(uint32_t w, uint32_t h)
+{
+ status_t err = NO_ERROR;
+
+ err = sAllocDev->alloc(sAllocDev, w, h, format, usage, &handle, &stride);
+
+ if (err == NO_ERROR) {
+ if (err == NO_ERROR) {
+ width = w;
+ height = h;
+ }
+ }
+
+ return err;
+}
+
+status_t Buffer::lock(GGLSurface* sur, uint32_t usage)
+{
+ void* vaddr;
+ status_t res = SurfaceBuffer::lock(usage, &vaddr);
+ if (res == NO_ERROR && sur) {
+ sur->version = sizeof(GGLSurface);
+ sur->width = width;
+ sur->height = height;
+ sur->stride = stride;
+ sur->format = format;
+ sur->data = static_cast<GGLubyte*>(vaddr);
+ }
+ return res;
+}
+
+
+void Buffer::setPixel(int x, int y, int r, int g, int b, int a) {
+ if (x < 0 || (unsigned int) x >= width
+ || y < 0 || (unsigned int) y >= height) {
+ // clipped
+ return;
+ }
+ int index = stride * y + x;
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGB_565: {
+ unsigned short val = (unsigned short) (
+ ((0x1f & (r >> 3)) << 11)
+ | ((0x3f & (g >> 2)) << 5)
+ | (0x1f & (b >> 3)));
+ ((unsigned short*) mData)[index]= val;
+ }
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888: { // ABGR
+ unsigned int val = (unsigned int)
+ (((a & 0xff) << 24)
+ | ((b & 0xff) << 16)
+ | ((g & 0xff) << 8)
+ | (r & 0xff));
+ ((unsigned int*) mData)[index] = val;
+ }
+ break;
+ default:
+ // Unsupported pixel format
+ break;
+ }
+}
+
+
+static void gluLookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ, float upX, float upY,
+ float upZ)
+{
+ // See the OpenGL GLUT documentation for gluLookAt for a description
+ // of the algorithm. We implement it in a straightforward way:
+
+ float fx = centerX - eyeX;
+ float fy = centerY - eyeY;
+ float fz = centerZ - eyeZ;
+
+ // Normalize f
+ float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz);
+ fx *= rlf;
+ fy *= rlf;
+ fz *= rlf;
+
+ // Normalize up
+ float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ);
+ upX *= rlup;
+ upY *= rlup;
+ upZ *= rlup;
+
+ // compute s = f x up (x means "cross product")
+
+ float sx = fy * upZ - fz * upY;
+ float sy = fz * upX - fx * upZ;
+ float sz = fx * upY - fy * upX;
+
+ // compute u = s x f
+ float ux = sy * fz - sz * fy;
+ float uy = sz * fx - sx * fz;
+ float uz = sx * fy - sy * fx;
+
+ float m[16] ;
+ m[0] = sx;
+ m[1] = ux;
+ m[2] = -fx;
+ m[3] = 0.0f;
+
+ m[4] = sy;
+ m[5] = uy;
+ m[6] = -fy;
+ m[7] = 0.0f;
+
+ m[8] = sz;
+ m[9] = uz;
+ m[10] = -fz;
+ m[11] = 0.0f;
+
+ m[12] = 0.0f;
+ m[13] = 0.0f;
+ m[14] = 0.0f;
+ m[15] = 1.0f;
+
+ glMultMatrixf(m);
+ glTranslatef(-eyeX, -eyeY, -eyeZ);
+}
+
+int init_gralloc() {
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &gralloc_module);
+ LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
+
+ if (err == 0) {
+ gralloc_open(gralloc_module, &sAllocDev);
+ }
+ return err;
+}
+
+int init_gl_surface(void)
+{
+ EGLint numConfigs = 1;
+ EGLConfig myConfig = {0};
+ EGLint attrib[] =
+ {
+ EGL_DEPTH_SIZE, 16,
+ EGL_NONE
+ };
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ printf("init_gl_surface\n");
+ if ( (eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY )
+ {
+ printf("eglGetDisplay failed\n");
+ return 0;
+ }
+
+ if ( eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE )
+ {
+ printf("eglInitialize failed\n");
+ return 0;
+ }
+
+ if ( EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig) != 0)
+ {
+ printf("EGLUtils::selectConfigForNativeWindow failed\n");
+ return 0;
+ }
+
+
+ if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig,
+ window, 0)) == EGL_NO_SURFACE )
+ {
+ printf("eglCreateWindowSurface failed\n");
+ return 0;
+ }
+
+ if ( (eglContext = eglCreateContext(eglDisplay, myConfig, 0, 0)) == EGL_NO_CONTEXT )
+ {
+ printf("eglCreateContext failed\n");
+ return 0;
+ }
+
+ if ( eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext) != EGL_TRUE )
+ {
+ printf("eglMakeCurrent failed\n");
+ return 0;
+ }
+
+#if EGL_ANDROID_swap_rectangle
+ eglSetSwapRectangleANDROID(eglDisplay, eglSurface, 0, 0, 320, 480);
+#endif
+
+ return 1;
+}
+
+void free_gl_surface(void)
+{
+ if (eglDisplay != EGL_NO_DISPLAY)
+ {
+ eglMakeCurrent( eglDisplay, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT );
+ eglDestroyContext( eglDisplay, eglContext );
+ eglDestroySurface( eglDisplay, eglSurface );
+ eglTerminate( eglDisplay );
+ eglDisplay = EGL_NO_DISPLAY;
+ }
+}
+
+void init_scene(void)
+{
+ glDisable(GL_DITHER);
+ glEnable(GL_CULL_FACE);
+ float ratio = 320.0f / 480.0f;
+ glViewport(0, 0, 320, 480);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ glLoadIdentity();
+ gluLookAt(
+ 0, 0, 3, // eye
+ 0, 0, 0, // center
+ 0, 1, 0); // up
+
+ glEnable(GL_TEXTURE_2D);
+}
+
+// #define USE_ALPHA_COLOR
+
+#define USE_GL_REPLACE
+//#define USE_GL_MODULATE
+
+// #define USE_BLEND
+
+#define USE_565
+// #define USE_8888
+
+// #define USE_NEAREST
+#define USE_LINEAR
+
+#define USE_SCALE
+
+void setSmoothGradient(Buffer* bufferObject) {
+ int pixels = bufferObject->getHeight() * bufferObject->getWidth();
+ int step = 0;
+ for (unsigned int y = 0; y < bufferObject->getHeight(); y++) {
+ for(unsigned int x = 0; x < bufferObject->getWidth() ; x++) {
+ int grey = step * 255 / pixels;
+ bufferObject->setPixel(x, y, grey, grey, grey, 255);
+ ++step;
+ }
+ }
+}
+
+void setSmoothAlphaGradient(Buffer* bufferObject) {
+ int pixels = bufferObject->getHeight() * bufferObject->getWidth();
+ int step = 0;
+ for (unsigned int y = 0; y < bufferObject->getHeight(); y++) {
+ for(unsigned int x = 0; x < bufferObject->getWidth() ; x++) {
+ int grey = step * 255 / pixels;
+ bufferObject->setPixel(x, y, 255, 255, 255, grey);
+ ++step;
+ }
+ }
+}
+
+void setOrientedCheckerboard(Buffer* bufferObject) {
+ bufferObject->setPixel(0, 0, 0, 0, 0, 255);
+ for(unsigned int x = 1; x < bufferObject->getWidth() ; x++) {
+ bufferObject->setPixel(x, 0, 0, 255, 0, 255);
+ }
+ for (unsigned int y = 1; y < bufferObject->getHeight(); y++) {
+ for(unsigned int x = 0; x < bufferObject->getWidth() ; x++) {
+ if ((x ^ y ) & 1) {
+ bufferObject->setPixel(x, y, 255, 255, 255, 255);
+ } else {
+ bufferObject->setPixel(x, y, 255, 0, 0, 255);
+ }
+ }
+ }
+}
+
+int create_physical_texture(unsigned int w, unsigned int h)
+{
+
+#ifdef USE_565
+ PixelFormat format = HAL_PIXEL_FORMAT_RGB_565;
+#else
+ PixelFormat format = HAL_PIXEL_FORMAT_RGBA_8888;
+#endif
+ int usage = GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_TEXTURE |
+ GRALLOC_USAGE_HW_2D; /* This is the key to allocating the texture in pmem. */
+ int32_t stride;
+ buffer_handle_t handle;
+
+ // Allocate the hardware buffer
+ Buffer* bufferObject = new Buffer(w, h, format, usage);
+
+ android_native_buffer_t* buffer = bufferObject->getNativeBuffer();
+
+ buffer->common.incRef(&buffer->common);
+
+ // create the new EGLImageKHR
+ EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_NONE };
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ (EGLClientBuffer)buffer, attrs);
+ if (image == EGL_NO_IMAGE_KHR) {
+ printf("Could not create an image %d\n", eglGetError());
+ return -1;
+ }
+
+ bufferObject->lock();
+ setOrientedCheckerboard(bufferObject);
+ // setSmoothGradient(bufferObject);
+ // setSmoothAlphaGradient(bufferObject);
+ bufferObject->unlock();
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+#ifdef USE_LINEAR
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#elif defined(USE_NEAREST)
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#endif
+
+#ifdef USE_GL_REPLACE
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+#elif defined(USE_GL_MODULATE)
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+#endif
+
+#ifdef USE_ALPHA_COLOR
+ glColor4f(1.0f, 1.0f, 1.0f, 0.4f);
+#else
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+#endif
+
+#ifdef USE_BLEND
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+#endif
+ return 0;
+}
+
+static const int SCALE_COUNT = 12;
+
+int scale(int base, int factor) {
+ static const float kTable[SCALE_COUNT] = {
+ 0.24f, 0.25f, 0.5f, 0.75f, 1.0f,
+ 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 5.0f
+ };
+ return base * kTable[factor];
+}
+
+class Timer {
+ struct timeval first;
+ double elapsedSeconds;
+
+public:
+ Timer() {}
+ void start() {
+ gettimeofday(&first, NULL);
+ }
+
+ void stop() {
+ struct timeval second,
+ elapsed;
+ gettimeofday(&second, NULL);
+
+ if (first.tv_usec > second.tv_usec) {
+ second.tv_usec += 1000000;
+ second.tv_sec--;
+ }
+
+ elapsedSeconds = (second.tv_sec - first.tv_sec) +
+ (second.tv_usec - first.tv_usec) / 1000000.0;
+ }
+
+ double getElapsedSeconds() {
+ return elapsedSeconds;
+ }
+
+ double getElapsedMs() {
+ return elapsedSeconds* 1000.0f;
+ }
+};
+
+int testTime()
+{
+ static const int WIDTH = 320;
+ static const int HEIGHT = 480;
+ static const int SCALE = 8;
+
+ if (create_physical_texture(WIDTH, HEIGHT) != 0) {
+ return -1;
+ }
+ // Need to do a dummy eglSwapBuffers first. Don't know why.
+ glClearColor(0.4, 1.0, 0.4, 0.4);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(eglDisplay, eglSurface);
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+
+#if defined(USE_SCALE)
+ static const int scaleOffset = 0;
+#else
+ static const int scaleOffset = 1;
+#endif
+ printf("ms\n");
+ for(int j = 0; j < SCALE; j++) {
+ int w = WIDTH >> (j + scaleOffset);
+ int h = HEIGHT >> j;
+ int cropRect[4] = {0,h,w,-h}; // Left bottom width height. Width and Height can be neg to flip.
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
+ Timer timer;
+ timer.start();
+
+ int copyCount = 1000;
+ for (int i = 0; i < copyCount; i++) {
+ glDrawTexiOES(0, 0, 0, w, h);
+ }
+
+ timer.stop();
+ printf("%g\n", timer.getElapsedMs() / copyCount);
+ }
+
+ eglSwapBuffers(eglDisplay, eglSurface);
+ return 0;
+}
+
+int testStretch()
+{
+ static const int WIDTH = 8;
+ static const int HEIGHT = 8;
+
+ if (create_physical_texture(WIDTH, HEIGHT) != 0) {
+ return -1;
+ }
+ // Need to do a dummy eglSwapBuffers first. Don't know why.
+ glClearColor(0.4, 1.0, 0.4, 1.0);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(eglDisplay, eglSurface);
+
+ int cropRect[4] = {0,HEIGHT,WIDTH,-HEIGHT}; // Left bottom width height. Width and Height can be neg to flip.
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
+
+ for(int frame = 0; frame < 2; frame++) {
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ int baseX = 10;
+ for (int x = 0; x < SCALE_COUNT; x++) {
+ int baseY = 10;
+ int width = scale(WIDTH, x);
+ for (int y = 0; y < SCALE_COUNT; y++) {
+ int height = scale(HEIGHT, y);
+ glDrawTexxOES(baseX << 16, baseY << 16, 0, width << 16, height << 16);
+ baseY += height + 10;
+ }
+ baseX += width + 10;
+ }
+
+ eglSwapBuffers(eglDisplay, eglSurface);
+ LOGD("wait 1s");
+ usleep(1000000);
+ }
+ return 0;
+}
+
+int testRot90()
+{
+ static const int WIDTH = 8;
+ static const int HEIGHT = 8;
+
+ if (create_physical_texture(WIDTH, HEIGHT) != 0) {
+ return -1;
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, 320, 480, 0, 0, 1);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ glLoadIdentity();
+
+ // Need to do a dummy eglSwapBuffers first. Don't know why.
+ glClearColor(0.4, 0.4, 0.4, 0.4);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(eglDisplay, eglSurface);
+
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
+ glDisable(GL_BLEND);
+ glShadeModel(GL_FLAT);
+ glDisable(GL_DITHER);
+ glDisable(GL_CULL_FACE);
+
+ for(int frame = 0; frame < 2; frame++) {
+ LOGD("frame = %d", frame);
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+ int baseX = 10;
+ for (int x = 0; x < SCALE_COUNT; x++) {
+ int baseY = 10;
+ int width = scale(WIDTH, x);
+ for (int y = 0; y < SCALE_COUNT; y++) {
+ int height = scale(HEIGHT, y);
+
+ // Code copied from SurfaceFlinger LayerBase.cpp
+
+ const GLfixed texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 0x10000 },
+ { 0x10000, 0x10000 },
+ { 0x10000, 0 }
+ };
+
+ GLfixed fx = baseX << 16;
+ GLfixed fy = baseY << 16;
+ GLfixed fw = width << 16;
+ GLfixed fh = height << 16;
+
+ /*
+ * Vertex pattern:
+ * (2)--(3)
+ * |\ |
+ * | \ |
+ * | \ |
+ * | \|
+ * (1)--(0)
+ *
+ */
+
+ const GLfixed vertices[4][2] = {
+ {fx + fw, fy},
+ {fx, fy},
+ {fx, fy + fh},
+ {fx + fw, fy + fh}
+ };
+
+ static const bool rotate90 = true;
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FIXED, 0, vertices);
+ glTexCoordPointer(2, GL_FIXED, 0, texCoords);
+
+ LOGD("testRot90 %d, %d %d, %d", baseX, baseY, width, height);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ baseY += height + 10;
+ }
+ baseX += width + 10;
+ }
+
+ eglSwapBuffers(eglDisplay, eglSurface);
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+
+ int q;
+ int start, end;
+
+ if (init_gralloc()) {
+ printf("gralloc initialization failed - exiting\n");
+ return 0;
+ }
+
+ printf("Initializing EGL...\n");
+
+ if(!init_gl_surface())
+ {
+ printf("GL initialisation failed - exiting\n");
+ return 0;
+ }
+
+ init_scene();
+
+ printf("Start test...\n");
+ // testTime();
+ testStretch();
+ //testRot90();
+ free_gl_surface();
+
+ return 0;
+}
diff --git a/opengl/tests/fillrate/Android.mk b/opengl/tests/fillrate/Android.mk
new file mode 100644
index 0000000..a7d30c2
--- /dev/null
+++ b/opengl/tests/fillrate/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ fillrate.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-fillrate
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp
new file mode 100644
index 0000000..911d354
--- /dev/null
+++ b/opengl/tests/fillrate/fillrate.cpp
@@ -0,0 +1,161 @@
+/*
+**
+** 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 "fillrate"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/StopWatch.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+
+ printf("w=%d, h=%d\n", w, h);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1,1,1,1);
+
+ uint32_t* t32 = (uint32_t*)malloc(512*512*4);
+ for (int y=0 ; y<512 ; y++) {
+ for (int x=0 ; x<512 ; x++) {
+ int u = x-256;
+ int v = y-256;
+ if (u*u+v*v < 256*256) {
+ t32[x+y*512] = 0x10FFFFFF;
+ } else {
+ t32[x+y*512] = 0x20FF0000;
+ }
+ }
+ }
+
+ const GLfloat vertices[4][2] = {
+ { 0, 0 },
+ { 0, h },
+ { w, h },
+ { w, 0 }
+ };
+
+ const GLfloat texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 1 },
+ { 1, 0 }
+ };
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, w, 0, h, 0, 1);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+
+ eglSwapInterval(dpy, 1);
+
+ glClearColor(1,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ eglSwapBuffers(dpy, surface);
+
+
+ nsecs_t times[32];
+
+ for (int c=1 ; c<32 ; c++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (int i=0 ; i<c ; i++) {
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ eglSwapBuffers(dpy, surface);
+ }
+
+
+ // for (int c=31 ; c>=1 ; c--) {
+ int j=0;
+ for (int c=1 ; c<32 ; c++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ nsecs_t now = systemTime();
+ for (int i=0 ; i<c ; i++) {
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+ eglSwapBuffers(dpy, surface);
+ nsecs_t t = systemTime() - now;
+ times[j++] = t;
+ }
+
+ for (int c=1, j=0 ; c<32 ; c++, j++) {
+ nsecs_t t = times[j];
+ printf("%lld\t%d\t%f\n", t, c, (double(t)/c)/1000000.0);
+ }
+
+
+
+ eglTerminate(dpy);
+
+ return 0;
+}
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
index 31b7d9a..a254127 100644
--- a/opengl/tests/filter/Android.mk
+++ b/opengl/tests/filter/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- filter.c
+ filter.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -14,4 +14,6 @@ LOCAL_MODULE:= test-opengl-filter
LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/filter/filter.c b/opengl/tests/filter/filter.c
deleted file mode 100644
index de97119..0000000
--- a/opengl/tests/filter/filter.c
+++ /dev/null
@@ -1,130 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <EGL/egl.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-int main(int argc, char** argv)
-{
- if (argc!=2 && argc!=3) {
- printf("usage: %s <0-6> [pbuffer]\n", argv[0]);
- return 0;
- }
-
- const int test = atoi(argv[1]);
- int usePbuffer = argc==3 && !strcmp(argv[2], "pbuffer");
- EGLint s_configAttribs[] = {
- EGL_SURFACE_TYPE, EGL_PBUFFER_BIT|EGL_WINDOW_BIT,
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_NONE
- };
-
- EGLint numConfigs = -1;
- EGLint majorVersion;
- EGLint minorVersion;
- EGLConfig config;
- EGLContext context;
- EGLSurface surface;
- EGLint w, h;
-
- EGLDisplay dpy;
-
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(dpy, &majorVersion, &minorVersion);
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- if (!usePbuffer) {
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
- } else {
- printf("using pbuffer\n");
- EGLint attribs[] = { EGL_WIDTH, 320, EGL_HEIGHT, 480, EGL_NONE };
- surface = eglCreatePbufferSurface(dpy, config, attribs);
- if (surface == EGL_NO_SURFACE) {
- printf("eglCreatePbufferSurface error %x\n", eglGetError());
- }
- }
- context = eglCreateContext(dpy, config, NULL, NULL);
- eglMakeCurrent(dpy, surface, surface, context);
- eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
- eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
- GLint dim = w<h ? w : h;
-
- glClear(GL_COLOR_BUFFER_BIT);
-
- GLint crop[4] = { 0, 4, 4, -4 };
- glBindTexture(GL_TEXTURE_2D, 0);
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glEnable(GL_TEXTURE_2D);
- glColor4f(1,1,1,1);
-
- // packing is always 4
- uint8_t t8[] = {
- 0x00, 0x55, 0x00, 0x55,
- 0xAA, 0xFF, 0xAA, 0xFF,
- 0x00, 0x55, 0x00, 0x55,
- 0xAA, 0xFF, 0xAA, 0xFF };
-
- uint16_t t16[] = {
- 0x0000, 0x5555, 0x0000, 0x5555,
- 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
- 0x0000, 0x5555, 0x0000, 0x5555,
- 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF };
-
- uint16_t t5551[] = {
- 0x0000, 0xFFFF, 0x0000, 0xFFFF,
- 0xFFFF, 0x0000, 0xFFFF, 0x0000,
- 0x0000, 0xFFFF, 0x0000, 0xFFFF,
- 0xFFFF, 0x0000, 0xFFFF, 0x0000 };
-
- uint32_t t32[] = {
- 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
- 0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF,
- 0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00,
- 0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
- };
-
- switch(test)
- {
- case 1:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
- 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
- break;
- case 2:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
- break;
- case 3:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
- break;
- case 4:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
- 4, 4, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, t16);
- break;
- case 5:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, t5551);
- break;
- case 6:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
- break;
- }
-
- glDrawTexiOES(0, 0, 0, dim, dim);
-
- if (!usePbuffer) {
- eglSwapBuffers(dpy, surface);
- } else {
- glFinish();
- }
-
- eglTerminate(dpy);
- return 0;
-}
diff --git a/opengl/tests/filter/filter.cpp b/opengl/tests/filter/filter.cpp
new file mode 100644
index 0000000..2351909
--- /dev/null
+++ b/opengl/tests/filter/filter.cpp
@@ -0,0 +1,190 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+#define USE_DRAW_TEXTURE 1
+
+int main(int argc, char** argv)
+{
+ if (argc!=2 && argc!=3) {
+ printf("usage: %s <0-6> [pbuffer]\n", argv[0]);
+ return 0;
+ }
+
+ const int test = atoi(argv[1]);
+ int usePbuffer = argc==3 && !strcmp(argv[2], "pbuffer");
+ EGLint s_configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT|EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_NONE
+ };
+
+ EGLint numConfigs = -1;
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLConfig config;
+ EGLContext context;
+ EGLSurface surface;
+ EGLint w, h;
+
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = 0;
+ if (!usePbuffer) {
+ window = android_createDisplaySurface();
+ }
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+ if (!usePbuffer) {
+ EGLUtils::selectConfigForNativeWindow(
+ dpy, s_configAttribs, window, &config);
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ } else {
+ printf("using pbuffer\n");
+ eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
+ EGLint attribs[] = { EGL_WIDTH, 320, EGL_HEIGHT, 480, EGL_NONE };
+ surface = eglCreatePbufferSurface(dpy, config, attribs);
+ if (surface == EGL_NO_SURFACE) {
+ printf("eglCreatePbufferSurface error %x\n", eglGetError());
+ }
+ }
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ GLint dim = w<h ? w : h;
+
+ glViewport(0, 0, w, h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, w, 0, h, 0, 1);
+
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ GLint crop[4] = { 0, 4, 4, -4 };
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1,1,1,1);
+
+ // packing is always 4
+ uint8_t t8[] = {
+ 0x00, 0x55, 0x00, 0x55,
+ 0xAA, 0xFF, 0xAA, 0xFF,
+ 0x00, 0x55, 0x00, 0x55,
+ 0xAA, 0xFF, 0xAA, 0xFF };
+
+ uint16_t t16[] = {
+ 0x0000, 0x5555, 0x0000, 0x5555,
+ 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
+ 0x0000, 0x5555, 0x0000, 0x5555,
+ 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF };
+
+ uint16_t t5551[] = {
+ 0x0000, 0xFFFF, 0x0000, 0xFFFF,
+ 0xFFFF, 0x0000, 0xFFFF, 0x0000,
+ 0x0000, 0xFFFF, 0x0000, 0xFFFF,
+ 0xFFFF, 0x0000, 0xFFFF, 0x0000 };
+
+ uint32_t t32[] = {
+ 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
+ 0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF,
+ 0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00,
+ 0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
+ };
+
+ switch(test)
+ {
+ case 1:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
+ 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
+ break;
+ case 2:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
+ break;
+ case 3:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
+ break;
+ case 4:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
+ 4, 4, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, t16);
+ break;
+ case 5:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, t5551);
+ break;
+ case 6:
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+ break;
+ }
+
+ //glDrawTexiOES(0, 0, 0, dim, dim);
+
+ const GLfloat vertices[4][2] = {
+ { 0, 0 },
+ { 0, dim },
+ { dim, dim },
+ { dim, 0 }
+ };
+
+ const GLfloat texCoords[4][2] = {
+ { 0, 0 },
+ { 0, 1 },
+ { 1, 1 },
+ { 1, 0 }
+ };
+
+ if (!usePbuffer) {
+ eglSwapBuffers(dpy, surface);
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glScissor(0,dim,dim,h-dim);
+ glDisable(GL_SCISSOR_TEST);
+
+ for (int y=0 ; y<dim ; y++) {
+ //glDisable(GL_SCISSOR_TEST);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ //glEnable(GL_SCISSOR_TEST);
+
+#if USE_DRAW_TEXTURE && GL_OES_draw_texture
+ glDrawTexiOES(0, y, 1, dim, dim);
+#else
+ glLoadIdentity();
+ glTranslatef(0, y, 0);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+#endif
+
+ if (!usePbuffer) {
+ eglSwapBuffers(dpy, surface);
+ } else {
+ glFinish();
+ }
+ }
+
+ eglTerminate(dpy);
+ return 0;
+}
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
index 8b46cd7..5620814 100644
--- a/opengl/tests/finish/Android.mk
+++ b/opengl/tests/finish/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- finish.c
+ finish.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -14,4 +14,6 @@ LOCAL_MODULE:= test-opengl-finish
LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/finish.c b/opengl/tests/finish/finish.c
deleted file mode 100644
index 45fc758..0000000
--- a/opengl/tests/finish/finish.c
+++ /dev/null
@@ -1,224 +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.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-#include <sched.h>
-#include <sys/resource.h>
-
-#include <EGL/egl.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-
-long long systemTime()
-{
- struct timespec t;
- t.tv_sec = t.tv_nsec = 0;
- clock_gettime(CLOCK_MONOTONIC, &t);
- return (long long)(t.tv_sec)*1000000000LL + t.tv_nsec;
-}
-
-int main(int argc, char** argv)
-{
- EGLint s_configAttribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_NONE
- };
-
- EGLint numConfigs = -1;
- EGLint majorVersion;
- EGLint minorVersion;
- EGLConfig config;
- EGLContext context;
- EGLSurface surface;
- EGLint w, h;
-
- EGLDisplay dpy;
-
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(dpy, &majorVersion, &minorVersion);
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
- context = eglCreateContext(dpy, config, NULL, NULL);
- eglMakeCurrent(dpy, surface, surface, context);
- eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
- eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
- GLint dim = w<h ? w : h;
-
- glBindTexture(GL_TEXTURE_2D, 0);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glEnable(GL_TEXTURE_2D);
- glColor4f(1,1,1,1);
- glDisable(GL_DITHER);
- glShadeModel(GL_FLAT);
-
- long long now, t;
- int i;
-
- char* texels = malloc(512*512*2);
- memset(texels,0xFF,512*512*2);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- 512, 512, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texels);
-
- char* dst = malloc(320*480*2);
- memset(dst, 0, 320*480*2);
- printf("307200 bytes memcpy\n");
- for (i=0 ; i<4 ; i++) {
- now = systemTime();
- memcpy(dst, texels, 320*480*2);
- t = systemTime();
- printf("memcpy() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- }
- free(dst);
-
- free(texels);
-
- setpriority(PRIO_PROCESS, 0, -20);
-
- printf("512x512 unmodified texture, 512x512 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 512, 512, -512 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 512, 512);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
- printf("512x512 unmodified texture, 1x1 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 1, 1, -1 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 1, 1);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
- printf("512x512 unmodified texture, 512x512 blit (x2):\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 512, 512, -512 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 512, 512);
- glDrawTexiOES(0, 0, 0, 512, 512);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
- printf("512x512 unmodified texture, 1x1 blit (x2):\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 1, 1, -1 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 1, 1);
- glDrawTexiOES(0, 0, 0, 1, 1);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
-
- printf("512x512 (1x1 texel MODIFIED texture), 512x512 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- uint16_t green = 0x7E0;
- GLint crop[4] = { 0, 512, 512, -512 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &green);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 512, 512);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
-
- int16_t texel = 0xF800;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &texel);
-
- printf("1x1 unmodified texture, 1x1 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 1, 1, -1 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 1, 1);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- eglSwapBuffers(dpy, surface);
- }
-
- printf("1x1 unmodified texture, 512x512 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- GLint crop[4] = { 0, 1, 1, -1 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 512, 512);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
- printf("1x1 (1x1 texel MODIFIED texture), 512x512 blit:\n");
- glClear(GL_COLOR_BUFFER_BIT);
- for (i=0 ; i<4 ; i++) {
- uint16_t green = 0x7E0;
- GLint crop[4] = { 0, 1, 1, -1 };
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &green);
- now = systemTime();
- glDrawTexiOES(0, 0, 0, 1, 1);
- glFinish();
- t = systemTime();
- printf("glFinish() time = %llu us\n", (t-now)/1000);
- fflush(stdout);
- eglSwapBuffers(dpy, surface);
- }
-
- return 0;
-}
diff --git a/opengl/tests/finish/finish.cpp b/opengl/tests/finish/finish.cpp
new file mode 100644
index 0000000..91f5c45
--- /dev/null
+++ b/opengl/tests/finish/finish.cpp
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/Timers.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ GLint dim = w<h ? w : h;
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1,1,1,1);
+ glDisable(GL_DITHER);
+ glShadeModel(GL_FLAT);
+
+ long long now, t;
+ int i;
+
+ char* texels = (char*)malloc(512*512*2);
+ memset(texels,0xFF,512*512*2);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ 512, 512, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texels);
+
+ char* dst = (char*)malloc(320*480*2);
+ memset(dst, 0, 320*480*2);
+ printf("307200 bytes memcpy\n");
+ for (i=0 ; i<4 ; i++) {
+ now = systemTime();
+ memcpy(dst, texels, 320*480*2);
+ t = systemTime();
+ printf("memcpy() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ }
+ free(dst);
+
+ free(texels);
+
+ setpriority(PRIO_PROCESS, 0, -20);
+
+ printf("512x512 unmodified texture, 512x512 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 512, 512, -512 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 512, 512);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ printf("512x512 unmodified texture, 1x1 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 1, 1, -1 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 1, 1);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ printf("512x512 unmodified texture, 512x512 blit (x2):\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 512, 512, -512 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 512, 512);
+ glDrawTexiOES(0, 0, 0, 512, 512);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ printf("512x512 unmodified texture, 1x1 blit (x2):\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 1, 1, -1 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 1, 1);
+ glDrawTexiOES(0, 0, 0, 1, 1);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+
+ printf("512x512 (1x1 texel MODIFIED texture), 512x512 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ uint16_t green = 0x7E0;
+ GLint crop[4] = { 0, 512, 512, -512 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &green);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 512, 512);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+
+ int16_t texel = 0xF800;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &texel);
+
+ printf("1x1 unmodified texture, 1x1 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 1, 1, -1 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 1, 1);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ printf("1x1 unmodified texture, 512x512 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ GLint crop[4] = { 0, 1, 1, -1 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 512, 512);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ printf("1x1 (1x1 texel MODIFIED texture), 512x512 blit:\n");
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (i=0 ; i<4 ; i++) {
+ uint16_t green = 0x7E0;
+ GLint crop[4] = { 0, 1, 1, -1 };
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &green);
+ now = systemTime();
+ glDrawTexiOES(0, 0, 0, 1, 1);
+ glFinish();
+ t = systemTime();
+ printf("glFinish() time = %llu us\n", (t-now)/1000);
+ fflush(stdout);
+ eglSwapBuffers(dpy, surface);
+ }
+
+ return 0;
+}
diff --git a/opengl/tests/swapinterval/Android.mk b/opengl/tests/swapinterval/Android.mk
new file mode 100644
index 0000000..619447c
--- /dev/null
+++ b/opengl/tests/swapinterval/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ swapinterval.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv1_CM \
+ libui
+
+LOCAL_MODULE:= test-opengl-swapinterval
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
new file mode 100644
index 0000000..df53b62
--- /dev/null
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -0,0 +1,121 @@
+/*
+ **
+ ** 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/StopWatch.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLint numConfigs=0;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, 0 ,0) ;//&majorVersion, &minorVersion);
+ eglGetConfigs(dpy, NULL, 0, &numConfigs);
+ printf("# configs = %d\n", numConfigs);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ EGLint r,g,b,a;
+ eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ if (surface == EGL_NO_SURFACE) {
+ EGLint err = eglGetError();
+ fprintf(stderr, "%s, config=%p, format = %d-%d-%d-%d\n",
+ EGLUtils::strerror(err), config, r,g,b,a);
+ return 0;
+ } else {
+ printf("config=%p, format = %d-%d-%d-%d\n", config, r,g,b,a);
+ }
+
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+
+ printf("w=%d, h=%d\n", w, h);
+
+ glDisable(GL_DITHER);
+ glEnable(GL_BLEND);
+
+ glViewport(0, 0, w, h);
+ glOrthof(0, w, 0, h, 0, 1);
+
+ eglSwapInterval(dpy, 1);
+
+ glClearColor(1,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(dpy, surface);
+
+
+ int time = 10;
+ printf("screen should flash red/green quickly for %d s...\n", time);
+
+ int c = 0;
+ nsecs_t start = systemTime();
+ nsecs_t t;
+ do {
+ glClearColor(1,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(dpy, surface);
+ glClearColor(0,1,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(dpy, surface);
+ t = systemTime() - start;
+ c += 2;
+ } while (int(ns2s(t))<=time);
+
+ double p = (double(t) / c) / 1000000000.0;
+ printf("refresh-rate is %f fps (%f ms)\n", 1.0f/p, p*1000.0);
+
+ eglTerminate(dpy);
+
+ return 0;
+}
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
index 8d5f56d..b2fa185 100644
--- a/opengl/tests/textures/Android.mk
+++ b/opengl/tests/textures/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- textures.c
+ textures.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -14,4 +14,6 @@ LOCAL_MODULE:= test-opengl-textures
LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/textures/textures.c b/opengl/tests/textures/textures.c
deleted file mode 100644
index 214291b..0000000
--- a/opengl/tests/textures/textures.c
+++ /dev/null
@@ -1,109 +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.
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <EGL/egl.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-int main(int argc, char** argv)
-{
- EGLint s_configAttribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_NONE
- };
-
- EGLint numConfigs = -1;
- EGLint majorVersion;
- EGLint minorVersion;
- EGLConfig config;
- EGLContext context;
- EGLSurface surface;
- EGLint w, h;
-
- EGLDisplay dpy;
-
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(dpy, &majorVersion, &minorVersion);
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
- context = eglCreateContext(dpy, config, NULL, NULL);
- eglMakeCurrent(dpy, surface, surface, context);
- eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
- eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
- GLint dim = w<h ? w : h;
-
-
- GLint crop[4] = { 0, 4, 4, -4 };
- glBindTexture(GL_TEXTURE_2D, 0);
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glEnable(GL_TEXTURE_2D);
- glColor4f(1,1,1,1);
-
- // packing is always 4
- uint8_t t8[] = {
- 0x00, 0x55, 0x00, 0x55,
- 0xAA, 0xFF, 0xAA, 0xFF,
- 0x00, 0x55, 0x00, 0x55,
- 0xAA, 0xFF, 0xAA, 0xFF };
-
- uint16_t t16[] = {
- 0x0000, 0x5555, 0x0000, 0x5555,
- 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
- 0x0000, 0x5555, 0x0000, 0x5555,
- 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF };
-
- uint16_t t5551[] = {
- 0x0000, 0xFFFF, 0x0000, 0xFFFF,
- 0xFFFF, 0x0000, 0xFFFF, 0x0000,
- 0x0000, 0xFFFF, 0x0000, 0xFFFF,
- 0xFFFF, 0x0000, 0xFFFF, 0x0000 };
-
- uint32_t t32[] = {
- 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
- 0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF,
- 0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00,
- 0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
- };
-
-
- glClear(GL_COLOR_BUFFER_BIT);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
- glDrawTexiOES(0, 0, 0, dim/2, dim/2);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
- glDrawTexiOES(dim/2, 0, 0, dim/2, dim/2);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
- glDrawTexiOES(0, dim/2, 0, dim/2, dim/2);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
- glDrawTexiOES(dim/2, dim/2, 0, dim/2, dim/2);
-
- eglSwapBuffers(dpy, surface);
- return 0;
-}
diff --git a/opengl/tests/textures/textures.cpp b/opengl/tests/textures/textures.cpp
new file mode 100644
index 0000000..cbe8ffd
--- /dev/null
+++ b/opengl/tests/textures/textures.cpp
@@ -0,0 +1,118 @@
+/*
+**
+** 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.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+ EGLint configAttribs[] = {
+ EGL_DEPTH_SIZE, 0,
+ EGL_NONE
+ };
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface surface;
+ EGLint w, h;
+ EGLDisplay dpy;
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
+
+ status_t err = EGLUtils::selectConfigForNativeWindow(
+ dpy, configAttribs, window, &config);
+ if (err) {
+ fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ return 0;
+ }
+
+ surface = eglCreateWindowSurface(dpy, config, window, NULL);
+ context = eglCreateContext(dpy, config, NULL, NULL);
+ eglMakeCurrent(dpy, surface, surface, context);
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+ GLint dim = w<h ? w : h;
+
+
+ GLint crop[4] = { 0, 4, 4, -4 };
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1,1,1,1);
+
+ // packing is always 4
+ uint8_t t8[] = {
+ 0x00, 0x55, 0x00, 0x55,
+ 0xAA, 0xFF, 0xAA, 0xFF,
+ 0x00, 0x55, 0x00, 0x55,
+ 0xAA, 0xFF, 0xAA, 0xFF };
+
+ uint16_t t16[] = {
+ 0x0000, 0x5555, 0x0000, 0x5555,
+ 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
+ 0x0000, 0x5555, 0x0000, 0x5555,
+ 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF };
+
+ uint16_t t5551[] = {
+ 0x0000, 0xFFFF, 0x0000, 0xFFFF,
+ 0xFFFF, 0x0000, 0xFFFF, 0x0000,
+ 0x0000, 0xFFFF, 0x0000, 0xFFFF,
+ 0xFFFF, 0x0000, 0xFFFF, 0x0000 };
+
+ uint32_t t32[] = {
+ 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
+ 0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF,
+ 0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00,
+ 0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
+ };
+
+
+ glClear(GL_COLOR_BUFFER_BIT);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
+ glDrawTexiOES(0, 0, 0, dim/2, dim/2);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
+ glDrawTexiOES(dim/2, 0, 0, dim/2, dim/2);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
+ glDrawTexiOES(0, dim/2, 0, dim/2, dim/2);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+ glDrawTexiOES(dim/2, dim/2, 0, dim/2, dim/2);
+
+ eglSwapBuffers(dpy, surface);
+ return 0;
+}
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index d84572b..af0a1bd 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -2,6 +2,8 @@
package="com.android.providers.settings"
android:sharedUserId="android.uid.system">
+ <uses-permission android:name="android.permission.BACKUP_DATA" />
+
<application android:allowClearUserData="false"
android:label="@string/app_label"
android:process="system"
diff --git a/packages/SettingsProvider/etc/bookmarks.xml b/packages/SettingsProvider/etc/bookmarks.xml
index 5af416a..734e0cd 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"
diff --git a/packages/SettingsProvider/res/values-ja/strings.xml b/packages/SettingsProvider/res/values-ja/strings.xml
deleted file mode 100644
index ffd57e6..0000000
--- a/packages/SettingsProvider/res/values-ja/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4567566098528588863">"ストレージã®è¨­å®š"</string>
-</resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index f60ea57..6b20445 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -22,6 +22,7 @@
<bool name="def_airplane_mode_on">false</bool>
<!-- Comma-separated list of bluetooth, wifi, and cell. -->
<string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi</string>
+ <string name="airplane_mode_toggleable_radios" translatable="false">wifi</string>
<bool name="def_auto_time">true</bool>
<bool name="def_accelerometer_rotation">true</bool>
<!-- Default screen brightness, from 0 to 255. 102 is 40%. -->
@@ -36,6 +37,7 @@
user opt-in via Setup Wizard or Settings.
-->
<string name="def_location_providers_allowed" translatable="false">gps</string>
+ <bool name="assisted_gps_enabled">true</bool>
<!-- 0 == mobile, 1 == wifi. -->
<integer name="def_network_preference">1</integer>
<bool name="def_usb_mass_storage_enabled">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 6dd1175..8f4061e 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.
*/
@@ -64,7 +64,7 @@ class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "SettingsProvider";
private static final String DATABASE_NAME = "settings.db";
- private static final int DATABASE_VERSION = 35;
+ private static final int DATABASE_VERSION = 39;
private Context mContext;
@@ -397,9 +397,66 @@ class DatabaseHelper extends SQLiteOpenHelper {
} finally {
db.endTransaction();
}
- upgradeVersion = 35;
}
-
+ // due to a botched merge from donut to eclair, the initialization of ASSISTED_GPS_ENABLED
+ // was accidentally done out of order here.
+ // to fix this, ASSISTED_GPS_ENABLED is now initialized while upgrading from 38 to 39,
+ // and we intentionally do nothing from 35 to 36 now.
+ if (upgradeVersion == 35) {
+ upgradeVersion = 36;
+ }
+
+ if (upgradeVersion == 36) {
+ // This upgrade adds the STREAM_SYSTEM_ENFORCED type to the list of
+ // types affected by ringer modes (silent, vibrate, etc.)
+ db.beginTransaction();
+ try {
+ db.execSQL("DELETE FROM system WHERE name='"
+ + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "'");
+ int newValue = (1 << AudioManager.STREAM_RING)
+ | (1 << AudioManager.STREAM_NOTIFICATION)
+ | (1 << AudioManager.STREAM_SYSTEM)
+ | (1 << AudioManager.STREAM_SYSTEM_ENFORCED);
+ db.execSQL("INSERT INTO system ('name', 'value') values ('"
+ + Settings.System.MODE_RINGER_STREAMS_AFFECTED + "', '"
+ + String.valueOf(newValue) + "')");
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ upgradeVersion = 37;
+ }
+
+ if (upgradeVersion == 37) {
+ db.beginTransaction();
+ try {
+ SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
+ + " VALUES(?,?);");
+ loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
+ R.string.airplane_mode_toggleable_radios);
+ stmt.close();
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ upgradeVersion = 38;
+ }
+
+ if (upgradeVersion == 38) {
+ db.beginTransaction();
+ try {
+ String value =
+ mContext.getResources().getBoolean(R.bool.assisted_gps_enabled) ? "1" : "0";
+ db.execSQL("INSERT OR IGNORE INTO secure(name,value) values('" +
+ Settings.Secure.ASSISTED_GPS_ENABLED + "','" + value + "');");
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+
+ upgradeVersion = 39;
+ }
+
if (upgradeVersion != currentVersion) {
Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
+ ", must wipe the settings provider");
@@ -560,7 +617,7 @@ class DatabaseHelper extends SQLiteOpenHelper {
// By default, only the ring/notification and system streams are affected
loadSetting(stmt, Settings.System.MODE_RINGER_STREAMS_AFFECTED,
(1 << AudioManager.STREAM_RING) | (1 << AudioManager.STREAM_NOTIFICATION) |
- (1 << AudioManager.STREAM_SYSTEM));
+ (1 << AudioManager.STREAM_SYSTEM) | (1 << AudioManager.STREAM_SYSTEM_ENFORCED));
loadSetting(stmt, Settings.System.MUTE_STREAMS_AFFECTED,
((1 << AudioManager.STREAM_MUSIC) |
@@ -627,6 +684,9 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_RADIOS,
R.string.def_airplane_mode_radios);
+ loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
+ R.string.airplane_mode_toggleable_radios);
+
loadBooleanSetting(stmt, Settings.System.AUTO_TIME,
R.bool.def_auto_time); // Sync time to NITZ
@@ -667,6 +727,9 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadStringSetting(stmt, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
R.string.def_location_providers_allowed);
+ loadBooleanSetting(stmt, Settings.Secure.ASSISTED_GPS_ENABLED,
+ R.bool.assisted_gps_enabled);
+
loadIntegerSetting(stmt, Settings.Secure.NETWORK_PREFERENCE,
R.integer.def_network_preference);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 2b36904..56a279a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -30,7 +30,7 @@ import java.util.zip.CRC32;
import android.backup.BackupDataInput;
import android.backup.BackupDataOutput;
import android.backup.BackupHelperAgent;
-import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
@@ -83,6 +83,11 @@ public class SettingsBackupAgent extends BackupHelperAgent {
};
private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
+
+ // the key to store the WIFI data under, should be sorted as last, so restore happens last.
+ // use very late unicode character to quasi-guarantee last sort position.
+ private static final String KEY_WIFI_SUPPLICANT = "\uffeeWIFI";
+
private static final String FILE_BT_ROOT = "/data/misc/hcid/";
private SettingsHelper mSettingsHelper;
@@ -113,7 +118,7 @@ public class SettingsBackupAgent extends BackupHelperAgent {
stateChecksums[STATE_LOCALE] =
writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
stateChecksums[STATE_WIFI] =
- writeIfChanged(stateChecksums[STATE_WIFI], FILE_WIFI_SUPPLICANT, wifiData, data);
+ writeIfChanged(stateChecksums[STATE_WIFI], KEY_WIFI_SUPPLICANT, wifiData, data);
writeNewChecksums(stateChecksums, newState);
}
@@ -122,7 +127,7 @@ public class SettingsBackupAgent extends BackupHelperAgent {
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
- enableWifi(false);
+
enableBluetooth(false);
while (data.readNextHeader()) {
@@ -133,12 +138,16 @@ public class SettingsBackupAgent extends BackupHelperAgent {
mSettingsHelper.applyAudioSettings();
} else if (KEY_SECURE.equals(key)) {
restoreSettings(data, Settings.Secure.CONTENT_URI);
- } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
+ } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
+ int retainedWifiState = enableWifi(false);
restoreFile(FILE_WIFI_SUPPLICANT, data);
FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
FileUtils.S_IRUSR | FileUtils.S_IWUSR |
FileUtils.S_IRGRP | FileUtils.S_IWGRP,
Process.myUid(), Process.WIFI_UID);
+ // retain the previous WIFI state.
+ enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
+ retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
} else if (KEY_SYNC.equals(key)) {
mSettingsHelper.setSyncProviders(data);
} else if (KEY_LOCALE.equals(key)) {
@@ -257,7 +266,7 @@ public class SettingsBackupAgent extends BackupHelperAgent {
}
/**
- * Given a cursor sorted by key name and a set of keys sorted by name,
+ * Given a cursor sorted by key name and a set of keys sorted by name,
* extract the required keys and values and write them to a byte array.
* @param sortedCursor
* @param sortedKeys
@@ -373,15 +382,18 @@ public class SettingsBackupAgent extends BackupHelperAgent {
return result;
}
- private void enableWifi(boolean enable) {
+ private int enableWifi(boolean enable) {
WifiManager wfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (wfm != null) {
+ int state = wfm.getWifiState();
wfm.setWifiEnabled(enable);
+ return state;
}
+ return WifiManager.WIFI_STATE_UNKNOWN;
}
private void enableBluetooth(boolean enable) {
- BluetoothDevice bt = (BluetoothDevice) getSystemService(Context.BLUETOOTH_SERVICE);
+ BluetoothAdapter bt = (BluetoothAdapter) getSystemService(Context.BLUETOOTH_SERVICE);
if (bt != null) {
if (!enable) {
bt.disable();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index ca739e6..b13883e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -118,16 +118,19 @@ public class SettingsHelper {
byte[] getSyncProviders() {
byte[] sync = new byte[1 + PROVIDERS.length];
+ // TODO: Sync backup needs to be moved to SystemBackupAgent
+ /*
try {
sync[0] = (byte) (mContentService.getListenForNetworkTickles() ? 1 : 0);
for (int i = 0; i < PROVIDERS.length; i++) {
sync[i + 1] = (byte)
- (mContentService.getSyncProviderAutomatically(PROVIDERS[i]) ? 1 : 0);
+ (mContentService.getSyncAutomatically(PROVIDERS[i]) ? 1 : 0);
}
} catch (RemoteException re) {
Log.w(TAG, "Unable to backup sync providers");
return sync;
}
+ */
return sync;
}
@@ -136,12 +139,15 @@ public class SettingsHelper {
try {
backup.readEntityData(sync, 0, sync.length);
+ // TODO: Sync backup needs to be moved to SystemBackupAgent
+ /*
mContentService.setListenForNetworkTickles(sync[0] == 1);
for (int i = 0; i < PROVIDERS.length; i++) {
mContentService.setSyncProviderAutomatically(PROVIDERS[i], sync[i + 1] > 0);
}
} catch (RemoteException re) {
Log.w(TAG, "Unable to restore sync providers");
+ */
} catch (java.io.IOException ioe) {
Log.w(TAG, "Unable to read sync settings");
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index c0de9a5..9877342 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -24,9 +24,11 @@ import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
+import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
@@ -45,8 +47,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;
private BackupManager mBackupManager;
/**
@@ -398,12 +399,8 @@ public class SettingsProvider extends ContentProvider {
// Get the current value for the default sound
Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
- if (soundUri == null) {
- // Fallback on any valid ringtone Uri
- soundUri = RingtoneManager.getValidRingtoneUri(context);
- }
- if (soundUri != null) {
+ if (soundUri != null) {
// Only proxy the openFile call to drm or media providers
String authority = soundUri.getAuthority();
boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
@@ -427,4 +424,64 @@ public class SettingsProvider extends ContentProvider {
return super.openFile(uri, mode);
}
+
+ @Override
+ public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
+
+ /*
+ * When a client attempts to openFile the default ringtone or
+ * notification setting Uri, we will proxy the call to the current
+ * default ringtone's Uri (if it is in the DRM or media provider).
+ */
+ int ringtoneType = RingtoneManager.getDefaultType(uri);
+ // Above call returns -1 if the Uri doesn't match a default type
+ if (ringtoneType != -1) {
+ Context context = getContext();
+
+ // Get the current value for the default sound
+ Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
+
+ if (soundUri != null) {
+ // Only proxy the openFile call to drm or media providers
+ String authority = soundUri.getAuthority();
+ boolean isDrmAuthority = authority.equals(DrmStore.AUTHORITY);
+ if (isDrmAuthority || authority.equals(MediaStore.AUTHORITY)) {
+
+ if (isDrmAuthority) {
+ try {
+ // Check DRM access permission here, since once we
+ // do the below call the DRM will be checking our
+ // permission, not our caller's permission
+ DrmStore.enforceAccessDrmPermission(context);
+ } catch (SecurityException e) {
+ throw new FileNotFoundException(e.getMessage());
+ }
+ }
+
+ ParcelFileDescriptor pfd = null;
+ try {
+ pfd = context.getContentResolver().openFileDescriptor(soundUri, mode);
+ return new AssetFileDescriptor(pfd, 0, -1);
+ } catch (FileNotFoundException ex) {
+ // fall through and open the fallback ringtone below
+ }
+ }
+
+ try {
+ return super.openAssetFile(soundUri, mode);
+ } catch (FileNotFoundException ex) {
+ // Since a non-null Uri was specified, but couldn't be opened,
+ // fall back to the built-in ringtone.
+ return context.getResources().openRawResourceFd(
+ com.android.internal.R.raw.fallbackring);
+ }
+ }
+ // no need to fall through and have openFile() try again, since we
+ // already know that will fail.
+ throw new FileNotFoundException(); // or return null ?
+ }
+
+ // Note that this will end up calling openFile() above.
+ return super.openAssetFile(uri, mode);
+ }
}
diff --git a/packages/SubscribedFeedsProvider/AndroidManifest.xml b/packages/SubscribedFeedsProvider/AndroidManifest.xml
index ca00a9b..a3938bd 100644
--- a/packages/SubscribedFeedsProvider/AndroidManifest.xml
+++ b/packages/SubscribedFeedsProvider/AndroidManifest.xml
@@ -13,13 +13,14 @@
android:label="@string/app_label">
<uses-library android:name="com.google.android.gtalkservice" />
<provider android:name="SubscribedFeedsProvider"
- android:authorities="subscribedfeeds" android:syncable="false"
+ android:authorities="subscribedfeeds"
+ android:label="@string/provider_label"
android:multiprocess="false"
android:readPermission="android.permission.SUBSCRIBED_FEEDS_READ"
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/res/values-cs/strings.xml b/packages/SubscribedFeedsProvider/res/values-cs/strings.xml
index 46de1b1..9b782b0 100644
--- a/packages/SubscribedFeedsProvider/res/values-cs/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-cs/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Synchronizace zdrojů"</string>
+ <string name="app_label">"Synchronizace zdrojů"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-de/strings.xml b/packages/SubscribedFeedsProvider/res/values-de/strings.xml
index 7e39aa8..1ade594 100644
--- a/packages/SubscribedFeedsProvider/res/values-de/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-de/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Feedsynchronisierung"</string>
+ <string name="app_label">"Feedsynchronisierung"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-es/strings.xml b/packages/SubscribedFeedsProvider/res/values-es/strings.xml
index 9165f65..86c6946 100644
--- a/packages/SubscribedFeedsProvider/res/values-es/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-es/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Sincronización de feeds"</string>
+ <string name="app_label">"Sincronización de feeds"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-fr/strings.xml b/packages/SubscribedFeedsProvider/res/values-fr/strings.xml
index f022e70..924b960 100644
--- a/packages/SubscribedFeedsProvider/res/values-fr/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-fr/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Synchronisation des flux"</string>
+ <string name="app_label">"Synchronisation des flux"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-it/strings.xml b/packages/SubscribedFeedsProvider/res/values-it/strings.xml
index 1053314..eabb17e 100644
--- a/packages/SubscribedFeedsProvider/res/values-it/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-it/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Sincronizzazione feed"</string>
+ <string name="app_label">"Sincronizzazione feed"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-ja/strings.xml b/packages/SubscribedFeedsProvider/res/values-ja/strings.xml
deleted file mode 100644
index b8f2d09..0000000
--- a/packages/SubscribedFeedsProvider/res/values-ja/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"フィードã®åŒæœŸ"</string>
-</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-nl/strings.xml b/packages/SubscribedFeedsProvider/res/values-nl/strings.xml
index 7dc5495..b9e82d1 100644
--- a/packages/SubscribedFeedsProvider/res/values-nl/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-nl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Feeds synchroniseren"</string>
+ <string name="app_label">"Feeds synchroniseren"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-pl/strings.xml b/packages/SubscribedFeedsProvider/res/values-pl/strings.xml
index 32c4a5e..02da9f3 100644
--- a/packages/SubscribedFeedsProvider/res/values-pl/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-pl/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"Synchronizowanie kanałów"</string>
+ <string name="app_label">"Synchronizowanie kanałów"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values-zh-rTW/strings.xml b/packages/SubscribedFeedsProvider/res/values-zh-rTW/strings.xml
index 15307aa..e6643cd 100644
--- a/packages/SubscribedFeedsProvider/res/values-zh-rTW/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values-zh-rTW/strings.xml
@@ -15,5 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5400580392303600842">"åŒæ­¥è³‡è¨Šæä¾›"</string>
+ <string name="app_label">"åŒæ­¥è³‡è¨Šæä¾›"</string>
</resources>
diff --git a/packages/SubscribedFeedsProvider/res/values/strings.xml b/packages/SubscribedFeedsProvider/res/values/strings.xml
index 072571d..c4c2484 100644
--- a/packages/SubscribedFeedsProvider/res/values/strings.xml
+++ b/packages/SubscribedFeedsProvider/res/values/strings.xml
@@ -17,5 +17,9 @@
<resources>
<!-- Title of the feed synchronization activity. -->
<string name="app_label">Sync Feeds</string>
+
+ <!-- What to show in messaging that refers to this provider, e.g. AccountSyncSettings -->
+ <string name="provider_label">Push Subscriptions</string>
+
</resources>
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
index 3513215..ea14307 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
@@ -16,6 +16,7 @@
package com.android.providers.subscribedfeeds;
+import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -35,7 +36,10 @@ public class SubscribedFeedsBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received intent " + intent);
- intent.setClass(context, SubscribedFeedsIntentService.class);
+ if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
+ setResultCode(Activity.RESULT_OK);
+ }
+ intent.setClass(context, SubscribedFeedsIntentService.class);
context.startService(intent);
}
}
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
index 8b3bedf..b854f86 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
@@ -16,13 +16,14 @@ import android.database.sqlite.SQLiteFullException;
import android.app.AlarmManager;
import android.app.PendingIntent;
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 +31,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 +41,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 +53,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 +69,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 +104,19 @@ 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
+ final Account account = new Account(accountName, "com.google.GAIA");
c = context.getContentResolver().query(SubscribedFeeds.Feeds.CONTENT_URI,
- null, where, new String[]{account, feed}, null);
+ null, where, new String[]{account.name, account.type, 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()) {
@@ -119,21 +124,14 @@ public class SubscribedFeedsIntentService extends IntentService {
String authority = c.getString(c.getColumnIndexOrThrow(
SubscribedFeeds.Feeds.AUTHORITY));
EventLog.writeEvent(LOG_TICKLE, authority);
- try {
- if (!ContentResolver.getContentService()
- .getSyncProviderAutomatically(authority)) {
- Log.d(TAG, "supressing tickle since provider " + authority
- + " is configured to not sync automatically");
- continue;
- }
- } catch (RemoteException e) {
+ if (!ContentResolver.getSyncAutomatically(account, authority)) {
+ Log.d(TAG, "supressing tickle since provider " + authority
+ + " is configured to not sync automatically");
continue;
}
- Uri uri = Uri.parse("content://" + authority);
Bundle extras = new Bundle();
- extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
extras.putString("feed", feed);
- context.getContentResolver().startSync(uri, extras);
+ ContentResolver.requestSync(account, authority, extras);
}
} finally {
if (c != null) c.deactivate();
@@ -150,31 +148,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.name);
+ values.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.type);
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.name, account.type});
}
} 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..2647752 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
@@ -16,6 +16,7 @@
package com.android.providers.subscribedfeeds;
+import android.accounts.Account;
import android.content.UriMatcher;
import android.content.*;
import android.database.Cursor;
@@ -39,7 +40,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 +89,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 +108,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,11 +118,22 @@ 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))");
}
@Override
+ protected void onAccountsChanged(Account[] accountsArray) {
+ super.onAccountsChanged(accountsArray);
+ for (Account account : accountsArray) {
+ if (account.type.equals("com.google.GAIA")) {
+ ContentResolver.setSyncAutomatically(account, "subscribedfeeds", true);
+ }
+ }
+ }
+
+ @Override
protected void onDatabaseOpened(SQLiteDatabase db) {
db.markTableSyncable("feeds", "_deleted_feeds");
}
@@ -170,7 +183,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 +324,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 +385,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/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 1bab717..071a90d 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -153,7 +153,7 @@ class SynthProxyJniStorage {
AudioTrack* mAudioOut;
AudioSystem::stream_type mStreamType;
uint32_t mSampleRate;
- AudioSystem::audio_format mAudFormat;
+ uint32_t mAudFormat;
int mNbChannels;
int8_t * mBuffer;
size_t mBufferSize;
@@ -200,7 +200,6 @@ class SynthProxyJniStorage {
mSampleRate = rate;
mAudFormat = format;
mNbChannels = channel;
-
mStreamType = streamType;
// retrieve system properties to ensure successful creation of the
@@ -221,7 +220,8 @@ class SynthProxyJniStorage {
if (minBufCount < 2) minBufCount = 2;
int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate;
- mAudioOut = new AudioTrack(mStreamType, rate, format, channel,
+ mAudioOut = new AudioTrack(mStreamType, rate, format,
+ (channel == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
minFrameCount > 4096 ? minFrameCount : 4096,
0, 0, 0, 0); // not using an AudioTrack callback
@@ -264,7 +264,7 @@ void prepAudioTrack(SynthProxyJniStorage* pJniData, AudioSystem::stream_type str
* Directly speaks using AudioTrack or write to file
*/
static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
- AudioSystem::audio_format format, int channel,
+ uint32_t format, int channel,
int8_t *&wav, size_t &bufferSize, tts_synth_status status) {
//LOGV("ttsSynthDoneCallback: %d bytes", bufferSize);
@@ -284,7 +284,7 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
}
if (bufferSize > 0) {
- prepAudioTrack(pJniData, pForAfter->streamType, rate, format, channel);
+ prepAudioTrack(pJniData, pForAfter->streamType, rate, (AudioSystem::audio_format)format, channel);
if (pJniData->mAudioOut) {
applyFilter((int16_t*)wav, bufferSize/2);
pJniData->mAudioOut->write(wav, bufferSize);
@@ -721,6 +721,27 @@ android_tts_SynthProxy_stop(JNIEnv *env, jobject thiz, jint jniData)
}
+static int
+android_tts_SynthProxy_stopSync(JNIEnv *env, jobject thiz, jint jniData)
+{
+ int result = TTS_FAILURE;
+
+ if (jniData == 0) {
+ LOGE("android_tts_SynthProxy_stop(): invalid JNI data");
+ return result;
+ }
+
+ // perform a regular stop
+ result = android_tts_SynthProxy_stop(env, thiz, jniData);
+ // but wait on the engine having released the engine mutex which protects
+ // the synthesizer resources.
+ engineMutex.lock();
+ engineMutex.unlock();
+
+ return result;
+}
+
+
static jobjectArray
android_tts_SynthProxy_getLanguage(JNIEnv *env, jobject thiz, jint jniData)
{
@@ -778,6 +799,10 @@ static JNINativeMethod gMethods[] = {
"(I)I",
(void*)android_tts_SynthProxy_stop
},
+ { "native_stopSync",
+ "(I)I",
+ (void*)android_tts_SynthProxy_stopSync
+ },
{ "native_speak",
"(ILjava/lang/String;I)I",
(void*)android_tts_SynthProxy_speak
diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java
index a0814aa..1d37ba0 100755
--- a/packages/TtsService/src/android/tts/SynthProxy.java
+++ b/packages/TtsService/src/android/tts/SynthProxy.java
@@ -40,7 +40,7 @@ public class SynthProxy {
* Constructor; pass the location of the native TTS .so to use.
*/
public SynthProxy(String nativeSoLib) {
- Log.e("TTS is loading", nativeSoLib);
+ Log.v(TtsService.SERVICE_TAG, "TTS is loading " + nativeSoLib);
native_setup(new WeakReference<SynthProxy>(this), nativeSoLib);
}
@@ -52,6 +52,18 @@ public class SynthProxy {
}
/**
+ * Synchronous stop of the synthesizer. This method returns when the synth
+ * has completed the stop procedure and doesn't use any of the resources it
+ * was using while synthesizing.
+ *
+ * @return {@link android.speech.tts.TextToSpeech.SUCCESS} or
+ * {@link android.speech.tts.TextToSpeech.ERROR}
+ */
+ public int stopSync() {
+ return native_stopSync(mJniData);
+ }
+
+ /**
* Synthesize speech and speak it directly using AudioTrack.
*/
public int speak(String text, int streamType) {
@@ -156,6 +168,8 @@ public class SynthProxy {
private native final int native_stop(int jniData);
+ private native final int native_stopSync(int jniData);
+
private native final int native_speak(int jniData, String text, int streamType);
private native final int native_synthesizeToFile(int jniData, String text, String filename);
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index cd24727..217d3bb 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -34,6 +34,8 @@ import android.speech.tts.ITts.Stub;
import android.speech.tts.ITtsCallback;
import android.speech.tts.TextToSpeech;
import android.util.Log;
+
+import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -120,6 +122,7 @@ public class TtsService extends Service implements OnCompletionListener {
private static final String ACTION = "android.intent.action.START_TTS_SERVICE";
private static final String CATEGORY = "android.intent.category.TTS";
private static final String PKGNAME = "android.tts";
+ protected static final String SERVICE_TAG = "TtsService";
private final RemoteCallbackList<ITtsCallback> mCallbacks
= new RemoteCallbackList<ITtsCallback>();
@@ -138,6 +141,7 @@ public class TtsService extends Service implements OnCompletionListener {
private ContentResolver mResolver;
+ // lock for the speech queue (mSpeechQueue) and the current speech item (mCurrentSpeechItem)
private final ReentrantLock speechQueueLock = new ReentrantLock();
private final ReentrantLock synthesizerLock = new ReentrantLock();
@@ -145,7 +149,7 @@ public class TtsService extends Service implements OnCompletionListener {
@Override
public void onCreate() {
super.onCreate();
- Log.i("TtsService", "TtsService.onCreate()");
+ Log.v("TtsService", "TtsService.onCreate()");
mResolver = getContentResolver();
@@ -173,10 +177,7 @@ public class TtsService extends Service implements OnCompletionListener {
public void onDestroy() {
super.onDestroy();
- // TODO replace the call to stopAll() with a method to clear absolutely all upcoming
- // uses of the native synth, including synthesis to a file, and delete files for which
- // synthesis was not complete.
- stopAll("");
+ killAllUtterances();
// Don't hog the media player
cleanUpPlayer();
@@ -188,6 +189,8 @@ public class TtsService extends Service implements OnCompletionListener {
// Unregister all callbacks.
mCallbacks.kill();
+
+ Log.v(SERVICE_TAG, "onDestroy() completed");
}
@@ -279,7 +282,6 @@ public class TtsService extends Service implements OnCompletionListener {
private int isLanguageAvailable(String lang, String country, String variant) {
- //Log.v("TtsService", "TtsService.isLanguageAvailable(" + lang + ", " + country + ", " +variant+")");
int res = TextToSpeech.LANG_NOT_SUPPORTED;
try {
res = sNativeSynth.isLanguageAvailable(lang, country, variant);
@@ -301,7 +303,7 @@ public class TtsService extends Service implements OnCompletionListener {
private int setLanguage(String callingApp, String lang, String country, String variant) {
- Log.v("TtsService", "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
+ Log.v(SERVICE_TAG, "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
int res = TextToSpeech.ERROR;
try {
if (isDefaultEnforced()) {
@@ -385,7 +387,7 @@ public class TtsService extends Service implements OnCompletionListener {
* engines.
*/
private int speak(String callingApp, String text, int queueMode, ArrayList<String> params) {
- Log.v("TtsService", "TTS service received " + text);
+ Log.v(SERVICE_TAG, "TTS service received " + text);
if (queueMode == TextToSpeech.QUEUE_FLUSH) {
stop(callingApp);
} else if (queueMode == 2) {
@@ -434,7 +436,7 @@ public class TtsService extends Service implements OnCompletionListener {
speechQueueAvailable =
speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
if (speechQueueAvailable) {
- Log.i("TtsService", "Stopping");
+ Log.i(SERVICE_TAG, "Stopping");
for (int i = mSpeechQueue.size() - 1; i > -1; i--){
if (mSpeechQueue.get(i).mCallingApp.equals(callingApp)){
mSpeechQueue.remove(i);
@@ -461,10 +463,13 @@ public class TtsService extends Service implements OnCompletionListener {
} else {
result = TextToSpeech.SUCCESS;
}
- Log.i("TtsService", "Stopped");
+ Log.i(SERVICE_TAG, "Stopped");
+ } else {
+ Log.e(SERVICE_TAG, "TTS stop(): queue locked longer than expected");
+ result = TextToSpeech.ERROR;
}
} catch (InterruptedException e) {
- Log.e("TtsService", "TTS stop: tryLock interrupted");
+ Log.e(SERVICE_TAG, "TTS stop: tryLock interrupted");
e.printStackTrace();
} finally {
// This check is needed because finally will always run; even if the
@@ -477,6 +482,63 @@ public class TtsService extends Service implements OnCompletionListener {
}
+ /**
+ * Stops all speech output, both rendered to a file and directly spoken, and removes any
+ * utterances still in the queue globally. Files that were being written are deleted.
+ */
+ @SuppressWarnings("finally")
+ private int killAllUtterances() {
+ int result = TextToSpeech.ERROR;
+ boolean speechQueueAvailable = false;
+
+ try {
+ speechQueueAvailable = speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT,
+ TimeUnit.MILLISECONDS);
+ if (speechQueueAvailable) {
+ // remove every single entry in the speech queue
+ mSpeechQueue.clear();
+
+ // clear the current speech item
+ if (mCurrentSpeechItem != null) {
+ result = sNativeSynth.stopSync();
+ mKillList.put(mCurrentSpeechItem, true);
+ mIsSpeaking = false;
+
+ // was the engine writing to a file?
+ if (mCurrentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) {
+ // delete the file that was being written
+ if (mCurrentSpeechItem.mFilename != null) {
+ File tempFile = new File(mCurrentSpeechItem.mFilename);
+ Log.v(SERVICE_TAG, "Leaving behind " + mCurrentSpeechItem.mFilename);
+ if (tempFile.exists()) {
+ Log.v(SERVICE_TAG, "About to delete "
+ + mCurrentSpeechItem.mFilename);
+ if (tempFile.delete()) {
+ Log.v(SERVICE_TAG, "file successfully deleted");
+ }
+ }
+ }
+ }
+
+ mCurrentSpeechItem = null;
+ }
+ } else {
+ Log.e(SERVICE_TAG, "TTS killAllUtterances(): queue locked longer than expected");
+ result = TextToSpeech.ERROR;
+ }
+ } catch (InterruptedException e) {
+ Log.e(SERVICE_TAG, "TTS killAllUtterances(): tryLock interrupted");
+ result = TextToSpeech.ERROR;
+ } finally {
+ // This check is needed because finally will always run, even if the
+ // method returns somewhere in the try block.
+ if (speechQueueAvailable) {
+ speechQueueLock.unlock();
+ }
+ return result;
+ }
+ }
+
/**
* Stops all speech output and removes any utterances still in the queue globally, except
@@ -516,10 +578,13 @@ public class TtsService extends Service implements OnCompletionListener {
} else {
result = TextToSpeech.SUCCESS;
}
- Log.i("TtsService", "Stopped all");
+ Log.i(SERVICE_TAG, "Stopped all");
+ } else {
+ Log.e(SERVICE_TAG, "TTS stopAll(): queue locked longer than expected");
+ result = TextToSpeech.ERROR;
}
} catch (InterruptedException e) {
- Log.e("TtsService", "TTS stopAll: tryLock interrupted");
+ Log.e(SERVICE_TAG, "TTS stopAll: tryLock interrupted");
e.printStackTrace();
} finally {
// This check is needed because finally will always run; even if the
@@ -646,11 +711,11 @@ public class TtsService extends Service implements OnCompletionListener {
sNativeSynth.speak(speechItem.mText, streamType);
} catch (NullPointerException e) {
// synth will become null during onDestroy()
- Log.v("TtsService", " null synth, can't speak");
+ Log.v(SERVICE_TAG, " null synth, can't speak");
}
}
} catch (InterruptedException e) {
- Log.e("TtsService", "TTS speakInternalOnly(): tryLock interrupted");
+ Log.e(SERVICE_TAG, "TTS speakInternalOnly(): tryLock interrupted");
e.printStackTrace();
} finally {
// This check is needed because finally will always run;
@@ -667,7 +732,7 @@ public class TtsService extends Service implements OnCompletionListener {
}
}
Thread synth = (new Thread(new SynthThread()));
- //synth.setPriority(Thread.MIN_PRIORITY);
+ synth.setPriority(Thread.MAX_PRIORITY);
synth.start();
}
@@ -676,7 +741,7 @@ public class TtsService extends Service implements OnCompletionListener {
public void run() {
boolean synthAvailable = false;
String utteranceId = "";
- Log.i("TtsService", "Synthesizing to " + speechItem.mFilename);
+ Log.i(SERVICE_TAG, "Synthesizing to " + speechItem.mFilename);
try {
synthAvailable = synthesizerLock.tryLock();
if (!synthAvailable) {
@@ -720,11 +785,11 @@ public class TtsService extends Service implements OnCompletionListener {
sNativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename);
} catch (NullPointerException e) {
// synth will become null during onDestroy()
- Log.v("TtsService", " null synth, can't synthesize to file");
+ Log.v(SERVICE_TAG, " null synth, can't synthesize to file");
}
}
} catch (InterruptedException e) {
- Log.e("TtsService", "TTS synthToFileInternalOnly(): tryLock interrupted");
+ Log.e(SERVICE_TAG, "TTS synthToFileInternalOnly(): tryLock interrupted");
e.printStackTrace();
} finally {
// This check is needed because finally will always run;
@@ -741,7 +806,7 @@ public class TtsService extends Service implements OnCompletionListener {
}
}
Thread synth = (new Thread(new SynthThread()));
- //synth.setPriority(Thread.MIN_PRIORITY);
+ synth.setPriority(Thread.MAX_PRIORITY);
synth.start();
}
@@ -769,7 +834,7 @@ public class TtsService extends Service implements OnCompletionListener {
if (cb == null){
return;
}
- Log.i("TtsService", "TTS callback: dispatch started");
+ Log.v(SERVICE_TAG, "TTS callback: dispatch started");
// Broadcast to all clients the new value.
final int N = mCallbacks.beginBroadcast();
try {
@@ -779,7 +844,7 @@ public class TtsService extends Service implements OnCompletionListener {
// the dead object for us.
}
mCallbacks.finishBroadcast();
- Log.i("TtsService", "TTS callback: dispatch completed to " + N);
+ Log.v(SERVICE_TAG, "TTS callback: dispatch completed to " + N);
}
private SpeechItem splitCurrentTextIfNeeded(SpeechItem currentSpeechItem){
@@ -816,11 +881,12 @@ public class TtsService extends Service implements OnCompletionListener {
speechQueueAvailable =
speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
if (!speechQueueAvailable) {
- Log.e("TtsService", "processSpeechQueue - Speech queue is unavailable.");
+ Log.e(SERVICE_TAG, "processSpeechQueue - Speech queue is unavailable.");
return;
}
if (mSpeechQueue.size() < 1) {
mIsSpeaking = false;
+ mKillList.clear();
broadcastTtsQueueProcessingCompleted();
return;
}
@@ -830,7 +896,7 @@ public class TtsService extends Service implements OnCompletionListener {
SoundResource sr = getSoundResource(mCurrentSpeechItem);
// Synth speech as needed - synthesizer should call
// processSpeechQueue to continue running the queue
- Log.i("TtsService", "TTS processing: " + mCurrentSpeechItem.mText);
+ Log.v(SERVICE_TAG, "TTS processing: " + mCurrentSpeechItem.mText);
if (sr == null) {
if (mCurrentSpeechItem.mType == SpeechItem.TEXT) {
mCurrentSpeechItem = splitCurrentTextIfNeeded(mCurrentSpeechItem);
@@ -886,7 +952,7 @@ public class TtsService extends Service implements OnCompletionListener {
mSpeechQueue.remove(0);
}
} catch (InterruptedException e) {
- Log.e("TtsService", "TTS processSpeechQueue: tryLock interrupted");
+ Log.e(SERVICE_TAG, "TTS processSpeechQueue: tryLock interrupted");
e.printStackTrace();
} finally {
// This check is needed because finally will always run; even if the
diff --git a/packages/VpnServices/res/values-cs/strings.xml b/packages/VpnServices/res/values-cs/strings.xml
index 58e211d..5f3522d 100644
--- a/packages/VpnServices/res/values-cs/strings.xml
+++ b/packages/VpnServices/res/values-cs/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"Služby VPN"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"Síť VPN %s připojena"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"Síť VPN %s odpojena"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Dotykem se znovu připojíte k síti VPN."</string>
+ <string name="app_label">"Služby VPN"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-de/strings.xml b/packages/VpnServices/res/values-de/strings.xml
index 23558bb..93fa474 100644
--- a/packages/VpnServices/res/values-de/strings.xml
+++ b/packages/VpnServices/res/values-de/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"VPN-Dienste"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"VPN \"%s\" verbunden"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"VPN \"%s \" getrennt"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Zur Wiederherstellung der Verbindung mit einem VPN berühren"</string>
+ <string name="app_label">"VPN-Dienste"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-es/strings.xml b/packages/VpnServices/res/values-es/strings.xml
index bc7e536..bb4f348 100644
--- a/packages/VpnServices/res/values-es/strings.xml
+++ b/packages/VpnServices/res/values-es/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"Servicios VPN"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"VPN %s conectada"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"VPN %s desconectada"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Toca para volver a conectarte a una red VPN."</string>
+ <string name="app_label">"Servicios VPN"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-fr/strings.xml b/packages/VpnServices/res/values-fr/strings.xml
index 5db5050..4395d03 100644
--- a/packages/VpnServices/res/values-fr/strings.xml
+++ b/packages/VpnServices/res/values-fr/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"Services VPN"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"VPN %s connecté"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"VPN %s déconnecté"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Touchez l\'écran pour vous reconnecter à un VPN."</string>
+ <string name="app_label">"Services VPN"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-it/strings.xml b/packages/VpnServices/res/values-it/strings.xml
index cc2a4eb..76e0214 100644
--- a/packages/VpnServices/res/values-it/strings.xml
+++ b/packages/VpnServices/res/values-it/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"Servizi VPN"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"VPN %s collegata"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"VPN %s scollegata"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Tocca per riconnetterti a una rete VPN."</string>
+ <string name="app_label">"Servizi VPN"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-ja/strings.xml b/packages/VpnServices/res/values-ja/strings.xml
deleted file mode 100644
index 1158347..0000000
--- a/packages/VpnServices/res/values-ja/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"VPNサービス"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"%s VPNãŒæŽ¥ç¶šã•ã‚Œã¾ã—ãŸ"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"%s VPNãŒåˆ‡æ–­ã•ã‚Œã¾ã—ãŸ"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"タップã—ã¦VPNã«å†æŽ¥ç¶šã—ã¦ãã ã•ã„。"</string>
-</resources>
diff --git a/packages/VpnServices/res/values-nl/strings.xml b/packages/VpnServices/res/values-nl/strings.xml
index 359cfe9..9a50f3b 100644
--- a/packages/VpnServices/res/values-nl/strings.xml
+++ b/packages/VpnServices/res/values-nl/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"VPN-services"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"%s VPN verbonden"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"%s VPN-verbinding verbroken"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Raak aan om opnieuw verbinding te maken met een VPN."</string>
+ <string name="app_label">"VPN-services"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-pl/strings.xml b/packages/VpnServices/res/values-pl/strings.xml
index 17d1dab..d2e8c60 100644
--- a/packages/VpnServices/res/values-pl/strings.xml
+++ b/packages/VpnServices/res/values-pl/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"Usługi VPN"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"Połączono z siecią VPN %s"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"Rozłączono z siecią VPN %s"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"Dotknij, aby ponownie połączyć się z siecią VPN."</string>
+ <string name="app_label">"Usługi VPN"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values-zh-rTW/strings.xml b/packages/VpnServices/res/values-zh-rTW/strings.xml
index ad8eddf..021077b 100644
--- a/packages/VpnServices/res/values-zh-rTW/strings.xml
+++ b/packages/VpnServices/res/values-zh-rTW/strings.xml
@@ -15,8 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4589592829302498102">"VPN æœå‹™"</string>
- <string name="vpn_notification_title_connected" msgid="2567196609405266775">"%s VPN 已連線"</string>
- <string name="vpn_notification_title_disconnected" msgid="3564361788336568244">"%s VPN 已中斷連線"</string>
- <string name="vpn_notification_hint_disconnected" msgid="1952209867082269429">"輕觸å³å¯é‡æ–°é€£ç·šè‡³ VPN。"</string>
+ <string name="app_label">"VPN æœå‹™"</string>
+ <!-- no translation found for vpn_notification_title_connected (2567196609405266775) -->
+ <skip />
+ <!-- no translation found for vpn_notification_title_disconnected (3564361788336568244) -->
+ <skip />
+ <!-- no translation found for vpn_notification_hint_disconnected (1952209867082269429) -->
+ <skip />
</resources>
diff --git a/packages/VpnServices/res/values/strings.xml b/packages/VpnServices/res/values/strings.xml
index 074655e..d82f52a 100755
--- a/packages/VpnServices/res/values/strings.xml
+++ b/packages/VpnServices/res/values/strings.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Title for the VPN Services activity. -->
<string name="app_label">VPN Services</string>
- <string name="vpn_notification_title_connected">%s VPN connected</string>
- <string name="vpn_notification_title_disconnected">%s VPN disconnected</string>
+ <string name="vpn_notification_title_connected"><xliff:g id="profilename">%s</xliff:g> VPN connected</string>
+ <string name="vpn_notification_title_disconnected"><xliff:g id="profilename">%s</xliff:g> VPN disconnected</string>
<string name="vpn_notification_hint_disconnected">Touch to reconnect to a VPN.</string>
</resources>
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index e3ac996..53167f6 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -56,10 +56,6 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
private static final String REMOTE_IP = "net.ipremote";
private static final String DNS_DOMAIN_SUFFICES = "net.dns.search";
- private static final int CHALLENGE_ERROR_CODE = 5;
- private static final int REMOTE_HUNG_UP_ERROR_CODE = 7;
- private static final int AUTH_ERROR_CODE = 51;
-
private final String TAG = VpnService.class.getSimpleName();
// FIXME: profile is only needed in connecting phase, so we can just save
@@ -202,7 +198,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
private void waitUntilConnectedOrTimedout() throws IOException {
sleep(2000); // 2 seconds
- for (int i = 0; i < 60; i++) {
+ for (int i = 0; i < 80; i++) {
if (mState != VpnState.CONNECTING) {
break;
} else if (VPN_IS_UP.equals(
@@ -464,22 +460,8 @@ abstract class VpnService<E extends VpnProfile> implements Serializable {
synchronized int getSocketError() {
for (DaemonProxy s : mDaemonList) {
- switch (getResultFromSocket(s)) {
- case 0:
- continue;
-
- case AUTH_ERROR_CODE:
- return VpnManager.VPN_ERROR_AUTH;
-
- case CHALLENGE_ERROR_CODE:
- return VpnManager.VPN_ERROR_CHALLENGE;
-
- case REMOTE_HUNG_UP_ERROR_CODE:
- return VpnManager.VPN_ERROR_REMOTE_HUNG_UP;
-
- default:
- return VpnManager.VPN_ERROR_CONNECTION_FAILED;
- }
+ int errCode = getResultFromSocket(s);
+ if (errCode != 0) return errCode;
}
return 0;
}
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
index 4892a7b..e5be847 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
@@ -91,7 +91,8 @@ public class VpnServiceBinder extends Service {
void removeStates() {
try {
- new File(STATES_FILE_PATH).delete();
+ File f = new File(STATES_FILE_PATH);
+ if (f.exists()) f.delete();
} catch (Throwable e) {
if (DBG) Log.d("VpnServiceBinder", " remove states: " + e);
}
diff --git a/preloaded-classes b/preloaded-classes
index 69c596c..6eb3cf2 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1,248 +1,192 @@
# Classes which are preloaded by com.android.internal.os.ZygoteInit.
-# Automatically generated by frameworks/base/tools/preload/WritePreloadedClassFile.java.
-# MIN_LOAD_TIME_MICROS=1250
-SQLite.Blob
-SQLite.Database
-SQLite.FunctionContext
-SQLite.Stmt
-SQLite.Vm
android.R$styleable
-android.accounts.IAccountsService$Stub
android.app.Activity
android.app.ActivityGroup
-android.app.ActivityManager
-android.app.ActivityManager$MemoryInfo
+android.app.ActivityManager$MemoryInfo$1
android.app.ActivityManagerNative
android.app.ActivityManagerProxy
android.app.ActivityThread
+android.app.ActivityThread$ActivityRecord
+android.app.ActivityThread$AppBindData
android.app.ActivityThread$ApplicationThread
+android.app.ActivityThread$ContextCleanupInfo
+android.app.ActivityThread$GcIdler
android.app.ActivityThread$H
+android.app.ActivityThread$Idler
+android.app.ActivityThread$PackageInfo
+android.app.ActivityThread$PackageInfo$ReceiverDispatcher
+android.app.ActivityThread$PackageInfo$ReceiverDispatcher$InnerReceiver
+android.app.ActivityThread$PackageInfo$ServiceDispatcher
+android.app.ActivityThread$PackageInfo$ServiceDispatcher$InnerConnection
+android.app.ActivityThread$ProviderRecord
+android.app.ActivityThread$ProviderRefCount
android.app.AlertDialog
android.app.Application
android.app.ApplicationContext
android.app.ApplicationContext$ApplicationContentResolver
android.app.ApplicationContext$ApplicationPackageManager
-android.app.ApplicationContext$WallpaperCallback
+android.app.ApplicationContext$ApplicationPackageManager$PackageRemovedReceiver
+android.app.ApplicationContext$ApplicationPackageManager$ResourceName
+android.app.ApplicationContext$SharedPreferencesImpl
+android.app.ApplicationLoaders
android.app.ApplicationThreadNative
-android.app.DatePickerDialog
android.app.Dialog
android.app.ExpandableListActivity
android.app.IActivityManager
-android.app.IActivityManager$ContentProviderHolder
+android.app.IActivityManager$ContentProviderHolder$1
android.app.IAlarmManager$Stub
+android.app.IAlarmManager$Stub$Proxy
+android.app.IApplicationThread
android.app.INotificationManager$Stub
+android.app.INotificationManager$Stub$Proxy
+android.app.ISearchManager
android.app.ISearchManager$Stub
-android.app.ISearchManagerCallback$Stub
-android.app.IStatusBar$Stub
-android.app.ITransientNotification$Stub
-android.app.IWallpaperService$Stub
-android.app.IWallpaperServiceCallback$Stub
+android.app.ISearchManager$Stub$Proxy
android.app.Instrumentation
-android.app.IntentService
+android.app.IntentReceiverLeaked
android.app.ListActivity
+android.app.ListActivity$1
+android.app.ListActivity$2
android.app.LocalActivityManager
android.app.Notification
+android.app.NotificationManager
android.app.PendingIntent
+android.app.PendingIntent$1
android.app.ProgressDialog
+android.app.ReceiverRestrictedContext
android.app.ResultInfo
-android.app.SearchManager$SearchManagerCallback
+android.app.ResultInfo$1
+android.app.SearchDialog
+android.app.SearchDialog$SearchAutoComplete
android.app.Service
-android.app.StatusBarManager
+android.app.ServiceConnectionLeaked
android.app.TabActivity
-android.app.TimePickerDialog
-android.appwidget.AppWidgetHost
-android.appwidget.AppWidgetHostView
-android.appwidget.AppWidgetManager
-android.appwidget.AppWidgetProvider
-android.appwidget.AppWidgetProviderInfo
-android.backup.BackupDataInput
-android.backup.BackupDataInput$EntityHeader
-android.backup.BackupDataOutput
-android.backup.BackupHelperDispatcher
-android.backup.BackupHelperDispatcher$Header
-android.backup.FileBackupHelperBase
-android.bluetooth.BluetoothAudioGateway
-android.bluetooth.BluetoothDevice
-android.bluetooth.Database
-android.bluetooth.HeadsetBase
-android.bluetooth.IBluetoothA2dp
-android.bluetooth.IBluetoothA2dp$Stub
-android.bluetooth.IBluetoothDevice
-android.bluetooth.IBluetoothDevice$Stub
-android.bluetooth.IBluetoothDevice$Stub$Proxy
-android.bluetooth.RfcommSocket
-android.bluetooth.ScoSocket
android.content.AbstractSyncableContentProvider
android.content.AbstractTableMerger
+android.content.AsyncQueryHandler$WorkerHandler
+android.content.BroadcastReceiver
+android.content.ComponentCallbacks
android.content.ComponentName
+android.content.ComponentName$1
android.content.ContentProvider$Transport
+android.content.ContentProviderProxy
+android.content.ContentQueryMap
+android.content.ContentQueryMap$1
android.content.ContentResolver
android.content.ContentResolver$CursorWrapperInner
android.content.ContentValues
android.content.Context
android.content.ContextWrapper
-android.content.DialogInterface$OnMultiChoiceClickListener
+android.content.DialogInterface
+android.content.DialogInterface$OnCancelListener
+android.content.DialogInterface$OnDismissListener
+android.content.IContentProvider
+android.content.IContentService
android.content.IContentService$Stub
-android.content.ISyncAdapter$Stub
android.content.Intent
-android.content.Intent$ShortcutIconResource
+android.content.Intent$1
android.content.IntentFilter
-android.content.SyncAdapter$Transport
+android.content.SearchRecentSuggestionsProvider
+android.content.ServiceConnection
+android.content.SharedPreferences
android.content.SyncResult
-android.content.SyncStateContentProviderHelper
+android.content.SyncResult$1
android.content.SyncStats
+android.content.SyncStats$1
android.content.SyncableContentProvider
-android.content.TempProviderSyncAdapter
android.content.UriMatcher
android.content.pm.ActivityInfo
+android.content.pm.ActivityInfo$1
android.content.pm.ApplicationInfo
-android.content.pm.ConfigurationInfo
-android.content.pm.IPackageDataObserver$Stub
-android.content.pm.IPackageDeleteObserver$Stub
+android.content.pm.ApplicationInfo$1
+android.content.pm.ComponentInfo
+android.content.pm.IPackageManager
android.content.pm.IPackageManager$Stub
android.content.pm.IPackageManager$Stub$Proxy
-android.content.pm.IPackageStatsObserver$Stub
android.content.pm.InstrumentationInfo
-android.content.pm.PackageInfo
+android.content.pm.InstrumentationInfo$1
+android.content.pm.PackageItemInfo
android.content.pm.PackageManager
-android.content.pm.PackageStats
-android.content.pm.PathPermission
+android.content.pm.PackageManager$NameNotFoundException
android.content.pm.PermissionInfo
-android.content.pm.ResolveInfo
-android.content.pm.Signature
-android.content.res.AssetFileDescriptor
-android.content.res.AssetFileDescriptor$1
+android.content.pm.ProviderInfo
+android.content.pm.ProviderInfo$1
+android.content.pm.ResolveInfo$1
+android.content.pm.ServiceInfo$1
android.content.res.AssetManager
android.content.res.AssetManager$AssetInputStream
android.content.res.ColorStateList
android.content.res.ColorStateList$1
-android.content.res.CompatibilityInfo
-android.content.res.CompatibilityInfo$1
android.content.res.Configuration
-android.content.res.Configuration$1
android.content.res.Resources
-android.content.res.Resources$1
+android.content.res.Resources$Theme
android.content.res.StringBlock
android.content.res.TypedArray
android.content.res.XmlBlock
android.content.res.XmlBlock$Parser
-android.content.res.XmlResourceParser
android.database.AbstractCursor
+android.database.AbstractCursor$SelfContentObserver
android.database.AbstractWindowedCursor
+android.database.BulkCursorNative
+android.database.BulkCursorProxy
android.database.BulkCursorToCursorAdaptor
-android.database.CharArrayBuffer
-android.database.CursorJoiner$Result
+android.database.ContentObservable
+android.database.ContentObserver$Transport
+android.database.Cursor
android.database.CursorToBulkCursorAdaptor
+android.database.CursorToBulkCursorAdaptor$ContentObserverProxy
android.database.CursorWindow
-android.database.CursorWindow$1
android.database.CursorWrapper
-android.database.DatabaseUtils
-android.database.MatrixCursor
+android.database.DataSetObservable
+android.database.IContentObserver$Stub$Proxy
android.database.MergeCursor
-android.database.sqlite.SQLiteClosable
android.database.sqlite.SQLiteCursor
android.database.sqlite.SQLiteDatabase
-android.database.sqlite.SQLiteDatabase$ConflictAlgorithm
-android.database.sqlite.SQLiteDebug
-android.database.sqlite.SQLiteDebug$PagerStats
+android.database.sqlite.SQLiteDatabase$CursorFactory
android.database.sqlite.SQLiteDirectCursorDriver
-android.database.sqlite.SQLiteProgram
android.database.sqlite.SQLiteQuery
-android.database.sqlite.SQLiteQueryBuilder
android.database.sqlite.SQLiteStatement
+android.ddm.DdmHandleAppName
+android.ddm.DdmHandleExit
android.ddm.DdmHandleHeap
android.ddm.DdmHandleHello
android.ddm.DdmHandleNativeHeap
-android.ddm.DdmHandleProfiling
android.ddm.DdmHandleThread
android.ddm.DdmRegister
-android.debug.JNITest
-android.emoji.EmojiFactory
-android.graphics.AvoidXfermode
android.graphics.Bitmap
-android.graphics.Bitmap$1
-android.graphics.Bitmap$CompressFormat
-android.graphics.Bitmap$Config
-android.graphics.BitmapFactory
-android.graphics.BitmapFactory$Options
android.graphics.BitmapShader
-android.graphics.BlurMaskFilter
-android.graphics.Camera
android.graphics.Canvas
+android.graphics.Canvas$EdgeType
android.graphics.Color
-android.graphics.ColorFilter
-android.graphics.ColorMatrixColorFilter
-android.graphics.ComposePathEffect
-android.graphics.ComposeShader
-android.graphics.CornerPathEffect
-android.graphics.DashPathEffect
-android.graphics.DiscretePathEffect
-android.graphics.DrawFilter
-android.graphics.EmbossMaskFilter
android.graphics.Interpolator
-android.graphics.LayerRasterizer
-android.graphics.LightingColorFilter
android.graphics.LinearGradient
-android.graphics.MaskFilter
android.graphics.Matrix
-android.graphics.Movie
+android.graphics.Matrix$ScaleToFit
android.graphics.NinePatch
android.graphics.Paint
-android.graphics.Paint$Align
-android.graphics.Paint$Cap
-android.graphics.Paint$FontMetrics
-android.graphics.Paint$FontMetricsInt
-android.graphics.Paint$Join
-android.graphics.Paint$Style
android.graphics.PaintFlagsDrawFilter
android.graphics.Path
-android.graphics.Path$FillType
-android.graphics.PathDashPathEffect
-android.graphics.PathEffect
-android.graphics.PathMeasure
+android.graphics.Path$Direction
android.graphics.Picture
-android.graphics.PixelFormat
-android.graphics.PixelXorXfermode
-android.graphics.Point
-android.graphics.PointF
+android.graphics.PorterDuff
android.graphics.PorterDuff$Mode
-android.graphics.PorterDuffColorFilter
android.graphics.PorterDuffXfermode
-android.graphics.RadialGradient
-android.graphics.Rasterizer
android.graphics.Rect
-android.graphics.Rect$1
android.graphics.RectF
-android.graphics.RectF$1
android.graphics.Region
-android.graphics.Region$1
android.graphics.Region$Op
-android.graphics.RegionIterator
android.graphics.Shader
android.graphics.Shader$TileMode
-android.graphics.SumPathEffect
-android.graphics.SweepGradient
android.graphics.Typeface
android.graphics.Xfermode
-android.graphics.drawable.Animatable
-android.graphics.drawable.AnimatedRotateDrawable
-android.graphics.drawable.AnimatedRotateDrawable$AnimatedRotateState
android.graphics.drawable.AnimationDrawable
-android.graphics.drawable.AnimationDrawable$AnimationState
android.graphics.drawable.BitmapDrawable
android.graphics.drawable.BitmapDrawable$BitmapState
-android.graphics.drawable.ClipDrawable
-android.graphics.drawable.ClipDrawable$ClipState
android.graphics.drawable.ColorDrawable
android.graphics.drawable.ColorDrawable$ColorState
android.graphics.drawable.Drawable
-android.graphics.drawable.Drawable$Callback
-android.graphics.drawable.Drawable$ConstantState
android.graphics.drawable.DrawableContainer
-android.graphics.drawable.DrawableContainer$DrawableContainerState
android.graphics.drawable.GradientDrawable
-android.graphics.drawable.GradientDrawable$GradientState
-android.graphics.drawable.GradientDrawable$Orientation
android.graphics.drawable.LayerDrawable
android.graphics.drawable.LayerDrawable$ChildDrawable
android.graphics.drawable.LayerDrawable$LayerState
@@ -250,432 +194,377 @@ android.graphics.drawable.NinePatchDrawable
android.graphics.drawable.NinePatchDrawable$NinePatchState
android.graphics.drawable.PaintDrawable
android.graphics.drawable.RotateDrawable
+android.graphics.drawable.RotateDrawable$RotateState
+android.graphics.drawable.ScaleDrawable
+android.graphics.drawable.ScaleDrawable$ScaleState
android.graphics.drawable.ShapeDrawable
+android.graphics.drawable.ShapeDrawable$ShapeState
android.graphics.drawable.StateListDrawable
android.graphics.drawable.StateListDrawable$StateListState
android.graphics.drawable.TransitionDrawable
android.graphics.drawable.TransitionDrawable$TransitionState
android.graphics.drawable.shapes.RoundRectShape
-android.hardware.Camera
-android.hardware.ISensorService$Stub
android.hardware.SensorManager
-android.inputmethodservice.AbstractInputMethodService
-android.inputmethodservice.AbstractInputMethodService$AbstractInputMethodSessionImpl
-android.inputmethodservice.ExtractButton
-android.inputmethodservice.ExtractEditText
-android.inputmethodservice.IInputMethodSessionWrapper
-android.inputmethodservice.IInputMethodSessionWrapper$InputMethodEventCallbackWrapper
-android.inputmethodservice.IInputMethodWrapper
-android.inputmethodservice.InputMethodService
-android.inputmethodservice.Keyboard
-android.inputmethodservice.Keyboard$Key
android.inputmethodservice.KeyboardView
-android.inputmethodservice.KeyboardView$2
-android.location.Address
-android.location.Criteria
android.location.ILocationManager$Stub
-android.location.ILocationManager$Stub$Proxy
-android.location.ILocationProvider
-android.location.ILocationProvider$Stub
android.location.Location
-android.location.LocationManager
-android.location.LocationManager$ListenerTransport
-android.location.LocationManager$LpPowerComparator
-android.media.AudioFormat
android.media.AudioManager
-android.media.AudioRecord
-android.media.AudioSystem
-android.media.AudioTrack
-android.media.ExifInterface
-android.media.FaceDetector
-android.media.FaceDetector$Face
android.media.IAudioService$Stub
android.media.IAudioService$Stub$Proxy
-android.media.JetPlayer
-android.media.MediaMetadataRetriever
-android.media.MediaPlayer
-android.media.MediaRecorder
-android.media.MediaScanner
-android.media.MediaScanner$MyMediaScannerClient
-android.media.Ringtone
-android.media.RingtoneManager
-android.media.ToneGenerator
-android.net.ConnectivityManager
-android.net.Credentials
-android.net.DhcpInfo
-android.net.DhcpInfo$1
-android.net.IConnectivityManager$Stub
-android.net.LocalServerSocket
android.net.LocalSocket
+android.net.LocalSocketAddress
android.net.LocalSocketAddress$Namespace
android.net.LocalSocketImpl
android.net.LocalSocketImpl$SocketInputStream
android.net.LocalSocketImpl$SocketOutputStream
-android.net.NetworkConnectivityListener
+android.net.NetworkConnectivityListener$State
android.net.NetworkInfo
android.net.NetworkInfo$DetailedState
-android.net.NetworkUtils
+android.net.SSLCertificateSocketFactory
android.net.Uri
+android.net.Uri$1
+android.net.Uri$AbstractHierarchicalUri
+android.net.Uri$AbstractPart
android.net.Uri$HierarchicalUri
android.net.Uri$OpaqueUri
android.net.Uri$Part
+android.net.Uri$Part$EmptyPart
+android.net.Uri$PathPart
+android.net.Uri$PathSegments
android.net.Uri$StringUri
android.net.WebAddress
android.net.http.AndroidHttpClient
+android.net.http.AndroidHttpClient$1
android.net.http.AndroidHttpClient$2
-android.net.http.CertificateChainValidator
-android.net.http.Connection
+android.net.http.AndroidHttpClient$CurlLogger
android.net.http.DomainNameChecker
+android.net.http.CertificateChainValidator
android.net.http.EventHandler
-android.net.http.Headers
android.net.http.HttpsConnection
-android.net.http.Request
android.net.http.RequestQueue
-android.net.http.SslCertificate
-android.net.vpn.IVpnService$Stub
-android.net.vpn.PptpProfile
-android.net.vpn.VpnManager
-android.net.vpn.VpnProfile
-android.net.vpn.VpnState
-android.net.vpn.VpnType
+android.net.http.SslError
android.net.wifi.IWifiManager$Stub
-android.net.wifi.IWifiManager$Stub$Proxy
-android.net.wifi.WifiManager
-android.net.wifi.WifiNative
-android.opengl.GLES10
-android.opengl.GLES10Ext
-android.opengl.GLES11
-android.opengl.GLES11Ext
-android.opengl.GLU
-android.opengl.GLUtils
-android.opengl.Matrix
-android.opengl.Visibility
-android.os.Base64Utils
+android.net.wifi.SupplicantState
+android.net.wifi.WifiConfiguration
+android.net.wifi.WifiInfo
+android.opengl.Material
android.os.Binder
android.os.BinderProxy
android.os.Build
-android.os.Build$VERSION
android.os.Bundle
-android.os.DeadObjectException
-android.os.Debug
-android.os.Debug$MemoryInfo
+android.os.Bundle$1
android.os.Environment
-android.os.Exec
-android.os.FileObserver$ObserverThread
android.os.FileUtils
-android.os.FileUtils$FileStatus
android.os.Handler
-android.os.Hardware
+android.os.HandlerThread
android.os.IBinder
-android.os.ICheckinService$Stub
android.os.IHardwareService$Stub
-android.os.IInterface
-android.os.IMountService$Stub
-android.os.IParentalControlCallback$Stub
+android.os.IHardwareService$Stub$Proxy
android.os.IPowerManager$Stub
+android.os.IPowerManager$Stub$Proxy
+android.os.IServiceManager
android.os.Looper
-android.os.MemoryFile
android.os.Message
-android.os.NetStat
+android.os.Message$1
+android.os.MessageQueue
+android.os.MessageQueue$IdleHandler
android.os.Parcel
-android.os.Parcel$1
-android.os.ParcelFileDescriptor
-android.os.ParcelFileDescriptor$1
-android.os.Parcelable
-android.os.Parcelable$Creator
android.os.PatternMatcher
-android.os.Power
+android.os.PatternMatcher$1
+android.os.PowerManager
+android.os.PowerManager$WakeLock
+android.os.PowerManager$WakeLock$1
android.os.Process
-android.os.ResultReceiver
-android.os.StatFs
-android.os.SystemClock
-android.os.SystemProperties
-android.os.UEventObserver
-android.pim.EventRecurrence
+android.os.ServiceManager
+android.os.ServiceManagerNative
+android.os.ServiceManagerProxy
+android.os.Vibrator
android.preference.CheckBoxPreference
-android.preference.CheckBoxPreference$SavedState
android.preference.DialogPreference
android.preference.EditTextPreference
android.preference.ListPreference
-android.preference.ListPreference$SavedState
android.preference.Preference
android.preference.PreferenceActivity
android.preference.PreferenceGroup
android.preference.PreferenceGroupAdapter
-android.preference.PreferenceInflater
android.preference.PreferenceManager
android.preference.PreferenceScreen
android.preference.RingtonePreference
-android.preference.VolumePreference
-android.preference.VolumePreference$SeekBarVolumizer
-android.provider.Browser
-android.provider.Calendar$Attendees
-android.provider.Calendar$BusyBits
-android.provider.Calendar$CalendarAlerts
-android.provider.Calendar$Calendars
-android.provider.Calendar$Events
-android.provider.Calendar$Instances
-android.provider.CallLog$Calls
-android.provider.Checkin$Events$Tag
-android.provider.Checkin$Properties
-android.provider.Checkin$Properties$Tag
-android.provider.Checkin$Stats$Tag
-android.provider.Contacts
-android.provider.Contacts$ContactMethods
-android.provider.Contacts$People
-android.provider.Contacts$Phones
-android.provider.Contacts$Presence
-android.provider.Contacts$Settings
-android.provider.Downloads
-android.provider.Gmail
-android.provider.Gmail$AttachmentOrigin
-android.provider.Gmail$AttachmentRendition
-android.provider.Gmail$ConversationCursor
-android.provider.Gmail$CursorStatus
-android.provider.Gmail$LabelMap
-android.provider.Gmail$MessageCursor
-android.provider.Gmail$PersonalLevel
-android.provider.Gmail$Settings
-android.provider.Im$Account
-android.provider.Im$Avatars
-android.provider.Im$Chats
-android.provider.Im$Contacts
-android.provider.Im$LastRmqId
-android.provider.Im$Messages
-android.provider.Im$OutgoingRmq
-android.provider.Im$Presence
-android.provider.Im$Provider
-android.provider.Im$ProviderSettings
-android.provider.MediaStore
-android.provider.MediaStore$Audio$Albums
-android.provider.MediaStore$Audio$Artists
-android.provider.MediaStore$Audio$Artists$Albums
-android.provider.MediaStore$Audio$Media
-android.provider.MediaStore$Audio$Playlists
-android.provider.MediaStore$Images$Media
-android.provider.MediaStore$Images$Thumbnails
-android.provider.SearchRecentSuggestions
-android.provider.Settings$Gservices
-android.provider.Settings$Secure
-android.provider.Settings$System
-android.provider.SubscribedFeeds$Feeds
-android.provider.Telephony$Carriers
-android.provider.Telephony$Mms
-android.provider.Telephony$MmsSms
-android.provider.Telephony$MmsSms$PendingMessages
-android.provider.Telephony$Sms
-android.provider.Telephony$Sms$Conversations
-android.provider.Telephony$Threads
-android.provider.UserDictionary
-android.provider.UserDictionary$Words
android.sax.RootElement
-android.sax.RootElement$Handler
-android.security.Keystore
-android.security.Keystore$FileKeystore
-android.security.Md5MessageDigest
-android.security.MessageDigest
-android.security.ServiceCommand
-android.security.Sha1MessageDigest
-android.server.BluetoothA2dpService
-android.server.BluetoothDeviceService
-android.server.BluetoothEventLoop
-android.server.data.BuildData
-android.server.data.CrashData
-android.server.data.ThrowableData
android.server.search.SearchableInfo
-android.server.search.Searchables
-android.speech.IRecognitionListener$Stub
-android.speech.IRecognitionService$Stub
-android.speech.RecognitionResult
-android.speech.RecognitionServiceUtil
-android.speech.srec.MicrophoneInputStream
-android.speech.srec.Recognizer
-android.speech.tts.ITts$Stub
-android.speech.tts.ITts$Stub$Proxy
-android.speech.tts.TextToSpeech
+android.server.search.SearchableInfo$1
android.telephony.PhoneNumberUtils
-android.telephony.PhoneStateListener$1
+android.telephony.PhoneStateListener
android.telephony.ServiceState
-android.telephony.SignalStrength
-android.telephony.SmsMessage
android.telephony.TelephonyManager
-android.text.AndroidCharacter
-android.text.Annotation
+android.telephony.SmsManager
+android.telephony.SmsMessage
android.text.AutoText
android.text.BoringLayout
+android.text.BoringLayout$Metrics
android.text.DynamicLayout
-android.text.Html
+android.text.DynamicLayout$ChangeWatcher
+android.text.Editable
+android.text.Editable$Factory
+android.text.GetChars
+android.text.GraphicsOperations
android.text.Html$HtmlParser
-android.text.HtmlToSpannedConverter
-android.text.IClipboard$Stub
+android.text.InputFilter
android.text.Layout
+android.text.Layout$Alignment
+android.text.Layout$Directions
+android.text.Layout$Ellipsizer
+android.text.NoCopySpan
+android.text.NoCopySpan$Concrete
+android.text.PackedIntVector
+android.text.PackedObjectVector
+android.text.ParcelableSpan
android.text.Selection
+android.text.Selection$END
+android.text.Selection$START
+android.text.SpanWatcher
+android.text.Spannable
+android.text.Spannable$Factory
+android.text.SpannableString
android.text.SpannableStringBuilder
+android.text.SpannableStringInternal
+android.text.Spanned
android.text.SpannedString
android.text.StaticLayout
+android.text.Styled
+android.text.TextPaint
android.text.TextUtils
+android.text.TextUtils$1
+android.text.TextUtils$EllipsizeCallback
+android.text.TextUtils$SimpleStringSplitter
+android.text.TextUtils$TruncateAt
+android.text.TextWatcher
android.text.format.DateUtils
-android.text.format.Formatter
android.text.format.Time
android.text.method.ArrowKeyMovementMethod
android.text.method.BaseKeyListener
-android.text.method.DialerKeyListener
-android.text.method.DigitsKeyListener
-android.text.method.LinkMovementMethod
+android.text.method.KeyListener
android.text.method.MetaKeyKeyListener
+android.text.method.MovementMethod
android.text.method.QwertyKeyListener
+android.text.method.ReplacementTransformationMethod
android.text.method.ReplacementTransformationMethod$SpannedReplacementCharSequence
android.text.method.SingleLineTransformationMethod
android.text.method.TextKeyListener
-android.text.style.BulletSpan
-android.text.style.ImageSpan
+android.text.method.TextKeyListener$Capitalize
+android.text.method.TextKeyListener$SettingsObserver
+android.text.method.TransformationMethod
+android.text.style.AlignmentSpan
+android.text.style.CharacterStyle
+android.text.style.ForegroundColorSpan
+android.text.style.LeadingMarginSpan
+android.text.style.LineBackgroundSpan
+android.text.style.LineHeightSpan
android.text.style.MetricAffectingSpan
+android.text.style.ParagraphStyle
+android.text.style.ReplacementSpan
android.text.style.StyleSpan
-android.text.style.TextAppearanceSpan
android.text.style.URLSpan
+android.text.style.UpdateAppearance
+android.text.style.UpdateLayout
+android.text.style.WrapTogetherSpan
android.text.util.Linkify
android.text.util.Regex
-android.text.util.Rfc822Validator
+android.util.AndroidRuntimeException
android.util.AttributeSet
android.util.DisplayMetrics
-android.util.EventLog
-android.util.EventLog$Event
-android.util.EventLog$List
android.util.FloatMath
-android.util.Log
-android.util.LongSparseArray
android.util.SparseArray
-android.util.StateSet
android.util.TypedValue
-android.util.Xml
-android.util.Xml$Encoding
+android.util.Xml$XmlSerializerFactory
android.view.AbsSavedState
+android.view.ContextMenu
+android.view.ContextMenu$ContextMenuInfo
android.view.ContextThemeWrapper
android.view.Display
android.view.FocusFinder
-android.view.GestureDetector
+android.view.FocusFinder$1
android.view.GestureDetector$SimpleOnGestureListener
-android.view.IRotationWatcher$Stub
+android.view.Gravity
+android.view.IWindow
+android.view.IWindow$Stub
+android.view.IWindowManager
android.view.IWindowManager$Stub
android.view.IWindowManager$Stub$Proxy
+android.view.IWindowSession
android.view.IWindowSession$Stub
+android.view.IWindowSession$Stub$Proxy
android.view.KeyCharacterMap
-android.view.KeyCharacterMap$KeyData
android.view.KeyEvent
+android.view.KeyEvent$1
+android.view.KeyEvent$Callback
android.view.LayoutInflater
-android.view.MenuInflater$MenuState
+android.view.LayoutInflater$Factory
+android.view.Menu
+android.view.MenuInflater
+android.view.MenuItem
android.view.MotionEvent
+android.view.MotionEvent$1
android.view.Surface
-android.view.Surface$1
-android.view.SurfaceSession
+android.view.SurfaceHolder
android.view.SurfaceView
+android.view.TouchDelegate
android.view.VelocityTracker
android.view.View
+android.view.View$AttachInfo
android.view.View$AttachInfo$Callbacks
-android.view.View$AttachInfo$InvalidateInfo
android.view.View$BaseSavedState
+android.view.View$BaseSavedState$1
+android.view.View$MeasureSpec
+android.view.View$OnCreateContextMenuListener
+android.view.View$ScrollabilityCache
+android.view.ViewConfiguration
android.view.ViewGroup
-android.view.ViewParent
+android.view.ViewGroup$LayoutParams
+android.view.ViewGroup$MarginLayoutParams
+android.view.ViewManager
android.view.ViewRoot
+android.view.ViewRoot$1
+android.view.ViewRoot$InputMethodCallback
+android.view.ViewRoot$RunQueue
+android.view.ViewRoot$TrackballAxis
+android.view.ViewRoot$W
android.view.ViewStub
+android.view.ViewTreeObserver
+android.view.ViewTreeObserver$InternalInsetsInfo
+android.view.ViewTreeObserver$OnPreDrawListener
android.view.Window
+android.view.Window$Callback
+android.view.Window$LocalWindowManager
+android.view.WindowLeaked
+android.view.WindowManager
android.view.WindowManager$LayoutParams
+android.view.WindowManager$LayoutParams$1
android.view.WindowManagerImpl
-android.view.accessibility.AccessibilityEvent
-android.view.accessibility.AccessibilityEvent$1
+android.view.animation.AccelerateDecelerateInterpolator
+android.view.animation.AlphaAnimation
android.view.animation.Animation
android.view.animation.AnimationSet
+android.view.animation.LinearInterpolator
+android.view.animation.Transformation
android.view.inputmethod.BaseInputConnection
android.view.inputmethod.CompletionInfo
+android.view.inputmethod.CompletionInfo$1
+
android.view.inputmethod.EditorInfo
+android.view.inputmethod.EditorInfo$1
+
android.view.inputmethod.ExtractedText
+android.view.inputmethod.ExtractedText$1
+
+android.view.inputmethod.ExtractedTextRequest
+android.view.inputmethod.ExtractedTextRequest$1
+
+android.view.inputmethod.InputBinding
+android.view.inputmethod.InputBinding$1
+android.view.inputmethod.InputConnection
+android.view.inputmethod.InputMethod
+android.view.inputmethod.InputMethod$SessionCallback
+
android.view.inputmethod.InputMethodInfo
+android.view.inputmethod.InputMethodInfo$1
android.view.inputmethod.InputMethodManager
android.view.inputmethod.InputMethodManager$1
+android.view.inputmethod.InputMethodManager$2
+android.view.inputmethod.InputMethodManager$ControlledInputConnectionWrapper
+android.view.inputmethod.InputMethodManager$H
+
+android.view.inputmethod.InputMethodSession
+android.view.inputmethod.InputMethodSession$EventCallback
android.webkit.BrowserFrame
-android.webkit.CacheLoader
android.webkit.CacheManager
android.webkit.CallbackProxy
-android.webkit.CallbackProxy$ResultTransport
android.webkit.CookieManager
android.webkit.CookieSyncManager
-android.webkit.DataLoader
-android.webkit.GearsPermissionsManager
android.webkit.HttpDateTime
android.webkit.JWebCoreJavaBridge
android.webkit.LoadListener
android.webkit.MimeTypeMap
-android.webkit.TextDialog
android.webkit.URLUtil
-android.webkit.WebIconDatabase$IconListener
+android.webkit.WebBackForwardList
+android.webkit.WebHistoryItem
+android.webkit.WebIconDatabase
+android.webkit.WebIconDatabase$EventHandler
+android.webkit.WebIconDatabase$EventHandler$1
+android.webkit.WebIconDatabase$EventHandler$IconResult
android.webkit.WebSettings
+android.webkit.WebSettings$EventHandler
+android.webkit.WebSettings$EventHandler$1
+android.webkit.WebSettings$LayoutAlgorithm
+android.webkit.WebSettings$RenderPriority
android.webkit.WebSettings$TextSize
+android.webkit.WebSyncManager
+android.webkit.WebSyncManager$SyncHandler
+android.webkit.WebTextView
android.webkit.WebView
-android.webkit.WebView$HitTestResult
+android.webkit.WebView$ExtendedZoomControls
+android.webkit.WebView$PrivateHandler
android.webkit.WebViewCore
+android.webkit.WebViewCore$CursorData
+android.webkit.WebViewCore$EventHub
+android.webkit.WebViewCore$EventHub$1
+android.webkit.WebViewCore$WebCoreThread
+android.webkit.WebViewCore$WebCoreThread$1
android.webkit.WebViewDatabase
-android.webkit.gears.ApacheHttpRequestAndroid
-android.webkit.gears.ApacheHttpRequestAndroid$Buffer
-android.webkit.gears.NativeDialog
android.widget.AbsListView
-android.widget.AbsListView$3
+android.widget.AbsListView$CheckForLongPress
+android.widget.AbsListView$CheckForTap
+android.widget.AbsListView$LayoutParams
android.widget.AbsListView$PerformClick
+android.widget.AbsListView$RecycleBin
android.widget.AbsListView$SavedState
+android.widget.AbsListView$SavedState$1
android.widget.AbsSeekBar
android.widget.AbsSpinner
-android.widget.AbsSpinner$SavedState
android.widget.AbsoluteLayout
+android.widget.AbsoluteLayout$LayoutParams
android.widget.AdapterView
-android.widget.AnalogClock
-android.widget.AppSecurityPermissions
-android.widget.AppSecurityPermissions$State
+android.widget.AdapterView$AdapterDataSetObserver
android.widget.ArrayAdapter
android.widget.AutoCompleteTextView
+android.widget.AutoCompleteTextView$DropDownItemClickListener
android.widget.AutoCompleteTextView$DropDownListView
android.widget.BaseAdapter
-android.widget.BaseExpandableListAdapter
+android.widget.Button
android.widget.CheckBox
+android.widget.Checkable
android.widget.CheckedTextView
-android.widget.Chronometer
android.widget.CompoundButton
-android.widget.CompoundButton$SavedState
android.widget.CursorAdapter
+android.widget.CursorAdapter$ChangeObserver
+android.widget.CursorAdapter$MyDataSetObserver
android.widget.CursorTreeAdapter
-android.widget.DatePicker
android.widget.EditText
-android.widget.ExpandableListConnector
-android.widget.ExpandableListConnector$GroupMetadata
android.widget.ExpandableListView
-android.widget.FastScroller
android.widget.FrameLayout
+android.widget.FrameLayout$LayoutParams
android.widget.Gallery
-android.widget.GridView
android.widget.HeaderViewListAdapter
android.widget.ImageView
android.widget.ImageView$ScaleType
android.widget.LinearLayout
+android.widget.LinearLayout$LayoutParams
android.widget.ListView
+android.widget.ListView$ArrowScrollFocusResult
android.widget.ListView$SavedState
-android.widget.MediaController
-android.widget.MultiAutoCompleteTextView
+android.widget.ListView$SavedState$1
android.widget.PopupWindow
-android.widget.PopupWindow$PopupViewContainer
android.widget.ProgressBar
-android.widget.ProgressBar$SavedState
-android.widget.RadioButton
android.widget.RadioGroup
android.widget.RatingBar
android.widget.RelativeLayout
-android.widget.RelativeLayout$DependencyGraph$Node
+android.widget.RelativeLayout$LayoutParams
android.widget.RemoteViews
-android.widget.ResourceCursorAdapter
-android.widget.ResourceCursorTreeAdapter
android.widget.ScrollBarDrawable
android.widget.ScrollView
+android.widget.Scroller
android.widget.SeekBar
-android.widget.SimpleAdapter
android.widget.SimpleCursorAdapter
-android.widget.SimpleCursorTreeAdapter
android.widget.SlidingDrawer
android.widget.Spinner
android.widget.Spinner$DropDownAdapter
@@ -684,335 +573,248 @@ android.widget.TabWidget
android.widget.TableLayout
android.widget.TableRow
android.widget.TextView
+android.widget.TextView$1
+android.widget.TextView$Blink
android.widget.TextView$BufferType
-android.widget.TextView$CommitSelectionReceiver
+android.widget.TextView$ChangeWatcher
+android.widget.TextView$CharWrapper
+android.widget.TextView$Drawables
+android.widget.TextView$InputContentType
+android.widget.TextView$InputMethodState
+android.widget.TextView$Marquee
+android.widget.TextView$MenuHandler
android.widget.TextView$SavedState
-android.widget.TimePicker
-android.widget.TimePicker$SavedState
-android.widget.Toast
-android.widget.Toast$TN
+android.widget.TextView$SavedState$1
+android.widget.ToggleButton
android.widget.TwoLineListItem
-android.widget.VideoView
android.widget.ViewAnimator
android.widget.ViewSwitcher
android.widget.ZoomButton
-android.widget.ZoomButtonsController
android.widget.ZoomControls
-com.android.internal.R$drawable
-com.android.internal.R$styleable
-com.android.internal.app.AlertActivity
-com.android.internal.app.AlertController
-com.android.internal.app.AlertController$AlertParams
-com.android.internal.app.AlertController$AlertParams$1
-com.android.internal.app.AlertController$RecycleListView
-com.android.internal.app.ChooserActivity
-com.android.internal.app.ResolverActivity
-com.android.internal.app.ResolverActivity$ResolveListAdapter
-com.android.internal.app.RingtonePickerActivity
-com.android.internal.appwidget.IAppWidgetHost$Stub
-com.android.internal.appwidget.IAppWidgetService$Stub
com.android.internal.database.ArrayListCursor
com.android.internal.database.SortCursor
-com.android.internal.database.SortCursor$1
-com.android.internal.graphics.NativeUtils
-com.android.internal.location.DummyLocationProvider
-com.android.internal.location.GpsLocationProvider
+com.android.internal.appwidget.IAppWidgetService$Stub
+com.android.internal.http.multipart.FilePart
+com.android.internal.http.multipart.MultipartEntity
+com.android.internal.http.multipart.Part
+com.android.internal.http.multipart.PartSource
+com.android.internal.http.multipart.StringPart
+com.android.internal.logging.AndroidConfig
com.android.internal.logging.AndroidHandler
com.android.internal.os.AndroidPrintStream
-com.android.internal.os.BinderInternal
com.android.internal.os.BinderInternal$GcWatcher
com.android.internal.os.LoggingPrintStream
+com.android.internal.os.LoggingPrintStream$1
com.android.internal.os.RuntimeInit
com.android.internal.os.RuntimeInit$1
-com.android.internal.os.ZygoteConnection
-com.android.internal.os.ZygoteConnection$Arguments
-com.android.internal.os.ZygoteInit
+com.android.internal.os.RuntimeInit$UncaughtHandler
+com.android.internal.os.ZygoteInit$MethodAndArgsCaller
+com.android.internal.policy.IPolicy
com.android.internal.policy.PolicyManager
com.android.internal.policy.impl.PhoneLayoutInflater
com.android.internal.policy.impl.PhoneWindow
+com.android.internal.policy.impl.PhoneWindow$1
+com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback
com.android.internal.policy.impl.PhoneWindow$DecorView
+com.android.internal.policy.impl.PhoneWindow$PanelFeatureState
com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState
-com.android.internal.policy.impl.PhoneWindowManager
+com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState$1
com.android.internal.policy.impl.Policy
-com.android.internal.telephony.GsmAlphabet
+com.android.internal.telephony.Connection$DisconnectCause
+com.android.internal.telephony.Connection$PostDialState
com.android.internal.telephony.IPhoneStateListener$Stub
-com.android.internal.telephony.IPhoneSubInfo$Stub
com.android.internal.telephony.ITelephony$Stub
-com.android.internal.telephony.ITelephony$Stub$Proxy
-com.android.internal.telephony.ITelephonyRegistry$Stub
-com.android.internal.telephony.IccCard$State
+com.android.internal.telephony.Phone
+com.android.internal.telephony.Phone$DataActivityState
+com.android.internal.telephony.Phone$DataState
com.android.internal.telephony.Phone$State
+com.android.internal.telephony.Phone$SuppService
+com.android.internal.telephony.PhoneBase
com.android.internal.telephony.PhoneStateIntentReceiver
-com.android.internal.telephony.SmsMessageBase
-com.android.internal.telephony.gsm.GsmSmsAddress
-com.android.internal.telephony.gsm.SmsMessage
-com.android.internal.telephony.gsm.SmsMessage$SubmitPdu
-com.android.internal.util.ArrayUtils
+com.android.internal.telephony.IccCard$State
+com.android.internal.telephony.BaseCommands
+com.android.internal.telephony.CallForwardInfo
+com.android.internal.telephony.CommandsInterface
+com.android.internal.telephony.DriverCall
+com.android.internal.telephony.DriverCall$State
+com.android.internal.telephony.gsm.GsmConnection
+com.android.internal.telephony.gsm.GSMPhone
+com.android.internal.telephony.GsmAlphabet
+com.android.internal.telephony.gsm.GsmMmiCode
+com.android.internal.telephony.gsm.SimCard
+com.android.internal.telephony.ISms$Stub
+com.android.internal.telephony.RIL
+com.android.internal.telephony.ServiceStateTracker
+
+com.android.internal.telephony.gsm.stk.ComprehensionTlvTag
+com.android.internal.telephony.gsm.stk.ResultCode
com.android.internal.util.FastXmlSerializer
com.android.internal.view.IInputConnectionWrapper
+com.android.internal.view.IInputConnectionWrapper$MyHandler
+com.android.internal.view.IInputConnectionWrapper$SomeArgs
+
+com.android.internal.view.IInputContext
com.android.internal.view.IInputContext$Stub
+com.android.internal.view.IInputContext$Stub$Proxy
+
+com.android.internal.view.IInputContextCallback
+com.android.internal.view.IInputContextCallback$Stub
+com.android.internal.view.IInputContextCallback$Stub$Proxy
+
+com.android.internal.view.IInputMethod
com.android.internal.view.IInputMethod$Stub
+com.android.internal.view.IInputMethod$Stub$Proxy
+
+com.android.internal.view.IInputMethodCallback
+com.android.internal.view.IInputMethodCallback$Stub
+com.android.internal.view.IInputMethodCallback$Stub$Proxy
+
+com.android.internal.view.IInputMethodClient
+com.android.internal.view.IInputMethodClient$Stub
+com.android.internal.view.IInputMethodClient$Stub$Proxy
+
+com.android.internal.view.IInputMethodManager
com.android.internal.view.IInputMethodManager$Stub
+com.android.internal.view.IInputMethodManager$Stub$Proxy
+
+com.android.internal.view.IInputMethodSession
+com.android.internal.view.IInputMethodSession$Stub
+com.android.internal.view.IInputMethodSession$Stub$Proxy
+
+com.android.internal.view.InputBindResult
+com.android.internal.view.InputBindResult$1
+
+com.android.internal.view.InputConnectionWrapper
com.android.internal.view.InputConnectionWrapper$InputContextCallback
com.android.internal.view.menu.ExpandedMenuView
com.android.internal.view.menu.IconMenuItemView
com.android.internal.view.menu.IconMenuView
-com.android.internal.view.menu.IconMenuView$SavedState
com.android.internal.view.menu.ListMenuItemView
com.android.internal.view.menu.MenuBuilder
+com.android.internal.view.menu.MenuBuilder$Callback
+com.android.internal.view.menu.MenuDialogHelper
com.android.internal.view.menu.MenuItemImpl
com.android.internal.view.menu.SubMenuBuilder
-com.android.internal.widget.LockPatternUtils
+com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+com.android.internal.widget.LockPatternView
com.android.internal.widget.NumberPicker
com.android.internal.widget.NumberPickerButton
-com.android.internal.widget.Smileys
com.google.android.gdata.client.AndroidGDataClient
-com.google.android.gdata.client.AndroidXmlParserFactory
+com.google.android.gdata.client.AndroidGDataClient$PostRequestCreator
com.google.android.gles_jni.EGLImpl
com.google.android.gles_jni.GLImpl
+com.google.android.mms.ContentType
+com.google.android.mms.pdu.CharacterSets
+com.google.android.mms.pdu.PduPart
com.google.android.mms.pdu.PduPersister
-com.google.android.mms.util.PduCache
com.google.android.net.GoogleHttpClient
-com.google.android.net.NetworkStatsEntity
com.google.android.net.UrlRules
com.google.android.net.UrlRules$Rule
+com.google.android.util.SimplePullParser
com.google.common.Config
-com.google.common.Log
-com.google.common.android.AndroidConfig
-com.google.common.async.AsyncHttpRequestFactory$AsyncHttpRequestImpl
-com.google.common.graphics.android.AndroidGraphics
-com.google.common.io.BaseHttpConnectionFactory
-com.google.common.io.IoUtil
-com.google.common.io.android.AndroidHttpClient
-com.google.common.io.android.AndroidHttpConnectionFactory
-com.google.common.io.android.AndroidPersistentStore
com.google.common.io.protocol.ProtoBuf
com.google.common.io.protocol.ProtoBufType
com.google.common.util.text.TextUtil
-com.google.masf.BlockingByteQueue
-com.google.masf.MobileServiceMux
-com.google.masf.protocol.PlainRequest
-com.google.masf.services.EventLogService
-com.google.masf.services.LogserviceMessageTypes
-com.google.masf.services.resume.WindowResumeService
-com.google.wireless.gdata.calendar.client.CalendarClient
-com.google.wireless.gdata.client.GDataServiceClient
-com.google.wireless.gdata.contacts.client.ContactsClient
-com.google.wireless.gdata.contacts.parser.xml.XmlContactsGDataParserFactory
com.ibm.icu4jni.charset.CharsetDecoderICU
com.ibm.icu4jni.charset.CharsetEncoderICU
com.ibm.icu4jni.charset.CharsetICU
-com.ibm.icu4jni.charset.CharsetProviderICU
-com.ibm.icu4jni.charset.NativeConverter
-com.ibm.icu4jni.common.ErrorCode
-com.ibm.icu4jni.lang.UCharacter
-com.ibm.icu4jni.regex.NativeRegEx
+com.ibm.icu4jni.text.CollationAttribute
com.ibm.icu4jni.text.DecimalFormat
-com.ibm.icu4jni.text.NativeBreakIterator
-com.ibm.icu4jni.text.NativeCollation
-com.ibm.icu4jni.text.NativeDecimalFormat
+com.ibm.icu4jni.text.DecimalFormatSymbols
com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatAttribute
com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatSymbol
-com.ibm.icu4jni.text.RuleBasedNumberFormat
-com.ibm.icu4jni.util.Resources
-dalvik.system.NativeStart
+com.ibm.icu4jni.text.RuleBasedCollator
+dalvik.system.DexFile
dalvik.system.PathClassLoader
-dalvik.system.TouchDex
-dalvik.system.VMDebug
-dalvik.system.VMRuntime
-dalvik.system.VMStack
-dalvik.system.Zygote
java.beans.PropertyChangeEvent
+java.beans.PropertyChangeListener
java.beans.PropertyChangeSupport
java.io.BufferedInputStream
-java.io.BufferedReader
-java.io.Closeable
-java.io.DataInput
-java.io.DataOutput
-java.io.DataOutputStream
-java.io.EmulatedFieldsForDumping
-java.io.EmulatedFieldsForLoading
+java.io.ByteArrayInputStream
+java.io.ByteArrayOutputStream
java.io.File
java.io.FileDescriptor
java.io.FileInputStream
java.io.FileInputStream$RepositioningLock
-java.io.FileOutputStream
-java.io.FilterOutputStream
-java.io.Flushable
-java.io.InputStream
-java.io.InputStreamReader
-java.io.ObjectInput
-java.io.ObjectInputStream
-java.io.ObjectOutput
-java.io.ObjectOutputStream
+java.io.FileNotFoundException
+java.io.FilterInputStream
+java.io.IOException
java.io.ObjectStreamClass
-java.io.ObjectStreamConstants
-java.io.ObjectStreamField
-java.io.OutputStream
-java.io.PrintStream
java.io.PrintWriter
-java.io.PushbackReader
java.io.RandomAccessFile
-java.io.Reader
-java.io.Serializable
+java.io.RandomAccessFile$RepositionLock
java.io.StringWriter
-java.lang.AbstractStringBuilder
-java.lang.Appendable
-java.lang.ArrayIndexOutOfBoundsException
-java.lang.Boolean
-java.lang.BootClassLoader
-java.lang.Byte
-java.lang.CharSequence
-java.lang.Character
+java.io.Writer
java.lang.Character$valueOfCache
java.lang.Class
java.lang.ClassCache
-java.lang.ClassCache$EnumComparator
-java.lang.ClassLoader
-java.lang.ClassLoader$SystemClassLoader
-java.lang.Cloneable
-java.lang.Comparable
-java.lang.Double
-java.lang.Enum
-java.lang.Error
-java.lang.Exception
-java.lang.Float
+java.lang.ClassNotFoundException
java.lang.IllegalArgumentException
+java.lang.IllegalStateException
java.lang.Integer
java.lang.Integer$valueOfCache
-java.lang.InternalError
-java.lang.InterruptedException
-java.lang.Iterable
-java.lang.LangAccessImpl
java.lang.LinkageError
java.lang.Long
java.lang.Long$valueOfCache
-java.lang.Math
java.lang.NoClassDefFoundError
-java.lang.Number
java.lang.NumberFormatException
java.lang.Object
-java.lang.OutOfMemoryError
-java.lang.Readable
-java.lang.Runnable
java.lang.Runtime
java.lang.RuntimeException
-java.lang.RuntimePermission
-java.lang.SecurityException
-java.lang.Short
java.lang.Short$valueOfCache
-java.lang.StackOverflowError
-java.lang.StackTraceElement
-java.lang.StrictMath
java.lang.String
-java.lang.String$CaseInsensitiveComparator
java.lang.StringBuffer
java.lang.StringBuilder
-java.lang.System
-java.lang.SystemProperties
java.lang.Thread
-java.lang.Thread$State
-java.lang.Thread$UncaughtExceptionHandler
-java.lang.ThreadGroup
-java.lang.ThreadGroup$ChildrenGroupsLock
-java.lang.ThreadGroup$ChildrenThreadsLock
+java.lang.ThreadLocal
+java.lang.ThreadLocal$Values
java.lang.Throwable
-java.lang.UnsatisfiedLinkError
-java.lang.UnsupportedOperationException
-java.lang.VMClassLoader
java.lang.VMThread
-java.lang.VirtualMachineError
-java.lang.Void
-java.lang.annotation.Annotation
-java.lang.ref.Reference
java.lang.ref.ReferenceQueue
java.lang.ref.SoftReference
java.lang.ref.WeakReference
-java.lang.reflect.AccessibleObject
-java.lang.reflect.AnnotatedElement
-java.lang.reflect.Array
java.lang.reflect.Constructor
-java.lang.reflect.Field
-java.lang.reflect.GenericDeclaration
-java.lang.reflect.InvocationHandler
-java.lang.reflect.Member
java.lang.reflect.Method
java.lang.reflect.Modifier
-java.lang.reflect.Proxy
-java.lang.reflect.ReflectionAccessImpl
-java.lang.reflect.Type
java.math.BigDecimal
java.math.BigInt
java.math.BigInteger
java.math.Multiplication
-java.net.DatagramPacket
-java.net.HttpURLConnection
-java.net.Inet4Address
+java.net.ContentHandler
java.net.InetAddress
+java.net.InetAddress$CacheElement
java.net.InetAddress$WaitReachable
-java.net.InetSocketAddress
java.net.JarURLConnection
-java.net.NetworkInterface
-java.net.Proxy
-java.net.ProxySelector
+java.net.NegativeCache
+java.net.NetPermission
java.net.ProxySelectorImpl
-java.net.ServerSocket
-java.net.Socket
-java.net.SocketImpl
-java.net.SocketOptions
+java.net.Socket$ConnectLock
java.net.URI
java.net.URL
java.net.URLConnection
-java.nio.BaseByteBuffer
-java.nio.Buffer
-java.nio.BufferFactory
-java.nio.ByteBuffer
+java.net.URLConnection$DefaultContentHandler
+java.net.URLStreamHandler
java.nio.ByteOrder
-java.nio.CharArrayBuffer
-java.nio.CharBuffer
java.nio.CharSequenceAdapter
-java.nio.CharToByteBufferAdapter
java.nio.DirectByteBuffer
-java.nio.FloatBuffer
-java.nio.FloatToByteBufferAdapter
-java.nio.HeapByteBuffer
-java.nio.IntToByteBufferAdapter
-java.nio.NIOAccess
-java.nio.ReadWriteCharArrayBuffer
java.nio.ReadWriteDirectByteBuffer
-java.nio.ReadWriteHeapByteBuffer
java.nio.ReadWriteIntArrayBuffer
+java.nio.ReadWriteShortArrayBuffer
+java.nio.ShortBuffer
java.nio.ShortToByteBufferAdapter
-java.nio.channels.ByteChannel
-java.nio.channels.Channel
-java.nio.channels.FileChannel
-java.nio.channels.GatheringByteChannel
-java.nio.channels.InterruptibleChannel
-java.nio.channels.ReadableByteChannel
-java.nio.channels.ScatteringByteChannel
-java.nio.channels.WritableByteChannel
-java.nio.channels.spi.AbstractInterruptibleChannel
-java.nio.channels.spi.AbstractInterruptibleChannel$1
-java.nio.charset.Charset
-java.nio.charset.Charset$1
-java.nio.charset.CharsetDecoder
java.nio.charset.CharsetEncoder
-java.nio.charset.CoderResult
-java.nio.charset.CodingErrorAction
-java.nio.charset.spi.CharsetProvider
-java.security.AccessController
-java.security.BasicPermission
-java.security.Guard
+java.security.AccessControlContext
+java.security.GeneralSecurityException
java.security.KeyStore
java.security.MessageDigest
-java.security.Permission
-java.security.PrivilegedAction
-java.security.PrivilegedExceptionAction
+java.security.ProtectionDomain
java.security.Provider
java.security.SecureRandom
java.security.Security
-java.security.cert.CertificateParsingException
+java.security.cert.CertPathValidator
+java.security.cert.CertificateFactory
java.security.cert.PKIXParameters
+java.security.cert.TrustAnchor
java.security.cert.X509CertSelector
java.security.cert.X509Certificate
java.text.Collator
@@ -1020,339 +822,356 @@ java.text.DateFormat
java.text.DateFormat$Field
java.text.DecimalFormat
java.text.DecimalFormatSymbols
-java.text.Format
+java.text.MessageFormat
java.text.NumberFormat
+java.text.RuleBasedCollator
java.text.SimpleDateFormat
-java.util.AbstractCollection
-java.util.AbstractList
-java.util.AbstractMap
-java.util.AbstractSet
+java.util.AbstractList$FullListIterator
+java.util.AbstractList$SimpleListIterator
java.util.ArrayList
java.util.Arrays
-java.util.BitSet
+java.util.Arrays$ArrayList
java.util.Calendar
-java.util.Collection
-java.util.Collections
-java.util.Collections$EmptyList
-java.util.Collections$EmptyMap
-java.util.Collections$EmptySet
-java.util.Collections$SynchronizedList
-java.util.Collections$SynchronizedRandomAccessList
-java.util.Collections$UnmodifiableCollection
-java.util.Collections$UnmodifiableCollection$1
+java.util.Collections$SynchronizedCollection
java.util.Collections$UnmodifiableList
-java.util.Collections$UnmodifiableRandomAccessList
-java.util.Collections$UnmodifiableSet
-java.util.Comparator
+java.util.Collections$UnmodifiableMap
+java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1
java.util.Date
-java.util.Dictionary
java.util.EnumMap
-java.util.EnumSet
-java.util.Enumeration
+java.util.EventListener
+java.util.EventObject
java.util.Formatter
java.util.GregorianCalendar
java.util.HashMap
java.util.HashMap$1
-java.util.HashMap$1$1
+java.util.HashMap$2
+java.util.HashMap$AbstractMapIterator
java.util.HashMap$Entry
-java.util.HashMap$HashMapIterator
+java.util.HashMap$EntryIterator
+java.util.HashMap$HashMapEntrySet
+java.util.HashMap$KeyIterator
+java.util.HashMap$ValueIterator
java.util.HashSet
java.util.Hashtable
-java.util.Hashtable$1
+java.util.Hashtable$6
+java.util.Hashtable$6$1
java.util.Hashtable$Entry
+java.util.Hashtable$HashEnumIterator
+java.util.Hashtable$HashIterator
java.util.IdentityHashMap
-java.util.Iterator
+java.util.LinkedHashMap
+java.util.LinkedHashMap$LinkedHashMapEntry
java.util.LinkedList
+java.util.LinkedList$Link
java.util.List
java.util.Locale
-java.util.Map
-java.util.Map$Entry
-java.util.MapEntry
-java.util.MapEntry$Type
-java.util.PriorityQueue
java.util.Properties
-java.util.PropertyPermission
-java.util.RandomAccess
+java.util.Random
java.util.ResourceBundle
-java.util.Scanner
-java.util.Set
java.util.SimpleTimeZone
-java.util.SortedMap
-java.util.SortedSet
-java.util.SpecialAccess
-java.util.Stack
-java.util.StringTokenizer
java.util.TimeZone
-java.util.Timer
java.util.TreeMap
+java.util.TreeMap$MapEntry
java.util.TreeSet
java.util.Vector
-java.util.Vector$1
java.util.WeakHashMap
java.util.WeakHashMap$Entry
-java.util.concurrent.AbstractExecutorService
-java.util.concurrent.ArrayBlockingQueue
java.util.concurrent.ConcurrentHashMap
-java.util.concurrent.ConcurrentHashMap$Segment
-java.util.concurrent.CopyOnWriteArrayList
+java.util.concurrent.ConcurrentLinkedQueue
java.util.concurrent.DelayQueue
-java.util.concurrent.Executors$DelegatedExecutorService
-java.util.concurrent.Executors$DelegatedScheduledExecutorService
java.util.concurrent.LinkedBlockingQueue
java.util.concurrent.ScheduledThreadPoolExecutor
java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue
-java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask
-java.util.concurrent.Semaphore
-java.util.concurrent.SynchronousQueue
-java.util.concurrent.SynchronousQueue$Node
-java.util.concurrent.ThreadPoolExecutor
java.util.concurrent.TimeUnit
+java.util.concurrent.atomic.AtomicBoolean
java.util.concurrent.atomic.AtomicInteger
-java.util.concurrent.atomic.AtomicLong
-java.util.concurrent.atomic.AtomicReference
java.util.concurrent.atomic.UnsafeAccess
java.util.concurrent.locks.AbstractQueuedSynchronizer
+java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject
+java.util.concurrent.locks.AbstractQueuedSynchronizer$Node
+java.util.concurrent.locks.Lock
+java.util.concurrent.locks.LockSupport
java.util.concurrent.locks.ReentrantLock
+java.util.concurrent.locks.ReentrantLock$FairSync
+java.util.concurrent.locks.ReentrantLock$NonfairSync
java.util.concurrent.locks.ReentrantLock$Sync
+java.util.concurrent.locks.ReentrantReadWriteLock
+java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync
+java.util.concurrent.locks.UnsafeAccess
+java.util.jar.Attributes
java.util.jar.Attributes$Name
+java.util.jar.InitManifest
+java.util.jar.JarEntry
java.util.jar.JarFile
+java.util.jar.JarFile$1JarFileEnumerator
+java.util.jar.JarFile$JarFileInputStream
+java.util.jar.JarVerifier
java.util.jar.Manifest
+java.util.logging.ErrorManager
+java.util.logging.Formatter
+java.util.logging.Handler
java.util.logging.Level
java.util.logging.LogManager
+java.util.logging.LogManager$1
+java.util.logging.LogManager$2
+java.util.logging.LogManager$2$1
+java.util.logging.LogManager$3
java.util.logging.LogRecord
java.util.logging.Logger
-java.util.regex.MatchResult
+java.util.logging.LoggingPermission
+java.util.logging.SimpleFormatter
java.util.regex.Matcher
java.util.regex.Pattern
-java.util.zip.Adler32
-java.util.zip.CRC32
-java.util.zip.Checksum
-java.util.zip.Deflater
java.util.zip.DeflaterOutputStream
java.util.zip.Inflater
+java.util.zip.InflaterInputStream
+java.util.zip.ZipConstants
+java.util.zip.ZipEntry
+java.util.zip.ZipEntry$LittleEndianReader
java.util.zip.ZipFile
-javax.crypto.Cipher
-javax.crypto.spec.SecretKeySpec
-javax.microedition.khronos.egl.EGL
-javax.microedition.khronos.egl.EGL10
+java.util.zip.ZipFile$2
+java.util.zip.ZipFile$RAFStream
javax.microedition.khronos.egl.EGLContext
-javax.microedition.khronos.opengles.GL
-javax.microedition.khronos.opengles.GL10
-javax.microedition.khronos.opengles.GL10Ext
-javax.microedition.khronos.opengles.GL11
-javax.microedition.khronos.opengles.GL11Ext
-javax.microedition.khronos.opengles.GL11ExtensionPack
-javax.net.ssl.DefaultHostnameVerifier
javax.net.ssl.HttpsURLConnection
-javax.net.ssl.SSLContext
javax.net.ssl.SSLHandshakeException
-javax.net.ssl.SSLServerSocket
-javax.net.ssl.SSLSession
-javax.net.ssl.SSLSocket
+javax.security.auth.x500.X500Principal
javax.security.cert.X509Certificate
+javax.security.cert.X509Certificate$2
junit.framework.Assert
org.apache.commons.codec.binary.Base64
org.apache.commons.codec.binary.Hex
org.apache.commons.logging.LogFactory
org.apache.commons.logging.impl.Jdk14Logger
-org.apache.harmony.dalvik.NativeTestTarget
+org.apache.harmony.archive.util.Util
+org.apache.harmony.dalvik.ddmc.Chunk
org.apache.harmony.dalvik.ddmc.ChunkHandler
org.apache.harmony.dalvik.ddmc.DdmServer
-org.apache.harmony.kernel.vm.LangAccess
-org.apache.harmony.kernel.vm.ReflectionAccess
-org.apache.harmony.lang.annotation.AnnotationFactory
-org.apache.harmony.lang.annotation.AnnotationMember
-org.apache.harmony.lang.annotation.AnnotationMember$DefaultValues
-org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnection
+org.apache.harmony.dalvik.ddmc.DdmVmInternal
+org.apache.harmony.luni.internal.net.www.protocol.file.FileURLConnection
+org.apache.harmony.luni.internal.net.www.protocol.file.Handler
+org.apache.harmony.luni.internal.net.www.protocol.http.Handler
org.apache.harmony.luni.internal.net.www.protocol.https.Handler
org.apache.harmony.luni.internal.net.www.protocol.jar.Handler
org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection
+org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection$1
+org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnection$JarURLConnectionInputStream
+org.apache.harmony.luni.internal.util.TimezoneGetter
+org.apache.harmony.luni.internal.util.ZoneInfo
org.apache.harmony.luni.internal.util.ZoneInfoDB
-org.apache.harmony.luni.net.GenericIPMreq
org.apache.harmony.luni.net.PlainSocketImpl
-org.apache.harmony.luni.platform.AdapterManager
-org.apache.harmony.luni.platform.Endianness
-org.apache.harmony.luni.platform.IAdaptable
-org.apache.harmony.luni.platform.IAdapterManager
-org.apache.harmony.luni.platform.ICommonDataTypes
-org.apache.harmony.luni.platform.IFileSystem
-org.apache.harmony.luni.platform.IMemorySystem
-org.apache.harmony.luni.platform.INetworkSystem
-org.apache.harmony.luni.platform.ISystemComponent
-org.apache.harmony.luni.platform.OSComponent
-org.apache.harmony.luni.platform.OSComponentFactory
-org.apache.harmony.luni.platform.OSFileSystem
-org.apache.harmony.luni.platform.OSMemory
-org.apache.harmony.luni.platform.OSNetworkSystem
-org.apache.harmony.luni.platform.Platform
org.apache.harmony.luni.platform.PlatformAddress
-org.apache.harmony.luni.platform.PlatformAddressFactory
-org.apache.harmony.luni.util.FloatingPointParser
-org.apache.harmony.luni.util.NumberConverter
-org.apache.harmony.luni.util.PriviAction
-org.apache.harmony.luni.util.Util
-org.apache.harmony.nio.AddressUtil
-org.apache.harmony.nio.FileChannelFactory
-org.apache.harmony.nio.internal.DirectBuffer
-org.apache.harmony.nio.internal.FileChannelImpl
+org.apache.harmony.luni.util.TwoKeyHashMap
org.apache.harmony.nio.internal.FileChannelImpl$RepositioningLock
org.apache.harmony.nio.internal.LockManager
org.apache.harmony.nio.internal.LockManager$1
-org.apache.harmony.nio.internal.WriteOnlyFileChannel
+org.apache.harmony.nio.internal.ReadOnlyFileChannel
+org.apache.harmony.security.asn1.ASN1BitString
+org.apache.harmony.security.asn1.ASN1BitString$ASN1NamedBitList
+org.apache.harmony.security.asn1.ASN1Boolean
+org.apache.harmony.security.asn1.ASN1Explicit
org.apache.harmony.security.asn1.ASN1GeneralizedTime
+org.apache.harmony.security.asn1.ASN1Implicit
org.apache.harmony.security.asn1.ASN1Integer
-org.apache.harmony.security.asn1.ASN1Oid
-org.apache.harmony.security.asn1.ASN1Sequence
+org.apache.harmony.security.asn1.ASN1OctetString
+org.apache.harmony.security.asn1.ASN1SetOf
org.apache.harmony.security.asn1.ASN1StringType
-org.apache.harmony.security.asn1.DerInputStream
-org.apache.harmony.security.asn1.DerOutputStream
+org.apache.harmony.security.asn1.ASN1StringType$1
+org.apache.harmony.security.asn1.ASN1StringType$2
+org.apache.harmony.security.asn1.ASN1StringType$3
+org.apache.harmony.security.asn1.ASN1StringType$4
+org.apache.harmony.security.asn1.ASN1StringType$5
+org.apache.harmony.security.asn1.ASN1StringType$6
+org.apache.harmony.security.asn1.ASN1StringType$7
+org.apache.harmony.security.asn1.ASN1UTCTime
+org.apache.harmony.security.asn1.BitString
+org.apache.harmony.security.fortress.Engine
+org.apache.harmony.security.fortress.SecurityUtils
org.apache.harmony.security.fortress.Services
org.apache.harmony.security.pkcs7.ContentInfo
-org.apache.harmony.security.provider.cert.DRLCertFactory
org.apache.harmony.security.provider.cert.X509CertFactoryImpl
org.apache.harmony.security.provider.cert.X509CertImpl
org.apache.harmony.security.provider.cert.X509CertPathImpl
org.apache.harmony.security.provider.crypto.RandomBitsSupplier
org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl
-org.apache.harmony.security.provider.crypto.SHA1_MessageDigestImpl
org.apache.harmony.security.utils.AlgNameMapper
org.apache.harmony.security.x501.AttributeTypeAndValue
+org.apache.harmony.security.x501.AttributeValue
org.apache.harmony.security.x501.DirectoryString
+org.apache.harmony.security.x501.DirectoryString$1
org.apache.harmony.security.x501.Name
+org.apache.harmony.security.x501.Name$1
org.apache.harmony.security.x509.AlgorithmIdentifier
+org.apache.harmony.security.x509.AlgorithmIdentifier$1
org.apache.harmony.security.x509.BasicConstraints
+org.apache.harmony.security.x509.BasicConstraints$1
org.apache.harmony.security.x509.Certificate
-org.apache.harmony.security.x509.EDIPartyName
+org.apache.harmony.security.x509.Certificate$1
org.apache.harmony.security.x509.Extension
+org.apache.harmony.security.x509.Extension$1
+org.apache.harmony.security.x509.Extension$2
org.apache.harmony.security.x509.Extensions
+org.apache.harmony.security.x509.Extensions$1
org.apache.harmony.security.x509.GeneralName
org.apache.harmony.security.x509.GeneralNames
org.apache.harmony.security.x509.KeyUsage
org.apache.harmony.security.x509.ORAddress
-org.apache.harmony.security.x509.OtherName
-org.apache.harmony.security.x509.PolicyQualifierInfo
org.apache.harmony.security.x509.SubjectPublicKeyInfo
+org.apache.harmony.security.x509.SubjectPublicKeyInfo$1
org.apache.harmony.security.x509.TBSCertificate
+org.apache.harmony.security.x509.TBSCertificate$1
org.apache.harmony.security.x509.Time
+org.apache.harmony.security.x509.Time$1
org.apache.harmony.security.x509.Validity
-org.apache.harmony.text.BidiWrapper
-org.apache.harmony.xml.ExpatAttributes
+org.apache.harmony.security.x509.Validity$1
org.apache.harmony.xml.ExpatParser
org.apache.harmony.xml.ExpatPullParser
-org.apache.harmony.xml.ExpatPullParser$ByteDocument
org.apache.harmony.xml.ExpatReader
-org.apache.harmony.xml.dom.AttrImpl
-org.apache.harmony.xml.dom.CharacterDataImpl
-org.apache.harmony.xml.dom.CommentImpl
-org.apache.harmony.xml.dom.DocumentImpl
-org.apache.harmony.xml.dom.ElementImpl
-org.apache.harmony.xml.dom.InnerNodeImpl
-org.apache.harmony.xml.dom.NodeImpl
-org.apache.harmony.xml.dom.TextImpl
-org.apache.harmony.xml.parsers.DocumentBuilderFactoryImpl
-org.apache.harmony.xml.parsers.DocumentBuilderImpl
-org.apache.harmony.xml.parsers.SAXParserFactoryImpl
-org.apache.harmony.xnet.provider.jsse.AbstractSessionContext
-org.apache.harmony.xnet.provider.jsse.FileClientSessionCache
-org.apache.harmony.xnet.provider.jsse.NativeCrypto
-org.apache.harmony.xnet.provider.jsse.OpenSSLServerSocketImpl
+org.apache.harmony.xnet.provider.jsse.ClientSessionContext
org.apache.harmony.xnet.provider.jsse.OpenSSLSessionImpl
-org.apache.harmony.xnet.provider.jsse.OpenSSLSocketFactoryImpl
org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl
org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$Finalizer
-org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$LoggerHolder
-org.apache.harmony.xnet.provider.jsse.ProtocolVersion
+org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream
+org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream
org.apache.harmony.xnet.provider.jsse.SSLContextImpl
org.apache.harmony.xnet.provider.jsse.SSLParameters
-org.apache.harmony.xnet.provider.jsse.ServerSessionContext
+org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl
+org.apache.harmony.xnet.provider.jsse.TrustManagerImpl
+org.apache.http.HttpHost
+org.apache.http.HttpRequestInterceptor
org.apache.http.HttpVersion
-org.apache.http.NoHttpResponseException
-org.apache.http.ProtocolException
+org.apache.http.auth.AuthSchemeRegistry
org.apache.http.client.HttpClient
-org.apache.http.client.methods.HttpEntityEnclosingRequestBase
-org.apache.http.client.methods.HttpGet
-org.apache.http.client.methods.HttpPost
+org.apache.http.client.RequestDirector
org.apache.http.client.methods.HttpRequestBase
-org.apache.http.conn.BasicManagedEntity
-org.apache.http.conn.params.ConnManagerParams
+org.apache.http.client.protocol.RequestAddCookies
+org.apache.http.client.protocol.RequestDefaultHeaders
+org.apache.http.client.protocol.RequestProxyAuthentication
+org.apache.http.client.protocol.RequestTargetAuthentication
+org.apache.http.client.protocol.ResponseProcessCookies
+org.apache.http.conn.params.ConnManagerParams$1
org.apache.http.conn.params.ConnRouteParams
org.apache.http.conn.routing.HttpRoute
+org.apache.http.conn.routing.RouteInfo$LayerType
+org.apache.http.conn.routing.RouteInfo$TunnelType
+org.apache.http.conn.routing.RouteTracker
org.apache.http.conn.scheme.PlainSocketFactory
-org.apache.http.conn.ssl.AbstractVerifier
+org.apache.http.conn.scheme.Scheme
+org.apache.http.conn.scheme.SchemeRegistry
+org.apache.http.conn.ssl.AllowAllHostnameVerifier
+org.apache.http.conn.ssl.BrowserCompatHostnameVerifier
org.apache.http.conn.ssl.SSLSocketFactory
+org.apache.http.conn.ssl.StrictHostnameVerifier
org.apache.http.conn.util.InetAddressUtils
-org.apache.http.entity.BasicHttpEntity
-org.apache.http.entity.InputStreamEntity
-org.apache.http.entity.StringEntity
-org.apache.http.impl.AbstractHttpClientConnection
+org.apache.http.cookie.CookieSpecRegistry
+org.apache.http.impl.DefaultConnectionReuseStrategy
+org.apache.http.impl.DefaultHttpResponseFactory
org.apache.http.impl.EnglishReasonPhraseCatalog
org.apache.http.impl.HttpConnectionMetricsImpl
org.apache.http.impl.SocketHttpClientConnection
+org.apache.http.impl.auth.BasicSchemeFactory
+org.apache.http.impl.auth.DigestSchemeFactory
org.apache.http.impl.client.AbstractAuthenticationHandler
org.apache.http.impl.client.AbstractHttpClient
+org.apache.http.impl.client.BasicCredentialsProvider
org.apache.http.impl.client.DefaultHttpClient
+org.apache.http.impl.client.DefaultHttpRequestRetryHandler
+org.apache.http.impl.client.DefaultProxyAuthenticationHandler
+org.apache.http.impl.client.DefaultRedirectHandler
+org.apache.http.impl.client.DefaultTargetAuthenticationHandler
+org.apache.http.impl.client.DefaultUserTokenHandler
org.apache.http.impl.client.EntityEnclosingRequestWrapper
org.apache.http.impl.conn.AbstractClientConnAdapter
-org.apache.http.impl.conn.AbstractPooledConnAdapter
org.apache.http.impl.conn.DefaultClientConnection
-org.apache.http.impl.conn.SingleClientConnManager
+org.apache.http.impl.conn.DefaultClientConnectionOperator
+org.apache.http.impl.conn.DefaultHttpRoutePlanner
+org.apache.http.impl.conn.DefaultResponseParser
+org.apache.http.impl.conn.IdleConnectionHandler
+org.apache.http.impl.conn.tsccm.BasicPoolEntry
+org.apache.http.impl.conn.tsccm.BasicPoolEntryRef
org.apache.http.impl.conn.tsccm.ConnPoolByRoute
+org.apache.http.impl.conn.tsccm.RefQueueWorker
+org.apache.http.impl.conn.tsccm.RouteSpecificPool
org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager
org.apache.http.impl.cookie.BasicClientCookie
-org.apache.http.impl.cookie.BrowserCompatSpec
+org.apache.http.impl.cookie.BestMatchSpecFactory
+org.apache.http.impl.cookie.BrowserCompatSpecFactory
org.apache.http.impl.cookie.DateUtils
-org.apache.http.impl.cookie.RFC2109Spec
-org.apache.http.impl.cookie.RFC2965Spec
-org.apache.http.impl.io.AbstractSessionInputBuffer
+org.apache.http.impl.cookie.NetscapeDraftSpecFactory
+org.apache.http.impl.cookie.RFC2109SpecFactory
+org.apache.http.impl.cookie.RFC2965SpecFactory
+org.apache.http.impl.entity.EntityDeserializer
+org.apache.http.impl.entity.EntitySerializer
+org.apache.http.impl.entity.LaxContentLengthStrategy
+org.apache.http.impl.entity.StrictContentLengthStrategy
+org.apache.http.impl.io.HttpRequestWriter
+org.apache.http.impl.io.HttpTransportMetricsImpl
org.apache.http.impl.io.SocketInputBuffer
-org.apache.http.message.AbstractHttpMessage
-org.apache.http.message.BasicHeaderElement
+org.apache.http.impl.io.SocketOutputBuffer
+org.apache.http.message.BasicHeaderValueParser
org.apache.http.message.BasicHttpEntityEnclosingRequest
-org.apache.http.message.BasicHttpRequest
org.apache.http.message.BasicHttpResponse
org.apache.http.message.BasicLineFormatter
org.apache.http.message.BasicLineParser
-org.apache.http.message.BasicTokenIterator
-org.apache.http.params.AbstractHttpParams
org.apache.http.params.BasicHttpParams
org.apache.http.protocol.BasicHttpProcessor
org.apache.http.protocol.HTTP
-org.bouncycastle.asn1.DERNull
+org.apache.http.protocol.HttpRequestExecutor
+org.apache.http.protocol.HttpRequestInterceptorList
+org.apache.http.protocol.HttpResponseInterceptorList
+org.apache.http.protocol.RequestConnControl
+org.apache.http.protocol.RequestContent
+org.apache.http.protocol.RequestExpectContinue
+org.apache.http.protocol.RequestTargetHost
+org.apache.http.protocol.RequestUserAgent
+org.apache.http.util.ByteArrayBuffer
+org.apache.http.util.CharArrayBuffer
+org.apache.http.util.EntityUtils
+org.apache.http.util.VersionInfo
+org.bouncycastle.asn1.DERBitString
+org.bouncycastle.asn1.DERIA5String
+org.bouncycastle.asn1.DERInteger
org.bouncycastle.asn1.DERObject
org.bouncycastle.asn1.DERObjectIdentifier
-org.bouncycastle.asn1.iana.IANAObjectIdentifiers
+org.bouncycastle.asn1.DEROctetString
+org.bouncycastle.asn1.DERPrintableString
+org.bouncycastle.asn1.DERSequence
+org.bouncycastle.asn1.DERSet
+org.bouncycastle.asn1.DERTaggedObject
+org.bouncycastle.asn1.DERUTCTime
+org.bouncycastle.asn1.DERUTF8String
+org.bouncycastle.asn1.OrderedTable
org.bouncycastle.asn1.nist.NISTObjectIdentifiers
-org.bouncycastle.asn1.oiw.OIWObjectIdentifiers
org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
+org.bouncycastle.asn1.x509.AlgorithmIdentifier
+org.bouncycastle.asn1.x509.RSAPublicKeyStructure
+org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
+org.bouncycastle.asn1.x509.TBSCertificateStructure
+org.bouncycastle.asn1.x509.Time
+org.bouncycastle.asn1.x509.X509CertificateStructure
+org.bouncycastle.asn1.x509.X509Extension
org.bouncycastle.asn1.x509.X509Extensions
org.bouncycastle.asn1.x509.X509Name
-org.bouncycastle.crypto.digests.SHA1Digest
+org.bouncycastle.asn1.x509.X509NameElementList
+org.bouncycastle.asn1.x9.X9ObjectIdentifiers
org.bouncycastle.crypto.engines.AESFastEngine
-org.bouncycastle.crypto.generators.PKCS12ParametersGenerator
-org.bouncycastle.crypto.macs.HMac
-org.bouncycastle.jce.provider.BouncyCastleProvider
org.bouncycastle.jce.provider.CertPathValidatorUtilities
-org.bouncycastle.jce.provider.JCEBlockCipher
org.bouncycastle.jce.provider.JCEBlockCipher$AES
-org.bouncycastle.jce.provider.JCEMac
-org.bouncycastle.jce.provider.JDKKeyFactory
+org.bouncycastle.jce.provider.JCERSAPublicKey
org.bouncycastle.jce.provider.JDKKeyFactory$RSA
org.bouncycastle.jce.provider.JDKKeyStore
-org.bouncycastle.jce.provider.JDKX509CertificateFactory
+org.bouncycastle.jce.provider.JDKKeyStore$StoreEntry
org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi
-org.bouncycastle.jce.provider.WrapCipherSpi
+org.bouncycastle.jce.provider.RSAUtil
org.bouncycastle.jce.provider.X509CertificateObject
-org.ccil.cowan.tagsoup.AttributesImpl
org.ccil.cowan.tagsoup.HTMLScanner
-org.ccil.cowan.tagsoup.HTMLSchema
org.ccil.cowan.tagsoup.Parser
+org.json.JSONArray
org.json.JSONObject
+org.json.JSONStringer
org.kxml2.io.KXmlParser
org.kxml2.io.KXmlSerializer
-org.openssl.NativeBN
-org.xml.sax.Attributes
org.xml.sax.helpers.DefaultHandler
-org.xmlpull.v1.XmlPullParser
-org.xmlpull.v1.XmlPullParserException
+org.xml.sax.helpers.NewInstance
+org.xmlpull.v1.XmlPullParserFactory
org.xmlpull.v1.sax2.Driver
sun.misc.Unsafe
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 6e28515..4eed7fe 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -31,6 +31,7 @@ import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.PackageInfo;
+import android.content.pm.PermissionInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
@@ -46,6 +47,8 @@ import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
@@ -91,6 +94,20 @@ class BackupManagerService extends IBackupManager.Stub {
private static final int MSG_RUN_RESTORE = 3;
private static final int MSG_RUN_CLEAR = 4;
+ // Event tags -- see system/core/logcat/event-log-tags
+ private static final int BACKUP_DATA_CHANGED_EVENT = 2820;
+ private static final int BACKUP_START_EVENT = 2821;
+ private static final int BACKUP_TRANSPORT_FAILURE_EVENT = 2822;
+ private static final int BACKUP_AGENT_FAILURE_EVENT = 2823;
+ private static final int BACKUP_PACKAGE_EVENT = 2824;
+ private static final int BACKUP_SUCCESS_EVENT = 2825;
+
+ private static final int RESTORE_START_EVENT = 2830;
+ private static final int RESTORE_TRANSPORT_FAILURE_EVENT = 2831;
+ private static final int RESTORE_AGENT_FAILURE_EVENT = 2832;
+ private static final int RESTORE_PACKAGE_EVENT = 2833;
+ private static final int RESTORE_SUCCESS_EVENT = 2834;
+
// Timeout interval for deciding that a bind or clear-data has taken too long
static final long TIMEOUT_INTERVAL = 10 * 1000;
@@ -100,18 +117,18 @@ class BackupManagerService extends IBackupManager.Stub {
private PowerManager mPowerManager;
private AlarmManager mAlarmManager;
- private boolean mEnabled; // access to this is synchronized on 'this'
- private boolean mProvisioned;
- private PowerManager.WakeLock mWakelock;
- private final BackupHandler mBackupHandler = new BackupHandler();
- private PendingIntent mRunBackupIntent;
- private BroadcastReceiver mRunBackupReceiver;
- private IntentFilter mRunBackupFilter;
+ boolean mEnabled; // access to this is synchronized on 'this'
+ boolean mProvisioned;
+ PowerManager.WakeLock mWakelock;
+ final BackupHandler mBackupHandler = new BackupHandler();
+ PendingIntent mRunBackupIntent;
+ BroadcastReceiver mRunBackupReceiver;
+ IntentFilter mRunBackupFilter;
// map UIDs to the set of backup client services within that UID's app set
- private final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
+ final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
= new SparseArray<HashSet<ApplicationInfo>>();
// set of backup services that have pending changes
- private class BackupRequest {
+ class BackupRequest {
public ApplicationInfo appInfo;
public boolean fullBackup;
@@ -125,35 +142,35 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
// Backups that we haven't started yet.
- private HashMap<ApplicationInfo,BackupRequest> mPendingBackups
+ HashMap<ApplicationInfo,BackupRequest> mPendingBackups
= new HashMap<ApplicationInfo,BackupRequest>();
// Pseudoname that we use for the Package Manager metadata "package"
- private static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
+ static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
// locking around the pending-backup management
- private final Object mQueueLock = new Object();
+ final Object mQueueLock = new Object();
// The thread performing the sequence of queued backups binds to each app's agent
// in succession. Bind notifications are asynchronously delivered through the
// Activity Manager; use this lock object to signal when a requested binding has
// completed.
- private final Object mAgentConnectLock = new Object();
- private IBackupAgent mConnectedAgent;
- private volatile boolean mConnecting;
+ final Object mAgentConnectLock = new Object();
+ IBackupAgent mConnectedAgent;
+ volatile boolean mConnecting;
// A similar synchronicity mechanism around clearing apps' data for restore
- private final Object mClearDataLock = new Object();
- private volatile boolean mClearingData;
+ final Object mClearDataLock = new Object();
+ volatile boolean mClearingData;
// Transport bookkeeping
- private final HashMap<String,IBackupTransport> mTransports
+ final HashMap<String,IBackupTransport> mTransports
= new HashMap<String,IBackupTransport>();
- private String mCurrentTransport;
- private IBackupTransport mLocalTransport, mGoogleTransport;
- private RestoreSession mActiveRestoreSession;
+ String mCurrentTransport;
+ IBackupTransport mLocalTransport, mGoogleTransport;
+ RestoreSession mActiveRestoreSession;
- private class RestoreParams {
+ class RestoreParams {
public IBackupTransport transport;
public IRestoreObserver observer;
public long token;
@@ -165,7 +182,7 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- private class ClearParams {
+ class ClearParams {
public IBackupTransport transport;
public PackageInfo packageInfo;
@@ -176,11 +193,17 @@ class BackupManagerService extends IBackupManager.Stub {
}
// Where we keep our journal files and other bookkeeping
- private File mBaseStateDir;
- private File mDataDir;
- private File mJournalDir;
- private File mJournal;
- private RandomAccessFile mJournalStream;
+ File mBaseStateDir;
+ File mDataDir;
+ File mJournalDir;
+ File mJournal;
+ RandomAccessFile mJournalStream;
+
+ // Keep a log of all the apps we've ever backed up
+ private File mEverStored;
+ private RandomAccessFile mEverStoredStream;
+ HashSet<String> mEverStoredApps = new HashSet<String>();
+
public BackupManagerService(Context context) {
mContext = context;
@@ -195,7 +218,7 @@ class BackupManagerService extends IBackupManager.Stub {
Settings.Secure.BACKUP_ENABLED, 0) != 0;
// !!! TODO: mProvisioned needs to default to 0, not 1.
mProvisioned = Settings.Secure.getInt(context.getContentResolver(),
- Settings.Secure.BACKUP_PROVISIONED, 1) != 0;
+ Settings.Secure.BACKUP_PROVISIONED, 0) != 0;
mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
mDataDir = Environment.getDownloadCacheDirectory();
@@ -215,6 +238,9 @@ class BackupManagerService extends IBackupManager.Stub {
mJournalDir.mkdirs(); // creates mBaseStateDir along the way
makeJournalLocked(); // okay because no other threads are running yet
+ // Set up the various sorts of package tracking we do
+ initPackageTracking();
+
// Build our mapping of uid to backup client services. This implicitly
// schedules a backup pass on the Package Manager metadata the first
// time anything needs to be backed up.
@@ -249,14 +275,6 @@ class BackupManagerService extends IBackupManager.Stub {
// leftover journal files into the pending backup set
parseLeftoverJournals();
- // Register for broadcasts about package install, etc., so we can
- // update the provider list.
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- mContext.registerReceiver(mBroadcastReceiver, filter);
-
// Power management
mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "backup");
@@ -281,6 +299,73 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ private void initPackageTracking() {
+ if (DEBUG) Log.v(TAG, "Initializing package tracking");
+
+ // Keep a log of what apps we've ever backed up. Because we might have
+ // rebooted in the middle of an operation that was removing something from
+ // this log, we sanity-check its contents here and reconstruct it.
+ mEverStored = new File(mBaseStateDir, "processed");
+ File tempProcessedFile = new File(mBaseStateDir, "processed.new");
+ try {
+ // If there are previous contents, parse them out then start a new
+ // file to continue the recordkeeping.
+ if (mEverStored.exists()) {
+ RandomAccessFile temp = new RandomAccessFile(tempProcessedFile, "rw");
+ mEverStoredStream = new RandomAccessFile(mEverStored, "r");
+
+ // parse its existing contents
+ mEverStoredStream.seek(0);
+ temp.seek(0);
+ try {
+ while (true) {
+ PackageInfo info;
+ String pkg = mEverStoredStream.readUTF();
+ try {
+ info = mPackageManager.getPackageInfo(pkg, 0);
+ mEverStoredApps.add(pkg);
+ temp.writeUTF(pkg);
+ if (DEBUG) Log.v(TAG, " + " + pkg);
+ } catch (NameNotFoundException e) {
+ // nope, this package was uninstalled; don't include it
+ if (DEBUG) Log.v(TAG, " - " + pkg);
+ }
+ }
+ } catch (EOFException e) {
+ // now we're at EOF
+ }
+
+ // Once we've rewritten the backup history log, atomically replace the
+ // old one with the new one then reopen the file for continuing use.
+ temp.close();
+ mEverStoredStream.close();
+ tempProcessedFile.renameTo(mEverStored);
+ }
+ // This will create the file if it doesn't exist
+ mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
+ mEverStoredStream.seek(mEverStoredStream.length());
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to open known-stored file!");
+ mEverStoredStream = null;
+ }
+
+ // If we were in the middle of removing something from the ever-backed-up
+ // file, there might be a transient "processed.new" file still present.
+ // We've reconstructed a coherent state at this point though, so we can
+ // safely discard that file now.
+ if (tempProcessedFile.exists()) {
+ tempProcessedFile.delete();
+ }
+
+ // Register for broadcasts about package install, etc., so we can
+ // update the provider list.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+ }
+
private void makeJournalLocked() {
try {
mJournal = File.createTempFile("journal", null, mJournalDir);
@@ -485,6 +570,17 @@ class BackupManagerService extends IBackupManager.Stub {
mBackupParticipants.put(uid, set);
}
set.add(pkg.applicationInfo);
+
+ // If we've never seen this app before, schedule a backup for it
+ if (!mEverStoredApps.contains(pkg.packageName)) {
+ if (DEBUG) Log.i(TAG, "New app " + pkg.packageName
+ + " never backed up; scheduling");
+ try {
+ dataChanged(pkg.packageName);
+ } catch (RemoteException e) {
+ // can't happen; it's a local method call
+ }
+ }
}
}
}
@@ -528,6 +624,7 @@ class BackupManagerService extends IBackupManager.Stub {
for (ApplicationInfo entry: set) {
if (entry.packageName.equals(pkg.packageName)) {
set.remove(entry);
+ removeEverBackedUp(pkg.packageName);
break;
}
}
@@ -540,15 +637,18 @@ class BackupManagerService extends IBackupManager.Stub {
}
// Returns the set of all applications that define an android:backupAgent attribute
- private List<PackageInfo> allAgentPackages() {
+ List<PackageInfo> allAgentPackages() {
// !!! TODO: cache this and regenerate only when necessary
int flags = PackageManager.GET_SIGNATURES;
List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
int N = packages.size();
for (int a = N-1; a >= 0; a--) {
- ApplicationInfo app = packages.get(a).applicationInfo;
+ PackageInfo pkg = packages.get(a);
+ ApplicationInfo app = pkg.applicationInfo;
if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
- || app.backupAgentName == null) {
+ || app.backupAgentName == null
+ || (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
+ pkg.packageName) != PackageManager.PERMISSION_GRANTED)) {
packages.remove(a);
}
}
@@ -570,6 +670,65 @@ class BackupManagerService extends IBackupManager.Stub {
addPackageParticipantsLockedInner(packageName, allApps);
}
+ // Called from the backup thread: record that the given app has been successfully
+ // backed up at least once
+ void logBackupComplete(String packageName) {
+ if (mEverStoredStream != null && !packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
+ synchronized (mEverStoredApps) {
+ if (mEverStoredApps.add(packageName)) {
+ try {
+ mEverStoredStream.writeUTF(packageName);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to log backup of " + packageName + ", ceasing log");
+ try {
+ mEverStoredStream.close();
+ } catch (IOException ioe) {
+ // we're dropping it; no need to handle an exception on close here
+ }
+ mEverStoredStream = null;
+ }
+ }
+ }
+ }
+ }
+
+ // Remove our awareness of having ever backed up the given package
+ void removeEverBackedUp(String packageName) {
+ if (DEBUG) Log.v(TAG, "Removing backed-up knowledge of " + packageName
+ + ", new set:");
+
+ if (mEverStoredStream != null) {
+ synchronized (mEverStoredApps) {
+ // Rewrite the file and rename to overwrite. If we reboot in the middle,
+ // we'll recognize on initialization time that the package no longer
+ // exists and fix it up then.
+ File tempKnownFile = new File(mBaseStateDir, "processed.new");
+ try {
+ mEverStoredStream.close();
+ RandomAccessFile known = new RandomAccessFile(tempKnownFile, "rw");
+ mEverStoredApps.remove(packageName);
+ for (String s : mEverStoredApps) {
+ known.writeUTF(s);
+ if (DEBUG) Log.v(TAG, " " + s);
+ }
+ known.close();
+ tempKnownFile.renameTo(mEverStored);
+ mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
+ } catch (IOException e) {
+ // Bad: we couldn't create the new copy. For safety's sake we
+ // abandon the whole process and remove all what's-backed-up
+ // state entirely, meaning we'll force a backup pass for every
+ // participant on the next boot or [re]install.
+ Log.w(TAG, "Error rewriting backed-up set; halting log");
+ mEverStoredStream = null;
+ mEverStoredApps.clear();
+ tempKnownFile.delete();
+ mEverStored.delete();
+ }
+ }
+ }
+ }
+
// Return the given transport
private IBackupTransport getTransport(String transportName) {
synchronized (mTransports) {
@@ -637,6 +796,14 @@ class BackupManagerService extends IBackupManager.Stub {
synchronized(mClearDataLock) {
mClearingData = true;
+ /* This is causing some critical processes to be killed during setup.
+ Temporarily revert this change until we find a better solution.
+ try {
+ mActivityManager.clearApplicationUserData(packageName, observer);
+ } catch (RemoteException e) {
+ // can't happen because the activity manager is in this process
+ }
+ */
mPackageManager.clearApplicationUserData(packageName, observer);
// only wait 10 seconds for the clear data to happen
@@ -654,7 +821,7 @@ class BackupManagerService extends IBackupManager.Stub {
class ClearDataObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(String packageName, boolean succeeded)
- throws android.os.RemoteException {
+ throws RemoteException {
synchronized(mClearDataLock) {
mClearingData = false;
mClearDataLock.notifyAll();
@@ -687,49 +854,64 @@ class BackupManagerService extends IBackupManager.Stub {
@Override
public void run() {
+ long startRealtime = SystemClock.elapsedRealtime();
if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
// Backups run at background priority
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- // The package manager doesn't have a proper <application> etc, but since
- // it's running here in the system process we can just set up its agent
- // directly and use a synthetic BackupRequest. We always run this pass
- // because it's cheap and this way we guarantee that we don't get out of
- // step even if we're selecting among various transports at run time.
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
- mPackageManager, allAgentPackages());
- BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
- pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
- processOneBackup(pmRequest,
- IBackupAgent.Stub.asInterface(pmAgent.onBind()),
- mTransport);
-
- // Now run all the backups in our queue
- doQueuedBackups(mTransport);
-
- // Finally, tear down the transport
try {
- if (!mTransport.finishBackup()) {
- // STOPSHIP TODO: handle errors
- Log.e(TAG, "Backup failure in finishBackup()");
+ EventLog.writeEvent(BACKUP_START_EVENT, mTransport.transportDirName());
+
+ // The package manager doesn't have a proper <application> etc, but since
+ // it's running here in the system process we can just set up its agent
+ // directly and use a synthetic BackupRequest. We always run this pass
+ // because it's cheap and this way we guarantee that we don't get out of
+ // step even if we're selecting among various transports at run time.
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, allAgentPackages());
+ BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
+ pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
+ processOneBackup(pmRequest,
+ IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
+
+ // Now run all the backups in our queue
+ int count = mQueue.size();
+ doQueuedBackups(mTransport);
+
+ // Finally, tear down the transport
+ if (mTransport.finishBackup()) {
+ int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+ EventLog.writeEvent(BACKUP_SUCCESS_EVENT, count, millis);
+ } else {
+ EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, "");
+ Log.e(TAG, "Transport error in finishBackup()");
}
- } catch (RemoteException e) {
- Log.e(TAG, "Error in finishBackup()", e);
- }
- if (!mJournal.delete()) {
- Log.e(TAG, "Unable to remove backup journal file " + mJournal.getAbsolutePath());
+ if (!mJournal.delete()) {
+ Log.e(TAG, "Unable to remove backup journal file " + mJournal);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error in backup thread", e);
+ } finally {
+ // Only once we're entirely finished do we release the wakelock
+ mWakelock.release();
}
-
- // Only once we're entirely finished do we release the wakelock
- mWakelock.release();
}
private void doQueuedBackups(IBackupTransport transport) {
for (BackupRequest request : mQueue) {
Log.d(TAG, "starting agent for backup of " + request);
+ // Don't run backup, even if requested, if the target app does not have
+ // the requisite permission
+ if (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
+ request.appInfo.packageName) != PackageManager.PERMISSION_GRANTED) {
+ Log.w(TAG, "Skipping backup of unprivileged package "
+ + request.appInfo.packageName);
+ continue;
+ }
+
IBackupAgent agent = null;
int mode = (request.fullBackup)
? IApplicationThread.BACKUP_MODE_FULL
@@ -749,19 +931,27 @@ class BackupManagerService extends IBackupManager.Stub {
Log.v(TAG, "bind/backup threw");
e.printStackTrace();
}
-
}
}
void processOneBackup(BackupRequest request, IBackupAgent agent, IBackupTransport transport) {
final String packageName = request.appInfo.packageName;
- Log.d(TAG, "processOneBackup doBackup() on " + packageName);
+ if (DEBUG) Log.d(TAG, "processOneBackup doBackup() on " + packageName);
+ // !!! TODO: get the state file dir from the transport
+ File savedStateName = new File(mStateDir, packageName);
+ File backupDataName = new File(mDataDir, packageName + ".data");
+ File newStateName = new File(mStateDir, packageName + ".new");
+
+ ParcelFileDescriptor savedState = null;
+ ParcelFileDescriptor backupData = null;
+ ParcelFileDescriptor newState = null;
+
+ PackageInfo packInfo;
try {
// Look up the package info & signatures. This is first so that if it
// throws an exception, there's no file setup yet that would need to
// be unraveled.
- PackageInfo packInfo;
if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
// The metadata 'package' is synthetic
packInfo = new PackageInfo();
@@ -771,68 +961,65 @@ class BackupManagerService extends IBackupManager.Stub {
PackageManager.GET_SIGNATURES);
}
- // !!! TODO: get the state file dir from the transport
- File savedStateName = new File(mStateDir, packageName);
- File backupDataName = new File(mDataDir, packageName + ".data");
- File newStateName = new File(mStateDir, packageName + ".new");
-
// In a full backup, we pass a null ParcelFileDescriptor as
// the saved-state "file"
- ParcelFileDescriptor savedState = (request.fullBackup) ? null
- : ParcelFileDescriptor.open(savedStateName,
+ if (!request.fullBackup) {
+ savedState = ParcelFileDescriptor.open(savedStateName,
ParcelFileDescriptor.MODE_READ_ONLY |
- ParcelFileDescriptor.MODE_CREATE);
+ ParcelFileDescriptor.MODE_CREATE); // Make an empty file if necessary
+ }
- backupDataName.delete();
- ParcelFileDescriptor backupData =
- ParcelFileDescriptor.open(backupDataName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ backupData = ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
- newStateName.delete();
- ParcelFileDescriptor newState =
- ParcelFileDescriptor.open(newStateName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ newState = ParcelFileDescriptor.open(newStateName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
// Run the target's backup pass
- boolean success = false;
- try {
- agent.doBackup(savedState, backupData, newState);
- success = true;
- } finally {
- if (savedState != null) {
- savedState.close();
- }
- backupData.close();
- newState.close();
- }
+ agent.doBackup(savedState, backupData, newState);
+ logBackupComplete(packageName);
+ if (DEBUG) Log.v(TAG, "doBackup() success");
+ } catch (Exception e) {
+ Log.e(TAG, "Error backing up " + packageName, e);
+ EventLog.writeEvent(BACKUP_AGENT_FAILURE_EVENT, packageName, e.toString());
+ backupDataName.delete();
+ newStateName.delete();
+ return;
+ } finally {
+ try { if (savedState != null) savedState.close(); } catch (IOException e) {}
+ try { if (backupData != null) backupData.close(); } catch (IOException e) {}
+ try { if (newState != null) newState.close(); } catch (IOException e) {}
+ savedState = backupData = newState = null;
+ }
- // Now propagate the newly-backed-up data to the transport
- if (success) {
- if (DEBUG) Log.v(TAG, "doBackup() success");
- if (backupDataName.length() > 0) {
- backupData =
- ParcelFileDescriptor.open(backupDataName,
- ParcelFileDescriptor.MODE_READ_ONLY);
- if (!transport.performBackup(packInfo, backupData)) {
- // STOPSHIP TODO: handle errors
- Log.e(TAG, "Backup failure in performBackup()");
- }
- } else {
- if (DEBUG) {
- Log.i(TAG, "no backup data written; not calling transport");
- }
- }
+ // Now propagate the newly-backed-up data to the transport
+ try {
+ int size = (int) backupDataName.length();
+ if (size > 0) {
+ backupData = ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_ONLY);
- // After successful transport, delete the now-stale data
- // and juggle the files so that next time we supply the agent
- // with the new state file it just created.
- backupDataName.delete();
- newStateName.renameTo(savedStateName);
+ if (!transport.performBackup(packInfo, backupData)) throw new Exception();
+ } else {
+ if (DEBUG) Log.i(TAG, "no backup data written; not calling transport");
}
+
+ // After successful transport, delete the now-stale data
+ // and juggle the files so that next time we supply the agent
+ // with the new state file it just created.
+ backupDataName.delete();
+ newStateName.renameTo(savedStateName);
+ EventLog.writeEvent(BACKUP_PACKAGE_EVENT, packageName, size);
} catch (Exception e) {
- Log.e(TAG, "Error backing up " + packageName, e);
+ Log.e(TAG, "Transport error backing up " + packageName, e);
+ EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, packageName);
+ return;
+ } finally {
+ try { if (backupData != null) backupData.close(); } catch (IOException e) {}
}
}
}
@@ -878,7 +1065,6 @@ class BackupManagerService extends IBackupManager.Stub {
private IBackupTransport mTransport;
private IRestoreObserver mObserver;
private long mToken;
- private RestoreSet mImage;
private File mStateDir;
class RestoreRequest {
@@ -908,14 +1094,15 @@ class BackupManagerService extends IBackupManager.Stub {
@Override
public void run() {
+ long startRealtime = SystemClock.elapsedRealtime();
if (DEBUG) Log.v(TAG, "Beginning restore process mTransport=" + mTransport
- + " mObserver=" + mObserver + " mToken=" + mToken);
+ + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken));
/**
* Restore sequence:
*
* 1. get the restore set description for our identity
* 2. for each app in the restore set:
- * 3.a. if it's restorable on this device, add it to the restore queue
+ * 2.a. if it's restorable on this device, add it to the restore queue
* 3. for each app in the restore queue:
* 3.a. clear the app data
* 3.b. get the restore data for the app from the transport
@@ -923,25 +1110,18 @@ class BackupManagerService extends IBackupManager.Stub {
* 3.d. agent.doRestore() with the data from the server
* 3.e. unbind the agent [and kill the app?]
* 4. shut down the transport
+ *
+ * On errors, we try our best to recover and move on to the next
+ * application, but if necessary we abort the whole operation --
+ * the user is waiting, after al.
*/
int error = -1; // assume error
// build the set of apps to restore
try {
- RestoreSet[] images = mTransport.getAvailableRestoreSets();
- if (images == null) {
- // STOPSHIP TODO: Handle the failure somehow?
- Log.e(TAG, "Error getting restore sets");
- return;
- }
-
- if (images.length == 0) {
- Log.i(TAG, "No restore sets available");
- return;
- }
-
- mImage = images[0];
+ // TODO: Log this before getAvailableRestoreSets, somehow
+ EventLog.writeEvent(RESTORE_START_EVENT, mTransport.transportDirName());
// Get the list of all packages which have backup enabled.
// (Include the Package Manager metadata pseudo-package first.)
@@ -966,22 +1146,26 @@ class BackupManagerService extends IBackupManager.Stub {
}
if (!mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0]))) {
- // STOPSHIP TODO: Handle the failure somehow?
Log.e(TAG, "Error starting restore operation");
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
return;
}
String packageName = mTransport.nextRestorePackage();
if (packageName == null) {
- // STOPSHIP TODO: Handle the failure somehow?
Log.e(TAG, "Error getting first restore package");
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
return;
} else if (packageName.equals("")) {
Log.i(TAG, "No restore data available");
+ int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+ EventLog.writeEvent(RESTORE_SUCCESS_EVENT, 0, millis);
return;
} else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
Log.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
+ "\", found only \"" + packageName + "\"");
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, PACKAGE_MANAGER_SENTINEL,
+ "Package manager data missing");
return;
}
@@ -994,23 +1178,25 @@ class BackupManagerService extends IBackupManager.Stub {
// signature/version verification etc, so we simply do not proceed with
// the restore operation.
if (!pmAgent.hasMetadata()) {
- Log.i(TAG, "No restore metadata available, so not restoring settings");
+ Log.e(TAG, "No restore metadata available, so not restoring settings");
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, PACKAGE_MANAGER_SENTINEL,
+ "Package manager restore metadata missing");
return;
}
int count = 0;
for (;;) {
packageName = mTransport.nextRestorePackage();
+
if (packageName == null) {
- // STOPSHIP TODO: Handle the failure somehow?
Log.e(TAG, "Error getting next restore package");
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
return;
} else if (packageName.equals("")) {
break;
}
if (mObserver != null) {
- ++count;
try {
mObserver.onUpdate(count);
} catch (RemoteException e) {
@@ -1022,21 +1208,34 @@ class BackupManagerService extends IBackupManager.Stub {
Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
if (metaInfo == null) {
Log.e(TAG, "Missing metadata for " + packageName);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Package metadata missing");
+ continue;
+ }
+
+ PackageInfo packageInfo;
+ try {
+ int flags = PackageManager.GET_SIGNATURES;
+ packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Invalid package restoring data", e);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Package missing on device");
continue;
}
- int flags = PackageManager.GET_SIGNATURES;
- PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
if (metaInfo.versionCode > packageInfo.versionCode) {
- Log.w(TAG, "Package " + packageName
- + " restore version [" + metaInfo.versionCode
- + "] is too new for installed version ["
- + packageInfo.versionCode + "]");
+ String message = "Version " + metaInfo.versionCode
+ + " > installed version " + packageInfo.versionCode;
+ Log.w(TAG, "Package " + packageName + ": " + message);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName, message);
continue;
}
if (!signaturesMatch(metaInfo.signatures, packageInfo.signatures)) {
Log.w(TAG, "Signature mismatch restoring " + packageName);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Signature mismatch");
continue;
}
@@ -1052,11 +1251,14 @@ class BackupManagerService extends IBackupManager.Stub {
IApplicationThread.BACKUP_MODE_RESTORE);
if (agent == null) {
Log.w(TAG, "Can't find backup agent for " + packageName);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName,
+ "Restore agent missing");
continue;
}
try {
processOneRestore(packageInfo, metaInfo.versionCode, agent);
+ ++count;
} finally {
// unbind even on timeout or failure, just in case
mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
@@ -1065,21 +1267,19 @@ class BackupManagerService extends IBackupManager.Stub {
// if we get this far, report success to the observer
error = 0;
- } catch (NameNotFoundException e) {
- // STOPSHIP TODO: Handle the failure somehow?
- Log.e(TAG, "Invalid paackage restoring data", e);
- } catch (RemoteException e) {
- // STOPSHIP TODO: Handle the failure somehow?
- Log.e(TAG, "Error restoring data", e);
+ int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+ EventLog.writeEvent(RESTORE_SUCCESS_EVENT, count, millis);
+ } catch (Exception e) {
+ Log.e(TAG, "Error in restore thread", e);
} finally {
+ if (DEBUG) Log.d(TAG, "finishing restore mObserver=" + mObserver);
+
try {
mTransport.finishRestore();
} catch (RemoteException e) {
Log.e(TAG, "Error finishing restore", e);
}
- Log.d(TAG, "finishing restore mObserver=" + mObserver);
-
if (mObserver != null) {
try {
mObserver.restoreFinished(error);
@@ -1098,51 +1298,64 @@ class BackupManagerService extends IBackupManager.Stub {
// !!! TODO: actually run the restore through mTransport
final String packageName = app.packageName;
- Log.d(TAG, "processOneRestore packageName=" + packageName);
+ if (DEBUG) Log.d(TAG, "processOneRestore packageName=" + packageName);
+
+ // Don't restore to unprivileged packages
+ if (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
+ packageName) != PackageManager.PERMISSION_GRANTED) {
+ Log.d(TAG, "Skipping restore of unprivileged package " + packageName);
+ }
// !!! TODO: get the dirs from the transport
File backupDataName = new File(mDataDir, packageName + ".restore");
- backupDataName.delete();
+ File newStateName = new File(mStateDir, packageName + ".new");
+ File savedStateName = new File(mStateDir, packageName);
+
+ ParcelFileDescriptor backupData = null;
+ ParcelFileDescriptor newState = null;
+
try {
- ParcelFileDescriptor backupData =
- ParcelFileDescriptor.open(backupDataName,
+ // Run the transport's restore pass
+ backupData = ParcelFileDescriptor.open(backupDataName,
ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
- // Run the transport's restore pass
- // Run the target's backup pass
- try {
- if (!mTransport.getRestoreData(backupData)) {
- // STOPSHIP TODO: Handle this error somehow?
- Log.e(TAG, "Error getting restore data for " + packageName);
- return;
- }
- } finally {
- backupData.close();
+ if (!mTransport.getRestoreData(backupData)) {
+ Log.e(TAG, "Error getting restore data for " + packageName);
+ EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
+ return;
}
// Okay, we have the data. Now have the agent do the restore.
- File newStateName = new File(mStateDir, packageName + ".new");
- ParcelFileDescriptor newState =
- ParcelFileDescriptor.open(newStateName,
- ParcelFileDescriptor.MODE_READ_WRITE |
- ParcelFileDescriptor.MODE_CREATE);
-
+ backupData.close();
backupData = ParcelFileDescriptor.open(backupDataName,
ParcelFileDescriptor.MODE_READ_ONLY);
- try {
- agent.doRestore(backupData, appVersionCode, newState);
- } finally {
- newState.close();
- backupData.close();
- }
+ newState = ParcelFileDescriptor.open(newStateName,
+ ParcelFileDescriptor.MODE_READ_WRITE |
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE);
+
+ agent.doRestore(backupData, appVersionCode, newState);
// if everything went okay, remember the recorded state now
- File savedStateName = new File(mStateDir, packageName);
newStateName.renameTo(savedStateName);
+ int size = (int) backupDataName.length();
+ EventLog.writeEvent(RESTORE_PACKAGE_EVENT, packageName, size);
} catch (Exception e) {
Log.e(TAG, "Error restoring data for " + packageName, e);
+ EventLog.writeEvent(RESTORE_AGENT_FAILURE_EVENT, packageName, e.toString());
+
+ // If the agent fails restore, it might have put the app's data
+ // into an incoherent state. For consistency we wipe its data
+ // again in this case before propagating the exception
+ clearApplicationDataSynchronous(packageName);
+ } finally {
+ backupDataName.delete();
+ try { if (backupData != null) backupData.close(); } catch (IOException e) {}
+ try { if (newState != null) newState.close(); } catch (IOException e) {}
+ backupData = newState = null;
}
}
}
@@ -1188,6 +1401,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Record that we need a backup pass for the caller. Since multiple callers
// may share a uid, we need to note all candidates within that uid and schedule
// a backup pass for each of them.
+ EventLog.writeEvent(BACKUP_DATA_CHANGED_EVENT, packageName);
// If the caller does not hold the BACKUP permission, it can only request a
// backup of its own data.
@@ -1235,7 +1449,8 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
} else {
- Log.w(TAG, "dataChanged but no participant pkg='" + packageName + "'");
+ Log.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
+ + " uid=" + Binder.getCallingUid());
}
}
@@ -1288,10 +1503,12 @@ class BackupManagerService extends IBackupManager.Stub {
if (DEBUG) Log.v(TAG, "Found the app - running clear process");
// found it; fire off the clear request
synchronized (mQueueLock) {
+ long oldId = Binder.clearCallingIdentity();
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
new ClearParams(getTransport(mCurrentTransport), info));
mBackupHandler.sendMessage(msg);
+ Binder.restoreCallingIdentity(oldId);
}
break;
}
@@ -1301,7 +1518,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Run a backup pass immediately for any applications that have declared
// that they have pending updates.
public void backupNow() throws RemoteException {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "backupNow");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
synchronized (mQueueLock) {
@@ -1370,13 +1587,13 @@ class BackupManagerService extends IBackupManager.Stub {
// Report whether the backup mechanism is currently enabled
public boolean isBackupEnabled() {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
return mEnabled; // no need to synchronize just to read it
}
// Report the name of the currently active transport
public String getCurrentTransport() {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getCurrentTransport");
Log.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
return mCurrentTransport;
@@ -1405,7 +1622,7 @@ class BackupManagerService extends IBackupManager.Stub {
// name is not one of the available transports, no action is taken and the method
// returns null.
public String selectBackupTransport(String transport) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "selectBackupTransport");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "selectBackupTransport");
synchronized (mTransports) {
String prevTransport = null;
@@ -1459,7 +1676,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Hand off a restore session
public IRestoreSession beginRestoreSession(String transport) {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "beginRestoreSession");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "beginRestoreSession");
synchronized(this) {
if (mActiveRestoreSession != null) {
@@ -1484,55 +1701,71 @@ class BackupManagerService extends IBackupManager.Stub {
}
// --- Binder interface ---
- public RestoreSet[] getAvailableRestoreSets() throws android.os.RemoteException {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ public synchronized RestoreSet[] getAvailableRestoreSets() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getAvailableRestoreSets");
try {
- synchronized(this) {
- if (mRestoreSets == null) {
+ if (mRestoreTransport == null) {
+ Log.w(TAG, "Null transport getting restore sets");
+ return null;
+ }
+ if (mRestoreSets == null) { // valid transport; do the one-time fetch
mRestoreSets = mRestoreTransport.getAvailableRestoreSets();
+ if (mRestoreSets == null) EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
}
return mRestoreSets;
- }
- } catch (RuntimeException e) {
- Log.d(TAG, "getAvailableRestoreSets exception");
- e.printStackTrace();
- throw e;
+ } catch (Exception e) {
+ Log.e(TAG, "Error in getAvailableRestoreSets", e);
+ return null;
}
}
- public int performRestore(long token, IRestoreObserver observer)
- throws android.os.RemoteException {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "performRestore");
+ public synchronized int performRestore(long token, IRestoreObserver observer) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "performRestore");
- Log.d(TAG, "performRestore token=" + token + " observer=" + observer);
+ if (DEBUG) Log.d(TAG, "performRestore token=" + Long.toHexString(token)
+ + " observer=" + observer);
- if (mRestoreSets != null) {
- for (int i = 0; i < mRestoreSets.length; i++) {
- if (token == mRestoreSets[i].token) {
- mWakelock.acquire();
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, observer, token);
- mBackupHandler.sendMessage(msg);
- return 0;
- }
+ if (mRestoreTransport == null || mRestoreSets == null) {
+ Log.e(TAG, "Ignoring performRestore() with no restore set");
+ return -1;
+ }
+
+ for (int i = 0; i < mRestoreSets.length; i++) {
+ if (token == mRestoreSets[i].token) {
+ long oldId = Binder.clearCallingIdentity();
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token);
+ mBackupHandler.sendMessage(msg);
+ Binder.restoreCallingIdentity(oldId);
+ return 0;
}
- } else {
- if (DEBUG) Log.v(TAG, "No current restore set, not doing restore");
}
+
+ Log.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
return -1;
}
- public void endRestoreSession() throws android.os.RemoteException {
- mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ public synchronized void endRestoreSession() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"endRestoreSession");
- Log.d(TAG, "endRestoreSession");
+ if (DEBUG) Log.d(TAG, "endRestoreSession");
+
+ synchronized (this) {
+ try {
+ if (mRestoreTransport != null) mRestoreTransport.finishRestore();
+ } catch (Exception e) {
+ Log.e(TAG, "Error in finishRestore", e);
+ } finally {
+ mRestoreTransport = null;
+ }
+ }
- mRestoreTransport.finishRestore();
- mRestoreTransport = null;
- synchronized(BackupManagerService.this) {
+ synchronized (BackupManagerService.this) {
if (BackupManagerService.this.mActiveRestoreSession == this) {
BackupManagerService.this.mActiveRestoreSession = null;
} else {
@@ -1546,8 +1779,6 @@ class BackupManagerService extends IBackupManager.Stub {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mQueueLock) {
- long oldId = Binder.clearCallingIdentity();
-
pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
+ " / " + (!mProvisioned ? "not " : "") + "provisioned");
pw.println("Available transports:");
@@ -1566,12 +1797,14 @@ class BackupManagerService extends IBackupManager.Stub {
pw.println(" " + app.toString());
}
}
+ pw.println("Ever backed up: " + mEverStoredApps.size());
+ for (String pkg : mEverStoredApps) {
+ pw.println(" " + pkg);
+ }
pw.println("Pending: " + mPendingBackups.size());
for (BackupRequest req : mPendingBackups.values()) {
pw.println(" " + req);
}
-
- Binder.restoreCallingIdentity(oldId);
}
}
}
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 90d8c9d..26fee89 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -45,7 +45,6 @@ import java.io.IOException;
import java.io.PrintWriter;
-
/**
* <p>BatteryService monitors the charging status, and charge level of the device
* battery. When these values change this service broadcasts the new values
@@ -92,6 +91,9 @@ 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_CLOSE_WARNING = 20;
+ private static final int BATTERY_LEVEL_WARNING = 15;
+
private final Context mContext;
private final IBatteryStats mBatteryStats;
@@ -120,6 +122,7 @@ class BatteryService extends Binder {
private long mDischargeStartTime;
private int mDischargeStartLevel;
+ private boolean mSentLowBatteryBroadcast = false;
public BatteryService(Context context) {
mContext = context;
@@ -171,6 +174,22 @@ class BatteryService extends Binder {
return mBatteryLevel;
}
+ void systemReady() {
+ // check our power situation now that it is safe to display the shutdown dialog.
+ shutdownIfNoPower();
+ }
+
+ private final void shutdownIfNoPower() {
+ // shut down gracefully if our battery is critically low and we are not powered.
+ // wait until the system has booted before attempting to display the shutdown dialog.
+ if (mBatteryLevel == 0 && !isPowered() && ActivityManagerNative.isSystemReady()) {
+ Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+ intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+ }
+
private native void native_update();
private synchronized final void update() {
@@ -178,7 +197,9 @@ class BatteryService extends Binder {
boolean logOutlier = false;
long dischargeDuration = 0;
-
+
+ shutdownIfNoPower();
+
mBatteryLevelCritical = mBatteryLevel <= CRITICAL_BATTERY_LEVEL;
if (mAcOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
@@ -250,16 +271,28 @@ class BatteryService extends Binder {
// Separate broadcast is sent for power connected / not connected
// since the standard intent will not wake any applications and some
// applications may want to have smart behavior based on this.
+ Intent statusIntent = new Intent();
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (mPlugType != 0 && mLastPlugType == 0) {
- Intent intent = new Intent(Intent.ACTION_POWER_CONNECTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcast(intent);
+ statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
+ mContext.sendBroadcast(statusIntent);
}
else if (mPlugType == 0 && mLastPlugType != 0) {
- Intent intent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcast(intent);
+ statusIntent.setAction(Intent.ACTION_POWER_DISCONNECTED);
+ mContext.sendBroadcast(statusIntent);
}
+
+ 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 +302,17 @@ class BatteryService extends Binder {
mLastBatteryVoltage = mBatteryVoltage;
mLastBatteryTemperature = mBatteryTemperature;
mLastBatteryLevelCritical = mBatteryLevelCritical;
-
+
sendIntent();
+ if (sendBatteryLow) {
+ mSentLowBatteryBroadcast = true;
+ statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
+ mContext.sendBroadcast(statusIntent);
+ } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= BATTERY_LEVEL_CLOSE_WARNING) {
+ mSentLowBatteryBroadcast = false;
+ statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);
+ mContext.sendBroadcast(statusIntent);
+ }
// 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/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 493bd09..e26dd13 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -30,51 +30,136 @@ import android.net.NetworkStateTracker;
import android.net.wifi.WifiStateTracker;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
+import com.android.internal.telephony.Phone;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
/**
* @hide
*/
public class ConnectivityService extends IConnectivityManager.Stub {
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private static final String TAG = "ConnectivityService";
// Event log tags (must be in sync with event-log-tags)
private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020;
+ // how long to wait before switching back to a radio's default network
+ private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
+ // system property that can override the above value
+ private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
+ "android.telephony.apn-restore";
+
/**
* Sometimes we want to refer to the individual network state
* trackers separately, and sometimes we just want to treat them
* abstractly.
*/
private NetworkStateTracker mNetTrackers[];
- private WifiStateTracker mWifiStateTracker;
- private MobileDataStateTracker mMobileDataStateTracker;
+
+ /**
+ * A per Net list of the PID's that requested access to the net
+ * used both as a refcount and for per-PID DNS selection
+ */
+ private List mNetRequestersPids[];
+
private WifiWatchdogService mWifiWatchdogService;
+ // priority order of the nettrackers
+ // (excluding dynamically set mNetworkPreference)
+ // TODO - move mNetworkTypePreference into this
+ private int[] mPriorityList;
+
private Context mContext;
private int mNetworkPreference;
- private NetworkStateTracker mActiveNetwork;
+ private int mActiveDefaultNetwork = -1;
private int mNumDnsEntries;
- private static int sDnsChangeCounter;
private boolean mTestMode;
private static ConnectivityService sServiceInstance;
+ private Handler mHandler;
+
+ // list of DeathRecipients used to make sure features are turned off when
+ // a process dies
+ private List mFeatureUsers;
+
+ private boolean mSystemReady;
+ private ArrayList<Intent> mDeferredBroadcasts;
+
+ private class NetworkAttributes {
+ /**
+ * Class for holding settings read from resources.
+ */
+ public String mName;
+ public int mType;
+ public int mRadio;
+ public int mPriority;
+ public NetworkAttributes(String init) {
+ String fragments[] = init.split(",");
+ mName = fragments[0].toLowerCase();
+ if (fragments[1].toLowerCase().equals("wifi")) {
+ mRadio = ConnectivityManager.TYPE_WIFI;
+ } else {
+ mRadio = ConnectivityManager.TYPE_MOBILE;
+ }
+ if (mName.equals("default")) {
+ mType = mRadio;
+ } else if (mName.equals("mms")) {
+ mType = ConnectivityManager.TYPE_MOBILE_MMS;
+ } else if (mName.equals("supl")) {
+ mType = ConnectivityManager.TYPE_MOBILE_SUPL;
+ } else if (mName.equals("dun")) {
+ mType = ConnectivityManager.TYPE_MOBILE_DUN;
+ } else if (mName.equals("hipri")) {
+ mType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ }
+ mPriority = Integer.parseInt(fragments[2]);
+ }
+ public boolean isDefault() {
+ return (mType == mRadio);
+ }
+ }
+ NetworkAttributes[] mNetAttributes;
+
+ private class RadioAttributes {
+ public String mName;
+ public int mPriority;
+ public int mSimultaneity;
+ public int mType;
+ public RadioAttributes(String init) {
+ String fragments[] = init.split(",");
+ mName = fragments[0].toLowerCase();
+ mPriority = Integer.parseInt(fragments[1]);
+ mSimultaneity = Integer.parseInt(fragments[2]);
+ if (mName.equals("wifi")) {
+ mType = ConnectivityManager.TYPE_WIFI;
+ } else {
+ mType = ConnectivityManager.TYPE_MOBILE;
+ }
+ }
+ }
+ RadioAttributes[] mRadioAttributes;
+
private static class ConnectivityThread extends Thread {
private Context mContext;
-
+
private ConnectivityThread(Context context) {
super("ConnectivityThread");
mContext = context;
@@ -89,11 +174,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
Looper.loop();
}
-
+
public static ConnectivityService getServiceInstance(Context context) {
ConnectivityThread thread = new ConnectivityThread(context);
thread.start();
-
+
synchronized (thread) {
while (sServiceInstance == null) {
try {
@@ -101,27 +186,71 @@ public class ConnectivityService extends IConnectivityManager.Stub {
thread.wait();
} catch (InterruptedException ignore) {
Log.e(TAG,
- "Unexpected InterruptedException while waiting for ConnectivityService thread");
+ "Unexpected InterruptedException while waiting"+
+ " for ConnectivityService thread");
}
}
}
-
+
return sServiceInstance;
}
}
-
+
public static ConnectivityService getInstance(Context context) {
return ConnectivityThread.getServiceInstance(context);
}
-
+
private ConnectivityService(Context context) {
if (DBG) Log.v(TAG, "ConnectivityService starting up");
mContext = context;
- mNetTrackers = new NetworkStateTracker[2];
- Handler handler = new MyHandler();
-
+ mNetTrackers = new NetworkStateTracker[
+ ConnectivityManager.MAX_NETWORK_TYPE+1];
+ mHandler = new MyHandler();
+
mNetworkPreference = getPersistedNetworkPreference();
-
+
+ // Load device network attributes from resources
+ mNetAttributes = new NetworkAttributes[
+ ConnectivityManager.MAX_NETWORK_TYPE+1];
+ mRadioAttributes = new RadioAttributes[
+ ConnectivityManager.MAX_RADIO_TYPE+1];
+ String[] naStrings = context.getResources().getStringArray(
+ com.android.internal.R.array.networkAttributes);
+ // TODO - what if the setting has gaps/unknown types?
+ for (String a : naStrings) {
+ NetworkAttributes n = new NetworkAttributes(a);
+ mNetAttributes[n.mType] = n;
+ }
+ String[] raStrings = context.getResources().getStringArray(
+ com.android.internal.R.array.radioAttributes);
+ for (String a : raStrings) {
+ RadioAttributes r = new RadioAttributes(a);
+ mRadioAttributes[r.mType] = r;
+ }
+
+ // high priority first
+ mPriorityList = new int[naStrings.length];
+ {
+ int priority = 0; //lowest
+ int nextPos = naStrings.length-1;
+ while (nextPos>-1) {
+ for (int i = 0; i < mNetAttributes.length; i++) {
+ if(mNetAttributes[i].mPriority == priority) {
+ mPriorityList[nextPos--] = i;
+ }
+ }
+ priority++;
+ }
+ }
+
+ mNetRequestersPids =
+ new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
+ for (int i=0; i<=ConnectivityManager.MAX_NETWORK_TYPE; i++) {
+ mNetRequestersPids[i] = new ArrayList();
+ }
+
+ mFeatureUsers = new ArrayList();
+
/*
* Create the network state trackers for Wi-Fi and mobile
* data. Maybe this could be done with a factory class,
@@ -130,15 +259,36 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* to change very often.
*/
if (DBG) Log.v(TAG, "Starting Wifi Service.");
- mWifiStateTracker = new WifiStateTracker(context, handler);
- WifiService wifiService = new WifiService(context, mWifiStateTracker);
+ WifiStateTracker wst = new WifiStateTracker(context, mHandler);
+ WifiService wifiService = new WifiService(context, wst);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
- mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker;
+ mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE, Phone.APN_TYPE_DEFAULT,
+ "MOBILE");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_MMS] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_MMS, Phone.APN_TYPE_MMS,
+ "MOBILE_MMS");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_SUPL] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_SUPL, Phone.APN_TYPE_SUPL,
+ "MOBILE_SUPL");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_DUN, Phone.APN_TYPE_DUN,
+ "MOBILE_DUN");
+
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI] =
+ new MobileDataStateTracker(context, mHandler,
+ ConnectivityManager.TYPE_MOBILE_HIPRI, Phone.APN_TYPE_HIPRI,
+ "MOBILE_HIPRI");
- mMobileDataStateTracker = new MobileDataStateTracker(context, handler);
- mNetTrackers[ConnectivityManager.TYPE_MOBILE] = mMobileDataStateTracker;
-
- mActiveNetwork = null;
mNumDnsEntries = 0;
mTestMode = SystemProperties.get("cm.test.mode").equals("true")
@@ -148,16 +298,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
t.startMonitoring();
// Constructing this starts it too
- mWifiWatchdogService = new WifiWatchdogService(context, mWifiStateTracker);
+ mWifiWatchdogService = new WifiWatchdogService(context, wst);
}
/**
- * Sets the preferred network.
+ * Sets the preferred network.
* @param preference the new preference
*/
public synchronized void setNetworkPreference(int preference) {
enforceChangePermission();
- if (ConnectivityManager.isNetworkTypeValid(preference)) {
+ if (ConnectivityManager.isNetworkTypeValid(preference) &&
+ mNetAttributes[preference].isDefault()) {
if (mNetworkPreference != preference) {
persistNetworkPreference(preference);
mNetworkPreference = preference;
@@ -173,9 +324,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private void persistNetworkPreference(int networkPreference) {
final ContentResolver cr = mContext.getContentResolver();
- Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, networkPreference);
+ Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE,
+ networkPreference);
}
-
+
private int getPersistedNetworkPreference() {
final ContentResolver cr = mContext.getContentResolver();
@@ -187,31 +339,30 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
}
-
+
/**
- * Make the state of network connectivity conform to the preference settings.
+ * Make the state of network connectivity conform to the preference settings
* In this method, we only tear down a non-preferred network. Establishing
* a connection to the preferred network is taken care of when we handle
* the disconnect event from the non-preferred network
* (see {@link #handleDisconnect(NetworkInfo)}).
*/
private void enforcePreference() {
- if (mActiveNetwork == null)
+ if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
return;
- for (NetworkStateTracker t : mNetTrackers) {
- if (t == mActiveNetwork) {
- int netType = t.getNetworkInfo().getType();
- int otherNetType = ((netType == ConnectivityManager.TYPE_WIFI) ?
- ConnectivityManager.TYPE_MOBILE :
- ConnectivityManager.TYPE_WIFI);
-
- if (t.getNetworkInfo().getType() != mNetworkPreference) {
- NetworkStateTracker otherTracker = mNetTrackers[otherNetType];
- if (otherTracker.isAvailable()) {
- teardown(t);
- }
+ if (!mNetTrackers[mNetworkPreference].isAvailable())
+ return;
+
+ for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
+ if (t != mNetworkPreference &&
+ mNetTrackers[t].getNetworkInfo().isConnected()) {
+ if (DBG) {
+ Log.d(TAG, "tearing down " +
+ mNetTrackers[t].getNetworkInfo() +
+ " in enforcePreference");
}
+ teardown(mNetTrackers[t]);
}
}
}
@@ -229,13 +380,21 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* Return NetworkInfo for the active (i.e., connected) network interface.
* It is assumed that at most one network is active at a time. If more
* than one is active, it is indeterminate which will be returned.
- * @return the info for the active network, or {@code null} if none is active
+ * @return the info for the active network, or {@code null} if none is
+ * active
*/
public NetworkInfo getActiveNetworkInfo() {
enforceAccessPermission();
- for (NetworkStateTracker t : mNetTrackers) {
+ for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
+ if (!mNetAttributes[type].isDefault()) {
+ continue;
+ }
+ NetworkStateTracker t = mNetTrackers[type];
NetworkInfo info = t.getNetworkInfo();
if (info.isConnected()) {
+ if (DBG && type != mActiveDefaultNetwork) Log.e(TAG,
+ "connected default network is not " +
+ "mActiveDefaultNetwork!");
return info;
}
}
@@ -280,36 +439,199 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return tracker != null && tracker.setRadio(turnOn);
}
- public int startUsingNetworkFeature(int networkType, String feature) {
+ private class FeatureUser implements IBinder.DeathRecipient {
+ int mNetworkType;
+ String mFeature;
+ IBinder mBinder;
+ int mPid;
+ int mUid;
+
+ FeatureUser(int type, String feature, IBinder binder) {
+ super();
+ mNetworkType = type;
+ mFeature = feature;
+ mBinder = binder;
+ mPid = getCallingPid();
+ mUid = getCallingUid();
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+
+ void unlinkDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
+
+ public void binderDied() {
+ Log.d(TAG, "ConnectivityService FeatureUser binderDied(" +
+ mNetworkType + ", " + mFeature + ", " + mBinder);
+ stopUsingNetworkFeature(mNetworkType, mFeature, mPid, mUid);
+ }
+
+ }
+
+ public int startUsingNetworkFeature(int networkType, String feature,
+ IBinder binder) {
+ if (DBG) {
+ Log.d(TAG, "startUsingNetworkFeature for net " + networkType +
+ ": " + feature);
+ }
enforceChangePermission();
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
- return -1;
+ return Phone.APN_REQUEST_FAILED;
}
- NetworkStateTracker tracker = mNetTrackers[networkType];
- if (tracker != null) {
- return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid());
+
+ synchronized (mFeatureUsers) {
+ mFeatureUsers.add(new FeatureUser(networkType, feature, binder));
+ }
+
+ // TODO - move this into the MobileDataStateTracker
+ int usedNetworkType = networkType;
+ if(networkType == ConnectivityManager.TYPE_MOBILE) {
+ if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ }
}
- return -1;
+ NetworkStateTracker network = mNetTrackers[usedNetworkType];
+ if (network != null) {
+ if (usedNetworkType != networkType) {
+ Integer currentPid = new Integer(getCallingPid());
+
+ NetworkStateTracker radio = mNetTrackers[networkType];
+ NetworkInfo ni = network.getNetworkInfo();
+
+ if (ni.isAvailable() == false) {
+ if (DBG) Log.d(TAG, "special network not available");
+ return Phone.APN_TYPE_NOT_AVAILABLE;
+ }
+
+ if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
+ // this gets used for per-pid dns when connected
+ mNetRequestersPids[usedNetworkType].add(currentPid);
+ }
+
+ if ((ni.isConnectedOrConnecting() == true) &&
+ !network.isTeardownRequested()) {
+ if (ni.isConnected() == true) {
+ // add the pid-specific dns
+ handleDnsConfigurationChange();
+ if (DBG) Log.d(TAG, "special network already active");
+ return Phone.APN_ALREADY_ACTIVE;
+ }
+ if (DBG) Log.d(TAG, "special network already connecting");
+ return Phone.APN_REQUEST_STARTED;
+ }
+
+ // check if the radio in play can make another contact
+ // assume if cannot for now
+
+ // since we have to drop the default on this radio, setup
+ // an automatic event to switch back
+ if(mHandler.hasMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK, radio) ||
+ radio.getNetworkInfo().isConnectedOrConnecting()) {
+ mHandler.removeMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK,
+ radio);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
+ radio), getRestoreDefaultNetworkDelay());
+ }
+ if (DBG) Log.d(TAG, "reconnecting to special network");
+ network.reconnect();
+ return Phone.APN_REQUEST_STARTED;
+ } else {
+ return network.startUsingNetworkFeature(feature,
+ getCallingPid(), getCallingUid());
+ }
+ }
+ return Phone.APN_TYPE_NOT_AVAILABLE;
}
public int stopUsingNetworkFeature(int networkType, String feature) {
+ return stopUsingNetworkFeature(networkType, feature, getCallingPid(),
+ getCallingUid());
+ }
+
+ private int stopUsingNetworkFeature(int networkType, String feature,
+ int pid, int uid) {
+ if (DBG) {
+ Log.d(TAG, "stopUsingNetworkFeature for net " + networkType +
+ ": " + feature);
+ }
enforceChangePermission();
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
return -1;
}
- NetworkStateTracker tracker = mNetTrackers[networkType];
- if (tracker != null) {
- return tracker.stopUsingNetworkFeature(feature, getCallingPid(), getCallingUid());
+
+ synchronized (mFeatureUsers) {
+ for (int i=0; i < mFeatureUsers.size(); i++) {
+ FeatureUser u = (FeatureUser)mFeatureUsers.get(i);
+ if (uid == u.mUid && pid == u.mPid &&
+ networkType == u.mNetworkType &&
+ TextUtils.equals(feature, u.mFeature)) {
+ u.unlinkDeathRecipient();
+ mFeatureUsers.remove(i);
+ break;
+ }
+ }
+ }
+
+ // TODO - move to MobileDataStateTracker
+ int usedNetworkType = networkType;
+ if (networkType == ConnectivityManager.TYPE_MOBILE) {
+ if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
+ usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ }
+ }
+ NetworkStateTracker tracker = mNetTrackers[usedNetworkType];
+ if(usedNetworkType != networkType) {
+ Integer currentPid = new Integer(pid);
+ if (mNetRequestersPids[usedNetworkType].remove(currentPid)) {
+ reassessPidDns(pid, true);
+ }
+ if (mNetRequestersPids[usedNetworkType].size() != 0) {
+ if (DBG) Log.d(TAG, "not tearing down special network - " +
+ "others still using it");
+ return 1;
+ }
+
+ tracker.teardown();
+ NetworkStateTracker radio = mNetTrackers[networkType];
+ // Check if we want to revert to the default
+ if (mHandler.hasMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK, radio)) {
+ mHandler.removeMessages(NetworkStateTracker.
+ EVENT_RESTORE_DEFAULT_NETWORK, radio);
+ radio.reconnect();
+ }
+ return 1;
+ } else {
+ return tracker.stopUsingNetworkFeature(feature, pid, uid);
}
- return -1;
}
/**
* Ensure that a network route exists to deliver traffic to the specified
* host via the specified network interface.
- * @param networkType the type of the network over which traffic to the specified
- * host is to be routed
- * @param hostAddress the IP address of the host to which the route is desired
+ * @param networkType the type of the network over which traffic to the
+ * specified host is to be routed
+ * @param hostAddress the IP address of the host to which the route is
+ * desired
* @return {@code true} on success, {@code false} on failure
*/
public boolean requestRouteToHost(int networkType, int hostAddress) {
@@ -329,7 +651,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (getNumConnectedNetworks() > 1) {
return tracker.requestRouteToHost(hostAddress);
} else {
- return tracker.getNetworkInfo().getType() == networkType;
+ return (mNetAttributes[networkType].isDefault() &&
+ tracker.getNetworkInfo().isConnected());
}
}
@@ -340,7 +663,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.BACKGROUND_DATA, 1) == 1;
}
-
+
/**
* @see ConnectivityManager#setBackgroundDataSetting(boolean)
*/
@@ -348,87 +671,73 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
"ConnectivityService");
-
+
if (getBackgroundDataSetting() == allowBackgroundDataUsage) return;
Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.BACKGROUND_DATA, allowBackgroundDataUsage ? 1 : 0);
-
+ Settings.Secure.BACKGROUND_DATA,
+ allowBackgroundDataUsage ? 1 : 0);
+
Intent broadcast = new Intent(
ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
mContext.sendBroadcast(broadcast);
- }
-
+ }
+
private int getNumConnectedNetworks() {
int numConnectedNets = 0;
for (NetworkStateTracker nt : mNetTrackers) {
- if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
+ if (nt.getNetworkInfo().isConnected() &&
+ !nt.isTeardownRequested()) {
++numConnectedNets;
}
}
+ if (DBG) Log.d(TAG, "numConnectedNets returning "+numConnectedNets);
return numConnectedNets;
}
private void enforceAccessPermission() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
- "ConnectivityService");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE,
+ "ConnectivityService");
}
private void enforceChangePermission() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
- "ConnectivityService");
-
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE,
+ "ConnectivityService");
}
/**
- * Handle a {@code DISCONNECTED} event. If this pertains to the non-active network,
- * we ignore it. If it is for the active network, we send out a broadcast.
- * But first, we check whether it might be possible to connect to a different
- * network.
+ * Handle a {@code DISCONNECTED} event. If this pertains to the non-active
+ * network, we ignore it. If it is for the active network, we send out a
+ * broadcast. But first, we check whether it might be possible to connect
+ * to a different network.
* @param info the {@code NetworkInfo} for the network
*/
private void handleDisconnect(NetworkInfo info) {
if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName());
+ int prevNetType = info.getType();
- mNetTrackers[info.getType()].setTeardownRequested(false);
+ mNetTrackers[prevNetType].setTeardownRequested(false);
/*
* If the disconnected network is not the active one, then don't report
* this as a loss of connectivity. What probably happened is that we're
* getting the disconnect for a network that we explicitly disabled
* in accordance with network preference policies.
*/
- if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType())
- return;
-
- NetworkStateTracker newNet;
- if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
- newNet = mWifiStateTracker;
- } else /* info().getType() == TYPE_WIFI */ {
- newNet = mMobileDataStateTracker;
- }
-
- /**
- * See if the other network is available to fail over to.
- * If is not available, we enable it anyway, so that it
- * will be able to connect when it does become available,
- * but we report a total loss of connectivity rather than
- * report that we are attempting to fail over.
- */
- NetworkInfo switchTo = null;
- if (newNet.isAvailable()) {
- mActiveNetwork = newNet;
- switchTo = newNet.getNetworkInfo();
- switchTo.setFailover(true);
- if (!switchTo.isConnectedOrConnecting()) {
- newNet.reconnect();
+ if (!mNetAttributes[prevNetType].isDefault()) {
+ List pids = mNetRequestersPids[prevNetType];
+ for (int i = 0; i<pids.size(); i++) {
+ Integer pid = (Integer)pids.get(i);
+ // will remove them because the net's no longer connected
+ // need to do this now as only now do we know the pids and
+ // can properly null things that are no longer referenced.
+ reassessPidDns(pid.intValue(), false);
}
- } else {
- newNet.reconnect();
}
- boolean otherNetworkConnected = false;
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
if (info.isFailover()) {
@@ -439,31 +748,96 @@ public class ConnectivityService extends IConnectivityManager.Stub {
intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
}
if (info.getExtraInfo() != null) {
- intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
+ intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
+ info.getExtraInfo());
}
- if (switchTo != null) {
- otherNetworkConnected = switchTo.isConnected();
- if (DBG) {
- if (otherNetworkConnected) {
- Log.v(TAG, "Switching to already connected " + switchTo.getTypeName());
+
+ /*
+ * If this is a default network, check if other defaults are available
+ * or active
+ */
+ NetworkStateTracker newNet = null;
+ if (mNetAttributes[prevNetType].isDefault()) {
+ if (DBG) Log.d(TAG, "disconnecting a default network");
+ if (mActiveDefaultNetwork == prevNetType) {
+ mActiveDefaultNetwork = -1;
+ }
+
+ int newType = -1;
+ int newPriority = -1;
+ for (int checkType=0; checkType <=
+ ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
+ if (checkType == prevNetType) {
+ continue;
+ }
+ if (mNetAttributes[checkType].isDefault()) {
+ /* TODO - if we have multiple nets we could use
+ * we may want to put more thought into which we choose
+ */
+ if (checkType == mNetworkPreference) {
+ newType = checkType;
+ break;
+ }
+ if (mRadioAttributes[mNetAttributes[checkType].mRadio].
+ mPriority > newPriority) {
+ newType = checkType;
+ newPriority = mRadioAttributes[mNetAttributes[newType].
+ mRadio].mPriority;
+ }
+ }
+ }
+
+ if (newType != -1) {
+ newNet = mNetTrackers[newType];
+ /**
+ * See if the other network is available to fail over to.
+ * If is not available, we enable it anyway, so that it
+ * will be able to connect when it does become available,
+ * but we report a total loss of connectivity rather than
+ * report that we are attempting to fail over.
+ */
+ if (newNet.isAvailable()) {
+ NetworkInfo switchTo = newNet.getNetworkInfo();
+ switchTo.setFailover(true);
+ if (!switchTo.isConnectedOrConnecting() ||
+ newNet.isTeardownRequested()) {
+ newNet.reconnect();
+ }
+ if (DBG) {
+ if (switchTo.isConnected()) {
+ Log.v(TAG, "Switching to already connected " +
+ switchTo.getTypeName());
+ } else {
+ Log.v(TAG, "Attempting to switch to " +
+ switchTo.getTypeName());
+ }
+ }
+ intent.putExtra(ConnectivityManager.
+ EXTRA_OTHER_NETWORK_INFO, switchTo);
} else {
- Log.v(TAG, "Attempting to switch to " + switchTo.getTypeName());
+ newNet.reconnect();
}
+ } else {
+ intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
+ true);
}
- intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
- } else {
- intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
}
- if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " + info.getTypeName() +
- (switchTo == null ? "" : " other=" + switchTo.getTypeName()));
- mContext.sendStickyBroadcast(intent);
+ // do this before we broadcast the change
+ handleConnectivityChange();
+
+ if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " +
+ info.getTypeName() +
+ (newNet == null || !newNet.isAvailable() ? "" : " other=" +
+ newNet.getNetworkInfo().getTypeName()));
+
+ sendStickyBroadcast(intent);
/*
- * If the failover network is already connected, then immediately send out
- * a followup broadcast indicating successful failover
+ * If the failover network is already connected, then immediately send
+ * out a followup broadcast indicating successful failover
*/
- if (switchTo != null && otherNetworkConnected)
- sendConnectedBroadcast(switchTo);
+ if (newNet != null && newNet.getNetworkInfo().isConnected())
+ sendConnectedBroadcast(newNet.getNetworkInfo());
}
private void sendConnectedBroadcast(NetworkInfo info) {
@@ -477,9 +851,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
}
if (info.getExtraInfo() != null) {
- intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
+ intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
+ info.getExtraInfo());
}
- mContext.sendStickyBroadcast(intent);
+ sendStickyBroadcast(intent);
}
/**
@@ -488,106 +863,128 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
private void handleConnectionFailure(NetworkInfo info) {
mNetTrackers[info.getType()].setTeardownRequested(false);
- if (getActiveNetworkInfo() == null) {
- String reason = info.getReason();
- String extraInfo = info.getExtraInfo();
- if (DBG) {
- String reasonText;
- if (reason == null) {
- reasonText = ".";
- } else {
- reasonText = " (" + reason + ").";
- }
- Log.v(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
+ String reason = info.getReason();
+ String extraInfo = info.getExtraInfo();
+
+ if (DBG) {
+ String reasonText;
+ if (reason == null) {
+ reasonText = ".";
+ } else {
+ reasonText = " (" + reason + ").";
}
-
- Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ Log.v(TAG, "Attempt to connect to " + info.getTypeName() +
+ " failed" + reasonText);
+ }
+
+ Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ if (getActiveNetworkInfo() == null) {
intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
- if (reason != null) {
- intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
- }
- if (extraInfo != null) {
- intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
+ }
+ if (reason != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
+ }
+ if (extraInfo != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
+ }
+ if (info.isFailover()) {
+ intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
+ info.setFailover(false);
+ }
+ sendStickyBroadcast(intent);
+ }
+
+ private void sendStickyBroadcast(Intent intent) {
+ synchronized(this) {
+ if (mSystemReady) {
+ mContext.sendStickyBroadcast(intent);
+ } else {
+ if (mDeferredBroadcasts == null) {
+ mDeferredBroadcasts = new ArrayList<Intent>();
+ }
+ mDeferredBroadcasts.add(intent);
}
- if (info.isFailover()) {
- intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
- info.setFailover(false);
+ }
+ }
+
+ void systemReady() {
+ synchronized(this) {
+ mSystemReady = true;
+ if (mDeferredBroadcasts != null) {
+ int count = mDeferredBroadcasts.size();
+ for (int i = 0; i < count; i++) {
+ mContext.sendStickyBroadcast(mDeferredBroadcasts.get(i));
+ }
+ mDeferredBroadcasts = null;
}
- mContext.sendStickyBroadcast(intent);
}
}
private void handleConnect(NetworkInfo info) {
- if (DBG) Log.v(TAG, "Handle CONNECT for " + info.getTypeName());
+ if (DBG) Log.d(TAG, "Handle CONNECT for " + info.getTypeName());
+
+ int type = info.getType();
// snapshot isFailover, because sendConnectedBroadcast() resets it
boolean isFailover = info.isFailover();
- NetworkStateTracker thisNet = mNetTrackers[info.getType()];
- NetworkStateTracker deadnet = null;
- NetworkStateTracker otherNet;
- if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
- otherNet = mWifiStateTracker;
- } else /* info().getType() == TYPE_WIFI */ {
- otherNet = mMobileDataStateTracker;
- }
- /*
- * Check policy to see whether we are connected to a non-preferred
- * network that now needs to be torn down.
- */
- NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo();
- NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo();
- if (wifiInfo.isConnected() && mobileInfo.isConnected()) {
- if (mNetworkPreference == ConnectivityManager.TYPE_WIFI)
- deadnet = mMobileDataStateTracker;
- else
- deadnet = mWifiStateTracker;
- }
-
- boolean toredown = false;
- thisNet.setTeardownRequested(false);
- if (!mTestMode && deadnet != null) {
- if (DBG) Log.v(TAG, "Policy requires " +
- deadnet.getNetworkInfo().getTypeName() + " teardown");
- toredown = teardown(deadnet);
- if (DBG && !toredown) {
- Log.d(TAG, "Network declined teardown request");
- }
- }
-
- /*
- * Note that if toredown is true, deadnet cannot be null, so there is
- * no danger of a null pointer exception here..
- */
- if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) {
- mActiveNetwork = thisNet;
- if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + info.getTypeName());
- thisNet.updateNetworkSettings();
- sendConnectedBroadcast(info);
- if (isFailover) {
- otherNet.releaseWakeLock();
+ NetworkStateTracker thisNet = mNetTrackers[type];
+
+ // if this is a default net and other default is running
+ // kill the one not preferred
+ if (mNetAttributes[type].isDefault()) {
+ if (DBG) Log.d(TAG, "connecting to a default network");
+ if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
+ if ((type != mNetworkPreference &&
+ mNetAttributes[mActiveDefaultNetwork].mPriority >
+ mNetAttributes[type].mPriority) ||
+ mNetworkPreference == mActiveDefaultNetwork) {
+ // don't accept this one
+ if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION " +
+ "to torn down network " + info.getTypeName());
+ teardown(thisNet);
+ return;
+ } else {
+ // tear down the other
+ NetworkStateTracker otherNet =
+ mNetTrackers[mActiveDefaultNetwork];
+ if (DBG) Log.v(TAG, "Policy requires " +
+ otherNet.getNetworkInfo().getTypeName() +
+ " teardown");
+ if (!teardown(otherNet)) {
+ Log.e(TAG, "Network declined teardown request");
+ return;
+ }
+ if (isFailover) {
+ otherNet.releaseWakeLock();
+ }
+ }
}
- } else {
- if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION to torn down network " +
- info.getTypeName());
+ mActiveDefaultNetwork = type;
}
+ thisNet.setTeardownRequested(false);
+ if (DBG) Log.d(TAG, "Sending CONNECT bcast for " + info.getTypeName());
+ thisNet.updateNetworkSettings();
+ handleConnectivityChange();
+ sendConnectedBroadcast(info);
}
private void handleScanResultsAvailable(NetworkInfo info) {
int networkType = info.getType();
if (networkType != ConnectivityManager.TYPE_WIFI) {
- if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " + info.getTypeName() + " network."
- + " Don't know how to handle.");
+ if (DBG) Log.v(TAG, "Got ScanResultsAvailable for " +
+ info.getTypeName() + " network. Don't know how to handle.");
}
-
+
mNetTrackers[networkType].interpretScanResultsAvailable();
}
- private void handleNotificationChange(boolean visible, int id, Notification notification) {
+ private void handleNotificationChange(boolean visible, int id,
+ Notification notification) {
NotificationManager notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
-
+
if (visible) {
notificationManager.notify(id, notification);
} else {
@@ -604,80 +1001,175 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* table entries exist.
*/
private void handleConnectivityChange() {
+ if (DBG) Log.d(TAG, "handleConnectivityChange");
/*
+ * If a non-default network is enabled, add the host routes that
+ * will allow it's DNS servers to be accessed. Only
* If both mobile and wifi are enabled, add the host routes that
* will allow MMS traffic to pass on the mobile network. But
* remove the default route for the mobile network, so that there
* will be only one default route, to ensure that all traffic
* except MMS will travel via Wi-Fi.
*/
- int numConnectedNets = handleConfigurationChange();
- if (numConnectedNets > 1) {
- mMobileDataStateTracker.addPrivateRoutes();
- mMobileDataStateTracker.removeDefaultRoute();
- } else if (mMobileDataStateTracker.getNetworkInfo().isConnected()) {
- mMobileDataStateTracker.removePrivateRoutes();
- mMobileDataStateTracker.restoreDefaultRoute();
+ handleDnsConfigurationChange();
+
+ for (int netType : mPriorityList) {
+ if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
+ if (mNetAttributes[netType].isDefault()) {
+ mNetTrackers[netType].addDefaultRoute();
+ } else {
+ mNetTrackers[netType].addPrivateDnsRoutes();
+ }
+ } else {
+ if (mNetAttributes[netType].isDefault()) {
+ mNetTrackers[netType].removeDefaultRoute();
+ } else {
+ mNetTrackers[netType].removePrivateDnsRoutes();
+ }
+ }
+ }
+ }
+
+ /**
+ * Adjust the per-process dns entries (net.dns<x>.<pid>) based
+ * on the highest priority active net which this process requested.
+ * If there aren't any, clear it out
+ */
+ private void reassessPidDns(int myPid, boolean doBump)
+ {
+ if (DBG) Log.d(TAG, "reassessPidDns for pid " + myPid);
+ for(int i : mPriorityList) {
+ if (mNetAttributes[i].isDefault()) {
+ continue;
+ }
+ NetworkStateTracker nt = mNetTrackers[i];
+ if (nt.getNetworkInfo().isConnected() &&
+ !nt.isTeardownRequested()) {
+ List pids = mNetRequestersPids[i];
+ for (int j=0; j<pids.size(); j++) {
+ Integer pid = (Integer)pids.get(j);
+ if (pid.intValue() == myPid) {
+ String[] dnsList = nt.getNameServers();
+ writePidDns(dnsList, myPid);
+ if (doBump) {
+ bumpDns();
+ }
+ return;
+ }
+ }
+ }
+ }
+ // nothing found - delete
+ for (int i = 1; ; i++) {
+ String prop = "net.dns" + i + "." + myPid;
+ if (SystemProperties.get(prop).length() == 0) {
+ if (doBump) {
+ bumpDns();
+ }
+ return;
+ }
+ SystemProperties.set(prop, "");
+ }
+ }
+
+ private void writePidDns(String[] dnsList, int pid) {
+ int j = 1;
+ for (String dns : dnsList) {
+ if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
+ SystemProperties.set("net.dns" + j++ + "." + pid, dns);
+ }
}
}
- private int handleConfigurationChange() {
+ private void bumpDns() {
/*
- * Set DNS properties. Always put Wi-Fi entries at the front of
- * the list if it is active.
+ * Bump the property that tells the name resolver library to reread
+ * the DNS server list from the properties.
*/
- int index = 1;
- String lastDns = "";
- int numConnectedNets = 0;
- int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI;
- int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue;
+ String propVal = SystemProperties.get("net.dnschange");
+ int n = 0;
+ if (propVal.length() != 0) {
+ try {
+ n = Integer.parseInt(propVal);
+ } catch (NumberFormatException e) {}
+ }
+ SystemProperties.set("net.dnschange", "" + (n+1));
+ }
- for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; netType += incrValue) {
+ private void handleDnsConfigurationChange() {
+ if (DBG) Log.d(TAG, "handleDnsConfig Change");
+ // add default net's dns entries
+ for (int x = mPriorityList.length-1; x>= 0; x--) {
+ int netType = mPriorityList[x];
NetworkStateTracker nt = mNetTrackers[netType];
- if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
- ++numConnectedNets;
+ if (DBG) Log.d(TAG, " checking " + nt);
+ if (nt != null && nt.getNetworkInfo().isConnected() &&
+ !nt.isTeardownRequested()) {
+ if (DBG) Log.d(TAG, " connected");
String[] dnsList = nt.getNameServers();
- for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) {
- // skip duplicate entries
- if (!dnsList[i].equals(lastDns)) {
- SystemProperties.set("net.dns" + index++, dnsList[i]);
- lastDns = dnsList[i];
+ if (mNetAttributes[netType].isDefault()) {
+ int j = 1;
+ for (String dns : dnsList) {
+ if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
+ if (DBG) Log.d(TAG, " adding "+dns);
+ SystemProperties.set("net.dns" + j++, dns);
+ }
+ }
+ for (int k=j ; k<mNumDnsEntries; k++) {
+ if (DBG) Log.d(TAG, "erasing net.dns" + k);
+ SystemProperties.set("net.dns" + k, "");
+ }
+ mNumDnsEntries = j;
+ } else {
+ // set per-pid dns for attached secondary nets
+ List pids = mNetRequestersPids[netType];
+ for (int y=0; y< pids.size(); y++) {
+ Integer pid = (Integer)pids.get(y);
+ writePidDns(dnsList, pid.intValue());
}
}
}
}
- // Null out any DNS properties that are no longer used
- for (int i = index; i <= mNumDnsEntries; i++) {
- SystemProperties.set("net.dns" + i, "");
+
+ bumpDns();
+ }
+
+ private int getRestoreDefaultNetworkDelay() {
+ String restoreDefaultNetworkDelayStr = SystemProperties.get(
+ NETWORK_RESTORE_DELAY_PROP_NAME);
+ if(restoreDefaultNetworkDelayStr != null &&
+ restoreDefaultNetworkDelayStr.length() != 0) {
+ try {
+ return Integer.valueOf(restoreDefaultNetworkDelayStr);
+ } catch (NumberFormatException e) {
+ }
}
- mNumDnsEntries = index - 1;
- // Notify the name resolver library of the change
- SystemProperties.set("net.dnschange", String.valueOf(sDnsChangeCounter++));
- return numConnectedNets;
+ return RESTORE_DEFAULT_NETWORK_DELAY;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump ConnectivityService from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
+ pw.println("Permission Denial: can't dump ConnectivityService " +
+ "from from pid=" + Binder.getCallingPid() + ", uid=" +
+ Binder.getCallingUid());
return;
}
- if (mActiveNetwork == null) {
- pw.println("No active network");
- } else {
- pw.println("Active network: " + mActiveNetwork.getNetworkInfo().getTypeName());
- }
pw.println();
for (NetworkStateTracker nst : mNetTrackers) {
+ if (nst.getNetworkInfo().isConnected()) {
+ pw.println("Active network: " + nst.getNetworkInfo().
+ getTypeName());
+ }
pw.println(nst.getNetworkInfo());
pw.println(nst);
pw.println();
}
}
+ // must be stateless - things change under us.
private class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
@@ -685,46 +1177,54 @@ public class ConnectivityService extends IConnectivityManager.Stub {
switch (msg.what) {
case NetworkStateTracker.EVENT_STATE_CHANGED:
info = (NetworkInfo) msg.obj;
- if (DBG) Log.v(TAG, "ConnectivityChange for " + info.getTypeName() + ": " +
+ if (DBG) Log.d(TAG, "ConnectivityChange for " +
+ info.getTypeName() + ": " +
info.getState() + "/" + info.getDetailedState());
// Connectivity state changed:
// [31-13] Reserved for future use
- // [12-9] Network subtype (for mobile network, as defined by TelephonyManager)
- // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
+ // [12-9] Network subtype (for mobile network, as defined
+ // by TelephonyManager)
+ // [8-3] Detailed state ordinal (as defined by
+ // NetworkInfo.DetailedState)
// [2-0] Network type (as defined by ConnectivityManager)
int eventLogParam = (info.getType() & 0x7) |
((info.getDetailedState().ordinal() & 0x3f) << 3) |
(info.getSubtype() << 9);
- EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam);
-
- if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
+ EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED,
+ eventLogParam);
+
+ if (info.getDetailedState() ==
+ NetworkInfo.DetailedState.FAILED) {
handleConnectionFailure(info);
- } else if (info.getState() == NetworkInfo.State.DISCONNECTED) {
+ } else if (info.getState() ==
+ NetworkInfo.State.DISCONNECTED) {
handleDisconnect(info);
} else if (info.getState() == NetworkInfo.State.SUSPENDED) {
// TODO: need to think this over.
- // the logic here is, handle SUSPENDED the same as DISCONNECTED. The
- // only difference being we are broadcasting an intent with NetworkInfo
- // that's suspended. This allows the applications an opportunity to
- // handle DISCONNECTED and SUSPENDED differently, or not.
+ // the logic here is, handle SUSPENDED the same as
+ // DISCONNECTED. The only difference being we are
+ // broadcasting an intent with NetworkInfo that's
+ // suspended. This allows the applications an
+ // opportunity to handle DISCONNECTED and SUSPENDED
+ // differently, or not.
handleDisconnect(info);
} else if (info.getState() == NetworkInfo.State.CONNECTED) {
handleConnect(info);
}
- handleConnectivityChange();
break;
case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
info = (NetworkInfo) msg.obj;
handleScanResultsAvailable(info);
break;
-
+
case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
- handleNotificationChange(msg.arg1 == 1, msg.arg2, (Notification) msg.obj);
+ handleNotificationChange(msg.arg1 == 1, msg.arg2,
+ (Notification) msg.obj);
case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
- handleConfigurationChange();
+ handleDnsConfigurationChange();
break;
case NetworkStateTracker.EVENT_ROAMING_CHANGED:
@@ -734,6 +1234,19 @@ public class ConnectivityService extends IConnectivityManager.Stub {
case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
// fill me in
break;
+ case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
+ for (NetworkStateTracker net : mNetTrackers) {
+ NetworkInfo i = net.getNetworkInfo();
+ if (i.isConnected() &&
+ !mNetAttributes[i.getType()].isDefault()) {
+ if (DBG) {
+ Log.d(TAG, "tearing down " + i +
+ " to restore the default network");
+ }
+ teardown(net);
+ }
+ }
+ break;
}
}
}
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
new file mode 100644
index 0000000..7385359
--- /dev/null
+++ b/services/java/com/android/server/DockObserver.java
@@ -0,0 +1,112 @@
+/*
+ * 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.server;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.os.UEventObserver;
+import android.util.Log;
+
+import java.io.FileReader;
+import java.io.FileNotFoundException;
+
+/**
+ * <p>DockObserver monitors for a docking station.
+ */
+class DockObserver extends UEventObserver {
+ private static final String TAG = DockObserver.class.getSimpleName();
+ private static final boolean LOG = false;
+
+ private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
+ private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
+
+ private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ private boolean mSystemReady;
+
+ private final Context mContext;
+
+ public DockObserver(Context context) {
+ mContext = context;
+ init(); // set initial status
+ startObserving(DOCK_UEVENT_MATCH);
+ }
+
+ @Override
+ public void onUEvent(UEventObserver.UEvent event) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Dock UEVENT: " + event.toString());
+ }
+
+ synchronized (this) {
+ try {
+ int newState = Integer.parseInt(event.get("SWITCH_STATE"));
+ if (newState != mDockState) {
+ mDockState = newState;
+ if (mSystemReady) {
+ update();
+ }
+ }
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Could not parse switch state from event " + event);
+ }
+ }
+ }
+
+ private final void init() {
+ char[] buffer = new char[1024];
+
+ try {
+ FileReader file = new FileReader(DOCK_STATE_PATH);
+ int len = file.read(buffer, 0, 1024);
+ mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
+
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "This kernel does not have dock station support");
+ } catch (Exception e) {
+ Log.e(TAG, "" , e);
+ }
+ }
+
+ void systemReady() {
+ synchronized (this) {
+ // don't bother broadcasting undocked here
+ if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ update();
+ }
+ mSystemReady = true;
+ }
+ }
+
+ private final void update() {
+ mHandler.sendEmptyMessage(0);
+ }
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ synchronized (this) {
+ Log.d(TAG, "Broadcasting dock state " + mDockState);
+ // Pack up the values and broadcast them to everyone
+ Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
+ intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
+ mContext.sendStickyBroadcast(intent);
+ }
+ }
+ };
+}
diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java
index 5bc9b5f..6ac72e0 100755
--- a/services/java/com/android/server/HardwareService.java
+++ b/services/java/com/android/server/HardwareService.java
@@ -37,6 +37,9 @@ import android.os.Binder;
import android.os.SystemClock;
import android.util.Log;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
public class HardwareService extends IHardwareService.Stub {
private static final String TAG = "HardwareService";
@@ -50,9 +53,62 @@ public class HardwareService extends IHardwareService.Stub {
static final int LIGHT_FLASH_NONE = 0;
static final int LIGHT_FLASH_TIMED = 1;
+ private final LinkedList<Vibration> mVibrations;
+ private Vibration mCurrentVibration;
+
private boolean mAttentionLightOn;
private boolean mPulsing;
+ private class Vibration implements IBinder.DeathRecipient {
+ private final IBinder mToken;
+ private final long mTimeout;
+ private final long mStartTime;
+ private final long[] mPattern;
+ private final int mRepeat;
+
+ Vibration(IBinder token, long millis) {
+ this(token, millis, null, 0);
+ }
+
+ Vibration(IBinder token, long[] pattern, int repeat) {
+ this(token, 0, pattern, repeat);
+ }
+
+ private Vibration(IBinder token, long millis, long[] pattern,
+ int repeat) {
+ mToken = token;
+ mTimeout = millis;
+ mStartTime = SystemClock.uptimeMillis();
+ mPattern = pattern;
+ mRepeat = repeat;
+ }
+
+ public void binderDied() {
+ synchronized (mVibrations) {
+ mVibrations.remove(this);
+ if (this == mCurrentVibration) {
+ doCancelVibrateLocked();
+ startNextVibrationLocked();
+ }
+ }
+ }
+
+ public boolean hasLongerTimeout(long millis) {
+ if (mTimeout == 0) {
+ // This is a pattern, return false to play the simple
+ // vibration.
+ return false;
+ }
+ if ((mStartTime + mTimeout)
+ < (SystemClock.uptimeMillis() + millis)) {
+ // If this vibration will end before the time passed in, let
+ // the new vibration play.
+ return false;
+ }
+ return true;
+ }
+ }
+
HardwareService(Context context) {
// Reset the hardware to a default state, in case this is a runtime
// restart instead of a fresh boot.
@@ -66,6 +122,8 @@ public class HardwareService extends IHardwareService.Stub {
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.setReferenceCounted(true);
+ mVibrations = new LinkedList<Vibration>();
+
mBatteryStats = BatteryStatsService.getService();
IntentFilter filter = new IntentFilter();
@@ -78,13 +136,27 @@ public class HardwareService extends IHardwareService.Stub {
super.finalize();
}
- public void vibrate(long milliseconds) {
+ public void vibrate(long milliseconds, IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
}
- doCancelVibrate();
- vibratorOn(milliseconds);
+ // We're running in the system server so we cannot crash. Check for a
+ // timeout of 0 or negative. This will ensure that a vibration has
+ // either a timeout of > 0 or a non-null pattern.
+ if (milliseconds <= 0 || (mCurrentVibration != null
+ && mCurrentVibration.hasLongerTimeout(milliseconds))) {
+ // Ignore this vibration since the current vibration will play for
+ // longer than milliseconds.
+ return;
+ }
+ Vibration vib = new Vibration(token, milliseconds);
+ synchronized (mVibrations) {
+ removeVibrationLocked(token);
+ doCancelVibrateLocked();
+ mCurrentVibration = vib;
+ startVibrationLocked(vib);
+ }
}
private boolean isAll0(long[] pattern) {
@@ -121,34 +193,25 @@ public class HardwareService extends IHardwareService.Stub {
return;
}
- synchronized (this) {
- Death death = new Death(token);
- try {
- token.linkToDeath(death, 0);
- } catch (RemoteException e) {
- return;
- }
-
- Thread oldThread = mThread;
-
- if (oldThread != null) {
- // stop the old one
- synchronized (mThread) {
- mThread.mDone = true;
- mThread.notify();
- }
- }
+ Vibration vib = new Vibration(token, pattern, repeat);
+ try {
+ token.linkToDeath(vib, 0);
+ } catch (RemoteException e) {
+ return;
+ }
- if (mDeath != null) {
- mToken.unlinkToDeath(mDeath, 0);
+ synchronized (mVibrations) {
+ removeVibrationLocked(token);
+ doCancelVibrateLocked();
+ if (repeat >= 0) {
+ mVibrations.addFirst(vib);
+ startNextVibrationLocked();
+ } else {
+ // A negative repeat means that this pattern is not meant
+ // to repeat. Treat it like a simple vibration.
+ mCurrentVibration = vib;
+ startVibrationLocked(vib);
}
-
- mDeath = death;
- mToken = token;
-
- // start the new thread
- mThread = new VibrateThread(pattern, repeat);
- mThread.start();
}
}
finally {
@@ -156,7 +219,7 @@ public class HardwareService extends IHardwareService.Stub {
}
}
- public void cancelVibrate() {
+ public void cancelVibrate(IBinder token) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.VIBRATE,
"cancelVibrate");
@@ -164,7 +227,13 @@ public class HardwareService extends IHardwareService.Stub {
// so wakelock calls will succeed
long identity = Binder.clearCallingIdentity();
try {
- doCancelVibrate();
+ synchronized (mVibrations) {
+ final Vibration vib = removeVibrationLocked(token);
+ if (vib == mCurrentVibration) {
+ doCancelVibrateLocked();
+ startNextVibrationLocked();
+ }
+ }
}
finally {
Binder.restoreCallingIdentity(identity);
@@ -277,27 +346,74 @@ public class HardwareService extends IHardwareService.Stub {
}
};
- private void doCancelVibrate() {
- synchronized (this) {
- if (mThread != null) {
- synchronized (mThread) {
- mThread.mDone = true;
- mThread.notify();
- }
- mThread = null;
+ private final Runnable mVibrationRunnable = new Runnable() {
+ public void run() {
+ synchronized (mVibrations) {
+ doCancelVibrateLocked();
+ startNextVibrationLocked();
+ }
+ }
+ };
+
+ // Lock held on mVibrations
+ private void doCancelVibrateLocked() {
+ if (mThread != null) {
+ synchronized (mThread) {
+ mThread.mDone = true;
+ mThread.notify();
}
- vibratorOff();
+ mThread = null;
}
+ vibratorOff();
+ mH.removeCallbacks(mVibrationRunnable);
+ }
+
+ // Lock held on mVibrations
+ private void startNextVibrationLocked() {
+ if (mVibrations.size() <= 0) {
+ return;
+ }
+ mCurrentVibration = mVibrations.getFirst();
+ startVibrationLocked(mCurrentVibration);
+ }
+
+ // Lock held on mVibrations
+ private void startVibrationLocked(final Vibration vib) {
+ if (vib.mTimeout != 0) {
+ vibratorOn(vib.mTimeout);
+ mH.postDelayed(mVibrationRunnable, vib.mTimeout);
+ } else {
+ // mThread better be null here. doCancelVibrate should always be
+ // called before startNextVibrationLocked or startVibrationLocked.
+ mThread = new VibrateThread(vib);
+ mThread.start();
+ }
+ }
+
+ // Lock held on mVibrations
+ private Vibration removeVibrationLocked(IBinder token) {
+ ListIterator<Vibration> iter = mVibrations.listIterator(0);
+ while (iter.hasNext()) {
+ Vibration vib = iter.next();
+ if (vib.mToken == token) {
+ iter.remove();
+ return vib;
+ }
+ }
+ // We might be looking for a simple vibration which is only stored in
+ // mCurrentVibration.
+ if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
+ return mCurrentVibration;
+ }
+ return null;
}
private class VibrateThread extends Thread {
- long[] mPattern;
- int mRepeat;
+ final Vibration mVibration;
boolean mDone;
- VibrateThread(long[] pattern, int repeat) {
- mPattern = pattern;
- mRepeat = repeat;
+ VibrateThread(Vibration vib) {
+ mVibration = vib;
mWakeLock.acquire();
}
@@ -323,8 +439,9 @@ public class HardwareService extends IHardwareService.Stub {
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
synchronized (this) {
int index = 0;
- long[] pattern = mPattern;
+ long[] pattern = mVibration.mPattern;
int len = pattern.length;
+ int repeat = mVibration.mRepeat;
long duration = 0;
while (!mDone) {
@@ -347,50 +464,37 @@ public class HardwareService extends IHardwareService.Stub {
HardwareService.this.vibratorOn(duration);
}
} else {
- if (mRepeat < 0) {
+ if (repeat < 0) {
break;
} else {
- index = mRepeat;
+ index = repeat;
duration = 0;
}
}
}
- if (mDone) {
- // make sure vibrator is off if we were cancelled.
- // otherwise, it will turn off automatically
- // when the last timeout expires.
- HardwareService.this.vibratorOff();
- }
mWakeLock.release();
}
- synchronized (HardwareService.this) {
+ synchronized (mVibrations) {
if (mThread == this) {
mThread = null;
}
- }
- }
- };
-
- private class Death implements IBinder.DeathRecipient {
- IBinder mMe;
-
- Death(IBinder me) {
- mMe = me;
- }
-
- public void binderDied() {
- synchronized (HardwareService.this) {
- if (mMe == mToken) {
- doCancelVibrate();
+ if (!mDone) {
+ // If this vibration finished naturally, start the next
+ // vibration.
+ mVibrations.remove(mVibration);
+ startNextVibrationLocked();
}
}
}
- }
+ };
BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
- doCancelVibrate();
+ synchronized (mVibrations) {
+ doCancelVibrateLocked();
+ mVibrations.clear();
+ }
}
}
};
@@ -407,8 +511,6 @@ public class HardwareService extends IHardwareService.Stub {
private final IBatteryStats mBatteryStats;
volatile VibrateThread mThread;
- volatile Death mDeath;
- volatile IBinder mToken;
private int mNativePointer;
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
index 9b0a2d4..bee3108 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -41,10 +41,16 @@ class HeadsetObserver extends UEventObserver {
private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state";
private static final String HEADSET_NAME_PATH = "/sys/class/switch/h2w/name";
+ private static final int BIT_HEADSET = (1 << 0);
+ private static final int BIT_HEADSET_NO_MIC = (1 << 1);
+ private static final int BIT_TTY = (1 << 2);
+ private static final int BIT_FM_HEADSET = (1 << 3);
+ private static final int BIT_FM_SPEAKER = (1 << 4);
+
private int mHeadsetState;
+ private int mPrevHeadsetState;
private String mHeadsetName;
- private boolean mAudioRouteNeedsUpdate;
- private AudioManager mAudioManager;
+ private boolean mPendingIntent;
private final Context mContext;
private final WakeLock mWakeLock; // held while there is a pending route change
@@ -76,6 +82,7 @@ class HeadsetObserver extends UEventObserver {
String newName = mHeadsetName;
int newState = mHeadsetState;
+ mPrevHeadsetState = mHeadsetState;
try {
FileReader file = new FileReader(HEADSET_STATE_PATH);
int len = file.read(buffer, 0, 1024);
@@ -91,20 +98,25 @@ class HeadsetObserver extends UEventObserver {
Log.e(TAG, "" , e);
}
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
update(newName, newState);
}
private synchronized final void update(String newName, int newState) {
if (newName != mHeadsetName || newState != mHeadsetState) {
- boolean isUnplug = (newState == 0 && mHeadsetState == 1);
+ boolean isUnplug = false;
+ if ( (mHeadsetState & BIT_HEADSET) > 0 || (mHeadsetState & BIT_HEADSET_NO_MIC) > 0) {
+ if ((newState & BIT_HEADSET) == 0 && (newState & BIT_HEADSET_NO_MIC) == 0)
+ isUnplug = true;
+ }
mHeadsetName = newName;
+ mPrevHeadsetState = mHeadsetState;
mHeadsetState = newState;
- mAudioRouteNeedsUpdate = true;
-
- sendIntent(isUnplug);
+ mPendingIntent = true;
if (isUnplug) {
+ Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+
// It can take hundreds of ms flush the audio pipeline after
// apps pause audio playback, but audio route changes are
// immediate, so delay the route change by 1000ms.
@@ -113,12 +125,13 @@ class HeadsetObserver extends UEventObserver {
mWakeLock.acquire();
mHandler.sendEmptyMessageDelayed(0, 1000);
} else {
- updateAudioRoute();
+ sendIntent();
+ mPendingIntent = false;
}
}
}
- private synchronized final void sendIntent(boolean isUnplug) {
+ private synchronized final void sendIntent() {
// Pack up the values and broadcast them to everyone
Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -128,24 +141,15 @@ class HeadsetObserver extends UEventObserver {
// TODO: Should we require a permission?
ActivityManagerNative.broadcastStickyIntent(intent, null);
-
- if (isUnplug) {
- intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- mContext.sendBroadcast(intent);
- }
- }
-
- private synchronized final void updateAudioRoute() {
- if (mAudioRouteNeedsUpdate) {
- mAudioManager.setWiredHeadsetOn(mHeadsetState == 1);
- mAudioRouteNeedsUpdate = false;
- }
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- updateAudioRoute();
+ if (mPendingIntent) {
+ sendIntent();
+ mPendingIntent = false;
+ }
mWakeLock.release();
}
};
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index 7b8a2a4..e1bce73 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -23,9 +23,14 @@ import android.view.Surface;
import android.view.WindowManagerPolicy;
public class InputDevice {
+ static final boolean DEBUG_POINTERS = false;
+
/** Amount that trackball needs to move in order to generate a key event. */
static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
+ /** Maximum number of pointers we will track and report. */
+ static final int MAX_POINTERS = 10;
+
final int id;
final int classes;
final String name;
@@ -34,9 +39,13 @@ public class InputDevice {
final AbsoluteInfo absPressure;
final AbsoluteInfo absSize;
- long mDownTime = 0;
+ long mKeyDownTime = 0;
int mMetaKeysState = 0;
+ // For use by KeyInputQueue for keeping track of the current touch
+ // data in the old non-multi-touch protocol.
+ final int[] curTouchVals = new int[MotionEvent.NUM_SAMPLE_DATA * 2];
+
final MotionState mAbs = new MotionState(0, 0);
final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD,
TRACKBALL_MOVEMENT_THRESHOLD);
@@ -48,146 +57,503 @@ public class InputDevice {
float yMoveScale;
MotionEvent currentMove = null;
boolean changed = false;
- boolean down = false;
- boolean lastDown = false;
- long downTime = 0;
- int x = 0;
- int y = 0;
- int pressure = 1;
- int size = 0;
+ long mDownTime = 0;
+
+ // The currently assigned pointer IDs, corresponding to the last data.
+ int[] mPointerIds = new int[MAX_POINTERS];
+
+ // This is the last generated pointer data, ordered to match
+ // mPointerIds.
+ int mLastNumPointers = 0;
+ final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
+
+ // This is the next set of pointer data being generated. It is not
+ // in any known order, and will be propagated in to mLastData
+ // as part of mapping it to the appropriate pointer IDs.
+ // Note that we have one extra sample of data here, to help clients
+ // avoid doing bounds checking.
+ int mNextNumPointers = 0;
+ final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
+ + MotionEvent.NUM_SAMPLE_DATA];
+
+ // Temporary data structures for doing the pointer ID mapping.
+ final int[] mLast2Next = new int[MAX_POINTERS];
+ final int[] mNext2Last = new int[MAX_POINTERS];
+ final long[] mNext2LastDistance = new long[MAX_POINTERS];
+
+ // Temporary data structure for generating the final motion data.
+ final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
+
+ // This is not used here, but can be used by callers for state tracking.
+ int mAddingPointerOffset = 0;
+ final boolean[] mDown = new boolean[MAX_POINTERS];
MotionState(int mx, int my) {
xPrecision = mx;
yPrecision = my;
xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f;
yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
+ for (int i=0; i<MAX_POINTERS; i++) {
+ mPointerIds[i] = i;
+ }
}
- MotionEvent generateMotion(InputDevice device, long curTime,
- boolean isAbs, Display display, int orientation,
- int metaState) {
- if (!changed) {
- return null;
+ private boolean assignPointer(int nextIndex, boolean allowOverlap) {
+ final int lastNumPointers = mLastNumPointers;
+ final int[] next2Last = mNext2Last;
+ final long[] next2LastDistance = mNext2LastDistance;
+ final int[] last2Next = mLast2Next;
+ final int[] lastData = mLastData;
+ final int[] nextData = mNextData;
+ final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
+
+ if (DEBUG_POINTERS) Log.v("InputDevice", "assignPointer: nextIndex="
+ + nextIndex + " dataOff=" + id);
+ final int x1 = nextData[id + MotionEvent.SAMPLE_X];
+ final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
+
+ long bestDistance = -1;
+ int bestIndex = -1;
+ for (int j=0; j<lastNumPointers; j++) {
+ if (!allowOverlap && last2Next[j] < 0) {
+ continue;
+ }
+ final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
+ final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
+ final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
+ final long distance = xd*(long)xd + yd*(long)yd;
+ if (j == 0 || distance < bestDistance) {
+ bestDistance = distance;
+ bestIndex = j;
+ }
}
- float scaledX = x;
- float scaledY = y;
- float temp;
- float scaledPressure = 1.0f;
- float scaledSize = 0;
- int edgeFlags = 0;
- if (isAbs) {
- int w = display.getWidth()-1;
- int h = display.getHeight()-1;
- if (orientation == Surface.ROTATION_90
- || orientation == Surface.ROTATION_270) {
- int tmp = w;
- w = h;
- h = tmp;
- }
- if (device.absX != null) {
- scaledX = ((scaledX-device.absX.minValue)
- / device.absX.range) * w;
- }
- if (device.absY != null) {
- scaledY = ((scaledY-device.absY.minValue)
- / device.absY.range) * h;
- }
- if (device.absPressure != null) {
- scaledPressure =
- ((pressure-device.absPressure.minValue)
- / (float)device.absPressure.range);
- }
- if (device.absSize != null) {
- scaledSize =
- ((size-device.absSize.minValue)
- / (float)device.absSize.range);
+ if (DEBUG_POINTERS) Log.v("InputDevice", "New index " + nextIndex
+ + " best old index=" + bestIndex + " (distance="
+ + bestDistance + ")");
+ next2Last[nextIndex] = bestIndex;
+ next2LastDistance[nextIndex] = bestDistance;
+
+ if (bestIndex < 0) {
+ return true;
+ }
+
+ if (last2Next[bestIndex] == -1) {
+ last2Next[bestIndex] = nextIndex;
+ return false;
+ }
+
+ if (DEBUG_POINTERS) Log.v("InputDevice", "Old index " + bestIndex
+ + " has multiple best new pointers!");
+
+ last2Next[bestIndex] = -2;
+ return true;
+ }
+
+ private int updatePointerIdentifiers() {
+ final int[] lastData = mLastData;
+ final int[] nextData = mNextData;
+ final int nextNumPointers = mNextNumPointers;
+ final int lastNumPointers = mLastNumPointers;
+
+ if (nextNumPointers == 1 && lastNumPointers == 1) {
+ System.arraycopy(nextData, 0, lastData, 0,
+ MotionEvent.NUM_SAMPLE_DATA);
+ return -1;
+ }
+
+ // Clear our old state.
+ final int[] last2Next = mLast2Next;
+ for (int i=0; i<lastNumPointers; i++) {
+ last2Next[i] = -1;
+ }
+
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Update pointers: lastNumPointers=" + lastNumPointers
+ + " nextNumPointers=" + nextNumPointers);
+
+ // Figure out the closes new points to the previous points.
+ final int[] next2Last = mNext2Last;
+ final long[] next2LastDistance = mNext2LastDistance;
+ boolean conflicts = false;
+ for (int i=0; i<nextNumPointers; i++) {
+ conflicts |= assignPointer(i, true);
+ }
+
+ // Resolve ambiguities in pointer mappings, when two or more
+ // new pointer locations find their best previous location is
+ // the same.
+ if (conflicts) {
+ if (DEBUG_POINTERS) Log.v("InputDevice", "Resolving conflicts");
+
+ for (int i=0; i<lastNumPointers; i++) {
+ if (last2Next[i] != -2) {
+ continue;
+ }
+
+ // Note that this algorithm is far from perfect. Ideally
+ // we should do something like the one described at
+ // http://portal.acm.org/citation.cfm?id=997856
+
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Resolving last index #" + i);
+
+ int numFound;
+ do {
+ numFound = 0;
+ long worstDistance = 0;
+ int worstJ = -1;
+ for (int j=0; j<nextNumPointers; j++) {
+ if (next2Last[j] != i) {
+ continue;
+ }
+ numFound++;
+ if (worstDistance < next2LastDistance[j]) {
+ worstDistance = next2LastDistance[j];
+ worstJ = j;
+ }
+ }
+
+ if (worstJ >= 0) {
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Worst new pointer: " + worstJ
+ + " (distance=" + worstDistance + ")");
+ if (assignPointer(worstJ, false)) {
+ // In this case there is no last pointer
+ // remaining for this new one!
+ next2Last[worstJ] = -1;
+ }
+ }
+ } while (numFound > 2);
}
- switch (orientation) {
- case Surface.ROTATION_90:
- temp = scaledX;
- scaledX = scaledY;
- scaledY = w-temp;
+ }
+
+ int retIndex = -1;
+
+ if (lastNumPointers < nextNumPointers) {
+ // We have one or more new pointers that are down. Create a
+ // new pointer identifier for one of them.
+ if (DEBUG_POINTERS) Log.v("InputDevice", "Adding new pointer");
+ int nextId = 0;
+ int i=0;
+ while (i < lastNumPointers) {
+ if (mPointerIds[i] > nextId) {
+ // Found a hole, insert the pointer here.
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Inserting new pointer at hole " + i);
+ System.arraycopy(mPointerIds, i, mPointerIds,
+ i+1, lastNumPointers-i);
+ System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
+ lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
+ (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
break;
- case Surface.ROTATION_180:
- scaledX = w-scaledX;
- scaledY = h-scaledY;
+ }
+ i++;
+ nextId++;
+ }
+
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "New pointer id " + nextId + " at index " + i);
+
+ mLastNumPointers++;
+ retIndex = i;
+ mPointerIds[i] = nextId;
+
+ // And assign this identifier to the first new pointer.
+ for (int j=0; j<nextNumPointers; j++) {
+ if (next2Last[j] < 0) {
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Assigning new id to new pointer index " + j);
+ next2Last[j] = i;
break;
- case Surface.ROTATION_270:
- temp = scaledX;
- scaledX = h-scaledY;
- scaledY = temp;
+ }
+ }
+ }
+
+ // Propagate all of the current data into the appropriate
+ // location in the old data to match the pointer ID that was
+ // assigned to it.
+ for (int i=0; i<nextNumPointers; i++) {
+ int lastIndex = next2Last[i];
+ if (lastIndex >= 0) {
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Copying next pointer index " + i
+ + " to last index " + lastIndex);
+ System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
+ lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
+ MotionEvent.NUM_SAMPLE_DATA);
+ }
+ }
+
+ if (lastNumPointers > nextNumPointers) {
+ // One or more pointers has gone up. Find the first one,
+ // and adjust accordingly.
+ if (DEBUG_POINTERS) Log.v("InputDevice", "Removing old pointer");
+ for (int i=0; i<lastNumPointers; i++) {
+ if (last2Next[i] == -1) {
+ if (DEBUG_POINTERS) Log.v("InputDevice",
+ "Removing old pointer at index " + i);
+ retIndex = i;
break;
+ }
}
-
- if (scaledX == 0) {
- edgeFlags += MotionEvent.EDGE_LEFT;
- } else if (scaledX == display.getWidth() - 1.0f) {
- edgeFlags += MotionEvent.EDGE_RIGHT;
+ }
+
+ return retIndex;
+ }
+
+ void removeOldPointer(int index) {
+ final int lastNumPointers = mLastNumPointers;
+ if (index >= 0 && index < lastNumPointers) {
+ System.arraycopy(mPointerIds, index+1, mPointerIds,
+ index, lastNumPointers-index-1);
+ System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
+ mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
+ (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
+ mLastNumPointers--;
+ }
+ }
+
+ MotionEvent generateAbsMotion(InputDevice device, long curTime,
+ long curTimeNano, Display display, int orientation,
+ int metaState) {
+
+ if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
+ return null;
+ }
+
+ final int lastNumPointers = mLastNumPointers;
+ final int nextNumPointers = mNextNumPointers;
+ if (mNextNumPointers > MAX_POINTERS) {
+ Log.w("InputDevice", "Number of pointers " + mNextNumPointers
+ + " exceeded maximum of " + MAX_POINTERS);
+ mNextNumPointers = MAX_POINTERS;
+ }
+
+ int upOrDownPointer = updatePointerIdentifiers();
+
+ final float[] reportData = mReportData;
+ final int[] rawData = mLastData;
+
+ final int numPointers = mLastNumPointers;
+
+ if (DEBUG_POINTERS) Log.v("InputDevice", "Processing "
+ + numPointers + " pointers (going from " + lastNumPointers
+ + " to " + nextNumPointers + ")");
+
+ for (int i=0; i<numPointers; i++) {
+ final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
+ reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
+ reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
+ reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
+ reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
+ }
+
+ int action;
+ int edgeFlags = 0;
+ if (nextNumPointers != lastNumPointers) {
+ if (nextNumPointers > lastNumPointers) {
+ if (lastNumPointers == 0) {
+ action = MotionEvent.ACTION_DOWN;
+ mDownTime = curTime;
+ } else {
+ action = MotionEvent.ACTION_POINTER_DOWN
+ | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
+ }
+ } else {
+ if (numPointers == 1) {
+ action = MotionEvent.ACTION_UP;
+ } else {
+ action = MotionEvent.ACTION_POINTER_UP
+ | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);
+ }
}
-
- if (scaledY == 0) {
- edgeFlags += MotionEvent.EDGE_TOP;
- } else if (scaledY == display.getHeight() - 1.0f) {
- edgeFlags += MotionEvent.EDGE_BOTTOM;
+ currentMove = null;
+ } else {
+ action = MotionEvent.ACTION_MOVE;
+ }
+
+ final int dispW = display.getWidth()-1;
+ final int dispH = display.getHeight()-1;
+ int w = dispW;
+ int h = dispH;
+ if (orientation == Surface.ROTATION_90
+ || orientation == Surface.ROTATION_270) {
+ int tmp = w;
+ w = h;
+ h = tmp;
+ }
+
+ final AbsoluteInfo absX = device.absX;
+ final AbsoluteInfo absY = device.absY;
+ final AbsoluteInfo absPressure = device.absPressure;
+ final AbsoluteInfo absSize = device.absSize;
+ for (int i=0; i<numPointers; i++) {
+ final int j = i * MotionEvent.NUM_SAMPLE_DATA;
+
+ if (absX != null) {
+ reportData[j + MotionEvent.SAMPLE_X] =
+ ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
+ / absX.range) * w;
+ }
+ if (absY != null) {
+ reportData[j + MotionEvent.SAMPLE_Y] =
+ ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
+ / absY.range) * h;
+ }
+ if (absPressure != null) {
+ reportData[j + MotionEvent.SAMPLE_PRESSURE] =
+ ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
+ / (float)absPressure.range);
+ }
+ if (absSize != null) {
+ reportData[j + MotionEvent.SAMPLE_SIZE] =
+ ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
+ / (float)absSize.range);
}
- } else {
- scaledX *= xMoveScale;
- scaledY *= yMoveScale;
switch (orientation) {
- case Surface.ROTATION_90:
- temp = scaledX;
- scaledX = scaledY;
- scaledY = -temp;
+ case Surface.ROTATION_90: {
+ final float temp = reportData[j + MotionEvent.SAMPLE_X];
+ reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];
+ reportData[j + MotionEvent.SAMPLE_Y] = w-temp;
break;
- case Surface.ROTATION_180:
- scaledX = -scaledX;
- scaledY = -scaledY;
+ }
+ case Surface.ROTATION_180: {
+ reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];
+ reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];
break;
- case Surface.ROTATION_270:
- temp = scaledX;
- scaledX = -scaledY;
- scaledY = temp;
+ }
+ case Surface.ROTATION_270: {
+ final float temp = reportData[j + MotionEvent.SAMPLE_X];
+ reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];
+ reportData[j + MotionEvent.SAMPLE_Y] = temp;
break;
+ }
+ }
+ }
+
+ // We only consider the first pointer when computing the edge
+ // flags, since they are global to the event.
+ if (action == MotionEvent.ACTION_DOWN) {
+ if (reportData[MotionEvent.SAMPLE_X] <= 0) {
+ edgeFlags |= MotionEvent.EDGE_LEFT;
+ } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {
+ edgeFlags |= MotionEvent.EDGE_RIGHT;
+ }
+ if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
+ edgeFlags |= MotionEvent.EDGE_TOP;
+ } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
+ edgeFlags |= MotionEvent.EDGE_BOTTOM;
+ }
+ }
+
+ if (currentMove != null) {
+ if (false) Log.i("InputDevice", "Adding batch x="
+ + reportData[MotionEvent.SAMPLE_X]
+ + " y=" + reportData[MotionEvent.SAMPLE_Y]
+ + " to " + currentMove);
+ currentMove.addBatch(curTime, reportData, metaState);
+ if (WindowManagerPolicy.WATCH_POINTER) {
+ Log.i("KeyInputQueue", "Updating: " + currentMove);
}
+ return null;
+ }
+
+ MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
+ curTimeNano, action, numPointers, mPointerIds, reportData,
+ metaState, xPrecision, yPrecision, device.id, edgeFlags);
+ if (action == MotionEvent.ACTION_MOVE) {
+ currentMove = me;
+ }
+
+ if (nextNumPointers < lastNumPointers) {
+ removeOldPointer(upOrDownPointer);
}
- changed = false;
- if (down != lastDown) {
- int action;
- lastDown = down;
- if (down) {
+ return me;
+ }
+
+ boolean hasMore() {
+ return mLastNumPointers != mNextNumPointers;
+ }
+
+ void finish() {
+ mNextNumPointers = mAddingPointerOffset = 0;
+ mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
+ }
+
+ MotionEvent generateRelMotion(InputDevice device, long curTime,
+ long curTimeNano, int orientation, int metaState) {
+
+ final float[] scaled = mReportData;
+
+ // For now we only support 1 pointer with relative motions.
+ scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
+ scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
+ scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
+ scaled[MotionEvent.SAMPLE_SIZE] = 0;
+ int edgeFlags = 0;
+
+ int action;
+ if (mNextNumPointers != mLastNumPointers) {
+ mNextData[MotionEvent.SAMPLE_X] =
+ mNextData[MotionEvent.SAMPLE_Y] = 0;
+ if (mNextNumPointers > 0 && mLastNumPointers == 0) {
action = MotionEvent.ACTION_DOWN;
- downTime = curTime;
- } else {
+ mDownTime = curTime;
+ } else if (mNextNumPointers == 0) {
action = MotionEvent.ACTION_UP;
+ } else {
+ action = MotionEvent.ACTION_MOVE;
}
+ mLastNumPointers = mNextNumPointers;
currentMove = null;
- if (!isAbs) {
- x = y = 0;
- }
- return MotionEvent.obtain(downTime, curTime, action,
- scaledX, scaledY, scaledPressure, scaledSize, metaState,
- xPrecision, yPrecision, device.id, edgeFlags);
} else {
- if (currentMove != null) {
- if (false) Log.i("InputDevice", "Adding batch x=" + scaledX
- + " y=" + scaledY + " to " + currentMove);
- currentMove.addBatch(curTime, scaledX, scaledY,
- scaledPressure, scaledSize, metaState);
- if (WindowManagerPolicy.WATCH_POINTER) {
- Log.i("KeyInputQueue", "Updating: " + currentMove);
- }
- return null;
+ action = MotionEvent.ACTION_MOVE;
+ }
+
+ scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
+ scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
+ switch (orientation) {
+ case Surface.ROTATION_90: {
+ final float temp = scaled[MotionEvent.SAMPLE_X];
+ scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y];
+ scaled[MotionEvent.SAMPLE_Y] = -temp;
+ break;
}
- MotionEvent me = MotionEvent.obtain(downTime, curTime,
- MotionEvent.ACTION_MOVE, scaledX, scaledY,
- scaledPressure, scaledSize, metaState,
- xPrecision, yPrecision, device.id, edgeFlags);
+ case Surface.ROTATION_180: {
+ scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X];
+ scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y];
+ break;
+ }
+ case Surface.ROTATION_270: {
+ final float temp = scaled[MotionEvent.SAMPLE_X];
+ scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y];
+ scaled[MotionEvent.SAMPLE_Y] = temp;
+ break;
+ }
+ }
+
+ if (currentMove != null) {
+ if (false) Log.i("InputDevice", "Adding batch x="
+ + scaled[MotionEvent.SAMPLE_X]
+ + " y=" + scaled[MotionEvent.SAMPLE_Y]
+ + " to " + currentMove);
+ currentMove.addBatch(curTime, scaled, metaState);
+ if (WindowManagerPolicy.WATCH_POINTER) {
+ Log.i("KeyInputQueue", "Updating: " + currentMove);
+ }
+ return null;
+ }
+
+ MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
+ curTimeNano, action, 1, mPointerIds, scaled, metaState,
+ xPrecision, yPrecision, device.id, edgeFlags);
+ if (action == MotionEvent.ACTION_MOVE) {
currentMove = me;
- return me;
}
+ return me;
}
}
diff --git a/services/java/com/android/server/JournaledFile.java b/services/java/com/android/server/JournaledFile.java
new file mode 100644
index 0000000..3d1f52d
--- /dev/null
+++ b/services/java/com/android/server/JournaledFile.java
@@ -0,0 +1,107 @@
+/*
+ * 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.server;
+
+import java.io.File;
+import java.io.IOException;
+
+public class JournaledFile {
+ File mReal;
+ File mTemp;
+ boolean mWriting;
+
+ public JournaledFile(File real, File temp) {
+ mReal = real;
+ mTemp = temp;
+ }
+
+ /** Returns the file for you to read.
+ * @more
+ * Prefers the real file. If it doesn't exist, uses the temp one, and then copies
+ * it to the real one. If there is both a real file and a temp one, assumes that the
+ * temp one isn't fully written and deletes it.
+ */
+ public File chooseForRead() {
+ File result;
+ if (mReal.exists()) {
+ result = mReal;
+ if (mTemp.exists()) {
+ mTemp.delete();
+ }
+ } else if (mTemp.exists()) {
+ result = mTemp;
+ mTemp.renameTo(mReal);
+ } else {
+ return mReal;
+ }
+ return result;
+ }
+
+ /**
+ * Returns a file for you to write.
+ * @more
+ * If a write is already happening, throws. In other words, you must provide your
+ * own locking.
+ * <p>
+ * Call {@link #commit} to commit the changes, or {@link #rollback} to forget the changes.
+ */
+ public File chooseForWrite() {
+ if (mWriting) {
+ throw new IllegalStateException("uncommitted write already in progress");
+ }
+ if (!mReal.exists()) {
+ // If the real one doesn't exist, it's either because this is the first time
+ // or because something went wrong while copying them. In this case, we can't
+ // trust anything that's in temp. In order to have the chooseForRead code not
+ // use the temporary one until it's fully written, create an empty file
+ // for real, which will we'll shortly delete.
+ try {
+ mReal.createNewFile();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+
+ if (mTemp.exists()) {
+ mTemp.delete();
+ }
+ mWriting = true;
+ return mTemp;
+ }
+
+ /**
+ * Commit changes.
+ */
+ public void commit() {
+ if (!mWriting) {
+ throw new IllegalStateException("no file to commit");
+ }
+ mWriting = false;
+ mTemp.renameTo(mReal);
+ }
+
+ /**
+ * Roll back changes.
+ */
+ public void rollback() {
+ if (!mWriting) {
+ throw new IllegalStateException("no file to roll back");
+ }
+ mWriting = false;
+ mTemp.delete();
+ }
+}
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 411cd6b..7ca12f2 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -18,10 +18,13 @@ package com.android.server;
import android.content.Context;
import android.content.res.Configuration;
-import android.os.SystemClock;
+import android.os.Environment;
+import android.os.LatencyTimer;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
+import android.util.Xml;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -29,10 +32,30 @@ import android.view.RawInputEvent;
import android.view.Surface;
import android.view.WindowManagerPolicy;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
public abstract class KeyInputQueue {
static final String TAG = "KeyInputQueue";
- SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
+ static final boolean DEBUG_VIRTUAL_KEYS = false;
+ static final boolean DEBUG_POINTERS = false;
+
+ private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
+
+ final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
+ final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
+ final HapticFeedbackCallback mHapticFeedbackCallback;
int mGlobalMetaState = 0;
boolean mHaveGlobalMetaState = false;
@@ -43,10 +66,14 @@ public abstract class KeyInputQueue {
int mCacheCount;
Display mDisplay = null;
+ int mDisplayWidth;
+ int mDisplayHeight;
int mOrientation = Surface.ROTATION_0;
int[] mKeyRotationMap = null;
+ VirtualKey mPressedVirtualKey = null;
+
PowerManager.WakeLock mWakeLock;
static final int[] KEY_90_MAP = new int[] {
@@ -73,14 +100,21 @@ 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);
}
+ public interface HapticFeedbackCallback {
+ void virtualKeyFeedback(KeyEvent event);
+ }
+
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 +122,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;
@@ -106,7 +140,144 @@ public abstract class KeyInputQueue {
QueuedEvent next;
}
- KeyInputQueue(Context context) {
+ /**
+ * A key that exists as a part of the touch-screen, outside of the normal
+ * display area of the screen.
+ */
+ static class VirtualKey {
+ int scancode;
+ int centerx;
+ int centery;
+ int width;
+ int height;
+
+ int hitLeft;
+ int hitTop;
+ int hitRight;
+ int hitBottom;
+
+ InputDevice lastDevice;
+ int lastKeycode;
+
+ boolean checkHit(int x, int y) {
+ return (x >= hitLeft && x <= hitRight
+ && y >= hitTop && y <= hitBottom);
+ }
+
+ void computeHitRect(InputDevice dev, int dw, int dh) {
+ if (dev == lastDevice) {
+ return;
+ }
+
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode
+ + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
+
+ lastDevice = dev;
+
+ int minx = dev.absX.minValue;
+ int maxx = dev.absX.maxValue;
+
+ int halfw = width/2;
+ int left = centerx - halfw;
+ int right = centerx + halfw;
+ hitLeft = minx + ((left*maxx-minx)/dw);
+ hitRight = minx + ((right*maxx-minx)/dw);
+
+ int miny = dev.absY.minValue;
+ int maxy = dev.absY.maxValue;
+
+ int halfh = height/2;
+ int top = centery - halfh;
+ int bottom = centery + halfh;
+ hitTop = miny + ((top*maxy-miny)/dh);
+ hitBottom = miny + ((bottom*maxy-miny)/dh);
+ }
+ }
+
+ private void readVirtualKeys(String deviceName) {
+ try {
+ FileInputStream fis = new FileInputStream(
+ "/sys/board_properties/virtualkeys." + deviceName);
+ InputStreamReader isr = new InputStreamReader(fis);
+ BufferedReader br = new BufferedReader(isr);
+ String str = br.readLine();
+ if (str != null) {
+ String[] it = str.split(":");
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it);
+ final int N = it.length-6;
+ for (int i=0; i<=N; i+=6) {
+ if (!"0x01".equals(it[i])) {
+ Log.w(TAG, "Unknown virtual key type at elem #" + i
+ + ": " + it[i]);
+ continue;
+ }
+ try {
+ VirtualKey sb = new VirtualKey();
+ sb.scancode = Integer.parseInt(it[i+1]);
+ sb.centerx = Integer.parseInt(it[i+2]);
+ sb.centery = Integer.parseInt(it[i+3]);
+ sb.width = Integer.parseInt(it[i+4]);
+ sb.height = Integer.parseInt(it[i+5]);
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key "
+ + sb.scancode + ": center=" + sb.centerx + ","
+ + sb.centery + " size=" + sb.width + "x"
+ + sb.height);
+ mVirtualKeys.add(sb);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Bad number at region " + i + " in: "
+ + str, e);
+ }
+ }
+ }
+ br.close();
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "No virtual keys found");
+ } catch (IOException e) {
+ Log.w(TAG, "Error reading virtual keys", e);
+ }
+ }
+
+ private void readExcludedDevices() {
+ // Read partner-provided list of excluded input devices
+ XmlPullParser parser = null;
+ // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
+ File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
+ FileReader confreader = null;
+ try {
+ confreader = new FileReader(confFile);
+ parser = Xml.newPullParser();
+ parser.setInput(confreader);
+ XmlUtils.beginDocument(parser, "devices");
+
+ while (true) {
+ XmlUtils.nextElement(parser);
+ if (!"device".equals(parser.getName())) {
+ break;
+ }
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ Log.d(TAG, "addExcludedDevice " + name);
+ addExcludedDevice(name);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // It's ok if the file does not exist.
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
+ } finally {
+ try { if (confreader != null) confreader.close(); } catch (IOException e) { }
+ }
+ }
+
+ KeyInputQueue(Context context, HapticFeedbackCallback hapticFeedbackCallback) {
+ if (MEASURE_LATENCY) {
+ lt = new LatencyTimer(100, 1000);
+ }
+
+ mHapticFeedbackCallback = hapticFeedbackCallback;
+
+ readExcludedDevices();
+
PowerManager pm = (PowerManager)context.getSystemService(
Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -123,6 +294,12 @@ public abstract class KeyInputQueue {
public void setDisplay(Display display) {
mDisplay = display;
+
+ // We assume at this point that the display dimensions reflect the
+ // natural, unrotated display. We will perform hit tests for soft
+ // buttons based on that display.
+ mDisplayWidth = display.getWidth();
+ mDisplayHeight = display.getHeight();
}
public void getInputConfiguration(Configuration config) {
@@ -149,6 +326,10 @@ public abstract class KeyInputQueue {
config.navigation
= Configuration.NAVIGATION_TRACKBALL;
//Log.i("foo", "***** HAVE TRACKBALL!");
+ } else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) {
+ config.navigation
+ = Configuration.NAVIGATION_DPAD;
+ //Log.i("foo", "***** HAVE DPAD!");
}
}
}
@@ -157,6 +338,7 @@ public abstract class KeyInputQueue {
public static native String getDeviceName(int deviceId);
public static native int getDeviceClasses(int deviceId);
+ public static native void addExcludedDevice(String deviceName);
public static native boolean getAbsoluteInfo(int deviceId, int axis,
InputDevice.AbsoluteInfo outInfo);
public static native int getSwitchState(int sw);
@@ -165,6 +347,7 @@ public abstract class KeyInputQueue {
public static native int getScancodeState(int deviceId, int sw);
public static native int getKeycodeState(int sw);
public static native int getKeycodeState(int deviceId, int sw);
+ public static native int scancodeToKeycode(int deviceId, int scancode);
public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
public static KeyEvent newKeyEvent(InputDevice device, long downTime,
@@ -181,12 +364,13 @@ public abstract class KeyInputQueue {
Thread mThread = new Thread("InputDeviceReader") {
public void run() {
+ Log.d(TAG, "InputDeviceReader.run()");
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
- try {
- RawInputEvent ev = new RawInputEvent();
- while (true) {
+ RawInputEvent ev = new RawInputEvent();
+ while (true) {
+ try {
InputDevice di;
// block, doesn't release the monitor
@@ -208,6 +392,9 @@ public abstract class KeyInputQueue {
synchronized (mFirst) {
di = newInputDevice(ev.deviceId);
mDevices.put(ev.deviceId, di);
+ if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ readVirtualKeys(di.name);
+ }
configChanged = true;
}
} else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
@@ -241,7 +428,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 +443,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;
@@ -271,44 +459,92 @@ public abstract class KeyInputQueue {
boolean down;
if (ev.value != 0) {
down = true;
- di.mDownTime = curTime;
+ di.mKeyDownTime = curTime;
} else {
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,
+ newKeyEvent(di, di.mKeyDownTime, curTime, down,
keycode, 0, scancode,
((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
? KeyEvent.FLAG_WOKE_HERE : 0));
} else if (ev.type == RawInputEvent.EV_KEY) {
if (ev.scancode == RawInputEvent.BTN_TOUCH &&
- (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ (classes&(RawInputEvent.CLASS_TOUCHSCREEN
+ |RawInputEvent.CLASS_TOUCHSCREEN_MT))
+ == RawInputEvent.CLASS_TOUCHSCREEN) {
di.mAbs.changed = true;
- di.mAbs.down = ev.value != 0;
- }
- if (ev.scancode == RawInputEvent.BTN_MOUSE &&
+ di.mAbs.mDown[0] = ev.value != 0;
+ } else if (ev.scancode == RawInputEvent.BTN_2 &&
+ (classes&(RawInputEvent.CLASS_TOUCHSCREEN
+ |RawInputEvent.CLASS_TOUCHSCREEN_MT))
+ == RawInputEvent.CLASS_TOUCHSCREEN) {
+ di.mAbs.changed = true;
+ di.mAbs.mDown[1] = ev.value != 0;
+ } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
(classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
di.mRel.changed = true;
- di.mRel.down = ev.value != 0;
+ di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
send = true;
}
} else if (ev.type == RawInputEvent.EV_ABS &&
+ (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
+ if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
+ di.mAbs.changed = true;
+ di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ + MotionEvent.SAMPLE_PRESSURE] = ev.value;
+ } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {
+ di.mAbs.changed = true;
+ di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ + MotionEvent.SAMPLE_X] = ev.value;
+ if (DEBUG_POINTERS) Log.v(TAG, "MT @"
+ + di.mAbs.mAddingPointerOffset
+ + " X:" + ev.value);
+ } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {
+ di.mAbs.changed = true;
+ di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ + MotionEvent.SAMPLE_Y] = ev.value;
+ if (DEBUG_POINTERS) Log.v(TAG, "MT @"
+ + di.mAbs.mAddingPointerOffset
+ + " Y:" + ev.value);
+ } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {
+ di.mAbs.changed = true;
+ di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ + MotionEvent.SAMPLE_SIZE] = ev.value;
+ }
+
+ } else if (ev.type == RawInputEvent.EV_ABS &&
(classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ // Finger 1
if (ev.scancode == RawInputEvent.ABS_X) {
di.mAbs.changed = true;
- di.mAbs.x = ev.value;
+ di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
} else if (ev.scancode == RawInputEvent.ABS_Y) {
di.mAbs.changed = true;
- di.mAbs.y = ev.value;
+ di.curTouchVals[MotionEvent.SAMPLE_Y] = ev.value;
} else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {
di.mAbs.changed = true;
- di.mAbs.pressure = ev.value;
+ di.curTouchVals[MotionEvent.SAMPLE_PRESSURE] = ev.value;
+ di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ + MotionEvent.SAMPLE_PRESSURE] = ev.value;
} else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {
di.mAbs.changed = true;
- di.mAbs.size = ev.value;
+ di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
+ di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ + MotionEvent.SAMPLE_SIZE] = ev.value;
+
+ // Finger 2
+ } else if (ev.scancode == RawInputEvent.ABS_HAT0X) {
+ di.mAbs.changed = true;
+ di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ + MotionEvent.SAMPLE_X] = ev.value;
+ } else if (ev.scancode == RawInputEvent.ABS_HAT0Y) {
+ di.mAbs.changed = true;
+ di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
+ + MotionEvent.SAMPLE_Y] = ev.value;
}
} else if (ev.type == RawInputEvent.EV_REL &&
@@ -316,50 +552,277 @@ public abstract class KeyInputQueue {
// Add this relative movement into our totals.
if (ev.scancode == RawInputEvent.REL_X) {
di.mRel.changed = true;
- di.mRel.x += ev.value;
+ di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
} else if (ev.scancode == RawInputEvent.REL_Y) {
di.mRel.changed = true;
- di.mRel.y += ev.value;
+ di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
}
}
- if (send || ev.type == RawInputEvent.EV_SYN) {
+ if (ev.type == RawInputEvent.EV_SYN
+ && ev.scancode == RawInputEvent.SYN_MT_REPORT
+ && di.mAbs != null) {
+ di.mAbs.changed = true;
+ if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) {
+ // If the value is <= 0, the pointer is not
+ // down, so keep it in the count.
+
+ if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
+ + MotionEvent.SAMPLE_PRESSURE] != 0) {
+ final int num = di.mAbs.mNextNumPointers+1;
+ di.mAbs.mNextNumPointers = num;
+ if (DEBUG_POINTERS) Log.v(TAG,
+ "MT_REPORT: now have " + num + " pointers");
+ final int newOffset = (num <= InputDevice.MAX_POINTERS)
+ ? (num * MotionEvent.NUM_SAMPLE_DATA)
+ : (InputDevice.MAX_POINTERS *
+ MotionEvent.NUM_SAMPLE_DATA);
+ di.mAbs.mAddingPointerOffset = newOffset;
+ di.mAbs.mNextData[newOffset
+ + MotionEvent.SAMPLE_PRESSURE] = 0;
+ } else {
+ if (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer");
+ }
+ }
+ } else if (send || (ev.type == RawInputEvent.EV_SYN
+ && ev.scancode == RawInputEvent.SYN_REPORT)) {
if (mDisplay != null) {
if (!mHaveGlobalMetaState) {
computeGlobalMetaStateLocked();
}
MotionEvent me;
- me = di.mAbs.generateMotion(di, curTime, true,
- mDisplay, mOrientation, mGlobalMetaState);
- if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x
- + " y=" + di.mAbs.y + " ev=" + me);
- if (me != null) {
- if (WindowManagerPolicy.WATCH_POINTER) {
- Log.i(TAG, "Enqueueing: " + me);
+
+ InputDevice.MotionState ms = di.mAbs;
+ if (ms.changed) {
+ ms.changed = false;
+
+ if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
+ |RawInputEvent.CLASS_TOUCHSCREEN_MT))
+ == RawInputEvent.CLASS_TOUCHSCREEN) {
+ ms.mNextNumPointers = 0;
+ if (ms.mDown[0]) {
+ System.arraycopy(di.curTouchVals, 0,
+ ms.mNextData, 0,
+ MotionEvent.NUM_SAMPLE_DATA);
+ ms.mNextNumPointers++;
+ }
+ if (ms.mDown[1]) {
+ System.arraycopy(di.curTouchVals,
+ MotionEvent.NUM_SAMPLE_DATA,
+ ms.mNextData,
+ ms.mNextNumPointers
+ * MotionEvent.NUM_SAMPLE_DATA,
+ MotionEvent.NUM_SAMPLE_DATA);
+ ms.mNextNumPointers++;
+ }
+ }
+
+ boolean doMotion = !monitorVirtualKey(di,
+ ev, curTime, curTimeNano);
+
+ if (doMotion && ms.mNextNumPointers > 0
+ && ms.mLastNumPointers == 0) {
+ doMotion = !generateVirtualKeyDown(di,
+ ev, curTime, curTimeNano);
}
- addLocked(di, curTime, ev.flags,
- RawInputEvent.CLASS_TOUCHSCREEN, me);
+
+ if (doMotion) {
+ // XXX Need to be able to generate
+ // multiple events here, for example
+ // if two fingers change up/down state
+ // at the same time.
+ do {
+ me = ms.generateAbsMotion(di, curTime,
+ curTimeNano, mDisplay,
+ mOrientation, mGlobalMetaState);
+ if (false) Log.v(TAG, "Absolute: x="
+ + di.mAbs.mNextData[MotionEvent.SAMPLE_X]
+ + " y="
+ + di.mAbs.mNextData[MotionEvent.SAMPLE_Y]
+ + " ev=" + me);
+ if (me != null) {
+ if (WindowManagerPolicy.WATCH_POINTER) {
+ Log.i(TAG, "Enqueueing: " + me);
+ }
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_TOUCHSCREEN, me);
+ }
+ } while (ms.hasMore());
+ }
+
+ ms.finish();
}
- me = di.mRel.generateMotion(di, curTime, 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,
- RawInputEvent.CLASS_TRACKBALL, me);
+
+ ms = di.mRel;
+ if (ms.changed) {
+ ms.changed = false;
+
+ me = ms.generateRelMotion(di, curTime,
+ curTimeNano,
+ mOrientation, mGlobalMetaState);
+ if (false) Log.v(TAG, "Relative: x="
+ + di.mRel.mNextData[MotionEvent.SAMPLE_X]
+ + " y="
+ + di.mRel.mNextData[MotionEvent.SAMPLE_Y]
+ + " ev=" + me);
+ if (me != null) {
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_TRACKBALL, me);
+ }
+
+ ms.finish();
}
}
}
}
+
+ } catch (RuntimeException exc) {
+ Log.e(TAG, "InputReaderThread uncaught exception", exc);
}
}
- catch (RuntimeException exc) {
- Log.e(TAG, "InputReaderThread uncaught exception", exc);
- }
}
};
+ private boolean isInsideDisplay(InputDevice dev) {
+ final InputDevice.AbsoluteInfo absx = dev.absX;
+ final InputDevice.AbsoluteInfo absy = dev.absY;
+ final InputDevice.MotionState absm = dev.mAbs;
+ if (absx == null || absy == null || absm == null) {
+ return true;
+ }
+
+ if (absm.mNextData[MotionEvent.SAMPLE_X] >= absx.minValue
+ && absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue
+ && absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue
+ && absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) {
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input ("
+ + absm.mNextData[MotionEvent.SAMPLE_X]
+ + "," + absm.mNextData[MotionEvent.SAMPLE_Y]
+ + ") inside of display");
+ return true;
+ }
+
+ return false;
+ }
+
+ private VirtualKey findVirtualKey(InputDevice dev) {
+ final int N = mVirtualKeys.size();
+ if (N <= 0) {
+ return null;
+ }
+
+ final InputDevice.MotionState absm = dev.mAbs;
+ for (int i=0; i<N; i++) {
+ VirtualKey sb = mVirtualKeys.get(i);
+ sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test ("
+ + absm.mNextData[MotionEvent.SAMPLE_X] + ","
+ + absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code "
+ + sb.scancode + " - (" + sb.hitLeft
+ + "," + sb.hitTop + ")-(" + sb.hitRight + ","
+ + sb.hitBottom + ")");
+ if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X],
+ absm.mNextData[MotionEvent.SAMPLE_Y])) {
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!");
+ return sb;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean generateVirtualKeyDown(InputDevice di, RawInputEvent ev,
+ long curTime, long curTimeNano) {
+ if (isInsideDisplay(di)) {
+ // Didn't consume event.
+ return false;
+ }
+
+
+ VirtualKey vk = findVirtualKey(di);
+ if (vk != null) {
+ final InputDevice.MotionState ms = di.mAbs;
+ mPressedVirtualKey = vk;
+ vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode);
+ ms.mLastNumPointers = ms.mNextNumPointers;
+ di.mKeyDownTime = curTime;
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
+ "Generate key down for: " + vk.scancode
+ + " (keycode=" + vk.lastKeycode + ")");
+ KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true,
+ vk.lastKeycode, 0, vk.scancode,
+ KeyEvent.FLAG_VIRTUAL_HARD_KEY);
+ mHapticFeedbackCallback.virtualKeyFeedback(event);
+ addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
+ event);
+ }
+
+ // We always consume the event, even if we didn't
+ // generate a key event. There are two reasons for
+ // this: to avoid spurious touches when holding
+ // the edges of the device near the touchscreen,
+ // and to avoid reporting events if there are virtual
+ // keys on the touchscreen outside of the display
+ // area.
+ // Note that for all of this we are only looking at the
+ // first pointer, since what we are handling here is the
+ // first pointer going down, and this is the coordinate
+ // that will be used to dispatch the event.
+ if (false) {
+ final InputDevice.AbsoluteInfo absx = di.absX;
+ final InputDevice.AbsoluteInfo absy = di.absY;
+ final InputDevice.MotionState absm = di.mAbs;
+ Log.v(TAG, "Rejecting ("
+ + absm.mNextData[MotionEvent.SAMPLE_X] + ","
+ + absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of ("
+ + absx.minValue + "," + absy.minValue
+ + ")-(" + absx.maxValue + ","
+ + absx.maxValue + ")");
+ }
+ return true;
+ }
+
+ private boolean monitorVirtualKey(InputDevice di, RawInputEvent ev,
+ long curTime, long curTimeNano) {
+ VirtualKey vk = mPressedVirtualKey;
+ if (vk == null) {
+ return false;
+ }
+
+ final InputDevice.MotionState ms = di.mAbs;
+ if (ms.mNextNumPointers <= 0) {
+ mPressedVirtualKey = null;
+ ms.mLastNumPointers = 0;
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Generate key up for: " + vk.scancode);
+ KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
+ vk.lastKeycode, 0, vk.scancode,
+ KeyEvent.FLAG_VIRTUAL_HARD_KEY);
+ mHapticFeedbackCallback.virtualKeyFeedback(event);
+ addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
+ event);
+ return true;
+
+ } else if (isInsideDisplay(di)) {
+ // Whoops the pointer has moved into
+ // the display area! Cancel the
+ // virtual key and start a pointer
+ // motion.
+ mPressedVirtualKey = null;
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Cancel key up for: " + vk.scancode);
+ KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
+ vk.lastKeycode, 0, vk.scancode,
+ KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY);
+ mHapticFeedbackCallback.virtualKeyFeedback(event);
+ addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
+ event);
+ ms.mLastNumPointers = 0;
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Returns a new meta state for the given keys and old state.
*/
@@ -506,8 +969,8 @@ public abstract class KeyInputQueue {
if (ev.event == ev.inputDevice.mRel.currentMove) {
if (false) Log.i(TAG, "Detach rel " + ev.event);
ev.inputDevice.mRel.currentMove = null;
- ev.inputDevice.mRel.x = 0;
- ev.inputDevice.mRel.y = 0;
+ ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0;
+ ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0;
}
recycleLocked(ev);
}
@@ -530,7 +993,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 +1005,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 +1024,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 +1041,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);
+ }
}
}
@@ -593,7 +1063,12 @@ public abstract class KeyInputQueue {
InputDevice.AbsoluteInfo absY;
InputDevice.AbsoluteInfo absPressure;
InputDevice.AbsoluteInfo absSize;
- if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+ if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
+ absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_X, "X");
+ absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_Y, "Y");
+ absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure");
+ absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size");
+ } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_X, "X");
absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_Y, "Y");
absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_PRESSURE, "Pressure");
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 3f268c9..7c33e37 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -49,6 +49,7 @@ import android.location.IGpsStatusProvider;
import android.location.ILocationListener;
import android.location.ILocationManager;
import android.location.ILocationProvider;
+import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
@@ -71,6 +72,7 @@ import android.util.PrintWriterPrinter;
import com.android.internal.location.GpsLocationProvider;
import com.android.internal.location.LocationProviderProxy;
import com.android.internal.location.MockProvider;
+import com.android.internal.location.GpsNetInitiatedHandler;
/**
* The service class that manages LocationProviders and issues location
@@ -118,6 +120,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private final Context mContext;
private IGeocodeProvider mGeocodeProvider;
private IGpsStatusProvider mGpsStatusProvider;
+ private INetInitiatedListener mNetInitiatedListener;
private LocationWorkerHandler mLocationHandler;
// Cache the real providers for use in addTestProvider() and removeTestProvider()
@@ -541,6 +544,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// Create a gps location provider
GpsLocationProvider provider = new GpsLocationProvider(mContext, this);
mGpsStatusProvider = provider.getGpsStatusProvider();
+ mNetInitiatedListener = provider.getNetInitiatedListener();
LocationProviderProxy proxy = new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider);
addProvider(proxy);
mGpsLocationProvider = proxy;
@@ -1108,6 +1112,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
public boolean sendExtraCommand(String provider, String command, Bundle extras) {
+ if (provider == null) {
+ // throw NullPointerException to remain compatible with previous implementation
+ throw new NullPointerException();
+ }
+
// first check for permission to the provider
checkPermissionsSafe(provider);
// and check for ACCESS_LOCATION_EXTRA_COMMANDS
@@ -1118,7 +1127,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (mLock) {
LocationProviderProxy proxy = mProvidersByName.get(provider);
- if (provider == null) {
+ if (proxy == null) {
return false;
}
@@ -1126,6 +1135,22 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
+ public boolean sendNiResponse(int notifId, int userResponse)
+ {
+ if (Binder.getCallingUid() != Process.myUid()) {
+ throw new SecurityException(
+ "calling sendNiResponse from outside of the system is not allowed");
+ }
+ try {
+ return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
+ }
+ catch (RemoteException e)
+ {
+ Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
+ return false;
+ }
+ }
+
class ProximityAlert {
final int mUid;
final double mLatitude;
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/MountService.java b/services/java/com/android/server/MountService.java
index f81c519..3d4bcc5 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -231,6 +231,7 @@ class MountService extends IMountService.Stub {
if (getMassStorageConnected() && !suppressIfConnected) {
Intent intent = new Intent();
intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
setUsbStorageNotification(
com.android.internal.R.string.usb_storage_notification_title,
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index aac7124..d0f6eee 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -35,6 +35,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
@@ -48,6 +49,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Power;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.Vibrator;
@@ -96,7 +98,7 @@ class NotificationManagerService extends INotificationManager.Stub
private Vibrator mVibrator = new Vibrator();
// adb
- private int mBatteryPlugged;
+ private boolean mUsbConnected;
private boolean mAdbEnabled = false;
private boolean mAdbNotificationShown = false;
private Notification mAdbNotification;
@@ -257,7 +259,8 @@ class NotificationManagerService extends INotificationManager.Stub
}
public void onNotificationClick(String pkg, int id) {
- cancelNotification(pkg, id, Notification.FLAG_AUTO_CANCEL);
+ cancelNotification(pkg, id, Notification.FLAG_AUTO_CANCEL,
+ Notification.FLAG_FOREGROUND_SERVICE);
}
public void onPanelRevealed() {
@@ -310,8 +313,11 @@ class NotificationManagerService extends INotificationManager.Stub
mBatteryFull = batteryFull;
updateLights();
}
-
- mBatteryPlugged = intent.getIntExtra("plugged", 0);
+ } else if (action.equals(Intent.ACTION_UMS_CONNECTED)) {
+ mUsbConnected = true;
+ updateAdbNotification();
+ } else if (action.equals(Intent.ACTION_UMS_DISCONNECTED)) {
+ mUsbConnected = false;
updateAdbNotification();
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
@@ -323,7 +329,7 @@ class NotificationManagerService extends INotificationManager.Stub
if (pkgName == null) {
return;
}
- cancelAllNotifications(pkgName);
+ cancelAllNotificationsInt(pkgName, 0, 0);
}
}
};
@@ -380,6 +386,8 @@ class NotificationManagerService extends INotificationManager.Stub
// register for battery changed notifications
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(Intent.ACTION_UMS_CONNECTED);
+ filter.addAction(Intent.ACTION_UMS_DISCONNECTED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
mContext.registerReceiver(mIntentReceiver, filter);
@@ -575,6 +583,8 @@ class NotificationManagerService extends INotificationManager.Stub
// ============================================================================
public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)
{
+ checkIncomingCall(pkg);
+
// This conditional is a dirty hack to limit the logging done on
// behalf of the download manager without affecting other apps.
if (!pkg.equals("com.android.providers.downloads")
@@ -607,7 +617,20 @@ class NotificationManagerService extends INotificationManager.Stub
} else {
old = mNotificationList.remove(index);
mNotificationList.add(index, r);
+ // Make sure we don't lose the foreground service state.
+ if (old != null) {
+ notification.flags |=
+ old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
+ }
+ }
+
+ // Ensure if this is a foreground service that the proper additional
+ // flags are set.
+ if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+ notification.flags |= Notification.FLAG_ONGOING_EVENT
+ | Notification.FLAG_NO_CLEAR;
}
+
if (notification.icon != 0) {
IconData icon = IconData.makeIcon(null, pkg, notification.icon,
notification.iconLevel,
@@ -802,9 +825,11 @@ class NotificationManagerService extends INotificationManager.Stub
}
/**
- * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}.
+ * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
+ * and none of the {@code mustNotHaveFlags}.
*/
- private void cancelNotification(String pkg, int id, int mustHaveFlags) {
+ private void cancelNotification(String pkg, int id, int mustHaveFlags,
+ int mustNotHaveFlags) {
EventLog.writeEvent(EVENT_LOG_CANCEL, pkg, id, mustHaveFlags);
synchronized (mNotificationList) {
@@ -817,6 +842,9 @@ class NotificationManagerService extends INotificationManager.Stub
if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
return;
}
+ if ((r.notification.flags & mustNotHaveFlags) != 0) {
+ return;
+ }
mNotificationList.remove(index);
@@ -830,7 +858,8 @@ class NotificationManagerService extends INotificationManager.Stub
* Cancels all notifications from a given package that have all of the
* {@code mustHaveFlags}.
*/
- private void cancelAllNotificationsInt(String pkg, int mustHaveFlags) {
+ void cancelAllNotificationsInt(String pkg, int mustHaveFlags,
+ int mustNotHaveFlags) {
EventLog.writeEvent(EVENT_LOG_CANCEL_ALL, pkg, mustHaveFlags);
synchronized (mNotificationList) {
@@ -841,6 +870,9 @@ class NotificationManagerService extends INotificationManager.Stub
if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
continue;
}
+ if ((r.notification.flags & mustNotHaveFlags) != 0) {
+ continue;
+ }
if (!r.pkg.equals(pkg)) {
continue;
}
@@ -855,17 +887,40 @@ class NotificationManagerService extends INotificationManager.Stub
}
- public void cancelNotification(String pkg, int id)
- {
- cancelNotification(pkg, id, 0);
+ public void cancelNotification(String pkg, int id) {
+ checkIncomingCall(pkg);
+ // Don't allow client applications to cancel foreground service notis.
+ cancelNotification(pkg, id, 0,
+ Binder.getCallingUid() == Process.SYSTEM_UID
+ ? 0 : Notification.FLAG_FOREGROUND_SERVICE);
}
- public void cancelAllNotifications(String pkg)
- {
- cancelAllNotificationsInt(pkg, 0);
+ public void cancelAllNotifications(String pkg) {
+ checkIncomingCall(pkg);
+
+ // Calling from user space, don't allow the canceling of actively
+ // running foreground services.
+ cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE);
}
- public void cancelAll() {
+ void checkIncomingCall(String pkg) {
+ int uid = Binder.getCallingUid();
+ if (uid == Process.SYSTEM_UID || uid == 0) {
+ return;
+ }
+ try {
+ ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
+ pkg, 0);
+ if (ai.uid != uid) {
+ throw new SecurityException("Calling uid " + uid + " gave package"
+ + pkg + " which is owned by uid " + ai.uid);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new SecurityException("Unknown package " + pkg);
+ }
+ }
+
+ void cancelAll() {
synchronized (mNotificationList) {
final int N = mNotificationList.size();
for (int i=N-1; i>=0; i--) {
@@ -954,7 +1009,7 @@ class NotificationManagerService extends INotificationManager.Stub
// security feature that we don't want people customizing the platform
// to accidentally lose.
private void updateAdbNotification() {
- if (mAdbEnabled && mBatteryPlugged == BatteryManager.BATTERY_PLUGGED_USB) {
+ if (mAdbEnabled && mUsbConnected) {
if ("0".equals(SystemProperties.get("persist.adb.notify"))) {
return;
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 89f854e..8ec6ec3 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -35,6 +35,7 @@ import android.content.IntentSender.SendIntentException;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
+import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
@@ -88,6 +89,7 @@ import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
@@ -221,6 +223,14 @@ class PackageManagerService extends IPackageManager.Stub {
// etc/permissions.xml file.
final HashMap<String, String> mSharedLibraries = new HashMap<String, String>();
+ // Temporary for building the final shared libraries for an .apk.
+ String[] mTmpSharedLibraries = null;
+
+ // These are the features this devices supports that were read from the
+ // etc/permissions.xml file.
+ final HashMap<String, FeatureInfo> mAvailableFeatures =
+ new HashMap<String, FeatureInfo>();
+
// All available activities, for your resolving pleasure.
final ActivityIntentResolver mActivities =
new ActivityIntentResolver();
@@ -671,7 +681,21 @@ class PackageManagerService extends IPackageManager.Stub {
+ parser.getPositionDescription());
} else {
Log.i(TAG, "Got library " + lname + " in " + lfile);
- this.mSharedLibraries.put(lname, lfile);
+ mSharedLibraries.put(lname, lfile);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+
+ } else if ("feature".equals(name)) {
+ String fname = parser.getAttributeValue(null, "name");
+ if (fname == null) {
+ Log.w(TAG, "<feature> without name at "
+ + parser.getPositionDescription());
+ } else {
+ Log.i(TAG, "Got feature " + fname);
+ FeatureInfo fi = new FeatureInfo();
+ fi.name = fname;
+ mAvailableFeatures.put(fname, fi);
}
XmlUtils.skipCurrentTag(parser);
continue;
@@ -1001,12 +1025,30 @@ class PackageManagerService extends IPackageManager.Stub {
Set<String> libSet;
synchronized (mPackages) {
libSet = mSharedLibraries.keySet();
+ int size = libSet.size();
+ if (size > 0) {
+ String[] libs = new String[size];
+ libSet.toArray(libs);
+ return libs;
+ }
}
- int size = libSet.size();
- if (size > 0) {
- String[] libs = new String[size];
- libSet.toArray(libs);
- return libs;
+ return null;
+ }
+
+ public FeatureInfo[] getSystemAvailableFeatures() {
+ Collection<FeatureInfo> featSet;
+ synchronized (mPackages) {
+ featSet = mAvailableFeatures.values();
+ int size = featSet.size();
+ if (size > 0) {
+ FeatureInfo[] features = new FeatureInfo[size+1];
+ featSet.toArray(features);
+ FeatureInfo fi = new FeatureInfo();
+ fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
+ FeatureInfo.GL_ES_VERSION_UNDEFINED);
+ features[size] = fi;
+ return features;
+ }
}
return null;
}
@@ -1138,25 +1180,57 @@ class PackageManagerService extends IPackageManager.Stub {
|| p2 == null || p2.mExtras == null) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return checkSignaturesLP(p1, p2);
+ return checkSignaturesLP(p1.mSignatures, p2.mSignatures);
}
}
- int checkSignaturesLP(PackageParser.Package p1, PackageParser.Package p2) {
- if (p1.mSignatures == null) {
- return p2.mSignatures == null
+ public int checkUidSignatures(int uid1, int uid2) {
+ synchronized (mPackages) {
+ Signature[] s1;
+ Signature[] s2;
+ Object obj = mSettings.getUserIdLP(uid1);
+ if (obj != null) {
+ if (obj instanceof SharedUserSetting) {
+ s1 = ((SharedUserSetting)obj).signatures.mSignatures;
+ } else if (obj instanceof PackageSetting) {
+ s1 = ((PackageSetting)obj).signatures.mSignatures;
+ } else {
+ return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
+ }
+ } else {
+ return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
+ }
+ obj = mSettings.getUserIdLP(uid2);
+ if (obj != null) {
+ if (obj instanceof SharedUserSetting) {
+ s2 = ((SharedUserSetting)obj).signatures.mSignatures;
+ } else if (obj instanceof PackageSetting) {
+ s2 = ((PackageSetting)obj).signatures.mSignatures;
+ } else {
+ return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
+ }
+ } else {
+ return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
+ }
+ return checkSignaturesLP(s1, s2);
+ }
+ }
+
+ int checkSignaturesLP(Signature[] s1, Signature[] s2) {
+ if (s1 == null) {
+ return s2 == null
? PackageManager.SIGNATURE_NEITHER_SIGNED
: PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
}
- if (p2.mSignatures == null) {
+ if (s2 == null) {
return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
}
- final int N1 = p1.mSignatures.length;
- final int N2 = p2.mSignatures.length;
+ final int N1 = s1.length;
+ final int N2 = s2.length;
for (int i=0; i<N1; i++) {
boolean match = false;
for (int j=0; j<N2; j++) {
- if (p1.mSignatures[i].equals(p2.mSignatures[j])) {
+ if (s1[i].equals(s2[j])) {
match = true;
break;
}
@@ -1677,6 +1751,9 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ /**
+ * @deprecated
+ */
public void querySyncProviders(List outNames, List outInfo) {
synchronized (mPackages) {
Iterator<Map.Entry<String, PackageParser.Provider>> i
@@ -2030,17 +2107,62 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
// Check all shared libraries and map to their actual file path.
- if (pkg.usesLibraryFiles != null) {
- for (int i=0; i<pkg.usesLibraryFiles.length; i++) {
- String file = mSharedLibraries.get(pkg.usesLibraryFiles[i]);
+ if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
+ if (mTmpSharedLibraries == null ||
+ mTmpSharedLibraries.length < mSharedLibraries.size()) {
+ mTmpSharedLibraries = new String[mSharedLibraries.size()];
+ }
+ int num = 0;
+ int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
+ for (int i=0; i<N; i++) {
+ String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
if (file == null) {
Log.e(TAG, "Package " + pkg.packageName
+ " requires unavailable shared library "
- + pkg.usesLibraryFiles[i] + "; ignoring!");
+ + pkg.usesLibraries.get(i) + "; failing!");
mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
return null;
}
- pkg.usesLibraryFiles[i] = file;
+ mTmpSharedLibraries[num] = file;
+ num++;
+ }
+ N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
+ for (int i=0; i<N; i++) {
+ String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
+ if (file == null) {
+ Log.w(TAG, "Package " + pkg.packageName
+ + " desires unavailable shared library "
+ + pkg.usesOptionalLibraries.get(i) + "; ignoring!");
+ } else {
+ mTmpSharedLibraries[num] = file;
+ num++;
+ }
+ }
+ if (num > 0) {
+ pkg.usesLibraryFiles = new String[num];
+ System.arraycopy(mTmpSharedLibraries, 0,
+ pkg.usesLibraryFiles, 0, num);
+ }
+
+ if (pkg.reqFeatures != null) {
+ N = pkg.reqFeatures.size();
+ for (int i=0; i<N; i++) {
+ FeatureInfo fi = pkg.reqFeatures.get(i);
+ if ((fi.flags&FeatureInfo.FLAG_REQUIRED) == 0) {
+ // Don't care.
+ continue;
+ }
+
+ if (fi.name != null) {
+ if (mAvailableFeatures.get(fi.name) == null) {
+ Log.e(TAG, "Package " + pkg.packageName
+ + " requires unavailable feature "
+ + fi.name + "; failing!");
+ mLastScanError = PackageManager.INSTALL_FAILED_MISSING_FEATURE;
+ return null;
+ }
+ }
+ }
}
}
@@ -2904,9 +3026,9 @@ class PackageManagerService extends IPackageManager.Stub {
allowed = true;
} else if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE
|| p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
- allowed = (checkSignaturesLP(p.owner, pkg)
+ allowed = (checkSignaturesLP(p.owner.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
- || (checkSignaturesLP(mPlatformPackage, pkg)
+ || (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
@@ -3553,7 +3675,8 @@ class PackageManagerService extends IPackageManager.Stub {
// First find the old package info and check signatures
synchronized(mPackages) {
oldPackage = mPackages.get(pkgName);
- if(checkSignaturesLP(pkg, oldPackage) != PackageManager.SIGNATURE_MATCH) {
+ if(checkSignaturesLP(pkg.mSignatures, oldPackage.mSignatures)
+ != PackageManager.SIGNATURE_MATCH) {
res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return;
}
@@ -5029,6 +5152,15 @@ class PackageManagerService extends IPackageManager.Stub {
pw.println("Settings parse messages:");
pw.println(mSettings.mReadMessages.toString());
}
+
+ synchronized (mProviders) {
+ pw.println(" ");
+ pw.println("Registered ContentProviders:");
+ for (PackageParser.Provider p : mProviders.values()) {
+ pw.println(" ["); pw.println(p.info.authority); pw.println("]: ");
+ pw.println(p.toString());
+ }
+ }
}
static final class BasePermission {
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 79d78ad..38df47b 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -29,6 +29,10 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.Cursor;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
@@ -58,7 +62,8 @@ import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;
-class PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor {
+class PowerManagerService extends IPowerManager.Stub
+ implements LocalPowerManager,Watchdog.Monitor, SensorEventListener {
private static final String TAG = "PowerManagerService";
static final String PARTIAL_NAME = "PowerManagerService";
@@ -72,7 +77,8 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK
| PowerManager.SCREEN_DIM_WAKE_LOCK
| PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.FULL_WAKE_LOCK;
+ | PowerManager.FULL_WAKE_LOCK
+ | PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
// time since last state: time since last event:
// The short keylight delay comes from Gservices; this is the default.
@@ -138,11 +144,13 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
private int[] mBroadcastQueue = new int[] { -1, -1, -1 };
private int[] mBroadcastWhy = new int[3];
private int mPartialCount = 0;
+ private int mProximityCount = 0;
private int mPowerState;
private boolean mOffBecauseOfUser;
private int mUserState;
private boolean mKeyboardVisible = false;
private boolean mUserActivityAllowed = true;
+ private boolean mProximitySensorActive = false;
private int mTotalDelaySetting;
private int mKeylightDelay;
private int mDimDelay;
@@ -175,6 +183,8 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
private IActivityManager mActivityService;
private IBatteryStats mBatteryStats;
private BatteryService mBatteryService;
+ private SensorManager mSensorManager;
+ private Sensor mProximitySensor;
private boolean mDimScreen = true;
private long mNextTimeout;
private volatile int mPokey = 0;
@@ -536,6 +546,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
wl.minState = SCREEN_DIM;
break;
case PowerManager.PARTIAL_WAKE_LOCK:
+ case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
break;
default:
// just log and bail. we're in the server, so don't
@@ -583,6 +594,11 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
}
Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
+ } else if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+ mProximityCount++;
+ if (mProximityCount == 1) {
+ enableProximityLockLocked();
+ }
}
if (newlock) {
acquireUid = wl.uid;
@@ -639,6 +655,11 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
Power.releaseWakeLock(PARTIAL_NAME);
}
+ } else if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
+ mProximityCount--;
+ if (mProximityCount == 0) {
+ disableProximityLockLocked();
+ }
}
// Unlink the lock from the binder.
wl.binder.unlinkToDeath(wl, 0);
@@ -745,15 +766,17 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
switch (type)
{
case PowerManager.FULL_WAKE_LOCK:
- return "FULL_WAKE_LOCK ";
+ return "FULL_WAKE_LOCK ";
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- return "SCREEN_BRIGHT_WAKE_LOCK";
+ return "SCREEN_BRIGHT_WAKE_LOCK ";
case PowerManager.SCREEN_DIM_WAKE_LOCK:
- return "SCREEN_DIM_WAKE_LOCK ";
+ return "SCREEN_DIM_WAKE_LOCK ";
case PowerManager.PARTIAL_WAKE_LOCK:
- return "PARTIAL_WAKE_LOCK ";
+ return "PARTIAL_WAKE_LOCK ";
+ case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+ return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
default:
- return "??? ";
+ return "??? ";
}
}
@@ -926,6 +949,9 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
private void sendNotificationLocked(boolean on, int why)
{
+ if (mProximitySensorActive) {
+ why = WindowManagerPolicy.OFF_BECAUSE_OF_PROXIMITY_SENSOR;
+ }
if (!on) {
mStillNeedSleepNotification = false;
}
@@ -1230,6 +1256,10 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
if (noChangeLights) {
newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK);
}
+ if (mProximitySensorActive) {
+ // don't turn on the screen when the proximity sensor lock is held
+ newState = (newState & ~SCREEN_BRIGHT);
+ }
if (batteryIsLow()) {
newState |= BATTERY_LOW_BIT;
@@ -1726,11 +1756,13 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
Log.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time
+ " mUserActivityAllowed=" + mUserActivityAllowed
+ " mUserState=0x" + Integer.toHexString(mUserState)
- + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
+ + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)
+ + " mProximitySensorActive=" + mProximitySensorActive
+ + " force=" + force);
}
if (mLastEventTime <= time || force) {
mLastEventTime = time;
- if (mUserActivityAllowed || force) {
+ if ((mUserActivityAllowed && !mProximitySensorActive) || force) {
// Only turn on button backlights if a button was pressed.
if (eventType == BUTTON_EVENT) {
mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
@@ -1996,4 +2028,70 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
public void monitor() {
synchronized (mLocks) { }
}
+
+ public int getSupportedWakeLockFlags() {
+ int result = PowerManager.PARTIAL_WAKE_LOCK
+ | PowerManager.FULL_WAKE_LOCK
+ | PowerManager.SCREEN_DIM_WAKE_LOCK;
+
+ // call getSensorManager() to make sure mProximitySensor is initialized
+ getSensorManager();
+ if (mProximitySensor != null) {
+ result |= PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
+ }
+
+ return result;
+ }
+
+ private SensorManager getSensorManager() {
+ if (mSensorManager == null) {
+ mSensorManager = new SensorManager(mHandlerThread.getLooper());
+ mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ }
+ return mSensorManager;
+ }
+
+ private void enableProximityLockLocked() {
+ if (mSpew) {
+ Log.d(TAG, "enableProximityLockLocked");
+ }
+ mSensorManager.registerListener(this, mProximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ private void disableProximityLockLocked() {
+ if (mSpew) {
+ Log.d(TAG, "disableProximityLockLocked");
+ }
+ mSensorManager.unregisterListener(this);
+ mProximitySensorActive = false;
+ }
+
+ public void onSensorChanged(SensorEvent event) {
+ long milliseconds = event.timestamp / 1000000;
+ synchronized (mLocks) {
+ if (event.values[0] == 0.0) {
+ if (mSpew) {
+ Log.d(TAG, "onSensorChanged: proximity active");
+ }
+ goToSleepLocked(milliseconds);
+ mProximitySensorActive = true;
+ } else {
+ // proximity sensor negative events user activity.
+ // temporarily set mUserActivityAllowed to true so this will work
+ // even when the keyguard is on.
+ if (mSpew) {
+ Log.d(TAG, "onSensorChanged: proximity inactive");
+ }
+ mProximitySensorActive = false;
+ boolean savedActivityAllowed = mUserActivityAllowed;
+ mUserActivityAllowed = true;
+ userActivity(milliseconds, false);
+ mUserActivityAllowed = savedActivityAllowed;
+ }
+ }
+ }
+
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // ignore
+ }
}
diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java
index ceef39f..4dfeb9d 100644
--- a/services/java/com/android/server/SensorService.java
+++ b/services/java/com/android/server/SensorService.java
@@ -84,12 +84,16 @@ class SensorService extends ISensorService.Stub {
if (hasSensor(sensor)) {
removeSensor(sensor);
try {
- deactivateIfUnused(sensor);
+ deactivateIfUnusedLocked(sensor);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException in binderDied");
}
}
}
+ if (mListeners.size() == 0) {
+ _sensors_control_wake();
+ _sensors_control_close();
+ }
mListeners.notify();
}
}
@@ -102,9 +106,12 @@ class SensorService extends ISensorService.Stub {
}
public Bundle getDataChannel() throws RemoteException {
- return _sensors_control_open();
+ // synchronize so we do not require sensor HAL to be thread-safe.
+ synchronized(mListeners) {
+ return _sensors_control_open();
+ }
}
-
+
public boolean enableSensor(IBinder binder, String name, int sensor, int enable)
throws RemoteException {
if (localLOGV) Log.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable);
@@ -163,7 +170,7 @@ class SensorService extends ISensorService.Stub {
l.addSensor(sensor, enable);
} else {
l.removeSensor(sensor);
- deactivateIfUnused(sensor);
+ deactivateIfUnusedLocked(sensor);
if (l.mSensors == 0) {
mListeners.remove(l);
binder.unlinkToDeath(l, 0);
@@ -173,12 +180,13 @@ class SensorService extends ISensorService.Stub {
if (mListeners.size() == 0) {
_sensors_control_wake();
+ _sensors_control_close();
}
}
return true;
}
- void deactivateIfUnused(int sensor) throws RemoteException {
+ private void deactivateIfUnusedLocked(int sensor) throws RemoteException {
int size = mListeners.size();
for (int i=0 ; i<size ; i++) {
if (mListeners.get(i).hasSensor(sensor))
@@ -187,10 +195,11 @@ class SensorService extends ISensorService.Stub {
_sensors_control_activate(sensor, false);
}
- ArrayList<Listener> mListeners = new ArrayList<Listener>();
+ private ArrayList<Listener> mListeners = new ArrayList<Listener>();
private static native int _sensors_control_init();
private static native Bundle _sensors_control_open();
+ private static native int _sensors_control_close();
private static native boolean _sensors_control_activate(int sensor, boolean activate);
private static native int _sensors_control_set_delay(int ms);
private static native int _sensors_control_wake();
diff --git a/services/java/com/android/server/ShutdownActivity.java b/services/java/com/android/server/ShutdownActivity.java
new file mode 100644
index 0000000..7f0e90d
--- /dev/null
+++ b/services/java/com/android/server/ShutdownActivity.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 com.android.server;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import com.android.internal.app.ShutdownThread;
+
+public class ShutdownActivity extends Activity {
+
+ private static final String TAG = "ShutdownActivity";
+ private boolean mConfirm;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mConfirm = getIntent().getBooleanExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ Log.i(TAG, "onCreate(): confirm=" + mConfirm);
+
+ Handler h = new Handler();
+ h.post(new Runnable() {
+ public void run() {
+ ShutdownThread.shutdown(ShutdownActivity.this, mConfirm);
+ }
+ });
+ }
+}
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
new file mode 100644
index 0000000..17d0f1d
--- /dev/null
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -0,0 +1,67 @@
+/*
+ * 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.server;
+
+import android.backup.AbsoluteFileBackupHelper;
+import android.backup.BackupDataInput;
+import android.backup.BackupDataInputStream;
+import android.backup.BackupDataOutput;
+import android.backup.BackupHelper;
+import android.backup.BackupHelperAgent;
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.os.ServiceManager;
+import android.os.SystemService;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Backup agent for various system-managed data
+ */
+public class SystemBackupAgent extends BackupHelperAgent {
+ private static final String TAG = "SystemBackupAgent";
+
+ private static final String WALLPAPER_IMAGE = "/data/data/com.android.settings/files/wallpaper";
+ private static final String WALLPAPER_INFO = "/data/system/wallpaper_info.xml";
+
+ @Override
+ public void onCreate() {
+ addHelper("wallpaper", new AbsoluteFileBackupHelper(SystemBackupAgent.this,
+ new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }));
+ }
+
+ @Override
+ public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+ throws IOException {
+ boolean success = false;
+ try {
+ super.onRestore(data, appVersionCode, newState);
+
+ WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+ Context.WALLPAPER_SERVICE);
+ wallpaper.settingsRestored();
+ } catch (IOException ex) {
+ // If there was a failure, delete everything for the wallpaper, this is too aggresive,
+ // but this is hopefully a rare failure.
+ Log.d(TAG, "restore failed", ex);
+ (new File(WALLPAPER_IMAGE)).delete();
+ (new File(WALLPAPER_INFO)).delete();
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b2848ac..df01c61 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -31,23 +31,19 @@ import android.content.pm.IPackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.media.AudioService;
-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;
-import android.server.BluetoothDeviceService;
+import android.server.BluetoothService;
import android.server.search.SearchManagerService;
import android.util.EventLog;
import android.util.Log;
+import android.accounts.AccountManagerService;
class ServerThread extends Thread {
private static final String TAG = "SystemServer";
private final static boolean INCLUDE_DEMO = false;
- private final static boolean INCLUDE_BACKUP = false;
private static final int LOG_BOOT_PROGRESS_SYSTEM_RUN = 3010;
@@ -84,12 +80,15 @@ class ServerThread extends Thread {
HardwareService hardware = null;
PowerManagerService power = null;
+ BatteryService battery = null;
+ ConnectivityService connectivity = null;
IPackageManager pm = null;
Context context = null;
WindowManagerService wm = null;
- BluetoothDeviceService bluetooth = null;
+ BluetoothService bluetooth = null;
BluetoothA2dpService bluetoothA2dp = null;
HeadsetObserver headset = null;
+ DockObserver dock = null;
// Critical services...
try {
@@ -116,6 +115,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);
@@ -124,7 +131,7 @@ class ServerThread extends Thread {
ActivityManagerService.installSystemProviders();
Log.i(TAG, "Starting Battery Service.");
- BatteryService battery = new BatteryService(context);
+ battery = new BatteryService(context);
ServiceManager.addService("battery", battery);
Log.i(TAG, "Starting Hardware Service.");
@@ -165,10 +172,10 @@ class ServerThread extends Thread {
ServiceManager.addService(Context.BLUETOOTH_SERVICE, null);
} else {
Log.i(TAG, "Starting Bluetooth Service.");
- bluetooth = new BluetoothDeviceService(context);
- bluetooth.init();
+ bluetooth = new BluetoothService(context);
ServiceManager.addService(Context.BLUETOOTH_SERVICE, bluetooth);
- bluetoothA2dp = new BluetoothA2dpService(context);
+ bluetooth.initAfterRegistration();
+ bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
bluetoothA2dp);
@@ -187,6 +194,7 @@ class ServerThread extends Thread {
InputMethodManagerService imm = null;
AppWidgetService appWidget = null;
NotificationManagerService notification = null;
+ WallpaperManagerService wallpaper = null;
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
@@ -221,8 +229,8 @@ class ServerThread extends Thread {
try {
Log.i(TAG, "Starting Connectivity Service.");
- ServiceManager.addService(Context.CONNECTIVITY_SERVICE,
- ConnectivityService.getInstance(context));
+ connectivity = ConnectivityService.getInstance(context);
+ ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
} catch (Throwable e) {
Log.e(TAG, "Failure starting Connectivity Service", e);
}
@@ -293,7 +301,8 @@ class ServerThread extends Thread {
try {
Log.i(TAG, "Starting Wallpaper Service");
- ServiceManager.addService(Context.WALLPAPER_SERVICE, new WallpaperService(context));
+ wallpaper = new WallpaperManagerService(context);
+ ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
} catch (Throwable e) {
Log.e(TAG, "Failure starting Wallpaper Service", e);
}
@@ -314,10 +323,16 @@ class ServerThread extends Thread {
}
try {
- if (INCLUDE_BACKUP) {
- Log.i(TAG, "Starting Backup Service");
- ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context));
- }
+ Log.i(TAG, "Starting DockObserver");
+ // Listen for dock station changes
+ dock = new DockObserver(context);
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting DockObserver", e);
+ }
+
+ try {
+ Log.i(TAG, "Starting Backup Service");
+ ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context));
} catch (Throwable e) {
Log.e(TAG, "Failure starting Backup Service", e);
}
@@ -374,6 +389,10 @@ class ServerThread extends Thread {
} catch (RemoteException e) {
}
+ if (wallpaper != null) wallpaper.systemReady();
+ if (battery != null) battery.systemReady();
+ if (connectivity != null) connectivity.systemReady();
+ if (dock != null) dock.systemReady();
Watchdog.getInstance().start();
Looper.loop();
@@ -417,19 +436,19 @@ public class SystemServer
public static final int FACTORY_TEST_OFF = 0;
public static final int FACTORY_TEST_LOW_LEVEL = 1;
public static final int FACTORY_TEST_HIGH_LEVEL = 2;
-
- /**
- * This method is called from Zygote to initialize the system. This will cause the native
+
+ /**
+ * This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
* up into init2() to start the Android services.
- */
+ */
native public static void init1(String[] args);
public static void main(String[] args) {
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
-
+
System.loadLibrary("android_servers");
init1(args);
}
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 9f2856c..170a9f8 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -88,6 +88,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private String mDataConnectionApn = "";
+ private String[] mDataConnectionApnTypes = null;
+
private String mDataConnectionInterfaceName = "";
private Bundle mCellLocation = new Bundle();
@@ -337,7 +339,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
- String reason, String apn, String interfaceName) {
+ String reason, String apn, String[] apnTypes, String interfaceName) {
if (!checkNotifyPermission("notifyDataConnection()" )) {
return;
}
@@ -346,6 +348,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mDataConnectionPossible = isDataConnectivityPossible;
mDataConnectionReason = reason;
mDataConnectionApn = apn;
+ mDataConnectionApnTypes = apnTypes;
mDataConnectionInterfaceName = interfaceName;
for (int i = mRecords.size() - 1; i >= 0; i--) {
Record r = mRecords.get(i);
@@ -359,7 +362,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
- interfaceName);
+ apnTypes, interfaceName);
}
public void notifyDataConnectionFailed(String reason) {
@@ -517,8 +520,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE);
}
- private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible,
- String reason, String apn, String interfaceName) {
+ private void broadcastDataConnectionStateChanged(int state,
+ boolean isDataConnectivityPossible,
+ String reason, String apn, String[] apnTypes, String interfaceName) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
@@ -531,6 +535,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason);
}
intent.putExtra(Phone.DATA_APN_KEY, apn);
+ String types = new String("");
+ if (apnTypes.length > 0) {
+ types = apnTypes[0];
+ for (int i = 1; i < apnTypes.length; i++) {
+ types = types+","+apnTypes[i];
+ }
+ }
+ intent.putExtra(Phone.DATA_APN_TYPES_KEY, types);
intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName);
mContext.sendStickyBroadcast(intent);
}
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
new file mode 100644
index 0000000..c101463
--- /dev/null
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -0,0 +1,637 @@
+/*
+ * 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.server;
+
+import static android.os.FileObserver.*;
+import static android.os.ParcelFileDescriptor.*;
+
+import android.app.IWallpaperManager;
+import android.app.IWallpaperManagerCallback;
+import android.backup.BackupManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.FileObserver;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallbackList;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.service.wallpaper.IWallpaperConnection;
+import android.service.wallpaper.IWallpaperEngine;
+import android.service.wallpaper.IWallpaperService;
+import android.service.wallpaper.WallpaperService;
+import android.util.Log;
+import android.util.Xml;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import com.android.internal.service.wallpaper.ImageWallpaper;
+import com.android.internal.util.FastXmlSerializer;
+
+class WallpaperManagerService extends IWallpaperManager.Stub {
+ static final String TAG = "WallpaperService";
+ static final boolean DEBUG = false;
+
+ Object mLock = new Object();
+
+ /**
+ * Minimum time between crashes of a wallpaper service for us to consider
+ * restarting it vs. just reverting to the static wallpaper.
+ */
+ static final long MIN_WALLPAPER_CRASH_TIME = 10000;
+
+ static final File WALLPAPER_DIR = new File(
+ "/data/data/com.android.settings/files");
+ static final String WALLPAPER = "wallpaper";
+ static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER);
+
+ /**
+ * List of callbacks registered they should each be notified
+ * when the wallpaper is changed.
+ */
+ private final RemoteCallbackList<IWallpaperManagerCallback> mCallbacks
+ = new RemoteCallbackList<IWallpaperManagerCallback>();
+
+ /**
+ * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
+ * that the wallpaper has changed. The CREATE is triggered when there is no
+ * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
+ * everytime the wallpaper is changed.
+ */
+ private final FileObserver mWallpaperObserver = new FileObserver(
+ WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE | DELETE | DELETE_SELF) {
+ @Override
+ public void onEvent(int event, String path) {
+ if (path == null) {
+ return;
+ }
+ synchronized (mLock) {
+ // changing the wallpaper means we'll need to back up the new one
+ long origId = Binder.clearCallingIdentity();
+ BackupManager bm = new BackupManager(mContext);
+ bm.dataChanged();
+ Binder.restoreCallingIdentity(origId);
+
+ File changedFile = new File(WALLPAPER_DIR, path);
+ if (WALLPAPER_FILE.equals(changedFile)) {
+ notifyCallbacksLocked();
+ }
+ }
+ }
+ };
+
+ final Context mContext;
+ final IWindowManager mIWindowManager;
+
+ int mWidth = -1;
+ int mHeight = -1;
+ String mName = "";
+ ComponentName mWallpaperComponent;
+ WallpaperConnection mWallpaperConnection;
+ long mLastDiedTime;
+
+ class WallpaperConnection extends IWallpaperConnection.Stub
+ implements ServiceConnection {
+ final Binder mToken = new Binder();
+ IWallpaperService mService;
+ IWallpaperEngine mEngine;
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ if (mWallpaperConnection == this) {
+ mService = IWallpaperService.Stub.asInterface(service);
+ attachServiceLocked(this);
+ }
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized (mLock) {
+ mService = null;
+ mEngine = null;
+ if (mWallpaperConnection == this) {
+ Log.w(TAG, "Wallpaper service gone: " + mWallpaperComponent);
+ if ((mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
+ < SystemClock.uptimeMillis()) {
+ Log.w(TAG, "Reverting to built-in wallpaper!");
+ bindWallpaperComponentLocked(null);
+ }
+ }
+ }
+ }
+
+ public void attachEngine(IWallpaperEngine engine) {
+ mEngine = engine;
+ }
+
+ public ParcelFileDescriptor setWallpaper(String name) {
+ synchronized (mLock) {
+ if (mWallpaperConnection == this) {
+ ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
+ if (pfd != null) {
+ saveSettingsLocked();
+ }
+ return pfd;
+ }
+ return null;
+ }
+ }
+ }
+
+ public WallpaperManagerService(Context context) {
+ if (DEBUG) Log.d(TAG, "WallpaperService startup");
+ mContext = context;
+ mIWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ WALLPAPER_DIR.mkdirs();
+ loadSettingsLocked();
+ mWallpaperObserver.startWatching();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ mWallpaperObserver.stopWatching();
+ }
+
+ public void systemReady() {
+ synchronized (mLock) {
+ try {
+ bindWallpaperComponentLocked(mWallpaperComponent);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failure starting previous wallpaper", e);
+ try {
+ bindWallpaperComponentLocked(null);
+ } catch (RuntimeException e2) {
+ Log.w(TAG, "Failure starting default wallpaper", e2);
+ clearWallpaperComponentLocked();
+ }
+ }
+ }
+ }
+
+ public void clearWallpaper() {
+ synchronized (mLock) {
+ File f = WALLPAPER_FILE;
+ if (f.exists()) {
+ f.delete();
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ bindWallpaperComponentLocked(null);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public void setDimensionHints(int width, int height) throws RemoteException {
+ checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException("width and height must be > 0");
+ }
+
+ synchronized (mLock) {
+ if (width != mWidth || height != mHeight) {
+ mWidth = width;
+ mHeight = height;
+ saveSettingsLocked();
+ if (mWallpaperConnection != null) {
+ if (mWallpaperConnection.mEngine != null) {
+ try {
+ mWallpaperConnection.mEngine.setDesiredSize(
+ width, height);
+ } catch (RemoteException e) {
+ }
+ notifyCallbacksLocked();
+ }
+ }
+ }
+ }
+ }
+
+ public int getWidthHint() throws RemoteException {
+ synchronized (mLock) {
+ return mWidth;
+ }
+ }
+
+ public int getHeightHint() throws RemoteException {
+ synchronized (mLock) {
+ return mHeight;
+ }
+ }
+
+ public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
+ Bundle outParams) {
+ synchronized (mLock) {
+ try {
+ if (outParams != null) {
+ outParams.putInt("width", mWidth);
+ outParams.putInt("height", mHeight);
+ }
+ mCallbacks.register(cb);
+ File f = WALLPAPER_FILE;
+ if (!f.exists()) {
+ return null;
+ }
+ return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ /* Shouldn't happen as we check to see if the file exists */
+ Log.w(TAG, "Error getting wallpaper", e);
+ }
+ return null;
+ }
+ }
+
+ public ParcelFileDescriptor setWallpaper(String name) {
+ checkPermission(android.Manifest.permission.SET_WALLPAPER);
+ synchronized (mLock) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
+ if (pfd != null) {
+ bindWallpaperComponentLocked(null);
+ saveSettingsLocked();
+ }
+ return pfd;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ ParcelFileDescriptor updateWallpaperBitmapLocked(String name) {
+ if (name == null) name = "";
+ try {
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
+ MODE_CREATE|MODE_READ_WRITE);
+ mName = name;
+ return fd;
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Error setting wallpaper", e);
+ }
+ return null;
+ }
+
+ public void setWallpaperComponent(ComponentName name) {
+ checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
+ synchronized (mLock) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ bindWallpaperComponentLocked(name);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ void bindWallpaperComponentLocked(ComponentName name) {
+ // Has the component changed?
+ if (mWallpaperConnection != null) {
+ if (mWallpaperComponent == null) {
+ if (name == null) {
+ // Still using default wallpaper.
+ return;
+ }
+ } else if (mWallpaperComponent.equals(name)) {
+ // Changing to same wallpaper.
+ return;
+ }
+ }
+
+ try {
+ ComponentName realName = name;
+ if (realName == null) {
+ // The default component is our static image wallpaper.
+ realName = new ComponentName("android",
+ ImageWallpaper.class.getName());
+ //clearWallpaperComponentLocked();
+ //return;
+ }
+ ServiceInfo si = mContext.getPackageManager().getServiceInfo(realName,
+ PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS);
+ if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
+ throw new SecurityException("Selected service does not require "
+ + android.Manifest.permission.BIND_WALLPAPER
+ + ": " + realName);
+ }
+
+ Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
+ if (name != null) {
+ // Make sure the selected service is actually a wallpaper service.
+ List<ResolveInfo> ris = mContext.getPackageManager()
+ .queryIntentServices(intent, 0);
+ for (int i=0; i<ris.size(); i++) {
+ ServiceInfo rsi = ris.get(i).serviceInfo;
+ if (rsi.name.equals(si.name) &&
+ rsi.packageName.equals(si.packageName)) {
+ ris = null;
+ break;
+ }
+ }
+ if (ris != null) {
+ throw new SecurityException("Selected service is not a wallpaper: "
+ + realName);
+ }
+ }
+
+ // Bind the service!
+ WallpaperConnection newConn = new WallpaperConnection();
+ intent.setComponent(realName);
+ if (!mContext.bindService(intent, newConn,
+ Context.BIND_AUTO_CREATE)) {
+ throw new IllegalArgumentException("Unable to bind service: "
+ + name);
+ }
+
+ clearWallpaperComponentLocked();
+ mWallpaperComponent = name;
+ mWallpaperConnection = newConn;
+ mLastDiedTime = SystemClock.uptimeMillis();
+ try {
+ if (DEBUG) Log.v(TAG, "Adding window token: " + newConn.mToken);
+ mIWindowManager.addWindowToken(newConn.mToken,
+ WindowManager.LayoutParams.TYPE_WALLPAPER);
+ } catch (RemoteException e) {
+ }
+
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown component " + name);
+ }
+ }
+
+ void clearWallpaperComponentLocked() {
+ mWallpaperComponent = null;
+ if (mWallpaperConnection != null) {
+ if (mWallpaperConnection.mEngine != null) {
+ try {
+ mWallpaperConnection.mEngine.destroy();
+ } catch (RemoteException e) {
+ }
+ }
+ mContext.unbindService(mWallpaperConnection);
+ try {
+ if (DEBUG) Log.v(TAG, "Removing window token: "
+ + mWallpaperConnection.mToken);
+ mIWindowManager.removeWindowToken(mWallpaperConnection.mToken);
+ } catch (RemoteException e) {
+ }
+ mWallpaperConnection = null;
+ }
+ }
+
+ void attachServiceLocked(WallpaperConnection conn) {
+ try {
+ conn.mService.attach(conn, conn.mToken,
+ WindowManager.LayoutParams.TYPE_WALLPAPER, false,
+ mWidth, mHeight);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed attaching wallpaper; clearing", e);
+ bindWallpaperComponentLocked(null);
+ }
+ }
+
+ private void notifyCallbacksLocked() {
+ final int n = mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mCallbacks.getBroadcastItem(i).onWallpaperChanged();
+ } catch (RemoteException e) {
+
+ // The RemoteCallbackList will take care of removing
+ // the dead object for us.
+ }
+ }
+ mCallbacks.finishBroadcast();
+ final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
+ mContext.sendBroadcast(intent);
+ }
+
+ private void checkPermission(String permission) {
+ if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
+ throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+ + ", must have permission " + permission);
+ }
+ }
+
+ private static JournaledFile makeJournaledFile() {
+ final String base = "/data/system/wallpaper_info.xml";
+ return new JournaledFile(new File(base), new File(base + ".tmp"));
+ }
+
+ private void saveSettingsLocked() {
+ JournaledFile journal = makeJournaledFile();
+ FileOutputStream stream = null;
+ try {
+ stream = new FileOutputStream(journal.chooseForWrite(), false);
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, "utf-8");
+ out.startDocument(null, true);
+
+ out.startTag(null, "wp");
+ out.attribute(null, "width", Integer.toString(mWidth));
+ out.attribute(null, "height", Integer.toString(mHeight));
+ out.attribute(null, "name", mName);
+ if (mWallpaperComponent != null) {
+ out.attribute(null, "component",
+ mWallpaperComponent.flattenToShortString());
+ }
+ out.endTag(null, "wp");
+
+ out.endDocument();
+ stream.close();
+ journal.commit();
+ } catch (IOException e) {
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException ex) {
+ // Ignore
+ }
+ journal.rollback();
+ }
+ }
+
+ private void loadSettingsLocked() {
+ JournaledFile journal = makeJournaledFile();
+ FileInputStream stream = null;
+ File file = journal.chooseForRead();
+ boolean success = false;
+ try {
+ stream = new FileInputStream(file);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+
+ int type;
+ do {
+ type = parser.next();
+ if (type == XmlPullParser.START_TAG) {
+ String tag = parser.getName();
+ if ("wp".equals(tag)) {
+ mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
+ mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
+ mName = parser.getAttributeValue(null, "name");
+ String comp = parser.getAttributeValue(null, "component");
+ mWallpaperComponent = comp != null
+ ? ComponentName.unflattenFromString(comp)
+ : null;
+ }
+ }
+ } while (type != XmlPullParser.END_DOCUMENT);
+ success = true;
+ } catch (NullPointerException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (IOException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Log.w(TAG, "failed parsing " + file + " " + e);
+ }
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+
+ if (!success) {
+ mWidth = -1;
+ mHeight = -1;
+ mName = "";
+ }
+ }
+
+ void settingsRestored() {
+ boolean success = false;
+ synchronized (mLock) {
+ loadSettingsLocked();
+ // If there's a wallpaper name, we use that. If that can't be loaded, then we
+ // use the default.
+ if ("".equals(mName)) {
+ success = true;
+ } else {
+ success = restoreNamedResourceLocked();
+ }
+ }
+
+ if (!success) {
+ Log.e(TAG, "Failed to restore wallpaper: '" + mName + "'");
+ mName = "";
+ WALLPAPER_FILE.delete();
+ }
+ saveSettingsLocked();
+ }
+
+ boolean restoreNamedResourceLocked() {
+ if (mName.length() > 4 && "res:".equals(mName.substring(0, 4))) {
+ String resName = mName.substring(4);
+
+ String pkg = null;
+ int colon = resName.indexOf(':');
+ if (colon > 0) {
+ pkg = resName.substring(0, colon);
+ }
+
+ String ident = null;
+ int slash = resName.lastIndexOf('/');
+ if (slash > 0) {
+ ident = resName.substring(slash+1);
+ }
+
+ String type = null;
+ if (colon > 0 && slash > 0 && (slash-colon) > 1) {
+ type = resName.substring(colon+1, slash);
+ }
+
+ if (pkg != null && ident != null && type != null) {
+ int resId = -1;
+ InputStream res = null;
+ FileOutputStream fos = null;
+ try {
+ Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
+ Resources r = c.getResources();
+ resId = r.getIdentifier(resName, null, null);
+ if (resId == 0) {
+ Log.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
+ + " ident=" + ident);
+ return false;
+ }
+
+ res = r.openRawResource(resId);
+ fos = new FileOutputStream(WALLPAPER_FILE);
+
+ byte[] buffer = new byte[32768];
+ int amt;
+ while ((amt=res.read(buffer)) > 0) {
+ fos.write(buffer, 0, amt);
+ }
+ // mWallpaperObserver will notice the close and send the change broadcast
+
+ Log.d(TAG, "Restored wallpaper: " + resName);
+ return true;
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Package name " + pkg + " not found");
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "Resource not found: " + resId);
+ } catch (IOException e) {
+ Log.e(TAG, "IOException while restoring wallpaper ", e);
+ } finally {
+ if (res != null) {
+ try {
+ res.close();
+ } catch (IOException ex) {}
+ }
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException ex) {}
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/services/java/com/android/server/WallpaperService.java b/services/java/com/android/server/WallpaperService.java
deleted file mode 100644
index d921baf..0000000
--- a/services/java/com/android/server/WallpaperService.java
+++ /dev/null
@@ -1,203 +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 com.android.server;
-
-import static android.os.FileObserver.*;
-import static android.os.ParcelFileDescriptor.*;
-
-import android.app.IWallpaperService;
-import android.app.IWallpaperServiceCallback;
-import android.backup.BackupManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.os.FileObserver;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteCallbackList;
-import android.util.Config;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-
-class WallpaperService extends IWallpaperService.Stub {
- private static final String TAG = WallpaperService.class.getSimpleName();
-
- private static final File WALLPAPER_DIR = new File(
- "/data/data/com.android.settings/files");
- private static final String WALLPAPER = "wallpaper";
- private static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER);
-
- private static final String PREFERENCES = "wallpaper-hints";
-
- private static final String HINT_WIDTH = "hintWidth";
- private static final String HINT_HEIGHT = "hintHeight";
-
- /**
- * List of callbacks registered they should each be notified
- * when the wallpaper is changed.
- */
- private final RemoteCallbackList<IWallpaperServiceCallback> mCallbacks
- = new RemoteCallbackList<IWallpaperServiceCallback>();
-
- /**
- * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
- * that the wallpaper has changed. The CREATE is triggered when there is no
- * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
- * everytime the wallpaper is changed.
- */
- private final FileObserver mWallpaperObserver = new FileObserver(
- WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE) {
- @Override
- public void onEvent(int event, String path) {
- if (path == null) {
- return;
- }
-
- File changedFile = new File(WALLPAPER_DIR, path);
- if (WALLPAPER_FILE.equals(changedFile)) {
- notifyCallbacks();
- }
- }
- };
-
- private final Context mContext;
-
- private int mWidth = -1;
- private int mHeight = -1;
-
- public WallpaperService(Context context) {
- if (Config.LOGD) Log.d(TAG, "WallpaperService startup");
- mContext = context;
- createFilesDir();
- mWallpaperObserver.startWatching();
-
- SharedPreferences preferences = mContext.getSharedPreferences(PREFERENCES,
- Context.MODE_PRIVATE);
- mWidth = preferences.getInt(HINT_WIDTH, -1);
- mHeight = preferences.getInt(HINT_HEIGHT, -1);
- }
-
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- mWallpaperObserver.stopWatching();
- }
-
- public void clearWallpaper() {
- File f = WALLPAPER_FILE;
- if (f.exists()) {
- f.delete();
- }
- }
-
- public void setDimensionHints(int width, int height) throws RemoteException {
- checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
-
- if (width <= 0 || height <= 0) {
- throw new IllegalArgumentException("width and height must be > 0");
- }
-
- if (width != mWidth || height != mHeight) {
- mWidth = width;
- mHeight = height;
-
- SharedPreferences preferences = mContext.getSharedPreferences(PREFERENCES,
- Context.MODE_PRIVATE);
-
- final SharedPreferences.Editor editor = preferences.edit();
- editor.putInt(HINT_WIDTH, width);
- editor.putInt(HINT_HEIGHT, height);
- editor.commit();
- }
- }
-
- public int getWidthHint() throws RemoteException {
- return mWidth;
- }
-
- public int getHeightHint() throws RemoteException {
- return mHeight;
- }
-
- public ParcelFileDescriptor getWallpaper(IWallpaperServiceCallback cb) {
- try {
- mCallbacks.register(cb);
- File f = WALLPAPER_FILE;
- if (!f.exists()) {
- return null;
- }
- return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
- } catch (FileNotFoundException e) {
-
- /* Shouldn't happen as we check to see if the file exists */
- if (Config.LOGD) Log.d(TAG, "Error getting wallpaper", e);
- }
- return null;
- }
-
- public ParcelFileDescriptor setWallpaper() {
- checkPermission(android.Manifest.permission.SET_WALLPAPER);
- try {
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
- MODE_CREATE|MODE_READ_WRITE);
-
- // changing the wallpaper means we'll need to back up the new one
- long origId = Binder.clearCallingIdentity();
- BackupManager bm = new BackupManager(mContext);
- bm.dataChanged();
- Binder.restoreCallingIdentity(origId);
-
- return fd;
- } catch (FileNotFoundException e) {
- if (Config.LOGD) Log.d(TAG, "Error setting wallpaper", e);
- }
- return null;
- }
-
- private void createFilesDir() {
- if (!WALLPAPER_DIR.exists()) {
- WALLPAPER_DIR.mkdirs();
- }
- }
-
- private void notifyCallbacks() {
- final int n = mCallbacks.beginBroadcast();
- for (int i = 0; i < n; i++) {
- try {
- mCallbacks.getBroadcastItem(i).onWallpaperChanged();
- } catch (RemoteException e) {
-
- // The RemoteCallbackList will take care of removing
- // the dead object for us.
- }
- }
- mCallbacks.finishBroadcast();
- final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
- mContext.sendBroadcast(intent);
- }
-
- private void checkPermission(String permission) {
- if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) {
- throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
- + ", must have permission " + permission);
- }
- }
-}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 394ed3a..2dc747e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -41,6 +41,7 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.SupplicantState;
import android.net.NetworkStateTracker;
import android.net.DhcpInfo;
+import android.net.NetworkUtils;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -92,6 +93,9 @@ public class WifiService extends IWifiManager.Stub {
private boolean mDeviceIdle;
private int mPluggedType;
+ // true if the user enabled Wifi while in airplane mode
+ private boolean mAirplaneModeOverwridden;
+
private final LockList mLocks = new LockList();
// some wifi lock statistics
private int mFullLocksAcquired;
@@ -142,28 +146,6 @@ public class WifiService extends IWifiManager.Stub {
private final WifiHandler mWifiHandler;
/*
- * Map used to keep track of hidden networks presence, which
- * is needed to switch between active and passive scan modes.
- * If there is at least one hidden network that is currently
- * present (enabled), we want to do active scans instead of
- * passive.
- */
- private final Map<Integer, Boolean> mIsHiddenNetworkPresent;
- /*
- * The number of currently present hidden networks. When this
- * counter goes from 0 to 1 or from 1 to 0, we change the
- * scan mode to active or passive respectively. Initially, we
- * set the counter to 0 and we increment it every time we add
- * a new present (enabled) hidden network.
- */
- private int mNumHiddenNetworkPresent;
- /*
- * Whether we change the scan mode is due to a hidden network
- * (in this class, this is always the case)
- */
- private final static boolean SET_DUE_TO_A_HIDDEN_NETWORK = true;
-
- /*
* Cache of scan results objects (size is somewhat arbitrary)
*/
private static final int SCAN_RESULT_CACHE_SIZE = 80;
@@ -195,12 +177,6 @@ public class WifiService extends IWifiManager.Stub {
mWifiStateTracker.enableRssiPolling(true);
mBatteryStats = BatteryStatsService.getService();
- /*
- * Initialize the hidden-networks state
- */
- mIsHiddenNetworkPresent = new HashMap<Integer, Boolean>();
- mNumHiddenNetworkPresent = 0;
-
mScanResultCache = new LinkedHashMap<String, ScanResult>(
SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
/*
@@ -246,6 +222,8 @@ public class WifiService extends IWifiManager.Stub {
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // clear our flag indicating the user has overwridden airplane mode
+ mAirplaneModeOverwridden = false;
updateWifiState();
}
},
@@ -254,155 +232,6 @@ public class WifiService extends IWifiManager.Stub {
setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
}
- /**
- * Initializes the hidden networks state. Must be called when we
- * enable Wi-Fi.
- */
- private synchronized void initializeHiddenNetworksState() {
- // First, reset the state
- resetHiddenNetworksState();
-
- // ... then add networks that are marked as hidden
- List<WifiConfiguration> networks = getConfiguredNetworks();
- if (!networks.isEmpty()) {
- for (WifiConfiguration config : networks) {
- if (config != null && config.hiddenSSID) {
- addOrUpdateHiddenNetwork(
- config.networkId,
- config.status != WifiConfiguration.Status.DISABLED);
- }
- }
-
- }
- }
-
- /**
- * Resets the hidden networks state.
- */
- private synchronized void resetHiddenNetworksState() {
- mNumHiddenNetworkPresent = 0;
- mIsHiddenNetworkPresent.clear();
- }
-
- /**
- * Marks all but netId network as not present.
- */
- private synchronized void markAllHiddenNetworksButOneAsNotPresent(int netId) {
- for (Map.Entry<Integer, Boolean> entry : mIsHiddenNetworkPresent.entrySet()) {
- if (entry != null) {
- Integer networkId = entry.getKey();
- if (networkId != netId) {
- updateNetworkIfHidden(
- networkId, false);
- }
- }
- }
- }
-
- /**
- * Updates the netId network presence status if netId is an existing
- * hidden network.
- */
- private synchronized void updateNetworkIfHidden(int netId, boolean present) {
- if (isHiddenNetwork(netId)) {
- addOrUpdateHiddenNetwork(netId, present);
- }
- }
-
- /**
- * Updates the netId network presence status if netId is an existing
- * hidden network. If the network does not exist, adds the network.
- */
- private synchronized void addOrUpdateHiddenNetwork(int netId, boolean present) {
- if (0 <= netId) {
-
- // If we are adding a new entry or modifying an existing one
- Boolean isPresent = mIsHiddenNetworkPresent.get(netId);
- if (isPresent == null || isPresent != present) {
- if (present) {
- incrementHiddentNetworkPresentCounter();
- } else {
- // If we add a new hidden network, no need to change
- // the counter (it must be 0)
- if (isPresent != null) {
- decrementHiddentNetworkPresentCounter();
- }
- }
- mIsHiddenNetworkPresent.put(netId, present);
- }
- } else {
- Log.e(TAG, "addOrUpdateHiddenNetwork(): Invalid (negative) network id!");
- }
- }
-
- /**
- * Removes the netId network if it is hidden (being kept track of).
- */
- private synchronized void removeNetworkIfHidden(int netId) {
- if (isHiddenNetwork(netId)) {
- removeHiddenNetwork(netId);
- }
- }
-
- /**
- * Removes the netId network. For the call to be successful, the network
- * must be hidden.
- */
- private synchronized void removeHiddenNetwork(int netId) {
- if (0 <= netId) {
- Boolean isPresent =
- mIsHiddenNetworkPresent.remove(netId);
- if (isPresent != null) {
- // If we remove an existing hidden network that is not
- // present, no need to change the counter
- if (isPresent) {
- decrementHiddentNetworkPresentCounter();
- }
- } else {
- if (DBG) {
- Log.d(TAG, "removeHiddenNetwork(): Removing a non-existent network!");
- }
- }
- } else {
- Log.e(TAG, "removeHiddenNetwork(): Invalid (negative) network id!");
- }
- }
-
- /**
- * Returns true if netId is an existing hidden network.
- */
- private synchronized boolean isHiddenNetwork(int netId) {
- return mIsHiddenNetworkPresent.containsKey(netId);
- }
-
- /**
- * Increments the present (enabled) hidden networks counter. If the
- * counter value goes from 0 to 1, changes the scan mode to active.
- */
- private void incrementHiddentNetworkPresentCounter() {
- ++mNumHiddenNetworkPresent;
- if (1 == mNumHiddenNetworkPresent) {
- // Switch the scan mode to "active"
- mWifiStateTracker.setScanMode(true, SET_DUE_TO_A_HIDDEN_NETWORK);
- }
- }
-
- /**
- * Decrements the present (enabled) hidden networks counter. If the
- * counter goes from 1 to 0, changes the scan mode back to passive.
- */
- private void decrementHiddentNetworkPresentCounter() {
- if (0 < mNumHiddenNetworkPresent) {
- --mNumHiddenNetworkPresent;
- if (0 == mNumHiddenNetworkPresent) {
- // Switch the scan mode to "passive"
- mWifiStateTracker.setScanMode(false, SET_DUE_TO_A_HIDDEN_NETWORK);
- }
- } else {
- Log.e(TAG, "Hidden-network counter invariant violation!");
- }
- }
-
private boolean getPersistedWifiEnabled() {
final ContentResolver cr = mContext.getContentResolver();
try {
@@ -468,6 +297,8 @@ public class WifiService extends IWifiManager.Stub {
synchronized (mWifiHandler) {
sWakeLock.acquire();
mLastEnableUid = Binder.getCallingUid();
+ // set a flag if the user is enabling Wifi while in airplane mode
+ mAirplaneModeOverwridden = (enable && isAirplaneModeOn() && isAirplaneToggleable());
sendEnableMessage(enable, true, Binder.getCallingUid());
}
@@ -488,7 +319,7 @@ public class WifiService extends IWifiManager.Stub {
if (mWifiState == eventualWifiState) {
return true;
}
- if (enable && isAirplaneModeOn()) {
+ if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) {
return false;
}
@@ -522,7 +353,7 @@ public class WifiService extends IWifiManager.Stub {
}
// We must reset the interface before we unload the driver
- mWifiStateTracker.resetInterface();
+ mWifiStateTracker.resetInterface(false);
if (!WifiNative.unloadDriver()) {
Log.e(TAG, "Failed to unload Wi-Fi driver.");
@@ -544,12 +375,10 @@ public class WifiService extends IWifiManager.Stub {
setWifiEnabledState(eventualWifiState, uid);
/*
- * Initialize the hidden networks state and the number of allowed
- * radio channels if Wi-Fi is being turned on.
+ * Initialize the number of allowed radio channels if Wi-Fi is being turned on.
*/
if (enable) {
mWifiStateTracker.setNumAllowedChannels();
- initializeHiddenNetworksState();
}
return true;
@@ -884,15 +713,6 @@ public class WifiService extends IWifiManager.Stub {
}
mNeedReconfig = mNeedReconfig || doReconfig;
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- if (config.hiddenSSID) {
- // Mark the network as present unless it is disabled
- addOrUpdateHiddenNetwork(
- netId, config.status != WifiConfiguration.Status.DISABLED);
- }
-
setVariables: {
/*
* Note that if a networkId for a non-existent network
@@ -1231,11 +1051,6 @@ public class WifiService extends IWifiManager.Stub {
public boolean removeNetwork(int netId) {
enforceChangePermission();
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- removeNetworkIfHidden(netId);
-
return mWifiStateTracker.removeNetwork(netId);
}
@@ -1249,18 +1064,14 @@ public class WifiService extends IWifiManager.Stub {
public boolean enableNetwork(int netId, boolean disableOthers) {
enforceChangePermission();
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- synchronized(this) {
- if (disableOthers) {
- markAllHiddenNetworksButOneAsNotPresent(netId);
- }
- updateNetworkIfHidden(netId, true);
- }
-
synchronized (mWifiStateTracker) {
- return WifiNative.enableNetworkCommand(netId, disableOthers);
+ String ifname = mWifiStateTracker.getInterfaceName();
+ NetworkUtils.enableInterface(ifname);
+ boolean result = WifiNative.enableNetworkCommand(netId, disableOthers);
+ if (!result) {
+ NetworkUtils.disableInterface(ifname);
+ }
+ return result;
}
}
@@ -1273,11 +1084,6 @@ public class WifiService extends IWifiManager.Stub {
public boolean disableNetwork(int netId) {
enforceChangePermission();
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- updateNetworkIfHidden(netId, false);
-
synchronized (mWifiStateTracker) {
return WifiNative.disableNetworkCommand(netId);
}
@@ -1375,45 +1181,49 @@ public class WifiService extends IWifiManager.Stub {
level = 0;
}
- // bssid is the hash key
- scanResult = mScanResultCache.get(bssid);
- if (scanResult != null) {
- scanResult.level = level;
- } else {
- /*
- * The formatting of the results returned by
- * wpa_supplicant is intended to make the fields
- * line up nicely when printed,
- * not to make them easy to parse. So we have to
- * apply some heuristics to figure out which field
- * is the SSID and which field is the flags.
- */
- String ssid;
- String flags;
- if (result.length == 4) {
- if (result[3].charAt(0) == '[') {
- flags = result[3];
- ssid = "";
- } else {
- flags = "";
- ssid = result[3];
- }
- } else if (result.length == 5) {
+ /*
+ * The formatting of the results returned by
+ * wpa_supplicant is intended to make the fields
+ * line up nicely when printed,
+ * not to make them easy to parse. So we have to
+ * apply some heuristics to figure out which field
+ * is the SSID and which field is the flags.
+ */
+ String ssid;
+ String flags;
+ if (result.length == 4) {
+ if (result[3].charAt(0) == '[') {
flags = result[3];
- ssid = result[4];
+ ssid = "";
} else {
- // Here, we must have 3 fields: no flags and ssid
- // set
flags = "";
- ssid = "";
+ ssid = result[3];
}
+ } else if (result.length == 5) {
+ flags = result[3];
+ ssid = result[4];
+ } else {
+ // Here, we must have 3 fields: no flags and ssid
+ // set
+ flags = "";
+ ssid = "";
+ }
+ // bssid + ssid is the hash key
+ String key = bssid + ssid;
+ scanResult = mScanResultCache.get(key);
+ if (scanResult != null) {
+ scanResult.level = level;
+ scanResult.SSID = ssid;
+ scanResult.capabilities = flags;
+ scanResult.frequency = frequency;
+ } else {
// Do not add scan results that have no SSID set
if (0 < ssid.trim().length()) {
scanResult =
new ScanResult(
ssid, bssid, flags, level, frequency);
- mScanResultCache.put(bssid, scanResult);
+ mScanResultCache.put(key, scanResult);
}
}
} else {
@@ -1479,14 +1289,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,
@@ -1505,9 +1318,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;
}
@@ -1688,7 +1503,7 @@ public class WifiService extends IWifiManager.Stub {
private void updateWifiState() {
boolean wifiEnabled = getPersistedWifiEnabled();
- boolean airplaneMode = isAirplaneModeOn();
+ boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden;
boolean lockHeld = mLocks.hasLocks();
int strongestLockMode;
boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
@@ -1752,6 +1567,13 @@ public class WifiService extends IWifiManager.Stub {
|| airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
}
+ private boolean isAirplaneToggleable() {
+ String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
+ Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+ return toggleableRadios != null
+ && toggleableRadios.contains(Settings.System.RADIO_WIFI);
+ }
+
/**
* Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is
* currently on.
@@ -2068,7 +1890,9 @@ public class WifiService extends IWifiManager.Stub {
// our new size == 1 (first call), but this function won't
// be called often and by making the stopPacket call each
// time we're less fragile and self-healing.
- WifiNative.stopPacketFiltering();
+ synchronized (mWifiStateTracker) {
+ WifiNative.stopPacketFiltering();
+ }
}
int uid = Binder.getCallingUid();
@@ -2104,7 +1928,9 @@ public class WifiService extends IWifiManager.Stub {
removed.unlinkDeathRecipient();
}
if (mMulticasters.size() == 0) {
- WifiNative.startPacketFiltering();
+ synchronized (mWifiStateTracker) {
+ WifiNative.startPacketFiltering();
+ }
}
Long ident = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index d4c27b7..81e0136 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -31,15 +31,15 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU;
-import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_HARDWARE;
import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import com.android.internal.app.IBatteryStats;
import com.android.internal.policy.PolicyManager;
@@ -66,6 +66,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;
@@ -124,7 +125,8 @@ import java.util.Iterator;
import java.util.List;
/** {@hide} */
-public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor {
+public class WindowManagerService extends IWindowManager.Stub
+ implements Watchdog.Monitor, KeyInputQueue.HapticFeedbackCallback {
static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_FOCUS = false;
@@ -137,7 +139,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
static final boolean DEBUG_APP_TRANSITIONS = false;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
+ static final boolean DEBUG_WALLPAPER = 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;
@@ -395,6 +400,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
WindowState mInputMethodWindow = null;
final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
+ final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
+
+ // If non-null, this is the currently visible window that is associated
+ // with the wallpaper.
+ WindowState mWallpaperTarget = null;
+ // If non-null, we are in the middle of animating from one wallpaper target
+ // to another, and this is the lower one in Z-order.
+ WindowState mLowerWallpaperTarget = null;
+ // If non-null, we are in the middle of animating from one wallpaper target
+ // to another, and this is the higher one in Z-order.
+ WindowState mUpperWallpaperTarget = null;
+ int mWallpaperAnimLayerAdjustment;
+ float mLastWallpaperX;
+ float mLastWallpaperY;
+
AppWindowToken mFocusedApp = null;
PowerManagerService mPowerManager;
@@ -512,6 +532,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(
@@ -1159,6 +1183,418 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
}
+ boolean adjustWallpaperWindowsLocked() {
+ boolean changed = false;
+
+ final int dw = mDisplay.getWidth();
+ final int dh = mDisplay.getHeight();
+
+ // First find top-most window that has asked to be on top of the
+ // wallpaper; all wallpapers go behind it.
+ final ArrayList localmWindows = mWindows;
+ int N = localmWindows.size();
+ WindowState w = null;
+ WindowState foundW = null;
+ int foundI = 0;
+ int i = N;
+ while (i > 0) {
+ i--;
+ w = (WindowState)localmWindows.get(i);
+ if (w.mAppToken != null) {
+ // If this window's app token is hidden and not animating,
+ // it is of no interest to us.
+ if (w.mAppToken.hidden && w.mAppToken.animation == null) {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Skipping hidden or animating token: " + w);
+ continue;
+ }
+ // If this window's app token is ot fullscreen, also irrelevant.
+ if (!w.mAppToken.appFullscreen) {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Skipping non-fullscreen token: " + w);
+ continue;
+ }
+ }
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Win " + w + ": readyfordisplay="
+ + w.isReadyForDisplay() + " drawpending=" + w.mDrawPending
+ + " commitdrawpending=" + w.mCommitDrawPending);
+ if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()
+ && (mWallpaperTarget == w
+ || (!w.mDrawPending && !w.mCommitDrawPending))) {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Found wallpaper activity: #" + i + "=" + w);
+ foundW = w;
+ foundI = i;
+ if (w == mWallpaperTarget && w.mAppToken != null
+ && w.mAppToken.animation != null) {
+ // The current wallpaper target is animating, so we'll
+ // look behind it for another possible target and figure
+ // out what is going on below.
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Win " + w
+ + ": token animating, looking behind.");
+ continue;
+ }
+ break;
+ }
+ }
+
+ if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+ // If we are currently waiting for an app transition, and either
+ // the current target or the next target are involved with it,
+ // then hold off on doing anything with the wallpaper.
+ // Note that we are checking here for just whether the target
+ // is part of an app token... which is potentially overly aggressive
+ // (the app token may not be involved in the transition), but good
+ // enough (we'll just wait until whatever transition is pending
+ // executes).
+ if (mWallpaperTarget != null && mWallpaperTarget.mAppToken != null) {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Wallpaper not changing: waiting for app anim in current target");
+ return false;
+ }
+ if (foundW != null && foundW.mAppToken != null) {
+ if (DEBUG_WALLPAPER) Log.v(TAG,
+ "Wallpaper not changing: waiting for app anim in found target");
+ return false;
+ }
+ }
+
+ if (mWallpaperTarget != foundW) {
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "New wallpaper target: " + foundW
+ + " oldTarget: " + mWallpaperTarget);
+ }
+
+ mLowerWallpaperTarget = null;
+ mUpperWallpaperTarget = null;
+
+ WindowState oldW = mWallpaperTarget;
+ mWallpaperTarget = foundW;
+
+ // Now what is happening... if the current and new targets are
+ // animating, then we are in our super special mode!
+ if (foundW != null && foundW.mAppToken != null && oldW != null
+ && oldW.mAppToken != null) {
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "New animation: " + foundW.mAppToken.animation
+ + " old animation: " + oldW.mAppToken.animation);
+ }
+ if (foundW.mAppToken.animation != null
+ && oldW.mAppToken.animation != null) {
+ int oldI = localmWindows.indexOf(oldW);
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "New i: " + foundI + " old i: " + oldI);
+ }
+ if (oldI >= 0) {
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "Animating wallpapers: old#" + oldI
+ + "=" + oldW + "; new#" + foundI
+ + "=" + foundW);
+ }
+
+ // Set the new target correctly.
+ if (foundW.mAppToken.hiddenRequested) {
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "Old wallpaper still the target.");
+ }
+ mWallpaperTarget = oldW;
+ }
+
+ // Now set the upper and lower wallpaper targets
+ // correctly, and make sure that we are positioning
+ // the wallpaper below the lower.
+ if (foundI > oldI) {
+ // The new target is on top of the old one.
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "Found target above old target.");
+ }
+ mUpperWallpaperTarget = foundW;
+ mLowerWallpaperTarget = oldW;
+ foundW = oldW;
+ foundI = oldI;
+ } else {
+ // The new target is below the old one.
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "Found target below old target.");
+ }
+ mUpperWallpaperTarget = oldW;
+ mLowerWallpaperTarget = foundW;
+ }
+ }
+ }
+ }
+
+ } else {
+ // Is it time to stop animating?
+ if (mLowerWallpaperTarget == null
+ || mLowerWallpaperTarget.mAppToken.animation == null
+ || mUpperWallpaperTarget == null
+ || mUpperWallpaperTarget.mAppToken.animation == null) {
+ if (DEBUG_WALLPAPER) {
+ Log.v(TAG, "No longer animating wallpaper targets!");
+ }
+ mLowerWallpaperTarget = null;
+ mUpperWallpaperTarget = null;
+ }
+ }
+
+ boolean visible = foundW != null;
+ if (visible) {
+ // The window is visible to the compositor... but is it visible
+ // to the user? That is what the wallpaper cares about.
+ visible = !foundW.mObscured;
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper visibility: " + visible);
+
+ // If the wallpaper target is animating, we may need to copy
+ // its layer adjustment. Only do this if we are not transfering
+ // between two wallpaper targets.
+ mWallpaperAnimLayerAdjustment =
+ (mLowerWallpaperTarget == null && foundW.mAppToken != null)
+ ? foundW.mAppToken.animLayerAdjustment : 0;
+
+ // Now w is the window we are supposed to be behind... but we
+ // need to be sure to also be behind any of its attached windows,
+ // AND any starting window associated with it.
+ while (foundI > 0) {
+ WindowState wb = (WindowState)localmWindows.get(foundI-1);
+ if (wb.mAttachedWindow != foundW &&
+ (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
+ wb.mToken != foundW.mToken)) {
+ // This window is not related to the previous one in any
+ // interesting way, so stop here.
+ break;
+ }
+ foundW = wb;
+ foundI--;
+ }
+ }
+
+ // Okay i is the position immediately above the wallpaper. Look at
+ // what is below it for later.
+ foundW = foundI > 0 ? (WindowState)localmWindows.get(foundI-1) : null;
+
+ if (visible) {
+ mLastWallpaperX = mWallpaperTarget.mWallpaperX;
+ mLastWallpaperY = mWallpaperTarget.mWallpaperY;
+ }
+
+ // Start stepping backwards from here, ensuring that our wallpaper windows
+ // are correctly placed.
+ int curTokenIndex = mWallpaperTokens.size();
+ while (curTokenIndex > 0) {
+ curTokenIndex--;
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ int curWallpaperIndex = token.windows.size();
+ while (curWallpaperIndex > 0) {
+ curWallpaperIndex--;
+ WindowState wallpaper = token.windows.get(curWallpaperIndex);
+
+ if (visible) {
+ updateWallpaperOffsetLocked(wallpaper, dw, dh);
+ }
+
+ // First, make sure the client has the current visibility
+ // state.
+ if (wallpaper.mWallpaperVisible != visible) {
+ wallpaper.mWallpaperVisible = visible;
+ try {
+ if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Log.v(TAG,
+ "Setting visibility of wallpaper " + wallpaper
+ + ": " + visible);
+ wallpaper.mClient.dispatchAppVisibility(visible);
+ } catch (RemoteException e) {
+ }
+ }
+
+ wallpaper.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
+ + wallpaper + " anim layer: " + wallpaper.mAnimLayer);
+
+ // First, if this window is at the current index, then all
+ // is well.
+ if (wallpaper == foundW) {
+ foundI--;
+ foundW = foundI > 0
+ ? (WindowState)localmWindows.get(foundI-1) : null;
+ continue;
+ }
+
+ // The window didn't match... the current wallpaper window,
+ // wherever it is, is in the wrong place, so make sure it is
+ // not in the list.
+ int oldIndex = localmWindows.indexOf(wallpaper);
+ if (oldIndex >= 0) {
+ localmWindows.remove(oldIndex);
+ if (oldIndex < foundI) {
+ foundI--;
+ }
+ }
+
+ // Now stick it in.
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Moving wallpaper " + wallpaper
+ + " from " + oldIndex + " to " + foundI);
+
+ localmWindows.add(foundI, wallpaper);
+ changed = true;
+ }
+ }
+
+ return changed;
+ }
+
+ void setWallpaperAnimLayerAdjustmentLocked(int adj) {
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG,
+ "Setting wallpaper layer adj to " + adj);
+ mWallpaperAnimLayerAdjustment = adj;
+ int curTokenIndex = mWallpaperTokens.size();
+ while (curTokenIndex > 0) {
+ curTokenIndex--;
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ int curWallpaperIndex = token.windows.size();
+ while (curWallpaperIndex > 0) {
+ curWallpaperIndex--;
+ WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ wallpaper.mAnimLayer = wallpaper.mLayer + adj;
+ if (DEBUG_LAYERS || DEBUG_WALLPAPER) Log.v(TAG, "Wallpaper win "
+ + wallpaper + " anim layer: " + wallpaper.mAnimLayer);
+ }
+ }
+ }
+
+ boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh) {
+ boolean changed = false;
+ boolean rawChanged = false;
+ if (mLastWallpaperX >= 0) {
+ int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
+ int offset = availw > 0 ? -(int)(availw*mLastWallpaperX+.5f) : 0;
+ changed = wallpaperWin.mXOffset != offset;
+ if (changed) {
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
+ + wallpaperWin + " x: " + offset);
+ wallpaperWin.mXOffset = offset;
+ }
+ if (wallpaperWin.mWallpaperX != mLastWallpaperX) {
+ wallpaperWin.mWallpaperX = mLastWallpaperX;
+ rawChanged = true;
+ }
+ }
+
+ if (mLastWallpaperY >= 0) {
+ int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh;
+ int offset = availh > 0 ? -(int)(availh*mLastWallpaperY+.5f) : 0;
+ if (wallpaperWin.mYOffset != offset) {
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Update wallpaper "
+ + wallpaperWin + " y: " + offset);
+ changed = true;
+ wallpaperWin.mYOffset = offset;
+ }
+ if (wallpaperWin.mWallpaperY != mLastWallpaperY) {
+ wallpaperWin.mWallpaperY = mLastWallpaperY;
+ rawChanged = true;
+ }
+ }
+
+ if (rawChanged) {
+ try {
+ if (DEBUG_WALLPAPER) Log.v(TAG, "Report new wp offset "
+ + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
+ + " y=" + wallpaperWin.mWallpaperY);
+ wallpaperWin.mClient.dispatchWallpaperOffsets(
+ wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY);
+ } catch (RemoteException e) {
+ }
+ }
+
+ return changed;
+ }
+
+ boolean updateWallpaperOffsetLocked() {
+ final int dw = mDisplay.getWidth();
+ final int dh = mDisplay.getHeight();
+
+ boolean changed = false;
+
+ WindowState target = mWallpaperTarget;
+ if (target != null) {
+ mLastWallpaperX = target.mWallpaperX;
+ mLastWallpaperY = target.mWallpaperY;
+ int curTokenIndex = mWallpaperTokens.size();
+ while (curTokenIndex > 0) {
+ curTokenIndex--;
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ int curWallpaperIndex = token.windows.size();
+ while (curWallpaperIndex > 0) {
+ curWallpaperIndex--;
+ WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ if (updateWallpaperOffsetLocked(wallpaper, dw, dh)) {
+ wallpaper.computeShownFrameLocked();
+ changed = true;
+ }
+ }
+ }
+ }
+
+ return changed;
+ }
+
+ void updateWallpaperVisibilityLocked() {
+ final boolean visible = mWallpaperTarget != null
+ && !mWallpaperTarget.mObscured;
+ final int dw = mDisplay.getWidth();
+ final int dh = mDisplay.getHeight();
+
+ int curTokenIndex = mWallpaperTokens.size();
+ while (curTokenIndex > 0) {
+ curTokenIndex--;
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ int curWallpaperIndex = token.windows.size();
+ while (curWallpaperIndex > 0) {
+ curWallpaperIndex--;
+ WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ if (visible) {
+ updateWallpaperOffsetLocked(wallpaper, dw, dh);
+ }
+
+ if (wallpaper.mWallpaperVisible != visible) {
+ wallpaper.mWallpaperVisible = visible;
+ try {
+ if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Log.v(TAG,
+ "Setting visibility of wallpaper " + wallpaper
+ + ": " + visible);
+ wallpaper.mClient.dispatchAppVisibility(visible);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+ }
+
+ void sendPointerToWallpaperLocked(WindowState srcWin,
+ MotionEvent pointer, long eventTime) {
+ int curTokenIndex = mWallpaperTokens.size();
+ while (curTokenIndex > 0) {
+ curTokenIndex--;
+ WindowToken token = mWallpaperTokens.get(curTokenIndex);
+ int curWallpaperIndex = token.windows.size();
+ while (curWallpaperIndex > 0) {
+ curWallpaperIndex--;
+ WindowState wallpaper = token.windows.get(curWallpaperIndex);
+ if ((wallpaper.mAttrs.flags &
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
+ continue;
+ }
+ try {
+ MotionEvent ev = MotionEvent.obtainNoHistory(pointer);
+ ev.offsetLocation(srcWin.mFrame.left-wallpaper.mFrame.left,
+ srcWin.mFrame.top-wallpaper.mFrame.top);
+ wallpaper.mClient.dispatchPointer(ev, eventTime, false);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failure sending pointer to wallpaper", e);
+ }
+ }
+ }
+ }
+
public int addWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int viewVisibility,
Rect outContentInsets) {
@@ -1216,6 +1652,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
+ if (attrs.type == TYPE_WALLPAPER) {
+ Log.w(TAG, "Attempted to add wallpaper window with unknown token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+ }
token = new WindowToken(attrs.token, -1, false);
addToken = true;
} else if (attrs.type >= FIRST_APPLICATION_WINDOW
@@ -1242,6 +1683,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
+ } else if (attrs.type == TYPE_WALLPAPER) {
+ if (token.windowType != TYPE_WALLPAPER) {
+ Log.w(TAG, "Attempted to add wallpaper window with bad token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+ }
}
win = new WindowState(session, client, token,
@@ -1292,6 +1739,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
imMayMove = false;
} else {
addWindowToListInOrderLocked(win, true);
+ if (attrs.type == TYPE_WALLPAPER ||
+ (attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+ adjustWallpaperWindowsLocked();
+ }
}
win.mEnterAnimationPending = true;
@@ -1432,6 +1883,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
private void removeWindowInnerLocked(Session session, WindowState win) {
+ mKeyWaiter.finishedKey(session, win.mClient, true,
+ KeyWaiter.RETURN_NOTHING);
mKeyWaiter.releasePendingPointerLocked(win.mSession);
mKeyWaiter.releasePendingTrackballLocked(win.mSession);
@@ -1490,6 +1943,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ if (win.mAttrs.type == TYPE_WALLPAPER ||
+ (win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+ adjustWallpaperWindowsLocked();
+ }
+
if (!mInLayout) {
assignLayersLocked();
mLayoutNeeded = true;
@@ -1552,6 +2010,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ public void setWindowWallpaperPositionLocked(WindowState window, float x, float y) {
+ if (window.mWallpaperX != x || window.mWallpaperY != y) {
+ window.mWallpaperX = x;
+ window.mWallpaperY = y;
+
+ if (mWallpaperTarget == window) {
+ if (updateWallpaperOffsetLocked()) {
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+ }
+ }
+
public int relayoutWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, boolean insetsPending,
@@ -1610,6 +2081,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
|| ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
|| (!win.mRelayoutCalled);
+ boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
+ && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
+
win.mRelayoutCalled = true;
final int oldVisibility = win.mViewVisibility;
win.mViewVisibility = viewVisibility;
@@ -1707,6 +2181,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
assignLayers = true;
}
}
+ if (wallpaperMayMove) {
+ if (adjustWallpaperWindowsLocked()) {
+ assignLayers = true;
+ }
+ }
mLayoutNeeded = true;
win.mGivenInsetsPending = insetsPending;
@@ -1715,6 +2194,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
newConfig = updateOrientationFromAppTokensLocked(null, null);
performLayoutAndPlaceSurfacesLocked();
+ if (displayed && win.mIsWallpaper) {
+ updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
+ mDisplay.getHeight());
+ }
if (win.mAppToken != null) {
win.mAppToken.updateReportedVisibilityLocked();
}
@@ -1750,6 +2233,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client);
if (win != null && win.finishDrawingLocked()) {
+ if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+ adjustWallpaperWindowsLocked();
+ }
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
}
@@ -1906,6 +2392,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
: com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
break;
+ case WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_OPEN:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_wallpaperActivityOpenEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_wallpaperActivityOpenExitAnimation;
+ break;
+ case WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_CLOSE:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_wallpaperActivityCloseEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_wallpaperActivityCloseExitAnimation;
+ break;
}
a = loadAnimation(lp, animAttr);
if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
@@ -2002,6 +2498,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
wtoken = new WindowToken(token, type, true);
mTokenMap.put(token, wtoken);
mTokenList.add(wtoken);
+ if (type == TYPE_WALLPAPER) {
+ mWallpaperTokens.add(wtoken);
+ }
}
}
@@ -2047,6 +2546,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (delayed) {
mExitingTokens.add(wtoken);
+ } else if (wtoken.windowType == TYPE_WALLPAPER) {
+ mWallpaperTokens.remove(wtoken);
}
}
@@ -2519,6 +3020,23 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return;
}
+ // If this is a translucent or wallpaper window, then don't
+ // show a starting window -- the current effect (a full-screen
+ // opaque starting window that fades away to the real contents
+ // when it is ready) does not work for this.
+ if (theme != 0) {
+ AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
+ com.android.internal.R.styleable.Window);
+ if (ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
+ return;
+ }
+ if (ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
+ return;
+ }
+ }
+
mStartingIconInTransition = true;
wtoken.startingData = new StartingData(
pkg, theme, nonLocalizedLabel,
@@ -3833,7 +4351,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;
@@ -3893,8 +4411,16 @@ 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, pid, uid);
+
+ if (MEASURE_LATENCY) {
+ lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano);
+ }
int action = ev.getAction();
@@ -3932,7 +4458,8 @@ 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);
if (uid != 0 && uid != target.mSession.mUid) {
@@ -3949,6 +4476,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return INJECT_NO_PERMISSION;
}
}
+
+ if (MEASURE_LATENCY) {
+ lt.sample("4 in dispatchPointer ", System.nanoTime() - eventTimeNano);
+ }
if ((target.mAttrs.flags &
WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
@@ -4032,6 +4563,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,
@@ -4047,7 +4582,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final Rect frame = out.mFrame;
oev.offsetLocation(-(float)frame.left, -(float)frame.top);
try {
- out.mClient.dispatchPointer(oev, eventTime);
+ out.mClient.dispatchPointer(oev, eventTime, false);
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
}
@@ -4060,6 +4595,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final Rect frame = target.mFrame;
ev.offsetLocation(-(float)frame.left, -(float)frame.top);
mKeyWaiter.bindTargetWindowLocked(target);
+
+ // If we are on top of the wallpaper, then the wallpaper also
+ // gets to see this movement.
+ if (mWallpaperTarget == target) {
+ sendPointerToWallpaperLocked(target, ev, eventTime);
+ }
}
}
@@ -4069,7 +4610,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);
}
- target.mClient.dispatchPointer(ev, eventTime);
+
+ if (MEASURE_LATENCY) {
+ lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
+ }
+
+ target.mClient.dispatchPointer(ev, eventTime, true);
+
+ if (MEASURE_LATENCY) {
+ lt.sample("7 after svr->client ipc ", System.nanoTime() - eventTimeNano);
+ }
return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
@@ -4141,7 +4691,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
try {
- focus.mClient.dispatchTrackball(ev, eventTime);
+ focus.mClient.dispatchTrackball(ev, eventTime, true);
return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during key dispatch: " + focus);
@@ -4664,7 +5214,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED) {
mPolicy.interceptKeyTi(null, keycode,
- nextKey.getMetaState(), down, repeatCount);
+ nextKey.getMetaState(), down, repeatCount,
+ nextKey.getFlags());
}
Log.w(TAG, "Event timeout during app switch: dropping "
+ nextKey);
@@ -4687,7 +5238,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED) {
if (mPolicy.interceptKeyTi(focus,
- keycode, nextKey.getMetaState(), down, repeatCount)) {
+ keycode, nextKey.getMetaState(), down, repeatCount,
+ nextKey.getFlags())) {
return CONSUMED_EVENT_TOKEN;
}
}
@@ -4914,14 +5466,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return null;
}
+ MotionEvent res = null;
+ QueuedEvent qev = null;
+ WindowState win = null;
+
synchronized (this) {
if (DEBUG_INPUT) Log.v(
TAG, "finishedKey: client=" + client.asBinder()
+ ", force=" + force + ", last=" + mLastBinder
+ " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
- QueuedEvent qev = null;
- WindowState win = null;
if (returnWhat == RETURN_PENDING_POINTER) {
qev = session.mPendingPointerMove;
win = session.mPendingPointerWindow;
@@ -4951,17 +5505,25 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
if (qev != null) {
- MotionEvent res = (MotionEvent)qev.event;
+ res = (MotionEvent)qev.event;
if (DEBUG_INPUT) Log.v(TAG,
"Returning pending motion: " + res);
mQueue.recycleEvent(qev);
if (win != null && returnWhat == RETURN_PENDING_POINTER) {
res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
}
- return res;
}
- return null;
}
+
+ if (res != null && returnWhat == RETURN_PENDING_POINTER) {
+ synchronized (mWindowMap) {
+ if (mWallpaperTarget == win) {
+ sendPointerToWallpaperLocked(win, res, res.getEventTime());
+ }
+ }
+ }
+
+ return res;
}
void tickle() {
@@ -5107,7 +5669,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
PowerManager.WakeLock mHoldingScreen;
KeyQ() {
- super(mContext);
+ super(mContext, WindowManagerService.this);
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
"KEEP_SCREEN_ON_FLAG");
@@ -5238,7 +5800,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
- };
+ }
public boolean detectSafeMode() {
mSafeMode = mPolicy.detectSafeMode();
@@ -5303,9 +5865,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);
@@ -5316,17 +5882,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;
@@ -5592,6 +6170,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ public void setWallpaperPosition(IBinder window, float x, float y) {
+ synchronized(mWindowMap) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ setWindowWallpaperPositionLocked(windowForClientLocked(this, window),
+ x, y);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (localLOGV) Log.v(
@@ -5667,6 +6257,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final int mSubLayer;
final boolean mLayoutAttached;
final boolean mIsImWindow;
+ final boolean mIsWallpaper;
+ final boolean mIsFloatingLayer;
int mViewVisibility;
boolean mPolicyVisibility = true;
boolean mPolicyVisibilityAfterAnim = true;
@@ -5674,16 +6266,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Surface mSurface;
boolean mAttachedHidden; // is our parent window hidden?
boolean mLastHidden; // was this window last hidden?
+ boolean mWallpaperVisible; // for wallpaper, what was last vis report?
int mRequestedWidth;
int mRequestedHeight;
int mLastRequestedWidth;
int mLastRequestedHeight;
- int mReqXPos;
- int mReqYPos;
int mLayer;
int mAnimLayer;
int mLastLayer;
boolean mHaveFrame;
+ boolean mObscured;
WindowState mNextOutsideTouch;
@@ -5764,6 +6356,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean mHasLocalTransformation;
final Transformation mTransformation = new Transformation();
+ // If a window showing a wallpaper: the requested offset for the
+ // wallpaper; if a wallpaper window: the currently applied offset.
+ float mWallpaperX = -1;
+ float mWallpaperY = -1;
+
+ // Wallpaper windows: pixels offset based on above variables.
+ int mXOffset;
+ int mYOffset;
+
// This is set after IWindowSession.relayout() has been called at
// least once for the window. It allows us to detect the situation
// where we don't yet have a surface, but should have one soon, so
@@ -5824,6 +6425,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mAttachedWindow = null;
mLayoutAttached = false;
mIsImWindow = false;
+ mIsWallpaper = false;
+ mIsFloatingLayer = false;
mBaseLayer = 0;
mSubLayer = 0;
return;
@@ -5844,6 +6447,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
|| attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
+ mIsWallpaper = attachedWindow.mAttrs.type == TYPE_WALLPAPER;
+ mIsFloatingLayer = mIsImWindow || mIsWallpaper;
} else {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
@@ -5855,6 +6460,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mLayoutAttached = false;
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
+ mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
+ mIsFloatingLayer = mIsImWindow || mIsWallpaper;
}
WindowState appWin = this;
@@ -5877,8 +6484,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mRequestedHeight = 0;
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
- mReqXPos = 0;
- mReqYPos = 0;
+ mXOffset = 0;
+ mYOffset = 0;
mLayer = 0;
mAnimLayer = 0;
mLastLayer = 0;
@@ -5926,6 +6533,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
visible.set(vf);
final Rect frame = mFrame;
+ final int fw = frame.width();
+ final int fh = frame.height();
//System.out.println("In: w=" + w + " h=" + h + " container=" +
// container + " x=" + mAttrs.x + " y=" + mAttrs.y);
@@ -5962,6 +6571,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
visibleInsets.right = frame.right-visible.right;
visibleInsets.bottom = frame.bottom-visible.bottom;
+ if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
+ updateWallpaperOffsetLocked(this, mDisplay.getWidth(),
+ mDisplay.getHeight());
+ }
+
if (localLOGV) {
//if ("com.google.android.youtube".equals(mAttrs.packageName)
// && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
@@ -6059,11 +6673,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
int flags = 0;
- if (mAttrs.memoryType == MEMORY_TYPE_HARDWARE) {
- flags |= Surface.HARDWARE;
- } else if (mAttrs.memoryType == MEMORY_TYPE_GPU) {
- flags |= Surface.GPU;
- } else if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) {
+ if (mAttrs.memoryType == MEMORY_TYPE_PUSH_BUFFERS) {
flags |= Surface.PUSH_BUFFERS;
}
@@ -6114,7 +6724,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Surface.openTransaction();
try {
try {
- mSurface.setPosition(mFrame.left, mFrame.top);
+ mSurface.setPosition(mFrame.left + mXOffset,
+ mFrame.top + mYOffset);
mSurface.setLayer(mAnimLayer);
mSurface.hide();
if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
@@ -6149,11 +6760,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mAppToken.startingDisplayed = false;
}
- if (localLOGV) Log.v(
- TAG, "Window " + this
- + " destroying surface " + mSurface + ", session " + mSession);
if (mSurface != null) {
try {
+ if (DEBUG_VISIBILITY) {
+ RuntimeException e = new RuntimeException();
+ e.fillInStackTrace();
+ Log.w(TAG, "Window " + this + " destroying surface "
+ + mSurface + ", session " + mSession, e);
+ }
if (SHOW_TRANSACTIONS) {
RuntimeException ex = new RuntimeException();
ex.fillInStackTrace();
@@ -6192,10 +6806,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
// This must be called while inside a transaction.
- void commitFinishDrawingLocked(long currentTime) {
+ boolean commitFinishDrawingLocked(long currentTime) {
//Log.i(TAG, "commitFinishDrawingLocked: " + mSurface);
if (!mCommitDrawPending) {
- return;
+ return false;
}
mCommitDrawPending = false;
mReadyToShow = true;
@@ -6204,6 +6818,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (atoken == null || atoken.allDrawn || starting) {
performShowLocked();
}
+ return true;
}
// This must be called while inside a transaction.
@@ -6302,7 +6917,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
mHasLocalTransformation = false;
if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
- && mAppToken.hasTransformation) {
+ && mAppToken.animation != null) {
// When our app token is animating, we kind-of pretend like
// we are as well. Note the mLocalAnimating mAnimationIsEntrance
// part of this check means that we will only do this if
@@ -6344,6 +6959,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mAnimLayer = mLayer;
if (mIsImWindow) {
mAnimLayer += mInputMethodAnimLayerAdjustment;
+ } else if (mIsWallpaper) {
+ mAnimLayer += mWallpaperAnimLayerAdjustment;
}
if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
+ " anim layer: " + mAnimLayer);
@@ -6430,6 +7047,26 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Transformation appTransformation =
(mAppToken != null && mAppToken.hasTransformation)
? mAppToken.transformation : null;
+
+ // Wallpapers are animated based on the "real" window they
+ // are currently targeting.
+ if (mAttrs.type == TYPE_WALLPAPER && mLowerWallpaperTarget == null
+ && mWallpaperTarget != null) {
+ if (mWallpaperTarget.mHasLocalTransformation) {
+ attachedTransformation = mWallpaperTarget.mTransformation;
+ }
+ if (mWallpaperTarget.mAppToken != null &&
+ mWallpaperTarget.mAppToken.hasTransformation) {
+ appTransformation = mWallpaperTarget.mAppToken.transformation;
+ }
+ if (DEBUG_WALLPAPER && attachedTransformation != null) {
+ Log.v(TAG, "WP target attached xform: " + attachedTransformation);
+ }
+ if (DEBUG_WALLPAPER && appTransformation != null) {
+ Log.v(TAG, "WP target app xform: " + appTransformation);
+ }
+ }
+
if (selfTransformation || attachedTransformation != null
|| appTransformation != null) {
// cache often used attributes locally
@@ -6460,8 +7097,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mDtDx = tmpFloats[Matrix.MSKEW_X];
mDsDy = tmpFloats[Matrix.MSKEW_Y];
mDtDy = tmpFloats[Matrix.MSCALE_Y];
- int x = (int)tmpFloats[Matrix.MTRANS_X];
- int y = (int)tmpFloats[Matrix.MTRANS_Y];
+ int x = (int)tmpFloats[Matrix.MTRANS_X] + mXOffset;
+ int y = (int)tmpFloats[Matrix.MTRANS_Y] + mYOffset;
int w = frame.width();
int h = frame.height();
mShownFrame.set(x, y, x+w, y+h);
@@ -6498,6 +7135,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
mShownFrame.set(mFrame);
+ if (mXOffset != 0 || mYOffset != 0) {
+ mShownFrame.offset(mXOffset, mYOffset);
+ }
mShownAlpha = mAlpha;
mDsDx = 1;
mDtDx = 0;
@@ -6561,10 +7201,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (atoken != null) {
return mSurface != null && mPolicyVisibility && !mDestroying
&& ((!mAttachedHidden && !atoken.hiddenRequested)
- || mAnimating || atoken.animating);
+ || mAnimation != null || atoken.animation != null);
} else {
return mSurface != null && mPolicyVisibility && !mDestroying
- && (!mAttachedHidden || mAnimating);
+ && (!mAttachedHidden || mAnimation != null);
}
}
@@ -6574,10 +7214,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
*/
boolean isReadyForDisplay() {
final AppWindowToken atoken = mAppToken;
- final boolean animating = atoken != null ? atoken.animating : false;
+ final boolean animating = atoken != null
+ ? (atoken.animation != null) : false;
return mSurface != null && mPolicyVisibility && !mDestroying
- && ((!mAttachedHidden && !mRootToken.hidden)
- || mAnimating || animating);
+ && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
+ && !mRootToken.hidden)
+ || mAnimation != null || animating);
}
/** Is the window or its container currently animating? */
@@ -6659,7 +7301,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean isFullscreen(int screenWidth, int screenHeight) {
return mFrame.left <= 0 && mFrame.top <= 0 &&
- mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
+ mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
}
void removeLocked() {
@@ -6749,8 +7391,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.print(prefix); pw.print("mAttachedWindow="); pw.print(mAttachedWindow);
pw.print(" mLayoutAttached="); pw.println(mLayoutAttached);
}
- if (mIsImWindow) {
- pw.print(prefix); pw.print("mIsImWindow="); pw.println(mIsImWindow);
+ if (mIsImWindow || mIsWallpaper || mIsFloatingLayer) {
+ pw.print(prefix); pw.print("mIsImWindow="); pw.print(mIsImWindow);
+ pw.print(" mIsWallpaper="); pw.print(mIsWallpaper);
+ pw.print(" mIsFloatingLayer="); pw.print(mIsFloatingLayer);
+ pw.print(" mWallpaperVisible="); pw.println(mWallpaperVisible);
}
pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
pw.print(" mSubLayer="); pw.print(mSubLayer);
@@ -6773,7 +7418,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.print(prefix); pw.print("mViewVisibility=0x");
pw.print(Integer.toHexString(mViewVisibility));
pw.print(" mLastHidden="); pw.print(mLastHidden);
- pw.print(" mHaveFrame="); pw.println(mHaveFrame);
+ pw.print(" mHaveFrame="); pw.print(mHaveFrame);
+ pw.print(" mObscured="); pw.println(mObscured);
if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
pw.print(prefix); pw.print("mPolicyVisibility=");
pw.print(mPolicyVisibility);
@@ -6782,9 +7428,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
}
pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
- pw.print(" h="); pw.print(mRequestedHeight);
- pw.print(" x="); pw.print(mReqXPos);
- pw.print(" y="); pw.println(mReqYPos);
+ pw.print(" h="); pw.println(mRequestedHeight);
+ if (mXOffset != 0 || mYOffset != 0) {
+ pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
+ pw.print(" y="); pw.println(mYOffset);
+ }
pw.print(prefix); pw.print("mGivenContentInsets=");
mGivenContentInsets.printShortString(pw);
pw.print(" mGivenVisibleInsets=");
@@ -6852,6 +7500,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.print(prefix); pw.print("mHScale="); pw.print(mHScale);
pw.print(" mVScale="); pw.println(mVScale);
}
+ if (mWallpaperX != -1 || mWallpaperY != -1) {
+ pw.print(prefix); pw.print("mWallpaperX="); pw.print(mWallpaperX);
+ pw.print(" mWallpaperY="); pw.println(mWallpaperY);
+ }
}
@Override
@@ -7036,6 +7688,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (w == mInputMethodTarget) {
setInputMethodAnimLayerAdjustment(adj);
}
+ if (w == mWallpaperTarget && mLowerWallpaperTarget == null) {
+ setWallpaperAnimLayerAdjustmentLocked(adj);
+ }
}
}
@@ -7073,7 +7728,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (animation == sDummyAnimation) {
// This guy is going to animate, but not yet. For now count
- // it is not animating for purposes of scheduling transactions;
+ // it as not animating for purposes of scheduling transactions;
// when it is really time to animate, this will be set to
// a real animation and the next call will execute normally.
return false;
@@ -7213,6 +7868,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
}
pw.print(prefix); pw.print("groupId="); pw.print(groupId);
+ pw.print(" appFullscreen="); pw.println(appFullscreen);
pw.print(" requestedOrientation="); pw.println(requestedOrientation);
pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
pw.print(" clientHidden="); pw.print(clientHidden);
@@ -7786,7 +8442,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
for (i=0; i<N; i++) {
WindowState w = (WindowState)mWindows.get(i);
- if (w.mBaseLayer == curBaseLayer || w.mIsImWindow) {
+ if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
+ || (i > 0 && w.mIsWallpaper)) {
curLayer += WINDOW_LAYER_MULTIPLIER;
w.mLayer = curLayer;
} else {
@@ -7802,6 +8459,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
if (w.mIsImWindow) {
w.mAnimLayer += mInputMethodAnimLayerAdjustment;
+ } else if (w.mIsWallpaper) {
+ w.mAnimLayer += mWallpaperAnimLayerAdjustment;
}
if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
+ w.mAnimLayer);
@@ -8008,6 +8667,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
restart = false;
boolean tokenMayBeDrawn = false;
+ boolean wallpaperMayChange = false;
mPolicy.beginAnimationLw(dw, dh);
@@ -8018,7 +8678,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (w.mSurface != null) {
// Execute animation.
- w.commitFinishDrawingLocked(currentTime);
+ if (w.commitFinishDrawingLocked(currentTime)) {
+ if ((w.mAttrs.flags
+ & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+ wallpaperMayChange = true;
+ }
+ }
if (w.stepAnimationLocked(currentTime, dw, dh)) {
animating = true;
//w.dump(" ");
@@ -8155,6 +8820,61 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
+ adjustWallpaperWindowsLocked();
+ wallpaperMayChange = false;
+
+ if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ "New wallpaper target=" + mWallpaperTarget
+ + ", lower target=" + mLowerWallpaperTarget
+ + ", upper target=" + mUpperWallpaperTarget);
+ if (mLowerWallpaperTarget != null) {
+ // Need to determine if both the closing and
+ // opening app token sets are wallpaper targets,
+ // in which case special animations are needed
+ // (since the wallpaper needs to stay static
+ // behind them).
+ int found = 0;
+ NN = mOpeningApps.size();
+ for (i=0; i<NN; i++) {
+ AppWindowToken wtoken = mOpeningApps.get(i);
+ if (mLowerWallpaperTarget.mAppToken == wtoken) {
+ found |= 1;
+ }
+ if (mUpperWallpaperTarget.mAppToken == wtoken) {
+ found |= 1;
+ }
+ }
+ NN = mClosingApps.size();
+ for (i=0; i<NN; i++) {
+ AppWindowToken wtoken = mClosingApps.get(i);
+ if (mLowerWallpaperTarget.mAppToken == wtoken) {
+ found |= 2;
+ }
+ if (mUpperWallpaperTarget.mAppToken == wtoken) {
+ found |= 2;
+ }
+ }
+
+ if (found == 3) {
+ if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ "Wallpaper animation!");
+ switch (transit) {
+ case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+ case WindowManagerPolicy.TRANSIT_TASK_OPEN:
+ case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
+ transit = WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_OPEN;
+ break;
+ case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
+ case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
+ case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
+ transit = WindowManagerPolicy.TRANSIT_WALLPAPER_ACTIVITY_CLOSE;
+ break;
+ }
+ if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
+ "New transit: " + transit);
+ }
+ }
+
// We need to figure out which animation to use...
WindowManager.LayoutParams lp = findAnimations(mAppTokens,
mOpeningApps, mClosingApps);
@@ -8166,6 +8886,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
"Now opening app" + wtoken);
wtoken.reportedVisible = false;
wtoken.inPendingTransaction = false;
+ wtoken.animation = null;
setTokenVisibilityLocked(wtoken, lp, true, transit, false);
wtoken.updateReportedVisibilityLocked();
wtoken.showAllWindowsLocked();
@@ -8176,6 +8897,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
"Now closing app" + wtoken);
wtoken.inPendingTransaction = false;
+ wtoken.animation = null;
setTokenVisibilityLocked(wtoken, lp, false, transit, false);
wtoken.updateReportedVisibilityLocked();
// Force the allDrawn flag, because we want to start
@@ -8199,6 +8921,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
restart = true;
}
}
+
+ if (wallpaperMayChange) {
+ if (adjustWallpaperWindowsLocked()) {
+ assignLayersLocked();
+ }
+ }
+
} while (restart);
// THIRD LOOP: Update the surfaces of all windows.
@@ -8464,8 +9193,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
focusDisplayed = true;
}
+ final boolean obscuredChanged = w.mObscured != obscured;
+
// Update effect.
- if (!obscured) {
+ if (!(w.mObscured=obscured)) {
if (w.mSurface != null) {
if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
holdScreen = w.mSession;
@@ -8482,7 +9213,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
boolean opaqueDrawn = w.isOpaqueDrawn();
- if (opaqueDrawn && w.isFullscreen(dw, dh)) {
+ if ((opaqueDrawn && w.isFullscreen(dw, dh))
+ || attrs.type == TYPE_WALLPAPER) {
// This window completely covers everything behind it,
// so we want to leave all of them as unblurred (for
// performance reasons).
@@ -8564,6 +9296,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
+
+ if (obscuredChanged && mWallpaperTarget == w) {
+ // This is the wallpaper target and its obscured state
+ // changed... make sure the current wallaper's visibility
+ // has been updated accordingly.
+ updateWallpaperVisibilityLocked();
+ }
}
if (backgroundFillerShown == false && mBackgroundFillerShown) {
@@ -8630,6 +9369,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
// Destroy the surface of any windows that are no longer visible.
+ boolean wallpaperDestroyed = false;
i = mDestroySurface.size();
if (i > 0) {
do {
@@ -8639,6 +9379,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (mInputMethodWindow == win) {
mInputMethodWindow = null;
}
+ if (win == mWallpaperTarget) {
+ wallpaperDestroyed = true;
+ }
win.destroySurfaceLocked();
} while (i > 0);
mDestroySurface.clear();
@@ -8649,6 +9392,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
WindowToken token = mExitingTokens.get(i);
if (!token.hasVisible) {
mExitingTokens.remove(i);
+ if (token.windowType == TYPE_WALLPAPER) {
+ mWallpaperTokens.remove(token);
+ }
}
}
@@ -8664,7 +9410,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (focusDisplayed) {
mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
}
- if (animating) {
+ if (wallpaperDestroyed) {
+ wallpaperDestroyed = adjustWallpaperWindowsLocked();
+ }
+ if (wallpaperDestroyed) {
+ requestAnimationLocked(0);
+ } else if (animating) {
requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
}
mQueue.setHoldScreenLocked(holdScreen != null);
@@ -9071,6 +9822,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.println(mTokenList.get(i));
}
}
+ if (mWallpaperTokens.size() > 0) {
+ pw.println(" ");
+ pw.println(" Wallpaper tokens:");
+ for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
+ WindowToken token = mWallpaperTokens.get(i);
+ pw.print(" Wallpaper #"); pw.print(i);
+ pw.print(' '); pw.print(token); pw.println(':');
+ token.dump(pw, " ");
+ }
+ }
if (mAppTokens.size() > 0) {
pw.println(" ");
pw.println(" Application tokens in Z order:");
@@ -9115,6 +9876,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.print(" mFocusedApp="); pw.println(mFocusedApp);
pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget);
pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
+ pw.print(" mWallpaperTarget="); pw.println(mWallpaperTarget);
+ if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
+ pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
+ pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
+ }
pw.print(" mInTouchMode="); pw.println(mInTouchMode);
pw.print(" mSystemBooted="); pw.print(mSystemBooted);
pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
@@ -9126,7 +9892,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.print( " no DimAnimator ");
}
pw.print(" mInputMethodAnimLayerAdjustment=");
- pw.println(mInputMethodAnimLayerAdjustment);
+ pw.print(mInputMethodAnimLayerAdjustment);
+ pw.print(" mWallpaperAnimLayerAdjustment=");
+ pw.println(mWallpaperAnimLayerAdjustment);
+ pw.print(" mLastWallpaperX="); pw.print(mLastWallpaperX);
+ pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
@@ -9166,6 +9936,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
synchronized (mKeyWaiter) { }
}
+ public void virtualKeyFeedback(KeyEvent event) {
+ mPolicy.keyFeedbackFromInput(event);
+ }
+
/**
* DimAnimator class that controls the dim animation. This holds the surface and
* all state used for dim animation.
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5d34d00..d4e69c0 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -39,8 +39,10 @@ import android.app.IInstrumentationWatcher;
import android.app.IServiceConnection;
import android.app.IThumbnailReceiver;
import android.app.Instrumentation;
+import android.app.Notification;
import android.app.PendingIntent;
import android.app.ResultInfo;
+import android.app.Service;
import android.backup.IBackupManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -334,6 +336,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Memory pages are 4K.
static final int PAGE_SIZE = 4*1024;
+ // System property defining error report receiver for system apps
+ static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
+
+ // System property defining default error report receiver
+ static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
+
// Corresponding memory levels for above adjustments.
final int EMPTY_APP_MEM;
final int HIDDEN_APP_MEM;
@@ -763,6 +771,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
String mTopData;
boolean mSystemReady = false;
boolean mBooting = false;
+ boolean mWaitingUpdate = false;
+ boolean mDidUpdate = false;
Context mContext;
@@ -980,6 +990,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
res.set(0);
}
}
+
+ ensureBootCompleted();
} break;
case SHOW_NOT_RESPONDING_MSG: {
synchronized (ActivityManagerService.this) {
@@ -1000,13 +1012,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
proc.anrDialog = d;
}
- ensureScreenEnabled();
+ ensureBootCompleted();
} break;
case SHOW_FACTORY_ERROR_MSG: {
Dialog d = new FactoryErrorDialog(
mContext, msg.getData().getCharSequence("msg"));
d.show();
- enableScreenAfterBoot();
+ ensureBootCompleted();
} break;
case UPDATE_CONFIGURATION_MSG: {
final ContentResolver resolver = mContext.getContentResolver();
@@ -1850,12 +1862,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
- "activity", r.intent.getComponent());
+ "activity", r.intent.getComponent(), false);
}
private final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
- String hostingType, ComponentName hostingName) {
+ String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
ProcessRecord app = getProcessRecordLocked(processName, info.uid);
// We don't have to do anything more if:
// (1) There is an existing application record; and
@@ -1908,7 +1920,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// If the system is not ready yet, then hold off on starting this
// process until it is.
if (!mSystemReady
- && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ && !isAllowedWhileBooting(info)
+ && !allowWhileBooting) {
if (!mProcessesOnHold.contains(app)) {
mProcessesOnHold.add(app);
}
@@ -1919,6 +1932,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return (app.pid != 0) ? app : null;
}
+ boolean isAllowedWhileBooting(ApplicationInfo ai) {
+ return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
+ }
+
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
if (app.pid > 0 && app.pid != MY_PID) {
@@ -2898,7 +2915,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* or null if none was found.
*/
private final HistoryRecord performClearTaskLocked(int taskId,
- HistoryRecord newR, boolean doClear) {
+ HistoryRecord newR, int launchFlags, boolean doClear) {
int i = mHistory.size();
// First find the requested task.
@@ -2941,7 +2958,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Finally, if this is a normal launch mode (that is, not
// expecting onNewIntent()), then we will finish the current
// instance of the activity so a new fresh one can be started.
- if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
+ if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
+ && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
if (!ret.finishing) {
int index = indexOfTokenLocked(ret);
if (index >= 0) {
@@ -3338,7 +3356,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// cases this means we are resetting the task to its
// initial state.
HistoryRecord top = performClearTaskLocked(
- taskTop.task.taskId, r, true);
+ taskTop.task.taskId, r, launchFlags, true);
if (top != null) {
if (top.frontOfTask) {
// Activity aliases may mean we use different
@@ -3481,7 +3499,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// task, but the caller has asked to clear that task if the
// activity is already running.
HistoryRecord top = performClearTaskLocked(
- sourceRecord.task.taskId, r, true);
+ sourceRecord.task.taskId, r, launchFlags, true);
if (top != null) {
logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
deliverNewIntentLocked(top, r.intent);
@@ -5101,8 +5119,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
- List providers = generateApplicationProvidersLocked(app);
+ boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
+ List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
+ if (!normalMode) {
+ Log.i(TAG, "Launching preboot mode app: " + app);
+ }
+
if (localLOGV) Log.v(
TAG, "New app record " + app
+ " thread=" + thread.asBinder() + " pid=" + pid);
@@ -5118,12 +5141,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mWaitForDebugger = mOrigWaitForDebugger;
}
}
+
// If the app is being launched for restore or full backup, set it up specially
boolean isRestrictedBackupMode = false;
if (mBackupTarget != null && mBackupAppName.equals(processName)) {
isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
|| (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
}
+
ensurePackageDexOpt(app.instrumentationInfo != null
? app.instrumentationInfo.packageName
: app.info.packageName);
@@ -5134,7 +5159,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
- isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
+ isRestrictedBackupMode || !normalMode,
+ mConfiguration, getCommonServicesLocked());
updateLRUListLocked(app, false);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
@@ -5300,6 +5326,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
void enableScreenAfterBoot() {
+ EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
+ SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
}
@@ -5410,26 +5438,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (booting) {
- // Ensure that any processes we had put on hold are now started
- // up.
- final int NP = mProcessesOnHold.size();
- if (NP > 0) {
- ArrayList<ProcessRecord> procs =
- new ArrayList<ProcessRecord>(mProcessesOnHold);
- for (int ip=0; ip<NP; ip++) {
- this.startProcessLocked(procs.get(ip), "on-hold", null);
- }
- }
- if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
- // Tell anyone interested that we are done booting!
- synchronized (this) {
- broadcastIntentLocked(null, null,
- new Intent(Intent.ACTION_BOOT_COMPLETED, null),
- null, null, 0, null, null,
- android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
- false, false, MY_PID, Process.SYSTEM_UID);
- }
- }
+ finishBooting();
}
trimApplications();
@@ -5437,22 +5446,48 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
//mWindowManager.dump();
if (enableScreen) {
- EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
- SystemClock.uptimeMillis());
enableScreenAfterBoot();
}
}
- final void ensureScreenEnabled() {
+ final void finishBooting() {
+ // Ensure that any processes we had put on hold are now started
+ // up.
+ final int NP = mProcessesOnHold.size();
+ if (NP > 0) {
+ ArrayList<ProcessRecord> procs =
+ new ArrayList<ProcessRecord>(mProcessesOnHold);
+ for (int ip=0; ip<NP; ip++) {
+ this.startProcessLocked(procs.get(ip), "on-hold", null);
+ }
+ }
+ if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+ // Tell anyone interested that we are done booting!
+ synchronized (this) {
+ broadcastIntentLocked(null, null,
+ new Intent(Intent.ACTION_BOOT_COMPLETED, null),
+ null, null, 0, null, null,
+ android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
+ false, false, MY_PID, Process.SYSTEM_UID);
+ }
+ }
+ }
+
+ final void ensureBootCompleted() {
+ boolean booting;
boolean enableScreen;
synchronized (this) {
+ booting = mBooting;
+ mBooting = false;
enableScreen = !mBooted;
mBooted = true;
}
+
+ if (booting) {
+ finishBooting();
+ }
if (enableScreen) {
- EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
- SystemClock.uptimeMillis());
enableScreenAfterBoot();
}
}
@@ -5604,6 +5639,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+ if (type == INTENT_SENDER_BROADCAST) {
+ if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
+ throw new IllegalArgumentException(
+ "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
+ }
+ }
+
synchronized(this) {
int callingUid = Binder.getCallingUid();
try {
@@ -7414,7 +7456,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ProcessRecord proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
- cpi.name));
+ cpi.name), false);
if (proc == null) {
Log.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
@@ -8141,17 +8183,93 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mSystemReady) {
return;
}
+
+ // Check to see if there are any update receivers to run.
+ if (!mDidUpdate) {
+ if (mWaitingUpdate) {
+ return;
+ }
+ Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
+ List<ResolveInfo> ris = null;
+ try {
+ ris = ActivityThread.getPackageManager().queryIntentReceivers(
+ intent, null, 0);
+ } catch (RemoteException e) {
+ }
+ if (ris != null) {
+ for (int i=ris.size()-1; i>=0; i--) {
+ if ((ris.get(i).activityInfo.applicationInfo.flags
+ &ApplicationInfo.FLAG_SYSTEM) == 0) {
+ ris.remove(i);
+ }
+ }
+ intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
+ for (int i=0; i<ris.size(); i++) {
+ ActivityInfo ai = ris.get(i).activityInfo;
+ intent.setComponent(new ComponentName(ai.packageName, ai.name));
+ IIntentReceiver finisher = null;
+ if (i == 0) {
+ finisher = new IIntentReceiver.Stub() {
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered)
+ throws RemoteException {
+ synchronized (ActivityManagerService.this) {
+ mDidUpdate = true;
+ }
+ systemReady();
+ }
+ };
+ }
+ Log.i(TAG, "Sending system update to: " + intent.getComponent());
+ broadcastIntentLocked(null, null, intent, null, finisher,
+ 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
+ if (i == 0) {
+ mWaitingUpdate = true;
+ }
+ }
+ }
+ if (mWaitingUpdate) {
+ return;
+ }
+ mDidUpdate = true;
+ }
+
mSystemReady = true;
if (!mStartRunning) {
return;
}
}
+ ArrayList<ProcessRecord> procsToKill = null;
+ synchronized(mPidsSelfLocked) {
+ for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
+ ProcessRecord proc = mPidsSelfLocked.valueAt(i);
+ if (!isAllowedWhileBooting(proc.info)){
+ if (procsToKill == null) {
+ procsToKill = new ArrayList<ProcessRecord>();
+ }
+ procsToKill.add(proc);
+ }
+ }
+ }
+
+ if (procsToKill != null) {
+ synchronized(this) {
+ for (int i=procsToKill.size()-1; i>=0; i--) {
+ ProcessRecord proc = procsToKill.get(i);
+ Log.i(TAG, "Removing system update proc: " + proc);
+ removeProcessLocked(proc, true);
+ }
+ }
+ }
+
if (Config.LOGD) Log.d(TAG, "Start running!");
EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
SystemClock.uptimeMillis());
synchronized(this) {
+ // Make sure we have no pre-ready processes sitting around.
+
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
ResolveInfo ri = mContext.getPackageManager()
.resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
@@ -8209,6 +8327,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ // Start up initial activity.
+ mBooting = true;
+
try {
if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
Message msg = Message.obtain();
@@ -8218,8 +8339,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (RemoteException e) {
}
- // Start up initial activity.
- mBooting = true;
resumeTopActivityLocked(null);
}
}
@@ -8236,27 +8355,62 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private ComponentName getErrorReportReceiver(ProcessRecord app) {
IPackageManager pm = ActivityThread.getPackageManager();
+
try {
- // was an installer package name specified when this app was
- // installed?
- String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
- if (installerPackageName == null) {
- return null;
+ // look for receiver in the installer package
+ String candidate = pm.getInstallerPackageName(app.info.packageName);
+ ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
+ if (result != null) {
+ return result;
}
- // is there an Activity in this package that handles ACTION_APP_ERROR?
- Intent intent = new Intent(Intent.ACTION_APP_ERROR);
- intent.setPackage(installerPackageName);
- ResolveInfo info = pm.resolveIntent(intent, null, 0);
- if (info == null || info.activityInfo == null) {
- return null;
+ // if the error app is on the system image, look for system apps
+ // error receiver
+ if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+ candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
+ result = getErrorReportReceiver(pm, app.info.packageName, candidate);
+ if (result != null) {
+ return result;
+ }
}
- return new ComponentName(installerPackageName, info.activityInfo.name);
+ // if there is a default receiver, try that
+ candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
+ return getErrorReportReceiver(pm, app.info.packageName, candidate);
} catch (RemoteException e) {
- // will return null and no error report will be delivered
+ // should not happen
+ Log.e(TAG, "error talking to PackageManager", e);
+ return null;
}
- return null;
+ }
+
+ /**
+ * Return activity in receiverPackage that handles ACTION_APP_ERROR.
+ *
+ * @param pm PackageManager isntance
+ * @param errorPackage package which caused the error
+ * @param receiverPackage candidate package to receive the error
+ * @return activity component within receiverPackage which handles
+ * ACTION_APP_ERROR, or null if not found
+ */
+ private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
+ String receiverPackage) throws RemoteException {
+ if (receiverPackage == null || receiverPackage.length() == 0) {
+ return null;
+ }
+
+ // break the loop if it's the error report receiver package that crashed
+ if (receiverPackage.equals(errorPackage)) {
+ return null;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_APP_ERROR);
+ intent.setPackage(receiverPackage);
+ ResolveInfo info = pm.resolveIntent(intent, null, 0);
+ if (info == null || info.activityInfo == null) {
+ return null;
+ }
+ return new ComponentName(receiverPackage, info.activityInfo.name);
}
void makeAppNotRespondingLocked(ProcessRecord app,
@@ -8578,6 +8732,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
report.crashInfo.throwFileName = trace.getFileName();
report.crashInfo.throwClassName = trace.getClassName();
report.crashInfo.throwMethodName = trace.getMethodName();
+ report.crashInfo.throwLineNumber = trace.getLineNumber();
} else if (r.notResponding) {
report.type = ApplicationErrorReport.TYPE_ANR;
report.anrInfo = new ApplicationErrorReport.AnrInfo();
@@ -9384,7 +9539,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
sr.app = null;
sr.executeNesting = 0;
mStoppingServices.remove(sr);
- if (sr.bindings.size() > 0) {
+
+ boolean hasClients = sr.bindings.size() > 0;
+ if (hasClients) {
Iterator<IntentBindRecord> bindings
= sr.bindings.values().iterator();
while (bindings.hasNext()) {
@@ -9405,7 +9562,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} else if (!allowRestart) {
bringDownServiceLocked(sr, true);
} else {
- scheduleServiceRestartLocked(sr);
+ boolean canceled = scheduleServiceRestartLocked(sr, true);
+
+ // Should the service remain running? Note that in the
+ // extreme case of so many attempts to deliver a command
+ // that it failed, that we also will stop it here.
+ if (sr.startRequested && (sr.stopIfKilled || canceled)) {
+ if (sr.pendingStarts.size() == 0) {
+ sr.startRequested = false;
+ if (!hasClients) {
+ // Whoops, no reason to restart!
+ bringDownServiceLocked(sr, true);
+ }
+ }
+ }
}
}
@@ -9844,35 +10014,55 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final void sendServiceArgsLocked(ServiceRecord r,
boolean oomAdjusted) {
- final int N = r.startArgs.size();
+ final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
- final int BASEID = r.lastStartId - N + 1;
int i = 0;
while (i < N) {
try {
- Intent args = r.startArgs.get(i);
+ ServiceRecord.StartItem si = r.pendingStarts.get(i);
if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
- + r.name + " " + r.intent + " args=" + args);
+ + r.name + " " + r.intent + " args=" + si.intent);
+ if (si.intent == null && N > 0) {
+ // If somehow we got a dummy start at the front, then
+ // just drop it here.
+ i++;
+ continue;
+ }
bumpServiceExecutingLocked(r);
if (!oomAdjusted) {
oomAdjusted = true;
updateOomAdjLocked(r.app);
}
- r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
+ int flags = 0;
+ if (si.deliveryCount > 0) {
+ flags |= Service.START_FLAG_RETRY;
+ }
+ if (si.doneExecutingCount > 0) {
+ flags |= Service.START_FLAG_REDELIVERY;
+ }
+ r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
+ si.deliveredTime = SystemClock.uptimeMillis();
+ r.deliveredStarts.add(si);
+ si.deliveryCount++;
i++;
+ } catch (RemoteException e) {
+ // Remote process gone... we'll let the normal cleanup take
+ // care of this.
+ break;
} catch (Exception e) {
+ Log.w(TAG, "Unexpected exception", e);
break;
}
}
if (i == N) {
- r.startArgs.clear();
+ r.pendingStarts.clear();
} else {
while (i > 0) {
- r.startArgs.remove(0);
i--;
+ r.pendingStarts.remove(i);
}
}
}
@@ -9936,36 +10126,81 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
ensurePackageDexOpt(r.serviceInfo.packageName);
app.thread.scheduleCreateService(r, r.serviceInfo);
+ r.postNotification();
created = true;
} finally {
if (!created) {
app.services.remove(r);
- scheduleServiceRestartLocked(r);
+ scheduleServiceRestartLocked(r, false);
}
}
requestServiceBindingsLocked(r);
+
+ // If the service is in the started state, and there are no
+ // pending arguments, then fake up one so its onStartCommand() will
+ // be called.
+ if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
+ r.lastStartId++;
+ if (r.lastStartId < 1) {
+ r.lastStartId = 1;
+ }
+ r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
+ }
+
sendServiceArgsLocked(r, true);
}
- private final void scheduleServiceRestartLocked(ServiceRecord r) {
+ private final boolean scheduleServiceRestartLocked(ServiceRecord r,
+ boolean allowCancel) {
+ boolean canceled = false;
+
final long now = SystemClock.uptimeMillis();
+ long minDuration = SERVICE_RESTART_DURATION;
+ long resetTime = SERVICE_RESET_RUN_DURATION;
+
+ // Any delivered but not yet finished starts should be put back
+ // on the pending list.
+ final int N = r.deliveredStarts.size();
+ if (N > 0) {
+ for (int i=N-1; i>=0; i--) {
+ ServiceRecord.StartItem si = r.deliveredStarts.get(i);
+ if (si.intent == null) {
+ // We'll generate this again if needed.
+ } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
+ && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
+ r.pendingStarts.add(0, si);
+ long dur = SystemClock.uptimeMillis() - si.deliveredTime;
+ dur *= 2;
+ if (minDuration < dur) minDuration = dur;
+ if (resetTime < dur) resetTime = dur;
+ } else {
+ Log.w(TAG, "Canceling start item " + si.intent + " in service "
+ + r.name);
+ canceled = true;
+ }
+ }
+ r.deliveredStarts.clear();
+ }
r.totalRestartCount++;
if (r.restartDelay == 0) {
r.restartCount++;
- r.restartDelay = SERVICE_RESTART_DURATION;
+ r.restartDelay = minDuration;
} else {
// If it has been a "reasonably long time" since the service
// was started, then reset our restart duration back to
// the beginning, so we don't infinitely increase the duration
// on a service that just occasionally gets killed (which is
// a normal case, due to process being killed to reclaim memory).
- if (now > (r.restartTime+SERVICE_RESET_RUN_DURATION)) {
+ if (now > (r.restartTime+resetTime)) {
r.restartCount = 1;
- r.restartDelay = SERVICE_RESTART_DURATION;
+ r.restartDelay = minDuration;
} else {
r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
+ if (r.restartDelay < minDuration) {
+ r.restartDelay = minDuration;
+ }
}
}
@@ -9994,6 +10229,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mRestartingServices.add(r);
}
+ r.cancelNotification();
+
mHandler.removeCallbacks(r.restarter);
mHandler.postAtTime(r.restarter, r.nextRestartTime);
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
@@ -10006,6 +10243,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
msg.what = SERVICE_ERROR_MSG;
msg.obj = r;
mHandler.sendMessage(msg);
+
+ return canceled;
}
final void performServiceRestartLocked(ServiceRecord r) {
@@ -10065,7 +10304,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
if (startProcessLocked(appName, r.appInfo, true, intentFlags,
- "service", r.name) == null) {
+ "service", r.name, false) == null) {
Log.w(TAG, "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
@@ -10162,13 +10401,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ r.cancelNotification();
+ r.isForeground = false;
+ r.foregroundId = 0;
+ r.foregroundNoti = null;
+
+ // Clear start entries.
+ r.deliveredStarts.clear();
+ r.pendingStarts.clear();
+
if (r.app != null) {
synchronized (r.stats.getBatteryStats()) {
r.stats.stopLaunchedLocked();
}
r.app.services.remove(r);
if (r.app.thread != null) {
- updateServiceForegroundLocked(r.app, false);
try {
Log.i(TAG, "Stopping service: " + r.shortName);
bumpServiceExecutingLocked(r);
@@ -10180,6 +10427,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ r.shortName, e);
serviceDoneExecutingLocked(r, true);
}
+ updateServiceForegroundLocked(r.app, false);
} else {
if (DEBUG_SERVICE) Log.v(
TAG, "Removed service that has no process: " + r.shortName);
@@ -10223,11 +10471,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ r.shortName);
}
r.startRequested = true;
- r.startArgs.add(service);
+ r.callStart = false;
r.lastStartId++;
if (r.lastStartId < 1) {
r.lastStartId = 1;
}
+ r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
r.lastActivity = SystemClock.uptimeMillis();
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
@@ -10295,6 +10544,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.record.stats.stopRunningLocked();
}
r.record.startRequested = false;
+ r.record.callStart = false;
final long origId = Binder.clearCallingIdentity();
bringDownServiceLocked(r.record, false);
Binder.restoreCallingIdentity(origId);
@@ -10343,10 +10593,35 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
+ " " + token + " startId=" + startId);
ServiceRecord r = findServiceLocked(className, token);
- if (r != null && (startId < 0 || r.lastStartId == startId)) {
+ if (r != null) {
+ if (startId >= 0) {
+ // Asked to only stop if done with all work. Note that
+ // to avoid leaks, we will take this as dropping all
+ // start items up to and including this one.
+ ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
+ if (si != null) {
+ while (r.deliveredStarts.size() > 0) {
+ if (r.deliveredStarts.remove(0) == si) {
+ break;
+ }
+ }
+ }
+
+ if (r.lastStartId != startId) {
+ return false;
+ }
+
+ if (r.deliveredStarts.size() > 0) {
+ Log.w(TAG, "stopServiceToken startId " + startId
+ + " is last, but have " + r.deliveredStarts.size()
+ + " remaining args");
+ }
+ }
+
synchronized (r.stats.getBatteryStats()) {
r.stats.stopRunningLocked();
r.startRequested = false;
+ r.callStart = false;
}
final long origId = Binder.clearCallingIdentity();
bringDownServiceLocked(r, false);
@@ -10358,20 +10633,45 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
public void setServiceForeground(ComponentName className, IBinder token,
- boolean isForeground) {
+ int id, Notification notification, boolean removeNotification) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
synchronized(this) {
ServiceRecord r = findServiceLocked(className, token);
if (r != null) {
- if (r.isForeground != isForeground) {
- final long origId = Binder.clearCallingIdentity();
- r.isForeground = isForeground;
+ if (id != 0) {
+ if (notification == null) {
+ throw new IllegalArgumentException("null notification");
+ }
+ if (r.foregroundId != id) {
+ r.cancelNotification();
+ r.foregroundId = id;
+ }
+ notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ r.foregroundNoti = notification;
+ r.isForeground = true;
+ r.postNotification();
if (r.app != null) {
updateServiceForegroundLocked(r.app, true);
}
- Binder.restoreCallingIdentity(origId);
+ } else {
+ if (r.isForeground) {
+ r.isForeground = false;
+ if (r.app != null) {
+ updateServiceForegroundLocked(r.app, true);
+ }
+ }
+ if (removeNotification) {
+ r.cancelNotification();
+ r.foregroundId = 0;
+ r.foregroundNoti = null;
+ }
}
}
}
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
@@ -10665,7 +10965,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- public void serviceDoneExecuting(IBinder token) {
+ public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
@@ -10683,6 +10983,51 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return;
}
+ if (type == 1) {
+ // This is a call from a service start... take care of
+ // book-keeping.
+ r.callStart = true;
+ switch (res) {
+ case Service.START_STICKY_COMPATIBILITY:
+ case Service.START_STICKY: {
+ // We are done with the associated start arguments.
+ r.findDeliveredStart(startId, true);
+ // Don't stop if killed.
+ r.stopIfKilled = false;
+ break;
+ }
+ case Service.START_NOT_STICKY: {
+ // We are done with the associated start arguments.
+ r.findDeliveredStart(startId, true);
+ if (r.lastStartId == startId) {
+ // There is no more work, and this service
+ // doesn't want to hang around if killed.
+ r.stopIfKilled = true;
+ }
+ break;
+ }
+ case Service.START_REDELIVER_INTENT: {
+ // We'll keep this item until they explicitly
+ // call stop for it, but keep track of the fact
+ // that it was delivered.
+ ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
+ if (si != null) {
+ si.deliveryCount = 0;
+ si.doneExecutingCount++;
+ // Don't stop if killed.
+ r.stopIfKilled = true;
+ }
+ break;
+ }
+ default:
+ throw new IllegalArgumentException(
+ "Unknown service start result: " + res);
+ }
+ if (res == Service.START_STICKY_COMPATIBILITY) {
+ r.callStart = false;
+ }
+ }
+
final long origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inStopping);
Binder.restoreCallingIdentity(origId);
@@ -10761,7 +11106,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
// startProcessLocked() returns existing proc's record if it's already running
ProcessRecord proc = startProcessLocked(app.processName, app,
- false, 0, "backup", hostingName);
+ false, 0, "backup", hostingName, false);
if (proc == null) {
Log.e(TAG, "Unable to start backup agent process " + r);
return false;
@@ -11298,10 +11643,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized(this) {
+ int flags = intent.getFlags();
+
if (!mSystemReady) {
// if the caller really truly claims to know what they're doing, go
// ahead and allow the broadcast without launching any receivers
- int flags = intent.getFlags();
if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
intent = new Intent(intent);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -11312,6 +11658,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
+ throw new IllegalArgumentException(
+ "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
+ }
+
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
@@ -11906,12 +12257,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// restart the application.
}
- // Not running -- get it started, and enqueue this history record
- // to be executed when the app comes up.
+ // Not running -- get it started, to be executed when the app comes up.
if ((r.curApp=startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
- "broadcast", r.curComponent)) == null) {
+ "broadcast", r.curComponent,
+ (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
+ == null) {
// Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next.
Log.w(TAG, "Unable to launch app "
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index c834b34..ed0d534 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -260,6 +260,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
enforceCallingPermission();
synchronized (mStats) {
mStats.noteBluetoothOnLocked();
+ mStats.setBtHeadset(new android.bluetooth.BluetoothHeadset(mContext, null));
}
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 98df4b3..2534410 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -18,12 +18,16 @@ package com.android.server.am;
import com.android.internal.os.BatteryStatsImpl;
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.SystemClock;
import java.io.PrintWriter;
@@ -60,13 +64,38 @@ class ServiceRecord extends Binder {
final HashMap<IBinder, ConnectionRecord> connections
= new HashMap<IBinder, ConnectionRecord>();
// IBinder -> ConnectionRecord of all bound clients
- final List<Intent> startArgs = new ArrayList<Intent>();
+
+ // Maximum number of delivery attempts before giving up.
+ static final int MAX_DELIVERY_COUNT = 3;
+
+ // Maximum number of times it can fail during execution before giving up.
+ static final int MAX_DONE_EXECUTING_COUNT = 6;
+
+ static class StartItem {
+ final int id;
+ final Intent intent;
+ long deliveredTime;
+ int deliveryCount;
+ int doneExecutingCount;
+
+ StartItem(int _id, Intent _intent) {
+ id = _id;
+ intent = _intent;
+ }
+ }
+ final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
+ // start() arguments which been delivered.
+ final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
// start() arguments that haven't yet been delivered.
- ProcessRecord app; // where this service is running or null.
- boolean isForeground; // asked to run as a foreground service?
+ ProcessRecord app; // where this service is running or null.
+ boolean isForeground; // is service currently in foreground mode?
+ int foregroundId; // Notification ID of last foreground req.
+ Notification foregroundNoti; // Notification record of foreground state.
long lastActivity; // last time there was some activity on the service.
boolean startRequested; // someone explicitly called start?
+ boolean stopIfKilled; // last onStart() said to stop if service killed?
+ boolean callStart; // last onStart() has asked to alway be called on restart.
int lastStartId; // identifier of most recent start request.
int executeNesting; // number of outstanding operations keeping foreground.
long executingStart; // start time of last execute request.
@@ -79,6 +108,25 @@ class ServiceRecord extends Binder {
String stringName; // caching of toString
+ void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) {
+ final int N = list.size();
+ for (int i=0; i<N; i++) {
+ StartItem si = list.get(i);
+ pw.print(prefix); pw.print("#"); pw.print(i);
+ pw.print(" id="); pw.print(si.id);
+ if (now != 0) pw.print(" dur="); pw.print(now-si.deliveredTime);
+ if (si.deliveryCount != 0) {
+ pw.print(" dc="); pw.print(si.deliveryCount);
+ }
+ if (si.doneExecutingCount != 0) {
+ pw.print(" dxc="); pw.print(si.doneExecutingCount);
+ }
+ pw.print(" ");
+ if (si.intent != null) pw.println(si.intent.toString());
+ else pw.println("null");
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("intent={");
pw.print(intent.getIntent().toShortString(true, false));
@@ -93,20 +141,39 @@ class ServiceRecord extends Binder {
if (!resDir.equals(baseDir)) pw.print(" resDir="); pw.print(resDir);
pw.print(" dataDir="); pw.println(dataDir);
pw.print(prefix); pw.print("app="); pw.println(app);
- pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
- pw.print(" lastActivity="); pw.println(lastActivity-now);
- pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
- pw.print(" startId="); pw.print(lastStartId);
- pw.print(" executeNesting="); pw.print(executeNesting);
+ if (isForeground || foregroundId != 0) {
+ pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
+ pw.print(" foregroundId="); pw.print(foregroundId);
+ pw.print(" foregroundNoti="); pw.println(foregroundNoti);
+ }
+ pw.print(prefix); pw.print("lastActivity="); pw.print(lastActivity-now);
pw.print(" executingStart="); pw.print(executingStart-now);
- pw.print(" crashCount="); pw.println(crashCount);
- pw.print(prefix); pw.print("totalRestartCount="); pw.print(totalRestartCount);
- pw.print(" restartCount="); pw.print(restartCount);
- pw.print(" restartDelay="); pw.print(restartDelay);
- pw.print(" restartTime="); pw.print(restartTime-now);
- pw.print(" nextRestartTime="); pw.println(nextRestartTime-now);
+ pw.print(" restartTime="); pw.println(restartTime);
+ if (startRequested || lastStartId != 0) {
+ pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
+ pw.print(" stopIfKilled="); pw.print(stopIfKilled);
+ pw.print(" callStart="); pw.print(callStart);
+ pw.print(" lastStartId="); pw.println(lastStartId);
+ }
+ if (executeNesting != 0 || crashCount != 0 || restartCount != 0
+ || restartDelay != 0 || nextRestartTime != 0) {
+ pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
+ pw.print(" restartCount="); pw.print(restartCount);
+ pw.print(" restartDelay="); pw.print(restartDelay-now);
+ pw.print(" nextRestartTime="); pw.print(nextRestartTime-now);
+ pw.print(" crashCount="); pw.println(crashCount);
+ }
+ if (deliveredStarts.size() > 0) {
+ pw.print(prefix); pw.println("Delivered Starts:");
+ dumpStartList(pw, prefix, deliveredStarts, SystemClock.uptimeMillis());
+ }
+ if (pendingStarts.size() > 0) {
+ pw.print(prefix); pw.println("Pending Starts:");
+ dumpStartList(pw, prefix, pendingStarts, 0);
+ }
if (bindings.size() > 0) {
Iterator<IntentBindRecord> it = bindings.values().iterator();
+ pw.print(prefix); pw.println("Bindings:");
while (it.hasNext()) {
IntentBindRecord b = it.next();
pw.print(prefix); pw.print("* IntentBindRecord{");
@@ -167,6 +234,45 @@ class ServiceRecord extends Binder {
restartTime = 0;
}
+ public StartItem findDeliveredStart(int id, boolean remove) {
+ final int N = deliveredStarts.size();
+ for (int i=0; i<N; i++) {
+ StartItem si = deliveredStarts.get(i);
+ if (si.id == id) {
+ if (remove) deliveredStarts.remove(i);
+ return si;
+ }
+ }
+
+ return null;
+ }
+
+ public void postNotification() {
+ if (foregroundId != 0 && foregroundNoti != null) {
+ INotificationManager inm = NotificationManager.getService();
+ if (inm != null) {
+ try {
+ int[] outId = new int[1];
+ inm.enqueueNotification(packageName, foregroundId,
+ foregroundNoti, outId);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
+ public void cancelNotification() {
+ if (foregroundId != 0) {
+ INotificationManager inm = NotificationManager.getService();
+ if (inm != null) {
+ try {
+ inm.cancelNotification(packageName, foregroundId);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
public String toString() {
if (stringName != null) {
return stringName;
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index d458911..66868a3 100755..100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -695,7 +695,14 @@ public final class UsageStatsService extends IUsageStats.Stub {
if (NC > 0) {
for (Map.Entry<String, TimeStats> ent : pus.mLaunchTimes.entrySet()) {
sb.append("A:");
- sb.append(ent.getKey());
+ String activity = ent.getKey();
+ if (activity.startsWith(pkgName)) {
+ sb.append('*');
+ sb.append(activity.substring(
+ pkgName.length(), activity.length()));
+ } else {
+ sb.append(activity);
+ }
TimeStats times = ent.getValue();
sb.append(',');
sb.append(times.count);
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index a4b47b5..10680dd 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -18,10 +18,11 @@ package com.android.server.status;
import android.app.AlertDialog;
import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothIntent;
+import android.bluetooth.BluetoothPbap;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -76,15 +77,8 @@ public class StatusBarPolicy {
private static StatusBarPolicy sInstance;
// message codes for the handler
- private static final int EVENT_DATA_CONN_STATE_CHANGED = 2;
- 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 final Context mContext;
private final StatusBarService mService;
private final Handler mHandler = new StatusBarHandler();
@@ -99,26 +93,21 @@ public class StatusBarPolicy {
private IBinder mBatteryIcon;
private IconData mBatteryData;
private boolean mBatteryFirst = true;
- private int mBatteryPlugged;
+ 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;
private int mBatteryViewSequence;
private boolean mBatteryShowLowOnEndCall = false;
- private boolean mSentLowBatteryBroadcast = false;
private static final boolean SHOW_LOW_BATTERY_WARNING = true;
// phone
private TelephonyManager mPhone;
private IBinder mPhoneIcon;
- private IBinder mPhoneEvdoIcon;
//***** Signal strength icons
private IconData mPhoneData;
- private IconData mPhoneEvdoData;
//GSM/UMTS
private static final int[] sSignalImages = new int[] {
com.android.internal.R.drawable.stat_sys_signal_0,
@@ -134,14 +123,6 @@ public class StatusBarPolicy {
com.android.internal.R.drawable.stat_sys_r_signal_3,
com.android.internal.R.drawable.stat_sys_r_signal_4
};
- //CDMA
- private static final int[] sSignalImages_cdma = new int[] {
- com.android.internal.R.drawable.stat_sys_signal_cdma_0,
- com.android.internal.R.drawable.stat_sys_signal_cdma_1,
- com.android.internal.R.drawable.stat_sys_signal_cdma_2,
- com.android.internal.R.drawable.stat_sys_signal_cdma_3,
- com.android.internal.R.drawable.stat_sys_signal_cdma_4
- };
private static final int[] sRoamingIndicatorImages_cdma = new int[] {
com.android.internal.R.drawable.stat_sys_roaming_cdma_0, //Standard Roaming Indicator
// 1 is Standard Roaming Indicator OFF
@@ -241,14 +222,6 @@ public class StatusBarPolicy {
// 128-255 Reserved
};
- // EVDO
- private static final int[] sSignalImages_evdo = new int[] {
- com.android.internal.R.drawable.stat_sys_signal_evdo_0,
- com.android.internal.R.drawable.stat_sys_signal_evdo_1,
- com.android.internal.R.drawable.stat_sys_signal_evdo_2,
- com.android.internal.R.drawable.stat_sys_signal_evdo_3,
- com.android.internal.R.drawable.stat_sys_signal_evdo_4
- };
//***** Data connection icons
private int[] mDataIconList = sDataNetType_g;
@@ -271,20 +244,21 @@ public class StatusBarPolicy {
com.android.internal.R.drawable.stat_sys_data_out_e,
com.android.internal.R.drawable.stat_sys_data_inandout_e,
};
- //CDMA
- private static final int[] sDataNetType_evdo = new int[] {
- com.android.internal.R.drawable.stat_sys_data_connected_evdo,
- com.android.internal.R.drawable.stat_sys_data_in_evdo,
- com.android.internal.R.drawable.stat_sys_data_out_evdo,
- com.android.internal.R.drawable.stat_sys_data_inandout_evdo,
- com.android.internal.R.drawable.stat_sys_data_dormant_evdo,
+ //3.5G
+ private static final int[] sDataNetType_h = new int[] {
+ com.android.internal.R.drawable.stat_sys_data_connected_h,
+ com.android.internal.R.drawable.stat_sys_data_in_h,
+ com.android.internal.R.drawable.stat_sys_data_out_h,
+ com.android.internal.R.drawable.stat_sys_data_inandout_h,
};
- private static final int[] sDataNetType_1xrtt = new int[] {
- com.android.internal.R.drawable.stat_sys_data_connected_1xrtt,
- com.android.internal.R.drawable.stat_sys_data_in_1xrtt,
- com.android.internal.R.drawable.stat_sys_data_out_1xrtt,
- com.android.internal.R.drawable.stat_sys_data_inandout_1xrtt,
- com.android.internal.R.drawable.stat_sys_data_dormant_1xrtt,
+
+ //CDMA
+ // Use 3G icons for EVDO data and 1x icons for 1XRTT data
+ private static final int[] sDataNetType_1x = new int[] {
+ com.android.internal.R.drawable.stat_sys_data_connected_1x,
+ com.android.internal.R.drawable.stat_sys_data_in_1x,
+ com.android.internal.R.drawable.stat_sys_data_out_1x,
+ com.android.internal.R.drawable.stat_sys_data_inandout_1x,
};
// Assume it's all good unless we hear otherwise. We don't always seem
@@ -311,6 +285,7 @@ public class StatusBarPolicy {
private IconData mBluetoothData;
private int mBluetoothHeadsetState;
private int mBluetoothA2dpState;
+ private int mBluetoothPbapState;
private boolean mBluetoothEnabled;
// wifi
@@ -363,6 +338,9 @@ public class StatusBarPolicy {
else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
updateClock();
}
+ else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+ updateBattery(intent);
+ }
else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
updateClock();
}
@@ -377,12 +355,17 @@ public class StatusBarPolicy {
else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
updateSyncState(intent);
}
- else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
- updateBattery(intent);
+ else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
+ onBatteryLow(intent);
+ }
+ else if (action.equals(Intent.ACTION_BATTERY_OKAY)
+ || action.equals(Intent.ACTION_POWER_CONNECTED)) {
+ onBatteryOkay(intent);
}
else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
- action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
+ action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION) ||
+ action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
updateBluetooth(intent);
}
else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
@@ -430,12 +413,6 @@ public class StatusBarPolicy {
null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
mPhoneIcon = service.addIcon(mPhoneData, null);
- // phone_evdo_signal
- mPhoneEvdoData = IconData.makeIcon("phone_evdo_signal",
- null, com.android.internal.R.drawable.stat_sys_signal_evdo_0, 0, 0);
- mPhoneEvdoIcon = service.addIcon(mPhoneEvdoData, null);
- service.setIconVisibility(mPhoneEvdoIcon, false);
-
// register for phone state notifications.
((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
.listen(mPhoneStateListener,
@@ -473,15 +450,16 @@ public class StatusBarPolicy {
mBluetoothData = IconData.makeIcon("bluetooth",
null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
mBluetoothIcon = service.addIcon(mBluetoothData, null);
- BluetoothDevice bluetooth =
- (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
- if (bluetooth != null) {
- mBluetoothEnabled = bluetooth.isEnabled();
+ BluetoothAdapter adapter =
+ (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ if (adapter != null) {
+ mBluetoothEnabled = adapter.isEnabled();
} else {
mBluetoothEnabled = false;
}
mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
+ mBluetoothPbapState = BluetoothPbap.STATE_DISCONNECTED;
mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
// Gps status
@@ -490,7 +468,7 @@ public class StatusBarPolicy {
mGpsFixIconData = IconData.makeIcon("gps",
null, com.android.internal.R.drawable.stat_sys_gps_on, 0, 0);
mGpsIcon = service.addIcon(mGpsEnabledIconData, null);
- service.setIconVisibility(mGpsIcon, false);
+ service.setIconVisibility(mGpsIcon, false);
// Alarm clock
mAlarmClockIconData = IconData.makeIcon(
@@ -513,7 +491,7 @@ public class StatusBarPolicy {
mVolumeIcon = service.addIcon(mVolumeData, null);
service.setIconVisibility(mVolumeIcon, false);
updateVolume();
-
+
IntentFilter filter = new IntentFilter();
// Register for Intent broadcasts for...
@@ -521,6 +499,9 @@ 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_BATTERY_OKAY);
+ filter.addAction(Intent.ACTION_POWER_CONNECTED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_ALARM_CHANGED);
filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
@@ -529,6 +510,7 @@ public class StatusBarPolicy {
filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+ filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
@@ -564,38 +546,22 @@ 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);
mService.updateIcon(mBatteryIcon, mBatteryData, null);
- int plugged = intent.getIntExtra("plugged", 0);
+ boolean plugged = intent.getIntExtra("plugged", 0) != 0;
int level = intent.getIntExtra("level", -1);
if (false) {
Log.d(TAG, "updateBattery level=" + level
+ " plugged=" + plugged
+ " mBatteryPlugged=" + mBatteryPlugged
+ " mBatteryLevel=" + mBatteryLevel
- + " mBatteryThreshold=" + mBatteryThreshold
+ " mBatteryFirst=" + mBatteryFirst);
}
- int oldPlugged = mBatteryPlugged;
- int oldThreshold = mBatteryThreshold;
- pickNextBatteryLevel(level);
+ boolean oldPlugged = mBatteryPlugged;
mBatteryPlugged = plugged;
mBatteryLevel = level;
@@ -617,49 +583,35 @@ 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 == 0
- && ((oldPlugged != 0 && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING])
- || (mBatteryThreshold > oldThreshold
- && mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) {
- // Broadcast the low battery warning
- mSentLowBatteryBroadcast = true;
- Intent batIntent = new Intent(Intent.ACTION_BATTERY_LOW);
- batIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcast(batIntent);
-
- 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;
- }
- }
- } else if (mBatteryThreshold < BATTERY_THRESHOLD_WARNING) {
- if (mSentLowBatteryBroadcast == true) {
- mSentLowBatteryBroadcast = false;
- Intent batIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
- batIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcast(batIntent);
+ private void onBatteryLow(Intent intent) {
+ if (SHOW_LOW_BATTERY_WARNING) {
+ if (false) {
+ Log.d(TAG, "mPhoneState=" + mPhoneState
+ + " mLowBatteryDialog=" + mLowBatteryDialog
+ + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
}
- if (SHOW_LOW_BATTERY_WARNING) {
- if (mLowBatteryDialog != null) {
- mLowBatteryDialog.dismiss();
- mBatteryShowLowOnEndCall = false;
- }
+
+ if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+ showLowBatteryWarning();
+ } else {
+ mBatteryShowLowOnEndCall = true;
}
}
}
- private void showBatteryView() {
+ private void onBatteryOkay(Intent intent) {
+ if (mLowBatteryDialog != null
+ && SHOW_LOW_BATTERY_WARNING) {
+ mLowBatteryDialog.dismiss();
+ mBatteryShowLowOnEndCall = false;
+ }
+ }
+
+ private void showBatteryView() {
closeLastBatteryView();
if (mLowBatteryDialog != null) {
mLowBatteryDialog.dismiss();
@@ -720,9 +672,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);
@@ -738,7 +692,7 @@ public class StatusBarPolicy {
b.setView(v);
b.setIcon(android.R.drawable.ic_dialog_alert);
b.setPositiveButton(android.R.string.ok, null);
-
+
final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_MULTIPLE_TASK
@@ -773,7 +727,7 @@ public class StatusBarPolicy {
}
if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
if (mBatteryShowLowOnEndCall) {
- if (mBatteryPlugged == 0) {
+ if (!mBatteryPlugged) {
showLowBatteryWarning();
}
mBatteryShowLowOnEndCall = false;
@@ -826,6 +780,10 @@ public class StatusBarPolicy {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
updateCallState(state);
+ // In cdma, if a voice call is made, RSSI should switch to 1x.
+ if (isCdma()) {
+ updateSignalStrength();
+ }
}
@Override
@@ -854,7 +812,7 @@ public class StatusBarPolicy {
final String lockedReason = intent.getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
mSimState = IccCard.State.PIN_REQUIRED;
- }
+ }
else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
mSimState = IccCard.State.PUK_REQUIRED;
}
@@ -871,6 +829,14 @@ public class StatusBarPolicy {
return ((mPhone != null) && (mPhone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA));
}
+ private boolean isEvdo() {
+ return ( (mServiceState != null)
+ && ((mServiceState.getRadioTechnology()
+ == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
+ || (mServiceState.getRadioTechnology()
+ == ServiceState.RADIO_TECHNOLOGY_EVDO_A)));
+ }
+
private boolean hasService() {
if (mServiceState != null) {
switch (mServiceState.getState()) {
@@ -887,9 +853,7 @@ public class StatusBarPolicy {
private final void updateSignalStrength() {
int iconLevel = -1;
- int evdoIconLevel = -1;
int[] iconList;
- int[] evdoIconList;
if (!hasService()) {
//Log.d(TAG, "updateSignalStrength: no service");
@@ -900,7 +864,6 @@ public class StatusBarPolicy {
mPhoneData.iconId = com.android.internal.R.drawable.stat_sys_signal_null;
}
mService.updateIcon(mPhoneIcon, mPhoneData, null);
- mService.setIconVisibility(mPhoneEvdoIcon,false);
return;
}
@@ -923,65 +886,67 @@ public class StatusBarPolicy {
iconList = sSignalImages;
}
} else {
- iconList = this.sSignalImages_cdma;
-
- int cdmaDbm = mSignalStrength.getCdmaDbm();
- int cdmaEcio = mSignalStrength.getCdmaEcio();
- int levelDbm = 0;
- int levelEcio = 0;
-
- if (cdmaDbm >= -75) levelDbm = 4;
- else if (cdmaDbm >= -85) levelDbm = 3;
- else if (cdmaDbm >= -95) levelDbm = 2;
- else if (cdmaDbm >= -100) levelDbm = 1;
- else levelDbm = 0;
-
- // Ec/Io are in dB*10
- if (cdmaEcio >= -90) levelEcio = 4;
- else if (cdmaEcio >= -110) levelEcio = 3;
- else if (cdmaEcio >= -130) levelEcio = 2;
- else if (cdmaEcio >= -150) levelEcio = 1;
- else levelEcio = 0;
-
- iconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
- }
+ iconList = this.sSignalImages;
- if ((mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
- || (mServiceState.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
- // Use Evdo icon
- evdoIconList = this.sSignalImages_evdo;
-
- int evdoEcio = mSignalStrength.getEvdoEcio();
- int evdoSnr = mSignalStrength.getEvdoSnr();
- int levelEvdoEcio = 0;
- int levelEvdoSnr = 0;
-
- // Ec/Io are in dB*10
- if (evdoEcio >= -650) levelEvdoEcio = 4;
- else if (evdoEcio >= -750) levelEvdoEcio = 3;
- else if (evdoEcio >= -900) levelEvdoEcio = 2;
- else if (evdoEcio >= -1050) levelEvdoEcio = 1;
- else levelEvdoEcio = 0;
-
- if (evdoSnr > 7) levelEvdoSnr = 4;
- else if (evdoSnr > 5) levelEvdoSnr = 3;
- else if (evdoSnr > 3) levelEvdoSnr = 2;
- else if (evdoSnr > 1) levelEvdoSnr = 1;
- else levelEvdoSnr = 0;
-
- evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr;
-
- mPhoneEvdoData.iconId = evdoIconList[evdoIconLevel];
- mService.updateIcon(mPhoneEvdoIcon, mPhoneEvdoData, null);
- mService.setIconVisibility(mPhoneEvdoIcon,true);
- } else {
- mService.setIconVisibility(mPhoneEvdoIcon,false);
+ // If 3G(EV) and 1x network are available than 3G should be
+ // displayed, displayed RSSI should be from the EV side.
+ // If a voice call is made then RSSI should switch to 1x.
+ if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
+ iconLevel = getEvdoLevel();
+ if (false) {
+ Log.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
+ }
+ } else {
+ iconLevel = getCdmaLevel();
+ }
}
-
mPhoneData.iconId = iconList[iconLevel];
mService.updateIcon(mPhoneIcon, mPhoneData, null);
}
+ private int getCdmaLevel() {
+ final int cdmaDbm = mSignalStrength.getCdmaDbm();
+ final int cdmaEcio = mSignalStrength.getCdmaEcio();
+ int levelDbm = 0;
+ int levelEcio = 0;
+
+ if (cdmaDbm >= -75) levelDbm = 4;
+ else if (cdmaDbm >= -85) levelDbm = 3;
+ else if (cdmaDbm >= -95) levelDbm = 2;
+ else if (cdmaDbm >= -100) levelDbm = 1;
+ else levelDbm = 0;
+
+ // Ec/Io are in dB*10
+ if (cdmaEcio >= -90) levelEcio = 4;
+ else if (cdmaEcio >= -110) levelEcio = 3;
+ else if (cdmaEcio >= -130) levelEcio = 2;
+ else if (cdmaEcio >= -150) levelEcio = 1;
+ else levelEcio = 0;
+
+ return (levelDbm < levelEcio) ? levelDbm : levelEcio;
+ }
+
+ private int getEvdoLevel() {
+ int evdoDbm = mSignalStrength.getEvdoDbm();
+ int evdoSnr = mSignalStrength.getEvdoSnr();
+ int levelEvdoDbm = 0;
+ int levelEvdoSnr = 0;
+
+ if (evdoDbm >= -65) levelEvdoDbm = 4;
+ else if (evdoDbm >= -75) levelEvdoDbm = 3;
+ else if (evdoDbm >= -90) levelEvdoDbm = 2;
+ else if (evdoDbm >= -105) levelEvdoDbm = 1;
+ else levelEvdoDbm = 0;
+
+ if (evdoSnr > 7) levelEvdoSnr = 4;
+ else if (evdoSnr > 5) levelEvdoSnr = 3;
+ else if (evdoSnr > 3) levelEvdoSnr = 2;
+ else if (evdoSnr > 1) levelEvdoSnr = 1;
+ else levelEvdoSnr = 0;
+
+ return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
+ }
+
private final void updateDataNetType() {
int net = mPhone.getNetworkType();
@@ -992,16 +957,21 @@ public class StatusBarPolicy {
case TelephonyManager.NETWORK_TYPE_UMTS:
mDataIconList = sDataNetType_3g;
break;
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ mDataIconList = sDataNetType_h;
+ break;
case TelephonyManager.NETWORK_TYPE_CDMA:
// display 1xRTT for IS95A/B
- mDataIconList = this.sDataNetType_1xrtt;
+ mDataIconList = this.sDataNetType_1x;
break;
case TelephonyManager.NETWORK_TYPE_1xRTT:
- mDataIconList = this.sDataNetType_1xrtt;
+ mDataIconList = this.sDataNetType_1x;
break;
case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
case TelephonyManager.NETWORK_TYPE_EVDO_A:
- mDataIconList = sDataNetType_evdo;
+ mDataIconList = sDataNetType_3g;
break;
default:
mDataIconList = sDataNetType_g;
@@ -1054,8 +1024,6 @@ public class StatusBarPolicy {
iconId = mDataIconList[3];
break;
case TelephonyManager.DATA_ACTIVITY_DORMANT:
- iconId = mDataIconList[4];
- break;
default:
iconId = mDataIconList[0];
break;
@@ -1107,20 +1075,24 @@ public class StatusBarPolicy {
if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
BluetoothError.ERROR);
- mBluetoothEnabled = state == BluetoothDevice.BLUETOOTH_STATE_ON;
+ mBluetoothEnabled = state == BluetoothAdapter.BLUETOOTH_STATE_ON;
} else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
BluetoothHeadset.STATE_ERROR);
} else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
BluetoothA2dp.STATE_DISCONNECTED);
+ } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
+ mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
+ BluetoothPbap.STATE_DISCONNECTED);
} else {
return;
}
if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
- mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING) {
+ mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING ||
+ mBluetoothPbapState == BluetoothPbap.STATE_CONNECTED) {
iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
}
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..8e7cadc 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>
@@ -31,6 +31,7 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
+#include <dirent.h>
#if HAVE_ANDROID_OS
#include <linux/ioctl.h>
@@ -38,15 +39,7 @@
namespace android {
-#define AC_ONLINE_PATH "/sys/class/power_supply/ac/online"
-#define USB_ONLINE_PATH "/sys/class/power_supply/usb/online"
-#define BATTERY_STATUS_PATH "/sys/class/power_supply/battery/status"
-#define BATTERY_HEALTH_PATH "/sys/class/power_supply/battery/health"
-#define BATTERY_PRESENT_PATH "/sys/class/power_supply/battery/present"
-#define BATTERY_CAPACITY_PATH "/sys/class/power_supply/battery/capacity"
-#define BATTERY_VOLTAGE_PATH "/sys/class/power_supply/battery/batt_vol"
-#define BATTERY_TEMPERATURE_PATH "/sys/class/power_supply/battery/batt_temp"
-#define BATTERY_TECHNOLOGY_PATH "/sys/class/power_supply/battery/technology"
+#define POWER_SUPPLY_PATH "/sys/class/power_supply"
struct FieldIds {
// members
@@ -77,6 +70,21 @@ struct BatteryManagerConstants {
};
static BatteryManagerConstants gConstants;
+struct PowerSupplyPaths {
+ char* acOnlinePath;
+ char* usbOnlinePath;
+ char* batteryStatusPath;
+ char* batteryHealthPath;
+ char* batteryPresentPath;
+ char* batteryCapacityPath;
+ char* batteryVoltagePath;
+ char* batteryTemperaturePath;
+ char* batteryTechnologyPath;
+};
+static PowerSupplyPaths gPaths;
+
+static int gVoltageDivisor = 1;
+
static jint getBatteryStatus(const char* status)
{
switch (status[0]) {
@@ -126,6 +134,8 @@ static jint getBatteryHealth(const char* status)
static int readFromFile(const char* path, char* buf, size_t size)
{
+ if (!path)
+ return -1;
int fd = open(path, O_RDONLY, 0);
if (fd == -1) {
LOGE("Could not open '%s'", path);
@@ -171,29 +181,43 @@ static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fie
env->SetIntField(obj, fieldID, value);
}
+static void setVoltageField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
+{
+ const int SIZE = 128;
+ char buf[SIZE];
+
+ jint value = 0;
+ if (readFromFile(path, buf, SIZE) > 0) {
+ value = atoi(buf);
+ value /= gVoltageDivisor;
+ }
+ env->SetIntField(obj, fieldID, value);
+}
+
+
static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
{
- setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline);
- setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline);
- setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent);
+ setBooleanField(env, obj, gPaths.acOnlinePath, gFieldIds.mAcOnline);
+ setBooleanField(env, obj, gPaths.usbOnlinePath, gFieldIds.mUsbOnline);
+ setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent);
- setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel);
- setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage);
- setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature);
+ setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel);
+ setVoltageField(env, obj, gPaths.batteryVoltagePath, gFieldIds.mBatteryVoltage);
+ setIntField(env, obj, gPaths.batteryTemperaturePath, gFieldIds.mBatteryTemperature);
const int SIZE = 128;
char buf[SIZE];
- if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0)
+ if (readFromFile(gPaths.batteryStatusPath, buf, SIZE) > 0)
env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
else
env->SetIntField(obj, gFieldIds.mBatteryStatus,
gConstants.statusUnknown);
- if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0)
+ if (readFromFile(gPaths.batteryHealthPath, buf, SIZE) > 0)
env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));
- if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0)
+ if (readFromFile(gPaths.batteryTechnologyPath, buf, SIZE) > 0)
env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
}
@@ -204,6 +228,101 @@ static JNINativeMethod sMethods[] = {
int register_android_server_BatteryService(JNIEnv* env)
{
+ char path[PATH_MAX];
+ struct dirent* entry;
+
+ DIR* dir = opendir(POWER_SUPPLY_PATH);
+ if (dir == NULL) {
+ LOGE("Could not open %s\n", POWER_SUPPLY_PATH);
+ return -1;
+ }
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
+
+ // ignore "." and ".."
+ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+ continue;
+ }
+
+ char buf[20];
+ // Look for "type" file in each subdirectory
+ snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
+ int length = readFromFile(path, buf, sizeof(buf));
+ if (length > 0) {
+ if (buf[length - 1] == '\n')
+ buf[length - 1] = 0;
+
+ if (strcmp(buf, "Mains") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.acOnlinePath = strdup(path);
+ }
+ else if (strcmp(buf, "USB") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.usbOnlinePath = strdup(path);
+ }
+ else if (strcmp(buf, "Battery") == 0) {
+ snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryStatusPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryHealthPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryPresentPath = strdup(path);
+ snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryCapacityPath = strdup(path);
+
+ snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0) {
+ gPaths.batteryVoltagePath = strdup(path);
+ // voltage_now is in microvolts, not millivolts
+ gVoltageDivisor = 1000;
+ } else {
+ snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryVoltagePath = strdup(path);
+ }
+
+ snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0) {
+ gPaths.batteryTemperaturePath = strdup(path);
+ } else {
+ snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryTemperaturePath = strdup(path);
+ }
+
+ snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
+ if (access(path, R_OK) == 0)
+ gPaths.batteryTechnologyPath = strdup(path);
+ }
+ }
+ }
+ closedir(dir);
+
+ if (!gPaths.acOnlinePath)
+ LOGE("acOnlinePath not found");
+ if (!gPaths.usbOnlinePath)
+ LOGE("usbOnlinePath not found");
+ if (!gPaths.batteryStatusPath)
+ LOGE("batteryStatusPath not found");
+ if (!gPaths.batteryHealthPath)
+ LOGE("batteryHealthPath not found");
+ if (!gPaths.batteryPresentPath)
+ LOGE("batteryPresentPath not found");
+ if (!gPaths.batteryCapacityPath)
+ LOGE("batteryCapacityPath not found");
+ if (!gPaths.batteryVoltagePath)
+ LOGE("batteryVoltagePath not found");
+ if (!gPaths.batteryTemperaturePath)
+ LOGE("batteryTemperaturePath not found");
+ if (!gPaths.batteryTechnologyPath)
+ LOGE("batteryTechnologyPath not found");
+
jclass clazz = env->FindClass("com/android/server/BatteryService");
if (clazz == NULL) {
diff --git a/services/jni/com_android_server_HardwareService.cpp b/services/jni/com_android_server_HardwareService.cpp
index b0aab59..22d4bd8 100644
--- a/services/jni/com_android_server_HardwareService.cpp
+++ b/services/jni/com_android_server_HardwareService.cpp
@@ -133,7 +133,7 @@ static void vibratorOff(JNIEnv *env, jobject clazz)
static JNINativeMethod method_table[] = {
{ "init_native", "()I", (void*)init_native },
- { "finalize_native", "(I)V", (void*)init_native },
+ { "finalize_native", "(I)V", (void*)finalize_native },
{ "setLight_native", "(IIIIII)V", (void*)setLight_native },
{ "vibratorOn", "(J)V", (void*)vibratorOn },
{ "vibratorOff", "()V", (void*)vibratorOff }
diff --git a/services/jni/com_android_server_KeyInputQueue.cpp b/services/jni/com_android_server_KeyInputQueue.cpp
index 63830d5..f27596c 100644
--- a/services/jni/com_android_server_KeyInputQueue.cpp
+++ b/services/jni/com_android_server_KeyInputQueue.cpp
@@ -110,6 +110,23 @@ android_server_KeyInputQueue_getDeviceName(JNIEnv* env, jobject clazz,
return NULL;
}
+static void
+android_server_KeyInputQueue_addExcludedDevice(JNIEnv* env, jobject clazz,
+ jstring deviceName)
+{
+ gLock.lock();
+ sp<EventHub> hub = gHub;
+ if (hub == NULL) {
+ hub = new EventHub;
+ gHub = hub;
+ }
+ gLock.unlock();
+
+ const char* nameStr = env->GetStringUTFChars(deviceName, NULL);
+ gHub->addExcludedDevice(nameStr);
+ env->ReleaseStringUTFChars(deviceName, nameStr);
+}
+
static jboolean
android_server_KeyInputQueue_getAbsoluteInfo(JNIEnv* env, jobject clazz,
jint deviceId, jint axis,
@@ -205,6 +222,23 @@ android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz,
return st;
}
+static jint
+android_server_KeyInputQueue_scancodeToKeycode(JNIEnv* env, jobject clazz,
+ jint deviceId, jint scancode)
+{
+ jint res = 0;
+ gLock.lock();
+ if (gHub != NULL) {
+ int32_t keycode;
+ uint32_t flags;
+ gHub->scancodeToKeycode(deviceId, scancode, &keycode, &flags);
+ res = keycode;
+ }
+ gLock.unlock();
+
+ return res;
+}
+
static jboolean
android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz,
jintArray keyCodes, jbooleanArray outFlags)
@@ -238,6 +272,8 @@ static JNINativeMethod gInputMethods[] = {
(void*) android_server_KeyInputQueue_getDeviceClasses },
{ "getDeviceName", "(I)Ljava/lang/String;",
(void*) android_server_KeyInputQueue_getDeviceName },
+ { "addExcludedDevice", "(Ljava/lang/String;)V",
+ (void*) android_server_KeyInputQueue_addExcludedDevice },
{ "getAbsoluteInfo", "(IILcom/android/server/InputDevice$AbsoluteInfo;)Z",
(void*) android_server_KeyInputQueue_getAbsoluteInfo },
{ "getSwitchState", "(I)I",
@@ -254,6 +290,8 @@ static JNINativeMethod gInputMethods[] = {
(void*) android_server_KeyInputQueue_getKeycodeStateDevice },
{ "hasKeys", "([I[Z)Z",
(void*) android_server_KeyInputQueue_hasKeys },
+ { "scancodeToKeycode", "(II)I",
+ (void*) android_server_KeyInputQueue_scancodeToKeycode },
};
int register_android_server_KeyInputQueue(JNIEnv* env)
diff --git a/services/jni/com_android_server_SensorService.cpp b/services/jni/com_android_server_SensorService.cpp
index 7390786..3911d1f 100644
--- a/services/jni/com_android_server_SensorService.cpp
+++ b/services/jni/com_android_server_SensorService.cpp
@@ -111,6 +111,15 @@ android_open(JNIEnv *env, jclass clazz)
return bundle;
}
+static jint
+android_close(JNIEnv *env, jclass clazz)
+{
+ if (sSensorDevice->close_data_source)
+ return sSensorDevice->close_data_source(sSensorDevice);
+ else
+ return 0;
+}
+
static jboolean
android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate)
{
@@ -135,6 +144,7 @@ android_data_wake(JNIEnv *env, jclass clazz)
static JNINativeMethod gMethods[] = {
{"_sensors_control_init", "()I", (void*) android_init },
{"_sensors_control_open", "()Landroid/os/Bundle;", (void*) android_open },
+ {"_sensors_control_close", "()I", (void*) android_close },
{"_sensors_control_activate", "(IZ)Z", (void*) android_activate },
{"_sensors_control_wake", "()I", (void*) android_data_wake },
{"_sensors_control_set_delay","(I)I", (void*) android_set_delay },
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index dbe8431..4368464 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -22,11 +22,17 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.SystemProperties;
import android.provider.Contacts;
+import android.provider.ContactsContract;
import android.text.Editable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
+import android.util.Log;
import android.util.SparseIntArray;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
+
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -56,6 +62,9 @@ public class PhoneNumberUtils
public static final int TOA_International = 0x91;
public static final int TOA_Unknown = 0x81;
+ static final String LOG_TAG = "PhoneNumberUtils";
+ private static final boolean DBG = false;
+
/*
* global-phone-number = ["+"] 1*( DIGIT / written-sep )
* written-sep = ("-"/".")
@@ -129,15 +138,23 @@ public class PhoneNumberUtils
}
String type = intent.resolveType(context);
+ String phoneColumn = null;
+
+ // Correctly read out the phone entry based on requested provider
+ final String authority = uri.getAuthority();
+ if (Contacts.AUTHORITY.equals(authority)) {
+ phoneColumn = Contacts.People.Phones.NUMBER;
+ } else if (ContactsContract.AUTHORITY.equals(authority)) {
+ phoneColumn = ContactsContract.CommonDataKinds.Phone.NUMBER;
+ }
- Cursor c = context.getContentResolver().query(
- uri, new String[]{ Contacts.People.Phones.NUMBER },
- null, null, null);
+ final Cursor c = context.getContentResolver().query(uri, new String[] {
+ phoneColumn
+ }, null, null, null);
if (c != null) {
try {
if (c.moveToFirst()) {
- number = c.getString(
- c.getColumnIndex(Contacts.People.Phones.NUMBER));
+ number = c.getString(c.getColumnIndex(phoneColumn));
}
} finally {
c.close();
@@ -218,6 +235,9 @@ public class PhoneNumberUtils
}
}
+ private static void log(String msg) {
+ Log.d(LOG_TAG, msg);
+ }
/** index of the last character of the network portion
* (eg anything after is a post-dial string)
*/
@@ -732,6 +752,14 @@ public class PhoneNumberUtils
return true;
}
+ private static boolean isNonSeparator(String address) {
+ for (int i = 0, count = address.length(); i < count; i++) {
+ if (!isNonSeparator(address.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
/**
* Note: calls extractNetworkPortion(), so do not use for
* SIM EF[ADN] style records
@@ -903,7 +931,7 @@ public class PhoneNumberUtils
"JM", // Jamaica
"PR", // Puerto Rico
"MS", // Montserrat
- "NP", // Northern Mariana Islands
+ "MP", // Northern Mariana Islands
"KN", // Saint Kitts and Nevis
"LC", // Saint Lucia
"VC", // Saint Vincent and the Grenadines
@@ -936,17 +964,7 @@ public class PhoneNumberUtils
public static int getFormatTypeForLocale(Locale locale) {
String country = locale.getCountry();
- // Check for the NANP countries
- int length = NANP_COUNTRIES.length;
- for (int i = 0; i < length; i++) {
- if (NANP_COUNTRIES[i].equals(country)) {
- return FORMAT_NANP;
- }
- }
- if (locale.equals(Locale.JAPAN)) {
- return FORMAT_JAPAN;
- }
- return FORMAT_UNKNOWN;
+ return getFormatTypeFromCountryCode(country);
}
/**
@@ -990,6 +1008,7 @@ public class PhoneNumberUtils
* as:
*
* <p><code>
+ * xxxxx
* xxx-xxxx
* xxx-xxx-xxxx
* 1-xxx-xxx-xxxx
@@ -1003,7 +1022,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
@@ -1215,4 +1238,288 @@ public class PhoneNumberUtils
KEYPAD_MAP.put('w', '9'); KEYPAD_MAP.put('x', '9'); KEYPAD_MAP.put('y', '9'); KEYPAD_MAP.put('z', '9');
KEYPAD_MAP.put('W', '9'); KEYPAD_MAP.put('X', '9'); KEYPAD_MAP.put('Y', '9'); KEYPAD_MAP.put('Z', '9');
}
+
+ //================ Plus Code formatting =========================
+ private static final char PLUS_SIGN_CHAR = '+';
+ private static final String PLUS_SIGN_STRING = "+";
+ private static final String NANP_IDP_STRING = "011";
+ private static final int NANP_LENGTH = 10;
+
+ /**
+ * This function checks if there is a plus sign (+) in the passed-in dialing number.
+ * If there is, it processes the plus sign based on the default telephone
+ * numbering plan of the system when the phone is activated and the current
+ * telephone numbering plan of the system that the phone is camped on.
+ * Currently, we only support the case that the default and current telephone
+ * numbering plans are North American Numbering Plan(NANP).
+ *
+ * The passed-in dialStr should only contain the valid format as described below,
+ * 1) the 1st character in the dialStr should be one of the really dialable
+ * characters listed below
+ * ISO-LATIN characters 0-9, *, # , +
+ * 2) the dialStr should already strip out the separator characters,
+ * every character in the dialStr should be one of the non separator characters
+ * listed below
+ * ISO-LATIN characters 0-9, *, # , +, WILD, WAIT, PAUSE
+ *
+ * Otherwise, this function returns the dial string passed in
+ *
+ * @param dialStr the original dial string
+ * @return the converted dial string if the current/default countries belong to NANP,
+ * and if there is the "+" in the original dial string. Otherwise, the original dial
+ * string returns.
+ *
+ * This API is for CDMA only
+ *
+ * @hide TODO: pending API Council approval
+ */
+ public static String cdmaCheckAndProcessPlusCode(String dialStr) {
+ if (!TextUtils.isEmpty(dialStr)) {
+ if (isReallyDialable(dialStr.charAt(0)) &&
+ isNonSeparator(dialStr)) {
+ String currIso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY, "");
+ String defaultIso = SystemProperties.get(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
+ if (!TextUtils.isEmpty(currIso) && !TextUtils.isEmpty(defaultIso)) {
+ return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr,
+ getFormatTypeFromCountryCode(currIso),
+ getFormatTypeFromCountryCode(defaultIso));
+ }
+ }
+ }
+ return dialStr;
+ }
+
+ /**
+ * This function should be called from checkAndProcessPlusCode only
+ * And it is used for test purpose also.
+ *
+ * It checks the dial string by looping through the network portion,
+ * post dial portion 1, post dial porting 2, etc. If there is any
+ * plus sign, then process the plus sign.
+ * Currently, this function supports the plus sign conversion within NANP only.
+ * Specifically, it handles the plus sign in the following ways:
+ * 1)+1NANP,remove +, e.g.
+ * +18475797000 is converted to 18475797000,
+ * 2)+NANP or +non-NANP Numbers,replace + with the current NANP IDP, e.g,
+ * +8475797000 is converted to 0118475797000,
+ * +11875767800 is converted to 01111875767800
+ * 3)+1NANP in post dial string(s), e.g.
+ * 8475797000;+18475231753 is converted to 8475797000;18475231753
+ *
+ *
+ * @param dialStr the original dial string
+ * @param currFormat the numbering system of the current country that the phone is camped on
+ * @param defaultFormat the numbering system of the country that the phone is activated on
+ * @return the converted dial string if the current/default countries belong to NANP,
+ * and if there is the "+" in the original dial string. Otherwise, the original dial
+ * string returns.
+ *
+ * @hide
+ */
+ public static String
+ cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormt) {
+ String retStr = dialStr;
+
+ // Checks if the plus sign character is in the passed-in dial string
+ if (dialStr != null &&
+ dialStr.lastIndexOf(PLUS_SIGN_STRING) != -1) {
+ // Format the string based on the rules for the country the number is from,
+ // and the current country the phone is camped on.
+ if ((currFormat == defaultFormt) && (currFormat == FORMAT_NANP)) {
+ // Handle case where default and current telephone numbering plans are NANP.
+ String postDialStr = null;
+ String tempDialStr = dialStr;
+
+ // Sets the retStr to null since the conversion will be performed below.
+ retStr = null;
+ if (DBG) log("checkAndProcessPlusCode,dialStr=" + dialStr);
+ // This routine is to process the plus sign in the dial string by loop through
+ // the network portion, post dial portion 1, post dial portion 2... etc. if
+ // applied
+ do {
+ String networkDialStr;
+ networkDialStr = extractNetworkPortion(tempDialStr);
+ // Handles the conversion within NANP
+ networkDialStr = processPlusCodeWithinNanp(networkDialStr);
+
+ // Concatenates the string that is converted from network portion
+ if (!TextUtils.isEmpty(networkDialStr)) {
+ if (retStr == null) {
+ retStr = networkDialStr;
+ } else {
+ retStr = retStr.concat(networkDialStr);
+ }
+ } else {
+ // This should never happen since we checked the if dialStr is null
+ // and if it contains the plus sign in the beginning of this function.
+ // The plus sign is part of the network portion.
+ Log.e("checkAndProcessPlusCode: null newDialStr", networkDialStr);
+ return dialStr;
+ }
+ postDialStr = extractPostDialPortion(tempDialStr);
+ if (!TextUtils.isEmpty(postDialStr)) {
+ int dialableIndex = findDialableIndexFromPostDialStr(postDialStr);
+
+ // dialableIndex should always be greater than 0
+ if (dialableIndex >= 1) {
+ retStr = appendPwCharBackToOrigDialStr(dialableIndex,
+ retStr,postDialStr);
+ // Skips the P/W character, extracts the dialable portion
+ tempDialStr = postDialStr.substring(dialableIndex);
+ } else {
+ // Non-dialable character such as P/W should not be at the end of
+ // the dial string after P/W processing in CdmaConnection.java
+ // Set the postDialStr to "" to break out of the loop
+ if (dialableIndex < 0) {
+ postDialStr = "";
+ }
+ Log.e("wrong postDialStr=", postDialStr);
+ }
+ }
+ if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr);
+ } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr));
+ } else {
+ // TODO: Support NANP international conversion and other telephone numbering plans.
+ // Currently the phone is never used in non-NANP system, so return the original
+ // dial string.
+ Log.e("checkAndProcessPlusCode:non-NANP not supported", dialStr);
+ }
+ }
+ return retStr;
+ }
+
+ // This function gets the default international dialing prefix
+ private static String getDefaultIdp( ) {
+ String ps = null;
+ SystemProperties.get(PROPERTY_IDP_STRING, ps);
+ if (TextUtils.isEmpty(ps)) {
+ ps = NANP_IDP_STRING;
+ }
+ return ps;
+ }
+
+ private static boolean isTwoToNine (char c) {
+ if (c >= '2' && c <= '9') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static int getFormatTypeFromCountryCode (String country) {
+ // Check for the NANP countries
+ int length = NANP_COUNTRIES.length;
+ for (int i = 0; i < length; i++) {
+ if (NANP_COUNTRIES[i].compareToIgnoreCase(country) == 0) {
+ return FORMAT_NANP;
+ }
+ }
+ if ("jp".compareToIgnoreCase(country) == 0) {
+ return FORMAT_JAPAN;
+ }
+ return FORMAT_UNKNOWN;
+ }
+
+ /**
+ * This function checks if the passed in string conforms to the NANP format
+ * i.e. NXX-NXX-XXXX, N is any digit 2-9 and X is any digit 0-9
+ */
+ private static boolean isNanp (String dialStr) {
+ boolean retVal = false;
+ if (dialStr != null) {
+ if (dialStr.length() == NANP_LENGTH) {
+ if (isTwoToNine(dialStr.charAt(0)) &&
+ isTwoToNine(dialStr.charAt(3))) {
+ retVal = true;
+ for (int i=1; i<NANP_LENGTH; i++ ) {
+ char c=dialStr.charAt(i);
+ if (!PhoneNumberUtils.isISODigit(c)) {
+ retVal = false;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ Log.e("isNanp: null dialStr passed in", dialStr);
+ }
+ return retVal;
+ }
+
+ /**
+ * This function checks if the passed in string conforms to 1-NANP format
+ */
+ private static boolean isOneNanp(String dialStr) {
+ boolean retVal = false;
+ if (dialStr != null) {
+ String newDialStr = dialStr.substring(1);
+ if ((dialStr.charAt(0) == '1') && isNanp(newDialStr)) {
+ retVal = true;
+ }
+ } else {
+ Log.e("isOneNanp: null dialStr passed in", dialStr);
+ }
+ return retVal;
+ }
+
+ /**
+ * This function handles the plus code conversion within NANP CDMA network
+ * If the number format is
+ * 1)+1NANP,remove +,
+ * 2)other than +1NANP, any + numbers,replace + with the current IDP
+ */
+ private static String processPlusCodeWithinNanp(String networkDialStr) {
+ String retStr = networkDialStr;
+
+ if (DBG) log("processPlusCodeWithinNanp,networkDialStr=" + networkDialStr);
+ // If there is a plus sign at the beginning of the dial string,
+ // Convert the plus sign to the default IDP since it's an international number
+ if (networkDialStr != null &
+ networkDialStr.charAt(0) == PLUS_SIGN_CHAR &&
+ networkDialStr.length() > 1) {
+ String newStr = networkDialStr.substring(1);
+ if (isOneNanp(newStr)) {
+ // Remove the leading plus sign
+ retStr = newStr;
+ } else {
+ String idpStr = getDefaultIdp();
+ // Replaces the plus sign with the default IDP
+ retStr = networkDialStr.replaceFirst("[+]", idpStr);
+ }
+ }
+ if (DBG) log("processPlusCodeWithinNanp,retStr=" + retStr);
+ return retStr;
+ }
+
+ // This function finds the index of the dialable character(s)
+ // in the post dial string
+ private static int findDialableIndexFromPostDialStr(String postDialStr) {
+ for (int index = 0;index < postDialStr.length();index++) {
+ char c = postDialStr.charAt(index);
+ if (isReallyDialable(c)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ // This function appends the non-diablable P/W character to the original
+ // dial string based on the dialable index passed in
+ private static String
+ appendPwCharBackToOrigDialStr(int dialableIndex,String origStr, String dialStr) {
+ String retStr;
+
+ // There is only 1 P/W character before the dialable characters
+ if (dialableIndex == 1) {
+ StringBuilder ret = new StringBuilder(origStr);
+ ret = ret.append(dialStr.charAt(0));
+ retStr = ret.toString();
+ } else {
+ // It means more than 1 P/W characters in the post dial string,
+ // appends to retStr
+ String nonDigitStr = dialStr.substring(0,dialableIndex);
+ retStr = origStr.concat(nonDigitStr);
+ }
+ return retStr;
+ }
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index e113680..73e7baa5 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -154,8 +154,9 @@ public class PhoneStateListener {
* @see ServiceState#STATE_IN_SERVICE
* @see ServiceState#STATE_OUT_OF_SERVICE
* @see ServiceState#STATE_POWER_OFF
- * @deprecated, @see #onSignalStrengthsChanged
+ * @deprecated see #onSignalStrengthsChanged
*/
+ @Deprecated
public void onSignalStrengthChanged(int asu) {
// default implementation empty
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 50c4d41..06b5c26 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -83,6 +83,12 @@ public class ServiceState implements Parcelable {
public static final int RADIO_TECHNOLOGY_EVDO_0 = 7;
/** @hide */
public static final int RADIO_TECHNOLOGY_EVDO_A = 8;
+ /** @hide */
+ public static final int RADIO_TECHNOLOGY_HSDPA = 9;
+ /** @hide */
+ public static final int RADIO_TECHNOLOGY_HSUPA = 10;
+ /** @hide */
+ public static final int RADIO_TECHNOLOGY_HSPA = 11;
/**
* Available registration states for GSM, UMTS and CDMA.
@@ -366,6 +372,15 @@ public class ServiceState implements Parcelable {
case 8:
radioTechnology = "EvDo rev. A";
break;
+ case 9:
+ radioTechnology = "HSDPA";
+ break;
+ case 10:
+ radioTechnology = "HSUPA";
+ break;
+ case 11:
+ radioTechnology = "HSPA";
+ break;
default:
Log.w(LOG_TAG, "mRadioTechnology variable out of range.");
break;
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 82539fb..14b1563 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -54,10 +54,13 @@ public final class SmsManager {
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is sucessfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
- * or one of these errors:
- * <code>RESULT_ERROR_GENERIC_FAILURE</code>
- * <code>RESULT_ERROR_RADIO_OFF</code>
- * <code>RESULT_ERROR_NULL_PDU</code>.
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
* is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
@@ -109,10 +112,13 @@ public final class SmsManager {
* <code>PendingIntent</code>s (one for each message part) that is
* broadcast when the corresponding message part has been sent.
* The result code will be <code>Activity.RESULT_OK<code> for success,
- * or one of these errors:
- * <code>RESULT_ERROR_GENERIC_FAILURE</code>
- * <code>RESULT_ERROR_RADIO_OFF</code>
- * <code>RESULT_ERROR_NULL_PDU</code>.
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
* is NULL the caller will be checked against all unknown applicaitons,
* which cause smaller number of SMS to be sent in checking period.
@@ -169,10 +175,13 @@ public final class SmsManager {
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is sucessfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
- * or one of these errors:
- * <code>RESULT_ERROR_GENERIC_FAILURE</code>
- * <code>RESULT_ERROR_RADIO_OFF</code>
- * <code>RESULT_ERROR_NULL_PDU</code>.
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
* is NULL the caller will be checked against all unknown applicaitons,
* which cause smaller number of SMS to be sent in checking period.
@@ -210,10 +219,13 @@ public final class SmsManager {
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is successfully sent, or failed.
* The result code will be <code>Activity.RESULT_OK<code> for success,
- * or one of these errors:
- * <code>RESULT_ERROR_GENERIC_FAILURE</code>
- * <code>RESULT_ERROR_RADIO_OFF</code>
- * <code>RESULT_ERROR_NULL_PDU</code>.
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
* The per-application based SMS control checks sentIntent. If sentIntent
* is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
@@ -409,4 +421,6 @@ public final class SmsManager {
static public final int RESULT_ERROR_NULL_PDU = 3;
/** Failed because service is currently unavailable */
static public final int RESULT_ERROR_NO_SERVICE = 4;
+ /** Failed because we reached the sending queue limit. {@hide} */
+ static public final int RESULT_ERROR_LIMIT_EXCEEDED = 5;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ed9af66..f3304a3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -382,6 +382,15 @@ public class TelephonyManager {
/** Current network is 1xRTT*/
/** @hide */
public static final int NETWORK_TYPE_1xRTT = 7;
+ /** Current network is HSDPA */
+ /** @hide */
+ public static final int NETWORK_TYPE_HSDPA = 8;
+ /** Current network is HSUPA */
+ /** @hide */
+ public static final int NETWORK_TYPE_HSUPA = 9;
+ /** Current network is HSPA */
+ /** @hide */
+ public static final int NETWORK_TYPE_HSPA = 10;
/**
* Returns a constant indicating the radio technology (network type)
@@ -392,35 +401,25 @@ public class TelephonyManager {
* @see #NETWORK_TYPE_GPRS
* @see #NETWORK_TYPE_EDGE
* @see #NETWORK_TYPE_UMTS
+ * @see #NETWORK_TYPE_HSDPA
+ * @see #NETWORK_TYPE_HSUPA
+ * @see #NETWORK_TYPE_HSPA
* @see #NETWORK_TYPE_CDMA
* @see #NETWORK_TYPE_EVDO_0
* @see #NETWORK_TYPE_EVDO_A
* @see #NETWORK_TYPE_1xRTT
*/
public int getNetworkType() {
- String prop = SystemProperties.get(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE);
- if ("GPRS".equals(prop)) {
- return NETWORK_TYPE_GPRS;
- }
- else if ("EDGE".equals(prop)) {
- return NETWORK_TYPE_EDGE;
- }
- else if ("UMTS".equals(prop)) {
- return NETWORK_TYPE_UMTS;
- }
- else if ("CDMA".equals(prop)) {
- return NETWORK_TYPE_CDMA;
- }
- else if ("CDMA - EvDo rev. 0".equals(prop)) {
- return NETWORK_TYPE_EVDO_0;
- }
- else if ("CDMA - EvDo rev. A".equals(prop)) {
- return NETWORK_TYPE_EVDO_A;
- }
- else if ("CDMA - 1xRTT".equals(prop)) {
- return NETWORK_TYPE_1xRTT;
+ try{
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getNetworkType();
+ } else {
+ // This can happen when the ITelephony interface is not up yet.
+ return NETWORK_TYPE_UNKNOWN;
}
- else {
+ } catch(RemoteException ex){
+ // This shouldn't happen in the normal case
return NETWORK_TYPE_UNKNOWN;
}
}
@@ -440,6 +439,12 @@ public class TelephonyManager {
return "EDGE";
case NETWORK_TYPE_UMTS:
return "UMTS";
+ case NETWORK_TYPE_HSDPA:
+ return "HSDPA";
+ case NETWORK_TYPE_HSUPA:
+ return "HSUPA";
+ case NETWORK_TYPE_HSPA:
+ return "HSPA";
case NETWORK_TYPE_CDMA:
return "CDMA";
case NETWORK_TYPE_EVDO_0:
diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java
index 84dfca0..37ef912 100644
--- a/telephony/java/android/telephony/gsm/SmsMessage.java
+++ b/telephony/java/android/telephony/gsm/SmsMessage.java
@@ -345,6 +345,7 @@ public class SmsMessage {
* the number of code units used, and int[2] is the number of code
* units remaining until the next message. int[3] is the encoding
* type that should be used for the message.
+ * @deprecated Use android.telephony.SmsMessage.
*/
@Deprecated
public static int[] calculateLength(String messageBody, boolean use7bitOnly) {
diff --git a/telephony/java/com/android/internal/telephony/Call.java b/telephony/java/com/android/internal/telephony/Call.java
index 7eb9d85..b95dd11 100644
--- a/telephony/java/com/android/internal/telephony/Call.java
+++ b/telephony/java/com/android/internal/telephony/Call.java
@@ -25,10 +25,10 @@ public abstract class Call {
/* Enums */
public enum State {
- IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED;
+ IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING;
public boolean isAlive() {
- return !(this == IDLE || this == DISCONNECTED);
+ return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING);
}
public boolean isRinging() {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index afc8b62..bda2d22 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -20,9 +20,8 @@ import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.provider.Contacts;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.text.TextUtils;
import android.telephony.TelephonyManager;
import android.telephony.PhoneNumberUtils;
@@ -134,44 +133,39 @@ public class CallerInfo {
int columnIndex;
// Look for the name
- columnIndex = cursor.getColumnIndex(People.NAME);
+ columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
if (columnIndex != -1) {
info.name = cursor.getString(columnIndex);
}
// Look for the number
- columnIndex = cursor.getColumnIndex(Phones.NUMBER);
+ columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER);
if (columnIndex != -1) {
info.phoneNumber = cursor.getString(columnIndex);
}
// Look for the label/type combo
- columnIndex = cursor.getColumnIndex(Phones.LABEL);
+ columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL);
if (columnIndex != -1) {
- int typeColumnIndex = cursor.getColumnIndex(Phones.TYPE);
+ int typeColumnIndex = cursor.getColumnIndex(PhoneLookup.TYPE);
if (typeColumnIndex != -1) {
info.numberType = cursor.getInt(typeColumnIndex);
info.numberLabel = cursor.getString(columnIndex);
- info.phoneLabel = Contacts.Phones.getDisplayLabel(context,
+ info.phoneLabel = Phone.getDisplayLabel(context,
info.numberType, info.numberLabel)
.toString();
}
}
// Look for the person ID
- columnIndex = cursor.getColumnIndex(Phones.PERSON_ID);
+ columnIndex = cursor.getColumnIndex(PhoneLookup._ID);
if (columnIndex != -1) {
info.person_id = cursor.getLong(columnIndex);
- } else {
- columnIndex = cursor.getColumnIndex(People._ID);
- if (columnIndex != -1) {
- info.person_id = cursor.getLong(columnIndex);
- }
}
// look for the custom ringtone, create from the string stored
// in the database.
- columnIndex = cursor.getColumnIndex(People.CUSTOM_RINGTONE);
+ columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE);
if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) {
info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex));
} else {
@@ -180,7 +174,7 @@ public class CallerInfo {
// look for the send to voicemail flag, set it to true only
// under certain circumstances.
- columnIndex = cursor.getColumnIndex(People.SEND_TO_VOICEMAIL);
+ columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL);
info.shouldSendToVoicemail = (columnIndex != -1) &&
((cursor.getInt(columnIndex)) == 1);
info.contactExists = true;
@@ -256,8 +250,7 @@ public class CallerInfo {
}
}
- Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL,
- Uri.encode(number));
+ Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number);
CallerInfo info = getCallerInfo(context, contactUri);
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index f81f42a..ef456f0 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -24,7 +24,7 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.provider.Contacts;
+import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -303,7 +303,7 @@ public class CallerInfoAsyncQuery {
public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
OnQueryCompleteListener listener, Object cookie) {
//contruct the URI object and start Query.
- Uri contactRef = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, number);
+ Uri contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number);
CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
c.allocate(context, contactRef);
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index e583110..ed8bc1e 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -82,15 +82,6 @@ public interface CommandsInterface {
}
}
- enum IccStatus {
- ICC_ABSENT,
- ICC_NOT_READY,
- ICC_READY,
- ICC_PIN,
- ICC_PUK,
- ICC_NETWORK_PERSONALIZATION
- }
-
//***** Constants
// Used as parameter to dial() and setCLIR() below
@@ -534,15 +525,6 @@ public interface CommandsInterface {
void unregisterForCdmaOtaProvision(Handler h);
/**
- * Returns current ICC status.
- *
- * AsyncResult.result is IccStatus
- *
- */
-
- void getIccStatus(Message result);
-
- /**
* Supply the ICC PIN to the ICC card
*
* returned message
@@ -625,8 +607,9 @@ public interface CommandsInterface {
* ar.exception carries exception on failure
* ar.userObject contains the orignal value of result.obj
* ar.result contains a List of DataCallState
- * @deprecated
+ * @deprecated Do not use.
*/
+ @Deprecated
void getPDPContextList(Message result);
/**
@@ -797,8 +780,9 @@ public interface CommandsInterface {
* cause code returned as int[0] in Message.obj.response
* returns an integer cause code defined in TS 24.008
* section 6.1.3.1.3 or close approximation
- * @deprecated
+ * @deprecated Do not use.
*/
+ @Deprecated
void getLastPdpFailCause (Message result);
/**
@@ -1243,8 +1227,10 @@ public interface CommandsInterface {
* Request the device MDN / H_SID / H_NID / MIN.
* "response" is const char **
* [0] is MDN if CDMA subscription is available
- * [1] is H_SID (Home SID) if CDMA subscription is available
- * [2] is H_NID (Home NID) if CDMA subscription is available
+ * [1] is a comma separated list of H_SID (Home SID) in decimal format
+ * if CDMA subscription is available
+ * [2] is a comma separated list of H_NID (Home NID) in decimal format
+ * if CDMA subscription is available
* [3] is MIN (10 digits, MIN2+MIN1) if CDMA subscription is available
*/
public void getCDMASubscription(Message response);
@@ -1316,11 +1302,13 @@ public interface CommandsInterface {
* the username for APN, or NULL
* @param password
* the password for APN, or NULL
+ * @param authType
+ * the PAP / CHAP auth type. Values is one of SETUP_DATA_AUTH_*
* @param result
* Callback message
*/
public void setupDataCall(String radioTechnology, String profile, String apn,
- String user, String password, Message result);
+ String user, String password, String authType, Message result);
/**
* Deactivate packet data connection
@@ -1366,4 +1354,12 @@ public interface CommandsInterface {
* @param response callback message
*/
public void exitEmergencyCallbackMode(Message response);
+
+ /**
+ * Request the status of the ICC and UICC cards.
+ *
+ * @param response
+ * Callback message containing {@link IccCardStatus} structure for the card.
+ */
+ public void getIccCardStatus(Message result);
}
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index 92f6cb8..e6fd0a0 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -56,7 +56,8 @@ public abstract class Connection {
CDMA_RETRY_ORDER, /* requeseted service is rejected, retry delay is set */
CDMA_ACCESS_FAILURE,
CDMA_PREEMPTED,
- CDMA_NOT_EMERGENCY /* not an emergency call */
+ CDMA_NOT_EMERGENCY, /* not an emergency call */
+ ERROR_UNSPECIFIED
}
Object userData;
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index c074cb8..ece708a 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -24,14 +24,18 @@ import android.os.Message;
import android.os.RemoteException;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
+import android.text.TextUtils;
import android.util.Log;
+import java.util.ArrayList;
+
/**
* {@hide}
*
*/
public abstract class DataConnectionTracker extends Handler {
- private static final boolean DBG = true;
+ protected static final boolean DBG = true;
+ protected final String LOG_TAG = "DataConnectionTracker";
/**
* IDLE: ready to start data connection setup, default state
@@ -67,7 +71,7 @@ public abstract class DataConnectionTracker extends Handler {
DORMANT
}
- //***** Event Codes
+ /***** Event Codes *****/
protected static final int EVENT_DATA_SETUP_COMPLETE = 1;
protected static final int EVENT_RADIO_AVAILABLE = 3;
protected static final int EVENT_RECORDS_LOADED = 4;
@@ -94,12 +98,33 @@ public abstract class DataConnectionTracker extends Handler {
protected static final int EVENT_PS_RESTRICT_ENABLED = 32;
protected static final int EVENT_PS_RESTRICT_DISABLED = 33;
public static final int EVENT_CLEAN_UP_CONNECTION = 34;
+ protected static final int EVENT_CDMA_OTA_PROVISION = 35;
+ protected static final int EVENT_RESTART_RADIO = 36;
+ private static final int EVENT_ENABLE_APN_REQUEST = 37;
+
+ /***** Constants *****/
+
+ protected static final int APN_INVALID_ID = -1;
+ protected static final int APN_DEFAULT_ID = 0;
+ protected static final int APN_MMS_ID = 1;
+ protected static final int APN_SUPL_ID = 2;
+ protected static final int APN_DUN_ID = 3;
+ protected static final int APN_HIPRI_ID = 4;
+ protected static final int APN_NUM_TYPES = 5;
+
+ protected static final int APN_DISABLED = 0;
+ protected static final int APN_ENABLED = 1;
+
+ protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
+ protected int enabledCount = 0;
- //***** Constants
- protected static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000;
+ /* Currently requested APN type */
+ protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
- /** Cap out with 30 min retry interval. */
- protected static final int RECONNECT_DELAY_MAX_MILLIS = 30 * 60 * 1000;
+ /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
+ protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
+ + "5000,10000,20000,40000,80000:5000,160000:5000,"
+ + "320000:5000,640000:5000,1280000:5000,1800000:5000";
/** Slow poll when attempting connection recovery. */
protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
@@ -145,6 +170,9 @@ public abstract class DataConnectionTracker extends Handler {
protected int mNoRecvPollCount = 0;
protected boolean netStatPollEnabled = false;
+ /** Manage the behavior of data retry after failure */
+ protected final RetryManager mRetryMgr = new RetryManager();
+
// wifi connection status will be updated by sticky intent
protected boolean mIsWifiConnected = false;
@@ -162,6 +190,8 @@ public abstract class DataConnectionTracker extends Handler {
this.phone = phone;
}
+ public abstract void dispose();
+
public Activity getActivity() {
return activity;
}
@@ -201,10 +231,13 @@ public abstract class DataConnectionTracker extends Handler {
if (getDataOnRoamingEnabled() != enabled) {
Settings.Secure.putInt(phone.getContext().getContentResolver(),
Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
+ if (phone.getServiceState().getRoaming()) {
+ if (enabled) {
+ mRetryMgr.resetRetryCount();
+ }
+ sendMessage(obtainMessage(EVENT_ROAMING_ON));
+ }
}
- Message roamingMsg = phone.getServiceState().getRoaming() ?
- obtainMessage(EVENT_ROAMING_ON) : obtainMessage(EVENT_ROAMING_OFF);
- sendMessage(roamingMsg);
}
//Retrieve the data roaming setting from the shared preferences.
@@ -218,7 +251,7 @@ public abstract class DataConnectionTracker extends Handler {
}
// abstract handler methods
- protected abstract void onTrySetupData(String reason);
+ protected abstract boolean onTrySetupData(String reason);
protected abstract void onRoamingOff();
protected abstract void onRoamingOn();
protected abstract void onRadioAvailable();
@@ -229,10 +262,39 @@ public abstract class DataConnectionTracker extends Handler {
protected abstract void onVoiceCallEnded();
protected abstract void onCleanUpConnection(boolean tearDown, String reason);
- //***** Overridden from Handler
+ @Override
public void handleMessage (Message msg) {
switch (msg.what) {
+ case EVENT_ENABLE_APN_REQUEST:
+ int apnId = msg.arg1;
+ synchronized (this) {
+ if (DBG) {
+ Log.d(LOG_TAG, "got EVENT_ENABLE_APN_REQUEST with apnType = " + apnId +
+ " and enable = " + msg.arg2);
+ Log.d(LOG_TAG, "dataEnabled[apnId] = " + dataEnabled[apnId] +
+ ", enabledCount = " + enabledCount);
+ }
+ if (msg.arg2 == APN_ENABLED) {
+ // enable
+ if (!dataEnabled[apnId]) {
+ dataEnabled[apnId] = true;
+ enabledCount++;
+ }
+ onTrySetupData(null);
+ } else {
+ // disable
+ if (dataEnabled[apnId]) {
+ dataEnabled[apnId] = false;
+ enabledCount--;
+ if (enabledCount == 0) {
+ onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
+ }
+ }
+ }
+ }
+ break;
+
case EVENT_TRY_SETUP_DATA:
String reason = null;
if (msg.obj instanceof String) {
@@ -242,6 +304,9 @@ public abstract class DataConnectionTracker extends Handler {
break;
case EVENT_ROAMING_OFF:
+ if (getDataOnRoamingEnabled() == false) {
+ mRetryMgr.resetRetryCount();
+ }
onRoamingOff();
break;
@@ -290,30 +355,161 @@ public abstract class DataConnectionTracker extends Handler {
* @return {@code false} if data connectivity has been explicitly disabled,
* {@code true} otherwise.
*/
- public abstract boolean getDataEnabled();
+ public synchronized boolean getDataEnabled() {
+ return dataEnabled[APN_DEFAULT_ID];
+ }
/**
* Report on whether data connectivity is enabled
* @return {@code false} if data connectivity has been explicitly disabled,
* {@code true} otherwise.
*/
- public abstract boolean getAnyDataEnabled();
+ public boolean getAnyDataEnabled() {
+ return (enabledCount != 0);
+ }
+
+ protected abstract void startNetStatPoll();
+
+ protected abstract void stopNetStatPoll();
+
+ protected abstract void restartRadio();
+
+ protected abstract void log(String s);
+
+ protected int apnTypeToId(String type) {
+ if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
+ return APN_DEFAULT_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
+ return APN_MMS_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
+ return APN_SUPL_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
+ return APN_DUN_ID;
+ } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
+ return APN_HIPRI_ID;
+ } else {
+ return APN_INVALID_ID;
+ }
+ }
+
+ protected abstract boolean isApnTypeActive(String type);
+
+ protected abstract boolean isApnTypeAvailable(String type);
+
+ protected abstract String[] getActiveApnTypes();
+
+ protected abstract String getActiveApnString();
+
+ public abstract ArrayList<DataConnection> getAllDataConnections();
+
+ protected abstract String getInterfaceName(String apnType);
+
+ protected abstract String getIpAddress(String apnType);
+
+ protected abstract String getGateway(String apnType);
+
+ protected abstract String[] getDnsServers(String apnType);
+
+ protected abstract void setState(State s);
+
+ protected synchronized boolean isEnabled(int id) {
+ if (id != APN_INVALID_ID) {
+ return dataEnabled[id];
+ }
+ return false;
+ }
+
+ /**
+ * Ensure that we are connected to an APN of the specified type.
+ * @param type the APN type (currently the only valid values
+ * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
+ * @return the result of the operation. Success is indicated by
+ * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or
+ * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast
+ * will be sent by the ConnectivityManager when a connection to
+ * the APN has been established.
+ */
+ public int enableApnType(String type) {
+ int id = apnTypeToId(type);
+ if (id == APN_INVALID_ID) {
+ return Phone.APN_REQUEST_FAILED;
+ }
+
+ // If already active, return
+ if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = "
+ + isApnTypeActive(type) + " and state = " + state);
+
+ if (isApnTypeActive(type)) {
+ if (state == State.INITING) return Phone.APN_REQUEST_STARTED;
+ else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE;
+ }
+
+ if (!isApnTypeAvailable(type)) {
+ return Phone.APN_TYPE_NOT_AVAILABLE;
+ }
+
+ setEnabled(id, true);
+ mRequestedApnType = type;
+ sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN));
+ return Phone.APN_REQUEST_STARTED;
+ }
+
+ /**
+ * The APN of the specified type is no longer needed. Ensure that if
+ * use of the default APN has not been explicitly disabled, we are connected
+ * to the default APN.
+ * @param type the APN type. The only valid values are currently
+ * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
+ * @return
+ */
+ public synchronized int disableApnType(String type) {
+ if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")");
+ int id = apnTypeToId(type);
+ if (id == APN_INVALID_ID) {
+ return Phone.APN_REQUEST_FAILED;
+ }
+ if (isEnabled(id)) {
+ setEnabled(id, false);
+ if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
+ mRequestedApnType = Phone.APN_TYPE_DEFAULT;
+ if (dataEnabled[APN_DEFAULT_ID]) {
+ return Phone.APN_ALREADY_ACTIVE;
+ } else {
+ return Phone.APN_REQUEST_STARTED;
+ }
+ } else {
+ return Phone.APN_REQUEST_STARTED;
+ }
+ } else {
+ return Phone.APN_REQUEST_FAILED;
+ }
+ }
+
+ protected void setEnabled(int id, boolean enable) {
+ if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " +
+ dataEnabled[id] + " and enabledCount = " + enabledCount);
+
+ Message msg = obtainMessage(EVENT_ENABLE_APN_REQUEST);
+ msg.arg1 = id;
+ msg.arg2 = (enable ? APN_ENABLED : APN_DISABLED);
+ sendMessage(msg);
+ }
/**
* Prevent mobile data connections from being established,
* or once again allow mobile data connections. If the state
* toggles, then either tear down or set up data, as
* appropriate to match the new state.
+ * <p>This operation only affects the default APN, and if the same APN is
+ * currently being used for MMS traffic, the teardown will not happen
+ * even when {@code enable} is {@code false}.</p>
* @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
* @return {@code true} if the operation succeeded
*/
- public abstract boolean setDataEnabled(boolean enable);
-
- protected abstract void startNetStatPoll();
-
- protected abstract void stopNetStatPoll();
-
- protected abstract void restartRadio();
+ public boolean setDataEnabled(boolean enable) {
+ if (DBG) Log.d(LOG_TAG, "setDataEnabled(" + enable + ")");
+ setEnabled(APN_DEFAULT_ID, enable);
+ return true;
+ }
- protected abstract void log(String s);
}
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index d6151c6..00d7c72 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -94,8 +94,11 @@ public class DefaultPhoneNotifier implements PhoneNotifier {
public void notifyDataConnection(Phone sender, String reason) {
try {
- mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()),
- sender.isDataConnectivityPossible(), reason, sender.getActiveApn(),
+ mRegistry.notifyDataConnection(
+ convertDataState(sender.getDataConnectionState()),
+ sender.isDataConnectivityPossible(), reason,
+ sender.getActiveApn(),
+ sender.getActiveApnTypes(),
sender.getInterfaceName(null));
} catch (RemoteException ex) {
// system process is dead
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index e8095e1..461b694 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -183,15 +183,9 @@ public class GsmAlphabet {
}
int headerBits = (header.length + 1) * 8;
- int headerSeptets = headerBits / 7;
- headerSeptets += (headerBits % 7) > 0 ? 1 : 0;
+ int headerSeptets = (headerBits + 6) / 7;
- int sz = data.length();
- int septetCount;
- septetCount = countGsmSeptets(data, true) + headerSeptets;
-
- byte[] ret = stringToGsm7BitPacked(data, 0, septetCount,
- (headerSeptets*7), true);
+ byte[] ret = stringToGsm7BitPacked(data, headerSeptets, true);
// Paste in the header
ret[1] = (byte)header.length;
@@ -215,7 +209,7 @@ public class GsmAlphabet {
*/
public static byte[] stringToGsm7BitPacked(String data)
throws EncodeException {
- return stringToGsm7BitPacked(data, 0, -1, 0, true);
+ return stringToGsm7BitPacked(data, 0, true);
}
/**
@@ -228,58 +222,37 @@ public class GsmAlphabet {
* septets.
*
* @param data the text to convert to septets
- * @param dataOffset the character offset in data to start the encoding from
- * @param maxSeptets the maximum number of septets to convert, or -1 for no
- * enforced maximum.
- * @param startingBitOffset the number of padding bits to put before
- * the start of the first septet at the begining of the array
+ * @param startingSeptetOffset the number of padding septets to put before
+ * the character data at the begining of the array
* @param throwException If true, throws EncodeException on invalid char.
* If false, replaces unencodable char with GSM alphabet space char.
*
* @throws EncodeException if String is too large to encode
*/
- public static byte[] stringToGsm7BitPacked(String data, int dataOffset,
- int maxSeptets, int startingBitOffset, boolean throwException)
- throws EncodeException {
-
- int sz = data.length();
- int septetCount;
- if (maxSeptets == -1) {
- septetCount = countGsmSeptets(data, true);
- } else {
- septetCount = maxSeptets;
+ public static byte[] stringToGsm7BitPacked(String data, int startingSeptetOffset,
+ boolean throwException) throws EncodeException {
+ int dataLen = data.length();
+ int septetCount = countGsmSeptets(data, throwException) + startingSeptetOffset;
+ if (septetCount > 255) {
+ throw new EncodeException("Payload cannot exceed 255 septets");
}
-
- if(septetCount > 0xff) {
- throw new EncodeException("Payload cannot exceed " + Short.MAX_VALUE
- + " septets");
- }
-
- // Enough for all the septets and the length 2 byte prefix
- byte[] ret = new byte[1 + (((septetCount * 7) + 7) / 8)];
-
- int bitOffset = startingBitOffset;
- int septets = startingBitOffset/7;
- for (int i = dataOffset; i < sz && septets < septetCount; i++, bitOffset += 7) {
+ int byteCount = ((septetCount * 7) + 7) / 8;
+ byte[] ret = new byte[byteCount + 1]; // Include space for one byte length prefix.
+ for (int i = 0, septets = startingSeptetOffset, bitOffset = startingSeptetOffset * 7;
+ i < dataLen && septets < septetCount;
+ i++, bitOffset += 7) {
char c = data.charAt(i);
-
int v = GsmAlphabet.charToGsm(c, throwException);
if (v == GSM_EXTENDED_ESCAPE) {
- // Lookup the extended char
- v = GsmAlphabet.charToGsmExtended(c);
-
+ v = GsmAlphabet.charToGsmExtended(c); // Lookup the extended char.
packSmsChar(ret, bitOffset, GSM_EXTENDED_ESCAPE);
bitOffset += 7;
septets++;
}
-
packSmsChar(ret, bitOffset, v);
septets++;
}
-
- // See check for > 0xff above
- ret[0] = (byte)septets;
-
+ ret[0] = (byte) (septetCount); // Validated by check above.
return ret;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index d83b135..63c23ae 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -239,9 +239,18 @@ interface ITelephony {
String getCdmaEriText();
/**
+ * Returns true if CDMA provisioning needs to run.
+ */
+ boolean getCdmaNeedsProvisioning();
+
+ /**
* Returns the unread count of voicemails
*/
int getVoiceMessageCount();
+ /**
+ * Returns the network type
+ */
+ int getNetworkType();
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 865c6ca..6b42e6b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -32,7 +32,7 @@ interface ITelephonyRegistry {
void notifyCallForwardingChanged(boolean cfi);
void notifyDataActivity(int state);
void notifyDataConnection(int state, boolean isDataConnectivityPossible,
- String reason, String apn, String interfaceName);
+ String reason, String apn, in String[] apnTypes, String interfaceName);
void notifyDataConnectionFailed(String reason);
void notifyCellLocation(in Bundle cellLocation);
}
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index d7ad492..6657060 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -16,13 +16,40 @@
package com.android.internal.telephony;
-import android.os.Message;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import android.app.ActivityManagerNative;
+import android.content.Intent;
+import android.os.AsyncResult;
import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.util.Log;
+
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.telephony.CommandsInterface.RadioState;
/**
* {@hide}
*/
-public interface IccCard {
+public abstract class IccCard {
+ protected String mLogTag;
+ protected boolean mDbg;
+
+ private IccCardStatus mIccCardStatus = null;
+ protected State mState = null;
+ protected PhoneBase mPhone;
+ private RegistrantList mAbsentRegistrants = new RegistrantList();
+ private RegistrantList mPinLockedRegistrants = new RegistrantList();
+ private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
+
+ private boolean mDesiredPinLocked;
+ private boolean mDesiredFdnEnabled;
+ private boolean mIccPinLocked = true; // Default to locked
+ private boolean mIccFdnEnabled = false; // Default to disabled.
+ // Will be updated when SIM_READY.
+
+
/* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */
static public final String INTENT_KEY_ICC_STATE = "ss";
/* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */
@@ -46,6 +73,17 @@ public interface IccCard {
/* NETWORK means ICC is locked on NETWORK PERSONALIZATION */
static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK";
+ protected static final int EVENT_ICC_LOCKED_OR_ABSENT = 1;
+ private static final int EVENT_GET_ICC_STATUS_DONE = 2;
+ protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
+ private static final int EVENT_PINPUK_DONE = 4;
+ private static final int EVENT_REPOLL_STATUS_DONE = 5;
+ protected static final int EVENT_ICC_READY = 6;
+ private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
+ private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
+ private static final int EVENT_CHANGE_ICC_PASSWORD_DONE = 9;
+ private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
+ private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
/*
UNKNOWN is a transient state, for example, after uesr inputs ICC pin under
@@ -58,33 +96,108 @@ public interface IccCard {
PIN_REQUIRED,
PUK_REQUIRED,
NETWORK_LOCKED,
- READY;
+ READY,
+ NOT_READY;
public boolean isPinLocked() {
return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
}
}
- State getState();
+ public State getState() {
+ if (mState == null) {
+ switch(mPhone.mCM.getRadioState()) {
+ /* This switch block must not return anything in
+ * State.isLocked() or State.ABSENT.
+ * If it does, handleSimStatus() may break
+ */
+ case RADIO_OFF:
+ case RADIO_UNAVAILABLE:
+ case SIM_NOT_READY:
+ case RUIM_NOT_READY:
+ return State.UNKNOWN;
+ case SIM_LOCKED_OR_ABSENT:
+ case RUIM_LOCKED_OR_ABSENT:
+ //this should be transient-only
+ return State.UNKNOWN;
+ case SIM_READY:
+ case RUIM_READY:
+ case NV_READY:
+ return State.READY;
+ case NV_NOT_READY:
+ return State.ABSENT;
+ }
+ } else {
+ return mState;
+ }
+
+ Log.e(mLogTag, "IccCard.getState(): case should never be reached");
+ return State.UNKNOWN;
+ }
+
+ public IccCard(PhoneBase phone, String logTag, Boolean dbg) {
+ mPhone = phone;
+ mLogTag = logTag;
+ mDbg = dbg;
+ }
+
+ abstract public void dispose();
+ protected void finalize() {
+ if(mDbg) Log.d(mLogTag, "IccCard finalized");
+ }
/**
* Notifies handler of any transition into State.ABSENT
*/
- void registerForAbsent(Handler h, int what, Object obj);
- void unregisterForAbsent(Handler h);
+ public void registerForAbsent(Handler h, int what, Object obj) {
+ Registrant r = new Registrant (h, what, obj);
+
+ mAbsentRegistrants.add(r);
+
+ if (getState() == State.ABSENT) {
+ r.notifyRegistrant();
+ }
+ }
+
+ public void unregisterForAbsent(Handler h) {
+ mAbsentRegistrants.remove(h);
+ }
/**
- * Notifies handler of any transition into State.isPinLocked()
+ * Notifies handler of any transition into State.NETWORK_LOCKED
*/
- void registerForLocked(Handler h, int what, Object obj);
- void unregisterForLocked(Handler h);
+ public void registerForNetworkLocked(Handler h, int what, Object obj) {
+ Registrant r = new Registrant (h, what, obj);
+
+ mNetworkLockedRegistrants.add(r);
+
+ if (getState() == State.NETWORK_LOCKED) {
+ r.notifyRegistrant();
+ }
+ }
+
+ public void unregisterForNetworkLocked(Handler h) {
+ mNetworkLockedRegistrants.remove(h);
+ }
/**
- * Notifies handler of any transition into State.NETWORK_LOCKED
+ * Notifies handler of any transition into State.isPinLocked()
*/
- void registerForNetworkLocked(Handler h, int what, Object obj);
- void unregisterForNetworkLocked(Handler h);
+ public void registerForLocked(Handler h, int what, Object obj) {
+ Registrant r = new Registrant (h, what, obj);
+
+ mPinLockedRegistrants.add(r);
+
+ if (getState().isPinLocked()) {
+ r.notifyRegistrant();
+ }
+ }
+
+ public void unregisterForLocked(Handler h) {
+ mPinLockedRegistrants.remove(h);
+ }
+
/**
* Supply the ICC PIN to the ICC
@@ -107,10 +220,30 @@ public interface IccCard {
*
*/
- void supplyPin (String pin, Message onComplete);
- void supplyPuk (String puk, String newPin, Message onComplete);
- void supplyPin2 (String pin2, Message onComplete);
- void supplyPuk2 (String puk2, String newPin2, Message onComplete);
+ public void supplyPin (String pin, Message onComplete) {
+ mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ }
+
+ public void supplyPuk (String puk, String newPin, Message onComplete) {
+ mPhone.mCM.supplyIccPuk(puk, newPin,
+ mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ }
+
+ public void supplyPin2 (String pin2, Message onComplete) {
+ mPhone.mCM.supplyIccPin2(pin2,
+ mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ }
+
+ public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
+ mPhone.mCM.supplyIccPuk2(puk2, newPin2,
+ mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ }
+
+ public void supplyNetworkDepersonalization (String pin, Message onComplete) {
+ if(mDbg) log("Network Despersonalization: " + pin);
+ mPhone.mCM.supplyNetworkDepersonalization(pin,
+ mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ }
/**
* Check whether ICC pin lock is enabled
@@ -119,35 +252,9 @@ public interface IccCard {
* @return true for ICC locked enabled
* false for ICC locked disabled
*/
- boolean getIccLockEnabled ();
-
- /**
- * Set the ICC pin lock enabled or disabled
- * When the operation is complete, onComplete will be sent to its handler
- *
- * @param enabled "true" for locked "false" for unlocked.
- * @param password needed to change the ICC pin state, aka. Pin1
- * @param onComplete
- * onComplete.obj will be an AsyncResult
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- */
- void setIccLockEnabled(boolean enabled, String password, Message onComplete);
-
-
- /**
- * Change the ICC password used in ICC pin lock
- * When the operation is complete, onComplete will be sent to its handler
- *
- * @param oldPassword is the old password
- * @param newPassword is the new password
- * @param onComplete
- * onComplete.obj will be an AsyncResult
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- */
- void changeIccLockPassword(String oldPassword, String newPassword,
- Message onComplete);
+ public boolean getIccLockEnabled() {
+ return mIccPinLocked;
+ }
/**
* Check whether ICC fdn (fixed dialing number) is enabled
@@ -156,36 +263,99 @@ public interface IccCard {
* @return true for ICC fdn enabled
* false for ICC fdn disabled
*/
- boolean getIccFdnEnabled ();
+ public boolean getIccFdnEnabled() {
+ return mIccFdnEnabled;
+ }
- /**
- * Set the ICC fdn enabled or disabled
- * When the operation is complete, onComplete will be sent to its handler
- *
- * @param enabled "true" for locked "false" for unlocked.
- * @param password needed to change the ICC fdn enable, aka Pin2
- * @param onComplete
- * onComplete.obj will be an AsyncResult
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- */
- void setIccFdnEnabled(boolean enabled, String password, Message onComplete);
+ /**
+ * Set the ICC pin lock enabled or disabled
+ * When the operation is complete, onComplete will be sent to its handler
+ *
+ * @param enabled "true" for locked "false" for unlocked.
+ * @param password needed to change the ICC pin state, aka. Pin1
+ * @param onComplete
+ * onComplete.obj will be an AsyncResult
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ */
+ public void setIccLockEnabled (boolean enabled,
+ String password, Message onComplete) {
+ int serviceClassX;
+ serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
+ CommandsInterface.SERVICE_CLASS_DATA +
+ CommandsInterface.SERVICE_CLASS_FAX;
- /**
- * Change the ICC password used in ICC fdn enable
- * When the operation is complete, onComplete will be sent to its handler
- *
- * @param oldPassword is the old password
- * @param newPassword is the new password
- * @param onComplete
- * onComplete.obj will be an AsyncResult
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- */
- void changeIccFdnPassword(String oldPassword, String newPassword,
- Message onComplete);
+ mDesiredPinLocked = enabled;
+
+ mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,
+ enabled, password, serviceClassX,
+ mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
+ }
+
+ /**
+ * Set the ICC fdn enabled or disabled
+ * When the operation is complete, onComplete will be sent to its handler
+ *
+ * @param enabled "true" for locked "false" for unlocked.
+ * @param password needed to change the ICC fdn enable, aka Pin2
+ * @param onComplete
+ * onComplete.obj will be an AsyncResult
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ */
+ public void setIccFdnEnabled (boolean enabled,
+ String password, Message onComplete) {
+ int serviceClassX;
+ serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
+ CommandsInterface.SERVICE_CLASS_DATA +
+ CommandsInterface.SERVICE_CLASS_FAX +
+ CommandsInterface.SERVICE_CLASS_SMS;
+
+ mDesiredFdnEnabled = enabled;
+
+ mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD,
+ enabled, password, serviceClassX,
+ mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
+ }
+
+ /**
+ * Change the ICC password used in ICC pin lock
+ * When the operation is complete, onComplete will be sent to its handler
+ *
+ * @param oldPassword is the old password
+ * @param newPassword is the new password
+ * @param onComplete
+ * onComplete.obj will be an AsyncResult
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ */
+ public void changeIccLockPassword(String oldPassword, String newPassword,
+ Message onComplete) {
+ if(mDbg) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
+ mPhone.mCM.changeIccPin(oldPassword, newPassword,
+ mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete));
+
+ }
+
+ /**
+ * Change the ICC password used in ICC fdn enable
+ * When the operation is complete, onComplete will be sent to its handler
+ *
+ * @param oldPassword is the old password
+ * @param newPassword is the new password
+ * @param onComplete
+ * onComplete.obj will be an AsyncResult
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ */
+ public void changeIccFdnPassword(String oldPassword, String newPassword,
+ Message onComplete) {
+ if(mDbg) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
+ mPhone.mCM.changeIccPin2(oldPassword, newPassword,
+ mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete));
+
+ }
- void supplyNetworkDepersonalization (String pin, Message onComplete);
/**
* Returns service provider name stored in ICC card.
@@ -203,5 +373,301 @@ public interface IccCard {
* yet available
*
*/
- String getServiceProviderName();
+ public abstract String getServiceProviderName();
+
+ protected void updateStateProperty() {
+ mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString());
+ }
+
+ private void getIccCardStatusDone(AsyncResult ar) {
+ if (ar.exception != null) {
+ Log.e(mLogTag,"Error getting ICC status. "
+ + "RIL_REQUEST_GET_ICC_STATUS should "
+ + "never return an error", ar.exception);
+ return;
+ }
+ handleIccCardStatus((IccCardStatus) ar.result);
+ }
+
+ private void handleIccCardStatus(IccCardStatus newCardStatus) {
+ boolean transitionedIntoPinLocked;
+ boolean transitionedIntoAbsent;
+ boolean transitionedIntoNetworkLocked;
+
+ State oldState, newState;
+
+ oldState = mState;
+ mIccCardStatus = newCardStatus;
+ newState = getIccCardState();
+ mState = newState;
+
+ updateStateProperty();
+
+ transitionedIntoPinLocked = (
+ (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED)
+ || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED));
+ transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
+ transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
+ && newState == State.NETWORK_LOCKED);
+
+ if (transitionedIntoPinLocked) {
+ if(mDbg) log("Notify SIM pin or puk locked.");
+ mPinLockedRegistrants.notifyRegistrants();
+ broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
+ (newState == State.PIN_REQUIRED) ?
+ INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
+ } else if (transitionedIntoAbsent) {
+ if(mDbg) log("Notify SIM missing.");
+ mAbsentRegistrants.notifyRegistrants();
+ broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT, null);
+ } else if (transitionedIntoNetworkLocked) {
+ if(mDbg) log("Notify SIM network locked.");
+ mNetworkLockedRegistrants.notifyRegistrants();
+ broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
+ INTENT_VALUE_LOCKED_NETWORK);
+ }
+ }
+
+ /**
+ * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
+ * @param ar is asyncResult of Query_Facility_Locked
+ */
+ private void onQueryFdnEnabled(AsyncResult ar) {
+ if(ar.exception != null) {
+ if(mDbg) log("Error in querying facility lock:" + ar.exception);
+ return;
+ }
+
+ int[] ints = (int[])ar.result;
+ if(ints.length != 0) {
+ mIccFdnEnabled = (0!=ints[0]);
+ if(mDbg) log("Query facility lock : " + mIccFdnEnabled);
+ } else {
+ Log.e(mLogTag, "[IccCard] Bogus facility lock response");
+ }
+ }
+
+ /**
+ * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
+ * @param ar is asyncResult of Query_Facility_Locked
+ */
+ private void onQueryFacilityLock(AsyncResult ar) {
+ if(ar.exception != null) {
+ if (mDbg) log("Error in querying facility lock:" + ar.exception);
+ return;
+ }
+
+ int[] ints = (int[])ar.result;
+ if(ints.length != 0) {
+ mIccPinLocked = (0!=ints[0]);
+ if(mDbg) log("Query facility lock : " + mIccPinLocked);
+ } else {
+ Log.e(mLogTag, "[IccCard] Bogus facility lock response");
+ }
+ }
+
+ public void broadcastIccStateChangedIntent(String value, String reason) {
+ Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Phone.PHONE_NAME_KEY, mPhone.getPhoneName());
+ intent.putExtra(INTENT_KEY_ICC_STATE, value);
+ intent.putExtra(INTENT_KEY_LOCKED_REASON, reason);
+ if(mDbg) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " + value
+ + " reason " + reason);
+ ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE);
+ }
+
+ protected Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg){
+ AsyncResult ar;
+ int serviceClassX;
+
+ serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
+ CommandsInterface.SERVICE_CLASS_DATA +
+ CommandsInterface.SERVICE_CLASS_FAX;
+
+ switch (msg.what) {
+ case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
+ mState = null;
+ updateStateProperty();
+ broadcastIccStateChangedIntent(INTENT_VALUE_ICC_NOT_READY, null);
+ break;
+ case EVENT_ICC_READY:
+ //TODO: put facility read in SIM_READY now, maybe in REG_NW
+ mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
+ mPhone.mCM.queryFacilityLock (
+ CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
+ obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
+ mPhone.mCM.queryFacilityLock (
+ CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
+ obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
+ break;
+ case EVENT_ICC_LOCKED_OR_ABSENT:
+ mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
+ mPhone.mCM.queryFacilityLock (
+ CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
+ obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
+ break;
+ case EVENT_GET_ICC_STATUS_DONE:
+ ar = (AsyncResult)msg.obj;
+
+ getIccCardStatusDone(ar);
+ break;
+ case EVENT_PINPUK_DONE:
+ // a PIN/PUK/PIN2/PUK2/Network Personalization
+ // request has completed. ar.userObj is the response Message
+ // Repoll before returning
+ ar = (AsyncResult)msg.obj;
+ // TODO should abstract these exceptions
+ AsyncResult.forMessage(((Message)ar.userObj)).exception
+ = ar.exception;
+ mPhone.mCM.getIccCardStatus(
+ obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
+ break;
+ case EVENT_REPOLL_STATUS_DONE:
+ // Finished repolling status after PIN operation
+ // ar.userObj is the response messaeg
+ // ar.userObj.obj is already an AsyncResult with an
+ // appropriate exception filled in if applicable
+
+ ar = (AsyncResult)msg.obj;
+ getIccCardStatusDone(ar);
+ ((Message)ar.userObj).sendToTarget();
+ break;
+ case EVENT_QUERY_FACILITY_LOCK_DONE:
+ ar = (AsyncResult)msg.obj;
+ onQueryFacilityLock(ar);
+ break;
+ case EVENT_QUERY_FACILITY_FDN_DONE:
+ ar = (AsyncResult)msg.obj;
+ onQueryFdnEnabled(ar);
+ break;
+ case EVENT_CHANGE_FACILITY_LOCK_DONE:
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception == null) {
+ mIccPinLocked = mDesiredPinLocked;
+ if (mDbg) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
+ "mIccPinLocked= " + mIccPinLocked);
+ } else {
+ Log.e(mLogTag, "Error change facility lock with exception "
+ + ar.exception);
+ }
+ AsyncResult.forMessage(((Message)ar.userObj)).exception
+ = ar.exception;
+ ((Message)ar.userObj).sendToTarget();
+ break;
+ case EVENT_CHANGE_FACILITY_FDN_DONE:
+ ar = (AsyncResult)msg.obj;
+
+ if (ar.exception == null) {
+ mIccFdnEnabled = mDesiredFdnEnabled;
+ if (mDbg) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
+ "mIccFdnEnabled=" + mIccFdnEnabled);
+ } else {
+ Log.e(mLogTag, "Error change facility fdn with exception "
+ + ar.exception);
+ }
+ AsyncResult.forMessage(((Message)ar.userObj)).exception
+ = ar.exception;
+ ((Message)ar.userObj).sendToTarget();
+ break;
+ case EVENT_CHANGE_ICC_PASSWORD_DONE:
+ ar = (AsyncResult)msg.obj;
+ if(ar.exception != null) {
+ Log.e(mLogTag, "Error in change sim password with exception"
+ + ar.exception);
+ }
+ AsyncResult.forMessage(((Message)ar.userObj)).exception
+ = ar.exception;
+ ((Message)ar.userObj).sendToTarget();
+ break;
+ default:
+ Log.e(mLogTag, "[IccCard] Unknown Event " + msg.what);
+ }
+ }
+ };
+
+ public State getIccCardState() {
+ if (mIccCardStatus == null) {
+ Log.e(mLogTag, "[IccCard] IccCardStatus is null");
+ return IccCard.State.ABSENT;
+ }
+
+ // this is common for all radio technologies
+ if (!mIccCardStatus.getCardState().isCardPresent()) {
+ return IccCard.State.ABSENT;
+ }
+
+ RadioState currentRadioState = mPhone.mCM.getRadioState();
+ // check radio technology
+ if( currentRadioState == RadioState.RADIO_OFF ||
+ currentRadioState == RadioState.RADIO_UNAVAILABLE ||
+ currentRadioState == RadioState.SIM_NOT_READY ||
+ currentRadioState == RadioState.RUIM_NOT_READY ||
+ currentRadioState == RadioState.NV_NOT_READY ||
+ currentRadioState == RadioState.NV_READY) {
+ return IccCard.State.NOT_READY;
+ }
+
+ if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT ||
+ currentRadioState == RadioState.SIM_READY ||
+ currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
+ currentRadioState == RadioState.RUIM_READY) {
+
+ int index;
+
+ // check for CDMA radio technology
+ if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
+ currentRadioState == RadioState.RUIM_READY) {
+ index = mIccCardStatus.getCdmaSubscriptionAppIndex();
+ }
+ else {
+ index = mIccCardStatus.getGsmUmtsSubscriptionAppIndex();
+ }
+
+ IccCardApplication app = mIccCardStatus.getApplication(index);
+
+ if (app == null) {
+ Log.e(mLogTag, "[IccCard] Subscription Application in not present");
+ return IccCard.State.ABSENT;
+ }
+
+ // check if PIN required
+ if (app.app_state.isPinRequired()) {
+ return IccCard.State.PIN_REQUIRED;
+ }
+ if (app.app_state.isPukRequired()) {
+ return IccCard.State.PUK_REQUIRED;
+ }
+ if (app.app_state.isSubscriptionPersoEnabled()) {
+ return IccCard.State.NETWORK_LOCKED;
+ }
+ if (app.app_state.isAppReady()) {
+ return IccCard.State.READY;
+ }
+ if (app.app_state.isAppNotReady()) {
+ return IccCard.State.NOT_READY;
+ }
+ return IccCard.State.NOT_READY;
+ }
+
+ return IccCard.State.ABSENT;
+ }
+
+
+ public boolean hasApplicationType(IccCardApplication.AppType type) {
+ if (mIccCardStatus == null) return false;
+
+ for (int i = 0 ; i < mIccCardStatus.getNumApplications(); i++) {
+ IccCardApplication app = mIccCardStatus.getApplication(i);
+ if (app != null && app.app_type == type) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void log(String msg) {
+ Log.d(mLogTag, "[IccCard] " + msg);
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java
index b602b1c..0e7bad7 100644
--- a/telephony/java/com/android/internal/telephony/IccCardStatus.java
+++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java
@@ -45,42 +45,89 @@ public class IccCardStatus {
PINSTATE_ENABLED_PERM_BLOCKED
};
- public CardState card_state;
- public PinState universal_pin_state;
- public int gsm_umts_subscription_app_index;
- public int cdma_subscription_app_index;
- public int num_applications;
+ private CardState mCardState;
+ private PinState mUniversalPinState;
+ private int mGsmUmtsSubscriptionAppIndex;
+ private int mCdmaSubscriptionAppIndex;
+ private int mNumApplications;
- ArrayList<IccCardApplication> application = new ArrayList<IccCardApplication>(CARD_MAX_APPS);
+ private ArrayList<IccCardApplication> mApplications =
+ new ArrayList<IccCardApplication>(CARD_MAX_APPS);
- CardState CardStateFromRILInt(int state) {
- CardState newState;
- /* RIL_CardState ril.h */
+ public CardState getCardState() {
+ return mCardState;
+ }
+
+ public void setCardState(int state) {
switch(state) {
- case 0: newState = CardState.CARDSTATE_ABSENT; break;
- case 1: newState = CardState.CARDSTATE_PRESENT; break;
- case 2: newState = CardState.CARDSTATE_ERROR; break;
- default:
- throw new RuntimeException(
- "Unrecognized RIL_CardState: " +state);
+ case 0:
+ mCardState = CardState.CARDSTATE_ABSENT;
+ break;
+ case 1:
+ mCardState = CardState.CARDSTATE_PRESENT;
+ break;
+ case 2:
+ mCardState = CardState.CARDSTATE_ERROR;
+ break;
+ default:
+ throw new RuntimeException("Unrecognized RIL_CardState: " + state);
}
- return newState;
}
- PinState PinStateFromRILInt(int state) {
- PinState newState;
- /* RIL_PinState ril.h */
+ public void setUniversalPinState(int state) {
switch(state) {
- case 0: newState = PinState.PINSTATE_UNKNOWN; break;
- case 1: newState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; break;
- case 2: newState = PinState.PINSTATE_ENABLED_VERIFIED; break;
- case 3: newState = PinState.PINSTATE_DISABLED; break;
- case 4: newState = PinState.PINSTATE_ENABLED_BLOCKED; break;
- case 5: newState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; break;
- default:
- throw new RuntimeException(
- "Unrecognized RIL_PinState: " +state);
+ case 0:
+ mUniversalPinState = PinState.PINSTATE_UNKNOWN;
+ break;
+ case 1:
+ mUniversalPinState = PinState.PINSTATE_ENABLED_NOT_VERIFIED;
+ break;
+ case 2:
+ mUniversalPinState = PinState.PINSTATE_ENABLED_VERIFIED;
+ break;
+ case 3:
+ mUniversalPinState = PinState.PINSTATE_DISABLED;
+ break;
+ case 4:
+ mUniversalPinState = PinState.PINSTATE_ENABLED_BLOCKED;
+ break;
+ case 5:
+ mUniversalPinState = PinState.PINSTATE_ENABLED_PERM_BLOCKED;
+ break;
+ default:
+ throw new RuntimeException("Unrecognized RIL_PinState: " + state);
}
- return newState;
+ }
+
+ public int getGsmUmtsSubscriptionAppIndex() {
+ return mGsmUmtsSubscriptionAppIndex;
+ }
+
+ public void setGsmUmtsSubscriptionAppIndex(int gsmUmtsSubscriptionAppIndex) {
+ mGsmUmtsSubscriptionAppIndex = gsmUmtsSubscriptionAppIndex;
+ }
+
+ public int getCdmaSubscriptionAppIndex() {
+ return mCdmaSubscriptionAppIndex;
+ }
+
+ public void setCdmaSubscriptionAppIndex(int cdmaSubscriptionAppIndex) {
+ mCdmaSubscriptionAppIndex = cdmaSubscriptionAppIndex;
+ }
+
+ public int getNumApplications() {
+ return mNumApplications;
+ }
+
+ public void setNumApplications(int numApplications) {
+ mNumApplications = numApplications;
+ }
+
+ public void addApplication(IccCardApplication application) {
+ mApplications.add(application);
+ }
+
+ public IccCardApplication getApplication(int index) {
+ return mApplications.get(index);
}
}
diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java
index 881ed2d..3e7094e 100644
--- a/telephony/java/com/android/internal/telephony/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/IccUtils.java
@@ -74,7 +74,7 @@ public class IccUtils {
* exactly as received"
*/
public static int
- bcdByteToInt(byte b) {
+ gsmBcdByteToInt(byte b) {
int ret = 0;
// treat out-of-range BCD values as 0
@@ -89,11 +89,14 @@ public class IccUtils {
return ret;
}
- /** Decodes BCD byte like {@link bcdByteToInt}, but the most significant BCD
- * digit is expected in the most significant nibble.
+ /**
+ * Decodes a CDMA style BCD byte like {@link gsmBcdByteToInt}, but
+ * opposite nibble format. The least significant BCD digit
+ * is in the least significant nibble and the most significant
+ * is in the most significant nibble.
*/
public static int
- beBcdByteToInt(byte b) {
+ cdmaBcdByteToInt(byte b) {
int ret = 0;
// treat out-of-range BCD values as 0
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 7f2b849..e818175 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -22,6 +22,7 @@ import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.telephony.CellLocation;
+import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -98,8 +99,9 @@ public interface Phone {
static final String PHONE_NAME_KEY = "phoneName";
static final String FAILURE_REASON_KEY = "reason";
static final String STATE_CHANGE_REASON_KEY = "reason";
- static final String DATA_APN_TYPE_KEY = "apnType";
+ static final String DATA_APN_TYPES_KEY = "apnType";
static final String DATA_APN_KEY = "apn";
+
static final String DATA_IFACE_NAME_KEY = "iface";
static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
static final String PHONE_IN_ECM_STATE = "phoneinECMState";
@@ -119,10 +121,16 @@ public interface Phone {
static final String APN_TYPE_MMS = "mms";
/** APN type for SUPL assisted GPS */
static final String APN_TYPE_SUPL = "supl";
+ /** APN type for DUN traffic */
+ static final String APN_TYPE_DUN = "dun";
+ /** APN type for HiPri traffic */
+ static final String APN_TYPE_HIPRI = "hipri";
// "Features" accessible through the connectivity manager
static final String FEATURE_ENABLE_MMS = "enableMMS";
static final String FEATURE_ENABLE_SUPL = "enableSUPL";
+ static final String FEATURE_ENABLE_DUN = "enableDUN";
+ static final String FEATURE_ENABLE_HIPRI = "enableHIPRI";
/**
* Return codes for <code>enableApnType()</code>
@@ -260,8 +268,8 @@ public interface Phone {
/**
* Get current coarse-grained voice call state.
- * Use {@link #registerForPhoneStateChanged(Handler, int, Object)
- * registerForPhoneStateChanged()} for change notification. <p>
+ * Use {@link #registerForPreciseCallStateChanged(Handler, int, Object)
+ * registerForPreciseCallStateChanged()} for change notification. <p>
* If the phone has an active call and call waiting occurs,
* then the phone state is RINGING not OFFHOOK
* <strong>Note:</strong>
@@ -315,18 +323,21 @@ public interface Phone {
void unregisterForUnknownConnection(Handler h);
/**
- * Notifies when any aspect of the voice call state changes.
+ * Register for getting notifications for change in the Call State {@link Call.State}
+ * This is called PreciseCallState because the call state is more precise than the
+ * {@link Phone.State} which can be obtained using the {@link PhoneStateListener}
+ *
* Resulting events will have an AsyncResult in <code>Message.obj</code>.
* AsyncResult.userData will be set to the obj argument here.
* The <em>h</em> parameter is held only by a weak reference.
*/
- void registerForPhoneStateChanged(Handler h, int what, Object obj);
+ void registerForPreciseCallStateChanged(Handler h, int what, Object obj);
/**
* Unregisters for voice call state change notifications.
* Extraneous calls are tolerated silently.
*/
- void unregisterForPhoneStateChanged(Handler h);
+ void unregisterForPreciseCallStateChanged(Handler h);
/**
@@ -423,6 +434,20 @@ public interface Phone {
void unregisterForMmiComplete(Handler h);
/**
+ * Registration point for Ecm timer reset
+ * @param h handler to notify
+ * @param what user-defined message code
+ * @param obj placed in Message.obj
+ */
+ public void registerForEcmTimerReset(Handler h, int what, Object obj);
+
+ /**
+ * Unregister for notification for Ecm timer reset
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForEcmTimerReset(Handler h);
+
+ /**
* Returns a list of MMI codes that are pending. (They have initiated
* but have not yet completed).
* Presently there is only ever one.
@@ -538,6 +563,20 @@ public interface Phone {
void unregisterForCdmaOtaStatusChange(Handler h);
/**
+ * Registration point for subscription info ready
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ public void registerForSubscriptionInfoReady(Handler h, int what, Object obj);
+
+ /**
+ * Unregister for notifications for subscription info
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForSubscriptionInfoReady(Handler h);
+
+ /**
* Returns SIM record load state. Use
* <code>getSimCard().registerForReady()</code> for change notification.
*
@@ -556,8 +595,8 @@ public interface Phone {
/**
* Answers a ringing or waiting call. Active calls, if any, go on hold.
* Answering occurs asynchronously, and final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*
* @exception CallStateException when no call is ringing or waiting
*/
@@ -567,8 +606,8 @@ public interface Phone {
* Reject (ignore) a ringing call. In GSM, this means UDUB
* (User Determined User Busy). Reject occurs asynchronously,
* and final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*
* @exception CallStateException when no call is ringing or waiting
*/
@@ -578,8 +617,8 @@ public interface Phone {
* Places any active calls on hold, and makes any held calls
* active. Switch occurs asynchronously and may fail.
* Final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*
* @exception CallStateException if a call is ringing, waiting, or
* dialing/alerting. In these cases, this operation may not be performed.
@@ -596,8 +635,8 @@ public interface Phone {
/**
* Conferences holding and active. Conference occurs asynchronously
* and may fail. Final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*
* @exception CallStateException if canConference() would return false.
* In these cases, this operation may not be performed.
@@ -631,8 +670,8 @@ public interface Phone {
* Connects the two calls and disconnects the subscriber from both calls
* Explicit Call Transfer occurs asynchronously
* and may fail. Final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*
* @exception CallStateException if canTransfer() would return false.
* In these cases, this operation may not be performed.
@@ -659,8 +698,8 @@ public interface Phone {
* IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED.
*
* State change notification is available via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*/
Call getForegroundCall();
@@ -676,8 +715,8 @@ public interface Phone {
* IDLE, HOLDING or DISCONNECTED.
*
* State change notification is available via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*/
Call getBackgroundCall();
@@ -693,8 +732,8 @@ public interface Phone {
* IDLE, INCOMING, WAITING or DISCONNECTED.
*
* State change notification is available via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
*/
Call getRingingCall();
@@ -1067,8 +1106,8 @@ public interface Phone {
/**
* Gets current mute status. Use
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}
* as a change notifcation, although presently phone state changed is not
* fired when setMute() is called.
*
@@ -1262,6 +1301,13 @@ public interface Phone {
boolean disableDataConnectivity();
/**
+ * Report the current state of data connectivity (enabled or disabled)
+ * @return {@code false} if data connectivity has been explicitly disabled,
+ * {@code true} otherwise.
+ */
+ boolean isDataConnectivityEnabled();
+
+ /**
* Enables the specified APN type. Only works for "special" APN types,
* i.e., not the default APN.
* @param type The desired APN type. Cannot be {@link #APN_TYPE_DEFAULT}.
@@ -1342,7 +1388,7 @@ public interface Phone {
*/
String getIccSerialNumber();
- //***** CDMA support methods
+ /* CDMA support methods */
/*
* TODO(Moto) TODO(Teleca): can getCdmaMin, getEsn, getMeid use more generic calls
@@ -1355,6 +1401,13 @@ public interface Phone {
String getCdmaMin();
/**
+ * Check if subscription data has been assigned to mMin
+ *
+ * return true if MIN info is ready; false otherwise.
+ */
+ boolean isMinInfoReady();
+
+ /**
* Retrieves PRL Version for CDMA phones
*/
String getCdmaPrlVersion();
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index bcb1ccc..e340f85 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,8 +29,8 @@ 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;
import android.util.Log;
@@ -53,17 +54,20 @@ import java.util.Locale;
*
*/
-public abstract class PhoneBase implements Phone {
+public abstract class PhoneBase extends Handler implements Phone {
private static final String LOG_TAG = "PHONE";
private static final boolean LOCAL_DEBUG = true;
- // Key used to read and write the saved network selection value
+ // Key used to read and write the saved network selection numeric value
public static final String NETWORK_SELECTION_KEY = "network_selection_key";
+ // Key used to read and write the saved network selection operator name
+ public static final String NETWORK_SELECTION_NAME_KEY = "network_selection_name_key";
- // Key used to read/write "disable data connection on boot" pref (used for testing)
+
+ // Key used to read/write "disable data connection on boot" pref (used for testing)
public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key";
- //***** Event Constants
+ /* Event Constants */
protected static final int EVENT_RADIO_AVAILABLE = 1;
/** Supplementary Service Notification received. */
protected static final int EVENT_SSN = 2;
@@ -79,20 +83,22 @@ public abstract class PhoneBase implements Phone {
protected static final int EVENT_SET_CALL_FORWARD_DONE = 12;
protected static final int EVENT_GET_CALL_FORWARD_DONE = 13;
protected static final int EVENT_CALL_RING = 14;
+ protected static final int EVENT_CALL_RING_CONTINUE = 15;
+
// Used to intercept the carrier selection calls so that
// we can save the values.
- protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 15;
- protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 16;
- protected static final int EVENT_SET_CLIR_COMPLETE = 17;
- protected static final int EVENT_REGISTERED_TO_NETWORK = 18;
- protected static final int EVENT_SET_VM_NUMBER_DONE = 19;
+ protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 16;
+ protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 17;
+ protected static final int EVENT_SET_CLIR_COMPLETE = 18;
+ protected static final int EVENT_REGISTERED_TO_NETWORK = 19;
+ protected static final int EVENT_SET_VM_NUMBER_DONE = 20;
// Events for CDMA support
- protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 20;
- protected static final int EVENT_RUIM_RECORDS_LOADED = 21;
- protected static final int EVENT_NV_READY = 22;
- protected static final int EVENT_SET_ENHANCED_VP = 23;
- protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER = 24;
- protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 25;
+ protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 21;
+ protected static final int EVENT_RUIM_RECORDS_LOADED = 22;
+ protected static final int EVENT_NV_READY = 23;
+ protected static final int EVENT_SET_ENHANCED_VP = 24;
+ protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER = 25;
+ protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 26;
// Key used to read/write current CLIR setting
public static final String CLIR_KEY = "clir_key";
@@ -100,10 +106,14 @@ public abstract class PhoneBase implements Phone {
// Key used to read/write "disable DNS server check" pref (used for testing)
public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key";
- //***** Instance Variables
+ /* Instance Variables */
public CommandsInterface mCM;
protected IccFileHandler mIccFileHandler;
boolean mDnsCheckDisabled = false;
+ public DataConnectionTracker mDataConnection;
+ boolean mDoesRilSendMultipleCallRing;
+ int mCallRingContinueToken = 0;
+ int mCallRingDelay;
/**
* Set a system property, unless we're in unit test mode
@@ -117,7 +127,7 @@ public abstract class PhoneBase implements Phone {
}
- protected final RegistrantList mPhoneStateRegistrants
+ protected final RegistrantList mPreciseCallStateRegistrants
= new RegistrantList();
protected final RegistrantList mNewRingingConnectionRegistrants
@@ -166,8 +176,8 @@ public abstract class PhoneBase implements Phone {
* @param notifier An instance of DefaultPhoneNotifier,
* unless unit testing.
*/
- protected PhoneBase(PhoneNotifier notifier, Context context) {
- this(notifier, context, false);
+ protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci) {
+ this(notifier, context, ci, false);
}
/**
@@ -179,18 +189,83 @@ public abstract class PhoneBase implements Phone {
* @param unitTestMode when true, prevents notifications
* of state change events
*/
- protected PhoneBase(PhoneNotifier notifier, Context context,
+ protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,
boolean unitTestMode) {
this.mNotifier = notifier;
this.mContext = context;
mLooper = Looper.myLooper();
+ mCM = ci;
- setLocaleByCarrier();
+ setPropertiesByCarrier();
setUnitTestMode(unitTestMode);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);
+ mCM.setOnCallRing(this, EVENT_CALL_RING, null);
+
+ /**
+ * Some RIL's don't always send RIL_UNSOL_CALL_RING so it needs
+ * to be generated locally. Ideally all ring tones should be loops
+ * and this wouldn't be necessary. But to minimize changes to upper
+ * layers it is requested that it be generated by lower layers.
+ *
+ * By default old phones won't have the property set but do generate
+ * the RIL_UNSOL_CALL_RING so the default if there is no property is
+ * true.
+ */
+ mDoesRilSendMultipleCallRing = SystemProperties.getBoolean(
+ TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true);
+ Log.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
+
+ mCallRingDelay = SystemProperties.getInt(
+ TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);
+ Log.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);
+ }
+
+ public void dispose() {
+ synchronized(PhoneProxy.lockForRadioTechnologyChange) {
+ mCM.unSetOnCallRing(this);
+ }
+ }
+
+ /**
+ * When overridden the derived class needs to call
+ * super.handleMessage(msg) so this method has a
+ * a chance to process the message.
+ *
+ * @param msg
+ */
+ @Override
+ public void handleMessage(Message msg) {
+ AsyncResult ar;
+
+ switch(msg.what) {
+ case EVENT_CALL_RING:
+ Log.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState());
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception == null) {
+ Phone.State state = getState();
+ if ((!mDoesRilSendMultipleCallRing)
+ && ((state == Phone.State.RINGING) || (state == Phone.State.IDLE))) {
+ mCallRingContinueToken += 1;
+ sendIncomingCallRingNotification(mCallRingContinueToken);
+ } else {
+ notifyIncomingRing();
+ }
+ }
+ break;
+
+ case EVENT_CALL_RING_CONTINUE:
+ Log.d(LOG_TAG, "Event EVENT_CALL_RING_CONTINUE Received stat=" + getState());
+ if (getState() == Phone.State.RINGING) {
+ sendIncomingCallRingNotification(msg.arg1);
+ }
+ break;
+
+ default:
+ throw new RuntimeException("unexpected event not handled");
+ }
}
// Inherited documentation suffices.
@@ -219,25 +294,24 @@ public abstract class PhoneBase implements Phone {
}
// Inherited documentation suffices.
- public void registerForPhoneStateChanged(Handler h, int what, Object obj) {
+ public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) {
checkCorrectThread(h);
- mPhoneStateRegistrants.addUnique(h, what, obj);
+ mPreciseCallStateRegistrants.addUnique(h, what, obj);
}
// Inherited documentation suffices.
- public void unregisterForPhoneStateChanged(Handler h) {
- mPhoneStateRegistrants.remove(h);
+ public void unregisterForPreciseCallStateChanged(Handler h) {
+ mPreciseCallStateRegistrants.remove(h);
}
/**
- * Notify registrants of a PhoneStateChanged.
* Subclasses of Phone probably want to replace this with a
* version scoped to their packages
*/
- protected void notifyCallStateChangedP() {
+ protected void notifyPreciseCallStateChangedP() {
AsyncResult ar = new AsyncResult(null, this, null);
- mPhoneStateRegistrants.notifyRegistrants(ar);
+ mPreciseCallStateRegistrants.notifyRegistrants(ar);
}
// Inherited documentation suffices.
@@ -285,16 +359,6 @@ public abstract class PhoneBase implements Phone {
mCM.unregisterForInCallVoicePrivacyOff(h);
}
- /**
- * Notifiy registrants of a new ringing Connection.
- * Subclasses of Phone probably want to replace this with a
- * version scoped to their packages
- */
- protected void notifyNewRingingConnectionP(Connection cn) {
- AsyncResult ar = new AsyncResult(null, cn, null);
- mNewRingingConnectionRegistrants.notifyRegistrants(ar);
- }
-
// Inherited documentation suffices.
public void registerForIncomingRing(
Handler h, int what, Object obj) {
@@ -450,10 +514,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 +525,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;
}
}
@@ -530,16 +612,22 @@ public abstract class PhoneBase implements Phone {
}
}
- /*
- * Retrieves the Handler of the Phone instance
+ /**
+ * Get state
*/
- public abstract Handler getHandler();
+ public abstract Phone.State getState();
/**
* Retrieves the IccFileHandler of the Phone instance
*/
public abstract IccFileHandler getIccFileHandler();
+ /*
+ * Retrieves the Handler of the Phone instance
+ */
+ public Handler getHandler() {
+ return this;
+ }
/**
* Query the status of the CDMA roaming preference
@@ -595,7 +683,7 @@ public abstract class PhoneBase implements Phone {
* This should only be called in GSM mode.
* Only here for some backward compatibility
* issues concerning the GSMPhone class.
- * @deprecated
+ * @deprecated Always returns null.
*/
public List<PdpConnection> getCurrentPdpList() {
return null;
@@ -679,6 +767,12 @@ public abstract class PhoneBase implements Phone {
return null;
}
+ public boolean isMinInfoReady() {
+ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+ Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+ return false;
+ }
+
public String getCdmaPrlVersion(){
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
@@ -705,6 +799,16 @@ public abstract class PhoneBase implements Phone {
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
}
+ public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+ Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+ }
+
+ public void unregisterForSubscriptionInfoReady(Handler h) {
+ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+ Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+ }
+
public boolean isOtaSpNumber(String dialStr) {
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
@@ -721,6 +825,16 @@ public abstract class PhoneBase implements Phone {
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
}
+ public void registerForEcmTimerReset(Handler h, int what, Object obj) {
+ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+ Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+ }
+
+ public void unregisterForEcmTimerReset(Handler h) {
+ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
+ Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
+ }
+
public void registerForSignalInfo(Handler h, int what, Object obj) {
mCM.registerForSignalInfo(h, what, obj);
}
@@ -786,4 +900,106 @@ public abstract class PhoneBase implements Phone {
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
}
+
+ public String getInterfaceName(String apnType) {
+ return mDataConnection.getInterfaceName(apnType);
+ }
+
+ public String getIpAddress(String apnType) {
+ return mDataConnection.getIpAddress(apnType);
+ }
+
+ public boolean isDataConnectivityEnabled() {
+ return mDataConnection.getDataEnabled();
+ }
+
+ public String getGateway(String apnType) {
+ return mDataConnection.getGateway(apnType);
+ }
+
+ public String[] getDnsServers(String apnType) {
+ return mDataConnection.getDnsServers(apnType);
+ }
+
+ public String[] getActiveApnTypes() {
+ return mDataConnection.getActiveApnTypes();
+ }
+
+ public String getActiveApn() {
+ return mDataConnection.getActiveApnString();
+ }
+
+ public int enableApnType(String type) {
+ return mDataConnection.enableApnType(type);
+ }
+
+ public int disableApnType(String type) {
+ return mDataConnection.disableApnType(type);
+ }
+
+ /**
+ * simulateDataConnection
+ *
+ * simulates various data connection states. This messes with
+ * DataConnectionTracker's internal states, but doesn't actually change
+ * the underlying radio connection states.
+ *
+ * @param state Phone.DataState enum.
+ */
+ public void simulateDataConnection(Phone.DataState state) {
+ DataConnectionTracker.State dcState;
+
+ switch (state) {
+ case CONNECTED:
+ dcState = DataConnectionTracker.State.CONNECTED;
+ break;
+ case SUSPENDED:
+ dcState = DataConnectionTracker.State.CONNECTED;
+ break;
+ case DISCONNECTED:
+ dcState = DataConnectionTracker.State.FAILED;
+ break;
+ default:
+ dcState = DataConnectionTracker.State.CONNECTING;
+ break;
+ }
+
+ mDataConnection.setState(dcState);
+ notifyDataConnection(null);
+ }
+
+ /**
+ * Notifiy registrants of a new ringing Connection.
+ * Subclasses of Phone probably want to replace this with a
+ * version scoped to their packages
+ */
+ protected void notifyNewRingingConnectionP(Connection cn) {
+ AsyncResult ar = new AsyncResult(null, cn, null);
+ mNewRingingConnectionRegistrants.notifyRegistrants(ar);
+ }
+
+ /**
+ * Notify registrants of a RING event.
+ */
+ private void notifyIncomingRing() {
+ AsyncResult ar = new AsyncResult(null, this, null);
+ mIncomingRingRegistrants.notifyRegistrants(ar);
+ }
+
+ /**
+ * Send the incoming call Ring notification if conditions are right.
+ */
+ private void sendIncomingCallRingNotification(int token) {
+ if (!mDoesRilSendMultipleCallRing && (token == mCallRingContinueToken)) {
+ Log.d(LOG_TAG, "Sending notifyIncomingRing");
+ notifyIncomingRing();
+ sendMessageDelayed(
+ obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay);
+ } else {
+ Log.d(LOG_TAG, "Ignoring ring notification request,"
+ + " mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing
+ + " token=" + token
+ + " mCallRingContinueToken=" + mCallRingContinueToken);
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index da00268..8683278 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.telephony.CellLocation;
+import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.util.Log;
@@ -210,12 +211,12 @@ public class PhoneProxy extends Handler implements Phone {
mActivePhone.unregisterForUnknownConnection(h);
}
- public void registerForPhoneStateChanged(Handler h, int what, Object obj) {
- mActivePhone.registerForPhoneStateChanged(h, what, obj);
+ public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) {
+ mActivePhone.registerForPreciseCallStateChanged(h, what, obj);
}
- public void unregisterForPhoneStateChanged(Handler h) {
- mActivePhone.unregisterForPhoneStateChanged(h);
+ public void unregisterForPreciseCallStateChanged(Handler h) {
+ mActivePhone.unregisterForPreciseCallStateChanged(h);
}
public void registerForNewRingingConnection(Handler h, int what, Object obj) {
@@ -314,6 +315,22 @@ public class PhoneProxy extends Handler implements Phone {
mActivePhone.unregisterForCdmaOtaStatusChange(h);
}
+ public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+ mActivePhone.registerForSubscriptionInfoReady(h, what, obj);
+ }
+
+ public void unregisterForSubscriptionInfoReady(Handler h) {
+ mActivePhone.unregisterForSubscriptionInfoReady(h);
+ }
+
+ public void registerForEcmTimerReset(Handler h, int what, Object obj) {
+ mActivePhone.registerForEcmTimerReset(h,what,obj);
+ }
+
+ public void unregisterForEcmTimerReset(Handler h) {
+ mActivePhone.unregisterForEcmTimerReset(h);
+ }
+
public boolean getIccRecordsLoaded() {
return mActivePhone.getIccRecordsLoaded();
}
@@ -418,6 +435,10 @@ public class PhoneProxy extends Handler implements Phone {
return mActivePhone.getCdmaMin();
}
+ public boolean isMinInfoReady() {
+ return mActivePhone.isMinInfoReady();
+ }
+
public String getCdmaPrlVersion() {
return mActivePhone.getCdmaPrlVersion();
}
@@ -613,6 +634,10 @@ public class PhoneProxy extends Handler implements Phone {
return mActivePhone.disableApnType(type);
}
+ public boolean isDataConnectivityEnabled() {
+ return mActivePhone.isDataConnectivityEnabled();
+ }
+
public boolean isDataConnectivityPossible() {
return mActivePhone.isDataConnectivityPossible();
}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 690b38a..cd6340e 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -630,7 +630,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
}
public void
- getIccStatus(Message result) {
+ getIccCardStatus(Message result) {
//Note: This RIL request has not been renamed to ICC,
// but this request is also valid for SIM and RUIM
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);
@@ -1237,10 +1237,17 @@ public final class RIL extends BaseCommands implements CommandsInterface {
*/
public void
setupDefaultPDP(String apn, String user, String password, Message result) {
- String radioTechnology = "1"; //0 for CDMA, 1 for GSM/UMTS
+ int radioTechnology;
+ int authType;
String profile = ""; //profile number, NULL for GSM/UMTS
- setupDataCall(radioTechnology, profile, apn, user,
- password, result);
+
+ radioTechnology = RILConstants.SETUP_DATA_TECH_GSM;
+ //TODO(): Add to the APN database, AuthType is set to CHAP/PAP
+ authType = (user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP
+ : RILConstants.SETUP_DATA_AUTH_NONE;
+
+ setupDataCall(Integer.toString(radioTechnology), profile, apn, user,
+ password, Integer.toString(authType), result);
}
@@ -1259,7 +1266,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
*/
public void
setupDataCall(String radioTechnology, String profile, String apn,
- String user, String password, Message result) {
+ String user, String password, String authType, Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
@@ -1270,15 +1277,12 @@ public final class RIL extends BaseCommands implements CommandsInterface {
rr.mp.writeString(apn);
rr.mp.writeString(user);
rr.mp.writeString(password);
- //TODO(): Add to the APN database, AuthType is set to CHAP/PAP
- // 0 => Neither PAP nor CHAP will be performed, 3 => PAP / CHAP will be performed.
- if (user != null)
- rr.mp.writeString("3");
- else
- rr.mp.writeString("0");
+ rr.mp.writeString(authType);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " "
- + apn);
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ + requestToString(rr.mRequest) + " " + radioTechnology + " "
+ + profile + " " + apn + " " + user + " "
+ + password + " " + authType);
send(rr);
}
@@ -2507,6 +2511,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
mRestrictedStateRegistrant.notifyRegistrant(
new AsyncResult (null, ret, null));
}
+ break;
case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
if (RILJ_LOGD) unsljLog(response);
@@ -2553,7 +2558,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
break;
case RIL_UNSOL_CDMA_CALL_WAITING:
- if (RILJ_LOGD) unsljLog(response);
+ if (RILJ_LOGD) unsljLogRet(response, ret);
if (mCallWaitingInfoRegistrants != null) {
mCallWaitingInfoRegistrants.notifyRegistrants(
@@ -2735,24 +2740,22 @@ public final class RIL extends BaseCommands implements CommandsInterface {
private Object
responseIccCardStatus(Parcel p) {
- RadioState currentRadioState;
IccCardApplication ca;
- currentRadioState = getRadioState();
-
IccCardStatus status = new IccCardStatus();
- status.card_state = status.CardStateFromRILInt(p.readInt());
- status.universal_pin_state = status.PinStateFromRILInt(p.readInt());
- status.gsm_umts_subscription_app_index = p.readInt();
- status.cdma_subscription_app_index = p.readInt();
- status.num_applications = p.readInt();
+ status.setCardState(p.readInt());
+ status.setUniversalPinState(p.readInt());
+ status.setGsmUmtsSubscriptionAppIndex(p.readInt());
+ status.setCdmaSubscriptionAppIndex(p.readInt());
+ int numApplications = p.readInt();
// limit to maximum allowed applications
- if (status.num_applications > IccCardStatus.CARD_MAX_APPS) {
- status.num_applications = IccCardStatus.CARD_MAX_APPS;
+ if (numApplications > IccCardStatus.CARD_MAX_APPS) {
+ numApplications = IccCardStatus.CARD_MAX_APPS;
}
+ status.setNumApplications(numApplications);
- for (int i = 0 ; i < status.num_applications ; i++) {
+ for (int i = 0 ; i < numApplications ; i++) {
ca = new IccCardApplication();
ca.app_type = ca.AppTypeFromRILInt(p.readInt());
ca.app_state = ca.AppStateFromRILInt(p.readInt());
@@ -2762,62 +2765,9 @@ public final class RIL extends BaseCommands implements CommandsInterface {
ca.pin1_replaced = p.readInt();
ca.pin1 = p.readInt();
ca.pin2 = p.readInt();
- status.application.add(ca);
- }
-
- // this is common for all radio technologies
- if (!status.card_state.isCardPresent()) {
- return IccStatus.ICC_ABSENT;
- }
-
- // check radio technology
- if( currentRadioState == RadioState.RADIO_OFF ||
- currentRadioState == RadioState.RADIO_UNAVAILABLE ||
- currentRadioState == RadioState.SIM_NOT_READY ||
- currentRadioState == RadioState.RUIM_NOT_READY ||
- currentRadioState == RadioState.NV_NOT_READY ||
- currentRadioState == RadioState.NV_READY ) {
- return IccStatus.ICC_NOT_READY;
+ status.addApplication(ca);
}
-
- if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT ||
- currentRadioState == RadioState.SIM_READY ||
- currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
- currentRadioState == RadioState.RUIM_READY) {
-
- int index;
-
- // check for CDMA radio technology
- if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
- currentRadioState == RadioState.RUIM_READY) {
- index = status.cdma_subscription_app_index;
- }
- else {
- index = status.gsm_umts_subscription_app_index;
- }
-
- // check if PIN required
- if (status.application.get(index).app_state.isPinRequired()) {
- return IccStatus.ICC_PIN;
- }
- if (status.application.get(index).app_state.isPukRequired()) {
- return IccStatus.ICC_PUK;
- }
- if (status.application.get(index).app_state.isSubscriptionPersoEnabled()) {
- return IccStatus.ICC_NETWORK_PERSONALIZATION;
- }
- if (status.application.get(index).app_state.isAppReady()) {
- return IccStatus.ICC_READY;
- }
- if (status.application.get(index).app_state.isAppNotReady()) {
- return IccStatus.ICC_NOT_READY;
- }
- return IccStatus.ICC_NOT_READY;
- }
-
- // Unrecognized ICC status. Treat it like a missing ICC.
- Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status);
- return IccStatus.ICC_ABSENT;
+ return status;
}
private Object
@@ -3035,7 +2985,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
CdmaCallWaitingNotification notification = new CdmaCallWaitingNotification();
notification.number = p.readString();
- notification.numberPresentation = p.readInt();
+ notification.numberPresentation = notification.presentationFromCLIP(p.readInt());
notification.name = p.readString();
notification.namePresentation = notification.numberPresentation;
notification.isPresent = p.readInt();
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 0763e63..90a82f9 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -79,6 +79,14 @@ public interface RILConstants {
int CDM_TTY_HCO_MODE = 2;
int CDM_TTY_VCO_MODE = 3;
+ /* Setup a packet data connection. See ril.h RIL_REQUEST_SETUP_DATA_CALL */
+ int SETUP_DATA_TECH_CDMA = 0;
+ int SETUP_DATA_TECH_GSM = 1;
+ int SETUP_DATA_AUTH_NONE = 0;
+ int SETUP_DATA_AUTH_PAP = 1;
+ int SETUP_DATA_AUTH_CHAP = 2;
+ int SETUP_DATA_AUTH_PAP_CHAP = 3;
+
/*
cat include/telephony/ril.h | \
egrep '^#define' | \
diff --git a/telephony/java/com/android/internal/telephony/RetryManager.java b/telephony/java/com/android/internal/telephony/RetryManager.java
new file mode 100644
index 0000000..385b191
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/RetryManager.java
@@ -0,0 +1,392 @@
+/**
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.util.Log;
+import android.util.Pair;
+import android.text.TextUtils;
+
+import java.util.Random;
+import java.util.ArrayList;
+
+/**
+ * Retry manager allows a simple way to declare a series of
+ * retires timeouts. After creating a RetryManager the configure
+ * method is used to define the sequence. A simple linear series
+ * may be initialized using configure with three integer parameters
+ * The other configure method allows a series to be declared using
+ * a string.
+ *<p>
+ * The format of the configuration string is a series of parameters
+ * separated by a comma. There are two name value pair parameters plus a series
+ * of delay times. The units of of these delay times is unspecified.
+ * The name value pairs which may be specified are:
+ *<ul>
+ *<li>max_retries=<value>
+ *<li>default_randomizationTime=<value>
+ *</ul>
+ *<p>
+ * max_retries is the number of times that incrementRetryCount
+ * maybe called before isRetryNeeded will return false. if value
+ * is infinite then isRetryNeeded will always return true.
+ *
+ * default_randomizationTime will be used as the randomizationTime
+ * for delay times which have no supplied randomizationTime. If
+ * default_randomizationTime is not defined it defaults to 0.
+ *<p>
+ * The other parameters define The series of delay times and each
+ * may have an optional randomization value separated from the
+ * delay time by a colon.
+ *<p>
+ * Examples:
+ * <ul>
+ * <li>3 retires with no randomization value which means its 0:
+ * <ul><li><code>"1000, 2000, 3000"</code></ul>
+ *
+ * <li>10 retires with a 500 default randomization value for each and
+ * the 4..10 retries all using 3000 as the delay:
+ * <ul><li><code>"max_retries=10, default_randomization=500, 1000, 2000, 3000"</code></ul>
+ *
+ * <li>4 retires with a 100 as the default randomization value for the first 2 values and
+ * the other two having specified values of 500:
+ * <ul><li><code>"default_randomization=100, 1000, 2000, 4000:500, 5000:500"</code></ul>
+ *
+ * <li>Infinite number of retires with the first one at 1000, the second at 2000 all
+ * others will be at 3000.
+ * <ul><li><code>"max_retries=infinite,1000,2000,3000</code></ul>
+ * </ul>
+ *
+ * {@hide}
+ */
+public class RetryManager {
+ static public final String LOG_TAG = "RetryManager";
+ static public final boolean DBG = false;
+ static public final int RETRYIES_NOT_STARTED = 0;
+ static public final int RETRYIES_ON_GOING = 1;
+ static public final int RETRYIES_COMPLETED = 2;
+
+ /**
+ * Retry record with times in milli-seconds
+ */
+ private static class RetryRec {
+ RetryRec(int delayTime, int randomizationTime) {
+ mDelayTime = delayTime;
+ mRandomizationTime = randomizationTime;
+ }
+
+ int mDelayTime;
+ int mRandomizationTime;
+ }
+
+ /** The array of retry records */
+ private ArrayList<RetryRec> mRetryArray = new ArrayList<RetryRec>();
+
+ /** When true isRetryNeeded() will always return true */
+ private boolean mRetryForever;
+
+ /**
+ * The maximum number of retries to attempt before
+ * isRetryNeeded returns false
+ */
+ private int mMaxRetryCount;
+
+ /** The current number of retires */
+ private int mRetryCount;
+
+ /** Random number generator */
+ private Random rng = new Random();
+
+ /** Constructor */
+ public RetryManager() {
+ if (DBG) log("constructor");
+ }
+
+ /**
+ * Configure for a simple linear sequence of times plus
+ * a random value.
+ *
+ * @param maxRetryCount is the maximum number of retries
+ * before isRetryNeeded returns false.
+ * @param retryTime is a time that will be returned by getRetryTime.
+ * @param randomizationTime a random value between 0 and
+ * randomizationTime will be added to retryTime. this
+ * parameter may be 0.
+ * @return true if successfull
+ */
+ public boolean configure(int maxRetryCount, int retryTime, int randomizationTime) {
+ Pair<Boolean, Integer> value;
+
+ if (DBG) log("configure: " + maxRetryCount + ", " + retryTime + "," + randomizationTime);
+
+ if (!validateNonNegativeInt("maxRetryCount", maxRetryCount)) {
+ return false;
+ }
+
+ if (!validateNonNegativeInt("retryTime", retryTime)) {
+ return false;
+ }
+
+ if (!validateNonNegativeInt("randomizationTime", randomizationTime)) {
+ return false;
+ }
+
+ mMaxRetryCount = maxRetryCount;
+ resetRetryCount();
+ mRetryArray.clear();
+ mRetryArray.add(new RetryRec(retryTime, randomizationTime));
+
+ return true;
+ }
+
+ /**
+ * Configure for using string which allow arbitary
+ * sequences of times. See class comments for the
+ * string format.
+ *
+ * @return true if successfull
+ */
+ public boolean configure(String configStr) {
+ if (DBG) log("configure: '" + configStr + "'");
+
+ if (!TextUtils.isEmpty(configStr)) {
+ int defaultRandomization = 0;
+
+ if (DBG) log("configure: not empty");
+
+ mMaxRetryCount = 0;
+ resetRetryCount();
+ mRetryArray.clear();
+
+ String strArray[] = configStr.split(",");
+ for (int i = 0; i < strArray.length; i++) {
+ if (DBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'");
+ Pair<Boolean, Integer> value;
+ String splitStr[] = strArray[i].split("=", 2);
+ splitStr[0] = splitStr[0].trim();
+ if (DBG) log("configure: splitStr[0]='" + splitStr[0] + "'");
+ if (splitStr.length > 1) {
+ splitStr[1] = splitStr[1].trim();
+ if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
+ if (TextUtils.equals(splitStr[0], "default_randomization")) {
+ value = parseNonNegativeInt(splitStr[0], splitStr[1]);
+ if (!value.first) return false;
+ defaultRandomization = value.second;
+ } else if (TextUtils.equals(splitStr[0], "max_retries")) {
+ if (TextUtils.equals("infinite",splitStr[1])) {
+ mRetryForever = true;
+ } else {
+ value = parseNonNegativeInt(splitStr[0], splitStr[1]);
+ if (!value.first) return false;
+ mMaxRetryCount = value.second;
+ }
+ } else {
+ Log.e(LOG_TAG, "Unrecognized configuration name value pair: "
+ + strArray[i]);
+ return false;
+ }
+ } else {
+ /**
+ * Assume a retry time with an optional randomization value
+ * following a ":"
+ */
+ splitStr = strArray[i].split(":", 2);
+ splitStr[0] = splitStr[0].trim();
+ RetryRec rr = new RetryRec(0, 0);
+ value = parseNonNegativeInt("delayTime", splitStr[0]);
+ if (!value.first) return false;
+ rr.mDelayTime = value.second;
+
+ // Check if optional randomization value present
+ if (splitStr.length > 1) {
+ splitStr[1] = splitStr[1].trim();
+ if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'");
+ value = parseNonNegativeInt("randomizationTime", splitStr[1]);
+ if (!value.first) return false;
+ rr.mRandomizationTime = value.second;
+ } else {
+ rr.mRandomizationTime = defaultRandomization;
+ }
+ mRetryArray.add(rr);
+ }
+ }
+ if (mRetryArray.size() > mMaxRetryCount) {
+ mMaxRetryCount = mRetryArray.size();
+ if (DBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount);
+ }
+ if (DBG) log("configure: true");
+ return true;
+ } else {
+ if (DBG) log("configure: false it's empty");
+ return false;
+ }
+ }
+
+ /**
+ * Report whether data reconnection should be retried
+ *
+ * @return {@code true} if the max retires has not been reached. {@code
+ * false} otherwise.
+ */
+ public boolean isRetryNeeded() {
+ boolean retVal = mRetryForever || (mRetryCount < mMaxRetryCount);
+ if (DBG) log("isRetryNeeded: " + retVal);
+ return retVal;
+ }
+
+ /**
+ * Return the timer that should be used to trigger the data reconnection
+ */
+ public int getRetryTimer() {
+ int index;
+ if (mRetryCount < mRetryArray.size()) {
+ index = mRetryCount;
+ } else {
+ index = mRetryArray.size() - 1;
+ }
+
+ int retVal;
+ if ((index >= 0) && (index < mRetryArray.size())) {
+ retVal = mRetryArray.get(index).mDelayTime + nextRandomizationTime(index);
+ } else {
+ retVal = 0;
+ }
+
+ if (DBG) log("getRetryTimer: " + retVal);
+ return retVal;
+ }
+
+ /**
+ * @return retry count
+ */
+ public int getRetryCount() {
+ if (DBG) log("getRetryCount: " + mRetryCount);
+ return mRetryCount;
+ }
+
+ /**
+ * Increase the retry counter, does not change retry forever.
+ */
+ public void increaseRetryCount() {
+ mRetryCount++;
+ if (mRetryCount > mMaxRetryCount) {
+ mRetryCount = mMaxRetryCount;
+ }
+ if (DBG) log("increseRetryCount: " + mRetryCount);
+ }
+
+ /**
+ * Set retry count to the specified value
+ * and turns off retrying forever.
+ */
+ public void setRetryCount(int count) {
+ mRetryCount = count;
+ if (mRetryCount > mMaxRetryCount) {
+ mRetryCount = mMaxRetryCount;
+ }
+
+ if (mRetryCount < 0) {
+ mRetryCount = 0;
+ }
+
+ mRetryForever = false;
+ if (DBG) log("setRetryCount: " + mRetryCount);
+ }
+
+ /**
+ * Reset network re-registration indicator and clear the data-retry counter
+ * and turns off retrying forever.
+ */
+ public void resetRetryCount() {
+ mRetryCount = 0;
+ mRetryForever = false;
+ if (DBG) log("resetRetryCount: " + mRetryCount);
+ }
+
+ /**
+ * Retry forever using last timeout time.
+ */
+ public void retryForeverUsingLastTimeout() {
+ mRetryCount = mMaxRetryCount;
+ mRetryForever = true;
+ if (DBG) log("retryForeverUsingLastTimeout: " + mRetryForever + ", " + mRetryCount);
+ }
+
+ /**
+ * @return true if retrying forever
+ */
+ public boolean isRetryForever() {
+ if (DBG) log("isRetryForever: " + mRetryForever);
+ return mRetryForever;
+ }
+
+ /**
+ * Parse an integer validating the value is not negative.
+ *
+ * @param name
+ * @param stringValue
+ * @return Pair.first == true if stringValue an integer >= 0
+ */
+ private Pair<Boolean, Integer> parseNonNegativeInt(String name, String stringValue) {
+ int value;
+ Pair<Boolean, Integer> retVal;
+ try {
+ value = Integer.parseInt(stringValue);
+ retVal = new Pair<Boolean, Integer>(validateNonNegativeInt(name, value), value);
+ } catch (NumberFormatException e) {
+ Log.e(LOG_TAG, name + " bad value: " + stringValue, e);
+ retVal = new Pair<Boolean, Integer>(false, 0);
+ }
+ if (DBG) log("parseNonNetativeInt: " + name + ", " + stringValue + ", "
+ + retVal.first + ", " + retVal.second);
+ return retVal;
+ }
+
+ /**
+ * Validate an integer is >= 0 and logs an error if not
+ *
+ * @param name
+ * @param value
+ * @return Pair.first
+ */
+ private boolean validateNonNegativeInt(String name, int value) {
+ boolean retVal;
+ if (value < 0) {
+ Log.e(LOG_TAG, name + " bad value: is < 0");
+ retVal = false;
+ } else {
+ retVal = true;
+ }
+ if (DBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal);
+ return retVal;
+ }
+
+ /**
+ * Return next random number for the index
+ */
+ private int nextRandomizationTime(int index) {
+ int randomTime = mRetryArray.get(index).mRandomizationTime;
+ if (randomTime == 0) {
+ return 0;
+ } else {
+ return rng.nextInt(randomTime);
+ }
+ }
+
+ private void log(String s) {
+ Log.d(LOG_TAG, s);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index 890ea63..bbfc6c9 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -61,6 +61,7 @@ import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
+import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
public abstract class SMSDispatcher extends Handler {
@@ -105,6 +106,9 @@ public abstract class SMSDispatcher extends Handler {
/** Alert is timeout */
static final protected int EVENT_ALERT_TIMEOUT = 9;
+ /** Stop the sending */
+ static final protected int EVENT_STOP_SENDING = 10;
+
protected Phone mPhone;
protected Context mContext;
protected ContentResolver mResolver;
@@ -120,6 +124,8 @@ public abstract class SMSDispatcher extends Handler {
private static final int SEND_RETRY_DELAY = 2000;
/** single part SMS */
private static final int SINGLE_PART_SMS = 1;
+ /** Message sending queue limit */
+ private static final int MO_MSG_QUEUE_LIMIT = 5;
/**
* Message reference for a CONCATENATED_8_BIT_REFERENCE or
@@ -130,7 +136,7 @@ public abstract class SMSDispatcher extends Handler {
private SmsCounter mCounter;
- private SmsTracker mSTracker;
+ private ArrayList mSTrackers = new ArrayList(MO_MSG_QUEUE_LIMIT);
/** Wake lock to ensure device stays awake while dispatching the SMS intent. */
private PowerManager.WakeLock mWakeLock;
@@ -214,7 +220,6 @@ public abstract class SMSDispatcher extends Handler {
mContext = phone.getContext();
mResolver = mContext.getContentResolver();
mCm = phone.mCM;
- mSTracker = null;
createWakelock();
@@ -330,17 +335,41 @@ public abstract class SMSDispatcher extends Handler {
case EVENT_ALERT_TIMEOUT:
((AlertDialog)(msg.obj)).dismiss();
msg.obj = null;
- mSTracker = null;
+ if (mSTrackers.isEmpty() == false) {
+ try {
+ SmsTracker sTracker = (SmsTracker)mSTrackers.remove(0);
+ sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
+ } catch (CanceledException ex) {
+ Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
+ }
+ }
+ if (Config.LOGD) {
+ Log.d(TAG, "EVENT_ALERT_TIMEOUT, message stop sending");
+ }
break;
case EVENT_SEND_CONFIRMED_SMS:
- if (mSTracker!=null) {
- if (isMultipartTracker(mSTracker)) {
- sendMultipartSms(mSTracker);
+ if (mSTrackers.isEmpty() == false) {
+ SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1);
+ if (isMultipartTracker(sTracker)) {
+ sendMultipartSms(sTracker);
} else {
- sendSms(mSTracker);
+ sendSms(sTracker);
+ }
+ removeMessages(EVENT_ALERT_TIMEOUT, msg.obj);
+ }
+ break;
+
+ case EVENT_STOP_SENDING:
+ if (mSTrackers.isEmpty() == false) {
+ // Remove the latest one.
+ try {
+ SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1);
+ sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
+ } catch (CanceledException ex) {
+ Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
}
- mSTracker = null;
+ removeMessages(EVENT_ALERT_TIMEOUT, msg.obj);
}
break;
}
@@ -445,7 +474,11 @@ public abstract class SMSDispatcher extends Handler {
} else if (tracker.mSentIntent != null) {
// Done retrying; return an error to the app.
try {
- tracker.mSentIntent.send(RESULT_ERROR_GENERIC_FAILURE);
+ Intent fillIn = new Intent();
+ if (ar.result != null) {
+ fillIn.putExtra("errorCode", ((SmsResponse)ar.result).errorCode);
+ }
+ tracker.mSentIntent.send(mContext, RESULT_ERROR_GENERIC_FAILURE, fillIn);
} catch (CanceledException ex) {}
}
}
@@ -689,6 +722,15 @@ public abstract class SMSDispatcher extends Handler {
* An SmsTracker for the current message.
*/
protected void handleReachSentLimit(SmsTracker tracker) {
+ if (mSTrackers.size() >= MO_MSG_QUEUE_LIMIT) {
+ // Deny the sending when the queue limit is reached.
+ try {
+ tracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
+ } catch (CanceledException ex) {
+ Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
+ }
+ return;
+ }
Resources r = Resources.getSystem();
@@ -698,13 +740,13 @@ public abstract class SMSDispatcher extends Handler {
.setTitle(r.getString(R.string.sms_control_title))
.setMessage(appName + " " + r.getString(R.string.sms_control_message))
.setPositiveButton(r.getString(R.string.sms_control_yes), mListener)
- .setNegativeButton(r.getString(R.string.sms_control_no), null)
+ .setNegativeButton(r.getString(R.string.sms_control_no), mListener)
.create();
d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
d.show();
- mSTracker = tracker;
+ mSTrackers.add(tracker);
sendMessageDelayed ( obtainMessage(EVENT_ALERT_TIMEOUT, d),
DEFAULT_SMS_TIMOUEOUT);
}
@@ -815,6 +857,9 @@ public abstract class SMSDispatcher extends Handler {
if (which == DialogInterface.BUTTON_POSITIVE) {
Log.d(TAG, "click YES to send out sms");
sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS));
+ } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+ Log.d(TAG, "click NO to stop sending");
+ sendMessage(obtainMessage(EVENT_STOP_SENDING));
}
}
};
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index bdcf3f7..c74bb8d 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -34,6 +34,14 @@ public abstract class ServiceStateTracker extends Handler {
* 1 = GPRS only
* 2 = EDGE
* 3 = UMTS
+ * 4 = IS95A
+ * 5 = IS95B
+ * 6 = 1xRTT
+ * 7 = EvDo_0
+ * 8 = EvDo_A
+ * 9 = HSDPA
+ * 10 = HSUPA
+ * 11 = HSPA
*/
protected static final int DATA_ACCESS_UNKNOWN = 0;
protected static final int DATA_ACCESS_GPRS = 1;
@@ -44,6 +52,9 @@ public abstract class ServiceStateTracker extends Handler {
protected static final int DATA_ACCESS_CDMA_1xRTT = 6;
protected static final int DATA_ACCESS_CDMA_EvDo_0 = 7;
protected static final int DATA_ACCESS_CDMA_EvDo_A = 8;
+ protected static final int DATA_ACCESS_HSDPA = 9;
+ protected static final int DATA_ACCESS_HSUPA = 10;
+ protected static final int DATA_ACCESS_HSPA = 11;
//***** Instance Variables
protected CommandsInterface cm;
@@ -77,7 +88,6 @@ public abstract class ServiceStateTracker extends Handler {
// waiting period before recheck gprs and voice registration
public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
- public static final int MAX_NUM_DATA_STATE_READS = 15;
public static final int DATA_STATE_POLL_SLEEP_MS = 100;
//*****GSM events
@@ -116,6 +126,8 @@ public abstract class ServiceStateTracker extends Handler {
protected static final int EVENT_POLL_STATE_CDMA_SUBSCRIPTION = 34;
protected static final int EVENT_NV_READY = 35;
protected static final int EVENT_ERI_FILE_LOADED = 36;
+ protected static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 37;
+ protected static final int EVENT_SET_RADIO_POWER_OFF = 38;
//***** Time Zones
protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 8b9ccb4..6177c8a 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -353,60 +353,30 @@ public abstract class SmsMessageBase {
}
/**
- * Try to parse this message as an email gateway message -> Neither
- * of the standard ways are currently supported: There are two ways
- * specified in TS 23.040 Section 3.8 (not supported via this mechanism) -
- * SMS message "may have its TP-PID set for internet electronic mail - MT
+ * Try to parse this message as an email gateway message
+ * There are two ways specified in TS 23.040 Section 3.8 :
+ * - SMS message "may have its TP-PID set for internet electronic mail - MT
* SMS format: [<from-address><space>]<message> - "Depending on the
* nature of the gateway, the destination/origination address is either
* derived from the content of the SMS TP-OA or TP-DA field, or the
* TP-OA/TP-DA field contains a generic gateway address and the to/from
- * address is added at the beginning as shown above." - multiple addreses
- * separated by commas, no spaces - subject field delimited by '()' or '##'
- * and '#' Section 9.2.3.24.11
+ * address is added at the beginning as shown above." (which is supported here)
+ * - Multiple addreses separated by commas, no spaces, Subject field delimited
+ * by '()' or '##' and '#' Section 9.2.3.24.11 (which are NOT supported here)
*/
protected void extractEmailAddressFromMessageBody() {
- /*
- * a little guesswork here. I haven't found doc for this.
- * the format could be either
+ /* Some carriers may use " /" delimiter as below
*
* 1. [x@y][ ]/[subject][ ]/[body]
* -or-
* 2. [x@y][ ]/[body]
*/
- int slash = 0, slash2 = 0, atSymbol = 0;
-
- try {
- slash = messageBody.indexOf(" /");
- if (slash == -1) {
- return;
- }
-
- atSymbol = messageBody.indexOf('@');
- if (atSymbol == -1 || atSymbol > slash) {
- return;
- }
-
- emailFrom = messageBody.substring(0, slash);
-
- slash2 = messageBody.indexOf(" /", slash + 2);
-
- if (slash2 == -1) {
- pseudoSubject = null;
- emailBody = messageBody.substring(slash + 2);
- } else {
- pseudoSubject = messageBody.substring(slash + 2, slash2);
- emailBody = messageBody.substring(slash2 + 2);
- }
-
- isEmail = true;
- } catch (Exception ex) {
- Log.w(LOG_TAG,
- "extractEmailAddressFromMessageBody: exception slash="
- + slash + ", atSymbol=" + atSymbol + ", slash2="
- + slash2, ex);
- }
+ String[] parts = messageBody.split("( /)|( )", 2);
+ if (parts.length < 1 || parts[0].indexOf('@') == -1) return;
+ emailFrom = parts[0];
+ emailBody = parts[1];
+ isEmail = true;
}
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 02e9800..2216ec4 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -220,28 +220,4 @@ public class TelephonyIntents {
*/
public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS
= "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
-
- /**
- * Broadcast Action: The MDN changed during the CDMA OTA Process
- * The intent will have the following extra values:</p>
- * <ul>
- * <li><em>mdn</em> - An Integer of the updated MDN number.</li>
- * </ul>
- *
- * <p class="note">This is a protected intent that can only be sent
- * by the system.
- *
- * <p class="note">
- */
- // TODO(Moto): Generally broadcast intents are for use to allow entities which
- // may not know about each other to "communicate". This seems quite specific
- // and maybe using the registrant style would be better.
-
- // Moto: Since this is used for apps not in the same process of phone, can the
- // registrant style be used? (Ling Li says: Maybe the "app" can request rather
- // than save the MDN each time and this intent would not be necessary?)
- // Moto response: Moto internal discussion is on-going.
- public static final String ACTION_CDMA_OTA_MDN_CHANGED
- = "android.intent.action.ACTION_MDN_STATE_CHANGED";
-
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 5ec4020..de5bbc1 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -109,4 +109,25 @@ public interface TelephonyProperties
/** The international dialing prefix conversion string */
static final String PROPERTY_IDP_STRING = "ro.cdma.idpstring";
+
+ /**
+ * Defines the schema for the carrier specified OTASP number
+ */
+ static final String PROPERTY_OTASP_NUM_SCHEMA = "ro.cdma.otaspnumschema";
+
+ /**
+ * Disable all calls including Emergency call when it set to true.
+ */
+ static final String PROPERTY_DISABLE_CALL = "ro.telephony.disable-call";
+
+ /**
+ * Set to true for vendor RIL's that send multiple UNSOL_CALL_RING notifications.
+ */
+ static final String PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING =
+ "ro.telephony.call_ring.multiple";
+
+ /**
+ * The number of milli-seconds between CALL_RING notifications.
+ */
+ static final String PROPERTY_CALL_RING_DELAY = "ro.telephony.call_ring.delay";
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 23eedfe..ebe3e096 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -26,14 +26,14 @@ import android.database.SQLException;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Handler;
-import android.os.Looper;
import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.preference.PreferenceManager;
-import android.provider.Settings;
import android.provider.Telephony;
import android.telephony.CellLocation;
import android.telephony.PhoneNumberUtils;
@@ -42,6 +42,7 @@ import android.telephony.SignalStrength;
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
@@ -71,34 +72,41 @@ import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OP
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
+
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* {@hide}
*/
public class CDMAPhone extends PhoneBase {
static final String LOG_TAG = "CDMA";
- private static final boolean LOCAL_DEBUG = true;
+ private static final boolean DBG = true;
// Default Emergency Callback Mode exit timer
- private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 30000;
+ private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
+
static final String VM_COUNT_CDMA = "vm_count_key_cdma";
private static final String VM_NUMBER_CDMA = "vm_number_key_cdma";
private String mVmNumber = null;
- //***** Instance Variables
+ static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
+ static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer
+
+ // Instance Variables
CdmaCallTracker mCT;
CdmaSMSDispatcher mSMS;
CdmaServiceStateTracker mSST;
- CdmaDataConnectionTracker mDataConnection;
RuimFileHandler mRuimFileHandler;
RuimRecords mRuimRecords;
RuimCard mRuimCard;
- MyHandler h;
RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager;
RuimSmsInterfaceManager mRuimSmsInterfaceManager;
PhoneSubInfo mSubInfo;
EriManager mEriManager;
+ WakeLock mWakeLock;
+
// mNvLoadedRegistrants are informed after the EVENT_NV_READY
private RegistrantList mNvLoadedRegistrants = new RegistrantList();
@@ -106,15 +114,20 @@ public class CDMAPhone extends PhoneBase {
// mEriFileLoadedRegistrants are informed after the ERI text has been loaded
private RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
- // mECMExitRespRegistrant is informed after the phone has been exited
+ // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
+ private RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
+
+ // mEcmExitRespRegistrant is informed after the phone has been exited
//the emergency callback mode
//keep track of if phone is in emergency callback mode
- private boolean mIsPhoneInECMState;
- private Registrant mECMExitRespRegistrant;
+ private boolean mIsPhoneInEcmState;
+ private Registrant mEcmExitRespRegistrant;
private String mEsn;
private String mMeid;
+ // string to define how the carrier specifies its own ota sp number
+ private String mCarrierOtaSpNumSchema;
- // A runnable which is used to automatically exit from ECM after a period of time.
+ // A runnable which is used to automatically exit from Ecm after a period of time.
private Runnable mExitEcmRunnable = new Runnable() {
public void run() {
exitEmergencyCallbackMode();
@@ -124,17 +137,14 @@ public class CDMAPhone extends PhoneBase {
Registrant mPostDialHandler;
- //***** Constructors
+ // Constructors
public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
this(context,ci,notifier, false);
}
public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
boolean unitTestMode) {
- super(notifier, context, unitTestMode);
-
- h = new MyHandler();
- mCM = ci;
+ super(notifier, context, ci, unitTestMode);
mCM.setPhoneType(RILConstants.CDMA_PHONE);
mCT = new CdmaCallTracker(this);
@@ -149,16 +159,18 @@ public class CDMAPhone extends PhoneBase {
mSubInfo = new PhoneSubInfo(this);
mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
- mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null);
- mRuimRecords.registerForRecordsLoaded(h, EVENT_RUIM_RECORDS_LOADED, null);
- mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
- mCM.registerForOn(h, EVENT_RADIO_ON, null);
- mCM.setOnSuppServiceNotification(h, EVENT_SSN, null);
- mCM.setOnCallRing(h, EVENT_CALL_RING, null);
- mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null);
- mCM.registerForNVReady(h, EVENT_NV_READY, null);
- mCM.setEmergencyCallbackMode(h, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
+ mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+ mRuimRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
+ mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+ mCM.registerForOn(this, EVENT_RADIO_ON, null);
+ mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
+ mSST.registerForNetworkAttach(this, EVENT_REGISTERED_TO_NETWORK, null);
+ mCM.registerForNVReady(this, EVENT_NV_READY, null);
+ mCM.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
+ PowerManager pm
+ = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,LOG_TAG);
//Change the system setting
SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
@@ -166,7 +178,11 @@ public class CDMAPhone extends PhoneBase {
// This is needed to handle phone process crashes
String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
- mIsPhoneInECMState = inEcm.equals("true");
+ mIsPhoneInEcmState = inEcm.equals("true");
+
+ // get the string that specifies the carrier OTA Sp number
+ mCarrierOtaSpNumSchema = SystemProperties.get(
+ TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA,"");
// Sets operator alpha property by retrieving from build-time system property
String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
@@ -185,23 +201,23 @@ public class CDMAPhone extends PhoneBase {
// Updates MCC MNC device configuration information
updateMccMncConfiguration(operatorNumeric);
+
// Notify voicemails.
notifier.notifyMessageWaitingChanged(this);
}
public void dispose() {
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
+ super.dispose();
//Unregister from all former registered events
- mRuimRecords.unregisterForRecordsLoaded(h); //EVENT_RUIM_RECORDS_LOADED
- mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE
- mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
- mCM.unregisterForOn(h); //EVENT_RADIO_ON
- mCM.unregisterForNVReady(h); //EVENT_NV_READY
- mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK
- mCM.unSetOnSuppServiceNotification(h);
- mCM.unSetOnCallRing(h);
-
+ mRuimRecords.unregisterForRecordsLoaded(this); //EVENT_RUIM_RECORDS_LOADED
+ mCM.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE
+ mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
+ mCM.unregisterForOn(this); //EVENT_RADIO_ON
+ mCM.unregisterForNVReady(this); //EVENT_NV_READY
+ mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK
+ mCM.unSetOnSuppServiceNotification(this);
//Force all referenced classes to unregister their former registered events
mCT.dispose();
@@ -233,11 +249,13 @@ public class CDMAPhone extends PhoneBase {
}
protected void finalize() {
- if(LOCAL_DEBUG) Log.d(LOG_TAG, "CDMAPhone finalized");
+ if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized");
+ if (mWakeLock.isHeld()) {
+ Log.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
+ mWakeLock.release();
+ }
}
-
- //***** Overridden from Phone
public ServiceState getServiceState() {
return mSST.ss;
}
@@ -358,42 +376,11 @@ public class CDMAPhone extends PhoneBase {
return mCT.backgroundCall;
}
- public String getGateway(String apnType) {
- return mDataConnection.getGateway();
- }
-
public boolean handleInCallMmiCommands(String dialString) {
Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!");
return false;
}
- public int enableApnType(String type) {
- // This request is mainly used to enable MMS APN
- // In CDMA there is no need to enable/disable a different APN for MMS
- Log.d(LOG_TAG, "Request to enableApnType("+type+")");
- if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- return Phone.APN_ALREADY_ACTIVE;
- } else {
- return Phone.APN_REQUEST_FAILED;
- }
- }
-
- public int disableApnType(String type) {
- // This request is mainly used to disable MMS APN
- // In CDMA there is no need to enable/disable a different APN for MMS
- Log.d(LOG_TAG, "Request to disableApnType("+type+")");
- if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- return Phone.APN_REQUEST_STARTED;
- } else {
- return Phone.APN_REQUEST_FAILED;
- }
- }
-
- public String getActiveApn() {
- Log.d(LOG_TAG, "Request to getActiveApn()");
- return null;
- }
-
public void
setNetworkSelectionModeAutomatic(Message response) {
Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!");
@@ -423,13 +410,17 @@ public class CDMAPhone extends PhoneBase {
}
public String getCdmaPrlVersion(){
- return mRuimRecords.getPrlVersion();
+ return mSST.getPrlVersion();
}
- public String getCdmaMIN() {
+ public String getCdmaMin() {
return mSST.getCdmaMin();
}
+ public boolean isMinInfoReady() {
+ return mSST.isMinInfoReady();
+ }
+
public void getCallWaiting(Message onComplete) {
mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
}
@@ -466,10 +457,6 @@ public class CDMAPhone extends PhoneBase {
return false;
}
- public String getInterfaceName(String apnType) {
- return mDataConnection.getInterfaceName();
- }
-
public CellLocation getCellLocation() {
return mSST.cellLoc;
}
@@ -509,10 +496,6 @@ public class CDMAPhone extends PhoneBase {
Log.e(LOG_TAG, "setLine1Number: not possible in CDMA");
}
- public String[] getDnsServers(String apnType) {
- return mDataConnection.getDnsServers();
- }
-
public IccCard getIccCard() {
return mRuimCard;
}
@@ -541,12 +524,20 @@ public class CDMAPhone extends PhoneBase {
mCM.unregisterForCdmaOtaProvision(h);
}
+ public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+ mSST.registerForSubscriptionInfoReady(h, what, obj);
+ }
+
+ public void unregisterForSubscriptionInfoReady(Handler h) {
+ mSST.unregisterForSubscriptionInfoReady(h);
+ }
+
public void setOnEcbModeExitResponse(Handler h, int what, Object obj) {
- mECMExitRespRegistrant = new Registrant (h, what, obj);
+ mEcmExitRespRegistrant = new Registrant (h, what, obj);
}
public void unsetOnEcbModeExitResponse(Handler h) {
- mECMExitRespRegistrant.clear();
+ mEcmExitRespRegistrant.clear();
}
public void registerForCallWaiting(Handler h, int what, Object obj) {
@@ -557,10 +548,6 @@ public class CDMAPhone extends PhoneBase {
mCT.unregisterForCallWaiting(h);
}
- public String getIpAddress(String apnType) {
- return mDataConnection.getIpAddress();
- }
-
public void
getNeighboringCids(Message response) {
/*
@@ -674,14 +661,6 @@ public class CDMAPhone extends PhoneBase {
Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA");
}
- public String[] getActiveApnTypes() {
- String[] result;
- Log.d(LOG_TAG, "Request to getActiveApn()");
- result = new String[1];
- result[0] = Phone.APN_TYPE_DEFAULT;
- return result;
- }
-
public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
Log.e(LOG_TAG, "setOutgoingCallerIdDisplay: not possible in CDMA");
}
@@ -714,7 +693,7 @@ public class CDMAPhone extends PhoneBase {
Message onComplete) {
Message resp;
mVmNumber = voiceMailNumber;
- resp = h.obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
+ resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
mRuimRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
}
@@ -758,10 +737,13 @@ public class CDMAPhone extends PhoneBase {
public boolean enableDataConnectivity() {
// block data activities when phone is in emergency callback mode
- if (mIsPhoneInECMState) {
+ if (mIsPhoneInEcmState) {
Intent intent = new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS);
ActivityManagerNative.broadcastStickyIntent(intent, null);
return false;
+ } else if ((mCT.state == Phone.State.OFFHOOK) && mCT.isInEmergencyCall()) {
+ // Do not allow data call to be enabled when emergency call is going on
+ return false;
} else {
return mDataConnection.setDataEnabled(true);
}
@@ -808,19 +790,19 @@ public class CDMAPhone extends PhoneBase {
}
/**
- * Notify any interested party of a Phone state change.
+ * Notify any interested party of a Phone state change {@link Phone.State}
*/
/*package*/ void notifyPhoneStateChanged() {
mNotifier.notifyPhoneState(this);
}
/**
- * Notifies registrants (ie, activities in the Phone app) about
- * changes to call state (including Phone and Connection changes).
+ * Notify registrants of a change in the call state. This notifies changes in {@link Call.State}
+ * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged.
*/
- /*package*/ void notifyCallStateChanged() {
+ /*package*/ void notifyPreciseCallStateChanged() {
/* we'd love it if this was package-scoped*/
- super.notifyCallStateChangedP();
+ super.notifyPreciseCallStateChangedP();
}
void notifyServiceStateChanged(ServiceState ss) {
@@ -836,14 +818,6 @@ public class CDMAPhone extends PhoneBase {
super.notifyNewRingingConnectionP(c);
}
- /**
- * Notifiy registrants of a RING event.
- */
- void notifyIncomingRing() {
- AsyncResult ar = new AsyncResult(null, this, null);
- mIncomingRingRegistrants.notifyRegistrants(ar);
- }
-
/*package*/ void notifyDisconnect(Connection cn) {
mDisconnectRegistrants.notifyResult(cn);
}
@@ -855,8 +829,9 @@ public class CDMAPhone extends PhoneBase {
void sendEmergencyCallbackModeChange(){
//Send an Intent
Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
- intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInECMState);
+ intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
ActivityManagerNative.broadcastStickyIntent(intent,null);
+ if (DBG) Log.d(LOG_TAG, "sendEmergencyCallbackModeChange");
}
/*package*/ void
@@ -888,15 +863,21 @@ public class CDMAPhone extends PhoneBase {
@Override
public void exitEmergencyCallbackMode() {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
// Send a message which will invoke handleExitEmergencyCallbackMode
- mCM.exitEmergencyCallbackMode(h.obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
+ mCM.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
}
private void handleEnterEmergencyCallbackMode(Message msg) {
- Log.d(LOG_TAG, "Event EVENT_EMERGENCY_CALLBACK_MODE Received");
- // if phone is not in ECM mode, and it's changed to ECM mode
- if (mIsPhoneInECMState == false) {
- mIsPhoneInECMState = true;
+ if (DBG) {
+ Log.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= "
+ + mIsPhoneInEcmState);
+ }
+ // if phone is not in Ecm mode, and it's changed to Ecm mode
+ if (mIsPhoneInEcmState == false) {
+ mIsPhoneInEcmState = true;
// notify change
sendEmergencyCallbackModeChange();
setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
@@ -905,147 +886,175 @@ public class CDMAPhone extends PhoneBase {
// if no one invokes exitEmergencyCallbackMode() directly.
long delayInMillis = SystemProperties.getLong(
TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
- h.postDelayed(mExitEcmRunnable, delayInMillis);
+ postDelayed(mExitEcmRunnable, delayInMillis);
+ // We don't want to go to sleep while in Ecm
+ mWakeLock.acquire();
}
}
private void handleExitEmergencyCallbackMode(Message msg) {
- Log.d(LOG_TAG, "Event EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE Received");
AsyncResult ar = (AsyncResult)msg.obj;
+ if (DBG) {
+ Log.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState "
+ + ar.exception + mIsPhoneInEcmState);
+ }
+ // Remove pending exit Ecm runnable, if any
+ removeCallbacks(mExitEcmRunnable);
- // Remove pending exit ECM runnable, if any
- h.removeCallbacks(mExitEcmRunnable);
-
- if (mECMExitRespRegistrant != null) {
- mECMExitRespRegistrant.notifyRegistrant(ar);
+ if (mEcmExitRespRegistrant != null) {
+ mEcmExitRespRegistrant.notifyRegistrant(ar);
}
// if exiting ecm success
if (ar.exception == null) {
- if (mIsPhoneInECMState) {
- mIsPhoneInECMState = false;
+ if (mIsPhoneInEcmState) {
+ mIsPhoneInEcmState = false;
setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
}
// send an Intent
sendEmergencyCallbackModeChange();
+ // Re-initiate data connection
+ mDataConnection.setDataEnabled(true);
}
}
- //***** Inner Classes
- class MyHandler extends Handler {
- MyHandler() {
+ /**
+ * Handle to cancel or restart Ecm timer in emergency call back mode
+ * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled;
+ * otherwise, restart Ecm timer and notify apps the timer is restarted.
+ */
+ void handleTimerInEmergencyCallbackMode(int action) {
+ switch(action) {
+ case CANCEL_ECM_TIMER:
+ removeCallbacks(mExitEcmRunnable);
+ mEcmTimerResetRegistrants.notifyResult(new Boolean(true));
+ break;
+ case RESTART_ECM_TIMER:
+ long delayInMillis = SystemProperties.getLong(
+ TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
+ postDelayed(mExitEcmRunnable, delayInMillis);
+ mEcmTimerResetRegistrants.notifyResult(new Boolean(false));
+ break;
+ default:
+ Log.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action);
}
+ }
- MyHandler(Looper l) {
- super(l);
- }
+ /**
+ * Registration point for Ecm timer reset
+ * @param h handler to notify
+ * @param what User-defined message code
+ * @param obj placed in Message.obj
+ */
+ public void registerForEcmTimerReset(Handler h, int what, Object obj) {
+ mEcmTimerResetRegistrants.addUnique(h, what, obj);
+ }
- @Override
- public void handleMessage(Message msg) {
- AsyncResult ar;
- Message onComplete;
+ public void unregisterForEcmTimerReset(Handler h) {
+ mEcmTimerResetRegistrants.remove(h);
+ }
- switch(msg.what) {
- case EVENT_RADIO_AVAILABLE: {
- mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
+ @Override
+ public void handleMessage(Message msg) {
+ AsyncResult ar;
+ Message onComplete;
- mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
- }
- break;
+ switch(msg.what) {
+ case EVENT_RADIO_AVAILABLE: {
+ mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
- case EVENT_GET_BASEBAND_VERSION_DONE:{
- ar = (AsyncResult)msg.obj;
+ mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
+ }
+ break;
- if (ar.exception != null) {
- break;
- }
+ case EVENT_GET_BASEBAND_VERSION_DONE:{
+ ar = (AsyncResult)msg.obj;
- if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
- setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result);
+ if (ar.exception != null) {
+ break;
}
- break;
- case EVENT_GET_DEVICE_IDENTITY_DONE:{
- ar = (AsyncResult)msg.obj;
+ if (DBG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
+ setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result);
+ }
+ break;
- if (ar.exception != null) {
- break;
- }
- String[] respId = (String[])ar.result;
- mEsn = respId[2];
- mMeid = respId[3];
- }
- break;
+ case EVENT_GET_DEVICE_IDENTITY_DONE:{
+ ar = (AsyncResult)msg.obj;
- case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
- handleEnterEmergencyCallbackMode(msg);
+ if (ar.exception != null) {
+ break;
}
- break;
+ String[] respId = (String[])ar.result;
+ mEsn = respId[2];
+ mMeid = respId[3];
+ }
+ break;
- case EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
- handleExitEmergencyCallbackMode(msg);
- }
- break;
+ case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{
+ handleEnterEmergencyCallbackMode(msg);
+ }
+ break;
- case EVENT_RUIM_RECORDS_LOADED:{
- Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received");
- }
- break;
+ case EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
+ handleExitEmergencyCallbackMode(msg);
+ }
+ break;
- case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{
- Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
- }
- break;
+ case EVENT_RUIM_RECORDS_LOADED:{
+ Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received");
+ }
+ break;
- case EVENT_RADIO_ON:{
- Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received");
- }
- break;
+ case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{
+ Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
+ }
+ break;
- case EVENT_SSN:{
- Log.d(LOG_TAG, "Event EVENT_SSN Received");
- }
- break;
+ case EVENT_RADIO_ON:{
+ Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received");
+ }
+ break;
- case EVENT_CALL_RING:{
- Log.d(LOG_TAG, "Event EVENT_CALL_RING Received");
- }
- break;
+ case EVENT_SSN:{
+ Log.d(LOG_TAG, "Event EVENT_SSN Received");
+ }
+ break;
- case EVENT_REGISTERED_TO_NETWORK:{
- Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received");
+ case EVENT_REGISTERED_TO_NETWORK:{
+ Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received");
+ }
+ break;
+
+ case EVENT_NV_READY:{
+ Log.d(LOG_TAG, "Event EVENT_NV_READY Received");
+ //Inform the Service State Tracker
+ mEriManager.loadEriFile();
+ mNvLoadedRegistrants.notifyRegistrants();
+ if(mEriManager.isEriFileLoaded()) {
+ // when the ERI file is loaded
+ Log.d(LOG_TAG, "ERI read, notify registrants");
+ mEriFileLoadedRegistrants.notifyRegistrants();
}
- break;
+ setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE,"false");
+ }
+ break;
- case EVENT_NV_READY:{
- Log.d(LOG_TAG, "Event EVENT_NV_READY Received");
- //Inform the Service State Tracker
- mEriManager.loadEriFile();
- mNvLoadedRegistrants.notifyRegistrants();
- if(mEriManager.isEriFileLoaded()) {
- // when the ERI file is loaded
- Log.d(LOG_TAG, "ERI read, notify registrants");
- mEriFileLoadedRegistrants.notifyRegistrants();
- }
- setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE,"false");
+ case EVENT_SET_VM_NUMBER_DONE:{
+ ar = (AsyncResult)msg.obj;
+ if (IccException.class.isInstance(ar.exception)) {
+ storeVoiceMailNumber(mVmNumber);
+ ar.exception = null;
}
- break;
-
- case EVENT_SET_VM_NUMBER_DONE:{
- ar = (AsyncResult)msg.obj;
- if (IccException.class.isInstance(ar.exception)) {
- storeVoiceMailNumber(mVmNumber);
- ar.exception = null;
- }
- onComplete = (Message) ar.userObj;
- if (onComplete != null) {
- AsyncResult.forMessage(onComplete, ar.result, ar.exception);
- onComplete.sendToTarget();
- }
+ onComplete = (Message) ar.userObj;
+ if (onComplete != null) {
+ AsyncResult.forMessage(onComplete, ar.result, ar.exception);
+ onComplete.sendToTarget();
}
+ }
+ break;
- default:{
- throw new RuntimeException("unexpected event not handled");
- }
+ default:{
+ super.handleMessage(msg);
}
}
}
@@ -1100,13 +1109,6 @@ public class CDMAPhone extends PhoneBase {
/**
* {@inheritDoc}
*/
- public Handler getHandler() {
- return h;
- }
-
- /**
- * {@inheritDoc}
- */
public IccFileHandler getIccFileHandler() {
return this.mIccFileHandler;
}
@@ -1153,10 +1155,10 @@ public class CDMAPhone extends PhoneBase {
mSMS.setCellBroadcastConfig(configValuesArray, response);
}
- public static final String IS683A_FEATURE_CODE = "*228" ;
- public static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4 ;
- public static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2 ;
- public static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
+ private static final String IS683A_FEATURE_CODE = "*228";
+ private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4;
+ private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2;
+ private static final int IS683A_SYS_SEL_CODE_OFFSET = 4;
private static final int IS683_CONST_800MHZ_A_BAND = 0;
private static final int IS683_CONST_800MHZ_B_BAND = 1;
@@ -1166,6 +1168,7 @@ public class CDMAPhone extends PhoneBase {
private static final int IS683_CONST_1900MHZ_D_BLOCK = 5;
private static final int IS683_CONST_1900MHZ_E_BLOCK = 6;
private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
+ private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
private boolean isIs683OtaSpDialStr(String dialStr) {
int sysSelCodeInt;
@@ -1176,58 +1179,168 @@ public class CDMAPhone extends PhoneBase {
if (dialStr.equals(IS683A_FEATURE_CODE)) {
isOtaspDialString = true;
}
- } else if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE, 0,
- IS683A_FEATURE_CODE_NUM_DIGITS) == true)
- && (dialStrLen >=
- (IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
- StringBuilder sb = new StringBuilder(dialStr);
- // Separate the System Selection Code into its own string
- char[] sysSel = new char[2];
- sb.delete(0, IS683A_SYS_SEL_CODE_OFFSET);
- sb.getChars(0, IS683A_SYS_SEL_CODE_NUM_DIGITS, sysSel, 0);
-
- if ((PhoneNumberUtils.isISODigit(sysSel[0]))
- && (PhoneNumberUtils.isISODigit(sysSel[1]))) {
- String sysSelCode = new String(sysSel);
- sysSelCodeInt = Integer.parseInt((String)sysSelCode);
- switch (sysSelCodeInt) {
- case IS683_CONST_800MHZ_A_BAND:
- case IS683_CONST_800MHZ_B_BAND:
- case IS683_CONST_1900MHZ_A_BLOCK:
- case IS683_CONST_1900MHZ_B_BLOCK:
- case IS683_CONST_1900MHZ_C_BLOCK:
- case IS683_CONST_1900MHZ_D_BLOCK:
- case IS683_CONST_1900MHZ_E_BLOCK:
- case IS683_CONST_1900MHZ_F_BLOCK:
- isOtaspDialString = true;
- break;
+ } else {
+ sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
+ switch (sysSelCodeInt) {
+ case IS683_CONST_800MHZ_A_BAND:
+ case IS683_CONST_800MHZ_B_BAND:
+ case IS683_CONST_1900MHZ_A_BLOCK:
+ case IS683_CONST_1900MHZ_B_BLOCK:
+ case IS683_CONST_1900MHZ_C_BLOCK:
+ case IS683_CONST_1900MHZ_D_BLOCK:
+ case IS683_CONST_1900MHZ_E_BLOCK:
+ case IS683_CONST_1900MHZ_F_BLOCK:
+ isOtaspDialString = true;
+ break;
+ default:
+ break;
+ }
+ }
+ return isOtaspDialString;
+ }
+ /**
+ * This function extracts the system selection code from the dial string.
+ */
+ private int extractSelCodeFromOtaSpNum(String dialStr) {
+ int dialStrLen = dialStr.length();
+ int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
+
+ if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE,
+ 0, IS683A_FEATURE_CODE_NUM_DIGITS)) &&
+ (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS +
+ IS683A_SYS_SEL_CODE_NUM_DIGITS))) {
+ // Since we checked the condition above, the system selection code
+ // extracted from dialStr will not cause any exception
+ sysSelCodeInt = Integer.parseInt (
+ dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS,
+ IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS));
+ }
+ if (DBG) Log.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt);
+ return sysSelCodeInt;
+ }
- default:
+ /**
+ * This function checks if the system selection code extracted from
+ * the dial string "sysSelCodeInt' is the system selection code specified
+ * in the carrier ota sp number schema "sch".
+ */
+ private boolean
+ checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) {
+ boolean isOtaSpNum = false;
+ try {
+ // Get how many number of system selection code ranges
+ int selRc = Integer.parseInt((String)sch[1]);
+ for (int i = 0; i < selRc; i++) {
+ if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) {
+ int selMin = Integer.parseInt((String)sch[i+2]);
+ int selMax = Integer.parseInt((String)sch[i+3]);
+ // Check if the selection code extracted from the dial string falls
+ // within any of the range pairs specified in the schema.
+ if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) {
+ isOtaSpNum = true;
break;
+ }
}
}
+ } catch (NumberFormatException ex) {
+ // If the carrier ota sp number schema is not correct, we still allow dial
+ // and only log the error:
+ Log.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex);
}
- return isOtaspDialString;
+ return isOtaSpNum;
}
- /**
- * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
- * OTASP dial string.
- *
- * @param dialStr the number to look up.
- * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
- */
+ // Define the pattern/format for carrier specified OTASP number schema.
+ // It separates by comma and/or whitespace.
+ private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+");
+
+ /**
+ * The following function checks if a dial string is a carrier specified
+ * OTASP number or not by checking against the OTASP number schema stored
+ * in PROPERTY_OTASP_NUM_SCHEMA.
+ *
+ * Currently, there are 2 schemas for carriers to specify the OTASP number:
+ * 1) Use system selection code:
+ * The schema is:
+ * SELC,the # of code pairs,min1,max1,min2,max2,...
+ * e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of
+ * selection codes, and they are {10,20}, {30,40} and {60,70} respectively.
+ *
+ * 2) Use feature code:
+ * The schema is:
+ * "FC,length of feature code,feature code".
+ * e.g "FC,2,*2" indicates that the length of the feature code is 2,
+ * and the code itself is "*2".
+ */
+ private boolean isCarrierOtaSpNum(String dialStr) {
+ boolean isOtaSpNum = false;
+ int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr);
+ if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) {
+ return isOtaSpNum;
+ }
+ // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA:
+ if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) {
+ Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema);
+ if (DBG) {
+ Log.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema);
+ }
+
+ if (m.find()) {
+ String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema);
+ // If carrier uses system selection code mechanism
+ if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) {
+ if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) {
+ isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch);
+ } else {
+ if (DBG) {
+ Log.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid");
+ }
+ }
+ } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) {
+ int fcLen = Integer.parseInt((String)sch[1]);
+ String fc = (String)sch[2];
+ if (dialStr.regionMatches(0,fc,0,fcLen)) {
+ isOtaSpNum = true;
+ } else {
+ if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number");
+ }
+ } else {
+ if (DBG) {
+ Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]);
+ }
+ }
+ } else {
+ if (DBG) {
+ Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" +
+ mCarrierOtaSpNumSchema);
+ }
+ }
+ } else {
+ if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty");
+ }
+ return isOtaSpNum;
+ }
+
+ /**
+ * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
+ * OTASP dial string.
+ *
+ * @param dialStr the number to look up.
+ * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
+ */
@Override
- public boolean isOtaSpNumber(String dialStr){
- boolean isOtaSpNum = false;
- if(dialStr != null){
- isOtaSpNum=isIs683OtaSpDialStr(dialStr);
- if(isOtaSpNum == false){
- //TO DO:Add carrier specific OTASP number detection here.
- }
- }
- return isOtaSpNum;
- }
+ public boolean isOtaSpNumber(String dialStr){
+ boolean isOtaSpNum = false;
+ String dialableStr = PhoneNumberUtils.extractNetworkPortion(dialStr);
+ if (dialableStr != null) {
+ isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
+ if (isOtaSpNum == false) {
+ isOtaSpNum = isCarrierOtaSpNum(dialableStr);
+ }
+ }
+ if (DBG) Log.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
+ return isOtaSpNum;
+ }
@Override
public int getCdmaEriIconIndex() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
index e8724c2..c3bb01f 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
@@ -24,6 +24,7 @@ import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.DriverCall;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.Call.State;
/**
* {@hide}
@@ -186,6 +187,7 @@ public final class CdmaCall extends Call {
cn.onHangupLocal();
}
+ state = State.DISCONNECTING;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index ed2ea90..806c31d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -72,7 +72,8 @@ public final class CdmaCallTracker extends CallTracker {
CdmaConnection pendingMO;
boolean hangupPendingMO;
- boolean pendingCallInECM=false;
+ boolean pendingCallInEcm=false;
+ boolean mIsInEmergencyCall = false;
CDMAPhone phone;
boolean desiredMute = false; // false = mute off
@@ -80,6 +81,7 @@ public final class CdmaCallTracker extends CallTracker {
int pendingCallClirMode;
Phone.State state = Phone.State.IDLE;
+ private boolean mIsEcmTimerCanceled = false;
// boolean needsPoll;
@@ -182,6 +184,14 @@ public final class CdmaCallTracker extends CallTracker {
throw new CallStateException("cannot dial in current state");
}
+ String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+ boolean isPhoneInEcmMode = inEcm.equals("true");
+ boolean isEmergencyCall = PhoneNumberUtils.isEmergencyNumber(dialString);
+
+ // Cancel Ecm timer if a second emergency call is originating in Ecm mode
+ if (isPhoneInEcmMode && isEmergencyCall) {
+ handleEcmTimer(phone.CANCEL_ECM_TIMER);
+ }
// We are initiating a call therefore even if we previously
// didn't know the state (i.e. Generic was true) we now know
@@ -210,19 +220,22 @@ public final class CdmaCallTracker extends CallTracker {
// Always unmute when initiating a new call
setMute(false);
- String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
- if(inEcm.equals("false")) {
+ // Check data call
+ disableDataCallInEmergencyCall(dialString);
+
+ // In Ecm mode, if another emergency call is dialed, Ecm mode will not exit.
+ if(!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) {
cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
} else {
phone.exitEmergencyCallbackMode();
phone.setOnEcbModeExitResponse(this,EVENT_EXIT_ECM_RESPONSE_CDMA, null);
pendingCallClirMode=clirMode;
- pendingCallInECM=true;
+ pendingCallInEcm=true;
}
}
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
return pendingMO;
}
@@ -236,6 +249,9 @@ public final class CdmaCallTracker extends CallTracker {
private Connection
dialThreeWay (String dialString) {
if (!foregroundCall.isIdle()) {
+ // Check data call
+ disableDataCallInEmergencyCall(dialString);
+
// Attach the new connection to foregroundCall
pendingMO = new CdmaConnection(phone.getContext(),
dialString, this, foregroundCall);
@@ -262,6 +278,7 @@ public final class CdmaCallTracker extends CallTracker {
// triggered by updateParent.
cwConn.updateParent(ringingCall, foregroundCall);
cwConn.onConnectedInOrOut();
+ updatePhoneState();
switchWaitingOrHoldingAndActive();
} else {
throw new CallStateException("phone not ringing");
@@ -284,8 +301,14 @@ public final class CdmaCallTracker extends CallTracker {
// Should we bother with this check?
if (ringingCall.getState() == CdmaCall.State.INCOMING) {
throw new CallStateException("cannot be in the incoming state");
- } else {
+ } else if (foregroundCall.getConnections().size() > 1) {
flashAndSetGenericTrue();
+ } else {
+ // Send a flash command to CDMA network for putting the other party on hold.
+ // For CDMA networks which do not support this the user would just hear a beep
+ // from the network. For CDMA networks which do support it will put the other
+ // party on hold.
+ cm.sendCDMAFeatureCode("", obtainMessage(EVENT_SWITCH_RESULT));
}
}
@@ -305,7 +328,7 @@ public final class CdmaCallTracker extends CallTracker {
internalClearDisconnected();
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
}
boolean
@@ -320,13 +343,16 @@ public final class CdmaCallTracker extends CallTracker {
canDial() {
boolean ret;
int serviceState = phone.getServiceState().getState();
+ String disableCall = SystemProperties.get(
+ TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
- ret = (serviceState != ServiceState.STATE_POWER_OFF) &&
- pendingMO == null
+ ret = (serviceState != ServiceState.STATE_POWER_OFF)
+ && pendingMO == null
&& !ringingCall.isRinging()
+ && !disableCall.equals("true")
&& (!foregroundCall.getState().isAlive()
- || (foregroundCall.getState() == CdmaCall.State.ACTIVE)
- || !backgroundCall.getState().isAlive());
+ || (foregroundCall.getState() == CdmaCall.State.ACTIVE)
+ || !backgroundCall.getState().isAlive());
return ret;
}
@@ -475,6 +501,11 @@ public final class CdmaCallTracker extends CallTracker {
// Someone has already asked to hangup this call
if (hangupPendingMO) {
hangupPendingMO = false;
+ // Re-start Ecm timer when an uncompleted emergency call ends
+ if (mIsEcmTimerCanceled) {
+ handleEcmTimer(phone.RESTART_ECM_TIMER);
+ }
+
try {
if (Phone.DEBUG_PHONE) log(
"poll: hangupPendingMO, hangup conn " + i);
@@ -528,20 +559,17 @@ public final class CdmaCallTracker extends CallTracker {
}
}
foregroundCall.setGeneric(false);
+
+ // Re-start Ecm timer when the connected emergency call ends
+ if (mIsEcmTimerCanceled) {
+ handleEcmTimer(phone.RESTART_ECM_TIMER);
+ } else {
+ mIsInEmergencyCall = false;
+ }
+
// Dropped connections are removed from the CallTracker
// list but kept in the Call list
connections[i] = null;
- } else if (conn != null && dc != null && !conn.compareTo(dc)) {
- // Connection in CLCC response does not match what
- // we were tracking. Assume dropped call and new call
-
- droppedDuringPoll.add(conn);
- connections[i] = new CdmaConnection (phone.getContext(), dc, this, i);
-
- if (connections[i].getCall() == ringingCall) {
- newRinging = connections[i];
- } // else something strange happened
- hasNonHangupStateChanged = true;
} else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */
boolean changed;
changed = conn.update(dc);
@@ -578,8 +606,8 @@ public final class CdmaCallTracker extends CallTracker {
droppedDuringPoll.add(pendingMO);
pendingMO = null;
hangupPendingMO = false;
- if( pendingCallInECM) {
- pendingCallInECM = false;
+ if( pendingCallInEcm) {
+ pendingCallInEcm = false;
}
}
@@ -644,7 +672,7 @@ public final class CdmaCallTracker extends CallTracker {
}
if (hasNonHangupStateChanged || newRinging != null) {
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
}
//dumpState();
@@ -678,7 +706,8 @@ public final class CdmaCallTracker extends CallTracker {
// the hangup reason is user ignoring or timing out. So conn.onDisconnect()
// is not called here. Instead, conn.onLocalDisconnect() is called.
conn.onLocalDisconnect();
- phone.notifyCallStateChanged();
+ updatePhoneState();
+ phone.notifyPreciseCallStateChanged();
return;
} else {
try {
@@ -760,6 +789,7 @@ public final class CdmaCallTracker extends CallTracker {
}
call.onHangupLocal();
+ phone.notifyPreciseCallStateChanged();
}
/* package */
@@ -821,7 +851,7 @@ public final class CdmaCallTracker extends CallTracker {
// the status of the call is after a call waiting is answered,
// 3 way call merged or a switch between calls.
foregroundCall.setGeneric(true);
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
}
private Phone.SuppService getFailedService(int what) {
@@ -865,6 +895,7 @@ public final class CdmaCallTracker extends CallTracker {
// Create a new CdmaConnection which attaches itself to ringingCall.
ringingCall.setGeneric(false);
new CdmaConnection(phone.getContext(), cw, this, ringingCall);
+ updatePhoneState();
// Finally notify application
notifyCallWaitingInfo(cw);
@@ -926,7 +957,7 @@ public final class CdmaCallTracker extends CallTracker {
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
droppedDuringPoll.clear();
break;
@@ -945,9 +976,9 @@ public final class CdmaCallTracker extends CallTracker {
case EVENT_EXIT_ECM_RESPONSE_CDMA:
//no matter the result, we still do the same here
- if (pendingCallInECM) {
+ if (pendingCallInEcm) {
cm.dial(pendingMO.address, pendingCallClirMode, obtainCompleteMessage());
- pendingCallInECM = false;
+ pendingCallInEcm = false;
}
phone.unsetOnEcbModeExitResponse(this);
break;
@@ -965,6 +996,7 @@ public final class CdmaCallTracker extends CallTracker {
if (ar.exception == null) {
// Assume 3 way call is connected
pendingMO.onConnectedInOrOut();
+ pendingMO = null;
}
break;
@@ -974,6 +1006,39 @@ public final class CdmaCallTracker extends CallTracker {
}
}
+ /**
+ * Handle Ecm timer to be canceled or re-started
+ */
+ private void handleEcmTimer(int action) {
+ phone.handleTimerInEmergencyCallbackMode(action);
+ switch(action) {
+ case CDMAPhone.CANCEL_ECM_TIMER: mIsEcmTimerCanceled = true; break;
+ case CDMAPhone.RESTART_ECM_TIMER: mIsEcmTimerCanceled = false; break;
+ default:
+ Log.e(LOG_TAG, "handleEcmTimer, unsupported action " + action);
+ }
+ }
+
+ /**
+ * Disable data call when emergency call is connected
+ */
+ private void disableDataCallInEmergencyCall(String dialString) {
+ if (PhoneNumberUtils.isEmergencyNumber(dialString)) {
+ phone.disableDataConnectivity();
+ mIsInEmergencyCall = true;
+ }
+ }
+
+ /**
+ * Check if current call is in emergency call
+ *
+ * @return true if it is in emergency call
+ * false if it is not in emergency call
+ */
+ boolean isInEmergencyCall() {
+ return mIsInEmergencyCall;
+ }
+
protected void log(String msg) {
Log.d(LOG_TAG, "[CdmaCallTracker] " + msg);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
index 54dec48..f4119ad 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java
@@ -16,12 +16,16 @@
package com.android.internal.telephony.cdma;
+import android.util.Log;
+import com.android.internal.telephony.Connection;
+
/**
* Represents a Supplementary Service Notification received from the network.
*
* {@hide}
*/
public class CdmaCallWaitingNotification {
+ static final String LOG_TAG = "CDMA";
public String number =null;
public int numberPresentation = 0;
public String name = null;
@@ -31,7 +35,6 @@ public class CdmaCallWaitingNotification {
public int alertPitch = 0;
public int signal = 0;
-
public String toString()
{
return super.toString() + "Call Waiting Notification "
@@ -45,4 +48,17 @@ public class CdmaCallWaitingNotification {
+ " signal: " + signal ;
}
+ public static int
+ presentationFromCLIP(int cli)
+ {
+ switch(cli) {
+ case 0: return Connection.PRESENTATION_ALLOWED;
+ case 1: return Connection.PRESENTATION_RESTRICTED;
+ case 2: return Connection.PRESENTATION_UNKNOWN;
+ default:
+ // This shouldn't happen, just log an error and treat as Unknown
+ Log.d(LOG_TAG, "Unexpected presentation " + cli);
+ return Connection.PRESENTATION_UNKNOWN;
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
index 025382d..0c94e6a 100644..100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -161,8 +161,8 @@ public class CdmaConnection extends Connection {
isIncoming = false;
cnapName = null;
- cnapNamePresentation = 0;
- numberPresentation = 0;
+ cnapNamePresentation = Connection.PRESENTATION_ALLOWED;
+ numberPresentation = Connection.PRESENTATION_ALLOWED;
createTime = System.currentTimeMillis();
if (parent != null) {
@@ -435,8 +435,10 @@ public class CdmaConnection extends Connection {
} else if (phone.mCM.getRadioState() != CommandsInterface.RadioState.NV_READY
&& phone.getIccCard().getState() != RuimCard.State.READY) {
return DisconnectCause.ICC_ERROR;
- } else {
+ } else if (causeCode==CallFailCause.NORMAL_CLEARING) {
return DisconnectCause.NORMAL;
+ } else {
+ return DisconnectCause.ERROR_UNSPECIFIED;
}
}
}
@@ -816,15 +818,12 @@ public class CdmaConnection extends Connection {
return c == PhoneNumberUtils.WAIT;
}
-
-
-
// This function is to find the next PAUSE character index if
// multiple pauses in a row. Otherwise it finds the next non PAUSE or
// non WAIT character index.
private static int
findNextPCharOrNonPOrNonWCharIndex(String phoneNumber, int currIndex) {
- boolean wMatched = false;
+ boolean wMatched = isWait(phoneNumber.charAt(currIndex));
int index = currIndex + 1;
int length = phoneNumber.length();
while (index < length) {
@@ -861,17 +860,17 @@ public class CdmaConnection extends Connection {
// Append the PW char
ret = (isPause(c)) ? PhoneNumberUtils.PAUSE : PhoneNumberUtils.WAIT;
- // if there is a PAUSE in at the begining of PW character sequences, and this
- // PW character sequences has more than 2 PAUSE and WAIT Characters,skip P, append W
- if (isPause(c) && (nextNonPwCharIndex > (currPwIndex + 1))) {
+ // if there is a PAUSE in at the beginning of PW character sequences, and this
+ // PW character sequences has more than 2 PAUSE and WAIT Characters,skip PAUSE,
+ // append WAIT.
+ if (isPause(c) && (nextNonPwCharIndex > (currPwIndex + 2))) {
ret = PhoneNumberUtils.WAIT;
}
return ret;
}
-
/**
- * format orignal dial string
+ * format original dial string
* 1) convert international dialing prefix "+" to
* string specified per region
*
@@ -890,20 +889,10 @@ public class CdmaConnection extends Connection {
StringBuilder ret = new StringBuilder();
char c;
int currIndex = 0;
+
while (currIndex < length) {
c = phoneNumber.charAt(currIndex);
- if (PhoneNumberUtils.isDialable(c)) {
- if (c == '+') {
- String ps = null;
- SystemProperties.get(TelephonyProperties.PROPERTY_IDP_STRING, ps);
- if (TextUtils.isEmpty(ps)) {
- ps = "011";
- }
- ret.append(ps);
- } else {
- ret.append(c);
- }
- } else if (isPause(c) || isWait(c)) {
+ if (isPause(c) || isWait(c)) {
if (currIndex < length - 1) {
// if PW not at the end
int nextIndex = findNextPCharOrNonPOrNonWCharIndex(phoneNumber, currIndex);
@@ -911,8 +900,10 @@ public class CdmaConnection extends Connection {
if (nextIndex < length) {
char pC = findPOrWCharToAppend(phoneNumber, currIndex, nextIndex);
ret.append(pC);
- // If PW char is immediately followed by non-PW char
- if (nextIndex > (currIndex + 1)) {
+ // If PW char sequence has more than 2 PW characters,
+ // skip to the last character since the sequence already be
+ // converted to WAIT character
+ if (nextIndex > (currIndex + 2)) {
currIndex = nextIndex - 1;
}
} else if (nextIndex == length) {
@@ -925,7 +916,7 @@ public class CdmaConnection extends Connection {
}
currIndex++;
}
- return ret.toString();
+ return PhoneNumberUtils.cdmaCheckAndProcessPlusCode(ret.toString());
}
private void log(String msg) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index fef6d3c..4588f36 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -143,9 +143,10 @@ public class CdmaDataConnection extends DataConnection {
lastFailTime = -1;
lastFailCause = FailCause.NONE;
receivedDisconnectReq = false;
- phone.mCM.setupDataCall(Integer.toString(RILConstants.CDMA_PHONE),
+ phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA),
Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), null, null,
- null, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
+ null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP),
+ obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
}
private void tearDownData(Message msg) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index c3818f5..ffaa1cd 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -31,6 +31,7 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.preference.PreferenceManager;
import android.provider.Checkin;
import android.telephony.ServiceState;
@@ -45,7 +46,9 @@ import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.DataConnection.FailCause;
import com.android.internal.telephony.DataConnectionTracker;
+import com.android.internal.telephony.RetryManager;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyEventLog;
import java.util.ArrayList;
@@ -54,15 +57,12 @@ import java.util.ArrayList;
* {@hide}
*/
public final class CdmaDataConnectionTracker extends DataConnectionTracker {
- private static final String LOG_TAG = "CDMA";
- private static final boolean DBG = true;
+ protected final String LOG_TAG = "CDMA";
private CDMAPhone mCdmaPhone;
// Indicates baseband will not auto-attach
private boolean noAutoAttach = false;
- long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- private boolean mReregisterOnReconnectFailure = false;
private boolean mIsScreenOn = true;
//useful for debugging
@@ -76,11 +76,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
/** Currently active CdmaDataConnection */
private CdmaDataConnection mActiveDataConnection;
- /** Defined cdma connection profiles */
- private static final int EXTERNAL_NETWORK_DEFAULT_ID = 0;
- private static final int EXTERNAL_NETWORK_NUM_TYPES = 1;
-
- private boolean[] dataEnabled = new boolean[EXTERNAL_NETWORK_NUM_TYPES];
+ private boolean mPendingRestartRadio = false;
+ private static final int TIME_DELAYED_TO_RESTART_RADIO =
+ SystemProperties.getInt("ro.cdma.timetoradiorestart", 20000);
/**
* Pool size of CdmaDataConnection objects.
@@ -100,6 +98,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
private static final int DATA_CONNECTION_ACTIVE_PH_LINK_DOWN = 1;
private static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2;
+ private static final String[] mSupportedApnTypes = {
+ Phone.APN_TYPE_DEFAULT,
+ Phone.APN_TYPE_MMS,
+ Phone.APN_TYPE_HIPRI };
+
// Possibly promoate to base class, the only difference is
// the INTENT_RECONNECT_ALARM action is a different string.
// Do consider technology changes if it is promoted.
@@ -143,7 +146,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
};
- //***** Constructor
+ /* Constructor */
CdmaDataConnectionTracker(CDMAPhone p) {
super(p);
@@ -160,6 +163,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
p.mSST.registerForCdmaDataConnectionDetached(this, EVENT_CDMA_DATA_DETACHED, null);
p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null);
p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
+ p.mCM.registerForCdmaOtaProvision(this, EVENT_CDMA_OTA_PROVISION, null);
this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat"));
@@ -170,7 +174,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
- p.getContext().registerReceiver(mIntentReceiver, filter, null, p.h);
+ // TODO: Why is this registering the phone as the receiver of the intent
+ // and not its own handler?
+ p.getContext().registerReceiver(mIntentReceiver, filter, null, p);
mDataConnectionTracker = this;
@@ -180,13 +186,25 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
// and 2) whether the RIL will setup the baseband to auto-PS attach.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID] =
+ dataEnabled[APN_DEFAULT_ID] =
!sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false);
- noAutoAttach = !dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID];
+ if (dataEnabled[APN_DEFAULT_ID]) {
+ enabledCount++;
+ }
+ noAutoAttach = !dataEnabled[APN_DEFAULT_ID];
+
+ if (!mRetryMgr.configure(SystemProperties.get("ro.cdma.data_retry_config"))) {
+ if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) {
+ // Should never happen, log an error and default to a simple linear sequence.
+ Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG="
+ + DEFAULT_DATA_RETRY_CONFIG);
+ mRetryMgr.configure(20, 2000, 1000);
+ }
+ }
}
public void dispose() {
- //Unregister from all events
+ // Unregister from all events
phone.mCM.unregisterForAvailable(this);
phone.mCM.unregisterForOffOrNotAvailable(this);
mCdmaPhone.mRuimRecords.unregisterForRecordsLoaded(this);
@@ -198,6 +216,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
mCdmaPhone.mSST.unregisterForCdmaDataConnectionDetached(this);
mCdmaPhone.mSST.unregisterForRoamingOn(this);
mCdmaPhone.mSST.unregisterForRoamingOff(this);
+ phone.mCM.unregisterForCdmaOtaProvision(this);
phone.getContext().unregisterReceiver(this.mIntentReceiver);
destroyAllDataConnectionList();
@@ -207,7 +226,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
if(DBG) Log.d(LOG_TAG, "CdmaDataConnectionTracker finalized");
}
- void setState(State s) {
+ protected void setState(State s) {
if (DBG) log ("setState: " + s);
if (state != s) {
if (s == State.INITING) { // request Data connection context
@@ -224,39 +243,33 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
state = s;
}
- public int enableApnType(String type) {
- // This request is mainly used to enable MMS APN
- // In CDMA there is no need to enable/disable a different APN for MMS
- Log.d(LOG_TAG, "Request to enableApnType("+type+")");
- if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- return Phone.APN_ALREADY_ACTIVE;
- } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
- Log.w(LOG_TAG, "Phone.APN_TYPE_SUPL not enabled for CDMA");
- return Phone.APN_REQUEST_FAILED;
- } else {
- return Phone.APN_REQUEST_FAILED;
- }
+ @Override
+ protected boolean isApnTypeActive(String type) {
+ return (isApnTypeAvailable(type) &&
+ mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() ==
+ ServiceState.STATE_IN_SERVICE);
}
- public int disableApnType(String type) {
- // This request is mainly used to disable MMS APN
- // In CDMA there is no need to enable/disable a different APN for MMS
- Log.d(LOG_TAG, "Request to disableApnType("+type+")");
- if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- return Phone.APN_REQUEST_STARTED;
- } else {
- return Phone.APN_REQUEST_FAILED;
+ @Override
+ protected boolean isApnTypeAvailable(String type) {
+ for (String s : mSupportedApnTypes) {
+ if (TextUtils.equals(type, s)) {
+ return true;
+ }
}
+ return false;
}
- private boolean isEnabled(int cdmaDataProfile) {
- return dataEnabled[cdmaDataProfile];
+ protected String[] getActiveApnTypes() {
+ if (mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() ==
+ ServiceState.STATE_IN_SERVICE) {
+ return mSupportedApnTypes.clone();
+ }
+ return new String[0];
}
- private void setEnabled(int cdmaDataProfile, boolean enable) {
- Log.d(LOG_TAG, "setEnabled(" + cdmaDataProfile + ", " + enable + ')');
- dataEnabled[cdmaDataProfile] = enable;
- Log.d(LOG_TAG, "dataEnabled[DEFAULT_PROFILE]=" + dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]);
+ protected String getActiveApnString() {
+ return null;
}
/**
@@ -282,54 +295,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
return true;
}
- /**
- * Prevent mobile data connections from being established,
- * or once again allow mobile data connections. If the state
- * toggles, then either tear down or set up data, as
- * appropriate to match the new state.
- * <p>This operation only affects the default connection
- * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
- * @return {@code true} if the operation succeeded
- */
- public boolean setDataEnabled(boolean enable) {
-
- boolean isEnabled = isEnabled(EXTERNAL_NETWORK_DEFAULT_ID);
-
- Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled);
- if (!isEnabled && enable) {
- setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, true);
- sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
- } else if (!enable) {
- setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, false);
- Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = 1; // tearDown is true
- msg.obj = Phone.REASON_DATA_DISABLED;
- sendMessage(msg);
- }
- return true;
- }
-
- /**
- * Report the current state of data connectivity (enabled or disabled)
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getDataEnabled() {
- return dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID];
- }
-
- /**
- * Report on whether data connectivity is enabled
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getAnyDataEnabled() {
- for (int i=0; i < EXTERNAL_NETWORK_NUM_TYPES; i++) {
- if (isEnabled(i)) return true;
- }
- return false;
- }
-
private boolean isDataAllowed() {
boolean roaming = phone.getServiceState().getRoaming();
return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled());
@@ -359,7 +324,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
&& (mCdmaPhone.mSST.isConcurrentVoiceAndData() ||
phone.getState() == Phone.State.IDLE )
&& isDataAllowed()
- && desiredPowerState) {
+ && desiredPowerState
+ && !mPendingRestartRadio) {
return setupData(reason);
@@ -375,7 +341,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
" dataEnabled=" + getAnyDataEnabled() +
" roaming=" + roaming +
" dataOnRoamingEnable=" + getDataOnRoamingEnabled() +
- " desiredPowerState=" + desiredPowerState);
+ " desiredPowerState=" + desiredPowerState +
+ " PendingRestartRadio=" + mPendingRestartRadio);
}
return false;
}
@@ -459,9 +426,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
setState(State.CONNECTED);
phone.notifyDataConnection(reason);
startNetStatPoll();
- // reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- mReregisterOnReconnectFailure = false;
+ mRetryMgr.resetRetryCount();
}
private void resetPollStats() {
@@ -488,16 +453,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
}
protected void restartRadio() {
- Log.d(LOG_TAG, "************TURN OFF RADIO**************");
+ if (DBG) log("Cleanup connection and wait " +
+ (TIME_DELAYED_TO_RESTART_RADIO / 1000) + "s to restart radio");
cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
- phone.mCM.setRadioPower(false, null);
- /* Note: no need to call setRadioPower(true). Assuming the desired
- * radio power state is still ON (as tracked by ServiceStateTracker),
- * ServiceStateTracker will call setRadioPower when it receives the
- * RADIO_STATE_CHANGED notification for the power off. And if the
- * desired power state has changed in the interim, we don't want to
- * override it with an unconditional power on.
- */
+ sendEmptyMessageDelayed(EVENT_RESTART_RADIO, TIME_DELAYED_TO_RESTART_RADIO);
+ mPendingRestartRadio = true;
}
private Runnable mPollNetStat = new Runnable() {
@@ -541,10 +501,10 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
sentSinceLastRecv = 0;
newActivity = Activity.DATAIN;
} else if (sent == 0 && received == 0) {
- newActivity = Activity.NONE;
+ newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE;
} else {
sentSinceLastRecv = 0;
- newActivity = Activity.NONE;
+ newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE;
}
if (activity != newActivity) {
@@ -608,8 +568,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
private boolean retryAfterDisconnected(String reason) {
boolean retry = true;
- if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
- Phone.REASON_DATA_DISABLED.equals(reason) ) {
+ if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) {
retry = false;
}
return retry;
@@ -617,21 +576,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
if (state == State.FAILED) {
- if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
- if (mReregisterOnReconnectFailure) {
- // We have already tried to re-register to the network.
- // This might be a problem with the data network.
- nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
- } else {
- // Try to Re-register to the network.
- Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network");
- mReregisterOnReconnectFailure = true;
- mCdmaPhone.mSST.reRegisterNetwork(null);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- return;
- }
- }
-
+ /**
+ * For now With CDMA we never try to reconnect on
+ * error and instead just continue to retry
+ * at the last time until the state is changed.
+ * TODO: Make this configurable?
+ */
+ int nextReconnectDelay = mRetryMgr.getRetryTimer();
Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for "
+ (nextReconnectDelay / 1000) + "s");
@@ -645,8 +596,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
SystemClock.elapsedRealtime() + nextReconnectDelay,
mReconnectIntent);
- // double it for next time
- nextReconnectDelay *= 2;
+ mRetryMgr.increaseRetryCount();
if (!shouldPostNotification(lastFailCauseCode)) {
Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification "
@@ -678,8 +628,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
/**
* @override com.android.internal.telephony.DataConnectionTracker
*/
- protected void onTrySetupData(String reason) {
- trySetupData(reason);
+ protected boolean onTrySetupData(String reason) {
+ return trySetupData(reason);
}
/**
@@ -723,10 +673,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
* @override com.android.internal.telephony.DataConnectionTracker
*/
protected void onRadioOffOrNotAvailable() {
- // Make sure our reconnect delay starts at the initial value
- // next time the radio comes on
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- mReregisterOnReconnectFailure = false;
+ mRetryMgr.resetRetryCount();
if (phone.getSimulatedRadioControl() != null) {
// Assume data is connected on the simulator
@@ -773,6 +720,20 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
reason = (String) ar.userObj;
}
setState(State.IDLE);
+
+ // Since the pending request to turn off or restart radio will be processed here,
+ // remove the pending event to restart radio from the message queue.
+ if (mPendingRestartRadio) removeMessages(EVENT_RESTART_RADIO);
+
+ // Process the pending request to turn off radio in ServiceStateTracker first.
+ // If radio is turned off in ServiceStateTracker, ignore the pending event to restart radio.
+ CdmaServiceStateTracker ssTracker = mCdmaPhone.mSST;
+ if (ssTracker.processPendingRadioPowerOffAfterDataOff()) {
+ mPendingRestartRadio = false;
+ } else {
+ onRestartRadio();
+ }
+
phone.notifyDataConnection(reason);
if (retryAfterDisconnected(reason)) {
trySetupData(reason);
@@ -802,9 +763,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
resetPollStats();
}
} else {
- // reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- mReregisterOnReconnectFailure = false;
+ mRetryMgr.resetRetryCount();
// in case data setup was attempted when we were on a voice call
trySetupData(Phone.REASON_VOICE_CALL_ENDED);
}
@@ -840,7 +799,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
} else {
if (state == State.FAILED) {
cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
int bsid = (loc != null) ? loc.getBaseStationId() : -1;
@@ -853,6 +812,37 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
}
}
+ private void onCdmaOtaProvision(AsyncResult ar) {
+ if (ar.exception != null) {
+ int [] otaPrivision = (int [])ar.result;
+ if ((otaPrivision != null) && (otaPrivision.length > 1)) {
+ switch (otaPrivision[0]) {
+ case Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED:
+ case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED:
+ mRetryMgr.resetRetryCount();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ private void onRestartRadio() {
+ if (mPendingRestartRadio) {
+ Log.d(LOG_TAG, "************TURN OFF RADIO**************");
+ phone.mCM.setRadioPower(false, null);
+ /* Note: no need to call setRadioPower(true). Assuming the desired
+ * radio power state is still ON (as tracked by ServiceStateTracker),
+ * ServiceStateTracker will call setRadioPower when it receives the
+ * RADIO_STATE_CHANGED notification for the power off. And if the
+ * desired power state has changed in the interim, we don't want to
+ * override it with an unconditional power on.
+ */
+ mPendingRestartRadio = false;
+ }
+ }
+
private void writeEventLogCdmaDataDrop() {
CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation());
int bsid = (loc != null) ? loc.getBaseStationId() : -1;
@@ -905,28 +895,28 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
}
}
- String getInterfaceName() {
+ protected String getInterfaceName(String apnType) {
if (mActiveDataConnection != null) {
return mActiveDataConnection.getInterface();
}
return null;
}
- protected String getIpAddress() {
+ protected String getIpAddress(String apnType) {
if (mActiveDataConnection != null) {
return mActiveDataConnection.getIpAddress();
}
return null;
}
- String getGateway() {
+ protected String getGateway(String apnType) {
if (mActiveDataConnection != null) {
return mActiveDataConnection.getGatewayAddress();
}
return null;
}
- protected String[] getDnsServers() {
+ protected String[] getDnsServers(String apnType) {
if (mActiveDataConnection != null) {
return mActiveDataConnection.getDnsServers();
}
@@ -961,6 +951,15 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
onDataStateChanged((AsyncResult) msg.obj);
break;
+ case EVENT_CDMA_OTA_PROVISION:
+ onCdmaOtaProvision((AsyncResult) msg.obj);
+ break;
+
+ case EVENT_RESTART_RADIO:
+ if (DBG) log("EVENT_RESTART_RADIO");
+ onRestartRadio();
+ break;
+
default:
// handle the message in the super class DataConnectionTracker
super.handleMessage(msg);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index ecdc8f6..88cccd3 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -19,18 +19,22 @@ package com.android.internal.telephony.cdma;
import android.app.Activity;
import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
import android.content.ContentValues;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.SQLException;
import android.os.AsyncResult;
import android.os.Message;
+import android.os.SystemProperties;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
import android.preference.PreferenceManager;
import android.util.Config;
import android.util.Log;
+import android.telephony.SmsManager;
+import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
@@ -43,6 +47,7 @@ import com.android.internal.util.HexDump;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
+import java.lang.Boolean;
final class CdmaSMSDispatcher extends SMSDispatcher {
@@ -75,13 +80,19 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
return Intents.RESULT_SMS_GENERIC_ERROR;
}
+ String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+ if (inEcm.equals("true")) {
+ return Intents.RESULT_SMS_GENERIC_ERROR;
+ }
+
// Decode BD stream and set sms variables.
SmsMessage sms = (SmsMessage) smsb;
sms.parseSms();
int teleService = sms.getTeleService();
boolean handled = false;
- if (sms.getUserData() == null) {
+ if ((sms.getUserData() == null) && (SmsEnvelope.TELESERVICE_MWI != teleService) &&
+ (SmsEnvelope.TELESERVICE_VMN != teleService)) {
if (Config.LOGD) {
Log.d(TAG, "Received SMS without user data");
}
@@ -92,10 +103,11 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
return Intents.RESULT_SMS_HANDLED;
}
- if (SmsEnvelope.TELESERVICE_WAP == teleService){
+ if (SmsEnvelope.TELESERVICE_WAP == teleService) {
return processCdmaWapPdu(sms.getUserData(), sms.messageRef,
sms.getOriginatingAddress());
- } else if (SmsEnvelope.TELESERVICE_VMN == teleService) {
+ } else if ((SmsEnvelope.TELESERVICE_VMN == teleService) ||
+ (SmsEnvelope.TELESERVICE_MWI == teleService)) {
// handling Voicemail
int voicemailCount = sms.getNumOfVoicemails();
Log.d(TAG, "Voicemail count=" + voicemailCount);
@@ -323,6 +335,24 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
sentIntent, deliveryIntent);
}
+ protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
+ PendingIntent deliveryIntent) {
+ String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
+ if (Boolean.parseBoolean(inEcm)) {
+ if (sentIntent != null) {
+ try {
+ sentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE);
+ } catch (CanceledException ex) {}
+ }
+ if (Config.LOGD) {
+ Log.d(TAG, "Block SMS in Emergency Callback mode");
+ }
+ return;
+ }
+
+ super.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent);
+ }
+
/** {@inheritDoc} */
protected void sendSms(SmsTracker tracker) {
HashMap map = tracker.mData;
@@ -343,6 +373,12 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
/** {@inheritDoc} */
protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){
// FIXME unit test leaves cm == null. this should change
+
+ String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+ if (inEcm.equals("true")) {
+ return;
+ }
+
if (mCm != null) {
mCm.acknowledgeLastIncomingCdmaSms(success, resultToCause(result), response);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 23a0520..b4de09b 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -93,6 +93,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
private int mRegistrationState = -1;
private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList();
private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList();
+ private RegistrantList cdmaForSubscriptionInfoReadyRegistrants = new RegistrantList();
// Sometimes we get the NITZ time before we know what country we are in.
// Keep the time zone information from the NITZ string so we can fix
@@ -121,13 +122,17 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
private int curSpnRule = 0;
private String mMdn;
- private int mHomeSystemId;
- private int mHomeNetworkId;
+ private int mHomeSystemId[] = null;
+ private int mHomeNetworkId[] = null;
private String mMin;
+ private String mPrlVersion;
+ private boolean mIsMinInfoReady = false;
private boolean isEriTextLoaded = false;
private boolean isSubscriptionFromRuim = false;
+ private boolean mPendingRadioPowerOffAfterDataOff = false;
+
// Registration Denied Reason, General/Authentication Failure, used only for debugging purposes
private String mRegistrationDeniedReason;
@@ -175,6 +180,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
cm.registerForNVReady(this, EVENT_NV_READY, null);
phone.registerForEriFileLoaded(this, EVENT_ERI_FILE_LOADED, null);
+ cm.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null);
// system setting property AIRPLANE_MODE_ON is set in Settings.
int airplaneMode = Settings.System.getInt(
@@ -198,6 +204,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
cm.unregisterForNetworkStateChanged(this);
cm.unregisterForRUIMReady(this);
cm.unregisterForNVReady(this);
+ cm.unregisterForCdmaOtaProvision(this);
phone.unregisterForEriFileLoaded(this);
phone.mRuimRecords.unregisterForRecordsLoaded(this);
cm.unSetOnSignalStrengthUpdate(this);
@@ -261,6 +268,25 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
cdmaDataConnectionDetachedRegistrants.remove(h);
}
+ /**
+ * Registration point for subscription info ready
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ cdmaForSubscriptionInfoReadyRegistrants.add(r);
+
+ if (isMinInfoReady()) {
+ r.notifyRegistrant();
+ }
+ }
+
+ public void unregisterForSubscriptionInfoReady(Handler h) {
+ cdmaForSubscriptionInfoReadyRegistrants.remove(h);
+ }
+
//***** Called from CDMAPhone
public void
getLacAndCid(Message onComplete) {
@@ -290,6 +316,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
EVENT_RUIM_RECORDS_LOADED, null);
mNeedToRegForRuimLoaded = false;
}
+
+ cm.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
+ if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
+
// restore the previous network selection.
pollState();
@@ -299,6 +329,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
case EVENT_NV_READY:
isSubscriptionFromRuim = false;
+ // For Non-RUIM phones, the subscription information is stored in
+ // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA
+ // subscription info.
+ cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
pollState();
// Signal strength polling stops when radio is off
queueNextSignalStrengthPoll();
@@ -376,11 +410,59 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
case EVENT_POLL_STATE_REGISTRATION_CDMA:
case EVENT_POLL_STATE_OPERATOR_CDMA:
- case EVENT_POLL_STATE_CDMA_SUBSCRIPTION:
ar = (AsyncResult) msg.obj;
handlePollStateResult(msg.what, ar);
break;
+ case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION
+ ar = (AsyncResult) msg.obj;
+
+ if (ar.exception == null) {
+ String cdmaSubscription[] = (String[])ar.result;
+ if (cdmaSubscription != null && cdmaSubscription.length >= 5) {
+ mMdn = cdmaSubscription[0];
+ if (cdmaSubscription[1] != null) {
+ String[] sid = cdmaSubscription[1].split(",");
+ mHomeSystemId = new int[sid.length];
+ for (int i = 0; i < sid.length; i++) {
+ try {
+ mHomeSystemId[i] = Integer.parseInt(sid[i]);
+ } catch (NumberFormatException ex) {
+ Log.e(LOG_TAG, "error parsing system id: ", ex);
+ }
+ }
+ }
+ Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION SID=" + cdmaSubscription[1] );
+
+ if (cdmaSubscription[2] != null) {
+ String[] nid = cdmaSubscription[2].split(",");
+ mHomeNetworkId = new int[nid.length];
+ for (int i = 0; i < nid.length; i++) {
+ try {
+ mHomeNetworkId[i] = Integer.parseInt(nid[i]);
+ } catch (NumberFormatException ex) {
+ Log.e(LOG_TAG, "error parsing network id: ", ex);
+ }
+ }
+ }
+ Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION NID=" + cdmaSubscription[2] );
+ mMin = cdmaSubscription[3];
+ mPrlVersion = cdmaSubscription[4];
+ Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION MDN=" + mMdn);
+ //Notify apps subscription info is ready
+ if (cdmaForSubscriptionInfoReadyRegistrants != null) {
+ cdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants();
+ }
+ if (!mIsMinInfoReady) {
+ mIsMinInfoReady = true;
+ }
+ } else {
+ Log.w(LOG_TAG,"error parsing cdmaSubscription params num="
+ + cdmaSubscription.length);
+ }
+ }
+ break;
+
case EVENT_POLL_SIGNAL_STRENGTH:
// Just poll signal strength...not part of pollState()
@@ -427,6 +509,29 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
pollState();
break;
+ case EVENT_OTA_PROVISION_STATUS_CHANGE:
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception == null) {
+ ints = (int[]) ar.result;
+ int otaStatus = ints[0];
+ if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_COMMITTED
+ || otaStatus == phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) {
+ Log.d(LOG_TAG, "Received OTA_PROGRAMMING Complete,Reload MDN ");
+ cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION));
+ }
+ }
+ break;
+
+ case EVENT_SET_RADIO_POWER_OFF:
+ synchronized(this) {
+ if (mPendingRadioPowerOffAfterDataOff) {
+ if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now.");
+ cm.setRadioPower(false, null);
+ mPendingRadioPowerOffAfterDataOff = false;
+ }
+ }
+ break;
+
default:
Log.e(LOG_TAG, "Unhandled message with number: " + msg.what);
break;
@@ -455,19 +560,23 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF;
dcTracker.sendMessage(msg);
- // Poll data state up to 15 times, with a 100ms delay
- // totaling 1.5 sec. Normal data disable action will finish in 100ms.
- for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) {
- DataConnectionTracker.State currentState = dcTracker.getState();
- if (currentState != DataConnectionTracker.State.CONNECTED
- && currentState != DataConnectionTracker.State.DISCONNECTING) {
- if (DBG) log("Data shutdown complete.");
- break;
+ synchronized(this) {
+ if (!mPendingRadioPowerOffAfterDataOff) {
+ DataConnectionTracker.State currentState = dcTracker.getState();
+ if (currentState != DataConnectionTracker.State.CONNECTED
+ && currentState != DataConnectionTracker.State.DISCONNECTING) {
+ if (DBG) log("Data disconnected, turn off radio right away.");
+ cm.setRadioPower(false, null);
+ }
+ else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 5000)) {
+ if (DBG) log("Wait 5 sec for data to be disconnected, then turn off radio.");
+ mPendingRadioPowerOffAfterDataOff = true;
+ } else {
+ Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
+ cm.setRadioPower(false, null);
+ }
}
- SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS);
}
- // If it's on and available and we want it off..
- cm.setRadioPower(false, null);
} // Otherwise, we're in the desired state
}
@@ -589,7 +698,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
}
mRegistrationState = registrationState;
- mCdmaRoaming = regCodeIsRoaming(registrationState);
+ // mCdmaRoaming is true when registration state is roaming and TSB58 roaming
+ // indicator is not in the carrier-specified list of ERIs for home system
+ mCdmaRoaming =
+ regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]);
newSS.setState (regCodeToServiceState(registrationState));
this.newCdmaDataConnectionState = radioTechnologyToDataServiceState(radioTechnology);
@@ -636,27 +748,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
}
break;
- case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION
- String cdmaSubscription[] = (String[])ar.result;
-
- if (cdmaSubscription != null && cdmaSubscription.length >= 4) {
- mMdn = cdmaSubscription[0];
- // TODO: Only grabbing the first SID/NID for now.
- if (cdmaSubscription[1] != null) {
- String[] sid = cdmaSubscription[1].split(",");
- mHomeSystemId = sid.length > 0 ? Integer.parseInt(sid[0]) : 0;
- }
- if (cdmaSubscription[2] != null) {
- String[] nid = cdmaSubscription[2].split(",");
- mHomeNetworkId = nid.length > 0 ? Integer.parseInt(nid[0]) : 0;
- }
- mMin = cdmaSubscription[3];
-
- } else {
- Log.w(LOG_TAG, "error parsing cdmaSubscription");
- }
- break;
-
default:
Log.e(LOG_TAG, "RIL response handle in wrong phone!"
+ " Expected CDMA RIL request and get GSM RIL request.");
@@ -672,7 +763,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
if (pollingContext[0] == 0) {
boolean namMatch = false;
- if ((mHomeSystemId != 0) && (mHomeSystemId == newSS.getSystemId()) ) {
+ if (!isSidsAllZeros() && isHomeSid(newSS.getSystemId())) {
namMatch = true;
}
@@ -684,33 +775,43 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
}
// Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator
- // TODO(Teleca): Validate this is correct.
- if (mIsInPrl) {
- if (namMatch && (mRoamingIndicator <= 2)) {
- // System is acquired, prl match, nam match and mRoamingIndicator <= 2
- newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
- } else {
- // System is acquired, prl match, no nam match or mRoamingIndicator > 2
- newSS.setCdmaRoamingIndicator(mRoamingIndicator);
- }
- } else {
- if (mRegistrationState == 5) {
- // System is acquired but prl not loaded or no prl match
+ newSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator);
+ newSS.setCdmaRoamingIndicator(mRoamingIndicator);
+ boolean isPrlLoaded = true;
+ if (TextUtils.isEmpty(mPrlVersion)) {
+ isPrlLoaded = false;
+ }
+ if (!isPrlLoaded) {
+ newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH);
+ } else if (!isSidsAllZeros()) {
+ if (!namMatch && !mIsInPrl) {
+ // Use default
+ newSS.setCdmaRoamingIndicator(mDefaultRoamingIndicator);
+ } else if (namMatch && !mIsInPrl) {
newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH);
+ } else if (!namMatch && mIsInPrl) {
+ // Use the one from PRL/ERI
+ newSS.setCdmaRoamingIndicator(mRoamingIndicator);
} else {
- // Use the default indicator
+ // It means namMatch && mIsInPrl
+ if ((mRoamingIndicator <= 2)) {
+ newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
+ } else {
+ // Use the one from PRL/ERI
+ newSS.setCdmaRoamingIndicator(mRoamingIndicator);
+ }
}
}
- newSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator);
// NOTE: Some operator may require to override the mCdmaRoaming (set by the modem)
// depending on the mRoamingIndicator.
if (DBG) {
log("Set CDMA Roaming Indicator to: " + newSS.getCdmaRoamingIndicator()
- + ". mCdmaRoaming = " + mCdmaRoaming + ", namMatch = " + namMatch
- + ", mIsInPrl = " + mIsInPrl + ", mRoamingIndicator = " + mRoamingIndicator
+ + ". mCdmaRoaming = " + mCdmaRoaming + ", isPrlLoaded = " + isPrlLoaded
+ + ". namMatch = " + namMatch + " , mIsInPrl = " + mIsInPrl
+ + ", mRoamingIndicator = " + mRoamingIndicator
+ ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator);
}
pollStateDone();
@@ -773,11 +874,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
// are allowed to arrive out-of-order
pollingContext[0]++;
- // RIL_REQUEST_CDMA_SUBSCRIPTION is necessary for CDMA
- cm.getCDMASubscription(
- obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION, pollingContext));
-
- pollingContext[0]++;
// RIL_REQUEST_OPERATOR is necessary for CDMA
cm.getOperator(
obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext));
@@ -972,7 +1068,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
cdmaDataConnectionDetachedRegistrants.notifyRegistrants();
}
- if (hasCdmaDataConnectionChanged) {
+ if (hasCdmaDataConnectionChanged || hasNetworkTypeChanged) {
phone.notifyDataConnection(null);
}
@@ -1047,7 +1143,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
/**
* send signal-strength-changed notification if changed
- * Called both for solicited and unsolicited signal stength updates
+ * Called both for solicited and unsolicited signal strength updates
*/
private void
onSignalStrengthResult(AsyncResult ar) {
@@ -1060,15 +1156,15 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
int[] ints = (int[])ar.result;
int offset = 2;
- int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -1;
- int cdmaEcio = (ints[offset+1] > 0) ? -ints[offset+1] : -1;
+ int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120;
+ int cdmaEcio = (ints[offset+1] > 0) ? -ints[offset+1] : -160;
int evdoRssi = -1;
int evdoEcio = -1;
int evdoSnr = -1;
if ((networkType == ServiceState.RADIO_TECHNOLOGY_EVDO_0)
|| (networkType == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) {
- evdoRssi = (ints[offset+2] > 0) ? -ints[offset+2] : -1;
+ evdoRssi = (ints[offset+2] > 0) ? -ints[offset+2] : -120;
evdoEcio = (ints[offset+3] > 0) ? -ints[offset+3] : -1;
evdoSnr = ((ints[offset+4] > 0) && (ints[offset+4] <= 8)) ? ints[offset+4] : -1;
}
@@ -1152,6 +1248,33 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
}
/**
+ * Determine whether a roaming indicator is in the carrier-specified list of ERIs for
+ * home system
+ *
+ * @param roamInd roaming indicator in String
+ * @return true if the roamInd is in the carrier-specified list of ERIs for home network
+ */
+ private boolean isRoamIndForHomeSystem(String roamInd) {
+ // retrieve the carrier-specified list of ERIs for home system
+ String homeRoamIndcators = SystemProperties.get("ro.cdma.homesystem");
+
+ if (!TextUtils.isEmpty(homeRoamIndcators)) {
+ // searches through the comma-separated list for a match,
+ // return true if one is found.
+ for (String homeRoamInd : homeRoamIndcators.split(",")) {
+ if (homeRoamInd.equals(roamInd)) {
+ return true;
+ }
+ }
+ // no matches found against the list!
+ return false;
+ }
+
+ // no system property found for the roaming indicators for home system
+ return false;
+ }
+
+ /**
* Set roaming state when cdmaRoaming is true and ons is different from spn
* @param cdmaRoaming TS 27.007 7.2 CREG registered roaming
* @param s ServiceState hold current ons
@@ -1396,6 +1519,31 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
}
}
+ private boolean isSidsAllZeros() {
+ if (mHomeSystemId != null) {
+ for (int i=0; i < mHomeSystemId.length; i++) {
+ if (mHomeSystemId[i] != 0) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check whether a specified system ID that matches one of the home system IDs.
+ */
+ private boolean isHomeSid(int sid) {
+ if (mHomeSystemId != null) {
+ for (int i=0; i < mHomeSystemId.length; i++) {
+ if (sid == mHomeSystemId[i]) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* @return true if phone is camping on a technology
* that could support voice and data simultaneously.
@@ -1420,6 +1568,11 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
return mMin;
}
+ /** Returns null if NV is not yet ready */
+ public String getPrlVersion() {
+ return mPrlVersion;
+ }
+
/**
* Returns IMSI as MCC + MNC + MIN
*/
@@ -1435,4 +1588,31 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
return null;
}
}
+
+ /**
+ * Check if subscription data has been assigned to mMin
+ *
+ * return true if MIN info is ready; false otherwise.
+ */
+ public boolean isMinInfoReady() {
+ return mIsMinInfoReady;
+ }
+
+ /**
+ * process the pending request to turn radio off after data is disconnected
+ *
+ * return true if there is pending request to process; false otherwise.
+ */
+ public boolean processPendingRadioPowerOffAfterDataOff() {
+ synchronized(this) {
+ if (mPendingRadioPowerOffAfterDataOff) {
+ if (DBG) log("Process pending request to turn radio off.");
+ removeMessages(EVENT_SET_RADIO_POWER_OFF);
+ cm.setRadioPower(false, null);
+ mPendingRadioPowerOffAfterDataOff = false;
+ return true;
+ }
+ return false;
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
index 9d9f479..734badd 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
@@ -16,507 +16,34 @@
package com.android.internal.telephony.cdma;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneProxy;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-
-import android.app.ActivityManagerNative;
-import android.content.Intent;
-import android.content.res.Configuration;
-
-import static android.Manifest.permission.READ_PHONE_STATE;
/**
* Note: this class shares common code with SimCard, consider a base class to minimize code
* duplication.
* {@hide}
*/
-public final class RuimCard extends Handler implements IccCard {
- static final String LOG_TAG="CDMA";
-
- //***** Instance Variables
- private static final boolean DBG = true;
-
- private CDMAPhone phone;
-
- private CommandsInterface.IccStatus status = null;
- private boolean mDesiredPinLocked;
- private boolean mDesiredFdnEnabled;
- private boolean mRuimPinLocked = true; // default to locked
- private boolean mRuimFdnEnabled = false; // Default to disabled.
- // Will be updated when RUIM_READY.
-// //***** Constants
-
-// // FIXME I hope this doesn't conflict with the Dialer's notifications
-// Nobody is using this at the moment
-// static final int NOTIFICATION_ID_ICC_STATUS = 33456;
-
- //***** Event Constants
-
- static final int EVENT_RUIM_LOCKED_OR_ABSENT = 1;
- static final int EVENT_GET_RUIM_STATUS_DONE = 2;
- static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
- static final int EVENT_PINPUK_DONE = 4;
- static final int EVENT_REPOLL_STATUS_DONE = 5;
- static final int EVENT_RUIM_READY = 6;
- static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
- static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
- static final int EVENT_CHANGE_RUIM_PASSWORD_DONE = 9;
- static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
- static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
-
-
- //***** Constructor
+public final class RuimCard extends IccCard {
RuimCard(CDMAPhone phone) {
- this.phone = phone;
-
- phone.mCM.registerForRUIMLockedOrAbsent(
- this, EVENT_RUIM_LOCKED_OR_ABSENT, null);
-
- phone.mCM.registerForOffOrNotAvailable(
- this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
-
- phone.mCM.registerForRUIMReady(
- this, EVENT_RUIM_READY, null);
-
+ super(phone, "CDMA", true);
+ mPhone.mCM.registerForRUIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null);
+ mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+ mPhone.mCM.registerForRUIMReady(mHandler, EVENT_ICC_READY, null);
updateStateProperty();
}
- //***** RuimCard implementation
-
- public State
- getState() {
- if (status == null) {
- switch(phone.mCM.getRadioState()) {
- /* This switch block must not return anything in
- * State.isLocked() or State.ABSENT.
- * If it does, handleSimStatus() may break
- */
- case RADIO_OFF:
- case RADIO_UNAVAILABLE:
- case RUIM_NOT_READY:
- return State.UNKNOWN;
- case RUIM_LOCKED_OR_ABSENT:
- //this should be transient-only
- return State.UNKNOWN;
- case RUIM_READY:
- return State.READY;
- case NV_READY:
- case NV_NOT_READY:
- return State.ABSENT;
- }
- } else {
- switch (status) {
- case ICC_ABSENT: return State.ABSENT;
- case ICC_NOT_READY: return State.UNKNOWN;
- case ICC_READY: return State.READY;
- case ICC_PIN: return State.PIN_REQUIRED;
- case ICC_PUK: return State.PUK_REQUIRED;
- case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED;
- }
- }
-
- Log.e(LOG_TAG, "RuimCard.getState(): case should never be reached");
- return State.UNKNOWN;
- }
-
+ @Override
public void dispose() {
//Unregister for all events
- phone.mCM.unregisterForRUIMLockedOrAbsent(this);
- phone.mCM.unregisterForOffOrNotAvailable(this);
- phone.mCM.unregisterForRUIMReady(this);
- }
-
- protected void finalize() {
- if(DBG) Log.d(LOG_TAG, "RuimCard finalized");
- }
-
- private RegistrantList absentRegistrants = new RegistrantList();
- private RegistrantList pinLockedRegistrants = new RegistrantList();
- private RegistrantList networkLockedRegistrants = new RegistrantList();
-
-
- public void registerForAbsent(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- absentRegistrants.add(r);
-
- if (getState() == State.ABSENT) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForAbsent(Handler h) {
- absentRegistrants.remove(h);
- }
-
- public void registerForNetworkLocked(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- networkLockedRegistrants.add(r);
-
- if (getState() == State.NETWORK_LOCKED) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForNetworkLocked(Handler h) {
- networkLockedRegistrants.remove(h);
- }
-
- public void registerForLocked(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- pinLockedRegistrants.add(r);
-
- if (getState().isPinLocked()) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForLocked(Handler h) {
- pinLockedRegistrants.remove(h);
- }
-
- public void supplyPin (String pin, Message onComplete) {
- phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyPuk (String puk, String newPin, Message onComplete) {
- phone.mCM.supplyIccPuk(puk, newPin, obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyPin2 (String pin2, Message onComplete) {
- phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
- phone.mCM.supplyIccPuk2(puk2, newPin2, obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyNetworkDepersonalization (String pin, Message onComplete) {
- if(DBG) log("Network Despersonalization: " + pin);
- phone.mCM.supplyNetworkDepersonalization(pin,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public boolean getIccLockEnabled() {
- return mRuimPinLocked;
- }
-
- public boolean getIccFdnEnabled() {
- return mRuimFdnEnabled;
- }
-
- public void setIccLockEnabled (boolean enabled,
- String password, Message onComplete) {
- int serviceClassX;
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX;
-
- mDesiredPinLocked = enabled;
-
- phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,
- enabled, password, serviceClassX,
- obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
- }
-
- public void setIccFdnEnabled (boolean enabled,
- String password, Message onComplete) {
- int serviceClassX;
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX +
- CommandsInterface.SERVICE_CLASS_SMS;
-
- mDesiredFdnEnabled = enabled;
-
- phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD,
- enabled, password, serviceClassX,
- obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
+ mPhone.mCM.unregisterForRUIMLockedOrAbsent(mHandler);
+ mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
+ mPhone.mCM.unregisterForRUIMReady(mHandler);
}
- public void changeIccLockPassword(String oldPassword, String newPassword,
- Message onComplete) {
- if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
- phone.mCM.changeIccPin(oldPassword, newPassword,
- obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete));
- }
-
- public void changeIccFdnPassword(String oldPassword, String newPassword,
- Message onComplete) {
- if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
- phone.mCM.changeIccPin2(oldPassword, newPassword,
- obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete));
- }
-
- public String getServiceProviderName() {
- return phone.mRuimRecords.getServiceProviderName();
- }
-
- //***** Handler implementation
@Override
- public void handleMessage(Message msg){
- AsyncResult ar;
- int serviceClassX;
-
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX;
-
- switch (msg.what) {
- case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
- Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
- status = null;
- updateStateProperty();
- broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_NOT_READY, null);
- break;
- case EVENT_RUIM_READY:
- Log.d(LOG_TAG, "Event EVENT_RUIM_READY Received");
- //TODO: put facility read in SIM_READY now, maybe in REG_NW
- phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
- break;
- case EVENT_RUIM_LOCKED_OR_ABSENT:
- Log.d(LOG_TAG, "Event EVENT_RUIM_LOCKED_OR_ABSENT Received");
- phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
- break;
- case EVENT_GET_RUIM_STATUS_DONE:
- Log.d(LOG_TAG, "Event EVENT_GET_RUIM_STATUS_DONE Received");
- ar = (AsyncResult)msg.obj;
-
- getRuimStatusDone(ar);
- break;
- case EVENT_PINPUK_DONE:
- Log.d(LOG_TAG, "Event EVENT_PINPUK_DONE Received");
- // a PIN/PUK/PIN2/PUK2/Network Personalization
- // request has completed. ar.userObj is the response Message
- // Repoll before returning
- ar = (AsyncResult)msg.obj;
- // TODO should abstract these exceptions
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- phone.mCM.getIccStatus(
- obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
- break;
- case EVENT_REPOLL_STATUS_DONE:
- Log.d(LOG_TAG, "Event EVENT_REPOLL_STATUS_DONE Received");
- // Finished repolling status after PIN operation
- // ar.userObj is the response messaeg
- // ar.userObj.obj is already an AsyncResult with an
- // appropriate exception filled in if applicable
-
- ar = (AsyncResult)msg.obj;
- getRuimStatusDone(ar);
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_QUERY_FACILITY_LOCK_DONE:
- Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_LOCK_DONE Received");
- ar = (AsyncResult)msg.obj;
- onQueryFacilityLock(ar);
- break;
- case EVENT_QUERY_FACILITY_FDN_DONE:
- Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_FDN_DONE Received");
- ar = (AsyncResult)msg.obj;
- onQueryFdnEnabled(ar);
- break;
- case EVENT_CHANGE_FACILITY_LOCK_DONE:
- Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_LOCK_DONE Received");
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- mRuimPinLocked = mDesiredPinLocked;
- if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
- "mRuimPinLocked= " + mRuimPinLocked);
- } else {
- Log.e(LOG_TAG, "Error change facility lock with exception "
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_CHANGE_FACILITY_FDN_DONE:
- Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_FDN_DONE Received");
- ar = (AsyncResult)msg.obj;
-
- if (ar.exception == null) {
- mRuimFdnEnabled = mDesiredFdnEnabled;
- if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
- "mRuimFdnEnabled=" + mRuimFdnEnabled);
- } else {
- Log.e(LOG_TAG, "Error change facility fdn with exception "
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_CHANGE_RUIM_PASSWORD_DONE:
- Log.d(LOG_TAG, "Event EVENT_CHANGE_RUIM_PASSWORD_DONE Received");
- ar = (AsyncResult)msg.obj;
- if(ar.exception != null) {
- Log.e(LOG_TAG, "Error in change sim password with exception"
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- default:
- Log.e(LOG_TAG, "[CdmaRuimCard] Unknown Event " + msg.what);
- }
- }
-
- //***** Private methods
-
- /**
- * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
- * @param ar is asyncResult of Query_Facility_Locked
- */
- private void onQueryFacilityLock(AsyncResult ar) {
- if(ar.exception != null) {
- if (DBG) log("Error in querying facility lock:" + ar.exception);
- return;
- }
-
- int[] ints = (int[])ar.result;
- if(ints.length != 0) {
- mRuimPinLocked = (0!=ints[0]);
- if(DBG) log("Query facility lock : " + mRuimPinLocked);
- } else {
- Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response");
- }
- }
-
- /**
- * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
- * @param ar is asyncResult of Query_Facility_Locked
- */
- private void onQueryFdnEnabled(AsyncResult ar) {
- if(ar.exception != null) {
- if(DBG) log("Error in querying facility lock:" + ar.exception);
- return;
- }
-
- int[] ints = (int[])ar.result;
- if(ints.length != 0) {
- mRuimFdnEnabled = (0!=ints[0]);
- if(DBG) log("Query facility lock : " + mRuimFdnEnabled);
- } else {
- Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response");
- }
- }
-
- private void
- getRuimStatusDone(AsyncResult ar) {
- if (ar.exception != null) {
- Log.e(LOG_TAG,"Error getting SIM status. "
- + "RIL_REQUEST_GET_SIM_STATUS should "
- + "never return an error", ar.exception);
- return;
- }
-
- CommandsInterface.IccStatus newStatus
- = (CommandsInterface.IccStatus) ar.result;
-
- handleRuimStatus(newStatus);
- }
-
- private void
- handleRuimStatus(CommandsInterface.IccStatus newStatus) {
- boolean transitionedIntoPinLocked;
- boolean transitionedIntoAbsent;
- boolean transitionedIntoNetworkLocked;
-
- RuimCard.State oldState, newState;
-
- oldState = getState();
- status = newStatus;
- newState = getState();
-
- updateStateProperty();
-
- transitionedIntoPinLocked = (
- (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED)
- || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED));
- transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
- transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
- && newState == State.NETWORK_LOCKED);
-
- if (transitionedIntoPinLocked) {
- if(DBG) log("Notify RUIM pin or puk locked.");
- pinLockedRegistrants.notifyRegistrants();
- broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED,
- (newState == State.PIN_REQUIRED) ?
- INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
- } else if (transitionedIntoAbsent) {
- if(DBG) log("Notify RUIM missing.");
- absentRegistrants.notifyRegistrants();
- broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_ABSENT, null);
- } else if (transitionedIntoNetworkLocked) {
- if(DBG) log("Notify RUIM network locked.");
- networkLockedRegistrants.notifyRegistrants();
- broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED,
- INTENT_VALUE_LOCKED_NETWORK);
- }
- }
-
- public void broadcastRuimStateChangedIntent(String value, String reason) {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName());
- intent.putExtra(RuimCard.INTENT_KEY_ICC_STATE, value);
- intent.putExtra(RuimCard.INTENT_KEY_LOCKED_REASON, reason);
- if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value
- + " reason " + reason);
- ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE);
- }
-
- public void updateImsiConfiguration(String imsi) {
- if (imsi.length() >= 6) {
- Configuration config = new Configuration();
- config.mcc = ((imsi.charAt(0)-'0')*100)
- + ((imsi.charAt(1)-'0')*10)
- + (imsi.charAt(2)-'0');
- config.mnc = ((imsi.charAt(3)-'0')*100)
- + ((imsi.charAt(4)-'0')*10)
- + (imsi.charAt(5)-'0');
- try {
- ActivityManagerNative.getDefault().updateConfiguration(config);
- } catch (RemoteException e) {
- }
- }
- }
-
- private void
- updateStateProperty() {
- phone.setSystemProperty(
- TelephonyProperties.PROPERTY_SIM_STATE,
- getState().toString());
- }
-
- private void log(String msg) {
- Log.d(LOG_TAG, "[RuimCard] " + msg);
+ public String getServiceProviderName () {
+ return ((CDMAPhone)mPhone).mRuimRecords.getServiceProviderName();
}
-}
+ }
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 55f48b1..7c74314 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -37,10 +37,6 @@ import com.android.internal.telephony.IccRecords;
import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.PhoneProxy;
-import com.android.internal.telephony.TelephonyIntents;
-import android.app.ActivityManagerNative;
-import android.content.Intent;
-
/**
* {@hide}
@@ -65,7 +61,6 @@ public final class RuimRecords extends IccRecords {
private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4;
private static final int EVENT_GET_ICCID_DONE = 5;
- private static final int EVENT_NV_READY = 9;
private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10;
private static final int EVENT_UPDATE_DONE = 14;
private static final int EVENT_GET_SST_DONE = 17;
@@ -76,7 +71,7 @@ public final class RuimRecords extends IccRecords {
private static final int EVENT_GET_SMS_DONE = 22;
private static final int EVENT_RUIM_REFRESH = 31;
- private static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 32;
+
RuimRecords(CDMAPhone p) {
super(p);
@@ -90,14 +85,12 @@ public final class RuimRecords extends IccRecords {
p.mCM.registerForRUIMReady(this, EVENT_RUIM_READY, null);
- p.mCM.registerForNVReady(this, EVENT_NV_READY, null);
p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
// NOTE the EVENT_SMS_ON_RUIM is not registered
p.mCM.setOnIccRefresh(this, EVENT_RUIM_REFRESH, null);
// Start off by setting empty state
onRadioOffOrNotAvailable();
- p.mCM.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null);
}
@@ -106,8 +99,6 @@ public final class RuimRecords extends IccRecords {
phone.mCM.unregisterForRUIMReady(this);
phone.mCM.unregisterForOffOrNotAvailable( this);
phone.mCM.unSetOnIccRefresh(this);
- phone.mCM.unregisterForNVReady(this);
- phone.mCM.unregisterForCdmaOtaProvision(this);
}
@Override
@@ -202,9 +193,7 @@ public final class RuimRecords extends IccRecords {
case EVENT_RUIM_READY:
onRuimReady();
break;
- case EVENT_NV_READY:
- onNvReady();
- break;
+
case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
onRadioOffOrNotAvailable();
break;
@@ -221,15 +210,7 @@ public final class RuimRecords extends IccRecords {
if (ar.exception != null) {
break;
}
- if (m_ota_commited) {
- if (mMyMobileNumber != localTemp[0]) {
- Intent intent = new Intent(TelephonyIntents.ACTION_CDMA_OTA_MDN_CHANGED);
- intent.putExtra("mdn", localTemp[0]);
- Log.d(LOG_TAG,"Broadcasting intent MDN Change in OTA ");
- ActivityManagerNative.broadcastStickyIntent(intent, null);
- }
- m_ota_commited = false;
- }
+
mMyMobileNumber = localTemp[0];
mMin2Min1 = localTemp[3];
mPrlVersion = localTemp[4];
@@ -281,21 +262,6 @@ public final class RuimRecords extends IccRecords {
}
break;
- case EVENT_OTA_PROVISION_STATUS_CHANGE:
- m_ota_commited=false;
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- int[] ints = (int[]) ar.result;
- int otaStatus = ints[0];
- if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_COMMITTED) {
- m_ota_commited=true;
- phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
- } else if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) {
- phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
- }
- }
- break;
-
}}catch (RuntimeException exc) {
// I don't want these exceptions to be fatal
Log.w(LOG_TAG, "Exception parsing RUIM record", exc);
@@ -329,7 +295,7 @@ public final class RuimRecords extends IccRecords {
recordsLoadedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
- ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent(
+ ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent(
RuimCard.INTENT_VALUE_ICC_LOADED, null);
}
@@ -338,7 +304,7 @@ public final class RuimRecords extends IccRecords {
READY is sent before IMSI ready
*/
- ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent(
+ ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent(
RuimCard.INTENT_VALUE_ICC_READY, null);
fetchRuimRecords();
@@ -347,10 +313,6 @@ public final class RuimRecords extends IccRecords {
}
- private void onNvReady() {
- phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
-
- }
private void fetchRuimRecords() {
recordsRequested = true;
diff --git a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
index 44958e9..4b88057 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java
@@ -35,7 +35,12 @@ public class SignalToneUtil {
static public final int IS95_CONST_IR_ALERT_MED = 0;
static public final int IS95_CONST_IR_ALERT_HIGH = 1;
static public final int IS95_CONST_IR_ALERT_LOW = 2;
- static public final int TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN = 255;
+
+ // Based on 3GPP2 C.S0005-E, seciton 3.7.5.5 Signal,
+ // set TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN to 0 to avoid
+ // the alert pitch to be involved in hash calculation for
+ // signal type other than IS54B.
+ static public final int TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN = 0;
// public final int int IS95_CONST_IR_SIGNAL_TYPE;
static public final int IS95_CONST_IR_SIG_ISDN_NORMAL = 0;
@@ -81,6 +86,15 @@ public class SignalToneUtil {
(alertPitch < 0) || (signal > 256) || (signal < 0)) {
return new Integer(CDMA_INVALID_TONE);
}
+ // Based on 3GPP2 C.S0005-E, seciton 3.7.5.5 Signal,
+ // the alert pitch field is ignored by the mobile station unless
+ // SIGNAL_TYPE is '10',IS-54B Alerting.
+ // Set alert pitch to TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN
+ // so the alert pitch is not involved in hash calculation
+ // when signal type is not IS-54B.
+ if (signalType != IS95_CONST_IR_SIGNAL_IS54B) {
+ alertPitch = TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN;
+ }
return new Integer(signalType * 256 * 256 + alertPitch * 256 + signal);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 3a92064..1597427 100644..100755
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -29,6 +29,7 @@ import com.android.internal.telephony.cdma.sms.BearerData;
import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.util.HexDump;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -67,6 +68,7 @@ import static android.telephony.SmsMessage.MessageClass;
*/
public class SmsMessage extends SmsMessageBase {
static final String LOG_TAG = "CDMA";
+ private final static Boolean DBG_SMS = false;
/**
* Status of a previously submitted SMS.
@@ -518,6 +520,7 @@ public class SmsMessage extends SmsMessageBase {
originatingAddress = addr;
env.origAddress = addr;
mEnvelope = env;
+ mPdu = pdu;
parseSms();
}
@@ -526,7 +529,25 @@ public class SmsMessage extends SmsMessageBase {
* Parses a SMS message from its BearerData stream. (mobile-terminated only)
*/
protected void parseSms() {
+ // Message Waiting Info Record defined in 3GPP2 C.S-0005, 3.7.5.6
+ // It contains only an 8-bit number with the number of messages waiting
+ if (mEnvelope.teleService == SmsEnvelope.TELESERVICE_MWI) {
+ mBearerData = new BearerData();
+ if (mEnvelope.bearerData != null) {
+ mBearerData.numberOfMessages = 0x000000FF & mEnvelope.bearerData[0];
+ }
+ if (Config.DEBUG) {
+ Log.d(LOG_TAG, "parseSms: get MWI " +
+ Integer.toString(mBearerData.numberOfMessages));
+ }
+ return;
+ }
mBearerData = BearerData.decode(mEnvelope.bearerData);
+ if (DBG_SMS) {
+ Log.d(LOG_TAG, "MT raw BearerData = '" +
+ HexDump.toHexString(mEnvelope.bearerData) + "'");
+ Log.d(LOG_TAG, "MT (decoded) BearerData = " + mBearerData);
+ }
messageRef = mBearerData.messageId;
if (mBearerData.userData != null) {
userData = mBearerData.userData.payload;
@@ -583,23 +604,6 @@ public class SmsMessage extends SmsMessageBase {
}
}
- private static CdmaSmsAddress parseCdmaSmsAddr(String addrStr) {
- // see C.S0015-B, v2.0, 3.4.3.3
- CdmaSmsAddress addr = new CdmaSmsAddress();
- addr.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR;
- try {
- addr.origBytes = addrStr.getBytes("UTF-8");
- } catch (java.io.UnsupportedEncodingException ex) {
- Log.e(LOG_TAG, "CDMA address parsing failed: " + ex);
- return null;
- }
- addr.numberOfDigits = (byte)addr.origBytes.length;
- addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK;
- addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY;
- addr.ton = CdmaSmsAddress.TON_INTERNATIONAL_OR_IP;
- return addr;
- }
-
/**
* Set the nextMessageId to a random value between 0 and 65536
* See C.S0015-B, v2.0, 4.3.1.5
@@ -626,7 +630,13 @@ public class SmsMessage extends SmsMessageBase {
* TODO(cleanup): give this function a more meaningful name.
*/
- CdmaSmsAddress destAddr = parseCdmaSmsAddr(destAddrStr);
+ /**
+ * TODO(cleanup): Make returning null from the getSubmitPdu
+ * variations meaningful -- clean up the error feedback
+ * mechanism, and avoid null pointer exceptions.
+ */
+
+ CdmaSmsAddress destAddr = CdmaSmsAddress.parse(destAddrStr);
if (destAddr == null) return null;
BearerData bearerData = new BearerData();
@@ -641,14 +651,17 @@ public class SmsMessage extends SmsMessageBase {
bearerData.reportReq = false;
bearerData.userData = userData;
- bearerData.hasUserDataHeader = (userData.userDataHeader != null);
-
- int teleservice = bearerData.hasUserDataHeader ?
- SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
byte[] encodedBearerData = BearerData.encode(bearerData);
+ if (DBG_SMS) {
+ Log.d(LOG_TAG, "MO (encoded) BearerData = " + bearerData);
+ Log.d(LOG_TAG, "MO raw BearerData = '" + HexDump.toHexString(encodedBearerData) + "'");
+ }
if (encodedBearerData == null) return null;
+ int teleservice = bearerData.hasUserDataHeader ?
+ SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
+
SmsEnvelope envelope = new SmsEnvelope();
envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
envelope.teleService = teleservice;
@@ -728,9 +741,8 @@ public class SmsMessage extends SmsMessageBase {
dos.close();
/**
- * TODO(cleanup) -- This is the only place where mPdu is
- * defined, and this is not obviously the only place where
- * it needs to be defined. It would be much nicer if
+ * TODO(cleanup) -- The mPdu field is managed in
+ * a fragile manner, and it would be much nicer if
* accessing the serialized representation used a less
* fragile mechanism. Maybe the getPdu method could
* generate a representation if there was not yet one?
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index ef3afff..721729d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -233,22 +233,22 @@ public final class BearerData {
public static TimeStamp fromByteArray(byte[] data) {
TimeStamp ts = new TimeStamp();
// C.S0015-B v2.0, 4.5.4: range is 1996-2095
- int year = IccUtils.beBcdByteToInt(data[0]);
+ int year = IccUtils.cdmaBcdByteToInt(data[0]);
if (year > 99 || year < 0) return null;
ts.year = year >= 96 ? year + 1900 : year + 2000;
- int month = IccUtils.beBcdByteToInt(data[1]);
+ int month = IccUtils.cdmaBcdByteToInt(data[1]);
if (month < 1 || month > 12) return null;
ts.month = month - 1;
- int day = IccUtils.beBcdByteToInt(data[2]);
+ int day = IccUtils.cdmaBcdByteToInt(data[2]);
if (day < 1 || day > 31) return null;
ts.monthDay = day;
- int hour = IccUtils.beBcdByteToInt(data[3]);
+ int hour = IccUtils.cdmaBcdByteToInt(data[3]);
if (hour < 0 || hour > 23) return null;
ts.hour = hour;
- int minute = IccUtils.beBcdByteToInt(data[4]);
+ int minute = IccUtils.cdmaBcdByteToInt(data[4]);
if (minute < 0 || minute > 59) return null;
ts.minute = minute;
- int second = IccUtils.beBcdByteToInt(data[5]);
+ int second = IccUtils.cdmaBcdByteToInt(data[5]);
if (second < 0 || second > 59) return null;
ts.second = second;
return ts;
@@ -455,53 +455,117 @@ public final class BearerData {
}
}
- private static int calcUdhSeptetPadding(int userDataHeaderLen) {
- int udhBits = userDataHeaderLen * 8;
- int udhSeptets = (udhBits + 6) / 7;
- int paddingBits = (udhSeptets * 7) - udhBits;
- return paddingBits;
+ private static class Gsm7bitCodingResult {
+ int septets;
+ byte[] data;
}
- private static byte[] encode7bitGsm(String msg, int paddingBits)
+ private static Gsm7bitCodingResult encode7bitGsm(String msg, int septetOffset, boolean force)
throws CodingException
{
try {
/*
* TODO(cleanup): It would be nice if GsmAlphabet provided
* an option to produce just the data without prepending
- * the length.
+ * the septet count, as this function is really just a
+ * wrapper to strip that off. Not to mention that the
+ * septet count is generally known prior to invocation of
+ * the encoder. Note that it cannot be derived from the
+ * resulting array length, since that cannot distinguish
+ * if the last contains either 1 or 8 valid bits.
+ *
+ * TODO(cleanup): The BitwiseXStreams could also be
+ * extended with byte-wise reversed endianness read/write
+ * routines to allow a corresponding implementation of
+ * stringToGsm7BitPacked, and potentially directly support
+ * access to the main bitwise stream from encode/decode.
*/
- byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg, 0, -1, paddingBits, true);
- byte []data = new byte[fullData.length - 1];
- System.arraycopy(fullData, 1, data, 0, fullData.length - 1);
- return data;
+ byte[] fullData = GsmAlphabet.stringToGsm7BitPacked(msg, septetOffset, !force);
+ Gsm7bitCodingResult result = new Gsm7bitCodingResult();
+ result.data = new byte[fullData.length - 1];
+ System.arraycopy(fullData, 1, result.data, 0, fullData.length - 1);
+ result.septets = fullData[0] & 0x00FF;
+ return result;
} catch (com.android.internal.telephony.EncodeException ex) {
throw new CodingException("7bit GSM encode failed: " + ex);
}
}
+ private static void encode7bitEms(UserData uData, byte[] udhData, boolean force)
+ throws CodingException
+ {
+ int udhBytes = udhData.length + 1; // Add length octet.
+ int udhSeptets = ((udhBytes * 8) + 6) / 7;
+ Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, udhSeptets, force);
+ uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
+ uData.msgEncodingSet = true;
+ uData.numFields = gcr.septets;
+ uData.payload = gcr.data;
+ uData.payload[0] = (byte)udhData.length;
+ System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
+ }
+
+ private static void encode16bitEms(UserData uData, byte[] udhData)
+ throws CodingException
+ {
+ byte[] payload = encodeUtf16(uData.payloadStr);
+ int udhBytes = udhData.length + 1; // Add length octet.
+ int udhCodeUnits = (udhBytes + 1) / 2;
+ int udhPadding = udhBytes % 2;
+ int payloadCodeUnits = payload.length / 2;
+ uData.msgEncoding = UserData.ENCODING_UNICODE_16;
+ uData.msgEncodingSet = true;
+ uData.numFields = udhCodeUnits + payloadCodeUnits;
+ uData.payload = new byte[uData.numFields * 2];
+ uData.payload[0] = (byte)udhData.length;
+ System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
+ System.arraycopy(payload, 0, uData.payload, udhBytes + udhPadding, payload.length);
+ }
+
+ private static void encodeEmsUserDataPayload(UserData uData)
+ throws CodingException
+ {
+ byte[] headerData = SmsHeader.toByteArray(uData.userDataHeader);
+ if (uData.msgEncodingSet) {
+ if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
+ encode7bitEms(uData, headerData, true);
+ } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
+ encode16bitEms(uData, headerData);
+ } else {
+ throw new CodingException("unsupported EMS user data encoding (" +
+ uData.msgEncoding + ")");
+ }
+ } else {
+ try {
+ encode7bitEms(uData, headerData, false);
+ } catch (CodingException ex) {
+ encode16bitEms(uData, headerData);
+ }
+ }
+ }
+
private static void encodeUserDataPayload(UserData uData)
throws CodingException
{
- // TODO(cleanup): UDH can only occur in EMS mode, meaning
- // encapsulation of GSM encoding, and so the logic here should
- // be refactored to more cleanly reflect this constraint.
+ if ((uData.payloadStr == null) && (uData.msgEncoding != UserData.ENCODING_OCTET)) {
+ Log.e(LOG_TAG, "user data with null payloadStr");
+ uData.payloadStr = "";
+ }
- byte[] headerData = null;
- if (uData.userDataHeader != null) headerData = SmsHeader.toByteArray(uData.userDataHeader);
- int headerDataLen = (headerData == null) ? 0 : headerData.length + 1; // + length octet
+ if (uData.userDataHeader != null) {
+ encodeEmsUserDataPayload(uData);
+ return;
+ }
- byte[] payloadData;
- int codeUnitCount;
if (uData.msgEncodingSet) {
if (uData.msgEncoding == UserData.ENCODING_OCTET) {
if (uData.payload == null) {
Log.e(LOG_TAG, "user data with octet encoding but null payload");
- payloadData = new byte[0];
- codeUnitCount = 0;
+ uData.payload = new byte[0];
+ uData.numFields = 0;
} else {
- payloadData = uData.payload;
- codeUnitCount = uData.payload.length;
+ uData.payload = uData.payload;
+ uData.numFields = uData.payload.length;
}
} else {
if (uData.payloadStr == null) {
@@ -509,67 +573,52 @@ public final class BearerData {
uData.payloadStr = "";
}
if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
- int paddingBits = calcUdhSeptetPadding(headerDataLen);
- payloadData = encode7bitGsm(uData.payloadStr, paddingBits);
- codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7;
+ Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, 0, true);
+ uData.payload = gcr.data;
+ uData.numFields = gcr.septets;
} else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
- payloadData = encode7bitAscii(uData.payloadStr, true);
- codeUnitCount = uData.payloadStr.length();
+ uData.payload = encode7bitAscii(uData.payloadStr, true);
+ uData.numFields = uData.payloadStr.length();
} else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
- payloadData = encodeUtf16(uData.payloadStr);
- codeUnitCount = uData.payloadStr.length();
+ uData.payload = encodeUtf16(uData.payloadStr);
+ uData.numFields = uData.payloadStr.length();
} else {
throw new CodingException("unsupported user data encoding (" +
uData.msgEncoding + ")");
}
}
} else {
- if (uData.payloadStr == null) {
- Log.e(LOG_TAG, "user data with null payloadStr");
- uData.payloadStr = "";
- }
try {
- if (headerData == null) {
- payloadData = encode7bitAscii(uData.payloadStr, false);
- codeUnitCount = uData.payloadStr.length();
- uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
- } else {
- // If there is a header, we are in EMS mode, in
- // which case we use GSM encodings.
- int paddingBits = calcUdhSeptetPadding(headerDataLen);
- payloadData = encode7bitGsm(uData.payloadStr, paddingBits);
- codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7;
- uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
- }
+ uData.payload = encode7bitAscii(uData.payloadStr, false);
+ uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
} catch (CodingException ex) {
- payloadData = encodeUtf16(uData.payloadStr);
- codeUnitCount = uData.payloadStr.length();
+ uData.payload = encodeUtf16(uData.payloadStr);
uData.msgEncoding = UserData.ENCODING_UNICODE_16;
}
+ uData.numFields = uData.payloadStr.length();
uData.msgEncodingSet = true;
}
-
- int totalLength = payloadData.length + headerDataLen;
- if (totalLength > SmsMessage.MAX_USER_DATA_BYTES) {
- throw new CodingException("encoded user data too large (" + totalLength +
- " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)");
- }
-
- uData.numFields = codeUnitCount;
- uData.payload = new byte[totalLength];
- if (headerData != null) {
- uData.payload[0] = (byte)headerData.length;
- System.arraycopy(headerData, 0, uData.payload, 1, headerData.length);
- }
- System.arraycopy(payloadData, 0, uData.payload, headerDataLen, payloadData.length);
}
private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream)
throws BitwiseOutputStream.AccessException, CodingException
{
+ /*
+ * TODO(cleanup): Do we really need to set userData.payload as
+ * a side effect of encoding? If not, we could avoid data
+ * copies by passing outStream directly.
+ */
encodeUserDataPayload(bData.userData);
- /**
- * XXX/TODO: figure out what the right answer is WRT padding bits
+ bData.hasUserDataHeader = bData.userData.userDataHeader != null;
+
+ if (bData.userData.payload.length > SmsMessage.MAX_USER_DATA_BYTES) {
+ throw new CodingException("encoded user data too large (" +
+ bData.userData.payload.length +
+ " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)");
+ }
+
+ /*
+ * TODO(cleanup): figure out what the right answer is WRT paddingBits field
*
* userData.paddingBits = (userData.payload.length * 8) - (userData.numFields * 7);
* userData.paddingBits = 0; // XXX this seems better, but why?
@@ -624,6 +673,12 @@ public final class BearerData {
return rawData;
}
+ /*
+ * TODO(cleanup): CdmaSmsAddress encoding should make use of
+ * CdmaSmsAddress.parse provided that DTMF encoding is unified,
+ * and the difference in 4bit vs 8bit is resolved.
+ */
+
private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException {
if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
try {
@@ -792,23 +847,34 @@ public final class BearerData {
return null;
}
- private static void decodeMessageId(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMessageId(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 3) {
- throw new CodingException("MESSAGE_IDENTIFIER subparam size incorrect");
- }
- bData.messageType = inStream.read(4);
- bData.messageId = inStream.read(8) << 8;
- bData.messageId |= inStream.read(8);
- bData.hasUserDataHeader = (inStream.read(1) == 1);
- inStream.skip(3);
+ final int EXPECTED_PARAM_SIZE = 3 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.messageType = inStream.read(4);
+ bData.messageId = inStream.read(8) << 8;
+ bData.messageId |= inStream.read(8);
+ bData.hasUserDataHeader = (inStream.read(1) == 1);
+ inStream.skip(3);
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeUserData(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeUserData(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException
{
- int paramBytes = inStream.read(8);
+ int paramBits = inStream.read(8) * 8;
bData.userData = new UserData();
bData.userData.msgEncoding = inStream.read(5);
bData.userData.msgEncodingSet = true;
@@ -821,13 +887,17 @@ public final class BearerData {
}
bData.userData.numFields = inStream.read(8);
consumedBits += 8;
- int dataBits = (paramBytes * 8) - consumedBits;
+ int dataBits = paramBits - consumedBits;
bData.userData.payload = inStream.readByteArray(dataBits);
+ return true;
}
private static String decodeUtf16(byte[] data, int offset, int numFields)
throws CodingException
{
+ // Start reading from the next 16-bit aligned boundry after offset.
+ int padding = offset % 2;
+ numFields -= (offset + padding) / 2;
try {
return new String(data, offset, numFields * 2, "utf-16be");
} catch (java.io.UnsupportedEncodingException ex) {
@@ -835,7 +905,7 @@ public final class BearerData {
}
}
- private static String decodeIa5(byte[] data, int offset, int numFields)
+ private static String decode7bitAscii(byte[] data, int offset, int numFields)
throws CodingException
{
try {
@@ -850,38 +920,20 @@ public final class BearerData {
inStream.skip(offset);
for (int i = 0; i < numFields; i++) {
int charCode = inStream.read(7);
- if ((charCode < UserData.IA5_MAP_BASE_INDEX) ||
- (charCode > UserData.IA5_MAP_MAX_INDEX)) {
- throw new CodingException("unsupported AI5 character code (" + charCode + ")");
+ if ((charCode >= UserData.ASCII_MAP_BASE_INDEX) &&
+ (charCode <= UserData.ASCII_MAP_MAX_INDEX)) {
+ strBuf.append(UserData.ASCII_MAP[charCode - UserData.ASCII_MAP_BASE_INDEX]);
+ } else if (charCode == UserData.ASCII_NL_INDEX) {
+ strBuf.append('\n');
+ } else if (charCode == UserData.ASCII_CR_INDEX) {
+ strBuf.append('\r');
+ } else {
+ /* For other charCodes, they are unprintable, and so simply use SPACE. */
+ strBuf.append(' ');
}
- strBuf.append(UserData.IA5_MAP[charCode - UserData.IA5_MAP_BASE_INDEX]);
}
return strBuf.toString();
} catch (BitwiseInputStream.AccessException ex) {
- throw new CodingException("AI5 decode failed: " + ex);
- }
- }
-
- private static String decode7bitAscii(byte[] data, int offset, int numFields)
- throws CodingException
- {
- try {
- offset *= 8;
- BitwiseInputStream inStream = new BitwiseInputStream(data);
- int wantedBits = offset + (numFields * 7);
- if (inStream.available() < wantedBits) {
- throw new CodingException("insufficient data (wanted " + wantedBits +
- " bits, but only have " + inStream.available() + ")");
- }
- inStream.skip(offset);
- byte[] expandedData = new byte[numFields];
- for (int i = 0; i < numFields; i++) {
- expandedData[i] = (byte)inStream.read(7);
- }
- return new String(expandedData, 0, numFields, "US-ASCII");
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("7bit ASCII decode failed: " + ex);
- } catch (BitwiseInputStream.AccessException ex) {
throw new CodingException("7bit ASCII decode failed: " + ex);
}
}
@@ -889,11 +941,11 @@ public final class BearerData {
private static String decode7bitGsm(byte[] data, int offset, int numFields)
throws CodingException
{
- int paddingBits = calcUdhSeptetPadding(offset);
- numFields -= (((offset * 8) + paddingBits) / 7);
- // TODO: It seems wrong that only Gsm7 bit encodings would
- // take into account the header in numFields calculations.
- // This should be verified.
+ // Start reading from the next 7-bit aligned boundry after offset.
+ int offsetBits = offset * 8;
+ int offsetSeptets = (offsetBits + 6) / 7;
+ numFields -= offsetSeptets;
+ int paddingBits = (offsetSeptets * 7) - offsetBits;
String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields, paddingBits);
if (result == null) {
throw new CodingException("7bit GSM decoding failed");
@@ -901,6 +953,16 @@ public final class BearerData {
return result;
}
+ private static String decodeLatin(byte[] data, int offset, int numFields)
+ throws CodingException
+ {
+ try {
+ return new String(data, offset, numFields - offset, "ISO-8859-1");
+ } catch (java.io.UnsupportedEncodingException ex) {
+ throw new CodingException("ISO-8859-1 decode failed: " + ex);
+ }
+ }
+
private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader)
throws CodingException
{
@@ -914,19 +976,33 @@ public final class BearerData {
}
switch (userData.msgEncoding) {
case UserData.ENCODING_OCTET:
+ // Strip off any padding bytes, meaning any differences between the length of the
+ // array and the target length specified by numFields. This is to avoid any confusion
+ // by code elsewhere that only considers the payload array length.
+ byte[] payload = new byte[userData.numFields];
+ int copyLen = userData.numFields < userData.payload.length
+ ? userData.numFields : userData.payload.length;
+
+ System.arraycopy(userData.payload, 0, payload, 0, copyLen);
+ userData.payload = payload;
+
+ // There are many devices in the market that send 8bit text sms (latin encoded) as
+ // octet encoded.
+ userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
break;
+ case UserData.ENCODING_IA5:
case UserData.ENCODING_7BIT_ASCII:
userData.payloadStr = decode7bitAscii(userData.payload, offset, userData.numFields);
break;
- case UserData.ENCODING_IA5:
- userData.payloadStr = decodeIa5(userData.payload, offset, userData.numFields);
- break;
case UserData.ENCODING_UNICODE_16:
userData.payloadStr = decodeUtf16(userData.payload, offset, userData.numFields);
break;
case UserData.ENCODING_GSM_7BIT_ALPHABET:
userData.payloadStr = decode7bitGsm(userData.payload, offset, userData.numFields);
break;
+ case UserData.ENCODING_LATIN:
+ userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
+ break;
default:
throw new CodingException("unsupported user data encoding ("
+ userData.msgEncoding + ")");
@@ -959,7 +1035,7 @@ public final class BearerData {
try {
StringBuffer strbuf = new StringBuffer(dataLen);
while (inStream.available() >= 6) {
- strbuf.append(UserData.IA5_MAP[inStream.read(6)]);
+ strbuf.append(UserData.ASCII_MAP[inStream.read(6)]);
}
String data = strbuf.toString();
bData.numberOfMessages = Integer.parseInt(data.substring(0, 2));
@@ -1001,7 +1077,7 @@ public final class BearerData {
}
StringBuffer strbuf = new StringBuffer(dataLen);
for (int i = 0; i < numFields; i++) {
- strbuf.append(UserData.IA5_MAP[inStream.read(6)]);
+ strbuf.append(UserData.ASCII_MAP[inStream.read(6)]);
}
bData.userData.payloadStr = strbuf.toString();
}
@@ -1049,36 +1125,68 @@ public final class BearerData {
}
}
- private static void decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- int paramBytes = inStream.read(8);
- if (paramBytes != 1) {
- throw new CodingException("REPLY_OPTION subparam size incorrect");
- }
- bData.userAckReq = (inStream.read(1) == 1);
- bData.deliveryAckReq = (inStream.read(1) == 1);
- bData.readAckReq = (inStream.read(1) == 1);
- bData.reportReq = (inStream.read(1) == 1);
- inStream.skip(4);
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.userAckReq = (inStream.read(1) == 1);
+ bData.deliveryAckReq = (inStream.read(1) == 1);
+ bData.readAckReq = (inStream.read(1) == 1);
+ bData.reportReq = (inStream.read(1) == 1);
+ inStream.skip(4);
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "REPLY_OPTION decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeMsgCount(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgCount(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("NUMBER_OF_MESSAGES subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.numberOfMessages = IccUtils.cdmaBcdByteToInt((byte)inStream.read(8));
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
}
- bData.numberOfMessages = inStream.read(8);
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeDepositIndex(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDepositIndex(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 2) {
- throw new CodingException("MESSAGE_DEPOSIT_INDEX subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 2 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
}
- bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
private static String decodeDtmfSmsAddress(byte[] rawData, int numFields)
@@ -1112,10 +1220,10 @@ public final class BearerData {
}
}
- private static void decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- int paramBytes = inStream.read(8);
+ int paramBits = inStream.read(8) * 8;
CdmaSmsAddress addr = new CdmaSmsAddress();
addr.digitMode = inStream.read(1);
byte fieldBits = 4;
@@ -1128,140 +1236,274 @@ public final class BearerData {
}
addr.numberOfDigits = inStream.read(8);
consumedBits += 8;
- int remainingBits = (paramBytes * 8) - consumedBits;
+ int remainingBits = paramBits - consumedBits;
int dataBits = addr.numberOfDigits * fieldBits;
int paddingBits = remainingBits - dataBits;
if (remainingBits < dataBits) {
throw new CodingException("CALLBACK_NUMBER subparam encoding size error (" +
- "remainingBits " + remainingBits + ", dataBits " +
- dataBits + ", paddingBits " + paddingBits + ")");
+ "remainingBits + " + remainingBits + ", dataBits + " +
+ dataBits + ", paddingBits + " + paddingBits + ")");
}
addr.origBytes = inStream.readByteArray(dataBits);
inStream.skip(paddingBits);
decodeSmsAddress(addr);
bData.callbackNumber = addr;
+ return true;
}
- private static void decodeMsgStatus(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgStatus(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("MESSAGE_STATUS subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.errorClass = inStream.read(2);
+ bData.messageStatus = inStream.read(6);
}
- bData.errorClass = inStream.read(2);
- bData.messageStatus = inStream.read(6);
- bData.messageStatusSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_STATUS decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.messageStatusSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 6) {
- throw new CodingException("MESSAGE_CENTER_TIME_STAMP subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 6 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
}
- bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeValidityAbs(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeValidityAbs(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 6) {
- throw new CodingException("VALIDITY_PERIOD_ABSOLUTE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 6 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
}
- bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 6) {
- throw new CodingException("DEFERRED_DELIVERY_TIME_ABSOLUTE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 6 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(
+ inStream.readByteArray(6 * 8));
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
}
- bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
+ inStream.skip(paramBits);
+ return decodeSuccess;
}
- private static void decodeValidityRel(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeValidityRel(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("VALIDITY_PERIOD_RELATIVE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.deferredDeliveryTimeRelative = inStream.read(8);
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
}
- bData.deferredDeliveryTimeRelative = inStream.read(8);
- bData.deferredDeliveryTimeRelativeSet = true;
+ inStream.skip(paramBits);
+ bData.deferredDeliveryTimeRelativeSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("DEFERRED_DELIVERY_TIME_RELATIVE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.validityPeriodRelative = inStream.read(8);
}
- bData.validityPeriodRelative = inStream.read(8);
- bData.validityPeriodRelativeSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.validityPeriodRelativeSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("PRIVACY_INDICATOR subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.privacy = inStream.read(2);
+ inStream.skip(6);
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "PRIVACY_INDICATOR decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
}
- bData.privacy = inStream.read(2);
- inStream.skip(6);
- bData.privacyIndicatorSet = true;
+ inStream.skip(paramBits);
+ bData.privacyIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("LANGUAGE_INDICATOR subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.language = inStream.read(8);
}
- bData.language = inStream.read(8);
- bData.languageIndicatorSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "LANGUAGE_INDICATOR decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.languageIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeDisplayMode(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeDisplayMode(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("DISPLAY_MODE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.displayMode = inStream.read(2);
+ inStream.skip(6);
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "DISPLAY_MODE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
}
- bData.displayMode = inStream.read(2);
- inStream.skip(6);
- bData.displayModeSet = true;
+ inStream.skip(paramBits);
+ bData.displayModeSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("PRIORITY_INDICATOR subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.priority = inStream.read(2);
+ inStream.skip(6);
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "PRIORITY_INDICATOR decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
}
- bData.priority = inStream.read(2);
- inStream.skip(6);
- bData.priorityIndicatorSet = true;
+ inStream.skip(paramBits);
+ bData.priorityIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("ALERT_ON_MESSAGE_DELIVERY subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.alert = inStream.read(2);
+ inStream.skip(6);
}
- bData.alert = inStream.read(2);
- inStream.skip(6);
- bData.alertIndicatorSet = true;
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
+ }
+ inStream.skip(paramBits);
+ bData.alertIndicatorSet = decodeSuccess;
+ return decodeSuccess;
}
- private static void decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream)
+ private static boolean decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream)
throws BitwiseInputStream.AccessException, CodingException
{
- if (inStream.read(8) != 1) {
- throw new CodingException("USER_REPONSE_CODE subparam size incorrect");
+ final int EXPECTED_PARAM_SIZE = 1 * 8;
+ boolean decodeSuccess = false;
+ int paramBits = inStream.read(8) * 8;
+ if (paramBits >= EXPECTED_PARAM_SIZE) {
+ paramBits -= EXPECTED_PARAM_SIZE;
+ decodeSuccess = true;
+ bData.userResponseCode = inStream.read(8);
+ }
+ if ((! decodeSuccess) || (paramBits > 0)) {
+ Log.d(LOG_TAG, "USER_REPONSE_CODE decode " +
+ (decodeSuccess ? "succeeded" : "failed") +
+ " (extra bits = " + paramBits + ")");
}
- bData.userResponseCode = inStream.read(8);
- bData.userResponseCodeSet = true;
+ inStream.skip(paramBits);
+ bData.userResponseCodeSet = decodeSuccess;
+ return decodeSuccess;
}
/**
@@ -1278,72 +1520,73 @@ public final class BearerData {
BearerData bData = new BearerData();
int foundSubparamMask = 0;
while (inStream.available() > 0) {
+ boolean decodeSuccess = false;
int subparamId = inStream.read(8);
int subparamIdBit = 1 << subparamId;
if ((foundSubparamMask & subparamIdBit) != 0) {
throw new CodingException("illegal duplicate subparameter (" +
subparamId + ")");
}
- foundSubparamMask |= subparamIdBit;
switch (subparamId) {
case SUBPARAM_MESSAGE_IDENTIFIER:
- decodeMessageId(bData, inStream);
+ decodeSuccess = decodeMessageId(bData, inStream);
break;
case SUBPARAM_USER_DATA:
- decodeUserData(bData, inStream);
+ decodeSuccess = decodeUserData(bData, inStream);
break;
case SUBPARAM_USER_REPONSE_CODE:
- decodeUserResponseCode(bData, inStream);
+ decodeSuccess = decodeUserResponseCode(bData, inStream);
break;
case SUBPARAM_REPLY_OPTION:
- decodeReplyOption(bData, inStream);
+ decodeSuccess = decodeReplyOption(bData, inStream);
break;
case SUBPARAM_NUMBER_OF_MESSAGES:
- decodeMsgCount(bData, inStream);
+ decodeSuccess = decodeMsgCount(bData, inStream);
break;
case SUBPARAM_CALLBACK_NUMBER:
- decodeCallbackNumber(bData, inStream);
+ decodeSuccess = decodeCallbackNumber(bData, inStream);
break;
case SUBPARAM_MESSAGE_STATUS:
- decodeMsgStatus(bData, inStream);
+ decodeSuccess = decodeMsgStatus(bData, inStream);
break;
case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
- decodeMsgCenterTimeStamp(bData, inStream);
+ decodeSuccess = decodeMsgCenterTimeStamp(bData, inStream);
break;
case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE:
- decodeValidityAbs(bData, inStream);
+ decodeSuccess = decodeValidityAbs(bData, inStream);
break;
case SUBPARAM_VALIDITY_PERIOD_RELATIVE:
- decodeValidityRel(bData, inStream);
+ decodeSuccess = decodeValidityRel(bData, inStream);
break;
case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE:
- decodeDeferredDeliveryAbs(bData, inStream);
+ decodeSuccess = decodeDeferredDeliveryAbs(bData, inStream);
break;
case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE:
- decodeDeferredDeliveryRel(bData, inStream);
+ decodeSuccess = decodeDeferredDeliveryRel(bData, inStream);
break;
case SUBPARAM_PRIVACY_INDICATOR:
- decodePrivacyIndicator(bData, inStream);
+ decodeSuccess = decodePrivacyIndicator(bData, inStream);
break;
case SUBPARAM_LANGUAGE_INDICATOR:
- decodeLanguageIndicator(bData, inStream);
+ decodeSuccess = decodeLanguageIndicator(bData, inStream);
break;
case SUBPARAM_MESSAGE_DISPLAY_MODE:
- decodeDisplayMode(bData, inStream);
+ decodeSuccess = decodeDisplayMode(bData, inStream);
break;
case SUBPARAM_PRIORITY_INDICATOR:
- decodePriorityIndicator(bData, inStream);
+ decodeSuccess = decodePriorityIndicator(bData, inStream);
break;
case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY:
- decodeMsgDeliveryAlert(bData, inStream);
+ decodeSuccess = decodeMsgDeliveryAlert(bData, inStream);
break;
case SUBPARAM_MESSAGE_DEPOSIT_INDEX:
- decodeDepositIndex(bData, inStream);
+ decodeSuccess = decodeDepositIndex(bData, inStream);
break;
default:
throw new CodingException("unsupported bearer data subparameter ("
+ subparamId + ")");
}
+ if (decodeSuccess) foundSubparamMask |= subparamIdBit;
}
if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) {
throw new CodingException("missing MESSAGE_IDENTIFIER subparam");
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
index 4d79966..d9cc2c6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
@@ -16,7 +16,10 @@
package com.android.internal.telephony.cdma.sms;
+import android.util.SparseBooleanArray;
+
import com.android.internal.telephony.SmsAddress;
+import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;
public class CdmaSmsAddress extends SmsAddress {
@@ -43,7 +46,8 @@ public class CdmaSmsAddress extends SmsAddress {
/**
* Number Types for data networks.
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+ * (See 3GPP2 C.S005-D, table2.7.1.3.2.4-2 for complete table)
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.3 for data network subset)
* NOTE: value is stored in the parent class ton field.
*/
static public final int TON_UNKNOWN = 0x00;
@@ -98,10 +102,127 @@ public class CdmaSmsAddress extends SmsAddress {
builder.append(", numberPlan=" + numberPlan);
builder.append(", numberOfDigits=" + numberOfDigits);
builder.append(", ton=" + ton);
- builder.append(", address=" + address);
+ builder.append(", address=\"" + address + "\"");
builder.append(", origBytes=" + HexDump.toHexString(origBytes));
builder.append(" }");
return builder.toString();
}
+ /*
+ * TODO(cleanup): Refactor the parsing for addresses to better
+ * share code and logic with GSM. Also, gather all DTMF/BCD
+ * processing code in one place.
+ */
+
+ private static byte[] parseToDtmf(String address) {
+ int digits = address.length();
+ byte[] result = new byte[digits];
+ for (int i = 0; i < digits; i++) {
+ char c = address.charAt(i);
+ int val = 0;
+ if ((c >= '1') && (c <= '9')) val = c - '0';
+ else if (c == '0') val = 10;
+ else if (c == '*') val = 11;
+ else if (c == '#') val = 12;
+ else return null;
+ result[i] = (byte)val;
+ }
+ return result;
+ }
+
+ private static final char[] numericCharsDialable = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#'
+ };
+
+ private static final char[] numericCharsSugar = {
+ '(', ')', ' ', '-', '+'
+ };
+
+ private static final SparseBooleanArray numericCharDialableMap = new SparseBooleanArray (
+ numericCharsDialable.length + numericCharsSugar.length);
+ static {
+ for (int i = 0; i < numericCharsDialable.length; i++) {
+ numericCharDialableMap.put(numericCharsDialable[i], true);
+ }
+ for (int i = 0; i < numericCharsSugar.length; i++) {
+ numericCharDialableMap.put(numericCharsSugar[i], false);
+ }
+ }
+
+ /**
+ * Given a numeric address string, return the string without
+ * syntactic sugar, meaning parens, spaces, hyphens/minuses, or
+ * plus signs. If the input string contains non-numeric
+ * non-punctuation characters, return null.
+ */
+ private static String filterNumericSugar(String address) {
+ StringBuilder builder = new StringBuilder();
+ int len = address.length();
+ for (int i = 0; i < len; i++) {
+ char c = address.charAt(i);
+ int mapIndex = numericCharDialableMap.indexOfKey(c);
+ if (mapIndex < 0) return null;
+ if (! numericCharDialableMap.valueAt(mapIndex)) continue;
+ builder.append(c);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Given a string, return the string without whitespace,
+ * including CR/LF.
+ */
+ private static String filterWhitespace(String address) {
+ StringBuilder builder = new StringBuilder();
+ int len = address.length();
+ for (int i = 0; i < len; i++) {
+ char c = address.charAt(i);
+ if ((c == ' ') || (c == '\r') || (c == '\n') || (c == '\t')) continue;
+ builder.append(c);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Given a string, create a corresponding CdmaSmsAddress object.
+ *
+ * The result will be null if the input string is not
+ * representable using printable ASCII.
+ *
+ * For numeric addresses, the string is cleaned up by removing
+ * common punctuation. For alpha addresses, the string is cleaned
+ * up by removing whitespace.
+ */
+ public static CdmaSmsAddress parse(String address) {
+ CdmaSmsAddress addr = new CdmaSmsAddress();
+ addr.address = address;
+ addr.ton = CdmaSmsAddress.TON_UNKNOWN;
+ byte[] origBytes = null;
+ String filteredAddr = filterNumericSugar(address);
+ if (filteredAddr != null) {
+ origBytes = parseToDtmf(filteredAddr);
+ }
+ if (origBytes != null) {
+ addr.digitMode = DIGIT_MODE_4BIT_DTMF;
+ addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+ if (address.indexOf('+') != -1) {
+ addr.ton = TON_INTERNATIONAL_OR_IP;
+ }
+ } else {
+ filteredAddr = filterWhitespace(address);
+ origBytes = UserData.stringToAscii(filteredAddr);
+ if (origBytes == null) {
+ return null;
+ }
+ addr.digitMode = DIGIT_MODE_8BIT_CHAR;
+ addr.numberMode = NUMBER_MODE_DATA_NETWORK;
+ if (address.indexOf('@') != -1) {
+ addr.ton = TON_NATIONAL_OR_EMAIL;
+ }
+ }
+ addr.origBytes = origBytes;
+ addr.numberOfDigits = origBytes.length;
+ return addr;
+ }
+
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
index f80e8c0..0dcacc1 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
@@ -36,6 +36,14 @@ public final class SmsEnvelope{
static public final int TELESERVICE_WAP = 0x1004;
static public final int TELESERVICE_WEMT = 0x1005;
+ /**
+ * The following are defined as extensions to the standard teleservices
+ */
+ // Voice mail notification through Message Waiting Indication in CDMA mode or Analog mode.
+ // Defined in 3GPP2 C.S-0005, 3.7.5.6, an Info Record containing an 8-bit number with the
+ // number of messages waiting, it's used by some CDMA carriers for a voice mail count.
+ static public final int TELESERVICE_MWI = 0x40000;
+
// ServiceCategories for Cell Broadcast, see 3GPP2 C.R1001 table 9.3.1-1
//static public final int SERVICECATEGORY_EMERGENCY = 0x0010;
//...
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
index 34cbbfa..d93852c 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
@@ -35,7 +35,7 @@ public class UserData {
//public static final int ENCODING_SHIFT_JIS = 0x05;
//public static final int ENCODING_KOREAN = 0x06;
//public static final int ENCODING_LATIN_HEBREW = 0x07;
- //public static final int ENCODING_LATIN = 0x08;
+ public static final int ENCODING_LATIN = 0x08;
public static final int ENCODING_GSM_7BIT_ALPHABET = 0x09;
public static final int ENCODING_GSM_DCS = 0x0A;
@@ -49,19 +49,20 @@ public class UserData {
public static final int IS91_MSG_TYPE_SHORT_MESSAGE = 0x85;
/**
- * IA5 data encoding character mappings.
- * (See CCITT Rec. T.50 Tables 1 and 3)
+ * US ASCII character mapping table.
*
- * Note this mapping is the the same as for printable ASCII
- * characters, with a 0x20 offset, meaning that the ASCII SPACE
- * character occurs with code 0x20.
+ * This table contains only the printable ASCII characters, with a
+ * 0x20 offset, meaning that the ASCII SPACE character is at index
+ * 0, with the resulting code of 0x20.
*
- * Note this mapping is also equivalent to that used by the IS-91
- * protocol, except for the latter using only 6 bits, and hence
- * mapping only entries up to the '_' character.
+ * Note this mapping is also equivalent to that used by both the
+ * IS5 and the IS-91 encodings. For the former this is defined
+ * using CCITT Rec. T.50 Tables 1 and 3. For the latter IS 637 B,
+ * Table 4.3.1.4.1-1 -- and note the encoding uses only 6 bits,
+ * and hence only maps entries up to the '_' character.
*
*/
- public static final char[] IA5_MAP = {
+ public static final char[] ASCII_MAP = {
' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
@@ -81,23 +82,43 @@ public class UserData {
* Only elements between these indices in the ASCII table are printable.
*/
public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20;
- public static final int ASCII_LF_INDEX = 0x0A;
+ public static final int ASCII_NL_INDEX = 0x0A;
public static final int ASCII_CR_INDEX = 0x0D;
public static final SparseIntArray charToAscii = new SparseIntArray();
static {
- for (int i = 0; i < IA5_MAP.length; i++) {
- charToAscii.put(IA5_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i);
+ for (int i = 0; i < ASCII_MAP.length; i++) {
+ charToAscii.put(ASCII_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i);
}
- charToAscii.put('\r', ASCII_LF_INDEX);
- charToAscii.put('\n', ASCII_CR_INDEX);
+ charToAscii.put('\n', ASCII_NL_INDEX);
+ charToAscii.put('\r', ASCII_CR_INDEX);
+ }
+
+ /*
+ * TODO(cleanup): Move this very generic functionality somewhere
+ * more general.
+ */
+ /**
+ * Given a string generate a corresponding ASCII-encoded byte
+ * array, but limited to printable characters. If the input
+ * contains unprintable characters, return null.
+ */
+ public static byte[] stringToAscii(String str) {
+ int len = str.length();
+ byte[] result = new byte[len];
+ for (int i = 0; i < len; i++) {
+ int charCode = charToAscii.get(str.charAt(i), -1);
+ if (charCode == -1) return null;
+ result[i] = (byte)charCode;
+ }
+ return result;
}
/**
- * Mapping for IA5 values less than 32 are flow control signals
+ * Mapping for ASCII values less than 32 are flow control signals
* and not used here.
*/
- public static final int IA5_MAP_BASE_INDEX = 0x20;
- public static final int IA5_MAP_MAX_INDEX = IA5_MAP_BASE_INDEX + IA5_MAP.length - 1;
+ public static final int ASCII_MAP_BASE_INDEX = 0x20;
+ public static final int ASCII_MAP_MAX_INDEX = ASCII_MAP_BASE_INDEX + ASCII_MAP.length - 1;
/**
* Contains the data header of the user data
@@ -133,7 +154,7 @@ public class UserData {
builder.append("{ msgEncoding=" + (msgEncodingSet ? msgEncoding : "unset"));
builder.append(", msgType=" + msgType);
builder.append(", paddingBits=" + paddingBits);
- builder.append(", numFields=" + (int)numFields);
+ builder.append(", numFields=" + numFields);
builder.append(", userDataHeader=" + userDataHeader);
builder.append(", payload='" + HexDump.toHexString(payload) + "'");
builder.append(", payloadStr='" + payloadStr + "'");
diff --git a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
index 3ca39de..dc6f92d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
+++ b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
@@ -72,7 +72,10 @@ public class ApnSetting {
boolean canHandleType(String type) {
for (String t : types) {
- if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL)) {
+ // DEFAULT handles all, and HIPRI is handled by DEFAULT
+ if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL) ||
+ (t.equals(Phone.APN_TYPE_DEFAULT) &&
+ type.equals(Phone.APN_TYPE_HIPRI))) {
return true;
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index d1e4b4f..ac7331e 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -23,13 +23,11 @@ import android.database.SQLException;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Handler;
-import android.os.Looper;
import android.os.Message;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.SystemProperties;
import android.preference.PreferenceManager;
-import android.provider.Settings;
import android.provider.Telephony;
import android.telephony.CellLocation;
import android.telephony.PhoneNumberUtils;
@@ -51,6 +49,7 @@ import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDI
import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION;
+import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallForwardInfo;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.CommandsInterface;
@@ -97,15 +96,13 @@ public class GSMPhone extends PhoneBase {
// Key used to read/write the SIM IMSI used for storing the voice mail
public static final String VM_SIM_IMSI = "vm_sim_imsi_key";
- //***** Instance Variables
+ // Instance Variables
GsmCallTracker mCT;
GsmServiceStateTracker mSST;
GsmSMSDispatcher mSMS;
- GsmDataConnectionTracker mDataConnection;
SIMRecords mSIMRecords;
SimCard mSimCard;
StkService mStkService;
- MyHandler h;
ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>();
SimPhoneBookInterfaceManager mSimPhoneBookIntManager;
SimSmsInterfaceManager mSimSmsIntManager;
@@ -129,7 +126,7 @@ public class GSMPhone extends PhoneBase {
private String mVmNumber;
- //***** Constructors
+ // Constructors
public
GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) {
@@ -138,9 +135,7 @@ public class GSMPhone extends PhoneBase {
public
GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {
- super(notifier, context, unitTestMode);
- h = new MyHandler();
- mCM = ci;
+ super(notifier, context, ci, unitTestMode);
if (ci instanceof SimulatedRadioControl) {
mSimulatedRadioControl = (SimulatedRadioControl) ci;
@@ -162,14 +157,13 @@ public class GSMPhone extends PhoneBase {
mStkService = StkService.getInstance(mCM, mSIMRecords, mContext,
(SIMFileHandler)mIccFileHandler, mSimCard);
- mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null);
- mSIMRecords.registerForRecordsLoaded(h, EVENT_SIM_RECORDS_LOADED, null);
- mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
- mCM.registerForOn(h, EVENT_RADIO_ON, null);
- mCM.setOnUSSD(h, EVENT_USSD, null);
- mCM.setOnSuppServiceNotification(h, EVENT_SSN, null);
- mCM.setOnCallRing(h, EVENT_CALL_RING, null);
- mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null);
+ mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+ mSIMRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
+ mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+ mCM.registerForOn(this, EVENT_RADIO_ON, null);
+ mCM.setOnUSSD(this, EVENT_USSD, null);
+ mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
+ mSST.registerForNetworkAttach(this, EVENT_REGISTERED_TO_NETWORK, null);
if (false) {
try {
@@ -212,15 +206,16 @@ public class GSMPhone extends PhoneBase {
public void dispose() {
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
+ super.dispose();
+
//Unregister from all former registered events
- mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE
- mSIMRecords.unregisterForRecordsLoaded(h); //EVENT_SIM_RECORDS_LOADED
- mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
- mCM.unregisterForOn(h); //EVENT_RADIO_ON
- mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK
- mCM.unSetOnUSSD(h);
- mCM.unSetOnSuppServiceNotification(h);
- mCM.unSetOnCallRing(h);
+ mCM.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE
+ mSIMRecords.unregisterForRecordsLoaded(this); //EVENT_SIM_RECORDS_LOADED
+ mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
+ mCM.unregisterForOn(this); //EVENT_RADIO_ON
+ mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK
+ mCM.unSetOnUSSD(this);
+ mCM.unSetOnSuppServiceNotification(this);
mPendingMMIs.clear();
@@ -258,8 +253,6 @@ public class GSMPhone extends PhoneBase {
}
- //***** Overridden from Phone
-
public ServiceState
getServiceState() {
return mSST.ss;
@@ -279,14 +272,6 @@ public class GSMPhone extends PhoneBase {
return "GSM";
}
- public String[] getActiveApnTypes() {
- return mDataConnection.getActiveApnTypes();
- }
-
- public String getActiveApn() {
- return mDataConnection.getActiveApnString();
- }
-
public SignalStrength getSignalStrength() {
return mSST.mSignalStrength;
}
@@ -378,20 +363,19 @@ public class GSMPhone extends PhoneBase {
}
/**
- * Notify any interested party of a Phone state change.
+ * Notify any interested party of a Phone state change {@link Phone.State}
*/
/*package*/ void notifyPhoneStateChanged() {
mNotifier.notifyPhoneState(this);
}
/**
- * Notifies registrants (ie, activities in the Phone app) about
- * changes to call state (including Phone and Connection changes).
+ * Notify registrants of a change in the call state. This notifies changes in {@link Call.State}
+ * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged.
*/
- /*package*/ void
- notifyCallStateChanged() {
+ /*package*/ void notifyPreciseCallStateChanged() {
/* we'd love it if this was package-scoped*/
- super.notifyCallStateChangedP();
+ super.notifyPreciseCallStateChangedP();
}
/*package*/ void
@@ -400,14 +384,6 @@ public class GSMPhone extends PhoneBase {
super.notifyNewRingingConnectionP(c);
}
- /**
- * Notifiy registrants of a RING event.
- */
- void notifyIncomingRing() {
- AsyncResult ar = new AsyncResult(null, this, null);
- mIncomingRingRegistrants.notifyRegistrants(ar);
- }
-
/*package*/ void
notifyDisconnect(Connection cn) {
mDisconnectRegistrants.notifyResult(cn);
@@ -926,7 +902,7 @@ public class GSMPhone extends PhoneBase {
Message resp;
mVmNumber = voiceMailNumber;
- resp = h.obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
+ resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
mSIMRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
}
@@ -965,7 +941,7 @@ public class GSMPhone extends PhoneBase {
if (LOCAL_DEBUG) Log.d(LOG_TAG, "requesting call forwarding query.");
Message resp;
if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
- resp = h.obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
+ resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
} else {
resp = onComplete;
}
@@ -983,7 +959,7 @@ public class GSMPhone extends PhoneBase {
Message resp;
if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
- resp = h.obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
+ resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, onComplete);
} else {
resp = onComplete;
@@ -1004,7 +980,7 @@ public class GSMPhone extends PhoneBase {
public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
Message onComplete) {
mCM.setCLIR(commandInterfaceCLIRMode,
- h.obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
+ obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
}
public void getCallWaiting(Message onComplete) {
@@ -1032,11 +1008,13 @@ public class GSMPhone extends PhoneBase {
/**
* Small container class used to hold information relevant to
* the carrier selection process. operatorNumeric can be ""
- * if we are looking for automatic selection.
+ * if we are looking for automatic selection. operatorAlphaLong is the
+ * corresponding operator name.
*/
private static class NetworkSelectMessage {
public Message message;
public String operatorNumeric;
+ public String operatorAlphaLong;
}
public void
@@ -1047,9 +1025,10 @@ public class GSMPhone extends PhoneBase {
NetworkSelectMessage nsm = new NetworkSelectMessage();
nsm.message = response;
nsm.operatorNumeric = "";
+ nsm.operatorAlphaLong = "";
// get the message
- Message msg = h.obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm);
+ Message msg = obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm);
if (LOCAL_DEBUG)
Log.d(LOG_TAG, "wrapping and sending message to connect automatically");
@@ -1064,9 +1043,10 @@ public class GSMPhone extends PhoneBase {
NetworkSelectMessage nsm = new NetworkSelectMessage();
nsm.message = response;
nsm.operatorNumeric = network.operatorNumeric;
+ nsm.operatorAlphaLong = network.operatorAlphaLong;
// get the message
- Message msg = h.obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm);
+ Message msg = obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm);
mCM.setNetworkSelectionModeManual(network.operatorNumeric, msg);
}
@@ -1089,8 +1069,9 @@ public class GSMPhone extends PhoneBase {
}
/**
- * @deprecated
+ * @deprecated Do not use.
*/
+ @Deprecated
public void getPdpContextList(Message response) {
getDataCallList(response);
}
@@ -1100,8 +1081,9 @@ public class GSMPhone extends PhoneBase {
}
/**
- * @deprecated
+ * @deprecated Do not use.
*/
+ @Deprecated
public List<PdpConnection> getCurrentPdpList() {
ArrayList<DataConnection> connections = new ArrayList<DataConnection>();
ArrayList<PdpConnection> pdp_list = new ArrayList<PdpConnection>();
@@ -1141,34 +1123,10 @@ public class GSMPhone extends PhoneBase {
return mDataConnection.setDataEnabled(true);
}
- public int enableApnType(String type) {
- return mDataConnection.enableApnType(type);
- }
-
- public int disableApnType(String type) {
- return mDataConnection.disableApnType(type);
- }
-
public boolean disableDataConnectivity() {
return mDataConnection.setDataEnabled(false);
}
- public String getInterfaceName(String apnType) {
- return mDataConnection.getInterfaceName(apnType);
- }
-
- public String getIpAddress(String apnType) {
- return mDataConnection.getIpAddress(apnType);
- }
-
- public String getGateway(String apnType) {
- return mDataConnection.getGateway(apnType);
- }
-
- public String[] getDnsServers(String apnType) {
- return mDataConnection.getDnsServers(apnType);
- }
-
/**
* The only circumstances under which we report that data connectivity is not
* possible are
@@ -1274,178 +1232,163 @@ public class GSMPhone extends PhoneBase {
}
}
- //***** Inner Classes
+ @Override
+ public void handleMessage (Message msg) {
+ AsyncResult ar;
+ Message onComplete;
- class MyHandler extends Handler {
- MyHandler() {
- }
+ switch (msg.what) {
+ case EVENT_RADIO_AVAILABLE: {
+ mCM.getBasebandVersion(
+ obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
- MyHandler(Looper l) {
- super(l);
- }
-
- public void
- handleMessage (Message msg) {
- AsyncResult ar;
- Message onComplete;
-
- switch (msg.what) {
- case EVENT_RADIO_AVAILABLE: {
- mCM.getBasebandVersion(
- obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
+ mCM.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE));
+ mCM.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE));
+ }
+ break;
- mCM.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE));
- mCM.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE));
- }
- break;
+ case EVENT_RADIO_ON:
+ break;
- case EVENT_RADIO_ON:
+ case EVENT_REGISTERED_TO_NETWORK:
+ syncClirSetting();
break;
- case EVENT_REGISTERED_TO_NETWORK:
- syncClirSetting();
- break;
-
- case EVENT_SIM_RECORDS_LOADED:
- updateCurrentCarrierInProvider();
+ case EVENT_SIM_RECORDS_LOADED:
+ updateCurrentCarrierInProvider();
- // Check if this is a different SIM than the previous one. If so unset the
- // voice mail number.
- String imsi = getVmSimImsi();
- if (imsi != null && !getSubscriberId().equals(imsi)) {
- storeVoiceMailNumber(null);
- setVmSimImsi(null);
- }
+ // Check if this is a different SIM than the previous one. If so unset the
+ // voice mail number.
+ String imsi = getVmSimImsi();
+ if (imsi != null && !getSubscriberId().equals(imsi)) {
+ storeVoiceMailNumber(null);
+ setVmSimImsi(null);
+ }
- break;
+ break;
- case EVENT_GET_BASEBAND_VERSION_DONE:
- ar = (AsyncResult)msg.obj;
+ case EVENT_GET_BASEBAND_VERSION_DONE:
+ ar = (AsyncResult)msg.obj;
- if (ar.exception != null) {
- break;
- }
+ if (ar.exception != null) {
+ break;
+ }
- if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
- setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result);
- break;
+ if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
+ setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result);
+ break;
- case EVENT_GET_IMEI_DONE:
- ar = (AsyncResult)msg.obj;
+ case EVENT_GET_IMEI_DONE:
+ ar = (AsyncResult)msg.obj;
- if (ar.exception != null) {
- break;
- }
+ if (ar.exception != null) {
+ break;
+ }
- mImei = (String)ar.result;
- break;
+ mImei = (String)ar.result;
+ break;
- case EVENT_GET_IMEISV_DONE:
- ar = (AsyncResult)msg.obj;
+ case EVENT_GET_IMEISV_DONE:
+ ar = (AsyncResult)msg.obj;
- if (ar.exception != null) {
- break;
- }
+ if (ar.exception != null) {
+ break;
+ }
- mImeiSv = (String)ar.result;
- break;
+ mImeiSv = (String)ar.result;
+ break;
- case EVENT_USSD:
- ar = (AsyncResult)msg.obj;
+ case EVENT_USSD:
+ ar = (AsyncResult)msg.obj;
- String[] ussdResult = (String[]) ar.result;
+ String[] ussdResult = (String[]) ar.result;
- if (ussdResult.length > 1) {
- try {
- onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
- } catch (NumberFormatException e) {
- Log.w(LOG_TAG, "error parsing USSD");
- }
+ if (ussdResult.length > 1) {
+ try {
+ onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
+ } catch (NumberFormatException e) {
+ Log.w(LOG_TAG, "error parsing USSD");
}
- break;
+ }
+ break;
- case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
- // Some MMI requests (eg USSD) are not completed
- // within the course of a CommandsInterface request
- // If the radio shuts off or resets while one of these
- // is pending, we need to clean up.
+ case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
+ // Some MMI requests (eg USSD) are not completed
+ // within the course of a CommandsInterface request
+ // If the radio shuts off or resets while one of these
+ // is pending, we need to clean up.
- for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
- if (mPendingMMIs.get(i).isPendingUSSD()) {
- mPendingMMIs.get(i).onUssdFinishedError();
- }
+ for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
+ if (mPendingMMIs.get(i).isPendingUSSD()) {
+ mPendingMMIs.get(i).onUssdFinishedError();
}
+ }
+ break;
+
+ case EVENT_SSN:
+ ar = (AsyncResult)msg.obj;
+ SuppServiceNotification not = (SuppServiceNotification) ar.result;
+ mSsnRegistrants.notifyRegistrants(ar);
+ break;
+
+ case EVENT_SET_CALL_FORWARD_DONE:
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception == null) {
+ mSIMRecords.setVoiceCallForwardingFlag(1, msg.arg1 == 1);
+ }
+ onComplete = (Message) ar.userObj;
+ if (onComplete != null) {
+ AsyncResult.forMessage(onComplete, ar.result, ar.exception);
+ onComplete.sendToTarget();
+ }
break;
- case EVENT_SSN:
- ar = (AsyncResult)msg.obj;
- SuppServiceNotification not = (SuppServiceNotification) ar.result;
- mSsnRegistrants.notifyRegistrants(ar);
+ case EVENT_SET_VM_NUMBER_DONE:
+ ar = (AsyncResult)msg.obj;
+ if (IccVmNotSupportedException.class.isInstance(ar.exception)) {
+ storeVoiceMailNumber(mVmNumber);
+ ar.exception = null;
+ }
+ onComplete = (Message) ar.userObj;
+ if (onComplete != null) {
+ AsyncResult.forMessage(onComplete, ar.result, ar.exception);
+ onComplete.sendToTarget();
+ }
break;
- case EVENT_SET_CALL_FORWARD_DONE:
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- mSIMRecords.setVoiceCallForwardingFlag(1, msg.arg1 == 1);
- }
- onComplete = (Message) ar.userObj;
- if (onComplete != null) {
- AsyncResult.forMessage(onComplete, ar.result, ar.exception);
- onComplete.sendToTarget();
- }
- break;
-
- case EVENT_SET_VM_NUMBER_DONE:
- ar = (AsyncResult)msg.obj;
- if (IccVmNotSupportedException.class.isInstance(ar.exception)) {
- storeVoiceMailNumber(mVmNumber);
- ar.exception = null;
- }
- onComplete = (Message) ar.userObj;
- if (onComplete != null) {
- AsyncResult.forMessage(onComplete, ar.result, ar.exception);
- onComplete.sendToTarget();
- }
- break;
-
- case EVENT_GET_CALL_FORWARD_DONE:
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- handleCfuQueryResult((CallForwardInfo[])ar.result);
- }
- onComplete = (Message) ar.userObj;
- if (onComplete != null) {
- AsyncResult.forMessage(onComplete, ar.result, ar.exception);
- onComplete.sendToTarget();
- }
- break;
+ case EVENT_GET_CALL_FORWARD_DONE:
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception == null) {
+ handleCfuQueryResult((CallForwardInfo[])ar.result);
+ }
+ onComplete = (Message) ar.userObj;
+ if (onComplete != null) {
+ AsyncResult.forMessage(onComplete, ar.result, ar.exception);
+ onComplete.sendToTarget();
+ }
+ break;
- case EVENT_CALL_RING:
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- notifyIncomingRing();
- }
- break;
+ // handle the select network completion callbacks.
+ case EVENT_SET_NETWORK_MANUAL_COMPLETE:
+ case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE:
+ handleSetSelectNetwork((AsyncResult) msg.obj);
+ break;
- // handle the select network completion callbacks.
- case EVENT_SET_NETWORK_MANUAL_COMPLETE:
- case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE:
- handleSetSelectNetwork((AsyncResult) msg.obj);
- break;
+ case EVENT_SET_CLIR_COMPLETE:
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception == null) {
+ saveClirSetting(msg.arg1);
+ }
+ onComplete = (Message) ar.userObj;
+ if (onComplete != null) {
+ AsyncResult.forMessage(onComplete, ar.result, ar.exception);
+ onComplete.sendToTarget();
+ }
+ break;
- case EVENT_SET_CLIR_COMPLETE:
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- saveClirSetting(msg.arg1);
- }
- onComplete = (Message) ar.userObj;
- if (onComplete != null) {
- AsyncResult.forMessage(onComplete, ar.result, ar.exception);
- onComplete.sendToTarget();
- }
- break;
- }
+ default:
+ super.handleMessage(msg);
}
}
@@ -1495,6 +1438,7 @@ public class GSMPhone extends PhoneBase {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric);
+ editor.putString(NETWORK_SELECTION_NAME_KEY, nsm.operatorAlphaLong);
// commit and log the result.
if (! editor.commit()) {
@@ -1534,36 +1478,6 @@ public class GSMPhone extends PhoneBase {
}
}
}
- /**
- * simulateDataConnection
- *
- * simulates various data connection states. This messes with
- * DataConnectionTracker's internal states, but doesn't actually change
- * the underlying radio connection states.
- *
- * @param state Phone.DataState enum.
- */
- public void simulateDataConnection(Phone.DataState state) {
- DataConnectionTracker.State dcState;
-
- switch (state) {
- case CONNECTED:
- dcState = DataConnectionTracker.State.CONNECTED;
- break;
- case SUSPENDED:
- dcState = DataConnectionTracker.State.CONNECTED;
- break;
- case DISCONNECTED:
- dcState = DataConnectionTracker.State.FAILED;
- break;
- default:
- dcState = DataConnectionTracker.State.CONNECTING;
- break;
- }
-
- mDataConnection.setState(dcState);
- notifyDataConnection(null);
- }
/**
* Retrieves the PhoneSubInfo of the GSMPhone
@@ -1589,13 +1503,6 @@ public class GSMPhone extends PhoneBase {
/**
* {@inheritDoc}
*/
- public Handler getHandler(){
- return h;
- }
-
- /**
- * {@inheritDoc}
- */
public IccFileHandler getIccFileHandler(){
return this.mIccFileHandler;
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCall.java b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java
index a92e52d..9542d20 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCall.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java
@@ -185,6 +185,7 @@ class GsmCall extends Call {
cn.onHangupLocal();
}
+ state = State.DISCONNECTING;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
index 5c5090f..91c089e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -212,7 +212,7 @@ public final class GsmCallTracker extends CallTracker {
}
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
return pendingMO;
}
@@ -279,7 +279,7 @@ public final class GsmCallTracker extends CallTracker {
internalClearDisconnected();
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
}
boolean
@@ -294,12 +294,15 @@ public final class GsmCallTracker extends CallTracker {
canDial() {
boolean ret;
int serviceState = phone.getServiceState().getState();
+ String disableCall = SystemProperties.get(
+ TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
- ret = (serviceState != ServiceState.STATE_POWER_OFF) &&
- pendingMO == null
+ ret = (serviceState != ServiceState.STATE_POWER_OFF)
+ && pendingMO == null
&& !ringingCall.isRinging()
+ && !disableCall.equals("true")
&& (!foregroundCall.getState().isAlive()
- || !backgroundCall.getState().isAlive());
+ || !backgroundCall.getState().isAlive());
return ret;
}
@@ -600,7 +603,7 @@ public final class GsmCallTracker extends CallTracker {
}
if (hasNonHangupStateChanged || newRinging != null) {
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
}
//dumpState();
@@ -738,6 +741,7 @@ public final class GsmCallTracker extends CallTracker {
}
call.onHangupLocal();
+ phone.notifyPreciseCallStateChanged();
}
/* package */
@@ -883,7 +887,7 @@ public final class GsmCallTracker extends CallTracker {
updatePhoneState();
- phone.notifyCallStateChanged();
+ phone.notifyPreciseCallStateChanged();
droppedDuringPoll.clear();
break;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
index d93ca1d..2091fb6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
@@ -381,10 +381,14 @@ public class GsmConnection extends Connection {
} else if (phone.mSST.rs.isCsNormalRestricted()) {
return DisconnectCause.CS_RESTRICTED_NORMAL;
} else {
- return DisconnectCause.NORMAL;
+ return DisconnectCause.ERROR_UNSPECIFIED;
}
- } else {
+ } else if (causeCode == CallFailCause.NORMAL_CLEARING) {
return DisconnectCause.NORMAL;
+ } else {
+ // If nothing else matches, report unknown call drop reason
+ // to app, not NORMAL call end.
+ return DisconnectCause.ERROR_UNSPECIFIED;
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index d48c941..0215ab2 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -52,6 +52,7 @@ import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.RetryManager;
import com.android.internal.telephony.TelephonyEventLog;
import com.android.internal.telephony.DataConnection.FailCause;
@@ -62,8 +63,7 @@ import java.util.ArrayList;
* {@hide}
*/
public final class GsmDataConnectionTracker extends DataConnectionTracker {
- private static final String LOG_TAG = "GSM";
- private static final boolean DBG = true;
+ protected final String LOG_TAG = "GSM";
private GSMPhone mGsmPhone;
/**
@@ -85,7 +85,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
INetStatService netstat;
// Indicates baseband will not auto-attach
private boolean noAutoAttach = false;
- long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+
private boolean mReregisterOnReconnectFailure = false;
private ContentResolver mResolver;
@@ -95,6 +95,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private int mPdpResetCount = 0;
private boolean mIsScreenOn = true;
+ /** Delay between APN attempts */
+ protected static final int APN_DELAY_MILLIS = 5000;
+
//useful for debugging
boolean failNextConnect = false;
@@ -115,27 +118,17 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private ApnSetting preferredApn = null;
+ /* Currently active APN */
+ protected ApnSetting mActiveApn;
+
/**
* pdpList holds all the PDP connection, i.e. IP Link in GPRS
*/
private ArrayList<DataConnection> pdpList;
- /** Currently requested APN type */
- private String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
-
- /** Currently active APN */
- private ApnSetting mActiveApn;
-
/** Currently active PdpConnection */
private PdpConnection mActivePdp;
- private static int APN_DEFAULT_ID = 0;
- private static int APN_MMS_ID = 1;
- private static int APN_SUPL_ID = 2;
- private static int APN_NUM_TYPES = 3;
-
- private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
-
/** Is packet service restricted by network */
private boolean mIsPsRestricted = false;
@@ -207,7 +200,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
GsmDataConnectionTracker(GSMPhone p) {
super(p);
mGsmPhone = p;
-
p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
@@ -230,7 +222,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
- p.getContext().registerReceiver(mIntentReceiver, filter, null, p.h);
+ // TODO: Why is this registering the phone as the receiver of the intent
+ // and not its own handler?
+ p.getContext().registerReceiver(mIntentReceiver, filter, null, p);
mDataConnectionTracker = this;
@@ -246,7 +240,19 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// and 2) whether the RIL will setup the baseband to auto-PS attach.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
+ if (dataEnabled[APN_DEFAULT_ID]) {
+ enabledCount++;
+ }
noAutoAttach = !dataEnabled[APN_DEFAULT_ID];
+
+ if (!mRetryMgr.configure(SystemProperties.get("ro.gsm.data_retry_config"))) {
+ if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) {
+ // Should never happen, log an error and default to a simple linear sequence.
+ Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG="
+ + DEFAULT_DATA_RETRY_CONFIG);
+ mRetryMgr.configure(20, 2000, 1000);
+ }
+ }
}
public void dispose() {
@@ -274,7 +280,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized");
}
- void setState(State s) {
+ protected void setState(State s) {
if (DBG) log ("setState: " + s);
if (state != s) {
if (s == State.INITING) { // request PDP context
@@ -298,7 +304,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
}
- String[] getActiveApnTypes() {
+ public String[] getActiveApnTypes() {
String[] result;
if (mActiveApn != null) {
result = mActiveApn.types;
@@ -318,91 +324,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
/**
- * Ensure that we are connected to an APN of the specified type.
- * @param type the APN type (currently the only valid values
- * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
- * @return the result of the operation. Success is indicated by
- * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or
- * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast
- * will be sent by the ConnectivityManager when a connection to
- * the APN has been established.
- */
- protected int enableApnType(String type) {
- if (!TextUtils.equals(type, Phone.APN_TYPE_MMS) &&
- !TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
- return Phone.APN_REQUEST_FAILED;
- }
-
- // If already active, return
- Log.d(LOG_TAG, "enableApnType("+type+")");
- if (isApnTypeActive(type)) {
- setEnabled(type, true);
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- /**
- * We're being asked to enable a non-default APN that's already in use.
- * This means we should restart the timer that will automatically
- * switch back to the default APN and disable the non-default APN
- * when it expires.
- */
- sendMessageDelayed(
- obtainMessage(EVENT_RESTORE_DEFAULT_APN),
- getRestoreDefaultApnDelay());
- if (state == State.INITING) return Phone.APN_REQUEST_STARTED;
- else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE;
- }
-
- if (!isApnTypeAvailable(type)) {
- return Phone.APN_TYPE_NOT_AVAILABLE;
- }
-
- setEnabled(type, true);
- mRequestedApnType = type;
- sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN));
- return Phone.APN_REQUEST_STARTED;
- }
-
- /**
- * The APN of the specified type is no longer needed. Ensure that if
- * use of the default APN has not been explicitly disabled, we are connected
- * to the default APN.
- * @param type the APN type. The only valid values are currently
- * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
- * @return
- */
- protected int disableApnType(String type) {
- Log.d(LOG_TAG, "disableApnType("+type+")");
- if ((TextUtils.equals(type, Phone.APN_TYPE_MMS) ||
- TextUtils.equals(type, Phone.APN_TYPE_SUPL))
- && isEnabled(type)) {
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- setEnabled(type, false);
- if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
- mRequestedApnType = Phone.APN_TYPE_DEFAULT;
- if (dataEnabled[APN_DEFAULT_ID]) {
- return Phone.APN_ALREADY_ACTIVE;
- } else {
- Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = 1; // tearDown is true;
- msg.obj = Phone.REASON_DATA_DISABLED;
- sendMessage(msg);
- return Phone.APN_REQUEST_STARTED;
- }
- } else {
- /*
- * Note that if default data is disabled, the following
- * has the effect of disabling the MMS APN, and then
- * ignoring the request to enable the default APN.
- * The net result is that data is completely disabled.
- */
- sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN));
- return Phone.APN_REQUEST_STARTED;
- }
- } else {
- return Phone.APN_REQUEST_FAILED;
- }
- }
-
- /**
* The data connection is expected to be setup while device
* 1. has sim card
* 2. registered to gprs service
@@ -428,12 +349,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return mGsmPhone.mSST.getDataRoaming();
}
- private boolean isApnTypeActive(String type) {
- // TODO: to support simultaneous, mActiveApn can be a List instead.
+ @Override
+ protected boolean isApnTypeActive(String type) {
+ // TODO: support simultaneous with List instead
return mActiveApn != null && mActiveApn.canHandleType(type);
}
- private boolean isApnTypeAvailable(String type) {
+ @Override
+ protected boolean isApnTypeAvailable(String type) {
if (allApns != null) {
for (ApnSetting apn : allApns) {
if (apn.canHandleType(type)) {
@@ -444,90 +367,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return false;
}
- private boolean isEnabled(String apnType) {
- if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) {
- return dataEnabled[APN_DEFAULT_ID];
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) {
- return dataEnabled[APN_MMS_ID];
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) {
- return dataEnabled[APN_SUPL_ID];
- } else {
- return false;
- }
- }
-
- private void setEnabled(String apnType, boolean enable) {
- Log.d(LOG_TAG, "setEnabled(" + apnType + ", " + enable + ')');
- if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) {
- dataEnabled[APN_DEFAULT_ID] = enable;
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) {
- dataEnabled[APN_MMS_ID] = enable;
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) {
- dataEnabled[APN_SUPL_ID] = enable;
- }
- Log.d(LOG_TAG, "dataEnabled[DEFAULT_APN]=" + dataEnabled[APN_DEFAULT_ID] +
- " dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID] +
- " dataEnabled[SUPL_APN]=" + dataEnabled[APN_SUPL_ID]);
- }
-
- /**
- * Prevent mobile data connections from being established,
- * or once again allow mobile data connections. If the state
- * toggles, then either tear down or set up data, as
- * appropriate to match the new state.
- * <p>This operation only affects the default APN, and if the same APN is
- * currently being used for MMS traffic, the teardown will not happen
- * even when {@code enable} is {@code false}.</p>
- * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
- * @return {@code true} if the operation succeeded
- */
- public boolean setDataEnabled(boolean enable) {
- boolean isEnabled = isEnabled(Phone.APN_TYPE_DEFAULT);
- Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled);
- if (!isEnabled && enable) {
- setEnabled(Phone.APN_TYPE_DEFAULT, true);
- // trySetupData() will be a no-op if we are currently
- // connected to the MMS APN
- sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
- return true;
- } else if (!enable) {
- setEnabled(Phone.APN_TYPE_DEFAULT, false);
- // Don't tear down if there is an active APN and it handles MMS or SUPL.
- // TODO: This isn't very general.
- if ((isApnTypeActive(Phone.APN_TYPE_MMS) && isEnabled(Phone.APN_TYPE_MMS)) ||
- (isApnTypeActive(Phone.APN_TYPE_SUPL) && isEnabled(Phone.APN_TYPE_SUPL))) {
- return false;
- }
- Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = 1; // tearDown is true
- msg.obj = Phone.REASON_DATA_DISABLED;
- sendMessage(msg);
- return true;
- } else {
- // isEnabled && enable
- return true;
- }
- }
-
- /**
- * Report the current state of data connectivity (enabled or disabled) for
- * the default APN.
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getDataEnabled() {
- return dataEnabled[APN_DEFAULT_ID];
- }
-
- /**
- * Report on whether data connectivity is enabled for any APN.
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getAnyDataEnabled() {
- return dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID];
- }
-
/**
* Formerly this method was ArrayList<PdpConnection> getAllPdps()
*/
@@ -562,7 +401,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
} else {
if (state == State.FAILED) {
cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
}
trySetupData(Phone.REASON_GPRS_ATTACHED);
}
@@ -607,7 +446,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
if (DBG) {
- log ("Setup watingApns : " + apnListToString(waitingApns));
+ log ("Setup waitngApns : " + apnListToString(waitingApns));
}
return setupData(reason);
} else {
@@ -618,6 +457,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
" sim=" + mGsmPhone.mSIMRecords.getRecordsLoaded() +
" UMTS=" + mGsmPhone.mSST.isConcurrentVoiceAndData() +
" phoneState=" + phone.getState() +
+ " isDataAllowed=" + isDataAllowed() +
" dataEnabled=" + getAnyDataEnabled() +
" roaming=" + roaming +
" dataOnRoamingEnable=" + getDataOnRoamingEnabled() +
@@ -742,7 +582,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return true;
}
- String getInterfaceName(String apnType) {
+ protected String getInterfaceName(String apnType) {
if (mActivePdp != null
&& (apnType == null || mActiveApn.canHandleType(apnType))) {
return mActivePdp.getInterface();
@@ -758,7 +598,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return null;
}
- String getGateway(String apnType) {
+ public String getGateway(String apnType) {
if (mActivePdp != null
&& (apnType == null || mActiveApn.canHandleType(apnType))) {
return mActivePdp.getGatewayAddress();
@@ -812,7 +652,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED);
if (!isConnected) {
// reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
trySetupData(Phone.REASON_APN_CHANGED);
}
@@ -893,7 +733,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
phone.notifyDataConnection(reason);
startNetStatPoll();
// reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
}
@@ -1170,8 +1010,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private boolean retryAfterDisconnected(String reason) {
boolean retry = true;
- if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
- Phone.REASON_DATA_DISABLED.equals(reason) ) {
+ if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) {
retry = false;
}
return retry;
@@ -1179,20 +1018,21 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
if (state == State.FAILED) {
- if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
+ if (!mRetryMgr.isRetryNeeded()) {
if (mReregisterOnReconnectFailure) {
- // We have already tried to re-register to the network.
- // This might be a problem with the data network.
- nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
+ // We've re-registerd once now just retry forever.
+ mRetryMgr.retryForeverUsingLastTimeout();
} else {
- // Try to Re-register to the network.
+ // Try to re-register to the network.
Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network");
mReregisterOnReconnectFailure = true;
mGsmPhone.mSST.reRegisterNetwork(null);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
return;
}
}
+
+ int nextReconnectDelay = mRetryMgr.getRetryTimer();
Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for "
+ (nextReconnectDelay / 1000) + "s");
@@ -1206,8 +1046,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
SystemClock.elapsedRealtime() + nextReconnectDelay,
mReconnectIntent);
- // double it for next time
- nextReconnectDelay *= 2;
+ mRetryMgr.increaseRetryCount();
if (!shouldPostNotification(lastFailCauseCode)) {
Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification "
@@ -1236,17 +1075,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
}
- protected void onTrySetupData(String reason) {
- trySetupData(reason);
- }
-
- protected void onRestoreDefaultApn() {
- if (DBG) Log.d(LOG_TAG, "Restore default APN");
- setEnabled(Phone.APN_TYPE_MMS, false);
- mRequestedApnType = Phone.APN_TYPE_DEFAULT;
- if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
- cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN);
- }
+ protected boolean onTrySetupData(String reason) {
+ return trySetupData(reason);
}
/**
@@ -1302,7 +1132,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
protected void onRadioOffOrNotAvailable() {
// Make sure our reconnect delay starts at the initial value
// next time the radio comes on
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
if (phone.getSimulatedRadioControl() != null) {
@@ -1324,22 +1154,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (ar.exception == null) {
// everything is setup
-
- /*
- * We may have switched away from the default PDP context
- * in order to enable a "special" APN (e.g., for MMS
- * traffic). Set a timer to switch back and/or disable the
- * special APN, so that a negligient application doesn't
- * permanently prevent data connectivity. What we are
- * protecting against here is not malicious apps, but
- * rather an app that inadvertantly fails to reset to the
- * default APN, or that dies before doing so.
- */
- if (dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID]) {
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- sendMessageDelayed(obtainMessage(EVENT_RESTORE_DEFAULT_APN),
- getRestoreDefaultApnDelay());
- }
if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
SystemProperties.set("gsm.defaultpdpcontext.active", "true");
if (canSetPreferApn && preferredApn == null) {
@@ -1387,8 +1201,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
setState(State.SCANNING);
// Wait a bit before trying the next APN, so that
// we're not tying up the RIL command channel
- sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason),
- RECONNECT_DELAY_INITIAL_MILLIS);
+ sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS);
}
}
}
@@ -1433,7 +1246,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
} else {
// reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
// in case data setup was attempted when we were on a voice call
trySetupData(Phone.REASON_VOICE_CALL_ENDED);
@@ -1444,18 +1257,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
cleanUpConnection(tearDown, reason);
}
- private int getRestoreDefaultApnDelay() {
- String restoreApnDelayStr = SystemProperties.get(APN_RESTORE_DELAY_PROP_NAME);
-
- if (restoreApnDelayStr != null && restoreApnDelayStr.length() != 0) {
- try {
- return Integer.valueOf(restoreApnDelayStr);
- } catch (NumberFormatException e) {
- }
- }
- return RESTORE_DEFAULT_APN_DELAY;
- }
-
/**
* Based on the sim operator numeric, create a list for all possible pdps
* with all apns associated with that pdp
@@ -1580,10 +1381,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private void startDelayedRetry(PdpConnection.FailCause cause, String reason) {
notifyNoData(cause);
- if (mRequestedApnType != Phone.APN_TYPE_DEFAULT) {
- sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN));
- }
- else {
+ if (mRequestedApnType == Phone.APN_TYPE_DEFAULT) {
reconnectAfterFail(cause, reason);
}
}
@@ -1638,7 +1436,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
public void handleMessage (Message msg) {
-
+ if (DBG) Log.d(LOG_TAG,"GSMDataConnTrack handleMessage "+msg);
switch (msg.what) {
case EVENT_RECORDS_LOADED:
onRecordsLoaded();
@@ -1648,10 +1446,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
onEnableNewApn();
break;
- case EVENT_RESTORE_DEFAULT_APN:
- onRestoreDefaultApn();
- break;
-
case EVENT_GPRS_DETACHED:
onGprsDetached();
break;
@@ -1710,7 +1504,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
} else {
if (state == State.FAILED) {
cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
}
trySetupData(Phone.REASON_PS_RESTRICT_ENABLED);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 60d4e8f..e7406e2 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -154,6 +154,8 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
static final int PS_NOTIFICATION = 888; //id to update and cancel PS restricted
static final int CS_NOTIFICATION = 999; //id to update and cancel CS restricted
+ static final int MAX_NUM_DATA_STATE_READS = 15;
+
private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
@@ -675,6 +677,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
newGPRSState = regCodeToServiceState(regState);
newDataRoaming = regCodeIsRoaming(regState);
newNetworkType = type;
+ newSS.setRadioTechnology(type);
break;
case EVENT_POLL_STATE_OPERATOR:
@@ -808,6 +811,15 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
case DATA_ACCESS_UMTS:
ret = "UMTS";
break;
+ case DATA_ACCESS_HSDPA:
+ ret = "HSDPA";
+ break;
+ case DATA_ACCESS_HSUPA:
+ ret = "HSUPA";
+ break;
+ case DATA_ACCESS_HSPA:
+ ret = "HSPA";
+ break;
default:
Log.e(LOG_TAG, "Wrong network type: " + Integer.toString(type));
break;
@@ -1286,7 +1298,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
* that could support voice and data simultaniously.
*/
boolean isConcurrentVoiceAndData() {
- return (networkType == DATA_ACCESS_UMTS);
+ return (networkType >= DATA_ACCESS_UMTS);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java
index e18da56..9343f44 100644
--- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java
+++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java
@@ -16,391 +16,541 @@
package com.android.internal.telephony.gsm;
-import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Arrays;
/**
- * Mobile Country Code
+ * The table below is built from two resources:
*
- * {@hide}
- */
-public final class MccTable
-{
- static ArrayList<MccEntry> table;
+ * 1) ITU "Mobile Network Code (MNC) for the international
+ * identification plan for mobile terminals and mobile users"
+ * which is available as an annex to the ITU operational bulletin
+ * available here: http://www.itu.int/itu-t/bulletin/annex.html
+ *
+ * 2) The ISO 3166 country codes list, available here:
+ * http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/index.html
+ *
+ * This table was verified (28 Aug 2009) against
+ * http://en.wikipedia.org/wiki/List_of_mobile_country_codes with the
+ * only unresolved discrepancy being that this list has an extra entry
+ * (461) for China.
+ *
+ * TODO: Complete the mappings for timezones and language/locale codes.
+ *
+ * The actual table data used in the Java code is generated from the
+ * below Python code for efficiency. The information is expected to
+ * be static, but if changes are required, the table in the python
+ * code can be modified and the trailing code run to re-generate the
+ * tables that are to be used by Java.
- static class MccEntry implements Comparable<MccEntry>
- {
- int mcc;
- String iso;
- int smallestDigitsMnc;
- String timezone;
- String language;
+mcc_table = [
+ (202, 'gr', 2, 'Greece'),
+ (204, 'nl', 2, 'Europe/Amsterdam', 'nl', 13, 'Netherlands (Kingdom of the)'),
+ (206, 'be', 2, 'Belgium'),
+ (208, 'fr', 2, 'Europe/Paris', 'fr', 'France'),
+ (212, 'mc', 2, 'Monaco (Principality of)'),
+ (213, 'ad', 2, 'Andorra (Principality of)'),
+ (214, 'es', 2, 'Europe/Madrid', 'es', 'Spain'),
+ (216, 'hu', 2, 'Hungary (Republic of)'),
+ (218, 'ba', 2, 'Bosnia and Herzegovina'),
+ (219, 'hr', 2, 'Croatia (Republic of)'),
+ (220, 'rs', 2, 'Serbia and Montenegro'),
+ (222, 'it', 2, 'Europe/Rome', 'it', 'Italy'),
+ (225, 'va', 2, 'Europe/Rome', 'it', 'Vatican City State'),
+ (226, 'ro', 2, 'Romania'),
+ (228, 'ch', 2, 'Europe/Zurich', 'de', 'Switzerland (Confederation of)'),
+ (230, 'cz', 2, 'Europe/Prague', 'cs', 13, 'Czech Republic'),
+ (231, 'sk', 2, 'Slovak Republic'),
+ (232, 'at', 2, 'Europe/Vienna', 'de', 13, 'Austria'),
+ (234, 'gb', 2, 'Europe/London', 'en', 13, 'United Kingdom of Great Britain and Northern Ireland'),
+ (235, 'gb', 2, 'Europe/London', 'en', 13, 'United Kingdom of Great Britain and Northern Ireland'),
+ (238, 'dk', 2, 'Denmark'),
+ (240, 'se', 2, 'Sweden'),
+ (242, 'no', 2, 'Norway'),
+ (244, 'fi', 2, 'Finland'),
+ (246, 'lt', 2, 'Lithuania (Republic of)'),
+ (247, 'lv', 2, 'Latvia (Republic of)'),
+ (248, 'ee', 2, 'Estonia (Republic of)'),
+ (250, 'ru', 2, 'Russian Federation'),
+ (255, 'ua', 2, 'Ukraine'),
+ (257, 'by', 2, 'Belarus (Republic of)'),
+ (259, 'md', 2, 'Moldova (Republic of)'),
+ (260, 'pl', 2, 'Europe/Warsaw', 'Poland (Republic of)'),
+ (262, 'de', 2, 'Europe/Berlin', 'de', 13, 'Germany (Federal Republic of)'),
+ (266, 'gi', 2, 'Gibraltar'),
+ (268, 'pt', 2, 'Portugal'),
+ (270, 'lu', 2, 'Luxembourg'),
+ (272, 'ie', 2, 'Europe/Dublin', 'en', 'Ireland'),
+ (274, 'is', 2, 'Iceland'),
+ (276, 'al', 2, 'Albania (Republic of)'),
+ (278, 'mt', 2, 'Malta'),
+ (280, 'cy', 2, 'Cyprus (Republic of)'),
+ (282, 'ge', 2, 'Georgia'),
+ (283, 'am', 2, 'Armenia (Republic of)'),
+ (284, 'bg', 2, 'Bulgaria (Republic of)'),
+ (286, 'tr', 2, 'Turkey'),
+ (288, 'fo', 2, 'Faroe Islands'),
+ (289, 'ge', 2, 'Abkhazia (Georgia)'),
+ (290, 'gl', 2, 'Greenland (Denmark)'),
+ (292, 'sm', 2, 'San Marino (Republic of)'),
+ (293, 'sl', 2, 'Slovenia (Republic of)'),
+ (294, 'mk', 2, 'The Former Yugoslav Republic of Macedonia'),
+ (295, 'li', 2, 'Liechtenstein (Principality of)'),
+ (297, 'me', 2, 'Montenegro (Republic of)'),
+ (302, 'ca', 2, '', '', 11, 'Canada'),
+ (308, 'pm', 2, 'Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise)'),
+ (310, 'us', 3, '', 'en', 11, 'United States of America'),
+ (311, 'us', 3, '', 'en', 11, 'United States of America'),
+ (312, 'us', 3, '', 'en', 11, 'United States of America'),
+ (313, 'us', 3, '', 'en', 11, 'United States of America'),
+ (314, 'us', 3, '', 'en', 11, 'United States of America'),
+ (315, 'us', 3, '', 'en', 11, 'United States of America'),
+ (316, 'us', 3, '', 'en', 11, 'United States of America'),
+ (330, 'pr', 2, 'Puerto Rico'),
+ (332, 'vi', 2, 'United States Virgin Islands'),
+ (334, 'mx', 3, 'Mexico'),
+ (338, 'jm', 3, 'Jamaica'),
+ (340, 'gp', 2, 'Guadeloupe (French Department of)'),
+ (342, 'bb', 3, 'Barbados'),
+ (344, 'ag', 3, 'Antigua and Barbuda'),
+ (346, 'ky', 3, 'Cayman Islands'),
+ (348, 'vg', 3, 'British Virgin Islands'),
+ (350, 'bm', 2, 'Bermuda'),
+ (352, 'gd', 2, 'Grenada'),
+ (354, 'ms', 2, 'Montserrat'),
+ (356, 'kn', 2, 'Saint Kitts and Nevis'),
+ (358, 'lc', 2, 'Saint Lucia'),
+ (360, 'vc', 2, 'Saint Vincent and the Grenadines'),
+ (362, 'nl', 2, 'Netherlands Antilles'),
+ (363, 'aw', 2, 'Aruba'),
+ (364, 'bs', 2, 'Bahamas (Commonwealth of the)'),
+ (365, 'ai', 3, 'Anguilla'),
+ (366, 'dm', 2, 'Dominica (Commonwealth of)'),
+ (368, 'cu', 2, 'Cuba'),
+ (370, 'do', 2, 'Dominican Republic'),
+ (372, 'ht', 2, 'Haiti (Republic of)'),
+ (374, 'tt', 2, 'Trinidad and Tobago'),
+ (376, 'tc', 2, 'Turks and Caicos Islands'),
+ (400, 'az', 2, 'Azerbaijani Republic'),
+ (401, 'kz', 2, 'Kazakhstan (Republic of)'),
+ (402, 'bt', 2, 'Bhutan (Kingdom of)'),
+ (404, 'in', 2, 'India (Republic of)'),
+ (405, 'in', 2, 'India (Republic of)'),
+ (410, 'pk', 2, 'Pakistan (Islamic Republic of)'),
+ (412, 'af', 2, 'Afghanistan'),
+ (413, 'lk', 2, 'Sri Lanka (Democratic Socialist Republic of)'),
+ (414, 'mm', 2, 'Myanmar (Union of)'),
+ (415, 'lb', 2, 'Lebanon'),
+ (416, 'jo', 2, 'Jordan (Hashemite Kingdom of)'),
+ (417, 'sy', 2, 'Syrian Arab Republic'),
+ (418, 'iq', 2, 'Iraq (Republic of)'),
+ (419, 'kw', 2, 'Kuwait (State of)'),
+ (420, 'sa', 2, 'Saudi Arabia (Kingdom of)'),
+ (421, 'ye', 2, 'Yemen (Republic of)'),
+ (422, 'om', 2, 'Oman (Sultanate of)'),
+ (423, 'ps', 2, 'Palestine'),
+ (424, 'ae', 2, 'United Arab Emirates'),
+ (425, 'il', 2, 'Israel (State of)'),
+ (426, 'bh', 2, 'Bahrain (Kingdom of)'),
+ (427, 'qa', 2, 'Qatar (State of)'),
+ (428, 'mn', 2, 'Mongolia'),
+ (429, 'np', 2, 'Nepal'),
+ (430, 'ae', 2, 'United Arab Emirates'),
+ (431, 'ae', 2, 'United Arab Emirates'),
+ (432, 'ir', 2, 'Iran (Islamic Republic of)'),
+ (434, 'uz', 2, 'Uzbekistan (Republic of)'),
+ (436, 'tj', 2, 'Tajikistan (Republic of)'),
+ (437, 'kg', 2, 'Kyrgyz Republic'),
+ (438, 'tm', 2, 'Turkmenistan'),
+ (440, 'jp', 2, 'Asia/Tokyo', 'ja', 14, 'Japan'),
+ (441, 'jp', 2, 'Asia/Tokyo', 'ja', 14, 'Japan'),
+ (450, 'kr', 2, 'Korea (Republic of)'),
+ (452, 'vn', 2, 'Viet Nam (Socialist Republic of)'),
+ (454, 'hk', 2, '"Hong Kong, China"'),
+ (455, 'mo', 2, '"Macao, China"'),
+ (456, 'kh', 2, 'Cambodia (Kingdom of)'),
+ (457, 'la', 2, "Lao People's Democratic Republic"),
+ (460, 'cn', 2, "China (People's Republic of)"),
+ (461, 'cn', 2, "China (People's Republic of)"),
+ (466, 'tw', 2, "Taiwan (Republic of China)"),
+ (467, 'kp', 2, "Democratic People's Republic of Korea"),
+ (470, 'bd', 2, "Bangladesh (People's Republic of)"),
+ (472, 'mv', 2, 'Maldives (Republic of)'),
+ (502, 'my', 2, 'Malaysia'),
+ (505, 'au', 2, 'Australia/Sydney', 'en', 11, 'Australia'),
+ (510, 'id', 2, 'Indonesia (Republic of)'),
+ (514, 'tl', 2, 'Democratic Republic of Timor-Leste'),
+ (515, 'ph', 2, 'Philippines (Republic of the)'),
+ (520, 'th', 2, 'Thailand'),
+ (525, 'sg', 2, 'Singapore', 'en', 11, 'Singapore (Republic of)'),
+ (528, 'bn', 2, 'Brunei Darussalam'),
+ (530, 'nz', 2, 'Pacific/Auckland', 'en', 'New Zealand'),
+ (534, 'mp', 2, 'Northern Mariana Islands (Commonwealth of the)'),
+ (535, 'gu', 2, 'Guam'),
+ (536, 'nr', 2, 'Nauru (Republic of)'),
+ (537, 'pg', 2, 'Papua New Guinea'),
+ (539, 'to', 2, 'Tonga (Kingdom of)'),
+ (540, 'sb', 2, 'Solomon Islands'),
+ (541, 'vu', 2, 'Vanuatu (Republic of)'),
+ (542, 'fj', 2, 'Fiji (Republic of)'),
+ (543, 'wf', 2, "Wallis and Futuna (Territoire franais d'outre-mer)"),
+ (544, 'as', 2, 'American Samoa'),
+ (545, 'ki', 2, 'Kiribati (Republic of)'),
+ (546, 'nc', 2, "New Caledonia (Territoire franais d'outre-mer)"),
+ (547, 'pf', 2, "French Polynesia (Territoire franais d'outre-mer)"),
+ (548, 'ck', 2, 'Cook Islands'),
+ (549, 'ws', 2, 'Samoa (Independent State of)'),
+ (550, 'fm', 2, 'Micronesia (Federated States of)'),
+ (551, 'mh', 2, 'Marshall Islands (Republic of the)'),
+ (552, 'pw', 2, 'Palau (Republic of)'),
+ (602, 'eg', 2, 'Egypt (Arab Republic of)'),
+ (603, 'dz', 2, "Algeria (People's Democratic Republic of)"),
+ (604, 'ma', 2, 'Morocco (Kingdom of)'),
+ (605, 'tn', 2, 'Tunisia'),
+ (606, 'ly', 2, "Libya (Socialist People's Libyan Arab Jamahiriya)"),
+ (607, 'gm', 2, 'Gambia (Republic of the)'),
+ (608, 'sn', 2, 'Senegal (Republic of)'),
+ (609, 'mr', 2, 'Mauritania (Islamic Republic of)'),
+ (610, 'ml', 2, 'Mali (Republic of)'),
+ (611, 'gn', 2, 'Guinea (Republic of)'),
+ (612, 'ci', 2, "Cte d'Ivoire (Republic of)"),
+ (613, 'bf', 2, 'Burkina Faso'),
+ (614, 'ne', 2, 'Niger (Republic of the)'),
+ (615, 'tg', 2, 'Togolese Republic'),
+ (616, 'bj', 2, 'Benin (Republic of)'),
+ (617, 'mu', 2, 'Mauritius (Republic of)'),
+ (618, 'lr', 2, 'Liberia (Republic of)'),
+ (619, 'sl', 2, 'Sierra Leone'),
+ (620, 'gh', 2, 'Ghana'),
+ (621, 'ng', 2, 'Nigeria (Federal Republic of)'),
+ (622, 'td', 2, 'Chad (Republic of)'),
+ (623, 'cf', 2, 'Central African Republic'),
+ (624, 'cm', 2, 'Cameroon (Republic of)'),
+ (625, 'cv', 2, 'Cape Verde (Republic of)'),
+ (626, 'st', 2, 'Sao Tome and Principe (Democratic Republic of)'),
+ (627, 'gq', 2, 'Equatorial Guinea (Republic of)'),
+ (628, 'ga', 2, 'Gabonese Republic'),
+ (629, 'cg', 2, 'Congo (Republic of the)'),
+ (630, 'cg', 2, 'Democratic Republic of the Congo'),
+ (631, 'ao', 2, 'Angola (Republic of)'),
+ (632, 'gw', 2, 'Guinea-Bissau (Republic of)'),
+ (633, 'sc', 2, 'Seychelles (Republic of)'),
+ (634, 'sd', 2, 'Sudan (Republic of the)'),
+ (635, 'rw', 2, 'Rwanda (Republic of)'),
+ (636, 'et', 2, 'Ethiopia (Federal Democratic Republic of)'),
+ (637, 'so', 2, 'Somali Democratic Republic'),
+ (638, 'dj', 2, 'Djibouti (Republic of)'),
+ (639, 'ke', 2, 'Kenya (Republic of)'),
+ (640, 'tz', 2, 'Tanzania (United Republic of)'),
+ (641, 'ug', 2, 'Uganda (Republic of)'),
+ (642, 'bi', 2, 'Burundi (Republic of)'),
+ (643, 'mz', 2, 'Mozambique (Republic of)'),
+ (645, 'zm', 2, 'Zambia (Republic of)'),
+ (646, 'mg', 2, 'Madagascar (Republic of)'),
+ (647, 're', 2, 'Reunion (French Department of)'),
+ (648, 'zw', 2, 'Zimbabwe (Republic of)'),
+ (649, 'na', 2, 'Namibia (Republic of)'),
+ (650, 'mw', 2, 'Malawi'),
+ (651, 'ls', 2, 'Lesotho (Kingdom of)'),
+ (652, 'bw', 2, 'Botswana (Republic of)'),
+ (653, 'sz', 2, 'Swaziland (Kingdom of)'),
+ (654, 'km', 2, 'Comoros (Union of the)'),
+ (655, 'za', 2, 'Africa/Johannesburg', 'en', 'South Africa (Republic of)'),
+ (657, 'er', 2, 'Eritrea'),
+ (702, 'bz', 2, 'Belize'),
+ (704, 'gt', 2, 'Guatemala (Republic of)'),
+ (706, 'sv', 2, 'El Salvador (Republic of)'),
+ (708, 'hn', 3, 'Honduras (Republic of)'),
+ (710, 'ni', 2, 'Nicaragua'),
+ (712, 'cr', 2, 'Costa Rica'),
+ (714, 'pa', 2, 'Panama (Republic of)'),
+ (716, 'pe', 2, 'Peru'),
+ (722, 'ar', 3, 'Argentine Republic'),
+ (724, 'br', 2, 'Brazil (Federative Republic of)'),
+ (730, 'cl', 2, 'Chile'),
+ (732, 'co', 3, 'Colombia (Republic of)'),
+ (734, 've', 2, 'Venezuela (Bolivarian Republic of)'),
+ (736, 'bo', 2, 'Bolivia (Republic of)'),
+ (738, 'gy', 2, 'Guyana'),
+ (740, 'ec', 2, 'Ecuador'),
+ (742, 'gf', 2, 'French Guiana (French Department of)'),
+ (744, 'py', 2, 'Paraguay (Republic of)'),
+ (746, 'sr', 2, 'Suriname (Republic of)'),
+ (748, 'uy', 2, 'Uruguay (Eastern Republic of)'),
+ (750, 'fk', 2, 'Falkland Islands (Malvinas)')]
- MccEntry(int mnc, String iso, int smallestDigitsMCC) {
- this(mnc, iso, smallestDigitsMCC, null);
- }
+get_mcc = lambda elt: elt[0]
+get_iso = lambda elt: elt[1]
+get_sd = lambda elt: elt[2]
+get_tz = lambda elt: len(elt) > 4 and elt[3] or ''
+get_lang = lambda elt: len(elt) > 5 and elt[4] or ''
+get_wifi = lambda elt: len(elt) > 6 and elt[5] or 0
- MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone) {
- this(mnc, iso, smallestDigitsMCC, timezone, null);
- }
+mcc_codes = ['0x%04x' % get_mcc(elt) for elt in mcc_table]
+tz_set = sorted(x for x in set(get_tz(elt) for elt in mcc_table))
+lang_set = sorted(x for x in set(get_lang(elt) for elt in mcc_table))
- MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone, String language) {
- this.mcc = mnc;
- this.iso = iso;
- this.smallestDigitsMnc = smallestDigitsMCC;
- this.timezone = timezone;
- this.language = language;
- }
+def mk_ind_code(elt):
+ iso = get_iso(elt)
+ iso_code = ((ord(iso[0]) << 8) | ord(iso[1])) & 0xFFFF # 16 bits
+ wifi = get_wifi(elt) & 0x000F # 4 bits
+ sd = get_sd(elt) & 0x0003 # 2 bits
+ tz_ind = tz_set.index(get_tz(elt)) & 0x001F # 5 bits
+ lang_ind = lang_set.index(get_lang(elt)) & 0x000F # 4 bits
+ return (iso_code << 16) | (wifi << 11) | (sd << 9) | (tz_ind << 4) | lang_ind
- public int compareTo(MccEntry o)
- {
- return mcc - o.mcc;
- }
- }
+ind_codes = ['0x%08x' % mk_ind_code(elt) for elt in mcc_table]
- private static MccEntry
- entryForMcc(int mcc)
- {
- int index;
+def fmt_list(title, l, batch_sz):
+ sl = []
+ for i in range(len(l) / batch_sz + (len(l) % batch_sz and 1 or 0)):
+ j = i * batch_sz
+ sl.append((' ' * 8) + ', '.join(l[j:j + batch_sz]))
+ return ' private static final %s = {\n' % title + ',\n'.join(sl) + '\n };\n'
- MccEntry m;
+def do_autogen_comment(extra_desc=[]):
+ print ' /' + '**\n * AUTO GENERATED (by the Python code above)'
+ for line in extra_desc:
+ print ' * %s' % line
+ print ' *' + '/'
- m = new MccEntry(mcc, null, 0);
+do_autogen_comment()
+print fmt_list('String[] TZ_STRINGS', ['"%s"' % x for x in tz_set], 1)
+do_autogen_comment()
+print fmt_list('String[] LANG_STRINGS', ['"%s"' % x for x in lang_set], 10)
+do_autogen_comment(['This table is a list of MCC codes. The index in this table',
+ 'of a given MCC code is the index of extra information about',
+ 'that MCC in the IND_CODES table.'])
+print fmt_list('short[] MCC_CODES', mcc_codes, 10)
+do_autogen_comment(['The values in this table are broken down as follows (msb to lsb):',
+ ' iso country code 16 bits',
+ ' (unused) 1 bit',
+ ' wifi channel 4 bits',
+ ' smalled digit 2 bits',
+ ' default timezone 5 bits',
+ ' default language 4 bits'])
+print fmt_list('int[] IND_CODES', ind_codes, 6)
- index = Collections.binarySearch(table, m);
+def parse_ind_code(ind):
+ mcc = eval(mcc_codes[ind])
+ code = eval(ind_codes[ind])
+ iso_lsb = int((code >> 16) & 0x00FF)
+ iso_msb = int((code >> 24) & 0x00FF)
+ iso = '%s%s' % (chr(iso_msb), chr(iso_lsb))
+ wifi = int((code >> 11) & 0x000F)
+ sd = int((code >> 9) & 0x0003)
+ tz_ind = (code >> 4) & 0x001F
+ lang_ind = (code >> 0) & 0x000F
+ return (mcc, iso, sd, tz_set[tz_ind], lang_set[lang_ind], wifi)
- if (index < 0) {
- return null;
- } else {
- return table.get(index);
- }
- }
+fmt_str = 'mcc = %s, iso = %s, sd = %s, tz = %s, lang = %s, wifi = %s'
+orig_table = [fmt_str % (get_mcc(elt), get_iso(elt), get_sd(elt),
+ get_tz(elt), get_lang(elt), get_wifi(elt))
+ for elt in mcc_table]
+derived_table = [fmt_str % parse_ind_code(i) for i in range(len(ind_codes))]
+for i in range(len(orig_table)):
+ if orig_table[i] == derived_table[i]: continue
+ print 'MISMATCH ERROR : ', orig_table[i], " != ", derived_table[i]
+
+*/
+/**
+ * Mobile Country Code
+ *
+ * {@hide}
+ */
+public final class MccTable
+{
/**
- * Returns a default time zone ID for the given MCC.
- * @param mcc Mobile Country Code
- * @return default TimeZone ID, or null if not specified
- */
- /* package */ static String defaultTimeZoneForMcc(int mcc) {
- MccEntry entry;
+ * AUTO GENERATED (by the Python code above)
+ */
+ private static final String[] TZ_STRINGS = {
+ "",
+ "Africa/Johannesburg",
+ "Asia/Tokyo",
+ "Australia/Sydney",
+ "Europe/Amsterdam",
+ "Europe/Berlin",
+ "Europe/Dublin",
+ "Europe/London",
+ "Europe/Madrid",
+ "Europe/Paris",
+ "Europe/Prague",
+ "Europe/Rome",
+ "Europe/Vienna",
+ "Europe/Warsaw",
+ "Europe/Zurich",
+ "Pacific/Auckland",
+ "Singapore"
+ };
- entry = entryForMcc(mcc);
+ /**
+ * AUTO GENERATED (by the Python code above)
+ */
+ private static final String[] LANG_STRINGS = {
+ "", "cs", "de", "en", "es", "fr", "it", "ja", "nl"
+ };
- if (entry == null) {
+ /**
+ * AUTO GENERATED (by the Python code above)
+ * This table is a list of MCC codes. The index in this table
+ * of a given MCC code is the index of extra information about
+ * that MCC in the IND_CODES table.
+ */
+ private static final short[] MCC_CODES = {
+ 0x00ca, 0x00cc, 0x00ce, 0x00d0, 0x00d4, 0x00d5, 0x00d6, 0x00d8, 0x00da, 0x00db,
+ 0x00dc, 0x00de, 0x00e1, 0x00e2, 0x00e4, 0x00e6, 0x00e7, 0x00e8, 0x00ea, 0x00eb,
+ 0x00ee, 0x00f0, 0x00f2, 0x00f4, 0x00f6, 0x00f7, 0x00f8, 0x00fa, 0x00ff, 0x0101,
+ 0x0103, 0x0104, 0x0106, 0x010a, 0x010c, 0x010e, 0x0110, 0x0112, 0x0114, 0x0116,
+ 0x0118, 0x011a, 0x011b, 0x011c, 0x011e, 0x0120, 0x0121, 0x0122, 0x0124, 0x0125,
+ 0x0126, 0x0127, 0x0129, 0x012e, 0x0134, 0x0136, 0x0137, 0x0138, 0x0139, 0x013a,
+ 0x013b, 0x013c, 0x014a, 0x014c, 0x014e, 0x0152, 0x0154, 0x0156, 0x0158, 0x015a,
+ 0x015c, 0x015e, 0x0160, 0x0162, 0x0164, 0x0166, 0x0168, 0x016a, 0x016b, 0x016c,
+ 0x016d, 0x016e, 0x0170, 0x0172, 0x0174, 0x0176, 0x0178, 0x0190, 0x0191, 0x0192,
+ 0x0194, 0x0195, 0x019a, 0x019c, 0x019d, 0x019e, 0x019f, 0x01a0, 0x01a1, 0x01a2,
+ 0x01a3, 0x01a4, 0x01a5, 0x01a6, 0x01a7, 0x01a8, 0x01a9, 0x01aa, 0x01ab, 0x01ac,
+ 0x01ad, 0x01ae, 0x01af, 0x01b0, 0x01b2, 0x01b4, 0x01b5, 0x01b6, 0x01b8, 0x01b9,
+ 0x01c2, 0x01c4, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01cc, 0x01cd, 0x01d2, 0x01d3,
+ 0x01d6, 0x01d8, 0x01f6, 0x01f9, 0x01fe, 0x0202, 0x0203, 0x0208, 0x020d, 0x0210,
+ 0x0212, 0x0216, 0x0217, 0x0218, 0x0219, 0x021b, 0x021c, 0x021d, 0x021e, 0x021f,
+ 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0226, 0x0227, 0x0228, 0x025a,
+ 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, 0x0260, 0x0261, 0x0262, 0x0263, 0x0264,
+ 0x0265, 0x0266, 0x0267, 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e,
+ 0x026f, 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, 0x0278,
+ 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, 0x0280, 0x0281, 0x0282,
+ 0x0283, 0x0285, 0x0286, 0x0287, 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d,
+ 0x028e, 0x028f, 0x0291, 0x02be, 0x02c0, 0x02c2, 0x02c4, 0x02c6, 0x02c8, 0x02ca,
+ 0x02cc, 0x02d2, 0x02d4, 0x02da, 0x02dc, 0x02de, 0x02e0, 0x02e2, 0x02e4, 0x02e6,
+ 0x02e8, 0x02ea, 0x02ec, 0x02ee
+ };
+
+ /**
+ * AUTO GENERATED (by the Python code above)
+ * The values in this table are broken down as follows (msb to lsb):
+ * iso country code 16 bits
+ * (unused) 1 bit
+ * wifi channel 4 bits
+ * smalled digit 2 bits
+ * default timezone 5 bits
+ * default language 4 bits
+ */
+ private static final int[] IND_CODES = {
+ 0x67720400, 0x6e6c6c48, 0x62650400, 0x66720495, 0x6d630400, 0x61640400,
+ 0x65730484, 0x68750400, 0x62610400, 0x68720400, 0x72730400, 0x697404b6,
+ 0x766104b6, 0x726f0400, 0x636804e2, 0x637a6ca1, 0x736b0400, 0x61746cc2,
+ 0x67626c73, 0x67626c73, 0x646b0400, 0x73650400, 0x6e6f0400, 0x66690400,
+ 0x6c740400, 0x6c760400, 0x65650400, 0x72750400, 0x75610400, 0x62790400,
+ 0x6d640400, 0x706c04d0, 0x64656c52, 0x67690400, 0x70740400, 0x6c750400,
+ 0x69650463, 0x69730400, 0x616c0400, 0x6d740400, 0x63790400, 0x67650400,
+ 0x616d0400, 0x62670400, 0x74720400, 0x666f0400, 0x67650400, 0x676c0400,
+ 0x736d0400, 0x736c0400, 0x6d6b0400, 0x6c690400, 0x6d650400, 0x63615c00,
+ 0x706d0400, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03,
+ 0x75735e03, 0x75735e03, 0x70720400, 0x76690400, 0x6d780600, 0x6a6d0600,
+ 0x67700400, 0x62620600, 0x61670600, 0x6b790600, 0x76670600, 0x626d0400,
+ 0x67640400, 0x6d730400, 0x6b6e0400, 0x6c630400, 0x76630400, 0x6e6c0400,
+ 0x61770400, 0x62730400, 0x61690600, 0x646d0400, 0x63750400, 0x646f0400,
+ 0x68740400, 0x74740400, 0x74630400, 0x617a0400, 0x6b7a0400, 0x62740400,
+ 0x696e0400, 0x696e0400, 0x706b0400, 0x61660400, 0x6c6b0400, 0x6d6d0400,
+ 0x6c620400, 0x6a6f0400, 0x73790400, 0x69710400, 0x6b770400, 0x73610400,
+ 0x79650400, 0x6f6d0400, 0x70730400, 0x61650400, 0x696c0400, 0x62680400,
+ 0x71610400, 0x6d6e0400, 0x6e700400, 0x61650400, 0x61650400, 0x69720400,
+ 0x757a0400, 0x746a0400, 0x6b670400, 0x746d0400, 0x6a707427, 0x6a707427,
+ 0x6b720400, 0x766e0400, 0x686b0400, 0x6d6f0400, 0x6b680400, 0x6c610400,
+ 0x636e0400, 0x636e0400, 0x74770400, 0x6b700400, 0x62640400, 0x6d760400,
+ 0x6d790400, 0x61755c33, 0x69640400, 0x746c0400, 0x70680400, 0x74680400,
+ 0x73675d03, 0x626e0400, 0x6e7a04f3, 0x6d700400, 0x67750400, 0x6e720400,
+ 0x70670400, 0x746f0400, 0x73620400, 0x76750400, 0x666a0400, 0x77660400,
+ 0x61730400, 0x6b690400, 0x6e630400, 0x70660400, 0x636b0400, 0x77730400,
+ 0x666d0400, 0x6d680400, 0x70770400, 0x65670400, 0x647a0400, 0x6d610400,
+ 0x746e0400, 0x6c790400, 0x676d0400, 0x736e0400, 0x6d720400, 0x6d6c0400,
+ 0x676e0400, 0x63690400, 0x62660400, 0x6e650400, 0x74670400, 0x626a0400,
+ 0x6d750400, 0x6c720400, 0x736c0400, 0x67680400, 0x6e670400, 0x74640400,
+ 0x63660400, 0x636d0400, 0x63760400, 0x73740400, 0x67710400, 0x67610400,
+ 0x63670400, 0x63670400, 0x616f0400, 0x67770400, 0x73630400, 0x73640400,
+ 0x72770400, 0x65740400, 0x736f0400, 0x646a0400, 0x6b650400, 0x747a0400,
+ 0x75670400, 0x62690400, 0x6d7a0400, 0x7a6d0400, 0x6d670400, 0x72650400,
+ 0x7a770400, 0x6e610400, 0x6d770400, 0x6c730400, 0x62770400, 0x737a0400,
+ 0x6b6d0400, 0x7a610413, 0x65720400, 0x627a0400, 0x67740400, 0x73760400,
+ 0x686e0600, 0x6e690400, 0x63720400, 0x70610400, 0x70650400, 0x61720600,
+ 0x62720400, 0x636c0400, 0x636f0600, 0x76650400, 0x626f0400, 0x67790400,
+ 0x65630400, 0x67660400, 0x70790400, 0x73720400, 0x75790400, 0x666b0400
+ };
+
+ /**
+ * Given a GSM Mobile Country Code, returns a default time zone ID
+ * if available. Returns null if unavailable.
+ */
+ public static String defaultTimeZoneForMcc(int mcc) {
+ int index = Arrays.binarySearch(MCC_CODES, (short)mcc);
+ if (index < 0) {
+ return null;
+ }
+ int indCode = IND_CODES[index];
+ int tzInd = (indCode >>> 4) & 0x001F;
+ String tz = TZ_STRINGS[tzInd];
+ if (tz == "") {
return null;
- } else {
- return entry.timezone;
}
+ return tz;
}
/**
- * Given a GSM Mobile Country Code, returns
- * an ISO two-character country code if available.
- * Returns "" if unavailable.
+ * Given a GSM Mobile Country Code, returns an ISO two-character
+ * country code if available. Returns "" if unavailable.
*/
- public static String
- countryCodeForMcc(int mcc)
- {
- MccEntry entry;
-
- entry = entryForMcc(mcc);
-
- if (entry == null) {
+ public static String countryCodeForMcc(int mcc) {
+ int index = Arrays.binarySearch(MCC_CODES, (short)mcc);
+ if (index < 0) {
return "";
- } else {
- return entry.iso;
}
+ int indCode = IND_CODES[index];
+ byte[] iso = {(byte)((indCode >>> 24) & 0x00FF), (byte)((indCode >>> 16) & 0x00FF)};
+ return new String(iso);
}
/**
- * Given a GSM Mobile Country Code, returns
- * an ISO 2-3 character language code if available.
- * Returns null if unavailable.
+ * Given a GSM Mobile Country Code, returns an ISO 2-3 character
+ * language code if available. Returns null if unavailable.
*/
- /* package */ static String defaultLanguageForMcc(int mcc) {
- MccEntry entry;
-
- entry = entryForMcc(mcc);
-
- if (entry == null) {
+ public static String defaultLanguageForMcc(int mcc) {
+ int index = Arrays.binarySearch(MCC_CODES, (short)mcc);
+ if (index < 0) {
return null;
- } else {
- return entry.language;
}
+ int indCode = IND_CODES[index];
+ int langInd = indCode & 0x000F;
+ String lang = LANG_STRINGS[langInd];
+ if (lang == "") {
+ return null;
+ }
+ return lang;
}
/**
- * Given a GSM Mobile Country Code, returns
- * the smallest number of digits that M if available.
- * Returns "" if unavailable.
+ * Given a GSM Mobile Country Code, returns the corresponding
+ * smallest number of digits field. Returns 2 if unavailable.
*/
- public static int
- smallestDigitsMccForMnc(int mcc)
- {
- MccEntry entry;
-
- entry = entryForMcc(mcc);
-
- if (entry == null) {
+ public static int smallestDigitsMccForMnc(int mcc) {
+ int index = Arrays.binarySearch(MCC_CODES, (short)mcc);
+ if (index < 0) {
return 2;
- } else {
- return entry.smallestDigitsMnc;
}
+ int indCode = IND_CODES[index];
+ int smDig = (indCode >>> 9) & 0x0003;
+ return smDig;
}
- static {
- table = new ArrayList<MccEntry>(240);
-
-
- /*
- * The table below is built from two resources:
- *
- * 1) ITU "Mobile Network Code (MNC) for the international
- * identification plan for mobile terminals and mobile users"
- * which is available as an annex to the ITU operational bulletin
- * available here: http://www.itu.int/itu-t/bulletin/annex.html
- *
- * 2) The ISO 3166 country codes list, available here:
- * http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/index.html
- *
- * This table has not been verified.
- *
- * FIXME(mkf) this should be stored in a more efficient representation
- */
-
- 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(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)
- table.add(new MccEntry(213,"ad",2)); //Andorra (Principality of)
- table.add(new MccEntry(214,"es",2,"Europe/Madrid","es")); //Spain
- table.add(new MccEntry(216,"hu",2)); //Hungary (Republic of)
- table.add(new MccEntry(218,"ba",2)); //Bosnia and Herzegovina
- table.add(new MccEntry(219,"hr",2)); //Croatia (Republic of)
- table.add(new MccEntry(220,"rs",2)); //Serbia and Montenegro
- table.add(new MccEntry(222,"it",2,"Europe/Rome","it")); //Italy
- 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(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(238,"dk",2)); //Denmark
- table.add(new MccEntry(240,"se",2)); //Sweden
- table.add(new MccEntry(242,"no",2)); //Norway
- table.add(new MccEntry(244,"fi",2)); //Finland
- table.add(new MccEntry(246,"lt",2)); //Lithuania (Republic of)
- table.add(new MccEntry(247,"lv",2)); //Latvia (Republic of)
- table.add(new MccEntry(248,"ee",2)); //Estonia (Republic of)
- table.add(new MccEntry(250,"ru",2)); //Russian Federation
- table.add(new MccEntry(255,"ua",2)); //Ukraine
- 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(266,"gi",2)); //Gibraltar
- table.add(new MccEntry(268,"pt",2)); //Portugal
- table.add(new MccEntry(270,"lu",2)); //Luxembourg
- table.add(new MccEntry(272,"ie",2,"Europe/Dublin","en")); //Ireland
- table.add(new MccEntry(274,"is",2)); //Iceland
- table.add(new MccEntry(276,"al",2)); //Albania (Republic of)
- table.add(new MccEntry(278,"mt",2)); //Malta
- table.add(new MccEntry(280,"cy",2)); //Cyprus (Republic of)
- table.add(new MccEntry(282,"ge",2)); //Georgia
- table.add(new MccEntry(283,"am",2)); //Armenia (Republic of)
- table.add(new MccEntry(284,"bg",2)); //Bulgaria (Republic of)
- table.add(new MccEntry(286,"tr",2)); //Turkey
- table.add(new MccEntry(288,"fo",2)); //Faroe Islands
- table.add(new MccEntry(290,"gl",2)); //Greenland (Denmark)
- table.add(new MccEntry(292,"sm",2)); //San Marino (Republic of)
- 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(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(330,"pr",2)); //Puerto Rico
- table.add(new MccEntry(332,"vi",2)); //United States Virgin Islands
- table.add(new MccEntry(334,"mx",3)); //Mexico
- table.add(new MccEntry(338,"jm",3)); //Jamaica
- table.add(new MccEntry(340,"gp",2)); //Guadeloupe (French Department of)
- table.add(new MccEntry(342,"bb",3)); //Barbados
- table.add(new MccEntry(344,"ag",3)); //Antigua and Barbuda
- table.add(new MccEntry(346,"ky",3)); //Cayman Islands
- table.add(new MccEntry(348,"vg",3)); //British Virgin Islands
- table.add(new MccEntry(350,"bm",2)); //Bermuda
- table.add(new MccEntry(352,"gd",2)); //Grenada
- table.add(new MccEntry(354,"ms",2)); //Montserrat
- table.add(new MccEntry(356,"kn",2)); //Saint Kitts and Nevis
- table.add(new MccEntry(358,"lc",2)); //Saint Lucia
- table.add(new MccEntry(360,"vc",2)); //Saint Vincent and the Grenadines
- table.add(new MccEntry(362,"nl",2)); //Netherlands Antilles
- table.add(new MccEntry(363,"aw",2)); //Aruba
- table.add(new MccEntry(364,"bs",2)); //Bahamas (Commonwealth of the)
- table.add(new MccEntry(365,"ai",3)); //Anguilla
- table.add(new MccEntry(366,"dm",2)); //Dominica (Commonwealth of)
- table.add(new MccEntry(368,"cu",2)); //Cuba
- table.add(new MccEntry(370,"do",2)); //Dominican Republic
- table.add(new MccEntry(372,"ht",2)); //Haiti (Republic of)
- table.add(new MccEntry(374,"tt",2)); //Trinidad and Tobago
- table.add(new MccEntry(376,"tc",2)); //Turks and Caicos Islands
- table.add(new MccEntry(400,"az",2)); //Azerbaijani Republic
- table.add(new MccEntry(401,"kz",2)); //Kazakhstan (Republic of)
- table.add(new MccEntry(402,"bt",2)); //Bhutan (Kingdom of)
- table.add(new MccEntry(404,"in",2)); //India (Republic of)
- table.add(new MccEntry(405,"in",2)); //India (Republic of)
- table.add(new MccEntry(410,"pk",2)); //Pakistan (Islamic Republic of)
- table.add(new MccEntry(412,"af",2)); //Afghanistan
- table.add(new MccEntry(413,"lk",2)); //Sri Lanka (Democratic Socialist Republic of)
- table.add(new MccEntry(414,"mm",2)); //Myanmar (Union of)
- table.add(new MccEntry(415,"lb",2)); //Lebanon
- table.add(new MccEntry(416,"jo",2)); //Jordan (Hashemite Kingdom of)
- table.add(new MccEntry(417,"sy",2)); //Syrian Arab Republic
- table.add(new MccEntry(418,"iq",2)); //Iraq (Republic of)
- table.add(new MccEntry(419,"kw",2)); //Kuwait (State of)
- table.add(new MccEntry(420,"sa",2)); //Saudi Arabia (Kingdom of)
- table.add(new MccEntry(421,"ye",2)); //Yemen (Republic of)
- table.add(new MccEntry(422,"om",2)); //Oman (Sultanate of)
- table.add(new MccEntry(424,"ae",2)); //United Arab Emirates
- table.add(new MccEntry(425,"il",2)); //Israel (State of)
- table.add(new MccEntry(426,"bh",2)); //Bahrain (Kingdom of)
- table.add(new MccEntry(427,"qa",2)); //Qatar (State of)
- table.add(new MccEntry(428,"mn",2)); //Mongolia
- table.add(new MccEntry(429,"np",2)); //Nepal
- table.add(new MccEntry(430,"ae",2)); //United Arab Emirates
- table.add(new MccEntry(431,"ae",2)); //United Arab Emirates
- table.add(new MccEntry(432,"ir",2)); //Iran (Islamic Republic of)
- table.add(new MccEntry(434,"uz",2)); //Uzbekistan (Republic of)
- 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(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"
- table.add(new MccEntry(455,"mo",2)); //"Macao, China"
- table.add(new MccEntry(456,"kh",2)); //Cambodia (Kingdom of)
- table.add(new MccEntry(457,"la",2)); //Lao People's Democratic Republic
- table.add(new MccEntry(460,"cn",2)); //China (People's Republic of)
- table.add(new MccEntry(461,"cn",2)); //China (People's Republic of)
- table.add(new MccEntry(466,"tw",2)); //"Taiwan, China"
- table.add(new MccEntry(467,"kp",2)); //Democratic People's Republic of Korea
- 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(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(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)
- table.add(new MccEntry(535,"gu",2)); //Guam
- table.add(new MccEntry(536,"nr",2)); //Nauru (Republic of)
- table.add(new MccEntry(537,"pg",2)); //Papua New Guinea
- table.add(new MccEntry(539,"to",2)); //Tonga (Kingdom of)
- table.add(new MccEntry(540,"sb",2)); //Solomon Islands
- table.add(new MccEntry(541,"vu",2)); //Vanuatu (Republic of)
- table.add(new MccEntry(542,"fj",2)); //Fiji (Republic of)
- table.add(new MccEntry(543,"wf",2)); //Wallis and Futuna (Territoire franais d'outre-mer)
- table.add(new MccEntry(544,"as",2)); //American Samoa
- table.add(new MccEntry(545,"ki",2)); //Kiribati (Republic of)
- table.add(new MccEntry(546,"nc",2)); //New Caledonia (Territoire franais d'outre-mer)
- table.add(new MccEntry(547,"pf",2)); //French Polynesia (Territoire franais d'outre-mer)
- table.add(new MccEntry(548,"ck",2)); //Cook Islands
- table.add(new MccEntry(549,"ws",2)); //Samoa (Independent State of)
- table.add(new MccEntry(550,"fm",2)); //Micronesia (Federated States of)
- table.add(new MccEntry(551,"mh",2)); //Marshall Islands (Republic of the)
- table.add(new MccEntry(552,"pw",2)); //Palau (Republic of)
- table.add(new MccEntry(602,"eg",2)); //Egypt (Arab Republic of)
- table.add(new MccEntry(603,"dz",2)); //Algeria (People's Democratic Republic of)
- table.add(new MccEntry(604,"ma",2)); //Morocco (Kingdom of)
- table.add(new MccEntry(605,"tn",2)); //Tunisia
- table.add(new MccEntry(606,"ly",2)); //Libya (Socialist People's Libyan Arab Jamahiriya)
- table.add(new MccEntry(607,"gm",2)); //Gambia (Republic of the)
- table.add(new MccEntry(608,"sn",2)); //Senegal (Republic of)
- table.add(new MccEntry(609,"mr",2)); //Mauritania (Islamic Republic of)
- table.add(new MccEntry(610,"ml",2)); //Mali (Republic of)
- table.add(new MccEntry(611,"gn",2)); //Guinea (Republic of)
- table.add(new MccEntry(612,"ci",2)); //Cte d'Ivoire (Republic of)
- table.add(new MccEntry(613,"bf",2)); //Burkina Faso
- table.add(new MccEntry(614,"ne",2)); //Niger (Republic of the)
- table.add(new MccEntry(615,"tg",2)); //Togolese Republic
- table.add(new MccEntry(616,"bj",2)); //Benin (Republic of)
- table.add(new MccEntry(617,"mu",2)); //Mauritius (Republic of)
- table.add(new MccEntry(618,"lr",2)); //Liberia (Republic of)
- table.add(new MccEntry(619,"sl",2)); //Sierra Leone
- table.add(new MccEntry(620,"gh",2)); //Ghana
- table.add(new MccEntry(621,"ng",2)); //Nigeria (Federal Republic of)
- table.add(new MccEntry(622,"td",2)); //Chad (Republic of)
- table.add(new MccEntry(623,"cf",2)); //Central African Republic
- table.add(new MccEntry(624,"cm",2)); //Cameroon (Republic of)
- table.add(new MccEntry(625,"cv",2)); //Cape Verde (Republic of)
- table.add(new MccEntry(626,"st",2)); //Sao Tome and Principe (Democratic Republic of)
- table.add(new MccEntry(627,"gq",2)); //Equatorial Guinea (Republic of)
- table.add(new MccEntry(628,"ga",2)); //Gabonese Republic
- table.add(new MccEntry(629,"cg",2)); //Congo (Republic of the)
- table.add(new MccEntry(630,"cg",2)); //Democratic Republic of the Congo
- table.add(new MccEntry(631,"ao",2)); //Angola (Republic of)
- table.add(new MccEntry(632,"gw",2)); //Guinea-Bissau (Republic of)
- table.add(new MccEntry(633,"sc",2)); //Seychelles (Republic of)
- table.add(new MccEntry(634,"sd",2)); //Sudan (Republic of the)
- table.add(new MccEntry(635,"rw",2)); //Rwanda (Republic of)
- table.add(new MccEntry(636,"et",2)); //Ethiopia (Federal Democratic Republic of)
- table.add(new MccEntry(637,"so",2)); //Somali Democratic Republic
- table.add(new MccEntry(638,"dj",2)); //Djibouti (Republic of)
- table.add(new MccEntry(639,"ke",2)); //Kenya (Republic of)
- table.add(new MccEntry(640,"tz",2)); //Tanzania (United Republic of)
- table.add(new MccEntry(641,"ug",2)); //Uganda (Republic of)
- table.add(new MccEntry(642,"bi",2)); //Burundi (Republic of)
- table.add(new MccEntry(643,"mz",2)); //Mozambique (Republic of)
- table.add(new MccEntry(645,"zm",2)); //Zambia (Republic of)
- table.add(new MccEntry(646,"mg",2)); //Madagascar (Republic of)
- table.add(new MccEntry(647,"re",2)); //Reunion (French Department of)
- table.add(new MccEntry(648,"zw",2)); //Zimbabwe (Republic of)
- table.add(new MccEntry(649,"na",2)); //Namibia (Republic of)
- table.add(new MccEntry(650,"mw",2)); //Malawi
- table.add(new MccEntry(651,"ls",2)); //Lesotho (Kingdom of)
- table.add(new MccEntry(652,"bw",2)); //Botswana (Republic of)
- table.add(new MccEntry(653,"sz",2)); //Swaziland (Kingdom of)
- table.add(new MccEntry(654,"km",2)); //Comoros (Union of the)
- table.add(new MccEntry(655,"za",2,"Africa/Johannesburg","en")); //South Africa (Republic of)
- table.add(new MccEntry(657,"er",2)); //Eritrea
- table.add(new MccEntry(702,"bz",2)); //Belize
- table.add(new MccEntry(704,"gt",2)); //Guatemala (Republic of)
- table.add(new MccEntry(706,"sv",2)); //El Salvador (Republic of)
- table.add(new MccEntry(708,"hn",3)); //Honduras (Republic of)
- table.add(new MccEntry(710,"ni",2)); //Nicaragua
- table.add(new MccEntry(712,"cr",2)); //Costa Rica
- table.add(new MccEntry(714,"pa",2)); //Panama (Republic of)
- table.add(new MccEntry(716,"pe",2)); //Peru
- table.add(new MccEntry(722,"ar",3)); //Argentine Republic
- table.add(new MccEntry(724,"br",2)); //Brazil (Federative Republic of)
- table.add(new MccEntry(730,"cl",2)); //Chile
- table.add(new MccEntry(732,"co",3)); //Colombia (Republic of)
- table.add(new MccEntry(734,"ve",2)); //Venezuela (Bolivarian Republic of)
- table.add(new MccEntry(736,"bo",2)); //Bolivia (Republic of)
- table.add(new MccEntry(738,"gy",2)); //Guyana
- table.add(new MccEntry(740,"ec",2)); //Ecuador
- table.add(new MccEntry(742,"gf",2)); //French Guiana (French Department of)
- table.add(new MccEntry(744,"py",2)); //Paraguay (Republic of)
- table.add(new MccEntry(746,"sr",2)); //Suriname (Republic of)
- table.add(new MccEntry(748,"uy",2)); //Uruguay (Eastern Republic of)
- table.add(new MccEntry(750,"fk",2)); //Falkland Islands (Malvinas)
- //table.add(new MccEntry(901,"",2)); //"International Mobile, shared code"
-
- Collections.sort(table);
+ /**
+ * 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) {
+ int index = Arrays.binarySearch(MCC_CODES, (short)mcc);
+ if (index < 0) {
+ return 0;
+ }
+ int indCode = IND_CODES[index];
+ int wifi = (indCode >>> 11) & 0x000F;
+ return wifi;
}
+
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
index 89de867..224419e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
@@ -84,9 +84,13 @@ public class PdpConnection extends DataConnection {
lastFailCause = FailCause.NONE;
receivedDisconnectReq = false;
- phone.mCM.setupDataCall(Integer.toString(RILConstants.GSM_PHONE),
+ int authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
+ RILConstants.SETUP_DATA_AUTH_NONE;
+
+ phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user,
- apn.password, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
+ apn.password, Integer.toString(authType),
+ obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
}
private void tearDownData(Message msg) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index e25de81..4272faa 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -16,39 +16,29 @@
package com.android.internal.telephony.gsm;
-import android.app.ActivityManagerNative;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
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;
-
-
-import static com.android.internal.telephony.TelephonyProperties.*;
import com.android.internal.telephony.AdnRecord;
import com.android.internal.telephony.AdnRecordCache;
import com.android.internal.telephony.AdnRecordLoader;
import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.gsm.SimCard;
-import com.android.internal.telephony.gsm.SmsMessage;
import com.android.internal.telephony.IccFileHandler;
import com.android.internal.telephony.IccRecords;
import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.IccVmFixedException;
import com.android.internal.telephony.IccVmNotSupportedException;
-import com.android.internal.telephony.PhoneProxy;
-
-
-
-
+import java.util.ArrayList;
/**
@@ -512,6 +502,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;
@@ -552,12 +565,13 @@ public final class SIMRecords extends IccRecords {
Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx");
((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi);
- ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+ ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
SimCard.INTENT_VALUE_ICC_IMSI, null);
int mcc = Integer.parseInt(imsi.substring(0, 3));
setTimezoneFromMccIfNeeded(mcc);
setLocaleFromMccIfNeeded(mcc);
+ setWifiChannelsFromMccIfNeeded(mcc);
break;
case EVENT_GET_MBI_DONE:
@@ -1178,7 +1192,7 @@ public final class SIMRecords extends IccRecords {
recordsLoadedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
- ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+ ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
SimCard.INTENT_VALUE_ICC_LOADED, null);
}
@@ -1203,7 +1217,7 @@ public final class SIMRecords extends IccRecords {
/* broadcast intent SIM_READY here so that we can make sure
READY is sent before IMSI ready
*/
- ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+ ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
SimCard.INTENT_VALUE_ICC_READY, null);
fetchSimRecords();
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index 9af3aa6..6c56682 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -17,469 +17,37 @@
package com.android.internal.telephony.gsm;
import android.app.ActivityManagerNative;
-import android.content.Intent;
import android.content.res.Configuration;
-import android.os.AsyncResult;
import android.os.RemoteException;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
import android.util.Log;
-import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneProxy;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-
-import static android.Manifest.permission.READ_PHONE_STATE;
/**
- * Note: this class shares common code with RuimCard, consider a base class to minimize code
- * duplication.
* {@hide}
*/
-public final class SimCard extends Handler implements IccCard {
- static final String LOG_TAG="GSM";
-
- //***** Instance Variables
- private static final boolean DBG = true;
-
- private GSMPhone phone;
- private CommandsInterface.IccStatus status = null;
- private boolean mDesiredPinLocked;
- private boolean mDesiredFdnEnabled;
- private boolean mSimPinLocked = true; // Default to locked
- private boolean mSimFdnEnabled = false; // Default to disabled.
- // Will be updated when SIM_READY.
-
- //***** Constants
-
- // FIXME I hope this doesn't conflict with the Dialer's notifications
- static final int NOTIFICATION_ID_SIM_STATUS = 33456;
-
- //***** Event Constants
-
- static final int EVENT_SIM_LOCKED_OR_ABSENT = 1;
- static final int EVENT_GET_SIM_STATUS_DONE = 2;
- static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
- static final int EVENT_PINPUK_DONE = 4;
- static final int EVENT_REPOLL_STATUS_DONE = 5;
- static final int EVENT_SIM_READY = 6;
- static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
- static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
- static final int EVENT_CHANGE_SIM_PASSWORD_DONE = 9;
- static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
- static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
-
-
- //***** Constructor
+public final class SimCard extends IccCard {
SimCard(GSMPhone phone) {
- this.phone = phone;
-
- phone.mCM.registerForSIMLockedOrAbsent(
- this, EVENT_SIM_LOCKED_OR_ABSENT, null);
-
- phone.mCM.registerForOffOrNotAvailable(
- this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
-
- phone.mCM.registerForSIMReady(
- this, EVENT_SIM_READY, null);
+ super(phone, "GSM", true);
+ mPhone.mCM.registerForSIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null);
+ mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+ mPhone.mCM.registerForSIMReady(mHandler, EVENT_ICC_READY, null);
updateStateProperty();
}
+ @Override
public void dispose() {
//Unregister for all events
- phone.mCM.unregisterForSIMLockedOrAbsent(this);
- phone.mCM.unregisterForOffOrNotAvailable(this);
- phone.mCM.unregisterForSIMReady(this);
- }
-
- protected void finalize() {
- if(DBG) Log.d(LOG_TAG, "SimCard finalized");
- }
-
- //***** SimCard implementation
-
- public State
- getState() {
- if (status == null) {
- switch(phone.mCM.getRadioState()) {
- /* This switch block must not return anything in
- * State.isLocked() or State.ABSENT.
- * If it does, handleSimStatus() may break
- */
- case RADIO_OFF:
- case RADIO_UNAVAILABLE:
- case SIM_NOT_READY:
- return State.UNKNOWN;
- case SIM_LOCKED_OR_ABSENT:
- //this should be transient-only
- return State.UNKNOWN;
- case SIM_READY:
- return State.READY;
- }
- } else {
- switch (status) {
- case ICC_ABSENT: return State.ABSENT;
- case ICC_NOT_READY: return State.UNKNOWN;
- case ICC_READY: return State.READY;
- case ICC_PIN: return State.PIN_REQUIRED;
- case ICC_PUK: return State.PUK_REQUIRED;
- case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED;
- }
- }
-
- Log.e(LOG_TAG, "GsmSimCard.getState(): case should never be reached");
- return State.UNKNOWN;
- }
-
- private RegistrantList absentRegistrants = new RegistrantList();
- private RegistrantList pinLockedRegistrants = new RegistrantList();
- private RegistrantList networkLockedRegistrants = new RegistrantList();
-
-
- public void registerForAbsent(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- absentRegistrants.add(r);
-
- if (getState() == State.ABSENT) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForAbsent(Handler h) {
- absentRegistrants.remove(h);
- }
-
- public void registerForNetworkLocked(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- networkLockedRegistrants.add(r);
-
- if (getState() == State.NETWORK_LOCKED) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForNetworkLocked(Handler h) {
- networkLockedRegistrants.remove(h);
- }
-
- public void registerForLocked(Handler h, int what, Object obj) {
- Registrant r = new Registrant (h, what, obj);
-
- pinLockedRegistrants.add(r);
-
- if (getState().isPinLocked()) {
- r.notifyRegistrant();
- }
- }
-
- public void unregisterForLocked(Handler h) {
- pinLockedRegistrants.remove(h);
- }
-
-
- public void supplyPin (String pin, Message onComplete) {
- phone.mCM.supplyIccPin(pin,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyPuk (String puk, String newPin, Message onComplete) {
- phone.mCM.supplyIccPuk(puk, newPin,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
- public void supplyPin2 (String pin2, Message onComplete) {
- phone.mCM.supplyIccPin2(pin2,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
- public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
- phone.mCM.supplyIccPuk2(puk2, newPin2,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyNetworkDepersonalization (String pin, Message onComplete) {
- if(DBG) log("Network Despersonalization: " + pin);
- phone.mCM.supplyNetworkDepersonalization(pin,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public boolean getIccLockEnabled() {
- return mSimPinLocked;
- }
-
- public boolean getIccFdnEnabled() {
- return mSimFdnEnabled;
+ mPhone.mCM.unregisterForSIMLockedOrAbsent(mHandler);
+ mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
+ mPhone.mCM.unregisterForSIMReady(mHandler);
}
- public void setIccLockEnabled (boolean enabled,
- String password, Message onComplete) {
- int serviceClassX;
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX;
-
- mDesiredPinLocked = enabled;
-
- phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,
- enabled, password, serviceClassX,
- obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
- }
-
- public void setIccFdnEnabled (boolean enabled,
- String password, Message onComplete) {
- int serviceClassX;
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX +
- CommandsInterface.SERVICE_CLASS_SMS;
-
- mDesiredFdnEnabled = enabled;
-
- phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD,
- enabled, password, serviceClassX,
- obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
- }
-
- public void changeIccLockPassword(String oldPassword, String newPassword,
- Message onComplete) {
- if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
- phone.mCM.changeIccPin(oldPassword, newPassword,
- obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete));
-
- }
-
- public void changeIccFdnPassword(String oldPassword, String newPassword,
- Message onComplete) {
- if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
- phone.mCM.changeIccPin2(oldPassword, newPassword,
- obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete));
-
- }
-
- public String getServiceProviderName () {
- return phone.mSIMRecords.getServiceProviderName();
- }
-
- //***** Handler implementation
@Override
- public void handleMessage(Message msg){
- AsyncResult ar;
- int serviceClassX;
-
- serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
- CommandsInterface.SERVICE_CLASS_DATA +
- CommandsInterface.SERVICE_CLASS_FAX;
-
- switch (msg.what) {
- case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
- status = null;
- updateStateProperty();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_NOT_READY, null);
- break;
- case EVENT_SIM_READY:
- //TODO: put facility read in SIM_READY now, maybe in REG_NW
- phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
- break;
- case EVENT_SIM_LOCKED_OR_ABSENT:
- phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
- break;
- case EVENT_GET_SIM_STATUS_DONE:
- ar = (AsyncResult)msg.obj;
-
- getSimStatusDone(ar);
- break;
- case EVENT_PINPUK_DONE:
- // a PIN/PUK/PIN2/PUK2/Network Personalization
- // request has completed. ar.userObj is the response Message
- // Repoll before returning
- ar = (AsyncResult)msg.obj;
- // TODO should abstract these exceptions
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- phone.mCM.getIccStatus(
- obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
- break;
- case EVENT_REPOLL_STATUS_DONE:
- // Finished repolling status after PIN operation
- // ar.userObj is the response messaeg
- // ar.userObj.obj is already an AsyncResult with an
- // appropriate exception filled in if applicable
-
- ar = (AsyncResult)msg.obj;
- getSimStatusDone(ar);
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_QUERY_FACILITY_LOCK_DONE:
- ar = (AsyncResult)msg.obj;
- onQueryFacilityLock(ar);
- break;
- case EVENT_QUERY_FACILITY_FDN_DONE:
- ar = (AsyncResult)msg.obj;
- onQueryFdnEnabled(ar);
- break;
- case EVENT_CHANGE_FACILITY_LOCK_DONE:
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- mSimPinLocked = mDesiredPinLocked;
- if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
- "mSimPinLocked= " + mSimPinLocked);
- } else {
- Log.e(LOG_TAG, "Error change facility lock with exception "
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_CHANGE_FACILITY_FDN_DONE:
- ar = (AsyncResult)msg.obj;
-
- if (ar.exception == null) {
- mSimFdnEnabled = mDesiredFdnEnabled;
- if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
- "mSimFdnEnabled=" + mSimFdnEnabled);
- } else {
- Log.e(LOG_TAG, "Error change facility fdn with exception "
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_CHANGE_SIM_PASSWORD_DONE:
- ar = (AsyncResult)msg.obj;
- if(ar.exception != null) {
- Log.e(LOG_TAG, "Error in change sim password with exception"
- + ar.exception);
- }
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- ((Message)ar.userObj).sendToTarget();
- break;
- default:
- Log.e(LOG_TAG, "[GsmSimCard] Unknown Event " + msg.what);
- }
- }
-
-
- //***** Private methods
-
- /**
- * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
- * @param ar is asyncResult of Query_Facility_Locked
- */
- private void onQueryFacilityLock(AsyncResult ar) {
- if(ar.exception != null) {
- if (DBG) log("Error in querying facility lock:" + ar.exception);
- return;
- }
-
- int[] ints = (int[])ar.result;
- if(ints.length != 0) {
- mSimPinLocked = (0!=ints[0]);
- if(DBG) log("Query facility lock : " + mSimPinLocked);
- } else {
- Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response");
- }
- }
-
- /**
- * Interperate EVENT_QUERY_FACILITY_LOCK_DONE
- * @param ar is asyncResult of Query_Facility_Locked
- */
- private void onQueryFdnEnabled(AsyncResult ar) {
- if(ar.exception != null) {
- if(DBG) log("Error in querying facility lock:" + ar.exception);
- return;
- }
-
- int[] ints = (int[])ar.result;
- if(ints.length != 0) {
- mSimFdnEnabled = (0!=ints[0]);
- if(DBG) log("Query facility lock : " + mSimFdnEnabled);
- } else {
- Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response");
- }
- }
-
- private void
- getSimStatusDone(AsyncResult ar) {
- if (ar.exception != null) {
- Log.e(LOG_TAG,"Error getting ICC status. "
- + "RIL_REQUEST_GET_ICC_STATUS should "
- + "never return an error", ar.exception);
- return;
- }
-
- CommandsInterface.IccStatus newStatus
- = (CommandsInterface.IccStatus) ar.result;
-
- handleSimStatus(newStatus);
- }
-
- private void
- handleSimStatus(CommandsInterface.IccStatus newStatus) {
- boolean transitionedIntoPinLocked;
- boolean transitionedIntoAbsent;
- boolean transitionedIntoNetworkLocked;
-
- SimCard.State oldState, newState;
-
- oldState = getState();
- status = newStatus;
- newState = getState();
-
- updateStateProperty();
-
- transitionedIntoPinLocked = (
- (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED)
- || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED));
- transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
- transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
- && newState == State.NETWORK_LOCKED);
-
- if (transitionedIntoPinLocked) {
- if(DBG) log("Notify SIM pin or puk locked.");
- pinLockedRegistrants.notifyRegistrants();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED,
- (newState == State.PIN_REQUIRED) ?
- INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
- } else if (transitionedIntoAbsent) {
- if(DBG) log("Notify SIM missing.");
- absentRegistrants.notifyRegistrants();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_ABSENT, null);
- } else if (transitionedIntoNetworkLocked) {
- if(DBG) log("Notify SIM network locked.");
- networkLockedRegistrants.notifyRegistrants();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED,
- INTENT_VALUE_LOCKED_NETWORK);
- }
- }
-
- public void broadcastSimStateChangedIntent(String value, String reason) {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName());
- intent.putExtra(SimCard.INTENT_KEY_ICC_STATE, value);
- intent.putExtra(SimCard.INTENT_KEY_LOCKED_REASON, reason);
- if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value
- + " reason " + reason);
- ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE);
+ public String getServiceProviderName () {
+ return ((GSMPhone)mPhone).mSIMRecords.getServiceProviderName();
}
public void updateImsiConfiguration(String imsi) {
@@ -494,19 +62,8 @@ public final class SimCard extends Handler implements IccCard {
try {
ActivityManagerNative.getDefault().updateConfiguration(config);
} catch (RemoteException e) {
+ Log.e(mLogTag, "[SimCard] Remote Exception when updating imsi configuration");
}
}
}
-
- private void
- updateStateProperty() {
- phone.setSystemProperty(
- TelephonyProperties.PROPERTY_SIM_STATE,
- getState().toString());
- }
-
- private void log(String msg) {
- Log.d(LOG_TAG, "[GsmSimCard] " + msg);
- }
}
-
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index af59126..93721ff 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -519,12 +519,12 @@ public class SmsMessage extends SmsMessageBase{
long getSCTimestampMillis() {
// TP-Service-Centre-Time-Stamp
- int year = IccUtils.bcdByteToInt(pdu[cur++]);
- int month = IccUtils.bcdByteToInt(pdu[cur++]);
- int day = IccUtils.bcdByteToInt(pdu[cur++]);
- int hour = IccUtils.bcdByteToInt(pdu[cur++]);
- int minute = IccUtils.bcdByteToInt(pdu[cur++]);
- int second = IccUtils.bcdByteToInt(pdu[cur++]);
+ int year = IccUtils.gsmBcdByteToInt(pdu[cur++]);
+ int month = IccUtils.gsmBcdByteToInt(pdu[cur++]);
+ int day = IccUtils.gsmBcdByteToInt(pdu[cur++]);
+ int hour = IccUtils.gsmBcdByteToInt(pdu[cur++]);
+ int minute = IccUtils.gsmBcdByteToInt(pdu[cur++]);
+ int second = IccUtils.gsmBcdByteToInt(pdu[cur++]);
// For the timezone, the most significant bit of the
// least signficant nibble is the sign byte
@@ -534,11 +534,9 @@ public class SmsMessage extends SmsMessageBase{
byte tzByte = pdu[cur++];
// Mask out sign bit.
- int timezoneOffset = IccUtils
- .bcdByteToInt((byte) (tzByte & (~0x08)));
+ int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08)));
- timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset
- : -timezoneOffset;
+ timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset;
Time time = new Time(Time.TIMEZONE_UTC);
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index f71ea48..11b3fd6 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -27,10 +27,11 @@ import com.android.internal.telephony.BaseCommands;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.DataCallState;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.Phone;
import com.android.internal.telephony.gsm.CallFailCause;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
import com.android.internal.telephony.gsm.SuppServiceNotification;
-import com.android.internal.telephony.Phone;
import java.util.ArrayList;
@@ -103,39 +104,8 @@ public final class SimulatedCommands extends BaseCommands
//***** CommandsInterface implementation
- public void getIccStatus(Message result) {
- switch (mState) {
- case SIM_READY:
- resultSuccess(result, IccStatus.ICC_READY);
- break;
-
- case SIM_LOCKED_OR_ABSENT:
- returnSimLockedStatus(result);
- break;
-
- default:
- resultSuccess(result, IccStatus.ICC_NOT_READY);
- break;
- }
- }
-
- private void returnSimLockedStatus(Message result) {
- switch (mSimLockedState) {
- case REQUIRE_PIN:
- Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PIN");
- resultSuccess(result, IccStatus.ICC_PIN);
- break;
-
- case REQUIRE_PUK:
- Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PUK");
- resultSuccess(result, IccStatus.ICC_PUK);
- break;
-
- default:
- Log.i(LOG_TAG,
- "[SimCmd] returnSimLockedStatus: mSimLockedState==NONE !?");
- break;
- }
+ public void getIccCardStatus(Message result) {
+ unimplemented(result);
}
public void supplyIccPin(String pin, Message result) {
@@ -974,7 +944,7 @@ public final class SimulatedCommands extends BaseCommands
}
public void setupDataCall(String radioTechnology, String profile, String apn, String user,
- String password, Message result) {
+ String password, String authType, Message result) {
unimplemented(result);
}
diff --git a/test-runner/android/test/AndroidTestRunner.java b/test-runner/android/test/AndroidTestRunner.java
index 79cedb0..358b7e9 100644
--- a/test-runner/android/test/AndroidTestRunner.java
+++ b/test-runner/android/test/AndroidTestRunner.java
@@ -158,16 +158,18 @@ public class AndroidTestRunner extends BaseTestRunner {
mTestResult.addListener(testListener);
}
+ Context testContext = mInstrumentation == null ? mContext : mInstrumentation.getContext();
for (TestCase testCase : mTestCases) {
- setContextIfAndroidTestCase(testCase, mContext);
+ setContextIfAndroidTestCase(testCase, mContext, testContext);
setInstrumentationIfInstrumentationTestCase(testCase, mInstrumentation);
testCase.run(mTestResult);
}
}
- private void setContextIfAndroidTestCase(Test test, Context context) {
+ private void setContextIfAndroidTestCase(Test test, Context context, Context testContext) {
if (AndroidTestCase.class.isAssignableFrom(test.getClass())) {
((AndroidTestCase) test).setContext(context);
+ ((AndroidTestCase) test).setTestContext(testContext);
}
}
@@ -178,14 +180,23 @@ public class AndroidTestRunner extends BaseTestRunner {
private void setInstrumentationIfInstrumentationTestCase(
Test test, Instrumentation instrumentation) {
if (InstrumentationTestCase.class.isAssignableFrom(test.getClass())) {
- ((InstrumentationTestCase) test).injectInsrumentation(instrumentation);
+ ((InstrumentationTestCase) test).injectInstrumentation(instrumentation);
}
}
- public void setInstrumentaiton(Instrumentation instrumentation) {
+ public void setInstrumentation(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
}
+ /**
+ * @deprecated Incorrect spelling,
+ * use {@link #setInstrumentation(android.app.Instrumentation)} instead.
+ */
+ @Deprecated
+ public void setInstrumentaiton(Instrumentation instrumentation) {
+ setInstrumentation(instrumentation);
+ }
+
@Override
protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
return mContext.getClassLoader().loadClass(suiteClassName);
diff --git a/test-runner/android/test/InstrumentationTestRunner.java b/test-runner/android/test/InstrumentationTestRunner.java
index 6658fb0..23f0ed4 100644
--- a/test-runner/android/test/InstrumentationTestRunner.java
+++ b/test-runner/android/test/InstrumentationTestRunner.java
@@ -329,7 +329,7 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
mTestRunner = getAndroidTestRunner();
mTestRunner.setContext(getTargetContext());
- mTestRunner.setInstrumentaiton(this);
+ mTestRunner.setInstrumentation(this);
mTestRunner.setSkipExecution(logOnly);
mTestRunner.setTest(testSuiteBuilder.build());
mTestCount = mTestRunner.getTestCases().size();
diff --git a/test-runner/android/test/IsolatedContext.java b/test-runner/android/test/IsolatedContext.java
index 859b2e5..4bd9528 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;
import java.io.File;
@@ -22,6 +26,7 @@ import java.io.File;
public class IsolatedContext extends ContextWrapper {
private ContentResolver mResolver;
+ private final MockAccountManager mMockAccountManager;
private List<Intent> mBroadcastIntents = Lists.newArrayList();
@@ -29,6 +34,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. */
@@ -79,10 +85,23 @@ 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
+ }
+ }
@Override
public File getFilesDir() {
return new File("/dev/null");
diff --git a/test-runner/android/test/ProviderTestCase.java b/test-runner/android/test/ProviderTestCase.java
index 445b4eb..668e9f7 100644
--- a/test-runner/android/test/ProviderTestCase.java
+++ b/test-runner/android/test/ProviderTestCase.java
@@ -15,6 +15,7 @@ import android.database.DatabaseUtils;
* @deprecated this class extends InstrumentationTestCase but should extend AndroidTestCase. Use
* ProviderTestCase2, which corrects this problem, instead.
*/
+@Deprecated
public abstract class ProviderTestCase<T extends ContentProvider>
extends InstrumentationTestCase {
diff --git a/test-runner/android/test/RenamingDelegatingContext.java b/test-runner/android/test/RenamingDelegatingContext.java
index 3f64340..0ea43ab 100644
--- a/test-runner/android/test/RenamingDelegatingContext.java
+++ b/test-runner/android/test/RenamingDelegatingContext.java
@@ -6,6 +6,8 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.content.ContentProvider;
import android.database.sqlite.SQLiteDatabase;
+import android.os.FileUtils;
+import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
@@ -22,6 +24,8 @@ public class RenamingDelegatingContext extends ContextWrapper {
private Context mFileContext;
private String mFilePrefix = null;
+ private File mCacheDir;
+ private final Object mSync = new Object();
private Set<String> mDatabaseNames = Sets.newHashSet();
private Set<String> mFileNames = Sets.newHashSet();
@@ -136,6 +140,11 @@ public class RenamingDelegatingContext extends ContextWrapper {
return false;
}
}
+
+ @Override
+ public File getDatabasePath(String name) {
+ return mFileContext.getDatabasePath(renamedFileName(name));
+ }
@Override
public String[] databaseList() {
@@ -179,6 +188,32 @@ public class RenamingDelegatingContext extends ContextWrapper {
public String[] fileList() {
return mFileNames.toArray(new String[]{});
}
+
+ /**
+ * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real
+ * one) and return it instead. This code is basically getCacheDir(), except it uses the real
+ * cache dir as the parent directory and creates a test cache dir inside that.
+ */
+ @Override
+ public File getCacheDir() {
+ synchronized (mSync) {
+ if (mCacheDir == null) {
+ mCacheDir = new File(mFileContext.getCacheDir(), renamedFileName("cache"));
+ }
+ if (!mCacheDir.exists()) {
+ if(!mCacheDir.mkdirs()) {
+ Log.w("RenamingDelegatingContext", "Unable to create cache directory");
+ return null;
+ }
+ FileUtils.setPermissions(
+ mCacheDir.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ }
+ }
+ return mCacheDir;
+ }
+
// /**
// * Given an array of files returns only those whose names indicate that they belong to this
diff --git a/test-runner/android/test/SyncBaseInstrumentation.java b/test-runner/android/test/SyncBaseInstrumentation.java
index 772d75c..a860bb3 100644
--- a/test-runner/android/test/SyncBaseInstrumentation.java
+++ b/test-runner/android/test/SyncBaseInstrumentation.java
@@ -19,9 +19,9 @@ package android.test;
import android.content.ContentResolver;
import android.content.Context;
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
@@ -44,12 +44,12 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase {
* Syncs the specified provider.
* @throws Exception
*/
- protected void syncProvider(Uri uri, String account, String authority) throws Exception {
+ protected void syncProvider(Uri uri, String accountName, String authority) throws Exception {
Bundle extras = new Bundle();
- extras.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true);
- extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ Account account = new Account(accountName, "com.google.GAIA");
- mContentResolver.startSync(uri, extras);
+ ContentResolver.requestSync(account, authority, extras);
long startTimeInMillis = SystemClock.elapsedRealtime();
long endTimeInMillis = startTimeInMillis + MAX_TIME_FOR_SYNC_IN_MINS * 60000;
@@ -64,7 +64,7 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase {
break;
}
- if (isSyncActive(account, authority)) {
+ if (ContentResolver.isSyncActive(account, authority)) {
counter = 0;
continue;
}
@@ -73,24 +73,7 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase {
}
protected void cancelSyncsandDisableAutoSync() {
- try {
- ContentResolver.getContentService().setListenForNetworkTickles(false);
- } catch (RemoteException e) {
- }
- mContentResolver.cancelSync(null);
- }
-
- /**
- * This method tests if any sync is active or not. Sync is considered to be active if the
- * entry is in either the Pending or Active tables.
- * @return
- */
- private boolean isSyncActive(String account, String authority) {
- try {
- return ContentResolver.getContentService().isSyncActive(account,
- authority);
- } catch (RemoteException e) {
- return false;
- }
+ ContentResolver.setMasterSyncAutomatically(false);
+ ContentResolver.cancelSync(null /* all accounts */, null /* all authorities */);
}
}
diff --git a/test-runner/android/test/TestRunner.java b/test-runner/android/test/TestRunner.java
index efa2480..012df35 100644
--- a/test-runner/android/test/TestRunner.java
+++ b/test-runner/android/test/TestRunner.java
@@ -39,7 +39,7 @@ import com.google.android.collect.Lists;
* and you probably will not need to instantiate, extend, or call this
* class yourself. See the full {@link android.test} package description
* to learn more about testing Android applications.
- *
+ *
* {@hide} Not needed for 1.0 SDK.
*/
public class TestRunner implements PerformanceTestCase.Intermediates {
@@ -84,6 +84,7 @@ public class TestRunner implements PerformanceTestCase.Intermediates {
super();
}
+ @Override
public void run(TestResult result) {
result.addListener(this);
super.run(result);
@@ -301,7 +302,7 @@ public class TestRunner implements PerformanceTestCase.Intermediates {
if (mMode == PERFORMANCE) {
runInPerformanceMode(test, className, false, className);
} else if (mMode == PROFILING) {
- //Need a way to mark a test to be run in profiling mode or not.
+ //Need a way to mark a test to be run in profiling mode or not.
startProfiling();
test.run();
finishProfiling();
@@ -337,6 +338,7 @@ public class TestRunner implements PerformanceTestCase.Intermediates {
AndroidTestCase testcase = (AndroidTestCase) test;
try {
testcase.setContext(mContext);
+ testcase.setTestContext(mContext);
} catch (Exception ex) {
Log.i("TestHarness", ex.toString());
}
@@ -700,7 +702,7 @@ public class TestRunner implements PerformanceTestCase.Intermediates {
}
} catch (ClassNotFoundException e) {
return 1; // this gets the count right, because either this test
- // is missing, and it will fail when run or it is a single Junit test to be run.
+ // is missing, and it will fail when run or it is a single Junit test to be run.
}
return 0;
}
diff --git a/test-runner/android/test/TouchUtils.java b/test-runner/android/test/TouchUtils.java
index 52d2ee8..962b2f9 100644
--- a/test-runner/android/test/TouchUtils.java
+++ b/test-runner/android/test/TouchUtils.java
@@ -565,6 +565,7 @@ public class TouchUtils {
* {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
* configuring the Activity under test
*/
+ @Deprecated
public static int dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX,
int deltaY) {
int[] xy = new int[2];
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 d5cd6ef..beb9044 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -22,6 +22,7 @@ import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageInstallObserver;
@@ -139,6 +140,11 @@ public class MockPackageManager extends PackageManager {
}
@Override
+ public int checkSignatures(int uid1, int uid2) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public String[] getPackagesForUid(int uid) {
throw new UnsupportedOperationException();
}
@@ -292,9 +298,6 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
- /**
- * @hide - to match hiding in superclass
- */
@Override
public String getInstallerPackageName(String packageName) {
throw new UnsupportedOperationException();
@@ -422,6 +425,11 @@ public class MockPackageManager extends PackageManager {
}
@Override
+ public FeatureInfo[] getSystemAvailableFeatures() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean isSafeMode() {
throw new UnsupportedOperationException();
}
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
index 845f547..d94327a 100644
--- a/tests/AndroidTests/AndroidManifest.xml
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -52,6 +52,7 @@
<uses-permission android:name="com.android.unit_tests.permission.TEST_GRANTED" />
+ <uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" />
<uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
diff --git a/tests/AndroidTests/res/raw/v21_simple_1.vcf b/tests/AndroidTests/res/raw/v21_simple_1.vcf
new file mode 100644
index 0000000..6aabb4c
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_simple_1.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+N:Ando;Roid;
+END:VCARD
diff --git a/tests/AndroidTests/res/raw/v21_simple_2.vcf b/tests/AndroidTests/res/raw/v21_simple_2.vcf
new file mode 100644
index 0000000..f0d5ab5
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_simple_2.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+FN:Ando Roid
+END:VCARD
diff --git a/tests/AndroidTests/res/raw/v21_simple.vcf b/tests/AndroidTests/res/raw/v21_simple_3.vcf
index beddabb..beddabb 100644
--- a/tests/AndroidTests/res/raw/v21_simple.vcf
+++ b/tests/AndroidTests/res/raw/v21_simple_3.vcf
diff --git a/tests/AndroidTests/run_test.sh b/tests/AndroidTests/run_test.sh
index 7ada698..bc06b7e 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:/data/app/com.android.unit_tests.apk \
+adb shell exec dalvikvm -Xbootclasspath:$bpath -cp /system/app/AndroidTests.apk:/data/app/com.android.unit_tests.apk:/data/app/AndroidTests.apk \
com.android.internal.util.WithFramework junit.textui.TestRunner $*
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index f0ba573..02af547 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -18,9 +18,11 @@ package com.android.unit_tests;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.SmsHeader;
+import com.android.internal.telephony.cdma.SmsMessage;
import com.android.internal.telephony.cdma.sms.BearerData;
import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
import com.android.internal.util.BitwiseInputStream;
import com.android.internal.util.BitwiseOutputStream;
import com.android.internal.util.HexDump;
@@ -28,16 +30,77 @@ import com.android.internal.util.HexDump;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
import java.util.Iterator;
import java.lang.Integer;
-import android.util.Log;
-
public class CdmaSmsTest extends AndroidTestCase {
private final static String LOG_TAG = "CDMA";
@SmallTest
+ public void testCdmaSmsAddrParsing() throws Exception {
+ CdmaSmsAddress addr = CdmaSmsAddress.parse("6502531000");
+ assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 10);
+ assertEquals(addr.origBytes.length, 10);
+ byte[] data = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10};
+ for (int i = 0; i < data.length; i++) {
+ assertEquals(addr.origBytes[i], data[i]);
+ }
+ addr = CdmaSmsAddress.parse("(650) 253-1000");
+ assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 10);
+ assertEquals(addr.origBytes.length, 10);
+ byte[] data2 = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10};
+ for (int i = 0; i < data2.length; i++) {
+ assertEquals(addr.origBytes[i], data2[i]);
+ }
+ addr = CdmaSmsAddress.parse("(+886) 917 222 555");
+ assertEquals(addr.ton, CdmaSmsAddress.TON_INTERNATIONAL_OR_IP);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 12);
+ assertEquals(addr.origBytes.length, 12);
+ byte[] data3 = {8, 8, 6, 9, 1, 7, 2, 2, 2, 5, 5, 5};
+ for (int i = 0; i < data3.length; i++) {
+ assertEquals(addr.origBytes[i], data3[i]);
+ }
+ addr = CdmaSmsAddress.parse("(650) *253-1000 #600");
+ byte[] data4 = {6, 5, 10, 11, 2, 5, 3, 1, 10, 10, 10, 12, 6, 10, 10};
+ for (int i = 0; i < data4.length; i++) {
+ assertEquals(addr.origBytes[i], data4[i]);
+ }
+ String input = "x@y.com,a@b.com";
+ addr = CdmaSmsAddress.parse(input);
+ assertEquals(addr.ton, CdmaSmsAddress.TON_NATIONAL_OR_EMAIL);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 15);
+ assertEquals(addr.origBytes.length, 15);
+ assertEquals(new String(addr.origBytes), input);
+ addr = CdmaSmsAddress.parse("foo bar");
+ assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN);
+ assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR);
+ assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK);
+ assertEquals(addr.numberOfDigits, 6);
+ assertEquals(addr.origBytes.length, 6);
+ assertEquals(new String(addr.origBytes), "foobar");
+ addr = CdmaSmsAddress.parse("f\noo\tb a\rr");
+ assertEquals(new String(addr.origBytes), "foobar");
+ assertEquals(CdmaSmsAddress.parse("f\u0000oo bar"), null);
+ assertEquals(CdmaSmsAddress.parse("f\u0007oo bar"), null);
+ assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null);
+ assertEquals(CdmaSmsAddress.parse("f\u1ECFboo\u001fbar"), null);
+ assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null);
+ }
+
+ @SmallTest
public void testUserData7bitGsm() throws Exception {
String pdu = "00031040900112488ea794e074d69e1b7392c270326cde9e98";
BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu));
@@ -84,6 +147,15 @@ public class CdmaSmsTest extends AndroidTestCase {
assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "Test \u007f standard \u0000 SMS";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals("Test standard SMS", revBearerData.userData.payloadStr);
+ userData.payloadStr = "Test \n standard \r SMS";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
}
@SmallTest
@@ -105,6 +177,21 @@ public class CdmaSmsTest extends AndroidTestCase {
assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "1234567";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "12345678901234567890123456789012345678901234567890" +
+ "12345678901234567890123456789012345678901234567890" +
+ "12345678901234567890123456789012345678901234567890" +
+ "1234567890";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "Test \u007f illegal \u0000 SMS chars";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals("Test illegal SMS chars", revBearerData.userData.payloadStr);
userData.payloadStr = "More @ testing\nis great^|^~woohoo";
revBearerData = BearerData.decode(BearerData.encode(bearerData));
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
@@ -153,6 +240,12 @@ public class CdmaSmsTest extends AndroidTestCase {
assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "1234567";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
}
@SmallTest
@@ -576,6 +669,16 @@ public class CdmaSmsTest extends AndroidTestCase {
BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4));
assertEquals(bd4.alert, 3);
assertEquals(bd4.userData.payloadStr, "Test Alert 3");
+ String pdu5 = "00031000000126114F4CBCFA20DB979F3C39F2A0C9976" +
+ "69ED979794187665E5D1028EFA7A6840E1062D3D39A900C028000";
+ BearerData bd5 = BearerData.decode(HexDump.hexStringToByteArray(pdu5));
+ assertEquals(bd5.alert, BearerData.ALERT_MEDIUM_PRIO);
+ assertEquals(bd5.userData.payloadStr, "test message delivery alert (with 8 bits)");
+ String pdu6 = "00031000000126114F4CBCFA20DB979F3C39F2A0C9976" +
+ "69ED979794187665E5D1028EFA7A6840C1062D3D39A900C00";
+ BearerData bd6 = BearerData.decode(HexDump.hexStringToByteArray(pdu6));
+ assertEquals(bd6.userData.payloadStr, "test message delivery alert (with 0 bits)");
+ assertEquals(bd6.alertIndicatorSet, false);
}
@SmallTest
@@ -707,4 +810,24 @@ public class CdmaSmsTest extends AndroidTestCase {
assertEquals(bd4.userData.payloadStr, "ABCDEFG");
}
+ @SmallTest
+ public void testUserDataHeaderWithEightCharMsg() throws Exception {
+ BearerData bearerData = new BearerData();
+ bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
+ bearerData.messageId = 55;
+ SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+ concatRef.refNumber = 0xEE;
+ concatRef.msgCount = 2;
+ concatRef.seqNumber = 2;
+ concatRef.isEightBits = true;
+ SmsHeader smsHeader = new SmsHeader();
+ smsHeader.concatRef = concatRef;
+ UserData userData = new UserData();
+ userData.payloadStr = "01234567";
+ userData.userDataHeader = smsHeader;
+ bearerData.userData = userData;
+ byte[] encodedSms = BearerData.encode(bearerData);
+ BearerData revBearerData = BearerData.decode(encodedSms);
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ }
}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java b/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java
new file mode 100644
index 0000000..875376a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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 com.android.unit_tests;
+
+import com.android.internal.telephony.gsm.MccTable;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import android.util.Log;
+
+public class MccTableTest extends AndroidTestCase {
+ private final static String LOG_TAG = "GSM";
+
+ @SmallTest
+ public void testTimeZone() throws Exception {
+ assertEquals(MccTable.defaultTimeZoneForMcc(208), "Europe/Paris");
+ assertEquals(MccTable.defaultTimeZoneForMcc(232), "Europe/Vienna");
+ assertEquals(MccTable.defaultTimeZoneForMcc(655), "Africa/Johannesburg");
+ assertEquals(MccTable.defaultTimeZoneForMcc(440), "Asia/Tokyo");
+ assertEquals(MccTable.defaultTimeZoneForMcc(441), "Asia/Tokyo");
+ assertEquals(MccTable.defaultTimeZoneForMcc(525), "Singapore");
+ assertEquals(MccTable.defaultTimeZoneForMcc(240), null); // tz not defined, hence default
+ assertEquals(MccTable.defaultTimeZoneForMcc(0), null); // mcc not defined, hence default
+ assertEquals(MccTable.defaultTimeZoneForMcc(2000), null); // mcc not defined, hence default
+ }
+
+ @SmallTest
+ public void testCountryCode() throws Exception {
+ assertEquals(MccTable.countryCodeForMcc(270), "lu");
+ assertEquals(MccTable.countryCodeForMcc(202), "gr");
+ assertEquals(MccTable.countryCodeForMcc(750), "fk");
+ assertEquals(MccTable.countryCodeForMcc(646), "mg");
+ assertEquals(MccTable.countryCodeForMcc(314), "us");
+ assertEquals(MccTable.countryCodeForMcc(300), ""); // mcc not defined, hence default
+ assertEquals(MccTable.countryCodeForMcc(0), ""); // mcc not defined, hence default
+ assertEquals(MccTable.countryCodeForMcc(2000), ""); // mcc not defined, hence default
+ }
+
+ @SmallTest
+ public void testLang() throws Exception {
+ assertEquals(MccTable.defaultLanguageForMcc(311), "en");
+ assertEquals(MccTable.defaultLanguageForMcc(232), "de");
+ assertEquals(MccTable.defaultLanguageForMcc(230), "cs");
+ assertEquals(MccTable.defaultLanguageForMcc(204), "nl");
+ assertEquals(MccTable.defaultLanguageForMcc(274), null); // lang not defined, hence default
+ assertEquals(MccTable.defaultLanguageForMcc(0), null); // mcc not defined, hence default
+ assertEquals(MccTable.defaultLanguageForMcc(2000), null); // mcc not defined, hence default
+ }
+
+ @SmallTest
+ public void testSmDigits() throws Exception {
+ assertEquals(MccTable.smallestDigitsMccForMnc(312), 3);
+ assertEquals(MccTable.smallestDigitsMccForMnc(430), 2);
+ assertEquals(MccTable.smallestDigitsMccForMnc(365), 3);
+ assertEquals(MccTable.smallestDigitsMccForMnc(536), 2);
+ assertEquals(MccTable.smallestDigitsMccForMnc(352), 2); // sd not defined, hence default
+ assertEquals(MccTable.smallestDigitsMccForMnc(0), 2); // mcc not defined, hence default
+ assertEquals(MccTable.smallestDigitsMccForMnc(2000), 2); // mcc not defined, hence default
+ }
+
+ @SmallTest
+ public void testWifi() throws Exception {
+ assertEquals(MccTable.wifiChannelsForMcc(262), 13);
+ assertEquals(MccTable.wifiChannelsForMcc(234), 13);
+ assertEquals(MccTable.wifiChannelsForMcc(505), 11);
+ assertEquals(MccTable.wifiChannelsForMcc(313), 11);
+ assertEquals(MccTable.wifiChannelsForMcc(330), 0); // wifi not defined, hence default
+ assertEquals(MccTable.wifiChannelsForMcc(0), 0); // mcc not defined, hence default
+ assertEquals(MccTable.wifiChannelsForMcc(2000), 0); // mcc not defined, hence default
+
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java b/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java
deleted file mode 100644
index b7f562d..0000000
--- a/tests/AndroidTests/src/com/android/unit_tests/VCardTests.java
+++ /dev/null
@@ -1,773 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.unit_tests;
-
-import android.content.ContentValues;
-import android.syncml.pim.PropertyNode;
-import android.syncml.pim.VDataBuilder;
-import android.syncml.pim.VNode;
-import android.syncml.pim.vcard.VCardException;
-import android.syncml.pim.vcard.VCardParser_V21;
-import android.syncml.pim.vcard.VCardParser_V30;
-import android.test.AndroidTestCase;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Vector;
-
-public class VCardTests extends AndroidTestCase {
-
- private class PropertyNodesVerifier {
- private HashMap<String, Vector<PropertyNode>> mPropertyNodeMap;
- public PropertyNodesVerifier(PropertyNode... nodes) {
- mPropertyNodeMap = new HashMap<String, Vector<PropertyNode>>();
- for (PropertyNode propertyNode : nodes) {
- String propName = propertyNode.propName;
- Vector<PropertyNode> expectedNodes =
- mPropertyNodeMap.get(propName);
- if (expectedNodes == null) {
- expectedNodes = new Vector<PropertyNode>();
- mPropertyNodeMap.put(propName, expectedNodes);
- }
- expectedNodes.add(propertyNode);
- }
- }
-
- public void verify(VNode vnode) {
- for (PropertyNode propertyNode : vnode.propList) {
- String propName = propertyNode.propName;
- Vector<PropertyNode> nodes = mPropertyNodeMap.get(propName);
- if (nodes == null) {
- fail("Unexpected propName \"" + propName + "\" exists.");
- }
- boolean successful = false;
- int size = nodes.size();
- for (int i = 0; i < size; i++) {
- PropertyNode expectedNode = nodes.get(i);
- if (expectedNode.propName.equals(propName)) {
- if (expectedNode.equals(propertyNode)) {
- successful = true;
- nodes.remove(i);
- if (nodes.size() == 0) {
- mPropertyNodeMap.remove(propName);
- }
- break;
- } else {
- fail("Property \"" + propName + "\" has wrong value.\n"
- + "expected: " + expectedNode.toString()
- + "\n actual: " + propertyNode.toString());
- }
- }
- }
- if (!successful) {
- fail("Unexpected property \"" + propName + "\" exists.");
- }
- }
- if (mPropertyNodeMap.size() != 0) {
- Vector<String> expectedProps = new Vector<String>();
- for (Vector<PropertyNode> nodes : mPropertyNodeMap.values()) {
- for (PropertyNode node : nodes) {
- expectedProps.add(node.propName);
- }
- }
- fail("expected props " + Arrays.toString(expectedProps.toArray()) +
- " was not found");
- }
- }
- }
-
- public void testV21SimpleCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("N", "Ando;Roid;",
- Arrays.asList("Ando", "Roid", ""),
- null, null, null, null),
- new PropertyNode("FN", "Ando Roid",
- null, null, null, null, null));
- verifier.verify(builder.vNodeList.get(0));
- }
-
- public void testV21BackslashCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_backslash);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", ";A;B\\;C\\;;D;:E;\\\\;",
- Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""),
- null, null, null, null),
- new PropertyNode("FN", "A;B\\C\\;D:E\\\\",
- null, null, null, null, null));
- verifier.verify(builder.vNodeList.get(0));
- }
-
- public void testV21ComplicatedCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_complicated);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- ContentValues contentValuesForQP = new ContentValues();
- contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
- ContentValues contentValuesForPhoto = new ContentValues();
- contentValuesForPhoto.put("ENCODING", "BASE64");
- // Push data into int array at first since values like 0x80 are
- // interpreted as int by the compiler and casting all of them is
- // cumbersome...
- int[] photoIntArray = {
- 0xff, 0xd8, 0xff, 0xe1, 0x0a, 0x0f, 0x45, 0x78, 0x69, 0x66, 0x00,
- 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d,
- 0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
- 0xaa, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
- 0x00, 0xba, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00,
- 0x00, 0x00, 0xc2, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x28, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x32, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xe6, 0x02, 0x13,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x82,
- 0x98, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xfa,
- 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
- 0x84, 0xc4, 0xa5, 0x00, 0x07, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x00, 0x04, 0x1e, 0x32, 0x30, 0x30, 0x38, 0x31,
- 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31, 0x00, 0x00,
- 0x44, 0x6f, 0x43, 0x6f, 0x4d, 0x6f, 0x00, 0x00, 0x44, 0x39, 0x30,
- 0x35, 0x69, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x44, 0x39, 0x30,
- 0x35, 0x69, 0x20, 0x56, 0x65, 0x72, 0x31, 0x2e, 0x30, 0x30, 0x00,
- 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
- 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x49, 0x4d, 0x00, 0x30, 0x33,
- 0x30, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x14, 0x00,
- 0x14, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
- 0x00, 0x34, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
- 0x00, 0x00, 0x00, 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x11, 0x09, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x0f, 0x0b, 0x00,
- 0x00, 0x27, 0x10, 0x00, 0x00, 0x05, 0x97, 0x00, 0x00, 0x27, 0x10,
- 0x00, 0x00, 0x08, 0xb0, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1c,
- 0x01, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x02, 0x5e, 0x00, 0x00,
- 0x27, 0x10, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x27, 0x10, 0x00,
- 0x00, 0x03, 0xcb, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1b, 0xe5,
- 0x00, 0x00, 0x27, 0x10, 0x00, 0x28, 0x82, 0x9a, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x6a, 0x82, 0x9d, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x72, 0x88, 0x22, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x90, 0x00,
- 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90,
- 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03, 0x7a,
- 0x90, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03,
- 0x8e, 0x91, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02,
- 0x03, 0x00, 0x91, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x03, 0xa2, 0x92, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x03, 0xaa, 0x92, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x03, 0xb2, 0x92, 0x04, 0x00, 0x0a, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x03, 0xba, 0x92, 0x05, 0x00, 0x05, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xc2, 0x92, 0x07, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x92, 0x08, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92,
- 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xca,
- 0x92, 0x7c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x92, 0x86, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
- 0x03, 0xd2, 0xa0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30,
- 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x60, 0x00, 0x00, 0xa0, 0x03, 0x00, 0x03, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x0e, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xe8, 0xa2, 0x0f, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xf0, 0xa2, 0x10,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0xa2,
- 0x17, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00,
- 0xa3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00,
- 0x00, 0xa3, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
- 0x00, 0x00, 0xa4, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x04, 0x00, 0x05, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x03, 0xf8, 0xa4, 0x05, 0x00, 0x03, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x07, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08,
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4,
- 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0xa4, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0xa4, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00,
- 0x00, 0x27, 0x10, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64,
- 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
- 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x33, 0x31, 0x00, 0x32, 0x30,
- 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20, 0x31, 0x33,
- 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x00, 0x00, 0x29, 0x88,
- 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0xb2, 0x00, 0x00, 0x00,
- 0x64, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x25, 0x00,
- 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0e, 0x92, 0x00, 0x00, 0x03, 0xe8,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x30, 0x30,
- 0x38, 0x31, 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31,
- 0x00, 0x00, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x2a,
- 0xe2, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x04, 0x52, 0x39, 0x38, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00,
- 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x06, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06,
- 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x04, 0x6c, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x04, 0x74, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x04, 0x7c, 0x02, 0x02, 0x00, 0x04, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x8b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84,
- 0x00, 0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
- 0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30, 0x2c, 0x2c, 0x30,
- 0x62, 0x46, 0x4a, 0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66,
- 0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a, 0x6e,
- 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c,
- 0x9a, 0xe2, 0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0x01,
- 0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6,
- 0x84, 0x70, 0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
- 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xff, 0xc0,
- 0x00, 0x11, 0x08, 0x00, 0x78, 0x00, 0xa0, 0x03, 0x01, 0x21, 0x00,
- 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00,
- 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
- 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03,
- 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
- 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
- 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81,
- 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
- 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
- 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
- 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
- 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92,
- 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
- 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
- 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
- 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
- 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
- 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00,
- 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
- 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
- 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
- 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
- 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
- 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15,
- 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
- 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
- 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
- 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
- 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
- 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5,
- 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
- 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
- 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2,
- 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00,
- 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
- 0x14, 0x54, 0xaa, 0x2a, 0x46, 0x48, 0xa2, 0xa4, 0x55, 0xa6, 0x04,
- 0x8a, 0x29, 0xe0, 0x53, 0x10, 0xe0, 0x29, 0xc0, 0x50, 0x03, 0xb1,
- 0x46, 0x29, 0x80, 0x84, 0x52, 0x11, 0x40, 0x0d, 0x22, 0x9a, 0x45,
- 0x20, 0x23, 0x61, 0x51, 0x30, 0xa0, 0x08, 0xc8, 0xa8, 0xd8, 0x52,
- 0x02, 0x26, 0x15, 0x0b, 0x0a, 0x00, 0xb4, 0xa2, 0xa5, 0x5a, 0x00,
- 0x91, 0x45, 0x4a, 0xa2, 0x81, 0x92, 0x01, 0x4e, 0x02, 0x98, 0x87,
- 0x0a, 0x70, 0xa0, 0x07, 0x62, 0x8c, 0x50, 0x21, 0x0d, 0x25, 0x00,
- 0x34, 0x8a, 0x61, 0x14, 0x0c, 0x63, 0x0a, 0x89, 0x85, 0x00, 0x46,
- 0xd5, 0x1b, 0x52, 0x02, 0x16, 0xa8, 0x98, 0x50, 0x05, 0x94, 0xa9,
- 0x16, 0x80, 0x25, 0x5a, 0x95, 0x68, 0x18, 0xf1, 0x4f, 0x14, 0xc4,
- 0x3b, 0xb5, 0x22, 0xb6, 0x38, 0x34, 0x00, 0xe3, 0x22, 0x8e, 0xf4,
- 0x79, 0x8a, 0x7b, 0xd1, 0x71, 0x03, 0x30, 0xc7, 0x14, 0x83, 0xa5,
- 0x00, 0x06, 0x98, 0x68, 0x01, 0x8d, 0x51, 0x35, 0x03, 0x22, 0x6a,
- 0x8d, 0xa9, 0x01, 0x13, 0x54, 0x4d, 0x40, 0x13, 0xa5, 0x4a, 0x28,
- 0x02, 0x45, 0x35, 0x2a, 0x9a, 0x00, 0x78, 0x34, 0xf0, 0x69, 0x80,
- 0x34, 0x81, 0x45, 0x40, 0xce, 0x58, 0xe6, 0xa2, 0x4c, 0x06, 0xe4,
- 0xfa, 0xd1, 0x93, 0x50, 0x21, 0xca, 0xe4, 0x55, 0x84, 0x90, 0x30,
- 0xab, 0x8b, 0x18, 0xa6, 0x9a, 0x6a, 0xc4, 0x31, 0xaa, 0x26, 0xa0,
- 0x64, 0x4d, 0x51, 0xb5, 0x20, 0x23, 0x6a, 0x89, 0xa8, 0x02, 0x44,
- 0x35, 0x2a, 0x9a, 0x00, 0x95, 0x4d, 0x48, 0xa6, 0x80, 0x24, 0x53,
- 0x4e, 0xce, 0x05, 0x30, 0x2b, 0x3b, 0xee, 0x6a, 0x91, 0x5d, 0x76,
- 0x63, 0xbd, 0x65, 0x7d, 0x40, 0x66, 0x68, 0xa9, 0x02, 0x45, 0x2b,
- 0xb3, 0x9e, 0xb4, 0xc5, 0x6d, 0xad, 0x9a, 0xa0, 0x2c, 0x06, 0xc8,
- 0xcd, 0x04, 0xd6, 0xa2, 0x23, 0x63, 0x51, 0xb1, 0xa0, 0x64, 0x4d,
- 0x51, 0x93, 0x48, 0x08, 0xda, 0xa2, 0x6a, 0x00, 0x72, 0x1a, 0x99,
- 0x4d, 0x00, 0x48, 0xa6, 0xa4, 0x53, 0x4c, 0x07, 0x86, 0x03, 0xbd,
- 0x2b, 0x9c, 0xa7, 0x14, 0x98, 0x10, 0x85, 0x34, 0xe0, 0xa6, 0xb3,
- 0xb0, 0x0b, 0xb5, 0xa8, 0x0a, 0xd4, 0x58, 0x42, 0xed, 0x3e, 0x94,
- 0xd2, 0xa6, 0x8b, 0x01, 0x34, 0x44, 0xed, 0xe6, 0x9c, 0x4d, 0x6a,
- 0x80, 0x8d, 0x8d, 0x46, 0xc6, 0x80, 0x23, 0x63, 0x51, 0x9a, 0x06,
- 0x46, 0xd5, 0x13, 0x52, 0x01, 0x54, 0xd4, 0xaa, 0x68, 0x02, 0x40,
- 0x6a, 0x40, 0x78, 0xa0, 0x08, 0x59, 0xce, 0xee, 0xb5, 0x2a, 0x39,
- 0xd9, 0x59, 0xa7, 0xa8, 0x00, 0x73, 0xeb, 0x4e, 0x0e, 0x7d, 0x69,
- 0x5c, 0x05, 0xf3, 0x0f, 0xad, 0x1e, 0x61, 0xf5, 0xa7, 0x71, 0x0b,
- 0xe6, 0x35, 0x21, 0x90, 0xd3, 0xb8, 0x0e, 0x32, 0x10, 0x95, 0x10,
- 0x91, 0xb3, 0xd6, 0x9b, 0x60, 0x4b, 0x9c, 0x8a, 0x63, 0x1a, 0xb0,
- 0x18, 0x4d, 0x46, 0xc6, 0x80, 0x22, 0x6a, 0x61, 0xa4, 0x31, 0xaa,
- 0x6a, 0x55, 0x34, 0x01, 0x2a, 0x9a, 0x7e, 0x78, 0xa0, 0x08, 0x09,
- 0xf9, 0xaa, 0x58, 0xcf, 0xca, 0x6b, 0x3e, 0xa0, 0x00, 0xd3, 0x81,
- 0xa9, 0x01, 0x73, 0x46, 0x69, 0x80, 0xb9, 0xa4, 0xcd, 0x00, 0x2b,
- 0x1f, 0x92, 0xa3, 0x07, 0x9a, 0x6f, 0x70, 0x26, 0xcf, 0x14, 0xd2,
- 0x6b, 0x51, 0x0c, 0x63, 0x51, 0xb1, 0xa0, 0x08, 0xda, 0x98, 0x69,
- 0x0c, 0x8d, 0x4d, 0x4a, 0xa6, 0x80, 0x24, 0x53, 0x52, 0x03, 0xc5,
- 0x02, 0x21, 0x27, 0xe6, 0xa9, 0x23, 0x3f, 0x29, 0xac, 0xfa, 0x8c,
- 0x01, 0xe6, 0x9c, 0x0d, 0x48, 0x0a, 0x0d, 0x2e, 0x68, 0x01, 0x73,
- 0x49, 0x9a, 0x60, 0x2b, 0x1f, 0x92, 0x98, 0x3a, 0xd3, 0x7b, 0x81,
- 0x36, 0x78, 0xa6, 0x93, 0x5a, 0x88, 0x8c, 0x9a, 0x63, 0x1a, 0x00,
- 0x8c, 0xd3, 0x0d, 0x21, 0x91, 0x29, 0xa9, 0x14, 0xd0, 0x04, 0x8a,
- 0x69, 0xe0, 0xd3, 0x11, 0x1b, 0x1e, 0x6a, 0x48, 0xcf, 0xca, 0x6b,
- 0x3e, 0xa3, 0x10, 0x1a, 0x70, 0x35, 0x20, 0x38, 0x1a, 0x5c, 0xd2,
- 0x01, 0x73, 0x49, 0x9a, 0x60, 0x39, 0x8f, 0xca, 0x29, 0x8b, 0xf7,
- 0xaa, 0xba, 0x88, 0x96, 0x9a, 0x6b, 0x40, 0x18, 0xc6, 0xa3, 0x26,
- 0x80, 0x18, 0x69, 0xa6, 0x90, 0xc8, 0x14, 0xd4, 0x8a, 0x69, 0x80,
- 0xf0, 0x6a, 0x40, 0x68, 0x10, 0xbb, 0x41, 0xa7, 0xe3, 0x0b, 0xc5,
- 0x2b, 0x01, 0x10, 0xa7, 0x03, 0x59, 0x0c, 0x76, 0x69, 0x73, 0x40,
- 0x0b, 0x9a, 0x28, 0x11, 0x28, 0x19, 0x5e, 0x69, 0x02, 0x81, 0x5a,
- 0xd8, 0x00, 0xd3, 0x4d, 0x50, 0x0c, 0x6a, 0x8c, 0xd2, 0x01, 0xa6,
- 0x98, 0x69, 0x0c, 0xae, 0xa6, 0xa4, 0x06, 0x80, 0x1e, 0xa6, 0x9e,
- 0x0d, 0x31, 0x12, 0x03, 0x4f, 0x06, 0x80, 0x13, 0x60, 0x34, 0xd3,
- 0xc1, 0xa8, 0x92, 0x01, 0xf1, 0x8d, 0xdd, 0x69, 0xcc, 0xa1, 0x69,
- 0x5b, 0x4b, 0x80, 0x83, 0x93, 0x52, 0x04, 0x14, 0xe2, 0xae, 0x03,
- 0xa9, 0x0d, 0x68, 0x03, 0x4d, 0x34, 0xd0, 0x03, 0x0d, 0x30, 0xd2,
- 0x01, 0x86, 0x9a, 0x68, 0x19, 0x58, 0x1a, 0x78, 0xa4, 0x04, 0x8a,
- 0x69, 0xe0, 0xd3, 0x10, 0xe0, 0x69, 0xe0, 0xd0, 0x03, 0xc1, 0xa8,
- 0xdb, 0xad, 0x4c, 0x81, 0x12, 0x45, 0xd6, 0x9d, 0x25, 0x1d, 0x00,
- 0x6a, 0xf5, 0xa9, 0xe8, 0x80, 0x31, 0x29, 0x0d, 0x58, 0x08, 0x69,
- 0x86, 0x80, 0x1a, 0x69, 0x86, 0x90, 0x0c, 0x34, 0xd3, 0x48, 0x65,
- 0x51, 0x4f, 0x06, 0x98, 0x0f, 0x14, 0xf0, 0x68, 0x10, 0xf0, 0x69,
- 0xe0, 0xd0, 0x03, 0x81, 0xa5, 0x2b, 0x9a, 0x1a, 0xb8, 0x87, 0xa8,
- 0xdb, 0x4a, 0x46, 0x68, 0xb6, 0x80, 0x2a, 0xa8, 0x14, 0xea, 0x12,
- 0xb0, 0x05, 0x21, 0xa6, 0x02, 0x1a, 0x61, 0xa0, 0x06, 0x9a, 0x61,
- 0xa4, 0x31, 0x86, 0x9a, 0x69, 0x0c, 0xa8, 0x0d, 0x3c, 0x53, 0x01,
- 0xe2, 0x9e, 0x28, 0x10, 0xf1, 0x4e, 0x06, 0x98, 0x0f, 0x06, 0x9e,
- 0x0d, 0x02, 0x1c, 0x29, 0xc2, 0x80, 0x16, 0x96, 0x80, 0x0a, 0x4a,
- 0x00, 0x43, 0x4d, 0x34, 0x0c, 0x61, 0xa6, 0x1a, 0x40, 0x34, 0xd3,
- 0x4d, 0x21, 0x80, 0xff, 0xd9, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0a,
- 0x07, 0x07, 0x08, 0x07, 0x06, 0x0a, 0x08, 0x08, 0x08, 0x0b, 0x0a,
- 0x0a, 0x0b, 0x0e, 0x18, 0x10, 0x0e, 0x0d, 0x0d, 0x0e, 0x1d, 0x15,
- 0x16, 0x11, 0x18, 0x23, 0x1f, 0x25, 0x24, 0x22, 0x1f, 0x22, 0x21,
- 0x26, 0x2b, 0x37, 0x2f, 0x26, 0x29, 0x34, 0x29, 0x21, 0x22, 0x30,
- 0x41, 0x31, 0x34, 0x39, 0x3b, 0x3e, 0x3e, 0x3e, 0x25, 0x2e, 0x44,
- 0x49, 0x43, 0x3c, 0x48, 0x37, 0x3d, 0x3e, 0x3b, 0x01, 0x0a, 0x0b,
- 0x0b, 0x0e, 0x0d, 0x0e, 0x1c, 0x10, 0x10, 0x1c, 0x3b, 0x28, 0x22,
- 0x28, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xc0, 0x00, 0x11,
- 0x08, 0x00, 0x48, 0x00, 0x60, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11,
- 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01,
- 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
- 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01,
- 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
- 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1,
- 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33,
- 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
- 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
- 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
- 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
- 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
- 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
- 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
- 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
- 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03,
- 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
- 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
- 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
- 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
- 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
- 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
- 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
- 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
- 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
- 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
- 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
- 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2,
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
- 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03,
- 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0x9e, 0xd2,
- 0x2e, 0x07, 0x15, 0xaf, 0x6d, 0x08, 0xe2, 0xb3, 0x45, 0x1a, 0xf6,
- 0xd0, 0x00, 0x01, 0xc5, 0x68, 0x45, 0x17, 0x4a, 0xb4, 0x22, 0xe4,
- 0x70, 0x8c, 0x74, 0xa9, 0x3c, 0xa1, 0x8e, 0x95, 0x48, 0x96, 0x31,
- 0xe2, 0x18, 0xe9, 0x55, 0xa5, 0x8c, 0x7a, 0x50, 0x05, 0x0b, 0x88,
- 0x86, 0x0f, 0x15, 0x8f, 0x75, 0x1f, 0x26, 0x93, 0x19, 0x91, 0x77,
- 0x18, 0xc1, 0xac, 0x4b, 0xc8, 0xfa, 0xd6, 0x63, 0x37, 0x6d, 0x31,
- 0xb4, 0x73, 0x5b, 0x36, 0xa0, 0x1c, 0x50, 0x80, 0xd7, 0x83, 0xa0,
- 0xab, 0xd1, 0x62, 0xad, 0x09, 0x8f, 0x17, 0x29, 0x03, 0xb2, 0xcc,
- 0xe0, 0x77, 0x14, 0xa3, 0x56, 0xb3, 0x27, 0x1e, 0x67, 0xe9, 0x52,
- 0xea, 0xc6, 0x3a, 0x36, 0x48, 0xef, 0x3d, 0x27, 0x70, 0x22, 0x60,
- 0x47, 0x52, 0x69, 0xb2, 0xe2, 0xad, 0x3b, 0xea, 0x80, 0xa3, 0x38,
- 0xe0, 0xd6, 0x3d, 0xd8, 0x1c, 0xd0, 0xca, 0x46, 0x3d, 0xd0, 0x18,
- 0x35, 0x89, 0x78, 0xa3, 0x9a, 0xcd, 0x8c, 0xd2, 0xb3, 0x93, 0x2a,
- 0x2b, 0x66, 0xd5, 0xf1, 0x8a, 0x10, 0x1a, 0xd6, 0xf2, 0x03, 0x8a,
- 0x9e, 0xe6, 0xf4, 0x5a, 0xdb, 0xef, 0xfe, 0x23, 0xc0, 0xa7, 0x27,
- 0xcb, 0x16, 0xc4, 0xcc, 0xdd, 0xe2, 0x78, 0x9a, 0x69, 0x66, 0xcc,
- 0x99, 0xe1, 0x4d, 0x47, 0xba, 0xbc, 0xd9, 0x6a, 0xee, 0x26, 0x59,
- 0x59, 0x4d, 0xac, 0x69, 0x34, 0x52, 0xe5, 0x8f, 0x55, 0xad, 0x58,
- 0xae, 0x85, 0xc4, 0x22, 0x41, 0xdf, 0xad, 0x76, 0x61, 0xe5, 0x6f,
- 0x74, 0x45, 0x69, 0xdc, 0x00, 0x79, 0xac, 0x8b, 0xa6, 0xc9, 0x35,
- 0xd4, 0x34, 0x64, 0xdc, 0x37, 0x06, 0xb1, 0xae, 0x88, 0xc1, 0xac,
- 0xd8, 0xc9, 0x2c, 0xa6, 0xe0, 0x73, 0x5b, 0x36, 0xf3, 0x74, 0xe6,
- 0x84, 0x05, 0xe3, 0xa9, 0x47, 0x6a, 0x14, 0xb6, 0x49, 0x3d, 0x85,
- 0x3a, 0xee, 0xee, 0x2b, 0xa8, 0xe2, 0x6f, 0x30, 0x81, 0xe9, 0x8a,
- 0xca, 0xa4, 0xe2, 0xd3, 0x8b, 0x01, 0xb1, 0xf9, 0x04, 0x7f, 0xaf,
- 0x23, 0xf0, 0xa9, 0x54, 0x41, 0x9c, 0xfd, 0xa3, 0xf4, 0xae, 0x65,
- 0x18, 0xf7, 0x25, 0x8a, 0xe2, 0x02, 0x38, 0xb8, 0xfd, 0x2a, 0x7b,
- 0x5b, 0xa8, 0x6d, 0x6d, 0x5d, 0x9a, 0x5d, 0xcb, 0xbb, 0xd2, 0xb6,
- 0xa6, 0xa3, 0x19, 0x5e, 0xe2, 0x03, 0x7b, 0x1d, 0xc2, 0x17, 0x8d,
- 0xb8, 0xac, 0xfb, 0x89, 0x39, 0x35, 0xd6, 0x9a, 0x6a, 0xe8, 0x66,
- 0x55, 0xcb, 0xf5, 0xac, 0x7b, 0x96, 0xeb, 0x50, 0xc6, 0x88, 0x6d,
- 0x66, 0xe9, 0xcd, 0x6c, 0xdb, 0x4f, 0xd3, 0x9a, 0x00, 0x2f, 0xe6,
- 0xf9, 0xa3, 0xe7, 0xb5, 0x4a, 0x93, 0x7f, 0xa2, 0xc6, 0x73, 0xdc,
- 0xd7, 0x15, 0x55, 0xef, 0x48, 0x7d, 0x09, 0x52, 0x6e, 0x3a, 0xd4,
- 0xab, 0x2f, 0xbd, 0x61, 0x16, 0x0c, 0x73, 0x49, 0xc5, 0x24, 0x92,
- 0x7f, 0xa2, 0x63, 0xfd, 0xaa, 0xd6, 0x2f, 0x71, 0x0e, 0xb1, 0x93,
- 0xf7, 0x2d, 0xf5, 0xa4, 0x9e, 0x4e, 0xb5, 0xdd, 0x4b, 0xf8, 0x68,
- 0x4c, 0xcb, 0xb9, 0x93, 0xad, 0x65, 0xce, 0xd9, 0x26, 0xa9, 0x8d,
- 0x19, 0xf6, 0xf2, 0xf4, 0xe6, 0xb5, 0xad, 0xe7, 0xc6, 0x39, 0xa0,
- 0x18, 0xeb, 0xc9, 0x77, 0x6c, 0x35, 0x2a, 0x4b, 0xfe, 0x8a, 0x9c,
- 0xff, 0x00, 0x11, 0xae, 0x3a, 0x8b, 0xde, 0x61, 0xd0, 0x9e, 0x39,
- 0xb8, 0xeb, 0x53, 0xac, 0xb9, 0xae, 0x5b, 0x00, 0xf3, 0x27, 0x14,
- 0x92, 0xc9, 0xfe, 0x8a, 0x3f, 0xde, 0x35, 0xac, 0x3a, 0x88, 0x92,
- 0xcd, 0xb1, 0x6e, 0x7d, 0xcd, 0x32, 0x67, 0xeb, 0xcd, 0x7a, 0x14,
- 0xfe, 0x04, 0x26, 0x66, 0xce, 0xf9, 0x26, 0xb3, 0xe6, 0x6e, 0xb4,
- 0xd9, 0x48, 0xc8, 0x82, 0x4e, 0x07, 0x35, 0xa7, 0x6f, 0x2f, 0x02,
- 0x9a, 0x06, 0x5f, 0x8c, 0xa4, 0x83, 0x0e, 0x32, 0x2a, 0x69, 0xe3,
- 0xdd, 0x12, 0x08, 0x97, 0x85, 0xec, 0x2a, 0x2a, 0x42, 0xf1, 0x76,
- 0x26, 0xe4, 0x6a, 0x59, 0x0e, 0x18, 0x10, 0x6a, 0xd2, 0x89, 0x02,
- 0x6e, 0x2a, 0x71, 0xeb, 0x5c, 0x1c, 0x8c, 0xa6, 0x48, 0xbb, 0xdc,
- 0x61, 0x41, 0x35, 0x72, 0x28, 0x87, 0xd9, 0xf6, 0x4a, 0xb9, 0xe7,
- 0x38, 0xae, 0x8c, 0x3d, 0x36, 0xdd, 0xde, 0xc4, 0xb0, 0x21, 0x51,
- 0x76, 0xa8, 0xc0, 0xaa, 0x93, 0x31, 0xe6, 0xbb, 0x2d, 0x65, 0x61,
- 0x19, 0xd3, 0x1e, 0xb5, 0x46, 0x5a, 0x96, 0x5a, 0x30, 0xa0, 0x7e,
- 0x05, 0x69, 0x5b, 0xc9, 0xc6, 0x28, 0x40, 0xcd, 0x08, 0x64, 0x3c,
- 0x73, 0x57, 0xe1, 0x94, 0xf1, 0xcd, 0x5a, 0x21, 0x8c, 0xb9, 0x63,
- 0xe7, 0x67, 0x1d, 0xab, 0x40, 0xb1, 0xfb, 0x00, 0x1d, 0xf0, 0x2b,
- 0x99, 0x2d, 0x66, 0x3e, 0x88, 0x75, 0x81, 0x3f, 0x31, 0xf6, 0xab,
- 0x64, 0xd6, 0xb4, 0x17, 0xee, 0xd0, 0x9e, 0xe4, 0x32, 0x1a, 0xa7,
- 0x31, 0xad, 0x18, 0x14, 0x26, 0xef, 0x54, 0xa5, 0xa8, 0x65, 0xa3,
- 0x9c, 0x81, 0xfa, 0x56, 0x8c, 0x2d, 0xce, 0x68, 0x40, 0xcb, 0xf1,
- 0x37, 0xbd, 0x5e, 0x85, 0xea, 0xd1, 0x0c, 0xbb, 0x19, 0x56, 0x23,
- 0x20, 0x1f, 0xad, 0x5c, 0x42, 0x08, 0x03, 0xb5, 0x55, 0x91, 0x04,
- 0xc9, 0x80, 0x38, 0x00, 0x0a, 0x71, 0x34, 0x6c, 0x32, 0x27, 0xe9,
- 0x55, 0x25, 0x15, 0x2c, 0x68, 0xa3, 0x30, 0xeb, 0x54, 0xa5, 0x15,
- 0x0c, 0xd1, 0x00, 0xff, 0xd9};
- int length = photoIntArray.length;
- byte[] photoByteArray = new byte[length];
- for (int i = 0; i < length; i++) {
- photoByteArray[i] = (byte)photoIntArray[i];
- }
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "Gump;Forrest;Hoge;Pos;Tao",
- Arrays.asList("Gump", "Forrest",
- "Hoge", "Pos", "Tao"),
- null, null, null, null),
- new PropertyNode("FN", "Joe Due",
- null, null, null, null, null),
- new PropertyNode("ORG",
- "Gump Shrimp Co.;Sales Dept.;Manager;Fish keeper",
- Arrays.asList("Gump Shrimp Co.",
- "Sales Dept.;Manager",
- "Fish keeper"),
- null, null, null, null),
- new PropertyNode("ROLE", "Fish Cake Keeper!",
- null, null, null, null, null),
- new PropertyNode("TITLE", "Shrimp Man",
- null, null, null, null, null),
- new PropertyNode("X-CLASS", "PUBLIC",
- null, null, null, null, null),
- new PropertyNode("TEL", "(111) 555-1212",
- null, null, null,
- new HashSet<String>(Arrays.asList("WORK", "VOICE")), null),
- new PropertyNode("TEL", "(404) 555-1212",
- null, null, null,
- new HashSet<String>(Arrays.asList("HOME", "VOICE")), null),
- new PropertyNode("TEL", "0311111111",
- null, null, null,
- new HashSet<String>(Arrays.asList("CELL")), null),
- new PropertyNode("TEL", "0322222222",
- null, null, null,
- new HashSet<String>(Arrays.asList("VIDEO")), null),
- new PropertyNode("TEL", "0333333333",
- null, null, null,
- new HashSet<String>(Arrays.asList("VOICE")), null),
- new PropertyNode("ADR",
- ";;100 Waters Edge;Baytown;LA;30314;United States of America",
- Arrays.asList("", "", "100 Waters Edge", "Baytown",
- "LA", "30314", "United States of America"),
- null, null,
- new HashSet<String>(Arrays.asList("WORK")), null),
- new PropertyNode("LABEL",
- "100 Waters Edge\r\nBaytown, LA 30314\r\nUnited States of America",
- null, null, contentValuesForQP,
- new HashSet<String>(Arrays.asList("WORK")), null),
- new PropertyNode("ADR",
- ";;42 Plantation St.;Baytown;LA;30314;United States of America",
- Arrays.asList("", "", "42 Plantation St.", "Baytown",
- "LA", "30314", "United States of America"), null, null,
- new HashSet<String>(Arrays.asList("HOME")), null),
- new PropertyNode("LABEL",
- "42 Plantation St.\r\nBaytown, LA 30314\r\nUnited States of America",
- null, null, contentValuesForQP,
- new HashSet<String>(Arrays.asList("HOME")), null),
- new PropertyNode("EMAIL", "forrestgump@walladalla.com",
- null, null, null,
- new HashSet<String>(Arrays.asList("PREF", "INTERNET")), null),
- new PropertyNode("EMAIL", "cell@example.com",
- null, null, null,
- new HashSet<String>(Arrays.asList("CELL")), null),
- new PropertyNode("NOTE", "The following note is the example from RFC 2045.",
- null, null, null, null, null),
- new PropertyNode("NOTE",
- "Now's the time for all folk to come to the aid of their country.",
- null, null, contentValuesForQP, null, null),
- new PropertyNode("PHOTO", null,
- null, photoByteArray, contentValuesForPhoto,
- new HashSet<String>(Arrays.asList("JPEG")), null),
- new PropertyNode("X-ATTRIBUTE", "Some String",
- null, null, null, null, null),
- new PropertyNode("BDAY", "19800101",
- null, null, null, null, null),
- new PropertyNode("GEO", "35.6563854,139.6994233",
- null, null, null, null, null),
- new PropertyNode("URL", "http://www.example.com/",
- null, null, null, null, null),
- new PropertyNode("REV", "20080424T195243Z",
- null, null, null, null, null));
- verifier.verify(builder.vNodeList.get(0));
- }
-
- public void testV21Japanese1() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_1);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- ContentValues contentValuesForShiftJis = new ContentValues();
- contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
- ContentValues contentValuesForQP = new ContentValues();
- contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
- contentValuesForQP.put("CHARSET", "SHIFT_JIS");
- // Though Japanese careers append ";;;;" at the end of the value of "SOUND",
- // vCard 2.1/3.0 specification does not allow multiple values.
- // Do not need to handle it as multiple values.
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
- null, contentValuesForShiftJis, null, null),
- new PropertyNode("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E;;;;",
- null, null, contentValuesForShiftJis,
- new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
- new PropertyNode("TEL", "0300000000",
- null, null, null,
- new HashSet<String>(Arrays.asList("VOICE", "PREF")), null));
- verifier.verify(builder.vNodeList.get(0));
- }
-
- public void testV21Japanese2() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_2);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- ContentValues contentValuesForShiftJis = new ContentValues();
- contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
- ContentValues contentValuesForQP = new ContentValues();
- contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
- contentValuesForQP.put("CHARSET", "SHIFT_JIS");
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
- Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
- "", "", ""),
- null, contentValuesForShiftJis, null, null),
- new PropertyNode("FN",
- "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031",
- null, null, contentValuesForShiftJis, null, null),
- new PropertyNode("SOUND",
- ("\uFF71\uFF9D\uFF84\uFF9E\uFF73" +
- ";\uFF9B\uFF72\uFF84\uFF9E\u0031;;;"),
- null, null, contentValuesForShiftJis,
- new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
- new PropertyNode("ADR",
- (";\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
- "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
- "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC\u0036" +
- "\u968E;;;;150-8512;"),
- Arrays.asList("",
- "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
- "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
- "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
- "\u0036\u968E", "", "", "", "150-8512", ""),
- null, contentValuesForQP,
- new HashSet<String>(Arrays.asList("HOME")), null),
- new PropertyNode("NOTE", "\u30E1\u30E2",
- null, null, contentValuesForQP, null, null));
- verifier.verify(builder.vNodeList.get(0));
- }
-
- public void testV21MultipleEntryCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V21();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(3, builder.vNodeList.size());
- ContentValues contentValuesForShiftJis = new ContentValues();
- contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
- null, contentValuesForShiftJis, null, null),
- new PropertyNode("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033;;;;",
- null, null, contentValuesForShiftJis,
- new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
- new PropertyNode("TEL", "9",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-SECRET")), null),
- new PropertyNode("TEL", "10",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-HOTEL")), null),
- new PropertyNode("TEL", "11",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-SCHOOL")), null),
- new PropertyNode("TEL", "12",
- null, null, null,
- new HashSet<String>(Arrays.asList("FAX", "HOME")), null));
- verifier.verify(builder.vNodeList.get(0));
-
- verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
- null, contentValuesForShiftJis, null, null),
- new PropertyNode("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034;;;;",
- null, null, contentValuesForShiftJis,
- new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
- new PropertyNode("TEL", "13",
- null, null, null,
- new HashSet<String>(Arrays.asList("MODEM")), null),
- new PropertyNode("TEL", "14",
- null, null, null,
- new HashSet<String>(Arrays.asList("PAGER")), null),
- new PropertyNode("TEL", "15",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-FAMILY")), null),
- new PropertyNode("TEL", "16",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-GIRL")), null));
- verifier.verify(builder.vNodeList.get(1));
- verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "2.1",
- null, null, null, null, null),
- new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
- Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
- null, contentValuesForShiftJis, null, null),
- new PropertyNode("SOUND",
- "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035;;;;",
- null, null, contentValuesForShiftJis,
- new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
- new PropertyNode("TEL", "17",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-BOY")), null),
- new PropertyNode("TEL", "18",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-FRIEND")), null),
- new PropertyNode("TEL", "19",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-PHS")), null),
- new PropertyNode("TEL", "20",
- null, null, null,
- new HashSet<String>(Arrays.asList("X-NEC-RESTAURANT")), null));
- verifier.verify(builder.vNodeList.get(2));
- }
-
- public void testV30SimpleCase() throws IOException, VCardException {
- VCardParser_V21 parser = new VCardParser_V30();
- VDataBuilder builder = new VDataBuilder();
- InputStream is = getContext().getResources().openRawResource(R.raw.v30_simple);
- assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
- is.close();
- assertEquals(1, builder.vNodeList.size());
- PropertyNodesVerifier verifier = new PropertyNodesVerifier(
- new PropertyNode("VERSION", "3.0",
- null, null, null, null, null),
- new PropertyNode("FN", "And Roid",
- null, null, null, null, null),
- new PropertyNode("N", "And;Roid;;;",
- Arrays.asList("And", "Roid", "", "", ""),
- null, null, null, null),
- new PropertyNode("ORG", "Open;Handset; Alliance",
- Arrays.asList("Open", "Handset", " Alliance"),
- null, null, null, null),
- new PropertyNode("SORT-STRING", "android", null, null, null, null, null),
- new PropertyNode("TEL", "0300000000",
- null, null, null,
- new HashSet<String>(Arrays.asList("PREF", "VOICE")), null),
- new PropertyNode("CLASS", "PUBLIC", null, null, null, null, null),
- new PropertyNode("X-GNO", "0", null, null, null, null, null),
- new PropertyNode("X-GN", "group0", null, null, null, null, null),
- new PropertyNode("X-REDUCTION", "0",
- null, null, null, null, null),
- new PropertyNode("REV", "20081031T065854Z",
- null, null, null, null, null));
- verifier.verify(builder.vNodeList.get(0));
- }
-}
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..1e4f161
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/accounts/AccountManagerServiceTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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;
+
+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.type.compareTo(object2.type);
+ if (result != 0) return result;
+ return object1.name.compareTo(object2.name);
+ }
+ }
+
+ 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");
+ ams.addAccount(a11, "p11", null);
+ ams.addAccount(a12, "p12", null);
+ ams.addAccount(a21, "p21", null);
+ ams.addAccount(a22, "p22", null);
+ ams.addAccount(a31, "p31", null);
+ ams.addAccount(a32, "p32", null);
+
+ Account[] accounts = ams.getAccounts(null);
+ 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(null, 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");
+ ams.addAccount(a11, "p11", null);
+ 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");
+ ams.addAccount(a11, "p11", u11);
+ 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");
+ ams.addAccount(a11, "p11", null);
+ 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.type, "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/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java
new file mode 100644
index 0000000..0ee74df
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNode.java
@@ -0,0 +1,322 @@
+/*
+ * 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.vcard;
+
+import android.content.ContentValues;
+
+import org.apache.commons.codec.binary.Base64;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.regex.Pattern;
+
+/**
+ * @hide old class just for test
+ */
+public class PropertyNode {
+ public String propName;
+ public String propValue;
+ public List<String> propValue_vector;
+
+ /** Store value as byte[],after decode.
+ * Used when propValue is encoded by something like BASE64, QUOTED-PRINTABLE, etc.
+ */
+ public byte[] propValue_bytes;
+
+ /** param store: key=paramType, value=paramValue
+ * Note that currently PropertyNode class does not support multiple param-values
+ * defined in vCard 3.0 (See also RFC 2426). multiple-values are stored as
+ * one String value like "A,B", not ["A", "B"]...
+ * TODO: fix this.
+ */
+ public ContentValues paramMap;
+
+ /** Only for TYPE=??? param store. */
+ public Set<String> paramMap_TYPE;
+
+ /** Store group values. Used only in VCard. */
+ public Set<String> propGroupSet;
+
+ public PropertyNode() {
+ propName = "";
+ propValue = "";
+ propValue_vector = new ArrayList<String>();
+ paramMap = new ContentValues();
+ paramMap_TYPE = new HashSet<String>();
+ propGroupSet = new HashSet<String>();
+ }
+
+ public PropertyNode(
+ String propName, String propValue, List<String> propValue_vector,
+ byte[] propValue_bytes, ContentValues paramMap, Set<String> paramMap_TYPE,
+ Set<String> propGroupSet) {
+ if (propName != null) {
+ this.propName = propName;
+ } else {
+ this.propName = "";
+ }
+ if (propValue != null) {
+ this.propValue = propValue;
+ } else {
+ this.propValue = "";
+ }
+ if (propValue_vector != null) {
+ this.propValue_vector = propValue_vector;
+ } else {
+ this.propValue_vector = new ArrayList<String>();
+ }
+ this.propValue_bytes = propValue_bytes;
+ if (paramMap != null) {
+ this.paramMap = paramMap;
+ } else {
+ this.paramMap = new ContentValues();
+ }
+ if (paramMap_TYPE != null) {
+ this.paramMap_TYPE = paramMap_TYPE;
+ } else {
+ this.paramMap_TYPE = new HashSet<String>();
+ }
+ if (propGroupSet != null) {
+ this.propGroupSet = propGroupSet;
+ } else {
+ this.propGroupSet = new HashSet<String>();
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PropertyNode)) {
+ return false;
+ }
+
+ PropertyNode node = (PropertyNode)obj;
+
+ if (propName == null || !propName.equals(node.propName)) {
+ return false;
+ } else if (!paramMap.equals(node.paramMap)) {
+ return false;
+ } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
+ return false;
+ } else if (!propGroupSet.equals(node.propGroupSet)) {
+ return false;
+ }
+
+ if (propValue_bytes != null && Arrays.equals(propValue_bytes, node.propValue_bytes)) {
+ return true;
+ } else {
+ // Log.d("@@@", propValue + ", " + node.propValue);
+ if (!propValue.equals(node.propValue)) {
+ return false;
+ }
+
+ // The value in propValue_vector is not decoded even if it should be
+ // decoded by BASE64 or QUOTED-PRINTABLE. When the size of propValue_vector
+ // is 1, the encoded value is stored in propValue, so we do not have to
+ // check it.
+ return (propValue_vector.equals(node.propValue_vector) ||
+ propValue_vector.size() == 1 ||
+ node.propValue_vector.size() == 1);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("propName: ");
+ builder.append(propName);
+ builder.append(", paramMap: ");
+ builder.append(paramMap.toString());
+ builder.append(", propmMap_TYPE: ");
+ builder.append(paramMap_TYPE.toString());
+ builder.append(", propGroupSet: ");
+ builder.append(propGroupSet.toString());
+ if (propValue_vector != null && propValue_vector.size() > 1) {
+ builder.append(", propValue_vector size: ");
+ builder.append(propValue_vector.size());
+ }
+ if (propValue_bytes != null) {
+ builder.append(", propValue_bytes size: ");
+ builder.append(propValue_bytes.length);
+ }
+ builder.append(", propValue: ");
+ builder.append(propValue);
+ return builder.toString();
+ }
+
+ /**
+ * Encode this object into a string which can be decoded.
+ */
+ public String encode() {
+ // PropertyNode#toString() is for reading, not for parsing in the future.
+ // We construct appropriate String here.
+ StringBuilder builder = new StringBuilder();
+ if (propName.length() > 0) {
+ builder.append("propName:[");
+ builder.append(propName);
+ builder.append("],");
+ }
+ int size = propGroupSet.size();
+ if (size > 0) {
+ Set<String> set = propGroupSet;
+ builder.append("propGroup:[");
+ int i = 0;
+ for (String group : set) {
+ // We do not need to double quote groups.
+ // group = 1*(ALPHA / DIGIT / "-")
+ builder.append(group);
+ if (i < size - 1) {
+ builder.append(",");
+ }
+ i++;
+ }
+ builder.append("],");
+ }
+
+ if (paramMap.size() > 0 || paramMap_TYPE.size() > 0) {
+ ContentValues values = paramMap;
+ builder.append("paramMap:[");
+ size = paramMap.size();
+ int i = 0;
+ for (Entry<String, Object> entry : values.valueSet()) {
+ // Assuming param-key does not contain NON-ASCII nor symbols.
+ //
+ // According to vCard 3.0:
+ // param-name = iana-token / x-name
+ builder.append(entry.getKey());
+
+ // param-value may contain any value including NON-ASCIIs.
+ // We use the following replacing rule.
+ // \ -> \\
+ // , -> \,
+ // In String#replaceAll(), "\\\\" means a single backslash.
+ builder.append("=");
+ builder.append(entry.getValue().toString()
+ .replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll(",", "\\\\,"));
+ if (i < size -1) {
+ builder.append(",");
+ }
+ i++;
+ }
+
+ Set<String> set = paramMap_TYPE;
+ size = paramMap_TYPE.size();
+ if (i > 0 && size > 0) {
+ builder.append(",");
+ }
+ i = 0;
+ for (String type : set) {
+ builder.append("TYPE=");
+ builder.append(type
+ .replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll(",", "\\\\,"));
+ if (i < size - 1) {
+ builder.append(",");
+ }
+ i++;
+ }
+ builder.append("],");
+ }
+
+ size = propValue_vector.size();
+ if (size > 0) {
+ builder.append("propValue:[");
+ List<String> list = propValue_vector;
+ for (int i = 0; i < size; i++) {
+ builder.append(list.get(i)
+ .replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll(",", "\\\\,"));
+ if (i < size -1) {
+ builder.append(",");
+ }
+ }
+ builder.append("],");
+ }
+
+ return builder.toString();
+ }
+
+ public static PropertyNode decode(String encodedString) {
+ PropertyNode propertyNode = new PropertyNode();
+ String trimed = encodedString.trim();
+ if (trimed.length() == 0) {
+ return propertyNode;
+ }
+ String[] elems = trimed.split("],");
+
+ for (String elem : elems) {
+ int index = elem.indexOf('[');
+ String name = elem.substring(0, index - 1);
+ Pattern pattern = Pattern.compile("(?<!\\\\),");
+ String[] values = pattern.split(elem.substring(index + 1), -1);
+ if (name.equals("propName")) {
+ propertyNode.propName = values[0];
+ } else if (name.equals("propGroupSet")) {
+ for (String value : values) {
+ propertyNode.propGroupSet.add(value);
+ }
+ } else if (name.equals("paramMap")) {
+ ContentValues paramMap = propertyNode.paramMap;
+ Set<String> paramMap_TYPE = propertyNode.paramMap_TYPE;
+ for (String value : values) {
+ String[] tmp = value.split("=", 2);
+ String mapKey = tmp[0];
+ // \, -> ,
+ // \\ -> \
+ // In String#replaceAll(), "\\\\" means a single backslash.
+ String mapValue =
+ tmp[1].replaceAll("\\\\,", ",").replaceAll("\\\\\\\\", "\\\\");
+ if (mapKey.equalsIgnoreCase("TYPE")) {
+ paramMap_TYPE.add(mapValue);
+ } else {
+ paramMap.put(mapKey, mapValue);
+ }
+ }
+ } else if (name.equals("propValue")) {
+ StringBuilder builder = new StringBuilder();
+ List<String> list = propertyNode.propValue_vector;
+ int length = values.length;
+ for (int i = 0; i < length; i++) {
+ String normValue = values[i]
+ .replaceAll("\\\\,", ",")
+ .replaceAll("\\\\\\\\", "\\\\");
+ list.add(normValue);
+ builder.append(normValue);
+ if (i < length - 1) {
+ builder.append(";");
+ }
+ }
+ propertyNode.propValue = builder.toString();
+ }
+ }
+
+ // At this time, QUOTED-PRINTABLE is already decoded to Java String.
+ // We just need to decode BASE64 String to binary.
+ String encoding = propertyNode.paramMap.getAsString("ENCODING");
+ if (encoding != null &&
+ (encoding.equalsIgnoreCase("BASE64") ||
+ encoding.equalsIgnoreCase("B"))) {
+ propertyNode.propValue_bytes =
+ Base64.decodeBase64(propertyNode.propValue_vector.get(0).getBytes());
+ }
+
+ return propertyNode;
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java
new file mode 100644
index 0000000..7589ba8
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTests.java
@@ -0,0 +1,923 @@
+/*
+ * 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.vcard;
+
+import android.content.ContentValues;
+import android.pim.vcard.ContactStruct;
+import android.pim.vcard.EntryHandler;
+import android.pim.vcard.VCardParser_V21;
+import android.pim.vcard.VCardParser_V30;
+import android.pim.vcard.exception.VCardException;
+import android.test.AndroidTestCase;
+
+import com.android.unit_tests.R;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+public class VCardTests extends AndroidTestCase {
+
+ // TODO: Use EntityIterator, which is added in Eclair.
+ private static class EntryHolder implements EntryHandler {
+ public List<ContactStruct> contacts = new ArrayList<ContactStruct>();
+ public void onParsingStart() {
+ }
+ public void onEntryCreated(ContactStruct contactStruct) {
+ contacts.add(contactStruct);
+ }
+ public void onParsingEnd() {
+ }
+ }
+ /*
+ static void verify(ContactStruct expected, ContactStruct actual) {
+ if (!equalsString(expected.getName(), actual.getName())) {
+ fail(String.format("Names do not equal: \"%s\" != \"%s\"",
+ expected.getName(), actual.getName()));
+ }
+ if (!equalsString(
+ expected.getPhoneticName(), actual.getPhoneticName())) {
+ fail(String.format("Phonetic names do not equal: \"%s\" != \"%s\"",
+ expected.getPhoneticName(), actual.getPhoneticName()));
+ }
+ {
+ final byte[] expectedPhotoBytes = expected.getPhotoBytes();
+ final byte[] actualPhotoBytes = actual.getPhotoBytes();
+ if (!((expectedPhotoBytes == null && actualPhotoBytes == null) ||
+ Arrays.equals(expectedPhotoBytes, actualPhotoBytes))) {
+ fail("photoBytes is not equal.");
+ }
+ }
+ verifyInternal(expected.getNotes(), actual.getNotes(), "notes");
+ verifyInternal(expected.getPhoneList(), actual.getPhoneList(), "phones");
+ verifyInternal(expected.getContactMethodList(), actual.getContactMethodList(),
+ "contact lists");
+ verifyInternal(expected.getOrganizationList(), actual.getOrganizationList(),
+ "organizations");
+ {
+ final Map<String, List<String>> expectedMap =
+ expected.getExtensionMap();
+ final Map<String, List<String>> actualMap =
+ actual.getExtensionMap();
+ if (verifySize((expectedMap == null ? 0 : expectedMap.size()),
+ (actualMap == null ? 0 : actualMap.size()), "extensions") > 0) {
+ for (String key : expectedMap.keySet()) {
+ if (!actualMap.containsKey(key)) {
+ fail(String.format(
+ "Actual does not have %s extension while expected has",
+ key));
+ }
+ final List<String> expectedList = expectedMap.get(key);
+ final List<String> actualList = actualMap.get(key);
+ verifyInternal(expectedList, actualList,
+ String.format("extension \"%s\"", key));
+ }
+ }
+ }
+ }
+
+ private static boolean equalsString(String a, String b) {
+ if (a == null || a.length() == 0) {
+ return b == null || b.length() == 0;
+ } else {
+ return a.equals(b);
+ }
+ }
+
+ private static int verifySize(int expectedSize, int actualSize, String name) {
+ if (expectedSize != actualSize) {
+ fail(String.format("Size of %s is different: %d != %d",
+ name, expectedSize, actualSize));
+ }
+ return expectedSize;
+ }
+
+ private static <T> void verifyInternal(final List<T> expected, final List<T> actual,
+ String name) {
+ if(verifySize((expected == null ? 0 : expected.size()),
+ (actual == null ? 0 : actual.size()), name) > 0) {
+ int size = expected.size();
+ for (int i = 0; i < size; i++) {
+ final T expectedObj = expected.get(i);
+ final T actualObj = actual.get(i);
+ if (!expected.equals(actual)) {
+ fail(String.format("The %i %s are different: %s != %s",
+ i, name, expectedObj, actualObj));
+ }
+ }
+ }
+ }*/
+
+ private class PropertyNodesVerifier {
+ private HashMap<String, ArrayList<PropertyNode>> mPropertyNodeMap;
+ public PropertyNodesVerifier(PropertyNode... nodes) {
+ mPropertyNodeMap = new HashMap<String, ArrayList<PropertyNode>>();
+ for (PropertyNode propertyNode : nodes) {
+ String propName = propertyNode.propName;
+ ArrayList<PropertyNode> expectedNodes =
+ mPropertyNodeMap.get(propName);
+ if (expectedNodes == null) {
+ expectedNodes = new ArrayList<PropertyNode>();
+ mPropertyNodeMap.put(propName, expectedNodes);
+ }
+ expectedNodes.add(propertyNode);
+ }
+ }
+
+ public void verify(VNode vnode) {
+ for (PropertyNode propertyNode : vnode.propList) {
+ String propName = propertyNode.propName;
+ ArrayList<PropertyNode> nodes = mPropertyNodeMap.get(propName);
+ if (nodes == null) {
+ fail("Unexpected propName \"" + propName + "\" exists.");
+ }
+ boolean successful = false;
+ int size = nodes.size();
+ for (int i = 0; i < size; i++) {
+ PropertyNode expectedNode = nodes.get(i);
+ if (expectedNode.propName.equals(propName)) {
+ if (expectedNode.equals(propertyNode)) {
+ successful = true;
+ nodes.remove(i);
+ if (nodes.size() == 0) {
+ mPropertyNodeMap.remove(propName);
+ }
+ break;
+ } else {
+ fail("Property \"" + propName + "\" has wrong value.\n"
+ + "expected: " + expectedNode.toString()
+ + "\n actual: " + propertyNode.toString());
+ }
+ }
+ }
+ if (!successful) {
+ fail("Unexpected property \"" + propName + "\" exists.");
+ }
+ }
+ if (mPropertyNodeMap.size() != 0) {
+ ArrayList<String> expectedProps = new ArrayList<String>();
+ for (ArrayList<PropertyNode> nodes : mPropertyNodeMap.values()) {
+ for (PropertyNode node : nodes) {
+ expectedProps.add(node.propName);
+ }
+ }
+ fail("expected props " + Arrays.toString(expectedProps.toArray()) +
+ " was not found");
+ }
+ }
+ }
+
+ /*
+ public void testV21SimpleCase1_1() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
+ EntryHolder holder = new EntryHolder();
+ builder.addEntryHandler(holder);
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_1);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, holder.contacts.size());
+ verify(new ContactStruct("Roid Ando", null,
+ null, null, null, null, null, null),
+ holder.contacts.get(0));
+ }
+
+ public void testV21SimpleCase1_2() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_JAPANESE);
+ EntryHolder holder = new EntryHolder();
+ builder.addEntryHandler(holder);
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_1);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, holder.contacts.size());
+ verify(new ContactStruct("Ando Roid", null,
+ null, null, null, null, null, null),
+ holder.contacts.get(0));
+ }
+
+ public void testV21SimpleCase2() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
+ EntryHolder holder = new EntryHolder();
+ builder.addEntryHandler(holder);
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_2);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, holder.contacts.size());
+ verify(new ContactStruct("Ando Roid", null,
+ null, null, null, null, null, null),
+ holder.contacts.get(0));
+ }
+
+ public void testV21SimpleCase3() throws IOException, VCardException {
+ VCardParser parser = new VCardParser_V21();
+ VCardDataBuilder builder1 = new VCardDataBuilder(VCardConfig.NAME_ORDER_TYPE_ENGLISH);
+ EntryHolder holder = new EntryHolder();
+ builder1.addEntryHandler(holder);
+ VNodeBuilder builder2 = new VNodeBuilder();
+ VCardBuilderCollection collection =
+ new VCardBuilderCollection(
+ new ArrayList<VCardBuilder>(Arrays.asList(builder1, builder2)));
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_simple_3);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", collection));
+ is.close();
+
+ assertEquals(1, builder2.vNodeList.size());
+ VNode vnode = builder2.vNodeList.get(0);
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("N", "Ando;Roid;",
+ Arrays.asList("Ando", "Roid", ""),
+ null, null, null, null),
+ new PropertyNode("FN", "Ando Roid",
+ null, null, null, null, null));
+ verifier.verify(vnode);
+
+ // FN is prefered.
+ assertEquals(1, holder.contacts.size());
+ ContactStruct actual = holder.contacts.get(0);
+ verify(new ContactStruct("Ando Roid", null,
+ null, null, null, null, null, null),
+ actual);
+ }*/
+
+ public void testV21BackslashCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_backslash);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", ";A;B\\;C\\;;D;:E;\\\\;",
+ Arrays.asList("", "A;B\\", "C\\;", "D", ":E", "\\\\", ""),
+ null, null, null, null),
+ new PropertyNode("FN", "A;B\\C\\;D:E\\\\",
+ null, null, null, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21ComplicatedCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_complicated);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ ContentValues contentValuesForQP = new ContentValues();
+ contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
+ ContentValues contentValuesForPhoto = new ContentValues();
+ contentValuesForPhoto.put("ENCODING", "BASE64");
+ // Push data into int array at first since values like 0x80 are
+ // interpreted as int by the compiler and casting all of them is
+ // cumbersome...
+ int[] photoIntArray = {
+ 0xff, 0xd8, 0xff, 0xe1, 0x0a, 0x0f, 0x45, 0x78, 0x69, 0x66, 0x00,
+ 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d,
+ 0x01, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
+ 0xaa, 0x01, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
+ 0x00, 0xba, 0x01, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0xc2, 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x28, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x32, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xe6, 0x02, 0x13,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x82,
+ 0x98, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xfa,
+ 0x87, 0x69, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x84, 0xc4, 0xa5, 0x00, 0x07, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x01, 0x08, 0x00, 0x00, 0x04, 0x1e, 0x32, 0x30, 0x30, 0x38, 0x31,
+ 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31, 0x00, 0x00,
+ 0x44, 0x6f, 0x43, 0x6f, 0x4d, 0x6f, 0x00, 0x00, 0x44, 0x39, 0x30,
+ 0x35, 0x69, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x44, 0x39, 0x30,
+ 0x35, 0x69, 0x20, 0x56, 0x65, 0x72, 0x31, 0x2e, 0x30, 0x30, 0x00,
+ 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
+ 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x49, 0x4d, 0x00, 0x30, 0x33,
+ 0x30, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x14, 0x00,
+ 0x14, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x34, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x09, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x0f, 0x0b, 0x00,
+ 0x00, 0x27, 0x10, 0x00, 0x00, 0x05, 0x97, 0x00, 0x00, 0x27, 0x10,
+ 0x00, 0x00, 0x08, 0xb0, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1c,
+ 0x01, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x02, 0x5e, 0x00, 0x00,
+ 0x27, 0x10, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x27, 0x10, 0x00,
+ 0x00, 0x03, 0xcb, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x1b, 0xe5,
+ 0x00, 0x00, 0x27, 0x10, 0x00, 0x28, 0x82, 0x9a, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x6a, 0x82, 0x9d, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x72, 0x88, 0x22, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x90, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30, 0x32, 0x32, 0x30, 0x90,
+ 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03, 0x7a,
+ 0x90, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03,
+ 0x8e, 0x91, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02,
+ 0x03, 0x00, 0x91, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x03, 0xa2, 0x92, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x03, 0xaa, 0x92, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x03, 0xb2, 0x92, 0x04, 0x00, 0x0a, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x03, 0xba, 0x92, 0x05, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xc2, 0x92, 0x07, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x92, 0x08, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92, 0x09,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x92,
+ 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xca,
+ 0x92, 0x7c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x92, 0x86, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
+ 0x03, 0xd2, 0xa0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x30,
+ 0x31, 0x30, 0x30, 0xa0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x60, 0x00, 0x00, 0xa0, 0x03, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x48, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x0e, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xe8, 0xa2, 0x0f, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xf0, 0xa2, 0x10,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0xa2,
+ 0x17, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00,
+ 0xa3, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00,
+ 0x00, 0xa3, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0xa4, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0xa4, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x04, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x03, 0xf8, 0xa4, 0x05, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0xa4, 0x06, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x07, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4,
+ 0x09, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0xa4, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0xa4, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00,
+ 0x00, 0x27, 0x10, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64,
+ 0x32, 0x30, 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20,
+ 0x31, 0x33, 0x3a, 0x35, 0x35, 0x3a, 0x33, 0x31, 0x00, 0x32, 0x30,
+ 0x30, 0x38, 0x3a, 0x31, 0x30, 0x3a, 0x32, 0x39, 0x20, 0x31, 0x33,
+ 0x3a, 0x35, 0x35, 0x3a, 0x34, 0x37, 0x00, 0x00, 0x00, 0x29, 0x88,
+ 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0xb2, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x01, 0x5e, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x25, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0e, 0x92, 0x00, 0x00, 0x03, 0xe8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x30, 0x30,
+ 0x38, 0x31, 0x30, 0x32, 0x39, 0x31, 0x33, 0x35, 0x35, 0x33, 0x31,
+ 0x00, 0x00, 0x20, 0x2a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x2a,
+ 0xe2, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x04, 0x52, 0x39, 0x38, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00,
+ 0x00, 0x04, 0x30, 0x31, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06,
+ 0x00, 0x00, 0x01, 0x1a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x04, 0x6c, 0x01, 0x1b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x04, 0x74, 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x04, 0x7c, 0x02, 0x02, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x8b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x01, 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84,
+ 0x00, 0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
+ 0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30, 0x2c, 0x2c, 0x30,
+ 0x62, 0x46, 0x4a, 0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66,
+ 0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a, 0x6e,
+ 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c,
+ 0x9a, 0xe2, 0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0x01,
+ 0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6,
+ 0x84, 0x70, 0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xff, 0xc0,
+ 0x00, 0x11, 0x08, 0x00, 0x78, 0x00, 0xa0, 0x03, 0x01, 0x21, 0x00,
+ 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00,
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03,
+ 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01,
+ 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
+ 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81,
+ 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
+ 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+ 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92,
+ 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+ 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00,
+ 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
+ 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
+ 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
+ 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15,
+ 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17,
+ 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65,
+ 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
+ 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5,
+ 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+ 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2,
+ 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00,
+ 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
+ 0x14, 0x54, 0xaa, 0x2a, 0x46, 0x48, 0xa2, 0xa4, 0x55, 0xa6, 0x04,
+ 0x8a, 0x29, 0xe0, 0x53, 0x10, 0xe0, 0x29, 0xc0, 0x50, 0x03, 0xb1,
+ 0x46, 0x29, 0x80, 0x84, 0x52, 0x11, 0x40, 0x0d, 0x22, 0x9a, 0x45,
+ 0x20, 0x23, 0x61, 0x51, 0x30, 0xa0, 0x08, 0xc8, 0xa8, 0xd8, 0x52,
+ 0x02, 0x26, 0x15, 0x0b, 0x0a, 0x00, 0xb4, 0xa2, 0xa5, 0x5a, 0x00,
+ 0x91, 0x45, 0x4a, 0xa2, 0x81, 0x92, 0x01, 0x4e, 0x02, 0x98, 0x87,
+ 0x0a, 0x70, 0xa0, 0x07, 0x62, 0x8c, 0x50, 0x21, 0x0d, 0x25, 0x00,
+ 0x34, 0x8a, 0x61, 0x14, 0x0c, 0x63, 0x0a, 0x89, 0x85, 0x00, 0x46,
+ 0xd5, 0x1b, 0x52, 0x02, 0x16, 0xa8, 0x98, 0x50, 0x05, 0x94, 0xa9,
+ 0x16, 0x80, 0x25, 0x5a, 0x95, 0x68, 0x18, 0xf1, 0x4f, 0x14, 0xc4,
+ 0x3b, 0xb5, 0x22, 0xb6, 0x38, 0x34, 0x00, 0xe3, 0x22, 0x8e, 0xf4,
+ 0x79, 0x8a, 0x7b, 0xd1, 0x71, 0x03, 0x30, 0xc7, 0x14, 0x83, 0xa5,
+ 0x00, 0x06, 0x98, 0x68, 0x01, 0x8d, 0x51, 0x35, 0x03, 0x22, 0x6a,
+ 0x8d, 0xa9, 0x01, 0x13, 0x54, 0x4d, 0x40, 0x13, 0xa5, 0x4a, 0x28,
+ 0x02, 0x45, 0x35, 0x2a, 0x9a, 0x00, 0x78, 0x34, 0xf0, 0x69, 0x80,
+ 0x34, 0x81, 0x45, 0x40, 0xce, 0x58, 0xe6, 0xa2, 0x4c, 0x06, 0xe4,
+ 0xfa, 0xd1, 0x93, 0x50, 0x21, 0xca, 0xe4, 0x55, 0x84, 0x90, 0x30,
+ 0xab, 0x8b, 0x18, 0xa6, 0x9a, 0x6a, 0xc4, 0x31, 0xaa, 0x26, 0xa0,
+ 0x64, 0x4d, 0x51, 0xb5, 0x20, 0x23, 0x6a, 0x89, 0xa8, 0x02, 0x44,
+ 0x35, 0x2a, 0x9a, 0x00, 0x95, 0x4d, 0x48, 0xa6, 0x80, 0x24, 0x53,
+ 0x4e, 0xce, 0x05, 0x30, 0x2b, 0x3b, 0xee, 0x6a, 0x91, 0x5d, 0x76,
+ 0x63, 0xbd, 0x65, 0x7d, 0x40, 0x66, 0x68, 0xa9, 0x02, 0x45, 0x2b,
+ 0xb3, 0x9e, 0xb4, 0xc5, 0x6d, 0xad, 0x9a, 0xa0, 0x2c, 0x06, 0xc8,
+ 0xcd, 0x04, 0xd6, 0xa2, 0x23, 0x63, 0x51, 0xb1, 0xa0, 0x64, 0x4d,
+ 0x51, 0x93, 0x48, 0x08, 0xda, 0xa2, 0x6a, 0x00, 0x72, 0x1a, 0x99,
+ 0x4d, 0x00, 0x48, 0xa6, 0xa4, 0x53, 0x4c, 0x07, 0x86, 0x03, 0xbd,
+ 0x2b, 0x9c, 0xa7, 0x14, 0x98, 0x10, 0x85, 0x34, 0xe0, 0xa6, 0xb3,
+ 0xb0, 0x0b, 0xb5, 0xa8, 0x0a, 0xd4, 0x58, 0x42, 0xed, 0x3e, 0x94,
+ 0xd2, 0xa6, 0x8b, 0x01, 0x34, 0x44, 0xed, 0xe6, 0x9c, 0x4d, 0x6a,
+ 0x80, 0x8d, 0x8d, 0x46, 0xc6, 0x80, 0x23, 0x63, 0x51, 0x9a, 0x06,
+ 0x46, 0xd5, 0x13, 0x52, 0x01, 0x54, 0xd4, 0xaa, 0x68, 0x02, 0x40,
+ 0x6a, 0x40, 0x78, 0xa0, 0x08, 0x59, 0xce, 0xee, 0xb5, 0x2a, 0x39,
+ 0xd9, 0x59, 0xa7, 0xa8, 0x00, 0x73, 0xeb, 0x4e, 0x0e, 0x7d, 0x69,
+ 0x5c, 0x05, 0xf3, 0x0f, 0xad, 0x1e, 0x61, 0xf5, 0xa7, 0x71, 0x0b,
+ 0xe6, 0x35, 0x21, 0x90, 0xd3, 0xb8, 0x0e, 0x32, 0x10, 0x95, 0x10,
+ 0x91, 0xb3, 0xd6, 0x9b, 0x60, 0x4b, 0x9c, 0x8a, 0x63, 0x1a, 0xb0,
+ 0x18, 0x4d, 0x46, 0xc6, 0x80, 0x22, 0x6a, 0x61, 0xa4, 0x31, 0xaa,
+ 0x6a, 0x55, 0x34, 0x01, 0x2a, 0x9a, 0x7e, 0x78, 0xa0, 0x08, 0x09,
+ 0xf9, 0xaa, 0x58, 0xcf, 0xca, 0x6b, 0x3e, 0xa0, 0x00, 0xd3, 0x81,
+ 0xa9, 0x01, 0x73, 0x46, 0x69, 0x80, 0xb9, 0xa4, 0xcd, 0x00, 0x2b,
+ 0x1f, 0x92, 0xa3, 0x07, 0x9a, 0x6f, 0x70, 0x26, 0xcf, 0x14, 0xd2,
+ 0x6b, 0x51, 0x0c, 0x63, 0x51, 0xb1, 0xa0, 0x08, 0xda, 0x98, 0x69,
+ 0x0c, 0x8d, 0x4d, 0x4a, 0xa6, 0x80, 0x24, 0x53, 0x52, 0x03, 0xc5,
+ 0x02, 0x21, 0x27, 0xe6, 0xa9, 0x23, 0x3f, 0x29, 0xac, 0xfa, 0x8c,
+ 0x01, 0xe6, 0x9c, 0x0d, 0x48, 0x0a, 0x0d, 0x2e, 0x68, 0x01, 0x73,
+ 0x49, 0x9a, 0x60, 0x2b, 0x1f, 0x92, 0x98, 0x3a, 0xd3, 0x7b, 0x81,
+ 0x36, 0x78, 0xa6, 0x93, 0x5a, 0x88, 0x8c, 0x9a, 0x63, 0x1a, 0x00,
+ 0x8c, 0xd3, 0x0d, 0x21, 0x91, 0x29, 0xa9, 0x14, 0xd0, 0x04, 0x8a,
+ 0x69, 0xe0, 0xd3, 0x11, 0x1b, 0x1e, 0x6a, 0x48, 0xcf, 0xca, 0x6b,
+ 0x3e, 0xa3, 0x10, 0x1a, 0x70, 0x35, 0x20, 0x38, 0x1a, 0x5c, 0xd2,
+ 0x01, 0x73, 0x49, 0x9a, 0x60, 0x39, 0x8f, 0xca, 0x29, 0x8b, 0xf7,
+ 0xaa, 0xba, 0x88, 0x96, 0x9a, 0x6b, 0x40, 0x18, 0xc6, 0xa3, 0x26,
+ 0x80, 0x18, 0x69, 0xa6, 0x90, 0xc8, 0x14, 0xd4, 0x8a, 0x69, 0x80,
+ 0xf0, 0x6a, 0x40, 0x68, 0x10, 0xbb, 0x41, 0xa7, 0xe3, 0x0b, 0xc5,
+ 0x2b, 0x01, 0x10, 0xa7, 0x03, 0x59, 0x0c, 0x76, 0x69, 0x73, 0x40,
+ 0x0b, 0x9a, 0x28, 0x11, 0x28, 0x19, 0x5e, 0x69, 0x02, 0x81, 0x5a,
+ 0xd8, 0x00, 0xd3, 0x4d, 0x50, 0x0c, 0x6a, 0x8c, 0xd2, 0x01, 0xa6,
+ 0x98, 0x69, 0x0c, 0xae, 0xa6, 0xa4, 0x06, 0x80, 0x1e, 0xa6, 0x9e,
+ 0x0d, 0x31, 0x12, 0x03, 0x4f, 0x06, 0x80, 0x13, 0x60, 0x34, 0xd3,
+ 0xc1, 0xa8, 0x92, 0x01, 0xf1, 0x8d, 0xdd, 0x69, 0xcc, 0xa1, 0x69,
+ 0x5b, 0x4b, 0x80, 0x83, 0x93, 0x52, 0x04, 0x14, 0xe2, 0xae, 0x03,
+ 0xa9, 0x0d, 0x68, 0x03, 0x4d, 0x34, 0xd0, 0x03, 0x0d, 0x30, 0xd2,
+ 0x01, 0x86, 0x9a, 0x68, 0x19, 0x58, 0x1a, 0x78, 0xa4, 0x04, 0x8a,
+ 0x69, 0xe0, 0xd3, 0x10, 0xe0, 0x69, 0xe0, 0xd0, 0x03, 0xc1, 0xa8,
+ 0xdb, 0xad, 0x4c, 0x81, 0x12, 0x45, 0xd6, 0x9d, 0x25, 0x1d, 0x00,
+ 0x6a, 0xf5, 0xa9, 0xe8, 0x80, 0x31, 0x29, 0x0d, 0x58, 0x08, 0x69,
+ 0x86, 0x80, 0x1a, 0x69, 0x86, 0x90, 0x0c, 0x34, 0xd3, 0x48, 0x65,
+ 0x51, 0x4f, 0x06, 0x98, 0x0f, 0x14, 0xf0, 0x68, 0x10, 0xf0, 0x69,
+ 0xe0, 0xd0, 0x03, 0x81, 0xa5, 0x2b, 0x9a, 0x1a, 0xb8, 0x87, 0xa8,
+ 0xdb, 0x4a, 0x46, 0x68, 0xb6, 0x80, 0x2a, 0xa8, 0x14, 0xea, 0x12,
+ 0xb0, 0x05, 0x21, 0xa6, 0x02, 0x1a, 0x61, 0xa0, 0x06, 0x9a, 0x61,
+ 0xa4, 0x31, 0x86, 0x9a, 0x69, 0x0c, 0xa8, 0x0d, 0x3c, 0x53, 0x01,
+ 0xe2, 0x9e, 0x28, 0x10, 0xf1, 0x4e, 0x06, 0x98, 0x0f, 0x06, 0x9e,
+ 0x0d, 0x02, 0x1c, 0x29, 0xc2, 0x80, 0x16, 0x96, 0x80, 0x0a, 0x4a,
+ 0x00, 0x43, 0x4d, 0x34, 0x0c, 0x61, 0xa6, 0x1a, 0x40, 0x34, 0xd3,
+ 0x4d, 0x21, 0x80, 0xff, 0xd9, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0a,
+ 0x07, 0x07, 0x08, 0x07, 0x06, 0x0a, 0x08, 0x08, 0x08, 0x0b, 0x0a,
+ 0x0a, 0x0b, 0x0e, 0x18, 0x10, 0x0e, 0x0d, 0x0d, 0x0e, 0x1d, 0x15,
+ 0x16, 0x11, 0x18, 0x23, 0x1f, 0x25, 0x24, 0x22, 0x1f, 0x22, 0x21,
+ 0x26, 0x2b, 0x37, 0x2f, 0x26, 0x29, 0x34, 0x29, 0x21, 0x22, 0x30,
+ 0x41, 0x31, 0x34, 0x39, 0x3b, 0x3e, 0x3e, 0x3e, 0x25, 0x2e, 0x44,
+ 0x49, 0x43, 0x3c, 0x48, 0x37, 0x3d, 0x3e, 0x3b, 0x01, 0x0a, 0x0b,
+ 0x0b, 0x0e, 0x0d, 0x0e, 0x1c, 0x10, 0x10, 0x1c, 0x3b, 0x28, 0x22,
+ 0x28, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+ 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xff, 0xc0, 0x00, 0x11,
+ 0x08, 0x00, 0x48, 0x00, 0x60, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11,
+ 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01,
+ 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
+ 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01,
+ 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
+ 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1,
+ 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33,
+ 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+ 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+ 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
+ 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
+ 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03,
+ 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
+ 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
+ 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
+ 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
+ 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+ 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+ 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+ 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
+ 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03,
+ 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0x9e, 0xd2,
+ 0x2e, 0x07, 0x15, 0xaf, 0x6d, 0x08, 0xe2, 0xb3, 0x45, 0x1a, 0xf6,
+ 0xd0, 0x00, 0x01, 0xc5, 0x68, 0x45, 0x17, 0x4a, 0xb4, 0x22, 0xe4,
+ 0x70, 0x8c, 0x74, 0xa9, 0x3c, 0xa1, 0x8e, 0x95, 0x48, 0x96, 0x31,
+ 0xe2, 0x18, 0xe9, 0x55, 0xa5, 0x8c, 0x7a, 0x50, 0x05, 0x0b, 0x88,
+ 0x86, 0x0f, 0x15, 0x8f, 0x75, 0x1f, 0x26, 0x93, 0x19, 0x91, 0x77,
+ 0x18, 0xc1, 0xac, 0x4b, 0xc8, 0xfa, 0xd6, 0x63, 0x37, 0x6d, 0x31,
+ 0xb4, 0x73, 0x5b, 0x36, 0xa0, 0x1c, 0x50, 0x80, 0xd7, 0x83, 0xa0,
+ 0xab, 0xd1, 0x62, 0xad, 0x09, 0x8f, 0x17, 0x29, 0x03, 0xb2, 0xcc,
+ 0xe0, 0x77, 0x14, 0xa3, 0x56, 0xb3, 0x27, 0x1e, 0x67, 0xe9, 0x52,
+ 0xea, 0xc6, 0x3a, 0x36, 0x48, 0xef, 0x3d, 0x27, 0x70, 0x22, 0x60,
+ 0x47, 0x52, 0x69, 0xb2, 0xe2, 0xad, 0x3b, 0xea, 0x80, 0xa3, 0x38,
+ 0xe0, 0xd6, 0x3d, 0xd8, 0x1c, 0xd0, 0xca, 0x46, 0x3d, 0xd0, 0x18,
+ 0x35, 0x89, 0x78, 0xa3, 0x9a, 0xcd, 0x8c, 0xd2, 0xb3, 0x93, 0x2a,
+ 0x2b, 0x66, 0xd5, 0xf1, 0x8a, 0x10, 0x1a, 0xd6, 0xf2, 0x03, 0x8a,
+ 0x9e, 0xe6, 0xf4, 0x5a, 0xdb, 0xef, 0xfe, 0x23, 0xc0, 0xa7, 0x27,
+ 0xcb, 0x16, 0xc4, 0xcc, 0xdd, 0xe2, 0x78, 0x9a, 0x69, 0x66, 0xcc,
+ 0x99, 0xe1, 0x4d, 0x47, 0xba, 0xbc, 0xd9, 0x6a, 0xee, 0x26, 0x59,
+ 0x59, 0x4d, 0xac, 0x69, 0x34, 0x52, 0xe5, 0x8f, 0x55, 0xad, 0x58,
+ 0xae, 0x85, 0xc4, 0x22, 0x41, 0xdf, 0xad, 0x76, 0x61, 0xe5, 0x6f,
+ 0x74, 0x45, 0x69, 0xdc, 0x00, 0x79, 0xac, 0x8b, 0xa6, 0xc9, 0x35,
+ 0xd4, 0x34, 0x64, 0xdc, 0x37, 0x06, 0xb1, 0xae, 0x88, 0xc1, 0xac,
+ 0xd8, 0xc9, 0x2c, 0xa6, 0xe0, 0x73, 0x5b, 0x36, 0xf3, 0x74, 0xe6,
+ 0x84, 0x05, 0xe3, 0xa9, 0x47, 0x6a, 0x14, 0xb6, 0x49, 0x3d, 0x85,
+ 0x3a, 0xee, 0xee, 0x2b, 0xa8, 0xe2, 0x6f, 0x30, 0x81, 0xe9, 0x8a,
+ 0xca, 0xa4, 0xe2, 0xd3, 0x8b, 0x01, 0xb1, 0xf9, 0x04, 0x7f, 0xaf,
+ 0x23, 0xf0, 0xa9, 0x54, 0x41, 0x9c, 0xfd, 0xa3, 0xf4, 0xae, 0x65,
+ 0x18, 0xf7, 0x25, 0x8a, 0xe2, 0x02, 0x38, 0xb8, 0xfd, 0x2a, 0x7b,
+ 0x5b, 0xa8, 0x6d, 0x6d, 0x5d, 0x9a, 0x5d, 0xcb, 0xbb, 0xd2, 0xb6,
+ 0xa6, 0xa3, 0x19, 0x5e, 0xe2, 0x03, 0x7b, 0x1d, 0xc2, 0x17, 0x8d,
+ 0xb8, 0xac, 0xfb, 0x89, 0x39, 0x35, 0xd6, 0x9a, 0x6a, 0xe8, 0x66,
+ 0x55, 0xcb, 0xf5, 0xac, 0x7b, 0x96, 0xeb, 0x50, 0xc6, 0x88, 0x6d,
+ 0x66, 0xe9, 0xcd, 0x6c, 0xdb, 0x4f, 0xd3, 0x9a, 0x00, 0x2f, 0xe6,
+ 0xf9, 0xa3, 0xe7, 0xb5, 0x4a, 0x93, 0x7f, 0xa2, 0xc6, 0x73, 0xdc,
+ 0xd7, 0x15, 0x55, 0xef, 0x48, 0x7d, 0x09, 0x52, 0x6e, 0x3a, 0xd4,
+ 0xab, 0x2f, 0xbd, 0x61, 0x16, 0x0c, 0x73, 0x49, 0xc5, 0x24, 0x92,
+ 0x7f, 0xa2, 0x63, 0xfd, 0xaa, 0xd6, 0x2f, 0x71, 0x0e, 0xb1, 0x93,
+ 0xf7, 0x2d, 0xf5, 0xa4, 0x9e, 0x4e, 0xb5, 0xdd, 0x4b, 0xf8, 0x68,
+ 0x4c, 0xcb, 0xb9, 0x93, 0xad, 0x65, 0xce, 0xd9, 0x26, 0xa9, 0x8d,
+ 0x19, 0xf6, 0xf2, 0xf4, 0xe6, 0xb5, 0xad, 0xe7, 0xc6, 0x39, 0xa0,
+ 0x18, 0xeb, 0xc9, 0x77, 0x6c, 0x35, 0x2a, 0x4b, 0xfe, 0x8a, 0x9c,
+ 0xff, 0x00, 0x11, 0xae, 0x3a, 0x8b, 0xde, 0x61, 0xd0, 0x9e, 0x39,
+ 0xb8, 0xeb, 0x53, 0xac, 0xb9, 0xae, 0x5b, 0x00, 0xf3, 0x27, 0x14,
+ 0x92, 0xc9, 0xfe, 0x8a, 0x3f, 0xde, 0x35, 0xac, 0x3a, 0x88, 0x92,
+ 0xcd, 0xb1, 0x6e, 0x7d, 0xcd, 0x32, 0x67, 0xeb, 0xcd, 0x7a, 0x14,
+ 0xfe, 0x04, 0x26, 0x66, 0xce, 0xf9, 0x26, 0xb3, 0xe6, 0x6e, 0xb4,
+ 0xd9, 0x48, 0xc8, 0x82, 0x4e, 0x07, 0x35, 0xa7, 0x6f, 0x2f, 0x02,
+ 0x9a, 0x06, 0x5f, 0x8c, 0xa4, 0x83, 0x0e, 0x32, 0x2a, 0x69, 0xe3,
+ 0xdd, 0x12, 0x08, 0x97, 0x85, 0xec, 0x2a, 0x2a, 0x42, 0xf1, 0x76,
+ 0x26, 0xe4, 0x6a, 0x59, 0x0e, 0x18, 0x10, 0x6a, 0xd2, 0x89, 0x02,
+ 0x6e, 0x2a, 0x71, 0xeb, 0x5c, 0x1c, 0x8c, 0xa6, 0x48, 0xbb, 0xdc,
+ 0x61, 0x41, 0x35, 0x72, 0x28, 0x87, 0xd9, 0xf6, 0x4a, 0xb9, 0xe7,
+ 0x38, 0xae, 0x8c, 0x3d, 0x36, 0xdd, 0xde, 0xc4, 0xb0, 0x21, 0x51,
+ 0x76, 0xa8, 0xc0, 0xaa, 0x93, 0x31, 0xe6, 0xbb, 0x2d, 0x65, 0x61,
+ 0x19, 0xd3, 0x1e, 0xb5, 0x46, 0x5a, 0x96, 0x5a, 0x30, 0xa0, 0x7e,
+ 0x05, 0x69, 0x5b, 0xc9, 0xc6, 0x28, 0x40, 0xcd, 0x08, 0x64, 0x3c,
+ 0x73, 0x57, 0xe1, 0x94, 0xf1, 0xcd, 0x5a, 0x21, 0x8c, 0xb9, 0x63,
+ 0xe7, 0x67, 0x1d, 0xab, 0x40, 0xb1, 0xfb, 0x00, 0x1d, 0xf0, 0x2b,
+ 0x99, 0x2d, 0x66, 0x3e, 0x88, 0x75, 0x81, 0x3f, 0x31, 0xf6, 0xab,
+ 0x64, 0xd6, 0xb4, 0x17, 0xee, 0xd0, 0x9e, 0xe4, 0x32, 0x1a, 0xa7,
+ 0x31, 0xad, 0x18, 0x14, 0x26, 0xef, 0x54, 0xa5, 0xa8, 0x65, 0xa3,
+ 0x9c, 0x81, 0xfa, 0x56, 0x8c, 0x2d, 0xce, 0x68, 0x40, 0xcb, 0xf1,
+ 0x37, 0xbd, 0x5e, 0x85, 0xea, 0xd1, 0x0c, 0xbb, 0x19, 0x56, 0x23,
+ 0x20, 0x1f, 0xad, 0x5c, 0x42, 0x08, 0x03, 0xb5, 0x55, 0x91, 0x04,
+ 0xc9, 0x80, 0x38, 0x00, 0x0a, 0x71, 0x34, 0x6c, 0x32, 0x27, 0xe9,
+ 0x55, 0x25, 0x15, 0x2c, 0x68, 0xa3, 0x30, 0xeb, 0x54, 0xa5, 0x15,
+ 0x0c, 0xd1, 0x00, 0xff, 0xd9};
+ int length = photoIntArray.length;
+ byte[] photoByteArray = new byte[length];
+ for (int i = 0; i < length; i++) {
+ photoByteArray[i] = (byte)photoIntArray[i];
+ }
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "Gump;Forrest;Hoge;Pos;Tao",
+ Arrays.asList("Gump", "Forrest",
+ "Hoge", "Pos", "Tao"),
+ null, null, null, null),
+ new PropertyNode("FN", "Joe Due",
+ null, null, null, null, null),
+ new PropertyNode("ORG",
+ "Gump Shrimp Co.;Sales Dept.;Manager;Fish keeper",
+ Arrays.asList("Gump Shrimp Co.",
+ "Sales Dept.;Manager",
+ "Fish keeper"),
+ null, null, null, null),
+ new PropertyNode("ROLE", "Fish Cake Keeper!",
+ null, null, null, null, null),
+ new PropertyNode("TITLE", "Shrimp Man",
+ null, null, null, null, null),
+ new PropertyNode("X-CLASS", "PUBLIC",
+ null, null, null, null, null),
+ new PropertyNode("TEL", "(111) 555-1212",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("WORK", "VOICE")), null),
+ new PropertyNode("TEL", "(404) 555-1212",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("HOME", "VOICE")), null),
+ new PropertyNode("TEL", "0311111111",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("CELL")), null),
+ new PropertyNode("TEL", "0322222222",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("VIDEO")), null),
+ new PropertyNode("TEL", "0333333333",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("VOICE")), null),
+ new PropertyNode("ADR",
+ ";;100 Waters Edge;Baytown;LA;30314;United States of America",
+ Arrays.asList("", "", "100 Waters Edge", "Baytown",
+ "LA", "30314", "United States of America"),
+ null, null,
+ new HashSet<String>(Arrays.asList("WORK")), null),
+ new PropertyNode("LABEL",
+ "100 Waters Edge\r\nBaytown, LA 30314\r\nUnited States of America",
+ null, null, contentValuesForQP,
+ new HashSet<String>(Arrays.asList("WORK")), null),
+ new PropertyNode("ADR",
+ ";;42 Plantation St.;Baytown;LA;30314;United States of America",
+ Arrays.asList("", "", "42 Plantation St.", "Baytown",
+ "LA", "30314", "United States of America"), null, null,
+ new HashSet<String>(Arrays.asList("HOME")), null),
+ new PropertyNode("LABEL",
+ "42 Plantation St.\r\nBaytown, LA 30314\r\nUnited States of America",
+ null, null, contentValuesForQP,
+ new HashSet<String>(Arrays.asList("HOME")), null),
+ new PropertyNode("EMAIL", "forrestgump@walladalla.com",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("PREF", "INTERNET")), null),
+ new PropertyNode("EMAIL", "cell@example.com",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("CELL")), null),
+ new PropertyNode("NOTE", "The following note is the example from RFC 2045.",
+ null, null, null, null, null),
+ new PropertyNode("NOTE",
+ "Now's the time for all folk to come to the aid of their country.",
+ null, null, contentValuesForQP, null, null),
+ new PropertyNode("PHOTO", null,
+ null, photoByteArray, contentValuesForPhoto,
+ new HashSet<String>(Arrays.asList("JPEG")), null),
+ new PropertyNode("X-ATTRIBUTE", "Some String",
+ null, null, null, null, null),
+ new PropertyNode("BDAY", "19800101",
+ null, null, null, null, null),
+ new PropertyNode("GEO", "35.6563854,139.6994233",
+ null, null, null, null, null),
+ new PropertyNode("URL", "http://www.example.com/",
+ null, null, null, null, null),
+ new PropertyNode("REV", "20080424T195243Z",
+ null, null, null, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21Japanese1() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_1);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ ContentValues contentValuesForShiftJis = new ContentValues();
+ contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
+ ContentValues contentValuesForQP = new ContentValues();
+ contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
+ contentValuesForQP.put("CHARSET", "SHIFT_JIS");
+ // Though Japanese careers append ";;;;" at the end of the value of "SOUND",
+ // vCard 2.1/3.0 specification does not allow multiple values.
+ // Do not need to handle it as multiple values.
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "0300000000",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("VOICE", "PREF")), null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21Japanese2() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_japanese_2);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ ContentValues contentValuesForShiftJis = new ContentValues();
+ contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
+ ContentValues contentValuesForQP = new ContentValues();
+ contentValuesForQP.put("ENCODING", "QUOTED-PRINTABLE");
+ contentValuesForQP.put("CHARSET", "SHIFT_JIS");
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4;\u30ED\u30A4\u30C9\u0031;;;",
+ Arrays.asList("\u5B89\u85E4", "\u30ED\u30A4\u30C9\u0031",
+ "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("FN",
+ "\u5B89\u85E4\u0020\u30ED\u30A4\u30C9\u0020\u0031",
+ null, null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ ("\uFF71\uFF9D\uFF84\uFF9E\uFF73" +
+ ";\uFF9B\uFF72\uFF84\uFF9E\u0031;;;"),
+ null, null, contentValuesForShiftJis,
+ new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("ADR",
+ (";\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
+ "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
+ "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC\u0036" +
+ "\u968E;;;;150-8512;"),
+ Arrays.asList("",
+ "\u6771\u4EAC\u90FD\u6E0B\u8C37\u533A\u685C" +
+ "\u4E18\u753A\u0032\u0036\u002D\u0031\u30BB" +
+ "\u30EB\u30EA\u30A2\u30F3\u30BF\u30EF\u30FC" +
+ "\u0036\u968E", "", "", "", "150-8512", ""),
+ null, contentValuesForQP,
+ new HashSet<String>(Arrays.asList("HOME")), null),
+ new PropertyNode("NOTE", "\u30E1\u30E2",
+ null, null, contentValuesForQP, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+
+ public void testV21MultipleEntryCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V21();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v21_multiple_entry);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(3, builder.vNodeList.size());
+ ContentValues contentValuesForShiftJis = new ContentValues();
+ contentValuesForShiftJis.put("CHARSET", "SHIFT_JIS");
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0033;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0033", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0033;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "9",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-SECRET")), null),
+ new PropertyNode("TEL", "10",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-HOTEL")), null),
+ new PropertyNode("TEL", "11",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-SCHOOL")), null),
+ new PropertyNode("TEL", "12",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("FAX", "HOME")), null));
+ verifier.verify(builder.vNodeList.get(0));
+
+ verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0034;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0034", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0034;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "13",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("MODEM")), null),
+ new PropertyNode("TEL", "14",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("PAGER")), null),
+ new PropertyNode("TEL", "15",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-FAMILY")), null),
+ new PropertyNode("TEL", "16",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-GIRL")), null));
+ verifier.verify(builder.vNodeList.get(1));
+ verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "2.1",
+ null, null, null, null, null),
+ new PropertyNode("N", "\u5B89\u85E4\u30ED\u30A4\u30C9\u0035;;;;",
+ Arrays.asList("\u5B89\u85E4\u30ED\u30A4\u30C9\u0035", "", "", "", ""),
+ null, contentValuesForShiftJis, null, null),
+ new PropertyNode("SOUND",
+ "\uFF71\uFF9D\uFF84\uFF9E\uFF73\uFF9B\uFF72\uFF84\uFF9E\u0035;;;;",
+ null, null, contentValuesForShiftJis,
+ new HashSet<String>(Arrays.asList("X-IRMC-N")), null),
+ new PropertyNode("TEL", "17",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-BOY")), null),
+ new PropertyNode("TEL", "18",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-FRIEND")), null),
+ new PropertyNode("TEL", "19",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-PHS")), null),
+ new PropertyNode("TEL", "20",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("X-NEC-RESTAURANT")), null));
+ verifier.verify(builder.vNodeList.get(2));
+ }
+
+ public void testV30SimpleCase() throws IOException, VCardException {
+ VCardParser_V21 parser = new VCardParser_V30();
+ VNodeBuilder builder = new VNodeBuilder();
+ InputStream is = getContext().getResources().openRawResource(R.raw.v30_simple);
+ assertEquals(true, parser.parse(is,"ISO-8859-1", builder));
+ is.close();
+ assertEquals(1, builder.vNodeList.size());
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(
+ new PropertyNode("VERSION", "3.0",
+ null, null, null, null, null),
+ new PropertyNode("FN", "And Roid",
+ null, null, null, null, null),
+ new PropertyNode("N", "And;Roid;;;",
+ Arrays.asList("And", "Roid", "", "", ""),
+ null, null, null, null),
+ new PropertyNode("ORG", "Open;Handset; Alliance",
+ Arrays.asList("Open", "Handset", " Alliance"),
+ null, null, null, null),
+ new PropertyNode("SORT-STRING", "android", null, null, null, null, null),
+ new PropertyNode("TEL", "0300000000",
+ null, null, null,
+ new HashSet<String>(Arrays.asList("PREF", "VOICE")), null),
+ new PropertyNode("CLASS", "PUBLIC", null, null, null, null, null),
+ new PropertyNode("X-GNO", "0", null, null, null, null, null),
+ new PropertyNode("X-GN", "group0", null, null, null, null, null),
+ new PropertyNode("X-REDUCTION", "0",
+ null, null, null, null, null),
+ new PropertyNode("REV", "20081031T065854Z",
+ null, null, null, null, null));
+ verifier.verify(builder.vNodeList.get(0));
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java
new file mode 100644
index 0000000..3eb827b
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNode.java
@@ -0,0 +1,30 @@
+/*
+ * 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.vcard;
+
+import java.util.ArrayList;
+
+/**
+ * @hide old class. Just for testing
+ */
+public class VNode {
+ public String VName;
+
+ public ArrayList<PropertyNode> propList = new ArrayList<PropertyNode>();
+
+ /** 0:parse over. 1:parsing. */
+ public int parseStatus = 1;
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java
new file mode 100644
index 0000000..6d69223
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VNodeBuilder.java
@@ -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.
+ */
+package com.android.unit_tests.vcard;
+
+import android.content.ContentValues;
+import android.pim.vcard.VCardBuilder;
+import android.pim.vcard.VCardConfig;
+import android.util.CharsetUtils;
+import android.util.Log;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.net.QuotedPrintableCodec;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Store the parse result to custom datastruct: VNode, PropertyNode
+ * Maybe several vcard instance, so use vNodeList to store.
+ * VNode: standy by a vcard instance.
+ * PropertyNode: standy by a property line of a card.
+ * @hide old class, just for testing use
+ */
+public class VNodeBuilder implements VCardBuilder {
+ static private String LOG_TAG = "VDATABuilder";
+
+ /**
+ * If there's no other information available, this class uses this charset for encoding
+ * byte arrays.
+ */
+ static public String TARGET_CHARSET = "UTF-8";
+
+ /** type=VNode */
+ public List<VNode> vNodeList = new ArrayList<VNode>();
+ private int mNodeListPos = 0;
+ private VNode mCurrentVNode;
+ private PropertyNode mCurrentPropNode;
+ private String mCurrentParamType;
+
+ /**
+ * The charset using which VParser parses the text.
+ */
+ private String mSourceCharset;
+
+ /**
+ * The charset with which byte array is encoded to String.
+ */
+ private String mTargetCharset;
+
+ private boolean mStrictLineBreakParsing;
+
+ public VNodeBuilder() {
+ this(VCardConfig.DEFAULT_CHARSET, TARGET_CHARSET, false);
+ }
+
+ public VNodeBuilder(String charset, boolean strictLineBreakParsing) {
+ this(null, charset, strictLineBreakParsing);
+ }
+
+ /**
+ * @hide sourceCharset is temporal.
+ */
+ public VNodeBuilder(String sourceCharset, String targetCharset,
+ boolean strictLineBreakParsing) {
+ if (sourceCharset != null) {
+ mSourceCharset = sourceCharset;
+ } else {
+ mSourceCharset = VCardConfig.DEFAULT_CHARSET;
+ }
+ if (targetCharset != null) {
+ mTargetCharset = targetCharset;
+ } else {
+ mTargetCharset = TARGET_CHARSET;
+ }
+ mStrictLineBreakParsing = strictLineBreakParsing;
+ }
+
+ public void start() {
+ }
+
+ public void end() {
+ }
+
+ // Note: I guess that this code assumes the Record may nest like this:
+ // START:VPOS
+ // ...
+ // START:VPOS2
+ // ...
+ // END:VPOS2
+ // ...
+ // END:VPOS
+ //
+ // However the following code has a bug.
+ // When error occurs after calling startRecord(), the entry which is probably
+ // the cause of the error remains to be in vNodeList, while endRecord() is not called.
+ //
+ // I leave this code as is since I'm not familiar with vcalendar specification.
+ // But I believe we should refactor this code in the future.
+ // Until this, the last entry has to be removed when some error occurs.
+ public void startRecord(String type) {
+
+ VNode vnode = new VNode();
+ vnode.parseStatus = 1;
+ vnode.VName = type;
+ // I feel this should be done in endRecord(), but it cannot be done because of
+ // the reason above.
+ vNodeList.add(vnode);
+ mNodeListPos = vNodeList.size() - 1;
+ mCurrentVNode = vNodeList.get(mNodeListPos);
+ }
+
+ public void endRecord() {
+ VNode endNode = vNodeList.get(mNodeListPos);
+ endNode.parseStatus = 0;
+ while(mNodeListPos > 0){
+ mNodeListPos--;
+ if((vNodeList.get(mNodeListPos)).parseStatus == 1)
+ break;
+ }
+ mCurrentVNode = vNodeList.get(mNodeListPos);
+ }
+
+ public void startProperty() {
+ mCurrentPropNode = new PropertyNode();
+ }
+
+ public void endProperty() {
+ mCurrentVNode.propList.add(mCurrentPropNode);
+ }
+
+ public void propertyName(String name) {
+ mCurrentPropNode.propName = name;
+ }
+
+ // Used only in VCard.
+ public void propertyGroup(String group) {
+ mCurrentPropNode.propGroupSet.add(group);
+ }
+
+ public void propertyParamType(String type) {
+ mCurrentParamType = type;
+ }
+
+ public void propertyParamValue(String value) {
+ if (mCurrentParamType == null ||
+ mCurrentParamType.equalsIgnoreCase("TYPE")) {
+ mCurrentPropNode.paramMap_TYPE.add(value);
+ } else {
+ mCurrentPropNode.paramMap.put(mCurrentParamType, value);
+ }
+
+ mCurrentParamType = null;
+ }
+
+ private String encodeString(String originalString, String targetCharset) {
+ if (mSourceCharset.equalsIgnoreCase(targetCharset)) {
+ return originalString;
+ }
+ Charset charset = Charset.forName(mSourceCharset);
+ ByteBuffer byteBuffer = charset.encode(originalString);
+ // byteBuffer.array() "may" return byte array which is larger than
+ // byteBuffer.remaining(). Here, we keep on the safe side.
+ byte[] bytes = new byte[byteBuffer.remaining()];
+ byteBuffer.get(bytes);
+ try {
+ return new String(bytes, targetCharset);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
+ return null;
+ }
+ }
+
+ private String handleOneValue(String value, String targetCharset, String encoding) {
+ if (encoding != null) {
+ if (encoding.equals("BASE64") || encoding.equals("B")) {
+ // Assume BASE64 is used only when the number of values is 1.
+ mCurrentPropNode.propValue_bytes =
+ Base64.decodeBase64(value.getBytes());
+ return value;
+ } else if (encoding.equals("QUOTED-PRINTABLE")) {
+ String quotedPrintable = value
+ .replaceAll("= ", " ").replaceAll("=\t", "\t");
+ String[] lines;
+ if (mStrictLineBreakParsing) {
+ lines = quotedPrintable.split("\r\n");
+ } else {
+ StringBuilder builder = new StringBuilder();
+ int length = quotedPrintable.length();
+ ArrayList<String> list = new ArrayList<String>();
+ for (int i = 0; i < length; i++) {
+ char ch = quotedPrintable.charAt(i);
+ if (ch == '\n') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ } else if (ch == '\r') {
+ list.add(builder.toString());
+ builder = new StringBuilder();
+ if (i < length - 1) {
+ char nextCh = quotedPrintable.charAt(i + 1);
+ if (nextCh == '\n') {
+ i++;
+ }
+ }
+ } else {
+ builder.append(ch);
+ }
+ }
+ String finalLine = builder.toString();
+ if (finalLine.length() > 0) {
+ list.add(finalLine);
+ }
+ lines = list.toArray(new String[0]);
+ }
+ StringBuilder builder = new StringBuilder();
+ for (String line : lines) {
+ if (line.endsWith("=")) {
+ line = line.substring(0, line.length() - 1);
+ }
+ builder.append(line);
+ }
+ byte[] bytes;
+ try {
+ bytes = builder.toString().getBytes(mSourceCharset);
+ } catch (UnsupportedEncodingException e1) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + mSourceCharset);
+ bytes = builder.toString().getBytes();
+ }
+
+ try {
+ bytes = QuotedPrintableCodec.decodeQuotedPrintable(bytes);
+ } catch (DecoderException e) {
+ Log.e(LOG_TAG, "Failed to decode quoted-printable: " + e);
+ return "";
+ }
+
+ try {
+ return new String(bytes, targetCharset);
+ } catch (UnsupportedEncodingException e) {
+ Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
+ return new String(bytes);
+ }
+ }
+ // Unknown encoding. Fall back to default.
+ }
+ return encodeString(value, targetCharset);
+ }
+
+ public void propertyValues(List<String> values) {
+ if (values == null || values.size() == 0) {
+ mCurrentPropNode.propValue_bytes = null;
+ mCurrentPropNode.propValue_vector.clear();
+ mCurrentPropNode.propValue_vector.add("");
+ mCurrentPropNode.propValue = "";
+ return;
+ }
+
+ ContentValues paramMap = mCurrentPropNode.paramMap;
+
+ String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET"));
+ String encoding = paramMap.getAsString("ENCODING");
+
+ if (targetCharset == null || targetCharset.length() == 0) {
+ targetCharset = mTargetCharset;
+ }
+
+ for (String value : values) {
+ mCurrentPropNode.propValue_vector.add(
+ handleOneValue(value, targetCharset, encoding));
+ }
+
+ mCurrentPropNode.propValue = listToString(mCurrentPropNode.propValue_vector);
+ }
+
+ private String listToString(List<String> list){
+ int size = list.size();
+ if (size > 1) {
+ StringBuilder typeListB = new StringBuilder();
+ for (String type : list) {
+ typeListB.append(type).append(";");
+ }
+ int len = typeListB.length();
+ if (len > 0 && typeListB.charAt(len - 1) == ';') {
+ return typeListB.substring(0, len - 1);
+ }
+ return typeListB.toString();
+ } else if (size == 1) {
+ return list.get(0);
+ } else {
+ return "";
+ }
+ }
+
+ public String getResult(){
+ return null;
+ }
+}
diff --git a/tests/BrowserTestPlugin/Android.mk b/tests/BrowserTestPlugin/Android.mk
new file mode 100644
index 0000000..968d9e6
--- /dev/null
+++ b/tests/BrowserTestPlugin/Android.mk
@@ -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.
+#
+
+TOP_LOCAL_PATH:= $(call my-dir)
+
+# Build application
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := BrowserTestPlugin
+
+LOCAL_JNI_SHARED_LIBRARIES := libtestplugin
+
+include $(BUILD_PACKAGE)
+
+# ============================================================
+
+# Also build all of the sub-targets under this one: the shared library.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/BrowserTestPlugin/AndroidManifest.xml b/tests/BrowserTestPlugin/AndroidManifest.xml
new file mode 100644
index 0000000..f071ab6
--- /dev/null
+++ b/tests/BrowserTestPlugin/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.testplugin"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-permission android:name="android.webkit.permission.PLUGIN"/>
+
+ <uses-sdk android:minSdkVersion="3" />
+
+ <application android:icon="@drawable/browser_test_plugin"
+ android:label="Browser Test Plugin">
+ <service android:name="TestPlugin">
+ <intent-filter>
+ <action android:name="android.webkit.PLUGIN" />
+ </intent-filter>
+ </service>
+ </application>
+
+</manifest>
diff --git a/tests/BrowserTestPlugin/MODULE_LICENSE_APACHE2 b/tests/BrowserTestPlugin/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/BrowserTestPlugin/MODULE_LICENSE_APACHE2
diff --git a/tests/BrowserTestPlugin/NOTICE b/tests/BrowserTestPlugin/NOTICE
new file mode 100644
index 0000000..9df2554
--- /dev/null
+++ b/tests/BrowserTestPlugin/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2009, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/tests/BrowserTestPlugin/jni/Android.mk b/tests/BrowserTestPlugin/jni/Android.mk
new file mode 100644
index 0000000..95a21e9
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/Android.mk
@@ -0,0 +1,49 @@
+##
+##
+## Copyright 2009, The Android Open Source Project
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+## * Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+## * Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ main.cpp \
+ PluginObject.cpp \
+ event/EventPlugin.cpp \
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/event \
+ external/webkit/WebCore/bridge \
+ external/webkit/WebCore/plugins \
+ external/webkit/WebCore/platform/android/JavaVM \
+ external/webkit/WebKit/android/plugins
+
+LOCAL_CFLAGS += -fvisibility=hidden
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_MODULE := libtestplugin
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/BrowserTestPlugin/jni/PluginObject.cpp b/tests/BrowserTestPlugin/jni/PluginObject.cpp
new file mode 100644
index 0000000..68fca60
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/PluginObject.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in
+ consideration of your agreement to the following terms, and your use, installation,
+ modification or redistribution of this Apple software constitutes acceptance of these
+ terms. If you do not agree with these terms, please do not use, install, modify or
+ redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject to these
+ terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in
+ this original Apple software (the "Apple Software"), to use, reproduce, modify and
+ redistribute the Apple Software, with or without modifications, in source and/or binary
+ forms; provided that if you redistribute the Apple Software in its entirety and without
+ modifications, you must retain this notice and the following text and disclaimers in all
+ such redistributions of the Apple Software. Neither the name, trademarks, service marks
+ or logos of Apple Computer, Inc. may be used to endorse or promote products derived from
+ the Apple Software without specific prior written permission from Apple. Except as expressly
+ stated in this notice, no other rights or licenses, express or implied, are granted by Apple
+ herein, including but not limited to any patent rights that may be infringed by your
+ derivative works or by other works in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES,
+ EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS
+ USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
+ REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
+ WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
+ OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include "main.h"
+#include "PluginObject.h"
+
+static void pluginInvalidate(NPObject *obj);
+static bool pluginHasProperty(NPObject *obj, NPIdentifier name);
+static bool pluginHasMethod(NPObject *obj, NPIdentifier name);
+static bool pluginGetProperty(NPObject *obj, NPIdentifier name, NPVariant *variant);
+static bool pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant);
+static bool pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result);
+static bool pluginInvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
+static NPObject *pluginAllocate(NPP npp, NPClass *theClass);
+static void pluginDeallocate(NPObject *obj);
+static bool pluginRemoveProperty(NPObject *npobj, NPIdentifier name);
+static bool pluginEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count);
+
+
+
+static NPClass pluginClass = {
+ NP_CLASS_STRUCT_VERSION,
+ pluginAllocate,
+ pluginDeallocate,
+ pluginInvalidate,
+ pluginHasMethod,
+ pluginInvoke,
+ pluginInvokeDefault,
+ pluginHasProperty,
+ pluginGetProperty,
+ pluginSetProperty,
+ pluginRemoveProperty,
+ pluginEnumerate
+};
+
+NPClass *getPluginClass(void)
+{
+ return &pluginClass;
+}
+
+static bool identifiersInitialized = false;
+
+#define ID_TESTFILE_PROPERTY 0
+#define NUM_PROPERTY_IDENTIFIERS 1
+
+static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS];
+static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = {
+ "testfile"
+};
+
+#define ID_GETTESTFILE_METHOD 0
+#define NUM_METHOD_IDENTIFIERS 1
+
+static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
+static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
+ "getTestFile"
+};
+
+static void initializeIdentifiers(void)
+{
+ browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers);
+ browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers);
+}
+
+static bool pluginHasProperty(NPObject *obj, NPIdentifier name)
+{
+ int i;
+ for (i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++)
+ if (name == pluginPropertyIdentifiers[i])
+ return true;
+ return false;
+}
+
+static bool pluginHasMethod(NPObject *obj, NPIdentifier name)
+{
+ int i;
+ for (i = 0; i < NUM_METHOD_IDENTIFIERS; i++)
+ if (name == pluginMethodIdentifiers[i])
+ return true;
+ return false;
+}
+
+static bool pluginGetProperty(NPObject *obj, NPIdentifier name, NPVariant *variant)
+{
+ PluginObject *plugin = (PluginObject *)obj;
+ if (name == pluginPropertyIdentifiers[ID_TESTFILE_PROPERTY]) {
+ BOOLEAN_TO_NPVARIANT(true, *variant);
+ return true;
+ }
+ return false;
+}
+
+static bool pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant)
+{
+ return false;
+}
+
+static bool pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result)
+{
+ PluginObject *plugin = (PluginObject *)obj;
+ if (name == pluginMethodIdentifiers[ID_GETTESTFILE_METHOD]) {
+ return true;
+ }
+ return false;
+}
+
+static bool pluginInvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result)
+{
+ return false;
+}
+
+static void pluginInvalidate(NPObject *obj)
+{
+ // Release any remaining references to JavaScript objects.
+}
+
+static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
+{
+ PluginObject *newInstance = (PluginObject*) malloc(sizeof(PluginObject));
+ newInstance->header._class = theClass;
+ newInstance->header.referenceCount = 1;
+
+ if (!identifiersInitialized) {
+ identifiersInitialized = true;
+ initializeIdentifiers();
+ }
+
+ newInstance->npp = npp;
+
+ return &newInstance->header;
+}
+
+static void pluginDeallocate(NPObject *obj)
+{
+ free(obj);
+}
+
+static bool pluginRemoveProperty(NPObject *npobj, NPIdentifier name)
+{
+ return false;
+}
+
+static bool pluginEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count)
+{
+ return false;
+}
diff --git a/tests/BrowserTestPlugin/jni/PluginObject.h b/tests/BrowserTestPlugin/jni/PluginObject.h
new file mode 100644
index 0000000..a058d4a
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/PluginObject.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in
+ consideration of your agreement to the following terms, and your use, installation,
+ modification or redistribution of this Apple software constitutes acceptance of these
+ terms. If you do not agree with these terms, please do not use, install, modify or
+ redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject to these
+ terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in
+ this original Apple software (the "Apple Software"), to use, reproduce, modify and
+ redistribute the Apple Software, with or without modifications, in source and/or binary
+ forms; provided that if you redistribute the Apple Software in its entirety and without
+ modifications, you must retain this notice and the following text and disclaimers in all
+ such redistributions of the Apple Software. Neither the name, trademarks, service marks
+ or logos of Apple Computer, Inc. may be used to endorse or promote products derived from
+ the Apple Software without specific prior written permission from Apple. Except as expressly
+ stated in this notice, no other rights or licenses, express or implied, are granted by Apple
+ herein, including but not limited to any patent rights that may be infringed by your
+ derivative works or by other works in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES,
+ EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS
+ USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
+ REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
+ WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
+ OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginObject__DEFINED
+#define PluginObject__DEFINED
+
+#include "main.h"
+
+class SubPlugin {
+public:
+ SubPlugin(NPP inst) : m_inst(inst) {}
+ virtual ~SubPlugin() {}
+ virtual int16 handleEvent(const ANPEvent* evt) = 0;
+
+ NPP inst() const { return m_inst; }
+
+private:
+ NPP m_inst;
+};
+
+typedef struct PluginObject {
+ NPObject header;
+ NPP npp;
+ NPWindow* window;
+
+ SubPlugin* subPlugin;
+
+} PluginObject;
+
+NPClass *getPluginClass(void);
+
+#endif // PluginObject__DEFINED
diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
new file mode 100644
index 0000000..1263204
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "EventPlugin.h"
+#include "android_npapi.h"
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+#include <math.h>
+#include <string.h>
+
+extern NPNetscapeFuncs* browser;
+extern ANPCanvasInterfaceV0 gCanvasI;
+extern ANPLogInterfaceV0 gLogI;
+extern ANPPaintInterfaceV0 gPaintI;
+extern ANPSurfaceInterfaceV0 gSurfaceI;
+extern ANPTypefaceInterfaceV0 gTypefaceI;
+
+///////////////////////////////////////////////////////////////////////////////
+
+EventPlugin::EventPlugin(NPP inst) : SubPlugin(inst) {
+
+ // initialize the drawing surface
+ m_surfaceReady = false;
+ m_surface = gSurfaceI.newRasterSurface(inst, kRGB_565_ANPBitmapFormat, false);
+ if(!m_surface)
+ gLogI.log(inst, kError_ANPLogType, "----%p Unable to create Raster surface", inst);
+}
+
+EventPlugin::~EventPlugin() {
+ gSurfaceI.deleteSurface(m_surface);
+}
+
+void EventPlugin::drawPlugin(int surfaceWidth, int surfaceHeight) {
+
+ gLogI.log(inst(), kDebug_ANPLogType, " ------ %p drawing the plugin (%d,%d)", inst(), surfaceWidth, surfaceHeight);
+
+ // get the plugin's dimensions according to the DOM
+ PluginObject *obj = (PluginObject*) inst()->pdata;
+ const int W = obj->window->width;
+ const int H = obj->window->height;
+
+ // compute the current zoom level
+ const float zoomFactorW = static_cast<float>(surfaceWidth) / W;
+ const float zoomFactorH = static_cast<float>(surfaceHeight) / H;
+
+ // check to make sure the zoom level is uniform
+ if (zoomFactorW + .01 < zoomFactorH && zoomFactorW - .01 > zoomFactorH)
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p zoom is out of sync (%f,%f)",
+ inst(), zoomFactorW, zoomFactorH);
+
+ // scale the variables based on the zoom level
+ const int fontSize = (int)(zoomFactorW * 16);
+ const int leftMargin = (int)(zoomFactorW * 10);
+
+ // lock the surface
+ ANPBitmap bitmap;
+ if (!m_surfaceReady || !gSurfaceI.lock(m_surface, &bitmap, NULL)) {
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p unable to lock the plugin", inst());
+ return;
+ }
+
+ // create a canvas
+ ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap);
+ gCanvasI.drawColor(canvas, 0xFFFFFFFF);
+
+ // configure the paint
+ ANPPaint* paint = gPaintI.newPaint();
+ gPaintI.setFlags(paint, gPaintI.getFlags(paint) | kAntiAlias_ANPPaintFlag);
+ gPaintI.setColor(paint, 0xFF0000FF);
+ gPaintI.setTextSize(paint, fontSize);
+
+ // configure the font
+ ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle);
+ gPaintI.setTypeface(paint, tf);
+ gTypefaceI.unref(tf);
+
+ // retrieve the font metrics
+ ANPFontMetrics fm;
+ gPaintI.getFontMetrics(paint, &fm);
+
+ // write text on the canvas
+ const char c[] = "Browser Test Plugin";
+ gCanvasI.drawText(canvas, c, sizeof(c)-1, leftMargin, -fm.fTop, paint);
+
+ // clean up variables and unlock the surface
+ gPaintI.deletePaint(paint);
+ gCanvasI.deleteCanvas(canvas);
+ gSurfaceI.unlock(m_surface);
+}
+
+void EventPlugin::printToDiv(const char* text, int length) {
+ // Get the plugin's DOM object
+ NPObject* windowObject = NULL;
+ browser->getvalue(inst(), NPNVWindowNPObject, &windowObject);
+
+ if (!windowObject)
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p Unable to retrieve DOM Window", inst());
+
+ // create a string (JS code) that is stored in memory allocated by the browser
+ const char* jsBegin = "var outputDiv = document.getElementById('eventOutput'); outputDiv.innerHTML += ' ";
+ const char* jsEnd = "';";
+
+ // allocate memory and configure pointers
+ int totalLength = strlen(jsBegin) + length + strlen(jsEnd);
+ char* beginMem = (char*)browser->memalloc(totalLength);
+ char* middleMem = beginMem + strlen(jsBegin);
+ char* endMem = middleMem + length;
+
+ // copy into the allocated memory
+ memcpy(beginMem, jsBegin, strlen(jsBegin));
+ memcpy(middleMem, text, length);
+ memcpy(endMem, jsEnd, strlen(jsEnd));
+
+ gLogI.log(inst(), kError_ANPLogType, "text: %.*s\n", totalLength, (char*)beginMem);
+
+ // execute the javascript in the plugin's DOM object
+ NPString script = { (char*)beginMem, totalLength };
+ NPVariant scriptVariant;
+ if (!browser->evaluate(inst(), windowObject, &script, &scriptVariant))
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p Unable to eval the JS.", inst());
+
+ // free the memory allocated within the browser
+ browser->memfree(beginMem);
+}
+
+int16 EventPlugin::handleEvent(const ANPEvent* evt) {
+ switch (evt->eventType) {
+ case kDraw_ANPEventType:
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request draw events", inst());
+ break;
+ case kSurface_ANPEventType:
+ switch (evt->data.surface.action) {
+ case kCreated_ANPSurfaceAction:
+ m_surfaceReady = true;
+ return 1;
+ case kDestroyed_ANPSurfaceAction:
+ m_surfaceReady = false;
+ return 1;
+ case kChanged_ANPSurfaceAction:
+ drawPlugin(evt->data.surface.data.changed.width,
+ evt->data.surface.data.changed.height);
+ return 1;
+ }
+ break;
+ case kLifecycle_ANPEventType:
+ switch (evt->data.lifecycle.action) {
+ case kOnLoad_ANPLifecycleAction: {
+ char msg[] = "lifecycle-onLoad";
+ printToDiv(msg, strlen(msg));
+ break;
+ }
+ case kGainFocus_ANPLifecycleAction: {
+ char msg[] = "lifecycle-gainFocus";
+ printToDiv(msg, strlen(msg));
+ break;
+ }
+ case kLoseFocus_ANPLifecycleAction: {
+ char msg[] = "lifecycle-loseFocus";
+ printToDiv(msg, strlen(msg));
+ break;
+ }
+ }
+ return 1;
+ case kTouch_ANPEventType:
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request touch events", inst());
+ break;
+ case kKey_ANPEventType:
+ gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request key events", inst());
+ break;
+ default:
+ break;
+ }
+ return 0; // unknown or unhandled event
+}
diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.h b/tests/BrowserTestPlugin/jni/event/EventPlugin.h
new file mode 100644
index 0000000..73dd6ea
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PluginObject.h"
+
+#ifndef eventPlugin__DEFINED
+#define eventPlugin__DEFINED
+
+class EventPlugin : public SubPlugin {
+public:
+ EventPlugin(NPP inst);
+ virtual ~EventPlugin();
+ virtual int16 handleEvent(const ANPEvent* evt);
+
+private:
+ void drawPlugin(int surfaceWidth, int surfaceHeight);
+ void printToDiv(const char* text, int length);
+
+ bool m_surfaceReady;
+ ANPSurface* m_surface;
+};
+
+#endif // eventPlugin__DEFINED
diff --git a/tests/BrowserTestPlugin/jni/main.cpp b/tests/BrowserTestPlugin/jni/main.cpp
new file mode 100644
index 0000000..056ec4d
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/main.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "android_npapi.h"
+#include "main.h"
+#include "PluginObject.h"
+#include "EventPlugin.h"
+
+NPNetscapeFuncs* browser;
+#define EXPORT __attribute__((visibility("default")))
+
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
+ char* argn[], char* argv[], NPSavedData* saved);
+NPError NPP_Destroy(NPP instance, NPSavedData** save);
+NPError NPP_SetWindow(NPP instance, NPWindow* window);
+NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
+int32 NPP_WriteReady(NPP instance, NPStream* stream);
+int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len,
+ void* buffer);
+void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
+void NPP_Print(NPP instance, NPPrint* platformPrint);
+int16 NPP_HandleEvent(NPP instance, void* event);
+void NPP_URLNotify(NPP instance, const char* URL, NPReason reason,
+ void* notifyData);
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value);
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value);
+
+extern "C" {
+EXPORT NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context);
+EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value);
+EXPORT const char* NP_GetMIMEDescription(void);
+EXPORT void NP_Shutdown(void);
+};
+
+ANPAudioTrackInterfaceV0 gSoundI;
+ANPBitmapInterfaceV0 gBitmapI;
+ANPCanvasInterfaceV0 gCanvasI;
+ANPLogInterfaceV0 gLogI;
+ANPPaintInterfaceV0 gPaintI;
+ANPPathInterfaceV0 gPathI;
+ANPSurfaceInterfaceV0 gSurfaceI;
+ANPSystemInterfaceV0 gSystemI;
+ANPTypefaceInterfaceV0 gTypefaceI;
+ANPWindowInterfaceV0 gWindowI;
+
+#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
+
+NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context)
+{
+ // Make sure we have a function table equal or larger than we are built against.
+ if (browserFuncs->size < sizeof(NPNetscapeFuncs)) {
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // Copy the function table (structure)
+ browser = (NPNetscapeFuncs*) malloc(sizeof(NPNetscapeFuncs));
+ memcpy(browser, browserFuncs, sizeof(NPNetscapeFuncs));
+
+ // Build the plugin function table
+ pluginFuncs->version = 11;
+ pluginFuncs->size = sizeof(pluginFuncs);
+ pluginFuncs->newp = NPP_New;
+ pluginFuncs->destroy = NPP_Destroy;
+ pluginFuncs->setwindow = NPP_SetWindow;
+ pluginFuncs->newstream = NPP_NewStream;
+ pluginFuncs->destroystream = NPP_DestroyStream;
+ pluginFuncs->asfile = NPP_StreamAsFile;
+ pluginFuncs->writeready = NPP_WriteReady;
+ pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
+ pluginFuncs->print = NPP_Print;
+ pluginFuncs->event = NPP_HandleEvent;
+ pluginFuncs->urlnotify = NPP_URLNotify;
+ pluginFuncs->getvalue = NPP_GetValue;
+ pluginFuncs->setvalue = NPP_SetValue;
+
+ static const struct {
+ NPNVariable v;
+ uint32_t size;
+ ANPInterface* i;
+ } gPairs[] = {
+ { kAudioTrackInterfaceV0_ANPGetValue, sizeof(gSoundI), &gSoundI },
+ { kBitmapInterfaceV0_ANPGetValue, sizeof(gBitmapI), &gBitmapI },
+ { kCanvasInterfaceV0_ANPGetValue, sizeof(gCanvasI), &gCanvasI },
+ { kLogInterfaceV0_ANPGetValue, sizeof(gLogI), &gLogI },
+ { kPaintInterfaceV0_ANPGetValue, sizeof(gPaintI), &gPaintI },
+ { kPathInterfaceV0_ANPGetValue, sizeof(gPathI), &gPathI },
+ { kSurfaceInterfaceV0_ANPGetValue, sizeof(gSurfaceI), &gSurfaceI },
+ { kSystemInterfaceV0_ANPGetValue, sizeof(gSystemI), &gSystemI },
+ { kTypefaceInterfaceV0_ANPGetValue, sizeof(gTypefaceI), &gTypefaceI },
+ { kWindowInterfaceV0_ANPGetValue, sizeof(gWindowI), &gWindowI },
+ };
+ for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) {
+ gPairs[i].i->inSize = gPairs[i].size;
+ NPError err = browser->getvalue(NULL, gPairs[i].v, gPairs[i].i);
+ if (err) {
+ return err;
+ }
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+void NP_Shutdown(void)
+{
+
+}
+
+const char *NP_GetMIMEDescription(void)
+{
+ return "application/x-browsertestplugin:btp:Android Browser Test Plugin";
+}
+
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
+ char* argn[], char* argv[], NPSavedData* saved)
+{
+
+
+ gLogI.log(instance, kDebug_ANPLogType, "creating plugin");
+
+ PluginObject *obj = NULL;
+
+ // Scripting functions appeared in NPAPI version 14
+ if (browser->version >= 14) {
+ instance->pdata = browser->createobject (instance, getPluginClass());
+ obj = static_cast<PluginObject*>(instance->pdata);
+ bzero(obj, sizeof(*obj));
+ } else {
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // select the drawing model
+ ANPDrawingModel model = kSurface_ANPDrawingModel;
+
+ // notify the plugin API of the drawing model we wish to use. This must be
+ // done prior to creating certain subPlugin objects (e.g. surfaceViews)
+ NPError err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue,
+ reinterpret_cast<void*>(model));
+ if (err) {
+ gLogI.log(instance, kError_ANPLogType, "request model %d err %d", model, err);
+ return err;
+ }
+
+ // create the sub-plugin
+ obj->subPlugin = new EventPlugin(instance);
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_Destroy(NPP instance, NPSavedData** save)
+{
+ PluginObject *obj = (PluginObject*) instance->pdata;
+ delete obj->subPlugin;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_SetWindow(NPP instance, NPWindow* window)
+{
+ PluginObject *obj = (PluginObject*) instance->pdata;
+
+ // Do nothing if browser didn't support NPN_CreateObject which would have created the PluginObject.
+ if (obj != NULL) {
+ obj->window = window;
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
+{
+ *stype = NP_ASFILEONLY;
+ return NPERR_NO_ERROR;
+}
+
+NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
+{
+ return NPERR_NO_ERROR;
+}
+
+int32 NPP_WriteReady(NPP instance, NPStream* stream)
+{
+ return 0;
+}
+
+int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer)
+{
+ return 0;
+}
+
+void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
+{
+}
+
+void NPP_Print(NPP instance, NPPrint* platformPrint)
+{
+}
+
+int16 NPP_HandleEvent(NPP instance, void* event)
+{
+ PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata);
+ const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event);
+
+ if(!obj->subPlugin) {
+ gLogI.log(instance, kError_ANPLogType, "the sub-plugin is null.");
+ return 0; // unknown or unhandled event
+ }
+ else {
+ return obj->subPlugin->handleEvent(evt);
+ }
+}
+
+void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
+{
+}
+
+EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) {
+
+ if (variable == NPPVpluginNameString) {
+ const char **str = (const char **)value;
+ *str = "Browser Test Plugin";
+ return NPERR_NO_ERROR;
+ }
+
+ if (variable == NPPVpluginDescriptionString) {
+ const char **str = (const char **)value;
+ *str = "Description of Browser Test Plugin";
+ return NPERR_NO_ERROR;
+ }
+
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
+{
+ if (variable == NPPVpluginScriptableNPObject) {
+ void **v = (void **)value;
+ PluginObject *obj = (PluginObject*) instance->pdata;
+
+ if (obj)
+ browser->retainobject((NPObject*)obj);
+
+ *v = obj;
+ return NPERR_NO_ERROR;
+ }
+
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
+{
+ return NPERR_GENERIC_ERROR;
+}
+
diff --git a/tests/BrowserTestPlugin/jni/main.h b/tests/BrowserTestPlugin/jni/main.h
new file mode 100644
index 0000000..e6e8c73
--- /dev/null
+++ b/tests/BrowserTestPlugin/jni/main.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <npapi.h>
+#include <npfunctions.h>
+#include <npruntime.h>
+#include "android_npapi.h"
+
+extern NPNetscapeFuncs* browser;
diff --git a/tests/BrowserTestPlugin/res/drawable/browser_test_plugin.png b/tests/BrowserTestPlugin/res/drawable/browser_test_plugin.png
new file mode 100755
index 0000000..47c79d1
--- /dev/null
+++ b/tests/BrowserTestPlugin/res/drawable/browser_test_plugin.png
Binary files differ
diff --git a/tests/BrowserTestPlugin/src/com/android/testplugin/TestPlugin.java b/tests/BrowserTestPlugin/src/com/android/testplugin/TestPlugin.java
new file mode 100644
index 0000000..94a18fd
--- /dev/null
+++ b/tests/BrowserTestPlugin/src/com/android/testplugin/TestPlugin.java
@@ -0,0 +1,15 @@
+package com.android.testplugin;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class TestPlugin extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
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/android/core/RecurrenceSetTest.java b/tests/CoreTests/android/core/RecurrenceSetTest.java
new file mode 100644
index 0000000..cee324c
--- /dev/null
+++ b/tests/CoreTests/android/core/RecurrenceSetTest.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.core;
+
+import android.content.ContentValues;
+import android.pim.ICalendar;
+import android.pim.RecurrenceSet;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.provider.Calendar;
+import junit.framework.TestCase;
+
+/**
+ * Test some pim.RecurrenceSet functionality.
+ */
+public class RecurrenceSetTest extends TestCase {
+
+ // Test a recurrence
+ @SmallTest
+ public void testRecurrenceSet0() throws Exception {
+ String recurrence = "DTSTART;TZID=America/New_York:20080221T070000\n"
+ + "DTEND;TZID=America/New_York:20080221T190000\n"
+ + "RRULE:FREQ=DAILY;UNTIL=20080222T000000Z\n"
+ + "EXDATE:20080222T120000Z";
+ verifyPopulateContentValues(recurrence, "FREQ=DAILY;UNTIL=20080222T000000Z", null,
+ null, "20080222T120000Z", 1203595200000L, "America/New_York", "P43200S", 0);
+ }
+
+ // Test 1 day all-day event
+ @SmallTest
+ public void testRecurrenceSet1() throws Exception {
+ String recurrence = "DTSTART;VALUE=DATE:20090821\nDTEND;VALUE=DATE:20090822\n"
+ + "RRULE:FREQ=YEARLY;WKST=SU";
+ verifyPopulateContentValues(recurrence, "FREQ=YEARLY;WKST=SU", null,
+ null, null, 1250812800000L, null, "P1D", 1);
+ }
+
+ // Test 2 day all-day event
+ @SmallTest
+ public void testRecurrenceSet2() throws Exception {
+ String recurrence = "DTSTART;VALUE=DATE:20090821\nDTEND;VALUE=DATE:20090823\n"
+ + "RRULE:FREQ=YEARLY;WKST=SU";
+ verifyPopulateContentValues(recurrence, "FREQ=YEARLY;WKST=SU", null,
+ null, null, 1250812800000L, null, "P2D", 1);
+ }
+
+ // run populateContentValues and verify the results
+ private void verifyPopulateContentValues(String recurrence, String rrule, String rdate,
+ String exrule, String exdate, long dtstart, String tzid, String duration, int allDay)
+ throws ICalendar.FormatException {
+ ICalendar.Component recurrenceComponent =
+ new ICalendar.Component("DUMMY", null /* parent */);
+ ICalendar.parseComponent(recurrenceComponent, recurrence);
+ ContentValues values = new ContentValues();
+ RecurrenceSet.populateContentValues(recurrenceComponent, values);
+ Log.d("KS", "values " + values);
+
+ assertEquals(rrule, values.get(android.provider.Calendar.Events.RRULE));
+ assertEquals(rdate, values.get(android.provider.Calendar.Events.RDATE));
+ assertEquals(exrule, values.get(android.provider.Calendar.Events.EXRULE));
+ assertEquals(exdate, values.get(android.provider.Calendar.Events.EXDATE));
+ assertEquals(dtstart, (long) values.getAsLong(Calendar.Events.DTSTART));
+ assertEquals(tzid, values.get(android.provider.Calendar.Events.EVENT_TIMEZONE));
+ assertEquals(duration, values.get(android.provider.Calendar.Events.DURATION));
+ assertEquals(allDay,
+ (int) values.getAsInteger(android.provider.Calendar.Events.ALL_DAY));
+ }
+}
diff --git a/tests/CoreTests/android/core/RequestAPITest.java b/tests/CoreTests/android/core/RequestAPITest.java
index d89f5ae..94eb23e 100644
--- a/tests/CoreTests/android/core/RequestAPITest.java
+++ b/tests/CoreTests/android/core/RequestAPITest.java
@@ -72,7 +72,7 @@ public class RequestAPITest extends AndroidTestCase implements HttpConstants {
RequestHandle handle =
mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", headers, null,
- null, 0, false);
+ null, 0);
handle.waitUntilComplete();
fail("expected exception not thrown");
@@ -121,7 +121,7 @@ public class RequestAPITest extends AndroidTestCase implements HttpConstants {
mTestWebServer.setKeepAlive(false);
RequestHandle handle = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", headers, null,
- null, 0, false);
+ null, 0);
handle.waitUntilComplete();
}
@@ -197,7 +197,7 @@ public class RequestAPITest extends AndroidTestCase implements HttpConstants {
RequestHandle handle = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", null, testEventHandler,
- null, 0, false);
+ null, 0);
Log.d(LOGTAG, "testGet - sent request. Waiting");
handle.waitUntilComplete();
@@ -231,11 +231,11 @@ public class RequestAPITest extends AndroidTestCase implements HttpConstants {
RequestHandle handle0 = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", null, testEventHandler,
- null, 0, false);
+ null, 0);
handle0.waitUntilComplete();
RequestHandle handle1 = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", null, testEventHandler2,
- null, 0, false);
+ null, 0);
handle1.waitUntilComplete();
/* It's not correct to use same listener for multiple
@@ -270,7 +270,7 @@ public class RequestAPITest extends AndroidTestCase implements HttpConstants {
RequestHandle handle = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "HEAD", null, testEventHandler,
- null, 0, false);
+ null, 0);
Log.d(LOGTAG, "testHead - sent request waiting");
handle.waitUntilComplete();
@@ -297,7 +297,7 @@ public class RequestAPITest extends AndroidTestCase implements HttpConstants {
RequestHandle handle = mRequestQueue.queueRequest(
"http://localhost:8080/test1", "GET", null, testEventHandler,
- null, 0, false);
+ null, 0);
Log.d(LOGTAG, "testChunked - sent request waiting");
handle.waitUntilComplete();
@@ -330,7 +330,7 @@ public class RequestAPITest extends AndroidTestCase implements HttpConstants {
Log.d(LOGTAG, testName + " start - rq = " + mRequestQueue);
RequestHandle requestHandle = mRequestQueue.queueRequest(
- "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0, false);
+ "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0);
Log.d(LOGTAG, testName + " - sent request waiting");
requestHandle.waitUntilComplete();
@@ -398,10 +398,10 @@ public class RequestAPITest extends AndroidTestCase implements HttpConstants {
leh2.expectHeaders();
RequestHandle handle0 = mRequestQueue.queueRequest(
- "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0, false);
+ "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0);
handle0.waitUntilComplete();
RequestHandle handle1 = mRequestQueue.queueRequest(
- "http://localhost:8080/test1", "HEAD", null, testEventHandler, null, 0, false);
+ "http://localhost:8080/test1", "HEAD", null, testEventHandler, null, 0);
Log.d(LOGTAG, "testGetAndHead - sent request. Waiting");
handle1.waitUntilComplete();
@@ -432,7 +432,7 @@ public class RequestAPITest extends AndroidTestCase implements HttpConstants {
Log.d(LOGTAG, "testPost start - rq = " + mRequestQueue);
RequestHandle handle = mRequestQueue.queueRequest(
- "http://localhost:8080/test1", "POST", null, testEventHandler, null, 0, false);
+ "http://localhost:8080/test1", "POST", null, testEventHandler, null, 0);
Log.d(LOGTAG, "testPost - sent request waiting");
handle.waitUntilComplete();
@@ -470,7 +470,7 @@ public class RequestAPITest extends AndroidTestCase implements HttpConstants {
InputStream bodyProvider = new ByteArrayInputStream(mBody.getBytes());
RequestHandle handle = mRequestQueue.queueRequest(
- "http://localhost:8080/test1", "POST", null, testEventHandler, bodyProvider, bodyLength, false);
+ "http://localhost:8080/test1", "POST", null, testEventHandler, bodyProvider, bodyLength);
Log.d(LOGTAG, "testPostWithData - sent request waiting");
handle.waitUntilComplete();
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
index 577d384..7426d33 100644
--- a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -309,6 +309,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
@@ -330,4 +335,76 @@ public class PhoneNumberUtilsTest extends TestCase {
assertEquals("(800) 222-3334",
PhoneNumberUtils.convertKeypadLettersToDigits("(800) ABC-DEFG"));
}
+
+ @SmallTest
+ public void testCheckAndProcessPlusCode() {
+ assertEquals("0118475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000"));
+ assertEquals("18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+18475797000"));
+ assertEquals("0111234567",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+1234567"));
+ assertEquals("01123456700000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+23456700000"));
+ assertEquals("01111875767800",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+11875767800"));
+ assertEquals("8475797000,18475231753",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+18475231753"));
+ assertEquals("0118475797000,18475231753",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000,+18475231753"));
+ assertEquals("8475797000;0118469312345",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;+8469312345"));
+ assertEquals("8475797000,0111234567",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+1234567"));
+ assertEquals("847597000;01111875767000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("847597000;+11875767000"));
+ assertEquals("8475797000,,0118469312345",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,+8469312345"));
+ assertEquals("8475797000;,0118469312345",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+8469312345"));
+ assertEquals("8475797000,;18475231753",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+18475231753"));
+ assertEquals("8475797000;,01111875767000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+11875767000"));
+ assertEquals("8475797000,;01111875767000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+11875767000"));
+ assertEquals("8475797000,,,01111875767000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,,+11875767000"));
+ assertEquals("8475797000;,,01111875767000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,,+11875767000"));
+ assertEquals("+;,8475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+;,8475797000"));
+ assertEquals("8475797000,",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,"));
+ assertEquals("847+579-7000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("847+579-7000"));
+ assertEquals(",8475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode(",8475797000"));
+ assertEquals(";;8475797000,,",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode(";;8475797000,,"));
+ assertEquals("+this+is$weird;,+",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+this+is$weird;,+"));
+ assertEquals("",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCode(""));
+ assertNull(PhoneNumberUtils.cdmaCheckAndProcessPlusCode(null));
+ }
+
+ @SmallTest
+ public void testCheckAndProcessPlusCodeByNumberFormat() {
+ assertEquals("18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
+ PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_NANP));
+ assertEquals("+18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
+ PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_JAPAN));
+ assertEquals("+18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
+ PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_UNKNOWN));
+ assertEquals("+18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
+ PhoneNumberUtils.FORMAT_JAPAN,PhoneNumberUtils.FORMAT_JAPAN));
+ assertEquals("+18475797000",
+ PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
+ PhoneNumberUtils.FORMAT_UNKNOWN,PhoneNumberUtils.FORMAT_UNKNOWN));
+ }
}
diff --git a/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java
index e733af9..6f25fd9 100644
--- a/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java
@@ -44,13 +44,22 @@ public class SimUtilsTest extends TestCase {
assertEquals("890", IccUtils.bcdToString(data, 0, data.length));
/*
- * bcdByteToInt()
- */
+ * gsmBcdByteToInt()
+ */
+
+ assertEquals(98, IccUtils.gsmBcdByteToInt((byte) 0x89));
+
+ // Out of range is treated as 0
+ assertEquals(8, IccUtils.gsmBcdByteToInt((byte) 0x8c));
- assertEquals(98, IccUtils.bcdByteToInt((byte) 0x89));
+ /*
+ * cdmaBcdByteToInt()
+ */
+
+ assertEquals(89, IccUtils.cdmaBcdByteToInt((byte) 0x89));
// Out of range is treated as 0
- assertEquals(8, IccUtils.bcdByteToInt((byte) 0x8c));
+ assertEquals(80, IccUtils.gsmBcdByteToInt((byte) 0x8c));
/*
* adnStringFieldToString()
@@ -76,4 +85,3 @@ public class SimUtilsTest extends TestCase {
}
}
-
diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
index b4fb324..fdfafe1 100644
--- a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
+++ b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
@@ -47,6 +47,7 @@ public class TelephonyTests {
suite.addTestSuite(SimUtilsTest.class);
suite.addTestSuite(SimPhoneBookTest.class);
suite.addTestSuite(SimSmsTest.class);
+ suite.addTestSuite(TelephonyUtilsTest.class);
return suite;
}
diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java
new file mode 100644
index 0000000..bf0c88b
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java
@@ -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.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.RetryManager;
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class TelephonyUtilsTest extends TestCase {
+
+ /**
+ * After first creating the RetryManager
+ * isRetryNeeded should be false and the time 0
+ */
+ @SmallTest
+ public void testRetryManagerEmpty() throws Exception {
+ RetryManager rm = new RetryManager();
+
+ assertEquals(0, rm.getRetryCount());
+ assertFalse(rm.isRetryForever());
+ assertFalse(rm.isRetryNeeded());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(0, rm.getRetryTimer());
+
+ rm.increaseRetryCount();
+ assertFalse(rm.isRetryForever());
+ assertFalse(rm.isRetryNeeded());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(0, rm.getRetryTimer());
+
+ rm.setRetryCount(123);
+ assertFalse(rm.isRetryForever());
+ assertFalse(rm.isRetryNeeded());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(0, rm.getRetryTimer());
+
+ rm.retryForeverUsingLastTimeout();
+ assertTrue(rm.isRetryForever());
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(0, rm.getRetryTimer());
+
+ rm.setRetryCount(2);
+ assertFalse(rm.isRetryForever());
+ assertFalse(rm.isRetryNeeded());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(0, rm.getRetryTimer());
+ }
+
+ /**
+ * A simple test and that randomization is doing something.
+ */
+ @SmallTest
+ public void testRetryManagerSimplest() throws Exception {
+ RetryManager rm = new RetryManager();
+
+ assertTrue(rm.configure(1, 500, 10));
+ int loops = 10;
+ int count = 0;
+ for (int i = 0; i < loops; i++) {
+ assertTrue(rm.isRetryNeeded());
+ int time = rm.getRetryTimer();
+ assertTrue((time >= 500) && (time < 600));
+ if (time == 500) {
+ count++;
+ }
+ }
+ assertFalse(count == loops);
+ rm.increaseRetryCount();
+ assertFalse(rm.isRetryNeeded());
+ rm.setRetryCount(0);
+ assertTrue(rm.isRetryNeeded());
+ }
+
+ /**
+ * Test multiple values using simple configuration.
+ */
+ @SmallTest
+ public void testRetryManagerSimple() throws Exception {
+ RetryManager rm = new RetryManager();
+
+ assertTrue(rm.configure(3, 1000, 0));
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(1000, rm.getRetryTimer());
+ assertEquals(rm.getRetryTimer(), 1000);
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(1000, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(1000, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertFalse(rm.isRetryNeeded());
+ assertEquals(1000, rm.getRetryTimer());
+ }
+
+ /**
+ * Test string configuration, simplest
+ */
+ @SmallTest
+ public void testRetryManageSimpleString() throws Exception {
+ RetryManager rm = new RetryManager();
+
+ assertTrue(rm.configure("101"));
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(101, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertFalse(rm.isRetryNeeded());
+ }
+
+ /**
+ * Test infinite retires
+ */
+ @SmallTest
+ public void testRetryManageInfinite() throws Exception {
+ RetryManager rm = new RetryManager();
+
+ assertTrue(rm.configure("1000,2000,3000,max_retries=infinite"));
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(1000, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ assertEquals(2000, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ // All others are 3000 and isRetryNeeded is always true
+ for (int i=0; i < 100; i++) {
+ assertEquals(3000, rm.getRetryTimer());
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ }
+ }
+
+ /**
+ * Test string configuration using all options.
+ */
+ @SmallTest
+ public void testRetryManageString() throws Exception {
+ RetryManager rm = new RetryManager();
+ int time;
+
+ assertTrue(rm.configure("max_retries=4,"
+ + "default_randomization=100,1000, 2000 :200 , 3000"));
+ assertTrue(rm.isRetryNeeded());
+ time = rm.getRetryTimer();
+ assertTrue((time >= 1000) && (time < 1100));
+
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ time = rm.getRetryTimer();
+ assertTrue((time >= 2000) && (time < 2200));
+
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ time = rm.getRetryTimer();
+ assertTrue((time >= 3000) && (time < 3100));
+
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ time = rm.getRetryTimer();
+ assertTrue((time >= 3000) && (time < 3100));
+
+ rm.increaseRetryCount();
+ assertFalse(rm.isRetryNeeded());
+ }
+
+ /**
+ * Test string configuration using all options.
+ */
+ @SmallTest
+ public void testRetryManageForever() throws Exception {
+ RetryManager rm = new RetryManager();
+ int time;
+
+ assertTrue(rm.configure("1000, 2000, 3000"));
+ assertTrue(rm.isRetryNeeded());
+ assertFalse(rm.isRetryForever());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(1000, rm.getRetryTimer());
+
+ rm.retryForeverUsingLastTimeout();
+ rm.increaseRetryCount();
+ rm.increaseRetryCount();
+ rm.increaseRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ assertTrue(rm.isRetryForever());
+ assertEquals(3, rm.getRetryCount());
+ assertEquals(3000, rm.getRetryTimer());
+
+ rm.setRetryCount(1);
+ assertTrue(rm.isRetryNeeded());
+ assertFalse(rm.isRetryForever());
+ assertEquals(1, rm.getRetryCount());
+ assertEquals(2000, rm.getRetryTimer());
+
+ rm.retryForeverUsingLastTimeout();
+ assertTrue(rm.isRetryNeeded());
+ assertTrue(rm.isRetryForever());
+ rm.resetRetryCount();
+ assertTrue(rm.isRetryNeeded());
+ assertFalse(rm.isRetryForever());
+ assertEquals(0, rm.getRetryCount());
+ assertEquals(1000, rm.getRetryTimer());
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
index 7107412..b96743a 100644
--- a/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
@@ -81,7 +81,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl = mGSMTestHandler.getSimulatedCommands();
mHandler = mGSMTestHandler.getHandler();
- mGSMPhone.registerForPhoneStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null);
+ mGSMPhone.registerForPreciseCallStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null);
mGSMPhone.registerForNewRingingConnection(mHandler, EVENT_RINGING, null);
mGSMPhone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
@@ -109,7 +109,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
protected void tearDown() throws Exception {
mRadioControl.shutdown();
- mGSMPhone.unregisterForPhoneStateChanged(mHandler);
+ mGSMPhone.unregisterForPreciseCallStateChanged(mHandler);
mGSMPhone.unregisterForNewRingingConnection(mHandler);
mGSMPhone.unregisterForDisconnect(mHandler);
mGSMPhone.setOnPostDialCharacter(mHandler, 0, null);
diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py
index 49165d0..c056de5 100755
--- a/tests/DumpRenderTree/assets/run_layout_tests.py
+++ b/tests/DumpRenderTree/assets/run_layout_tests.py
@@ -22,7 +22,7 @@
use --refresh-test-list option *once* to re-generate test list on the card.
Some other options are:
- --rebaseline generates expected layout tests results under /sdcard/android/expected_result/
+ --rebaseline generates expected layout tests results under /sdcard/android/expected_result/
--time-out-ms (default is 8000 millis) for each test
--adb-options="-e" passes option string to adb
--results-directory=..., (default is ./layout-test-results) directory name under which results are stored.
@@ -51,11 +51,11 @@ def CountLineNumber(filename):
def DumpRenderTreeFinished(adb_cmd):
""" Check if DumpRenderTree finished running tests
-
+
Args:
output: adb_cmd string
"""
-
+
# pull /sdcard/android/running_test.txt, if the content is "#DONE", it's done
shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
@@ -69,7 +69,7 @@ def DiffResults(marker, new_results, old_results, diff_results, strip_reason,
"""
old_file = open(old_results, "r")
new_file = open(new_results, "r")
- diff_file = open(diff_results, "a")
+ diff_file = open(diff_results, "a")
# Read lines from each file
ndict = new_file.readlines()
@@ -122,7 +122,7 @@ def CompareResults(ref_dir, results_dir):
"""
logging.info("Comparing results to " + ref_dir)
- diff_result = os.path.join(results_dir, "layout_tests_diff.txt")
+ diff_result = os.path.join(results_dir, "layout_tests_diff.txt")
if os.path.exists(diff_result):
os.remove(diff_result)
@@ -136,7 +136,7 @@ def CompareResults(ref_dir, results_dir):
def main(options, args):
"""Run the tests. Will call sys.exit when complete.
-
+
Args:
options: a dictionary of command line options
args: a list of sub directories or files to test
@@ -198,7 +198,7 @@ def main(options, args):
shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
crashed_test = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE).communicate()[0]
-
+
logging.info(crashed_test + " CRASHED");
crashed_tests.append(crashed_test);
@@ -226,14 +226,15 @@ def main(options, args):
result_files = ["/sdcard/layout_tests_passed.txt",
"/sdcard/layout_tests_failed.txt",
"/sdcard/layout_tests_nontext.txt"]
- for file in result_files:
+ for file in result_files:
shell_cmd_str = adb_cmd + " pull " + file + " " + results_dir
adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
logging.debug(adb_output)
-
+
# Create the crash list.
fp = open(results_dir + "/layout_tests_crashed.txt", "w");
- fp.writelines('\n'.join(crashed_tests))
+ for crashed_test in crashed_tests:
+ fp.writelines(crashed_test + '\n')
fp.close()
# Count the number of tests in each category.
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
index a389461..f33b01d 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -18,6 +18,8 @@ package com.android.dumprendertree;
import android.os.Handler;
import android.os.Message;
+import android.webkit.MockGeolocation;
+import android.webkit.WebStorage;
import java.util.HashMap;
@@ -25,7 +27,7 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon
private EventSender mEventSender;
private LayoutTestController mLayoutTestController;
-
+
private static final int EVENT_DOM_LOG = 1;
private static final int EVENT_FIRE_KBD = 2;
private static final int EVENT_KEY_DOWN_1 = 3;
@@ -57,6 +59,9 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon
private static final int LAYOUT_SET_WINDOW_KEY = 38;
private static final int LAYOUT_TEST_REPAINT = 39;
private static final int LAYOUT_WAIT_UNTIL_DONE = 40;
+ private static final int LAYOUT_DUMP_DATABASE_CALLBACKS = 41;
+ private static final int LAYOUT_SET_CAN_OPEN_WINDOWS = 42;
+ private static final int SET_GEOLOCATION_PERMISSION = 43;
CallbackProxy(EventSender eventSender,
LayoutTestController layoutTestController) {
@@ -190,6 +195,19 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon
case LAYOUT_WAIT_UNTIL_DONE:
mLayoutTestController.waitUntilDone();
break;
+
+ case LAYOUT_DUMP_DATABASE_CALLBACKS:
+ mLayoutTestController.dumpDatabaseCallbacks();
+ break;
+
+ case LAYOUT_SET_CAN_OPEN_WINDOWS:
+ mLayoutTestController.setCanOpenWindows();
+ break;
+
+ case SET_GEOLOCATION_PERMISSION:
+ mLayoutTestController.setGeolocationPermission(
+ msg.arg1 == 1 ? true : false);
+ break;
}
}
@@ -314,7 +332,7 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon
}
public void setWindowIsKey(boolean b) {
- obtainMessage(LAYOUT_SET_WINDOW_KEY,b ? 1 : 0, 0).sendToTarget();
+ obtainMessage(LAYOUT_SET_WINDOW_KEY, b ? 1 : 0, 0).sendToTarget();
}
public void testRepaint() {
@@ -325,4 +343,35 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon
obtainMessage(LAYOUT_WAIT_UNTIL_DONE).sendToTarget();
}
+ public void dumpDatabaseCallbacks() {
+ obtainMessage(LAYOUT_DUMP_DATABASE_CALLBACKS).sendToTarget();
+ }
+
+ public void clearAllDatabases() {
+ WebStorage.getInstance().deleteAllData();
+ }
+
+ public void setDatabaseQuota(long quota) {
+ WebStorage.getInstance().setQuotaForOrigin("file://", quota);
+ }
+
+ public void setCanOpenWindows() {
+ obtainMessage(LAYOUT_SET_CAN_OPEN_WINDOWS).sendToTarget();
+ }
+
+ public void setMockGeolocationPosition(double latitude,
+ double longitude,
+ double accuracy) {
+ MockGeolocation.getInstance().setPosition(latitude,
+ longitude,
+ accuracy);
+ }
+
+ public void setMockGeolocationError(int code, String message) {
+ MockGeolocation.getInstance().setError(code, message);
+ }
+
+ public void setGeolocationPermission(boolean allow) {
+ obtainMessage(SET_GEOLOCATION_PERMISSION, allow ? 1 : 0, 0).sendToTarget();
+ }
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 4f162b3..8fea967 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -79,11 +79,25 @@ public class FileFilter {
"profiler", // profiler is not supported
"svg", // svg is not supported
"platform", // platform specific
- "http" // requires local http(s) server
+ "http", // requires local http(s) server
+ "fast/workers",
};
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",
+ // The Android browser has no notion of private browsing.
+ "storage/private-browsing-readonly.html",
+ "storage/domstorage/localstorage/private-browsing-affects-storage.html",
+ "storage/domstorage/sessionstorage/private-browsing-affects-storage.html",
+ // Android layout tests are stored in "layout_tests". The following two
+ // tests expect "LayoutTests" in their output.
+ "storage/domstorage/localstorage/iframe-events.html",
+ "storage/domstorage/sessionstorage/iframe-events.html"
+ };
static void fillIgnoreResultSet() {
// need test plugin
@@ -195,11 +209,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/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
index 6166dd0..f535ed7 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
@@ -58,5 +58,11 @@ public interface LayoutTestController {
public void queueLoad(String Url, String frameTarget);
public void setAcceptsEditing(boolean b);
-
+
+ // For storage tests
+ public void dumpDatabaseCallbacks();
+ public void setCanOpenWindows();
+
+ // For Geolocation tests
+ public void setGeolocationPermission(boolean allow);
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index a03490d..2eecef8 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -16,6 +16,9 @@
package com.android.dumprendertree;
+import com.android.dumprendertree.forwarder.AdbUtils;
+import com.android.dumprendertree.forwarder.ForwardServer;
+
import android.app.Instrumentation;
import android.content.Intent;
import android.os.Bundle;
@@ -42,7 +45,7 @@ class MyTestRecorder {
private BufferedOutputStream mBufferedOutputFailedStream;
private BufferedOutputStream mBufferedOutputNoresultStream;
private BufferedOutputStream mBufferedOutputTimedoutStream;
-
+
public void passed(String layout_file) {
try {
mBufferedOutputPassedStream.write(layout_file.getBytes());
@@ -52,7 +55,7 @@ class MyTestRecorder {
e.printStackTrace();
}
}
-
+
public void failed(String layout_file) {
try {
mBufferedOutputFailedStream.write(layout_file.getBytes());
@@ -62,7 +65,7 @@ class MyTestRecorder {
e.printStackTrace();
}
}
-
+
public void noresult(String layout_file) {
try {
mBufferedOutputNoresultStream.write(layout_file.getBytes());
@@ -72,7 +75,7 @@ class MyTestRecorder {
e.printStackTrace();
}
}
-
+
public void timedout(String url) {
try {
mBufferedOutputTimedoutStream.write(url.getBytes());
@@ -82,14 +85,14 @@ class MyTestRecorder {
e.printStackTrace();
}
}
-
+
public MyTestRecorder(boolean resume) {
try {
File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt");
File resultTimedoutFile = new File("/sdcard/layout_tests_timedout.txt");
-
+
mBufferedOutputPassedStream =
new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
mBufferedOutputFailedStream =
@@ -102,7 +105,7 @@ class MyTestRecorder {
e.printStackTrace();
}
}
-
+
public void close() {
try {
mBufferedOutputPassedStream.close();
@@ -120,7 +123,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
private static final String LOGTAG = "LayoutTests";
static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
-
+
static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
static final String LAYOUT_TESTS_RESULT_DIR = "/sdcard/android/layout_tests_results/";
static final String ANDROID_EXPECTED_RESULT_DIR = "/sdcard/android/expected_results/";
@@ -139,14 +142,35 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
static final String LAYOUT_RESULTS_CRASHED_RESULT_FILE = "results/layout_tests_crashed.txt";
static final String LAYOUT_TESTS_RUNNER = "run_layout_tests.py";
+ static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
+ static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
+ static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
+ static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
+ static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
+
+
+ private ForwardServer fs8000, fs8080, fs8443;
+
private MyTestRecorder mResultRecorder;
private Vector<String> mTestList;
private boolean mRebaselineResults;
private String mTestPathPrefix;
private boolean mFinished;
-
+
public LayoutTestsAutoTest() {
super("com.android.dumprendertree", TestShellActivity.class);
+
+ int addr = -1;
+ try {
+ addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+ } catch (IOException ioe) {
+ Log.e(LOGTAG, "failed to resolve server address.", ioe);
+ }
+ if(addr != -1) {
+ fs8000 = new ForwardServer(8000, addr, 8000);
+ fs8080 = new ForwardServer(8080, addr, 8080);
+ fs8443 = new ForwardServer(8443, addr, 8443);
+ }
}
// This function writes the result of the layout test to
@@ -157,7 +181,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
bundle.putBoolean(file, result);
inst.sendStatus(0, bundle);
}
-
+
private void getTestList() {
// Read test list.
try {
@@ -174,7 +198,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
}
}
-
+
private void resumeTestList() {
// read out the test name it stoped last time.
try {
@@ -189,7 +213,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
}
}
-
+
private void clearTestStatus() {
// Delete TEST_STATUS_FILE
try {
@@ -208,13 +232,13 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
// Write actual results to result directory.
return shortName.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_RESULT_DIR) + "-result.txt";
}
-
+
private String getExpectedResultFile(String test) {
int pos = test.lastIndexOf('.');
if(pos == -1)
return null;
String shortName = test.substring(0, pos);
- return shortName + "-expected.txt";
+ return shortName + "-expected.txt";
}
private String getAndroidExpectedResultFile(String expectedResultFile) {
@@ -224,7 +248,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
// Wrap up
private void failedCase(String file) {
Log.w("Layout test: ", file + " failed");
- mResultRecorder.failed(file);
+ mResultRecorder.failed(file);
}
private void passedCase(String file) {
@@ -236,7 +260,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
Log.v("Layout test:", file + " no expected result");
mResultRecorder.noresult(file);
}
-
+
private void processResult(String testFile, String actualResultFile, String expectedResultFile) {
Log.v(LOGTAG, " Processing result: " + testFile);
@@ -257,13 +281,13 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
break;
}
}
-
+
if (passing) {
passedCase(testFile);
} else {
failedCase(testFile);
}
-
+
fe.close();
fr.close();
} catch (FileNotFoundException ex) {
@@ -278,7 +302,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
noresultCase(testFile);
}
}
-
+
private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout) {
activity.setCallback(new TestShellCallback() {
public void finished() {
@@ -287,7 +311,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
LayoutTestsAutoTest.this.notifyAll();
}
}
-
+
public void timedOut(String url) {
}
});
@@ -306,16 +330,16 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
resultFile = getAndroidExpectedResultFile(expectedResultFile);
}
-
+
mFinished = false;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(activity, TestShellActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- intent.putExtra(TestShellActivity.TEST_URL, "file://" + test);
+ intent.putExtra(TestShellActivity.TEST_URL, getTestUrl(test));
intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
activity.startActivity(intent);
-
+
// Wait until done.
synchronized (this) {
while(!mFinished){
@@ -324,18 +348,18 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
} catch (InterruptedException e) { }
}
}
-
+
if (!mRebaselineResults) {
String expectedResultFile = getExpectedResultFile(test);
File f = new File(expectedResultFile);
if (!f.exists()) {
expectedResultFile = getAndroidExpectedResultFile(expectedResultFile);
}
-
+
processResult(test, resultFile, expectedResultFile);
}
- }
-
+ }
+
// Invokes running of layout tests
// and waits till it has finished running.
public void executeLayoutTests(boolean resume) {
@@ -348,28 +372,28 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
}
this.mTestList = new Vector<String>();
-
+
// Read settings
try {
this.mTestPathPrefix =
(new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getCanonicalPath();
- } catch (IOException e) {
+ } catch (IOException e) {
Log.e(LOGTAG, "Cannot find test path prefix: " + e.getMessage());
return;
}
-
+
this.mRebaselineResults = runner.mRebaseline;
-
+
int timeout = runner.mTimeoutInMillis;
if (timeout <= 0) {
timeout = DEFAULT_TIMEOUT_IN_MILLIS;
}
-
+
this.mResultRecorder = new MyTestRecorder(resume);
-
+
if (!resume)
clearTestStatus();
-
+
getTestList();
if (resume)
resumeTestList();
@@ -377,6 +401,15 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
TestShellActivity activity = (TestShellActivity) getActivity();
// Run tests.
+ int addr = -1;
+ try{
+ addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error while resolving test host name", ioe);
+ }
+ if(addr == -1) {
+ Log.w(LOGTAG, "failed to resolve test host. http tests will fail.");
+ }
for (int i = 0; i < mTestList.size(); i++) {
String s = mTestList.elementAt(i);
FsUtils.updateTestStatus(TEST_STATUS_FILE, s);
@@ -385,10 +418,48 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
}
FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
-
+ if(fs8000 != null)
+ fs8000.stop();
+ if(fs8080 != null)
+ fs8080.stop();
+ if(fs8443 != null)
+ fs8443.stop();
+
activity.finish();
}
+ private void startForwardServerIfNeeded() {
+ try {
+ if(fs8000 != null)
+ fs8000.start();
+ if(fs8080 != null)
+ fs8080.start();
+ if(fs8443 != null)
+ fs8443.start();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
+ }
+ }
+
+ private String getTestUrl(String path) {
+ String url = null;
+ if (!path.startsWith(HTTP_TESTS_PREFIX)) {
+ url = "file://" + path;
+ } else {
+ startForwardServerIfNeeded();
+ if (path.startsWith(HTTPS_TESTS_PREFIX)) {
+ // still cut the URL after "http/tests/"
+ url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
+ && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
+ && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
+ url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else {
+ url = "file://" + path;
+ }
+ }
+ return url;
+ }
private String getTestPath() {
LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
@@ -403,10 +474,10 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
Log.e("LayoutTestsAutoTest", "Cannot get cannonical path " + e.getMessage());
}
Log.v("LayoutTestsAutoTest", " Test path : " + test_path);
-
+
return test_path;
}
-
+
public void generateTestList() {
try {
File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
@@ -431,7 +502,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
} catch (Exception e) {
e.printStackTrace();
}
-
+
executeLayoutTests(false);
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 09f7cbc..e342efb 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -28,12 +28,14 @@ import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.ViewGroup;
+import android.webkit.GeolocationPermissions;
import android.webkit.HttpAuthHandler;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
+import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
@@ -43,6 +45,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.Vector;
public class TestShellActivity extends Activity implements LayoutTestController {
@@ -88,7 +92,7 @@ public class TestShellActivity extends Activity implements LayoutTestController
}
public void clearCache() {
- mWebView.clearCache(true);
+ mWebView.freeMemory();
}
@Override
@@ -100,52 +104,20 @@ public class TestShellActivity extends Activity implements LayoutTestController
setContentView(contentView);
mWebView = new WebView(this);
- mWebView.getSettings().setJavaScriptEnabled(true);
- mWebView.setWebChromeClient(mChromeClient);
- mWebView.setWebViewClient(new WebViewClient(){
-
- @Override
- public void onPageFinished(WebView view, String url) {
- Log.v(LOGTAG, "onPageFinished, url=" + url);
- super.onPageFinished(view, url);
- }
-
- @Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- Log.v(LOGTAG, "onPageStarted, url=" + url);
- super.onPageStarted(view, url, favicon);
- }
-
- @Override
- public void onReceivedError(WebView view, int errorCode, String description,
- String failingUrl) {
- Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
- + ", desc=" + description + ", url=" + failingUrl);
- super.onReceivedError(view, errorCode, description, failingUrl);
- }
-
- @Override
- public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
- String host, String realm) {
- handler.cancel();
- }
-
- @Override
- public void onReceivedSslError(WebView view, SslErrorHandler handler,
- SslError error) {
- handler.proceed();
- }
-
- });
mEventSender = new WebViewEventSender(mWebView);
mCallbackProxy = new CallbackProxy(mEventSender, this);
- mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
- mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
+ setupWebViewForLayoutTests(mWebView, mCallbackProxy);
+
contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+ // Expose window.gc function to JavaScript. JSC build exposes
+ // this function by default, but V8 requires the flag to turn it on.
+ // WebView::setJsFlags is noop in JSC build.
+ mWebView.setJsFlags("--expose_gc");
+
mHandler = new AsyncHandler();
Intent intent = getIntent();
@@ -262,8 +234,8 @@ public class TestShellActivity extends Activity implements LayoutTestController
@Override
public void onLowMemory() {
super.onLowMemory();
- Log.e(LOGTAG, "Low memory, kill self");
- System.exit(1);
+ Log.e(LOGTAG, "Low memory, clearing caches");
+ mWebView.freeMemory();
}
// Dump the page
@@ -290,6 +262,12 @@ public class TestShellActivity extends Activity implements LayoutTestController
if (mDialogStrings != null)
os.write(mDialogStrings.toString().getBytes());
mDialogStrings = null;
+ if (mDatabaseCallbackStrings != null)
+ os.write(mDatabaseCallbackStrings.toString().getBytes());
+ mDatabaseCallbackStrings = null;
+ if (mConsoleMessages != null)
+ os.write(mConsoleMessages.toString().getBytes());
+ mConsoleMessages = null;
if (webkitData != null)
os.write(webkitData.getBytes());
os.flush();
@@ -438,6 +416,59 @@ public class TestShellActivity extends Activity implements LayoutTestController
mWebView.invalidate();
}
+ public void dumpDatabaseCallbacks() {
+ Log.v(LOGTAG, "dumpDatabaseCallbacks called.");
+ mDumpDatabaseCallbacks = true;
+ }
+
+ public void setCanOpenWindows() {
+ Log.v(LOGTAG, "setCanOpenWindows called.");
+ mCanOpenWindows = true;
+ }
+
+ /**
+ * Sets the Geolocation permission state to be used for all future requests.
+ */
+ public void setGeolocationPermission(boolean allow) {
+ mGeolocationPermissionSet = true;
+ mGeolocationPermission = allow;
+ }
+
+ private final WebViewClient mViewClient = new WebViewClient(){
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ Log.v(LOGTAG, "onPageFinished, url=" + url);
+ super.onPageFinished(view, url);
+ }
+
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ Log.v(LOGTAG, "onPageStarted, url=" + url);
+ super.onPageStarted(view, url, favicon);
+ }
+
+ @Override
+ public void onReceivedError(WebView view, int errorCode, String description,
+ String failingUrl) {
+ Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
+ + ", desc=" + description + ", url=" + failingUrl);
+ super.onReceivedError(view, errorCode, description, failingUrl);
+ }
+
+ @Override
+ public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
+ String host, String realm) {
+ handler.cancel();
+ }
+
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler,
+ SslError error) {
+ handler.proceed();
+ }
+ };
+
+
private final WebChromeClient mChromeClient = new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
@@ -512,6 +543,91 @@ public class TestShellActivity extends Activity implements LayoutTestController
result.confirm();
return true;
}
+
+ @Override
+ public boolean onJsTimeout() {
+ Log.v(LOGTAG, "JavaScript timeout");
+ return false;
+ }
+
+ @Override
+ public void onExceededDatabaseQuota(String url_str,
+ String databaseIdentifier, long currentQuota,
+ long estimatedSize, long totalUsedQuota,
+ WebStorage.QuotaUpdater callback) {
+ if (mDumpDatabaseCallbacks) {
+ if (mDatabaseCallbackStrings == null) {
+ mDatabaseCallbackStrings = new StringBuffer();
+ }
+
+ String protocol = "";
+ String host = "";
+ int port = 0;
+
+ try {
+ URL url = new URL(url_str);
+ protocol = url.getProtocol();
+ host = url.getHost();
+ if (url.getPort() > -1) {
+ port = url.getPort();
+ }
+ } catch (MalformedURLException e) {}
+
+ String databaseCallbackString =
+ "UI DELEGATE DATABASE CALLBACK: " +
+ "exceededDatabaseQuotaForSecurityOrigin:{" + protocol +
+ ", " + host + ", " + port + "} database:" +
+ databaseIdentifier + "\n";
+ Log.v(LOGTAG, "LOG: "+databaseCallbackString);
+ mDatabaseCallbackStrings.append(databaseCallbackString);
+ }
+ // Give 5MB more quota.
+ callback.updateQuota(currentQuota + 1024 * 1024 * 5);
+ }
+
+ /**
+ * Instructs the client to show a prompt to ask the user to set the
+ * Geolocation permission state for the specified origin.
+ */
+ @Override
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {
+ if (mGeolocationPermissionSet) {
+ callback.invoke(origin, mGeolocationPermission, false);
+ }
+ }
+
+ @Override
+ public void addMessageToConsole(String message, int lineNumber,
+ String sourceID) {
+ if (mConsoleMessages == null) {
+ mConsoleMessages = new StringBuffer();
+ }
+ String consoleMessage = "CONSOLE MESSAGE: line "
+ + lineNumber +": "+ message +"\n";
+ mConsoleMessages.append(consoleMessage);
+ Log.v(LOGTAG, "LOG: "+consoleMessage);
+ }
+
+ @Override
+ public boolean onCreateWindow(WebView view, boolean dialog,
+ boolean userGesture, Message resultMsg) {
+ if (!mCanOpenWindows) {
+ return false;
+ }
+
+ // We never display the new window, just create the view and
+ // allow it's content to execute and be recorded by the test
+ // runner.
+
+ WebView newWindowView = new WebView(TestShellActivity.this);
+ setupWebViewForLayoutTests(newWindowView, mCallbackProxy);
+ WebView.WebViewTransport transport =
+ (WebView.WebViewTransport) resultMsg.obj;
+ transport.setWebView(newWindowView);
+ resultMsg.sendToTarget();
+ return true;
+ }
};
private void resetTestStatus() {
@@ -520,9 +636,36 @@ public class TestShellActivity extends Activity implements LayoutTestController
mTimedOut = false;
mDumpTitleChanges = false;
mRequestedWebKitData = false;
+ mDumpDatabaseCallbacks = false;
+ mCanOpenWindows = false;
mEventSender.resetMouse();
}
+ private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
+ if (webview == null) {
+ return;
+ }
+
+ WebSettings settings = webview.getSettings();
+ settings.setAppCacheEnabled(true);
+ settings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
+ settings.setAppCacheMaxSize(Long.MAX_VALUE);
+ settings.setJavaScriptEnabled(true);
+ settings.setJavaScriptCanOpenWindowsAutomatically(true);
+ settings.setSupportMultipleWindows(true);
+ settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+ settings.setDatabaseEnabled(true);
+ settings.setDatabasePath(getDir("databases",0).getAbsolutePath());
+ settings.setDomStorageEnabled(true);
+ settings.setWorkersEnabled(false);
+
+ webview.addJavascriptInterface(callbackProxy, "layoutTestController");
+ webview.addJavascriptInterface(callbackProxy, "eventSender");
+
+ webview.setWebChromeClient(mChromeClient);
+ webview.setWebViewClient(mViewClient);
+ }
+
private WebView mWebView;
private WebViewEventSender mEventSender;
private AsyncHandler mHandler;
@@ -550,6 +693,10 @@ public class TestShellActivity extends Activity implements LayoutTestController
private StringBuffer mDialogStrings;
private boolean mKeepWebHistory;
private Vector mWebHistory;
+ private boolean mDumpDatabaseCallbacks;
+ private StringBuffer mDatabaseCallbackStrings;
+ private StringBuffer mConsoleMessages;
+ private boolean mCanOpenWindows;
static final String TIMEOUT_STR = "**Test timeout";
@@ -562,4 +709,7 @@ public class TestShellActivity extends Activity implements LayoutTestController
static final String RESULT_FILE = "ResultFile";
static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis";
static final String UI_AUTO_TEST = "UiAutoTest";
+
+ private boolean mGeolocationPermissionSet;
+ private boolean mGeolocationPermission;
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
new file mode 100644
index 0000000..9a3e9c2
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
@@ -0,0 +1,112 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+public class AdbUtils {
+
+ private static final String ADB_OK = "OKAY";
+ private static final int ADB_PORT = 5037;
+ private static final String ADB_HOST = "127.0.0.1";
+ private static final int ADB_RESPONSE_SIZE = 4;
+
+ private static final String LOGTAG = "AdbUtils";
+
+ /**
+ *
+ * Convert integer format IP into xxx.xxx.xxx.xxx format
+ *
+ * @param host IP address in integer format
+ * @return human readable format
+ */
+ public static String convert(int host) {
+ return ((host >> 24) & 0xFF) + "."
+ + ((host >> 16) & 0xFF) + "."
+ + ((host >> 8) & 0xFF) + "."
+ + (host & 0xFF);
+ }
+
+ /**
+ *
+ * Resolve DNS name into IP address
+ *
+ * @param host DNS name
+ * @return IP address in integer format
+ * @throws IOException
+ */
+ public static int resolve(String host) throws IOException {
+ Socket localSocket = new Socket(ADB_HOST, ADB_PORT);
+ DataInputStream dis = new DataInputStream(localSocket.getInputStream());
+ OutputStream os = localSocket.getOutputStream();
+ int count_read = 0;
+ byte[] buf = new byte[128];
+
+ if (localSocket == null || dis == null || os == null)
+ return -1;
+ String cmd = "dns:" + host;
+
+ if(!sendAdbCmd(dis, os, cmd))
+ return -1;
+
+ count_read = dis.readInt();
+ localSocket.close();
+ return count_read;
+ }
+
+ /**
+ *
+ * Send an ADB command using existing socket connection
+ *
+ * the streams provided must be from a socket connected to adbd already
+ *
+ * @param is input stream of the socket connection
+ * @param os output stream of the socket
+ * @param cmd the adb command to send
+ * @return if adb gave a success response
+ * @throws IOException
+ */
+ public static boolean sendAdbCmd(InputStream is, OutputStream os,
+ String cmd) throws IOException {
+ byte[] buf = new byte[ADB_RESPONSE_SIZE];
+
+ cmd = String.format("%04X", cmd.length()) + cmd;
+ os.write(cmd.getBytes());
+ int read = is.read(buf);
+ if(read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) {
+ Log.w(LOGTAG, "adb cmd faild.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ * Get a tcp socket connection to specified IP address and port proxied by adb
+ *
+ * The proxying is transparent, e.g. if a socket is returned, then it can be written to and
+ * read from as if it is directly connected to the target
+ *
+ * @param remoteAddress IP address of the host to connect to
+ * @param remotePort port of the host to connect to
+ * @return a valid Socket instance if successful, null otherwise
+ */
+ public static Socket getForwardedSocket(int remoteAddress, int remotePort) {
+ try {
+ Socket socket = new Socket(ADB_HOST, ADB_PORT);
+ String cmd = "tcp:" + remotePort + ":" + convert(remoteAddress);
+ if(!sendAdbCmd(socket.getInputStream(), socket.getOutputStream(), cmd)) {
+ socket.close();
+ return null;
+ }
+ return socket;
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error creating adb socket", ioe);
+ return null;
+ }
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
new file mode 100644
index 0000000..74e018e
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
@@ -0,0 +1,117 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ *
+ * A port forwarding server. Listens at specified local port and forward the tcp communications to
+ * external host/port via adb networking proxy.
+ *
+ */
+public class ForwardServer {
+
+ private static final String LOGTAG = "ForwardServer";
+
+ private int remotePort;
+ private int remoteAddress;
+ private int localPort;
+ private ServerSocket serverSocket;
+ private boolean started;
+
+ private Set<Forwarder> forwarders;
+
+ public ForwardServer(int localPort, int remoteAddress, int remotePort) {
+ this.localPort = localPort;
+ this.remoteAddress = remoteAddress;
+ this.remotePort = remotePort;
+ started = false;
+ forwarders = new HashSet<Forwarder>();
+ }
+
+ public synchronized void start() throws IOException {
+ if(!started) {
+ serverSocket = new ServerSocket(localPort);
+ Thread serverThread = new Thread(new ServerRunner(serverSocket));
+ serverThread.setName(LOGTAG);
+ serverThread.start();
+ started = true;
+ }
+ }
+
+ public synchronized void stop() {
+ if(started) {
+ synchronized (forwarders) {
+ for(Forwarder forwarder : forwarders)
+ forwarder.stop();
+ forwarders.clear();
+ }
+ try {
+ serverSocket.close();
+ } catch (IOException ioe) {
+ Log.v(LOGTAG, "exception while closing", ioe);
+ } finally {
+ started = false;
+ }
+ }
+ }
+
+ public synchronized boolean isRunning() {
+ return started;
+ }
+
+ private class ServerRunner implements Runnable {
+
+ private ServerSocket socket;
+
+ public ServerRunner(ServerSocket socket) {
+ this.socket = socket;
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ Socket localSocket = socket.accept();
+ Socket remoteSocket = AdbUtils.getForwardedSocket(remoteAddress, remotePort);
+ if(remoteSocket == null) {
+ try {
+ localSocket.close();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error while closing socket", ioe);
+ } finally {
+ Log.w(LOGTAG, "failed to start forwarding from " + localSocket);
+ }
+ } else {
+ Forwarder forwarder = new Forwarder(localSocket, remoteSocket,
+ ForwardServer.this);
+ forwarder.start();
+ }
+ }
+ } catch (IOException ioe) {
+ return;
+ }
+ }
+ }
+
+ public void register(Forwarder forwarder) {
+ synchronized (forwarders) {
+ if(!forwarders.contains(forwarder)) {
+ forwarders.add(forwarder);
+ }
+ }
+ }
+
+ public void unregister(Forwarder recyclable) {
+ synchronized (forwarders) {
+ if(forwarders.contains(recyclable)) {
+ recyclable.stop();
+ forwarders.remove(recyclable);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
new file mode 100644
index 0000000..e1e04a7
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
@@ -0,0 +1,92 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ *
+ * Worker class for {@link ForwardServer}. A Forwarder will be created once the ForwardServer
+ * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
+ * connection already proxied by adb networking (see also {@link AdbUtils}).
+ *
+ */
+public class Forwarder {
+
+ private ForwardServer server;
+ private Socket from, to;
+
+ private static final String LOGTAG = "Forwarder";
+
+ public Forwarder (Socket from, Socket to, ForwardServer server) {
+ this.server = server;
+ this.from = from;
+ this.to = to;
+ server.register(this);
+ }
+
+ public void start() {
+ Thread outgoing = new Thread(new SocketPipe(from, to));
+ Thread incoming = new Thread(new SocketPipe(to, from));
+ outgoing.setName(LOGTAG);
+ incoming.setName(LOGTAG);
+ outgoing.start();
+ incoming.start();
+ }
+
+ public void stop() {
+ shutdown(from);
+ shutdown(to);
+ }
+
+ private void shutdown(Socket socket) {
+ try {
+ socket.shutdownInput();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#shutdownInput", e);
+ }
+ try {
+ socket.shutdownOutput();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#shutdownOutput", e);
+ }
+ try {
+ socket.close();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#close", e);
+ }
+ }
+
+ private class SocketPipe implements Runnable {
+
+ private Socket in, out;
+
+ public SocketPipe(Socket in, Socket out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ public void run() {
+ try {
+ int length;
+ InputStream is = in.getInputStream();
+ OutputStream os = out.getOutputStream();
+ byte[] buffer = new byte[4096];
+ while ((length = is.read(buffer)) > 0) {
+ os.write(buffer, 0, length);
+ }
+ } catch (IOException ioe) {
+ } finally {
+ server.unregister(Forwarder.this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SocketPipe{" + in + "=>" + out + "}";
+ }
+ }
+}
diff --git a/tests/FrameworkTest/res/drawable-hdpi/big_drawable_background.9.png b/tests/FrameworkTest/res/drawable-hdpi/big_drawable_background.9.png
new file mode 100644
index 0000000..53470b8
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable-hdpi/big_drawable_background.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable-hdpi/black_square.png b/tests/FrameworkTest/res/drawable-hdpi/black_square.png
new file mode 100644
index 0000000..7752103
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable-hdpi/black_square.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable-hdpi/black_square_stretchable.9.png b/tests/FrameworkTest/res/drawable-hdpi/black_square_stretchable.9.png
new file mode 100644
index 0000000..4988163
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable-hdpi/black_square_stretchable.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable-hdpi/drawable_background.9.png b/tests/FrameworkTest/res/drawable-hdpi/drawable_background.9.png
new file mode 100644
index 0000000..f692d38
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable-hdpi/drawable_background.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_pause_1.png b/tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_pause_1.png
new file mode 100644
index 0000000..9edb064
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_pause_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_skip_backward_1.png b/tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_skip_backward_1.png
new file mode 100644
index 0000000..c4b6b92
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_skip_backward_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_skip_forward_1.png b/tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_skip_forward_1.png
new file mode 100644
index 0000000..03140f5
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable-hdpi/sym_now_playing_skip_forward_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/big_drawable_background.9.png b/tests/FrameworkTest/res/drawable-mdpi/big_drawable_background.9.png
index aded635..aded635 100644
--- a/tests/FrameworkTest/res/drawable/big_drawable_background.9.png
+++ b/tests/FrameworkTest/res/drawable-mdpi/big_drawable_background.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/black_square.png b/tests/FrameworkTest/res/drawable-mdpi/black_square.png
index 1bfe0a2..1bfe0a2 100644
--- a/tests/FrameworkTest/res/drawable/black_square.png
+++ b/tests/FrameworkTest/res/drawable-mdpi/black_square.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png b/tests/FrameworkTest/res/drawable-mdpi/black_square_stretchable.9.png
index 1fcbeb1..1fcbeb1 100644
--- a/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png
+++ b/tests/FrameworkTest/res/drawable-mdpi/black_square_stretchable.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/drawable_background.9.png b/tests/FrameworkTest/res/drawable-mdpi/drawable_background.9.png
index 1337ba9..1337ba9 100644
--- a/tests/FrameworkTest/res/drawable/drawable_background.9.png
+++ b/tests/FrameworkTest/res/drawable-mdpi/drawable_background.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png b/tests/FrameworkTest/res/drawable-mdpi/sym_now_playing_pause_1.png
index 2f19d08..2f19d08 100644
--- a/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png
+++ b/tests/FrameworkTest/res/drawable-mdpi/sym_now_playing_pause_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png b/tests/FrameworkTest/res/drawable-mdpi/sym_now_playing_skip_backward_1.png
index f945a81..f945a81 100644
--- a/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png
+++ b/tests/FrameworkTest/res/drawable-mdpi/sym_now_playing_skip_backward_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png b/tests/FrameworkTest/res/drawable-mdpi/sym_now_playing_skip_forward_1.png
index da9361a..da9361a 100644
--- a/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png
+++ b/tests/FrameworkTest/res/drawable-mdpi/sym_now_playing_skip_forward_1.png
Binary files differ
diff --git a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
index aa3d186..a8af7f8 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.name);
+ values.put("_sync_account_type", syncAccount.type);
+ }
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.name);
+ values.put("_sync_account_type", syncAccount.type);
+ }
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..1ba9d66
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
@@ -0,0 +1,498 @@
+/*
+ * 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.ContentValues;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+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.Set;
+import java.util.Map;
+import java.util.Map.Entry;
+
+@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 testAssert() {
+ // Build an operation to assert values match provider
+ ContentProviderOperation op1 = ContentProviderOperation.newAssertQuery(sTestUri1)
+ .withValues(sTestValues1).build();
+
+ try {
+ // Assert that values match from cursor
+ ContentProviderResult result = op1.apply(new TestContentProvider() {
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ // Return cursor over specific set of values
+ return getCursor(sTestValues1);
+ }
+ }, null, 0);
+ } catch (OperationApplicationException e) {
+ fail("newAssert() failed");
+ }
+ }
+
+ /**
+ * Build a {@link Cursor} with a single row that contains all values
+ * provided through the given {@link ContentValues}.
+ */
+ private Cursor getCursor(ContentValues contentValues) {
+ final Set<Entry<String, Object>> valueSet = contentValues.valueSet();
+ final String[] keys = new String[valueSet.size()];
+ final Object[] values = new Object[valueSet.size()];
+
+ int i = 0;
+ for (Entry<String, Object> entry : valueSet) {
+ keys[i] = entry.getKey();
+ values[i] = entry.getValue();
+ i++;
+ }
+
+ final MatrixCursor cursor = new MatrixCursor(keys);
+ cursor.addRow(values);
+ return cursor;
+ }
+
+ 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};
+
+ final ContentValues values = new ContentValues();
+ values.put("unused", "unused");
+
+ ContentProviderOperation op1 = ContentProviderOperation.newUpdate(sTestUri1)
+ .withSelectionBackReference(1, 3)
+ .withSelectionBackReference(2, 1)
+ .withSelectionBackReference(4, 2)
+ .withSelection("unused", selectionArgs)
+ .withValues(values)
+ .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(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(ContentProviderOperation.TYPE_UPDATE, operationGetType(op2));
+ assertEquals("content://goo/bar", operationGetUri(op2).toString());
+ 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(ContentProviderOperation.TYPE_DELETE, operationGetType(op2));
+ assertEquals("content://goo/bar", operationGetUri(op2).toString());
+ 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 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 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/tests/appwidgets/AppWidgetHostTest/res/drawable-hdpi/oh_hai_icon.png b/tests/appwidgets/AppWidgetHostTest/res/drawable-hdpi/oh_hai_icon.png
new file mode 100644
index 0000000..2ddde94
--- /dev/null
+++ b/tests/appwidgets/AppWidgetHostTest/res/drawable-hdpi/oh_hai_icon.png
Binary files differ
diff --git a/tests/appwidgets/AppWidgetHostTest/res/drawable/oh_hai_icon.png b/tests/appwidgets/AppWidgetHostTest/res/drawable-mdpi/oh_hai_icon.png
index 30ff267..30ff267 100644
--- a/tests/appwidgets/AppWidgetHostTest/res/drawable/oh_hai_icon.png
+++ b/tests/appwidgets/AppWidgetHostTest/res/drawable-mdpi/oh_hai_icon.png
Binary files differ
diff --git a/tests/backup/AndroidManifest.xml b/tests/backup/AndroidManifest.xml
index 3778742..d992627 100644
--- a/tests/backup/AndroidManifest.xml
+++ b/tests/backup/AndroidManifest.xml
@@ -1,5 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.backuptest">
+ <uses-permission android:name="android.permission.BACKUP_DATA" />
<application android:backupAgent="BackupTestAgent">
<activity android:name="BackupTestActivity" android:label="_BackupTest">
<intent-filter>
diff --git a/tests/backup/backup_stress_test.sh b/tests/backup/backup_stress_test.sh
new file mode 100755
index 0000000..8155507
--- /dev/null
+++ b/tests/backup/backup_stress_test.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+# 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.
+
+iterations=150
+failures=0
+i=0
+LOGDIR="$HOME/backup_tests"
+LOGFILE="$LOGDIR/backup_stress.`date +%s`.log"
+export BUGREPORT_DIR="$LOGDIR/bugreports"
+
+# make sure that we have a place to put logs and bugreports
+mkdir -p $LOGDIR $BUGREPORT_DIR
+
+echo "logfile is $LOGFILE"
+
+(while (sleep 10); do
+ failed=0
+
+ echo
+ echo "Iteration $i at `date`"
+ echo
+
+ ./test_backup.sh "$@" 2>&1
+
+ sleep 10
+ echo "Restore at `date`"
+ echo
+
+ ./test_restore.sh "$@" 2>&1 || failed=1
+
+ if [ "$failed" -ne 0 ]; then
+ failures=$(($failures+1))
+ # Long and verbose so it sticks out
+ echo "FAILED iteration $i of $iterations; $failures failures so far"
+ echo "FAILED iteration $i of $iterations; $failures failures so far" > /dev/stderr
+ else
+ printf "Iteration %d:\tPASS; remaining: %d\n" $i $(($iterations - $i - 1))
+ printf "Iteration %d:\tPASS; remaining: %d\n" $i $(($iterations - $i - 1)) > /dev/stderr
+ fi
+
+ echo "End $i at `date`"
+
+ i=$(($i+1))
+ if [ $i -eq $iterations ]; then
+ echo "DONE: $iterations iterations with $failures failures."
+ echo "DONE: $iterations iterations with $failures failures." > /dev/stderr
+ [ "$failures" -eq 0 ] && exit 0
+ exit 1
+ fi
+done) > "$LOGFILE"
+
diff --git a/tests/backup/test_backup.sh b/tests/backup/test_backup.sh
index dbf9ed2..10b809d 100755
--- a/tests/backup/test_backup.sh
+++ b/tests/backup/test_backup.sh
@@ -1,27 +1,63 @@
#!/bin/bash
-#adb kill-server
+# 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.
+
+# uncomment for debugging
+#export DRY_RUN="echo"
+source test_backup_common.sh
+
+# wipe prior backup data for packages
+b_pkgs=$(a shell dumpsys backup | \
+ ruby -ne 'print($1+" ") if $_ =~ /^\s*ApplicationInfo\S+ (.+?)\}/')
+
+for pkg in $b_pkgs; do
+ a shell bmgr wipe "$pkg"
+done
+
+echo 'Waiting 5 seconds for things to settle...'
+sleep 5
+
+# run adb as root so we can poke at com.android.backuptest's data
+adb_root
+
+# show commands as we go
+set -x
# set the transport
-adb shell bmgr transport 1
+a shell bmgr transport com.google.android.backup/.BackupTransportService
# load up the three files
-adb shell "rm /data/data/com.android.backuptest/files/* ; \
- mkdir /data/data/com.android.backuptest ; \
- mkdir /data/data/com.android.backuptest/files ; \
- mkdir /data/data/com.android.backuptest/shared_prefs ; \
- echo -n \"<map><int name=\\\"pref\\\" value=\\\"1\\\" /></map>\" > /data/data/com.android.backuptest/shared_prefs/raw.xml ; \
- echo -n first file > /data/data/com.android.backuptest/files/file.txt ; \
- echo -n asdf > /data/data/com.android.backuptest/files/another_file.txt ; \
- echo -n 3 > /data/data/com.android.backuptest/files/3.txt ; \
- echo -n "" > /data/data/com.android.backuptest/files/empty.txt ; \
+a shell \
+ "rm /data/data/com.android.backuptest/files/file.txt ; \
+ rm /data/data/com.android.backuptest/files/another_file.txt ; \
+ rm /data/data/com.android.backuptest/files/empty.txt ; \
+ mkdir /data/data/com.android.backuptest ; \
+ mkdir /data/data/com.android.backuptest/files ; \
+ mkdir /data/data/com.android.backuptest/shared_prefs ; \
+ echo -n \"<map><int name=\\\"pref\\\" value=\\\"1\\\" /></map>\" \
+ > /data/data/com.android.backuptest/shared_prefs/raw.xml ; \
+ echo -n first file > /data/data/com.android.backuptest/files/file.txt ; \
+ echo -n asdf > /data/data/com.android.backuptest/files/another_file.txt ; \
+ echo -n "" > /data/data/com.android.backuptest/files/empty.txt ; \
+ date >> /data/data/com.android.backuptest/files/3.txt ; \
"
+# echo -n 3 > /data/data/com.android.backuptest/files/3.txt ; \
# say that the data has changed
-adb shell bmgr backup com.android.backuptest
+a shell bmgr backup com.android.backuptest
# run the backup
-adb shell bmgr run
-
-
+a shell bmgr run
diff --git a/tests/backup/test_backup_common.sh b/tests/backup/test_backup_common.sh
new file mode 100755
index 0000000..61ec833
--- /dev/null
+++ b/tests/backup/test_backup_common.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+# 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.
+
+export ADB_OPTS="$@"
+
+# run adb with options
+function a { $DRY_RUN adb $ADB_OPTS "$@"; }
+
+# restart adb as root and wait for it to come back again
+function adb_root
+{
+ root_status=$(a root)
+ if [ "$root_status" != "adbd is already running as root" ]; then
+ echo -n "Restarting adb as root..."
+ sleep 2
+ a 'wait-for-device'
+ echo done.
+ fi
+}
+
diff --git a/tests/backup/test_restore.sh b/tests/backup/test_restore.sh
index ccf29cf..46b46e4 100755
--- a/tests/backup/test_restore.sh
+++ b/tests/backup/test_restore.sh
@@ -1,53 +1,111 @@
#!/bin/bash
+# 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.
+
+# uncomment for debugging
+#export DRY_RUN="echo"
+source test_backup_common.sh
+
+[ -z "$BUGREPORT_DIR" ] && BUGREPORT_DIR="$HOME/backup/bugreports"
+
function check_file
{
- data=$(adb shell cat /data/data/com.android.backuptest/$1)
+ data=$(a shell cat /data/data/com.android.backuptest/$1)
if [ "$data" = "$2" ] ; then
echo "$1 has correct value [$2]"
+ return 0
else
echo $1 is INCORRECT
echo " value: [$data]"
echo " expected: [$2]"
+ return 1
+ fi
+}
+
+function check_exists
+{
+ # return 0 if file exists, 1 otherwise
+ data=$(a shell "ls $@ 2> /dev/null >/dev/null && echo -n exists")
+ if [ "$data" = "exists" ]; then
+ return 0
+ else
+ return 1
fi
}
+# run adb as root so we can poke at com.android.backuptest's data
+adb_root
+
# delete the old data
echo --- Previous files
-adb shell "ls -l /data/data/com.android.backuptest/files"
-adb shell "rm /data/data/com.android.backuptest/files/*"
+a shell "ls -l /data/data/com.android.backuptest/files"
+a shell "rm /data/data/com.android.backuptest/files/*"
echo --- Previous shared_prefs
-adb shell "ls -l /data/data/com.android.backuptest/shared_prefs"
-adb shell "rm /data/data/com.android.backuptest/shared_prefs/*"
+a shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+a shell "rm /data/data/com.android.backuptest/shared_prefs/*"
echo --- Erased files and shared_prefs
-adb shell "ls -l /data/data/com.android.backuptest/files"
-adb shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+a shell "ls -l /data/data/com.android.backuptest/files"
+a shell "ls -l /data/data/com.android.backuptest/shared_prefs"
echo ---
echo
echo
-echo
+
+# FIXME: there's probably a smarter way to do this
+# FIXME: if we can get the android ID, that's probably the safest thing to do
+# pick the most recent set and restore from it
+restore_set=$(a shell bmgr list sets | head -n1 | awk '{print $1}')
# run the restore
-adb shell bmgr restore 0
+echo "Restoring from set [$restore_set]"
+a shell bmgr restore "$restore_set"
echo
echo
-echo
# check the results
-check_file files/file.txt "first file"
-check_file files/another_file.txt "asdf"
-check_file files/3.txt "3"
-check_file files/empty.txt ""
-check_file shared_prefs/raw.xml '<map><int name="pref" value="1" /></map>'
+export need_bug=0
+
+# make sure files have the expected contents
+check_file files/file.txt "first file" || need_bug=1
+check_file files/another_file.txt "asdf" || need_bug=1
+#check_file files/3.txt "3" || need_bug=1
+check_file files/empty.txt "" || need_bug=1
+check_file shared_prefs/raw.xml '<map><int name="pref" value="1" /></map>' || need_bug=1
+
+# make sure that missing files weren't somehow created
+check_exists files/file_doesnt_exist.txt && need_bug=1
+check_exists files/no_files_here.txt && need_bug=1
+
+if [ \( "$need_bug" -ne 0 \) -a -d "$BUGREPORT_DIR" ]; then
+ dev_id=$(a get-serialno)
+ filename="${dev_id}_`date +%s`"
+ echo "Grabbing bugreport; filename is $filename"
+ a bugreport > "$BUGREPORT_DIR/$filename.txt"
+fi
-echo
-echo
echo
echo --- Restored files
-adb shell "ls -l /data/data/com.android.backuptest/files"
+a shell "ls -l /data/data/com.android.backuptest/files"
echo --- Restored shared_prefs
-adb shell "ls -l /data/data/com.android.backuptest/shared_prefs"
+a shell "ls -l /data/data/com.android.backuptest/shared_prefs"
echo ---
echo
+
+echo "Last 3 timestamps in 3.txt:"
+a shell cat /data/data/com.android.backuptest/files/3.txt | tail -n 3
+
+exit $need_bug
+
diff --git a/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
index 719e758..aebd68c 100644
--- a/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
+++ b/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
@@ -46,7 +46,7 @@ public class HardwareServicePermissionTest extends TestCase {
*/
public void testVibrate() throws RemoteException {
try {
- mHardwareService.vibrate(2000);
+ mHardwareService.vibrate(2000, new Binder());
fail("vibrate did not throw SecurityException as expected");
} catch (SecurityException e) {
// expected
@@ -77,7 +77,7 @@ public class HardwareServicePermissionTest extends TestCase {
*/
public void testCancelVibrate() throws RemoteException {
try {
- mHardwareService.cancelVibrate();
+ mHardwareService.cancelVibrate(new Binder());
fail("cancelVibrate did not throw SecurityException as expected");
} catch (SecurityException e) {
// expected
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index dbcef6d..b00d8b0 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1819,6 +1819,19 @@ void AaptAssets::print() const
AaptDir::print();
}
+sp<AaptDir> AaptAssets::resDir(const String8& name)
+{
+ const Vector<sp<AaptDir> >& dirs = mDirs;
+ const size_t N = dirs.size();
+ for (size_t i=0; i<N; i++) {
+ const sp<AaptDir>& d = dirs.itemAt(i);
+ if (d->getLeaf() == name) {
+ return d;
+ }
+ }
+ return NULL;
+}
+
bool
valid_symbol_name(const String8& symbol)
{
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 63afe5c..865efd1 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"
@@ -131,7 +131,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; }
@@ -447,7 +449,13 @@ private:
AaptSymbolEntry mDefSymbol;
};
-class ResourceTypeSet;
+class ResourceTypeSet : public RefBase,
+ public KeyedVector<String8,sp<AaptGroup> >
+{
+public:
+ ResourceTypeSet();
+};
+
/**
* Asset hierarchy being operated on.
@@ -455,8 +463,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; }
@@ -474,6 +482,8 @@ public:
const sp<AaptFile>& file,
const String8& resType);
+ void addGroupEntry(const AaptGroupEntry& entry) { mGroupEntries.add(entry); }
+
ssize_t slurpFromArgs(Bundle* bundle);
virtual ssize_t slurpFullTree(Bundle* bundle,
@@ -498,13 +508,14 @@ public:
void print() const;
inline const Vector<sp<AaptDir> >& resDirs() { return mDirs; }
+ sp<AaptDir> resDir(const String8& name);
inline sp<AaptAssets> getOverlay() { return mOverlay; }
inline void setOverlay(sp<AaptAssets>& overlay) { mOverlay = overlay; }
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 a6fedf3..234e5b2 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>
@@ -36,7 +39,7 @@ public:
mRequireLocalization(false), mPseudolocalize(false),
mValues(false),
mCompressionMethod(0), mOutputAPKFile(NULL),
- mAssetSourceDir(NULL),
+ mAssetSourceDir(NULL), mProguardFile(NULL),
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
mRClassDir(NULL), mResourceIntermediatesDir(NULL),
mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
@@ -85,6 +88,8 @@ public:
*/
const char* getAssetSourceDir() const { return mAssetSourceDir; }
void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; }
+ const char* getProguardFile() const { return mProguardFile; }
+ void setProguardFile(const char* file) { mProguardFile = file; }
const android::Vector<const char*>& getResourceSourceDirs() const { return mResourceSourceDirs; }
void addResourceSourceDir(const char* dir) { mResourceSourceDirs.insertAt(dir,0); }
const char* getAndroidManifestFile() const { return mAndroidManifestFile; }
@@ -158,6 +163,7 @@ private:
int mCompressionMethod;
const char* mOutputAPKFile;
const char* mAssetSourceDir;
+ const char* mProguardFile;
const char* mAndroidManifestFile;
const char* mPublicOutputFile;
const char* mRClassDir;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 5f80ade..f2cdf75 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>
@@ -231,7 +233,7 @@ static ssize_t indexOfAttribute(const ResXMLTree& tree, uint32_t attrRes)
return -1;
}
-static String8 getAttribute(const ResXMLTree& tree, const char* ns,
+String8 getAttribute(const ResXMLTree& tree, const char* ns,
const char* attr, String8* outError)
{
ssize_t idx = tree.indexOfAttribute(ns, attr);
@@ -330,9 +332,11 @@ enum {
TARGET_SDK_VERSION_ATTR = 0x01010270,
TEST_ONLY_ATTR = 0x01010272,
DENSITY_ATTR = 0x0101026c,
+ GL_ES_VERSION_ATTR = 0x01010281,
SMALL_SCREEN_ATTR = 0x01010284,
NORMAL_SCREEN_ATTR = 0x01010285,
LARGE_SCREEN_ATTR = 0x01010286,
+ REQUIRED_ATTR = 0x0101028e,
};
const char *getComponentName(String8 &pkgName, String8 &componentName) {
@@ -501,8 +505,25 @@ int doDump(Bundle* bundle)
bool withinActivity = false;
bool isMainActivity = false;
bool isLauncherActivity = false;
+ bool isSearchable = false;
bool withinApplication = false;
bool withinReceiver = false;
+ bool withinService = false;
+ bool withinIntentFilter = false;
+ bool hasMainActivity = false;
+ bool hasOtherActivities = false;
+ bool hasOtherReceivers = false;
+ bool hasOtherServices = false;
+ bool hasWallpaperService = false;
+ bool hasImeService = false;
+ bool hasWidgetReceivers = false;
+ bool hasIntentFilter = false;
+ bool actMainActivity = false;
+ bool actWidgetReceivers = false;
+ bool actImeService = false;
+ bool actWallpaperService = false;
+ bool specCameraFeature = false;
+ bool hasCameraPermission = false;
int targetSdk = 0;
int smallScreen = 1;
int normalScreen = 1;
@@ -512,9 +533,48 @@ int doDump(Bundle* bundle)
String8 activityLabel;
String8 activityIcon;
String8 receiverName;
+ String8 serviceName;
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
depth--;
+ if (depth < 2) {
+ withinApplication = false;
+ } else if (depth < 3) {
+ if (withinActivity && isMainActivity && isLauncherActivity) {
+ const char *aName = getComponentName(pkg, activityName);
+ if (aName != NULL) {
+ printf("launchable activity name='%s'", aName);
+ }
+ printf("label='%s' icon='%s'\n",
+ activityLabel.string(),
+ activityIcon.string());
+ }
+ if (!hasIntentFilter) {
+ hasOtherActivities |= withinActivity;
+ hasOtherReceivers |= withinReceiver;
+ hasOtherServices |= withinService;
+ }
+ withinActivity = false;
+ withinService = false;
+ withinReceiver = false;
+ hasIntentFilter = false;
+ isMainActivity = isLauncherActivity = false;
+ } else if (depth < 4) {
+ if (withinIntentFilter) {
+ if (withinActivity) {
+ hasMainActivity |= actMainActivity;
+ hasOtherActivities |= !actMainActivity;
+ } else if (withinReceiver) {
+ hasWidgetReceivers |= actWidgetReceivers;
+ hasOtherReceivers |= !actWidgetReceivers;
+ } else if (withinService) {
+ hasImeService |= actImeService;
+ hasWallpaperService |= actWallpaperService;
+ hasOtherServices |= (!actImeService && !actWallpaperService);
+ }
+ }
+ withinIntentFilter = false;
+ }
continue;
}
if (code != ResXMLTree::START_TAG) {
@@ -522,7 +582,7 @@ int doDump(Bundle* bundle)
}
depth++;
String8 tag(tree.getElementName(&len));
- //printf("Depth %d tag %s\n", depth, tag.string());
+ //printf("Depth %d, %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
@@ -650,10 +710,41 @@ int doDump(Bundle* bundle)
NORMAL_SCREEN_ATTR, NULL, 1);
largeScreen = getIntegerAttribute(tree,
LARGE_SCREEN_ATTR, NULL, 1);
+ } else if (tag == "uses-feature") {
+ String8 name = getAttribute(tree, NAME_ATTR, &error);
+ if (error == "") {
+ int req = getIntegerAttribute(tree,
+ REQUIRED_ATTR, NULL, 1);
+ if (name == "android.hardware.camera") {
+ specCameraFeature = true;
+ }
+ printf("uses-feature%s:'%s'\n",
+ req ? "" : "-not-required", name.string());
+ } else {
+ int vers = getIntegerAttribute(tree,
+ GL_ES_VERSION_ATTR, &error);
+ if (error == "") {
+ printf("uses-gl-es:'0x%x'\n", vers);
+ }
+ }
+ } else if (tag == "uses-permission") {
+ String8 name = getAttribute(tree, NAME_ATTR, &error);
+ if (error == "") {
+ if (name == "android.permission.CAMERA") {
+ hasCameraPermission = true;
+ }
+ printf("uses-permission:'%s'\n", name.string());
+ } else {
+ fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+ error.string());
+ goto bail;
+ }
}
} else if (depth == 3 && withinApplication) {
withinActivity = false;
withinReceiver = false;
+ withinService = false;
+ hasIntentFilter = false;
if(tag == "activity") {
withinActivity = true;
activityName = getAttribute(tree, NAME_ATTR, &error);
@@ -679,7 +770,10 @@ int doDump(Bundle* bundle)
fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library: %s\n", error.string());
goto bail;
}
- printf("uses-library:'%s'\n", libraryName.string());
+ int req = getIntegerAttribute(tree,
+ REQUIRED_ATTR, NULL, 1);
+ printf("uses-library%s:'%s'\n",
+ req ? "" : "-not-required", libraryName.string());
} else if (tag == "receiver") {
withinReceiver = true;
receiverName = getAttribute(tree, NAME_ATTR, &error);
@@ -688,76 +782,97 @@ int doDump(Bundle* bundle)
fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string());
goto bail;
}
+ } else if (tag == "service") {
+ withinService = true;
+ serviceName = getAttribute(tree, NAME_ATTR, &error);
+
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:name' attribute for service: %s\n", error.string());
+ goto bail;
+ }
}
- } else if (depth == 5) {
- if (withinActivity) {
- if (tag == "action") {
- //printf("LOG: action tag\n");
- String8 action = getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
- goto bail;
- }
+ } else if ((depth == 4) && (tag == "intent-filter")) {
+ hasIntentFilter = true;
+ withinIntentFilter = true;
+ actMainActivity = actWidgetReceivers = actImeService = actWallpaperService = false;
+ } else if ((depth == 5) && withinIntentFilter){
+ String8 action;
+ if (tag == "action") {
+ action = getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
+ goto bail;
+ }
+ if (withinActivity) {
if (action == "android.intent.action.MAIN") {
isMainActivity = true;
- //printf("LOG: isMainActivity==true\n");
+ actMainActivity = true;
}
- } else if (tag == "category") {
- String8 category = getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string());
- goto bail;
+ } else if (withinReceiver) {
+ if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
+ actWidgetReceivers = true;
}
- if (category == "android.intent.category.LAUNCHER") {
- isLauncherActivity = true;
- //printf("LOG: isLauncherActivity==true\n");
+ } else if (withinService) {
+ if (action == "android.view.InputMethod") {
+ actImeService = true;
+ } else if (action == "android.service.wallpaper.WallpaperService") {
+ actWallpaperService = true;
}
}
- } else if (withinReceiver) {
- if (tag == "action") {
- String8 action = getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string());
- goto bail;
- }
- if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
- const char *rName = getComponentName(pkg, receiverName);
- if (rName != NULL) {
- printf("gadget-receiver:'%s/%s'\n", pkg.string(), rName);
- }
- }
+ if (action == "android.intent.action.SEARCH") {
+ isSearchable = true;
}
}
- }
-
- if (depth < 2) {
- withinApplication = false;
- }
- if (depth < 3) {
- //if (withinActivity) printf("LOG: withinActivity==false\n");
- withinActivity = false;
- withinReceiver = false;
- }
- if (depth < 5) {
- //if (isMainActivity) printf("LOG: isMainActivity==false\n");
- //if (isLauncherActivity) printf("LOG: isLauncherActivity==false\n");
- isMainActivity = false;
- isLauncherActivity = false;
- }
-
- if (withinActivity && isMainActivity && isLauncherActivity) {
- printf("launchable activity:");
- const char *aName = getComponentName(pkg, activityName);
- if (aName != NULL) {
- printf(" name='%s'", aName);
+ if (tag == "category") {
+ String8 category = getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string());
+ goto bail;
+ }
+ if (withinActivity) {
+ if (category == "android.intent.category.LAUNCHER") {
+ isLauncherActivity = true;
+ }
+ }
}
- printf("label='%s' icon='%s'\n",
- activityLabel.string(),
- activityIcon.string());
}
}
+
+ if (!specCameraFeature && hasCameraPermission) {
+ // For applications that have not explicitly stated their
+ // camera feature requirements, but have requested the camera
+ // permission, we are going to give them compatibility treatment
+ // of requiring the equivalent to original android devices.
+ printf("uses-feature:'android.hardware.camera'\n");
+ printf("uses-feature:'android.hardware.camera.autofocus'\n");
+ }
+ if (hasMainActivity) {
+ printf("main\n");
+ }
+ if (hasWidgetReceivers) {
+ printf("app-widget\n");
+ }
+ if (hasImeService) {
+ printf("ime\n");
+ }
+ if (hasWallpaperService) {
+ printf("wallpaper\n");
+ }
+ if (hasOtherActivities) {
+ printf("other-activities\n");
+ }
+ if (isSearchable) {
+ printf("search\n");
+ }
+ if (hasOtherReceivers) {
+ printf("other-receivers\n");
+ }
+ if (hasOtherServices) {
+ printf("other-services\n");
+ }
+
// Determine default values for any unspecified screen sizes,
// based on the target SDK of the package. As of 4 (donut)
// the screen size support was introduced, so all default to
@@ -776,7 +891,7 @@ int doDump(Bundle* bundle)
if (normalScreen != 0) printf(" 'normal'");
if (largeScreen != 0) printf(" 'large'");
printf("\n");
-
+
printf("locales:");
Vector<String8> locales;
res.getLocales(&locales);
@@ -789,7 +904,7 @@ int doDump(Bundle* bundle)
printf(" '%s'", localeStr);
}
printf("\n");
-
+
Vector<ResTable_config> configs;
res.getConfigurations(&configs);
SortedVector<int> densities;
@@ -799,14 +914,14 @@ int doDump(Bundle* bundle)
if (dens == 0) dens = 160;
densities.add(dens);
}
-
+
printf("densities:");
const size_t ND = densities.size();
for (size_t i=0; i<ND; i++) {
printf(" '%d'", densities[i]);
}
printf("\n");
-
+
AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
if (dir != NULL) {
if (dir->getFileCount() > 0) {
@@ -1043,6 +1158,12 @@ int doPackage(Bundle* bundle)
}
}
+ // Write out the ProGuard file
+ err = writeProguardFile(bundle, assets);
+ if (err < 0) {
+ goto bail;
+ }
+
// Write the apk
if (outputAPKFile) {
err = writeAPK(bundle, assets, String8(outputAPKFile));
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 12a0445..e61010c 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>
@@ -57,9 +59,9 @@ void usage(void)
" [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n"
" [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
" [--max-sdk-version VAL] [--app-version VAL] \\\n"
- " [--app-version-name TEXT] \\\n"
+ " [--app-version-name TEXT]\\\n"
" [-I base-package [-I base-package ...]] \\\n"
- " [-A asset-source-dir] [-P public-definitions-file] \\\n"
+ " [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \\\n"
" [-S resource-sources [-S resource-sources ...]] "
" [-F apk-file] [-J R-file-dir] \\\n"
" [raw-files-dir [raw-files-dir] ...]\n"
@@ -107,6 +109,7 @@ void usage(void)
" -z require localization of resource attributes marked with\n"
" localization=\"suggested\"\n"
" -A additional directory in which to find raw asset files\n"
+ " -G A file to output proguard options into.\n"
" -F specify the apk file to output\n"
" -I add an existing package to base include set\n"
" -J specify where to output R.java resource constant definitions\n"
@@ -272,6 +275,17 @@ int main(int argc, char* const argv[])
convertPath(argv[0]);
bundle.setAssetSourceDir(argv[0]);
break;
+ case 'G':
+ argc--;
+ argv++;
+ if (!argc) {
+ fprintf(stderr, "ERROR: No argument supplied for '-G' option\n");
+ wantUsage = true;
+ goto bail;
+ }
+ convertPath(argv[0]);
+ bundle.setProguardFile(argv[0]);
+ break;
case 'I':
argc--;
argv++;
diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h
index 65c0a8a..3ba4f39 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);
@@ -30,6 +33,8 @@ extern android::status_t buildResources(Bundle* bundle,
extern android::status_t writeResourceSymbols(Bundle* bundle,
const sp<AaptAssets>& assets, const String8& pkgName, bool includePrivate);
+extern android::status_t writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets);
+
extern bool isValidResourceType(const String8& type);
ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
@@ -38,4 +43,7 @@ extern status_t filterResources(Bundle* bundle, const sp<AaptAssets>& assets);
int dumpResources(Bundle* bundle);
+String8 getAttribute(const ResXMLTree& tree, const char* ns,
+ const char* attr, String8* outError);
+
#endif // __MAIN_H
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index eb7d6f5..999a5cf 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>
@@ -166,7 +168,7 @@ status_t writeAPK(Bundle* bundle, const sp<AaptAssets>& assets,
delete zip; // close the file so we can remove it in Win32
zip = NULL;
if (unlink(outputFile.string()) != 0) {
- fprintf(stderr, "WARNING: could not unlink '%s'\n", outputFile.string());
+ fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string());
}
}
@@ -179,7 +181,7 @@ bail:
printf("Removing %s due to earlier failures\n", outputFile.string());
}
if (unlink(outputFile.string()) != 0) {
- fprintf(stderr, "WARNING: could not unlink '%s'\n", outputFile.string());
+ fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string());
}
}
@@ -281,7 +283,7 @@ bool processFile(Bundle* bundle, ZipFile* zip,
if (fileNameLen > excludeExtensionLen
&& (0 == strcmp(storageName.string() + (fileNameLen - excludeExtensionLen),
kExcludeExtension))) {
- fprintf(stderr, "WARNING: '%s' not added to Zip\n", storageName.string());
+ fprintf(stderr, "warning: '%s' not added to Zip\n", storageName.string());
return true;
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 027e3ab..10849921 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> >()
@@ -181,7 +174,7 @@ static sp<AaptFile> getResourceFile(const sp<AaptAssets>& assets, bool makeIfNec
static status_t parsePackage(const sp<AaptAssets>& assets, const sp<AaptGroup>& grp)
{
if (grp->getFiles().size() != 1) {
- fprintf(stderr, "WARNING: Multiple AndroidManifest.xml files found, using %s\n",
+ fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
grp->getFiles().valueAt(0)->getPrintableSource().string());
}
@@ -279,15 +272,16 @@ static status_t preProcessImages(Bundle* bundle, const sp<AaptAssets>& assets,
ResourceDirIterator it(set, String8("drawable"));
Vector<sp<AaptFile> > newNameFiles;
Vector<String8> newNamePaths;
+ bool hasErrors = false;
ssize_t res;
while ((res=it.next()) == NO_ERROR) {
res = preProcessImage(bundle, assets, it.getFile(), NULL);
- if (res != NO_ERROR) {
- return res;
+ if (res < NO_ERROR) {
+ hasErrors = true;
}
}
- return NO_ERROR;
+ return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
}
status_t postProcessImages(const sp<AaptAssets>& assets,
@@ -295,15 +289,16 @@ status_t postProcessImages(const sp<AaptAssets>& assets,
const sp<ResourceTypeSet>& set)
{
ResourceDirIterator it(set, String8("drawable"));
+ bool hasErrors = false;
ssize_t res;
while ((res=it.next()) == NO_ERROR) {
res = postProcessImage(assets, table, it.getFile());
- if (res != NO_ERROR) {
- return res;
+ if (res < NO_ERROR) {
+ hasErrors = true;
}
}
- return res < NO_ERROR ? res : (status_t)NO_ERROR;
+ return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
}
static void collect_files(const sp<AaptDir>& dir,
@@ -426,17 +421,22 @@ static void checkForIds(const String8& path, ResXMLParser& parser)
if (code == ResXMLTree::START_TAG) {
ssize_t index = parser.indexOfAttribute(NULL, "id");
if (index >= 0) {
- fprintf(stderr, "%s:%d: WARNING: found plain 'id' attribute; did you mean the new 'android:id' name?\n",
+ fprintf(stderr, "%s:%d: warning: found plain 'id' attribute; did you mean the new 'android:id' name?\n",
path.string(), parser.getLineNumber());
}
}
}
}
-static bool applyFileOverlay(const sp<AaptAssets>& assets,
+static bool applyFileOverlay(Bundle *bundle,
+ const sp<AaptAssets>& assets,
const sp<ResourceTypeSet>& baseSet,
const char *resType)
{
+ if (bundle->getVerbose()) {
+ printf("applyFileOverlay for %s\n", resType);
+ }
+
// Replace any base level files in this category with any found from the overlay
// Also add any found only in the overlay.
sp<AaptAssets> overlay = assets->getOverlay();
@@ -455,6 +455,9 @@ static bool applyFileOverlay(const sp<AaptAssets>& assets,
// non-overlay "baseset".
size_t overlayCount = overlaySet->size();
for (size_t overlayIndex=0; overlayIndex<overlayCount; overlayIndex++) {
+ if (bundle->getVerbose()) {
+ printf("trying overlaySet Key=%s\n",overlaySet->keyAt(overlayIndex).string());
+ }
size_t baseIndex = baseSet->indexOfKey(overlaySet->keyAt(overlayIndex));
if (baseIndex < UNKNOWN_ERROR) {
// look for same flavor. For a given file (strings.xml, for example)
@@ -462,30 +465,57 @@ static bool applyFileOverlay(const sp<AaptAssets>& assets,
// the same flavor.
sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex);
sp<AaptGroup> baseGroup = baseSet->valueAt(baseIndex);
-
- DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > baseFiles =
- baseGroup->getFiles();
- DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > overlayFiles =
+
+ DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > overlayFiles =
overlayGroup->getFiles();
+ if (bundle->getVerbose()) {
+ DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > baseFiles =
+ baseGroup->getFiles();
+ for (size_t i=0; i < baseFiles.size(); i++) {
+ printf("baseFile %d has flavor %s\n", i,
+ baseFiles.keyAt(i).toString().string());
+ }
+ for (size_t i=0; i < overlayFiles.size(); i++) {
+ printf("overlayFile %d has flavor %s\n", i,
+ overlayFiles.keyAt(i).toString().string());
+ }
+ }
+
size_t overlayGroupSize = overlayFiles.size();
- for (size_t overlayGroupIndex = 0;
- overlayGroupIndex<overlayGroupSize;
+ for (size_t overlayGroupIndex = 0;
+ overlayGroupIndex<overlayGroupSize;
overlayGroupIndex++) {
- size_t baseFileIndex =
- baseFiles.indexOfKey(overlayFiles.keyAt(overlayGroupIndex));
+ size_t baseFileIndex =
+ baseGroup->getFiles().indexOfKey(overlayFiles.
+ keyAt(overlayGroupIndex));
if(baseFileIndex < UNKNOWN_ERROR) {
+ if (bundle->getVerbose()) {
+ printf("found a match (%d) for overlay file %s, for flavor %s\n",
+ baseFileIndex,
+ overlayGroup->getLeaf().string(),
+ overlayFiles.keyAt(overlayGroupIndex).toString().string());
+ }
baseGroup->removeFile(baseFileIndex);
} else {
// didn't find a match fall through and add it..
}
baseGroup->addFile(overlayFiles.valueAt(overlayGroupIndex));
+ assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex));
}
} else {
// this group doesn't exist (a file that's only in the overlay)
- fprintf(stderr, "aapt: error: "
- "*** Resource file '%s' exists only in an overlay\n",
- overlaySet->keyAt(overlayIndex).string());
- return false;
+ baseSet->add(overlaySet->keyAt(overlayIndex),
+ overlaySet->valueAt(overlayIndex));
+ // make sure all flavors are defined in the resources.
+ sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex);
+ DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > overlayFiles =
+ overlayGroup->getFiles();
+ size_t overlayGroupSize = overlayFiles.size();
+ for (size_t overlayGroupIndex = 0;
+ overlayGroupIndex<overlayGroupSize;
+ overlayGroupIndex++) {
+ assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex));
+ }
}
}
// this overlay didn't have resources for this type
@@ -619,13 +649,13 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
current = current->getOverlay();
}
// apply the overlay files to the base set
- if (!applyFileOverlay(assets, drawables, "drawable") ||
- !applyFileOverlay(assets, layouts, "layout") ||
- !applyFileOverlay(assets, anims, "anim") ||
- !applyFileOverlay(assets, xmls, "xml") ||
- !applyFileOverlay(assets, raws, "raw") ||
- !applyFileOverlay(assets, colors, "color") ||
- !applyFileOverlay(assets, menus, "menu")) {
+ if (!applyFileOverlay(bundle, assets, drawables, "drawable") ||
+ !applyFileOverlay(bundle, assets, layouts, "layout") ||
+ !applyFileOverlay(bundle, assets, anims, "anim") ||
+ !applyFileOverlay(bundle, assets, xmls, "xml") ||
+ !applyFileOverlay(bundle, assets, raws, "raw") ||
+ !applyFileOverlay(bundle, assets, colors, "color") ||
+ !applyFileOverlay(bundle, assets, menus, "menu")) {
return UNKNOWN_ERROR;
}
@@ -1118,6 +1148,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(
@@ -1135,7 +1166,6 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
return err;
}
}
-
return err;
}
@@ -1234,10 +1264,16 @@ static status_t writeLayoutClasses(
NA = idents.size();
+ bool deprecated = false;
+
String16 comment = symbols->getComment(realClassName);
fprintf(fp, "%s/** ", indentStr);
if (comment.size() > 0) {
- fprintf(fp, "%s\n", String8(comment).string());
+ String8 cmt(comment);
+ fprintf(fp, "%s\n", cmt.string());
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
+ }
} else {
fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.string());
}
@@ -1313,6 +1349,10 @@ static status_t writeLayoutClasses(
}
fprintf(fp, "%s */\n", getIndentSpace(indent));
+ if (deprecated) {
+ fprintf(fp, "%s@Deprecated\n", indentStr);
+ }
+
fprintf(fp,
"%spublic static final int[] %s = {\n"
"%s",
@@ -1361,11 +1401,17 @@ static status_t writeLayoutClasses(
//printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
// String8(attr16).string(), String8(name16).string(), typeSpecFlags);
const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
-
+
+ bool deprecated = false;
+
fprintf(fp, "%s/**\n", indentStr);
if (comment.size() > 0) {
+ String8 cmt(comment);
fprintf(fp, "%s <p>\n%s @attr description\n", indentStr, indentStr);
- fprintf(fp, "%s %s\n", indentStr, String8(comment).string());
+ fprintf(fp, "%s %s\n", indentStr, cmt.string());
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
+ }
} else {
fprintf(fp,
"%s <p>This symbol is the offset where the {@link %s.R.attr#%s}\n"
@@ -1377,7 +1423,11 @@ static status_t writeLayoutClasses(
indentStr, nclassName.string());
}
if (typeComment.size() > 0) {
- fprintf(fp, "\n\n%s %s\n", indentStr, String8(typeComment).string());
+ String8 cmt(typeComment);
+ fprintf(fp, "\n\n%s %s\n", indentStr, cmt.string());
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
+ }
}
if (comment.size() > 0) {
if (pub) {
@@ -1395,6 +1445,9 @@ static status_t writeLayoutClasses(
fprintf(fp, "%s @attr name %s:%s\n", indentStr,
"android", String8(name).string());
fprintf(fp, "%s*/\n", indentStr);
+ if (deprecated) {
+ fprintf(fp, "%s@Deprecated\n", indentStr);
+ }
fprintf(fp,
"%spublic static final int %s_%s = %d;\n",
indentStr, nclassName.string(),
@@ -1436,11 +1489,16 @@ static status_t writeSymbolClass(
}
String16 comment(sym.comment);
bool haveComment = false;
+ bool deprecated = false;
if (comment.size() > 0) {
haveComment = true;
+ String8 cmt(comment);
fprintf(fp,
"%s/** %s\n",
- getIndentSpace(indent), String8(comment).string());
+ getIndentSpace(indent), cmt.string());
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
+ }
} else if (sym.isPublic && !includePrivate) {
sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
assets->getPackage().string(), className.string(),
@@ -1448,20 +1506,25 @@ static status_t writeSymbolClass(
}
String16 typeComment(sym.typeComment);
if (typeComment.size() > 0) {
+ String8 cmt(typeComment);
if (!haveComment) {
haveComment = true;
fprintf(fp,
- "%s/** %s\n",
- getIndentSpace(indent), String8(typeComment).string());
+ "%s/** %s\n", getIndentSpace(indent), cmt.string());
} else {
fprintf(fp,
- "%s %s\n",
- getIndentSpace(indent), String8(typeComment).string());
+ "%s %s\n", getIndentSpace(indent), cmt.string());
+ }
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
}
}
if (haveComment) {
fprintf(fp,"%s */\n", getIndentSpace(indent));
}
+ if (deprecated) {
+ fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent));
+ }
fprintf(fp, "%spublic static final int %s=0x%08x;\n",
getIndentSpace(indent),
String8(name).string(), (int)sym.int32Val);
@@ -1480,17 +1543,25 @@ static status_t writeSymbolClass(
return UNKNOWN_ERROR;
}
String16 comment(sym.comment);
+ bool deprecated = false;
if (comment.size() > 0) {
+ String8 cmt(comment);
fprintf(fp,
"%s/** %s\n"
"%s */\n",
- getIndentSpace(indent), String8(comment).string(),
+ getIndentSpace(indent), cmt.string(),
getIndentSpace(indent));
+ if (strstr(cmt.string(), "@deprecated") != NULL) {
+ deprecated = true;
+ }
} else if (sym.isPublic && !includePrivate) {
sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
assets->getPackage().string(), className.string(),
String8(sym.name).string());
}
+ if (deprecated) {
+ fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent));
+ }
fprintf(fp, "%spublic static final String %s=\"%s\";\n",
getIndentSpace(indent),
String8(name).string(), sym.stringVal.string());
@@ -1585,3 +1656,230 @@ status_t writeResourceSymbols(Bundle* bundle, const sp<AaptAssets>& assets,
return NO_ERROR;
}
+
+
+
+class ProguardKeepSet
+{
+public:
+ // { rule --> { file locations } }
+ KeyedVector<String8, SortedVector<String8> > rules;
+
+ void add(const String8& rule, const String8& where);
+};
+
+void ProguardKeepSet::add(const String8& rule, const String8& where)
+{
+ ssize_t index = rules.indexOfKey(rule);
+ if (index < 0) {
+ index = rules.add(rule, SortedVector<String8>());
+ }
+ rules.editValueAt(index).add(where);
+}
+
+status_t
+writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
+{
+ status_t err;
+ ResXMLTree tree;
+ size_t len;
+ ResXMLTree::event_code_t code;
+ int depth = 0;
+ bool inApplication = false;
+ String8 error;
+ sp<AaptGroup> assGroup;
+ sp<AaptFile> assFile;
+ String8 pkg;
+
+ // First, look for a package file to parse. This is required to
+ // be able to generate the resource information.
+ assGroup = assets->getFiles().valueFor(String8("AndroidManifest.xml"));
+ if (assGroup == NULL) {
+ fprintf(stderr, "ERROR: No AndroidManifest.xml file found.\n");
+ return -1;
+ }
+
+ if (assGroup->getFiles().size() != 1) {
+ fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
+ assGroup->getFiles().valueAt(0)->getPrintableSource().string());
+ }
+
+ assFile = assGroup->getFiles().valueAt(0);
+
+ err = parseXMLResource(assFile, &tree);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ tree.restart();
+
+ while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ if (code == ResXMLTree::END_TAG) {
+ if (/* name == "Application" && */ depth == 2) {
+ inApplication = false;
+ }
+ depth--;
+ continue;
+ }
+ if (code != ResXMLTree::START_TAG) {
+ continue;
+ }
+ depth++;
+ String8 tag(tree.getElementName(&len));
+ // printf("Depth %d tag %s\n", depth, tag.string());
+ if (depth == 1) {
+ if (tag != "manifest") {
+ fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
+ return -1;
+ }
+ pkg = getAttribute(tree, NULL, "package", NULL);
+ } else if (depth == 2 && tag == "application") {
+ inApplication = true;
+ }
+ if (inApplication) {
+ if (tag == "application" || tag == "activity" || tag == "service" || tag == "receiver"
+ || tag == "provider") {
+ String8 name = getAttribute(tree, "http://schemas.android.com/apk/res/android",
+ "name", &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR: %s\n", error.string());
+ return -1;
+ }
+ // asdf --> package.asdf
+ // .asdf .a.b --> package.asdf package.a.b
+ // asdf.adsf --> asdf.asdf
+ String8 rule("-keep class ");
+ const char* p = name.string();
+ const char* q = strchr(p, '.');
+ if (p == q) {
+ rule += pkg;
+ rule += name;
+ } else if (q == NULL) {
+ rule += pkg;
+ rule += ".";
+ rule += name;
+ } else {
+ rule += name;
+ }
+
+ String8 location = tag;
+ location += " ";
+ location += assFile->getSourceFile();
+ char lineno[20];
+ sprintf(lineno, ":%d", tree.getLineNumber());
+ location += lineno;
+
+ keep->add(rule, location);
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t
+writeProguardForLayout(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile)
+{
+ status_t err;
+ ResXMLTree tree;
+ size_t len;
+ ResXMLTree::event_code_t code;
+
+ err = parseXMLResource(layoutFile, &tree);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ tree.restart();
+
+ while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ if (code != ResXMLTree::START_TAG) {
+ continue;
+ }
+ String8 tag(tree.getElementName(&len));
+
+ // If there is no '.', we'll assume that it's one of the built in names.
+ if (strchr(tag.string(), '.')) {
+ String8 rule("-keep class ");
+ rule += tag;
+ rule += " { <init>(...); }";
+
+ String8 location("view ");
+ location += layoutFile->getSourceFile();
+ char lineno[20];
+ sprintf(lineno, ":%d", tree.getLineNumber());
+ location += lineno;
+
+ keep->add(rule, location);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t
+writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
+{
+ status_t err;
+ sp<AaptDir> layout = assets->resDir(String8("layout"));
+
+ if (layout != NULL) {
+ const KeyedVector<String8,sp<AaptGroup> > groups = layout->getFiles();
+ const size_t N = groups.size();
+ for (size_t i=0; i<N; i++) {
+ const sp<AaptGroup>& group = groups.valueAt(i);
+ const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles();
+ const size_t M = files.size();
+ for (size_t j=0; j<M; j++) {
+ err = writeProguardForLayout(keep, files.valueAt(j));
+ if (err < 0) {
+ return err;
+ }
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t
+writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets)
+{
+ status_t err = -1;
+
+ if (!bundle->getProguardFile()) {
+ return NO_ERROR;
+ }
+
+ ProguardKeepSet keep;
+
+ err = writeProguardForAndroidManifest(&keep, assets);
+ if (err < 0) {
+ return err;
+ }
+
+ err = writeProguardForLayouts(&keep, assets);
+ if (err < 0) {
+ return err;
+ }
+
+ FILE* fp = fopen(bundle->getProguardFile(), "w+");
+ if (fp == NULL) {
+ fprintf(stderr, "ERROR: Unable to open class file %s: %s\n",
+ bundle->getProguardFile(), strerror(errno));
+ return UNKNOWN_ERROR;
+ }
+
+ const KeyedVector<String8, SortedVector<String8> >& rules = keep.rules;
+ const size_t N = rules.size();
+ for (size_t i=0; i<N; i++) {
+ const SortedVector<String8>& locations = rules.valueAt(i);
+ const size_t M = locations.size();
+ for (size_t j=0; j<M; j++) {
+ fprintf(fp, "# %s\n", locations.itemAt(j).string());
+ }
+ fprintf(fp, "%s\n\n", rules.keyAt(i).string());
+ }
+ fclose(fp);
+
+ return err;
+}
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index b004664..95a2384 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -663,6 +663,7 @@ status_t compileResourceFile(Bundle* bundle,
const String16 public16("public");
const String16 public_padding16("public-padding");
const String16 private_symbols16("private-symbols");
+ const String16 add_resource16("add-resource");
const String16 skip16("skip");
const String16 eat_comment16("eat-comment");
@@ -960,6 +961,36 @@ status_t compileResourceFile(Bundle* bundle,
}
continue;
+ } else if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
+ SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
+
+ String16 typeName;
+ ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
+ if (typeIdx < 0) {
+ srcPos.error("A 'type' attribute is required for <add-resource>\n");
+ hasErrors = localHasErrors = true;
+ }
+ typeName = String16(block.getAttributeStringValue(typeIdx, &len));
+
+ String16 name;
+ ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
+ if (nameIdx < 0) {
+ srcPos.error("A 'name' attribute is required for <add-resource>\n");
+ hasErrors = localHasErrors = true;
+ }
+ name = String16(block.getAttributeStringValue(nameIdx, &len));
+
+ outTable->canAddEntry(srcPos, myPackage, typeName, name);
+
+ while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ if (code == ResXMLTree::END_TAG) {
+ if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
+ break;
+ }
+ }
+ }
+ continue;
+
} else if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) {
SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
@@ -1557,9 +1588,21 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos,
}
#endif
if (overlay && !hasBagOrEntry(package, type, name)) {
- sourcePos.error("Can't add new bags in an overlay. See '%s'\n",
- String8(name).string());
- return UNKNOWN_ERROR;
+ bool canAdd = false;
+ sp<Package> p = mPackages.valueFor(package);
+ if (p != NULL) {
+ sp<Type> t = p->getTypes().valueFor(type);
+ if (t != NULL) {
+ if (t->getCanAddEntries().indexOf(name) >= 0) {
+ canAdd = true;
+ }
+ }
+ }
+ if (!canAdd) {
+ sourcePos.error("Resource does not already exist in overlay at '%s'; use <add-resource> to add.\n",
+ String8(name).string());
+ return UNKNOWN_ERROR;
+ }
}
sp<Entry> e = getEntry(package, type, name, sourcePos, overlay, params);
if (e == NULL) {
@@ -1724,6 +1767,15 @@ bool ResourceTable::appendTypeComment(const String16& package,
return false;
}
+void ResourceTable::canAddEntry(const SourcePos& pos,
+ const String16& package, const String16& type, const String16& name)
+{
+ sp<Type> t = getType(package, type, pos);
+ if (t != NULL) {
+ t->canAddEntry(name);
+ }
+}
+
size_t ResourceTable::size() const {
return mPackages.size();
}
@@ -3215,6 +3267,11 @@ status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos,
return NO_ERROR;
}
+void ResourceTable::Type::canAddEntry(const String16& name)
+{
+ mCanAddEntries.add(name);
+}
+
sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
const SourcePos& sourcePos,
const ResTable_config* config,
@@ -3224,9 +3281,10 @@ sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry,
int pos = -1;
sp<ConfigList> c = mConfigs.valueFor(entry);
if (c == NULL) {
- if (overlay == true) {
- sourcePos.error("Resource %s appears in overlay but not"
- " in the base package.\n", String8(entry).string());
+ if (overlay == true && mCanAddEntries.indexOf(entry) < 0) {
+ sourcePos.error("Resource at %s appears in overlay but not"
+ " in the base package; use <add-resource> to add.\n",
+ String8(entry).string());
return NULL;
}
c = new ConfigList(entry, sourcePos);
@@ -3554,26 +3612,26 @@ sp<const ResourceTable::Entry> ResourceTable::getEntry(uint32_t resID,
}
if (p == NULL) {
- fprintf(stderr, "WARNING: Package not found for resource #%08x\n", resID);
+ fprintf(stderr, "warning: Package not found for resource #%08x\n", resID);
return NULL;
}
int tid = Res_GETTYPE(resID);
if (tid < 0 || tid >= (int)p->getOrderedTypes().size()) {
- fprintf(stderr, "WARNING: Type not found for resource #%08x\n", resID);
+ fprintf(stderr, "warning: Type not found for resource #%08x\n", resID);
return NULL;
}
sp<Type> t = p->getOrderedTypes()[tid];
int eid = Res_GETENTRY(resID);
if (eid < 0 || eid >= (int)t->getOrderedConfigs().size()) {
- fprintf(stderr, "WARNING: Entry not found for resource #%08x\n", resID);
+ fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID);
return NULL;
}
sp<ConfigList> c = t->getOrderedConfigs()[eid];
if (c == NULL) {
- fprintf(stderr, "WARNING: Entry not found for resource #%08x\n", resID);
+ fprintf(stderr, "warning: Entry not found for resource #%08x\n", resID);
return NULL;
}
@@ -3581,7 +3639,7 @@ sp<const ResourceTable::Entry> ResourceTable::getEntry(uint32_t resID,
if (config) cdesc = *config;
sp<Entry> e = c->getEntries().valueFor(cdesc);
if (c == NULL) {
- fprintf(stderr, "WARNING: Entry configuration not found for resource #%08x\n", resID);
+ fprintf(stderr, "warning: Entry configuration not found for resource #%08x\n", resID);
return NULL;
}
@@ -3599,7 +3657,7 @@ const ResourceTable::Item* ResourceTable::getItem(uint32_t resID, uint32_t attrI
for (size_t i=0; i<N; i++) {
const Item& it = e->getBag().valueAt(i);
if (it.bagKeyId == 0) {
- fprintf(stderr, "WARNING: ID not yet assigned to '%s' in bag '%s'\n",
+ fprintf(stderr, "warning: ID not yet assigned to '%s' in bag '%s'\n",
String8(e->getName()).string(),
String8(e->getBag().keyAt(i)).string());
}
@@ -3627,7 +3685,7 @@ bool ResourceTable::getItemValue(
break;
}
}
- fprintf(stderr, "WARNING: Circular reference detected in key '%s' of bag '%s'\n",
+ fprintf(stderr, "warning: Circular reference detected in key '%s' of bag '%s'\n",
String8(e->getName()).string(),
String8(e->getBag().keyAt(i)).string());
return false;
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index ec4331a..caa01b3 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -132,6 +132,9 @@ public:
const String16& name,
const String16& comment);
+ void canAddEntry(const SourcePos& pos,
+ const String16& package, const String16& type, const String16& name);
+
size_t size() const;
size_t numLocalResources() const;
bool hasResources() const;
@@ -413,7 +416,9 @@ public:
status_t addPublic(const SourcePos& pos,
const String16& name,
const uint32_t ident);
-
+
+ void canAddEntry(const String16& name);
+
String16 getName() const { return mName; }
sp<Entry> getEntry(const String16& entry,
const SourcePos& pos,
@@ -435,6 +440,8 @@ public:
const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }
+ const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
+
const SourcePos& getPos() const { return mPos; }
private:
String16 mName;
@@ -443,6 +450,7 @@ public:
SortedVector<ConfigDescription> mUniqueConfigs;
DefaultKeyedVector<String16, sp<ConfigList> > mConfigs;
Vector<sp<ConfigList> > mOrderedConfigs;
+ SortedVector<String16> mCanAddEntries;
int32_t mPublicIndex;
int32_t mIndex;
SourcePos mPos;
diff --git a/tools/aapt/SourcePos.cpp b/tools/aapt/SourcePos.cpp
index 2761d18..e2a921c 100644
--- a/tools/aapt/SourcePos.cpp
+++ b/tools/aapt/SourcePos.cpp
@@ -86,7 +86,7 @@ ErrorPos::operator=(const ErrorPos& rhs)
void
ErrorPos::print(FILE* to) const
{
- const char* type = fatal ? "ERROR" : "WARNING";
+ const char* type = fatal ? "error:" : "warning:";
if (this->line >= 0) {
fprintf(to, "%s:%d: %s %s\n", this->file.string(), this->line, type, this->error.string());
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 2a85bc7..6daa0d2 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -220,7 +220,7 @@ moveon:
spanStack.pop();
if (empty) {
- fprintf(stderr, "%s:%d: WARNING: empty '%s' span found in text '%s'\n",
+ fprintf(stderr, "%s:%d: warning: empty '%s' span found in text '%s'\n",
fileName, inXml->getLineNumber(),
String8(spanTag).string(), String8(*outString).string());
@@ -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/tools/aapt/ZipEntry.cpp b/tools/aapt/ZipEntry.cpp
new file mode 100644
index 0000000..a0b54c2
--- /dev/null
+++ b/tools/aapt/ZipEntry.cpp
@@ -0,0 +1,696 @@
+/*
+ * 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.
+ */
+
+//
+// Access to entries in a Zip archive.
+//
+
+#define LOG_TAG "zip"
+
+#include "ZipEntry.h"
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Initialize a new ZipEntry structure from a FILE* positioned at a
+ * CentralDirectoryEntry.
+ *
+ * On exit, the file pointer will be at the start of the next CDE or
+ * at the EOCD.
+ */
+status_t ZipEntry::initFromCDE(FILE* fp)
+{
+ status_t result;
+ long posn;
+ bool hasDD;
+
+ //LOGV("initFromCDE ---\n");
+
+ /* read the CDE */
+ result = mCDE.read(fp);
+ if (result != NO_ERROR) {
+ LOGD("mCDE.read failed\n");
+ return result;
+ }
+
+ //mCDE.dump();
+
+ /* using the info in the CDE, go load up the LFH */
+ posn = ftell(fp);
+ if (fseek(fp, mCDE.mLocalHeaderRelOffset, SEEK_SET) != 0) {
+ LOGD("local header seek failed (%ld)\n",
+ mCDE.mLocalHeaderRelOffset);
+ return UNKNOWN_ERROR;
+ }
+
+ result = mLFH.read(fp);
+ if (result != NO_ERROR) {
+ LOGD("mLFH.read failed\n");
+ return result;
+ }
+
+ if (fseek(fp, posn, SEEK_SET) != 0)
+ return UNKNOWN_ERROR;
+
+ //mLFH.dump();
+
+ /*
+ * We *might* need to read the Data Descriptor at this point and
+ * integrate it into the LFH. If this bit is set, the CRC-32,
+ * compressed size, and uncompressed size will be zero. In practice
+ * these seem to be rare.
+ */
+ hasDD = (mLFH.mGPBitFlag & kUsesDataDescr) != 0;
+ if (hasDD) {
+ // do something clever
+ //LOGD("+++ has data descriptor\n");
+ }
+
+ /*
+ * Sanity-check the LFH. Note that this will fail if the "kUsesDataDescr"
+ * flag is set, because the LFH is incomplete. (Not a problem, since we
+ * prefer the CDE values.)
+ */
+ if (!hasDD && !compareHeaders()) {
+ LOGW("warning: header mismatch\n");
+ // keep going?
+ }
+
+ /*
+ * If the mVersionToExtract is greater than 20, we may have an
+ * issue unpacking the record -- could be encrypted, compressed
+ * with something we don't support, or use Zip64 extensions. We
+ * can defer worrying about that to when we're extracting data.
+ */
+
+ return NO_ERROR;
+}
+
+/*
+ * Initialize a new entry. Pass in the file name and an optional comment.
+ *
+ * Initializes the CDE and the LFH.
+ */
+void ZipEntry::initNew(const char* fileName, const char* comment)
+{
+ assert(fileName != NULL && *fileName != '\0'); // name required
+
+ /* most fields are properly initialized by constructor */
+ mCDE.mVersionMadeBy = kDefaultMadeBy;
+ mCDE.mVersionToExtract = kDefaultVersion;
+ mCDE.mCompressionMethod = kCompressStored;
+ mCDE.mFileNameLength = strlen(fileName);
+ if (comment != NULL)
+ mCDE.mFileCommentLength = strlen(comment);
+ mCDE.mExternalAttrs = 0x81b60020; // matches what WinZip does
+
+ if (mCDE.mFileNameLength > 0) {
+ mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+ strcpy((char*) mCDE.mFileName, fileName);
+ }
+ if (mCDE.mFileCommentLength > 0) {
+ /* TODO: stop assuming null-terminated ASCII here? */
+ mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+ strcpy((char*) mCDE.mFileComment, comment);
+ }
+
+ copyCDEtoLFH();
+}
+
+/*
+ * Initialize a new entry, starting with the ZipEntry from a different
+ * archive.
+ *
+ * Initializes the CDE and the LFH.
+ */
+status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
+ const ZipEntry* pEntry)
+{
+ /*
+ * Copy everything in the CDE over, then fix up the hairy bits.
+ */
+ memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
+
+ if (mCDE.mFileNameLength > 0) {
+ mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
+ if (mCDE.mFileName == NULL)
+ return NO_MEMORY;
+ strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
+ }
+ if (mCDE.mFileCommentLength > 0) {
+ mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
+ if (mCDE.mFileComment == NULL)
+ return NO_MEMORY;
+ strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
+ }
+ if (mCDE.mExtraFieldLength > 0) {
+ /* we null-terminate this, though it may not be a string */
+ mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
+ if (mCDE.mExtraField == NULL)
+ return NO_MEMORY;
+ memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
+ mCDE.mExtraFieldLength+1);
+ }
+
+ /* construct the LFH from the CDE */
+ copyCDEtoLFH();
+
+ /*
+ * The LFH "extra" field is independent of the CDE "extra", so we
+ * handle it here.
+ */
+ assert(mLFH.mExtraField == NULL);
+ mLFH.mExtraFieldLength = pEntry->mLFH.mExtraFieldLength;
+ if (mLFH.mExtraFieldLength > 0) {
+ mLFH.mExtraField = new unsigned char[mLFH.mExtraFieldLength+1];
+ if (mLFH.mExtraField == NULL)
+ return NO_MEMORY;
+ memcpy(mLFH.mExtraField, pEntry->mLFH.mExtraField,
+ mLFH.mExtraFieldLength+1);
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Insert pad bytes in the LFH by tweaking the "extra" field. This will
+ * potentially confuse something that put "extra" data in here earlier,
+ * but I can't find an actual problem.
+ */
+status_t ZipEntry::addPadding(int padding)
+{
+ if (padding <= 0)
+ return INVALID_OPERATION;
+
+ //LOGI("HEY: adding %d pad bytes to existing %d in %s\n",
+ // padding, mLFH.mExtraFieldLength, mCDE.mFileName);
+
+ if (mLFH.mExtraFieldLength > 0) {
+ /* extend existing field */
+ unsigned char* newExtra;
+
+ newExtra = new unsigned char[mLFH.mExtraFieldLength + padding];
+ if (newExtra == NULL)
+ return NO_MEMORY;
+ memset(newExtra + mLFH.mExtraFieldLength, 0, padding);
+ memcpy(newExtra, mLFH.mExtraField, mLFH.mExtraFieldLength);
+
+ delete[] mLFH.mExtraField;
+ mLFH.mExtraField = newExtra;
+ mLFH.mExtraFieldLength += padding;
+ } else {
+ /* create new field */
+ mLFH.mExtraField = new unsigned char[padding];
+ memset(mLFH.mExtraField, 0, padding);
+ mLFH.mExtraFieldLength = padding;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Set the fields in the LFH equal to the corresponding fields in the CDE.
+ *
+ * This does not touch the LFH "extra" field.
+ */
+void ZipEntry::copyCDEtoLFH(void)
+{
+ mLFH.mVersionToExtract = mCDE.mVersionToExtract;
+ mLFH.mGPBitFlag = mCDE.mGPBitFlag;
+ mLFH.mCompressionMethod = mCDE.mCompressionMethod;
+ mLFH.mLastModFileTime = mCDE.mLastModFileTime;
+ mLFH.mLastModFileDate = mCDE.mLastModFileDate;
+ mLFH.mCRC32 = mCDE.mCRC32;
+ mLFH.mCompressedSize = mCDE.mCompressedSize;
+ mLFH.mUncompressedSize = mCDE.mUncompressedSize;
+ mLFH.mFileNameLength = mCDE.mFileNameLength;
+ // the "extra field" is independent
+
+ delete[] mLFH.mFileName;
+ if (mLFH.mFileNameLength > 0) {
+ mLFH.mFileName = new unsigned char[mLFH.mFileNameLength+1];
+ strcpy((char*) mLFH.mFileName, (const char*) mCDE.mFileName);
+ } else {
+ mLFH.mFileName = NULL;
+ }
+}
+
+/*
+ * Set some information about a file after we add it.
+ */
+void ZipEntry::setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+ int compressionMethod)
+{
+ mCDE.mCompressionMethod = compressionMethod;
+ mCDE.mCRC32 = crc32;
+ mCDE.mCompressedSize = compLen;
+ mCDE.mUncompressedSize = uncompLen;
+ mCDE.mCompressionMethod = compressionMethod;
+ if (compressionMethod == kCompressDeflated) {
+ mCDE.mGPBitFlag |= 0x0002; // indicates maximum compression used
+ }
+ copyCDEtoLFH();
+}
+
+/*
+ * See if the data in mCDE and mLFH match up. This is mostly useful for
+ * debugging these classes, but it can be used to identify damaged
+ * archives.
+ *
+ * Returns "false" if they differ.
+ */
+bool ZipEntry::compareHeaders(void) const
+{
+ if (mCDE.mVersionToExtract != mLFH.mVersionToExtract) {
+ LOGV("cmp: VersionToExtract\n");
+ return false;
+ }
+ if (mCDE.mGPBitFlag != mLFH.mGPBitFlag) {
+ LOGV("cmp: GPBitFlag\n");
+ return false;
+ }
+ if (mCDE.mCompressionMethod != mLFH.mCompressionMethod) {
+ LOGV("cmp: CompressionMethod\n");
+ return false;
+ }
+ if (mCDE.mLastModFileTime != mLFH.mLastModFileTime) {
+ LOGV("cmp: LastModFileTime\n");
+ return false;
+ }
+ if (mCDE.mLastModFileDate != mLFH.mLastModFileDate) {
+ LOGV("cmp: LastModFileDate\n");
+ return false;
+ }
+ if (mCDE.mCRC32 != mLFH.mCRC32) {
+ LOGV("cmp: CRC32\n");
+ return false;
+ }
+ if (mCDE.mCompressedSize != mLFH.mCompressedSize) {
+ LOGV("cmp: CompressedSize\n");
+ return false;
+ }
+ if (mCDE.mUncompressedSize != mLFH.mUncompressedSize) {
+ LOGV("cmp: UncompressedSize\n");
+ return false;
+ }
+ if (mCDE.mFileNameLength != mLFH.mFileNameLength) {
+ LOGV("cmp: FileNameLength\n");
+ return false;
+ }
+#if 0 // this seems to be used for padding, not real data
+ if (mCDE.mExtraFieldLength != mLFH.mExtraFieldLength) {
+ LOGV("cmp: ExtraFieldLength\n");
+ return false;
+ }
+#endif
+ if (mCDE.mFileName != NULL) {
+ if (strcmp((char*) mCDE.mFileName, (char*) mLFH.mFileName) != 0) {
+ LOGV("cmp: FileName\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/*
+ * Convert the DOS date/time stamp into a UNIX time stamp.
+ */
+time_t ZipEntry::getModWhen(void) const
+{
+ struct tm parts;
+
+ parts.tm_sec = (mCDE.mLastModFileTime & 0x001f) << 1;
+ parts.tm_min = (mCDE.mLastModFileTime & 0x07e0) >> 5;
+ parts.tm_hour = (mCDE.mLastModFileTime & 0xf800) >> 11;
+ parts.tm_mday = (mCDE.mLastModFileDate & 0x001f);
+ parts.tm_mon = ((mCDE.mLastModFileDate & 0x01e0) >> 5) -1;
+ parts.tm_year = ((mCDE.mLastModFileDate & 0xfe00) >> 9) + 80;
+ parts.tm_wday = parts.tm_yday = 0;
+ parts.tm_isdst = -1; // DST info "not available"
+
+ return mktime(&parts);
+}
+
+/*
+ * Set the CDE/LFH timestamp from UNIX time.
+ */
+void ZipEntry::setModWhen(time_t when)
+{
+#ifdef HAVE_LOCALTIME_R
+ struct tm tmResult;
+#endif
+ time_t even;
+ unsigned short zdate, ztime;
+
+ struct tm* ptm;
+
+ /* round up to an even number of seconds */
+ even = (time_t)(((unsigned long)(when) + 1) & (~1));
+
+ /* expand */
+#ifdef HAVE_LOCALTIME_R
+ ptm = localtime_r(&even, &tmResult);
+#else
+ ptm = localtime(&even);
+#endif
+
+ int year;
+ year = ptm->tm_year;
+ if (year < 80)
+ year = 80;
+
+ zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday;
+ ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
+
+ mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime;
+ mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate;
+}
+
+
+/*
+ * ===========================================================================
+ * ZipEntry::LocalFileHeader
+ * ===========================================================================
+ */
+
+/*
+ * Read a local file header.
+ *
+ * On entry, "fp" points to the signature at the start of the header.
+ * On exit, "fp" points to the start of data.
+ */
+status_t ZipEntry::LocalFileHeader::read(FILE* fp)
+{
+ status_t result = NO_ERROR;
+ unsigned char buf[kLFHLen];
+
+ assert(mFileName == NULL);
+ assert(mExtraField == NULL);
+
+ if (fread(buf, 1, kLFHLen, fp) != kLFHLen) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+ LOGD("whoops: didn't find expected signature\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ mVersionToExtract = ZipEntry::getShortLE(&buf[0x04]);
+ mGPBitFlag = ZipEntry::getShortLE(&buf[0x06]);
+ mCompressionMethod = ZipEntry::getShortLE(&buf[0x08]);
+ mLastModFileTime = ZipEntry::getShortLE(&buf[0x0a]);
+ mLastModFileDate = ZipEntry::getShortLE(&buf[0x0c]);
+ mCRC32 = ZipEntry::getLongLE(&buf[0x0e]);
+ mCompressedSize = ZipEntry::getLongLE(&buf[0x12]);
+ mUncompressedSize = ZipEntry::getLongLE(&buf[0x16]);
+ mFileNameLength = ZipEntry::getShortLE(&buf[0x1a]);
+ mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1c]);
+
+ // TODO: validate sizes
+
+ /* grab filename */
+ if (mFileNameLength != 0) {
+ mFileName = new unsigned char[mFileNameLength+1];
+ if (mFileName == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileName[mFileNameLength] = '\0';
+ }
+
+ /* grab extra field */
+ if (mExtraFieldLength != 0) {
+ mExtraField = new unsigned char[mExtraFieldLength+1];
+ if (mExtraField == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mExtraField[mExtraFieldLength] = '\0';
+ }
+
+bail:
+ return result;
+}
+
+/*
+ * Write a local file header.
+ */
+status_t ZipEntry::LocalFileHeader::write(FILE* fp)
+{
+ unsigned char buf[kLFHLen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mVersionToExtract);
+ ZipEntry::putShortLE(&buf[0x06], mGPBitFlag);
+ ZipEntry::putShortLE(&buf[0x08], mCompressionMethod);
+ ZipEntry::putShortLE(&buf[0x0a], mLastModFileTime);
+ ZipEntry::putShortLE(&buf[0x0c], mLastModFileDate);
+ ZipEntry::putLongLE(&buf[0x0e], mCRC32);
+ ZipEntry::putLongLE(&buf[0x12], mCompressedSize);
+ ZipEntry::putLongLE(&buf[0x16], mUncompressedSize);
+ ZipEntry::putShortLE(&buf[0x1a], mFileNameLength);
+ ZipEntry::putShortLE(&buf[0x1c], mExtraFieldLength);
+
+ if (fwrite(buf, 1, kLFHLen, fp) != kLFHLen)
+ return UNKNOWN_ERROR;
+
+ /* write filename */
+ if (mFileNameLength != 0) {
+ if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write "extra field" */
+ if (mExtraFieldLength != 0) {
+ if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
+/*
+ * Dump the contents of a LocalFileHeader object.
+ */
+void ZipEntry::LocalFileHeader::dump(void) const
+{
+ LOGD(" LocalFileHeader contents:\n");
+ LOGD(" versToExt=%u gpBits=0x%04x compression=%u\n",
+ mVersionToExtract, mGPBitFlag, mCompressionMethod);
+ LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+ mLastModFileTime, mLastModFileDate, mCRC32);
+ LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
+ mCompressedSize, mUncompressedSize);
+ LOGD(" filenameLen=%u extraLen=%u\n",
+ mFileNameLength, mExtraFieldLength);
+ if (mFileName != NULL)
+ LOGD(" filename: '%s'\n", mFileName);
+}
+
+
+/*
+ * ===========================================================================
+ * ZipEntry::CentralDirEntry
+ * ===========================================================================
+ */
+
+/*
+ * Read the central dir entry that appears next in the file.
+ *
+ * On entry, "fp" should be positioned on the signature bytes for the
+ * entry. On exit, "fp" will point at the signature word for the next
+ * entry or for the EOCD.
+ */
+status_t ZipEntry::CentralDirEntry::read(FILE* fp)
+{
+ status_t result = NO_ERROR;
+ unsigned char buf[kCDELen];
+
+ /* no re-use */
+ assert(mFileName == NULL);
+ assert(mExtraField == NULL);
+ assert(mFileComment == NULL);
+
+ if (fread(buf, 1, kCDELen, fp) != kCDELen) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature) {
+ LOGD("Whoops: didn't find expected signature\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ mVersionMadeBy = ZipEntry::getShortLE(&buf[0x04]);
+ mVersionToExtract = ZipEntry::getShortLE(&buf[0x06]);
+ mGPBitFlag = ZipEntry::getShortLE(&buf[0x08]);
+ mCompressionMethod = ZipEntry::getShortLE(&buf[0x0a]);
+ mLastModFileTime = ZipEntry::getShortLE(&buf[0x0c]);
+ mLastModFileDate = ZipEntry::getShortLE(&buf[0x0e]);
+ mCRC32 = ZipEntry::getLongLE(&buf[0x10]);
+ mCompressedSize = ZipEntry::getLongLE(&buf[0x14]);
+ mUncompressedSize = ZipEntry::getLongLE(&buf[0x18]);
+ mFileNameLength = ZipEntry::getShortLE(&buf[0x1c]);
+ mExtraFieldLength = ZipEntry::getShortLE(&buf[0x1e]);
+ mFileCommentLength = ZipEntry::getShortLE(&buf[0x20]);
+ mDiskNumberStart = ZipEntry::getShortLE(&buf[0x22]);
+ mInternalAttrs = ZipEntry::getShortLE(&buf[0x24]);
+ mExternalAttrs = ZipEntry::getLongLE(&buf[0x26]);
+ mLocalHeaderRelOffset = ZipEntry::getLongLE(&buf[0x2a]);
+
+ // TODO: validate sizes and offsets
+
+ /* grab filename */
+ if (mFileNameLength != 0) {
+ mFileName = new unsigned char[mFileNameLength+1];
+ if (mFileName == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileName, 1, mFileNameLength, fp) != mFileNameLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileName[mFileNameLength] = '\0';
+ }
+
+ /* read "extra field" */
+ if (mExtraFieldLength != 0) {
+ mExtraField = new unsigned char[mExtraFieldLength+1];
+ if (mExtraField == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mExtraField[mExtraFieldLength] = '\0';
+ }
+
+
+ /* grab comment, if any */
+ if (mFileCommentLength != 0) {
+ mFileComment = new unsigned char[mFileCommentLength+1];
+ if (mFileComment == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+ if (fread(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+ {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ mFileComment[mFileCommentLength] = '\0';
+ }
+
+bail:
+ return result;
+}
+
+/*
+ * Write a central dir entry.
+ */
+status_t ZipEntry::CentralDirEntry::write(FILE* fp)
+{
+ unsigned char buf[kCDELen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mVersionMadeBy);
+ ZipEntry::putShortLE(&buf[0x06], mVersionToExtract);
+ ZipEntry::putShortLE(&buf[0x08], mGPBitFlag);
+ ZipEntry::putShortLE(&buf[0x0a], mCompressionMethod);
+ ZipEntry::putShortLE(&buf[0x0c], mLastModFileTime);
+ ZipEntry::putShortLE(&buf[0x0e], mLastModFileDate);
+ ZipEntry::putLongLE(&buf[0x10], mCRC32);
+ ZipEntry::putLongLE(&buf[0x14], mCompressedSize);
+ ZipEntry::putLongLE(&buf[0x18], mUncompressedSize);
+ ZipEntry::putShortLE(&buf[0x1c], mFileNameLength);
+ ZipEntry::putShortLE(&buf[0x1e], mExtraFieldLength);
+ ZipEntry::putShortLE(&buf[0x20], mFileCommentLength);
+ ZipEntry::putShortLE(&buf[0x22], mDiskNumberStart);
+ ZipEntry::putShortLE(&buf[0x24], mInternalAttrs);
+ ZipEntry::putLongLE(&buf[0x26], mExternalAttrs);
+ ZipEntry::putLongLE(&buf[0x2a], mLocalHeaderRelOffset);
+
+ if (fwrite(buf, 1, kCDELen, fp) != kCDELen)
+ return UNKNOWN_ERROR;
+
+ /* write filename */
+ if (mFileNameLength != 0) {
+ if (fwrite(mFileName, 1, mFileNameLength, fp) != mFileNameLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write "extra field" */
+ if (mExtraFieldLength != 0) {
+ if (fwrite(mExtraField, 1, mExtraFieldLength, fp) != mExtraFieldLength)
+ return UNKNOWN_ERROR;
+ }
+
+ /* write comment */
+ if (mFileCommentLength != 0) {
+ if (fwrite(mFileComment, 1, mFileCommentLength, fp) != mFileCommentLength)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Dump the contents of a CentralDirEntry object.
+ */
+void ZipEntry::CentralDirEntry::dump(void) const
+{
+ LOGD(" CentralDirEntry contents:\n");
+ LOGD(" versMadeBy=%u versToExt=%u gpBits=0x%04x compression=%u\n",
+ mVersionMadeBy, mVersionToExtract, mGPBitFlag, mCompressionMethod);
+ LOGD(" modTime=0x%04x modDate=0x%04x crc32=0x%08lx\n",
+ mLastModFileTime, mLastModFileDate, mCRC32);
+ LOGD(" compressedSize=%lu uncompressedSize=%lu\n",
+ mCompressedSize, mUncompressedSize);
+ LOGD(" filenameLen=%u extraLen=%u commentLen=%u\n",
+ mFileNameLength, mExtraFieldLength, mFileCommentLength);
+ LOGD(" diskNumStart=%u intAttr=0x%04x extAttr=0x%08lx relOffset=%lu\n",
+ mDiskNumberStart, mInternalAttrs, mExternalAttrs,
+ mLocalHeaderRelOffset);
+
+ if (mFileName != NULL)
+ LOGD(" filename: '%s'\n", mFileName);
+ if (mFileComment != NULL)
+ LOGD(" comment: '%s'\n", mFileComment);
+}
+
diff --git a/tools/aapt/ZipEntry.h b/tools/aapt/ZipEntry.h
new file mode 100644
index 0000000..7f721b4
--- /dev/null
+++ b/tools/aapt/ZipEntry.h
@@ -0,0 +1,345 @@
+/*
+ * 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.
+ */
+
+//
+// Zip archive entries.
+//
+// The ZipEntry class is tightly meshed with the ZipFile class.
+//
+#ifndef __LIBS_ZIPENTRY_H
+#define __LIBS_ZIPENTRY_H
+
+#include <utils/Errors.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+namespace android {
+
+class ZipFile;
+
+/*
+ * ZipEntry objects represent a single entry in a Zip archive.
+ *
+ * You can use one of these to get or set information about an entry, but
+ * there are no functions here for accessing the data itself. (We could
+ * tuck a pointer to the ZipFile in here for convenience, but that raises
+ * the likelihood of using ZipEntry objects after discarding the ZipFile.)
+ *
+ * File information is stored in two places: next to the file data (the Local
+ * File Header, and possibly a Data Descriptor), and at the end of the file
+ * (the Central Directory Entry). The two must be kept in sync.
+ */
+class ZipEntry {
+public:
+ friend class ZipFile;
+
+ ZipEntry(void)
+ : mDeleted(false), mMarked(false)
+ {}
+ ~ZipEntry(void) {}
+
+ /*
+ * Returns "true" if the data is compressed.
+ */
+ bool isCompressed(void) const {
+ return mCDE.mCompressionMethod != kCompressStored;
+ }
+ int getCompressionMethod(void) const { return mCDE.mCompressionMethod; }
+
+ /*
+ * Return the uncompressed length.
+ */
+ off_t getUncompressedLen(void) const { return mCDE.mUncompressedSize; }
+
+ /*
+ * Return the compressed length. For uncompressed data, this returns
+ * the same thing as getUncompresesdLen().
+ */
+ off_t getCompressedLen(void) const { return mCDE.mCompressedSize; }
+
+ /*
+ * Return the absolute file offset of the start of the compressed or
+ * uncompressed data.
+ */
+ off_t getFileOffset(void) const {
+ return mCDE.mLocalHeaderRelOffset +
+ LocalFileHeader::kLFHLen +
+ mLFH.mFileNameLength +
+ mLFH.mExtraFieldLength;
+ }
+
+ /*
+ * Return the data CRC.
+ */
+ unsigned long getCRC32(void) const { return mCDE.mCRC32; }
+
+ /*
+ * Return file modification time in UNIX seconds-since-epoch.
+ */
+ time_t getModWhen(void) const;
+
+ /*
+ * Return the archived file name.
+ */
+ const char* getFileName(void) const { return (const char*) mCDE.mFileName; }
+
+ /*
+ * Application-defined "mark". Can be useful when synchronizing the
+ * contents of an archive with contents on disk.
+ */
+ bool getMarked(void) const { return mMarked; }
+ void setMarked(bool val) { mMarked = val; }
+
+ /*
+ * Some basic functions for raw data manipulation. "LE" means
+ * Little Endian.
+ */
+ static inline unsigned short getShortLE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8);
+ }
+ static inline unsigned long getLongLE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+ }
+ static inline void putShortLE(unsigned char* buf, short val) {
+ buf[0] = (unsigned char) val;
+ buf[1] = (unsigned char) (val >> 8);
+ }
+ static inline void putLongLE(unsigned char* buf, long val) {
+ buf[0] = (unsigned char) val;
+ buf[1] = (unsigned char) (val >> 8);
+ buf[2] = (unsigned char) (val >> 16);
+ buf[3] = (unsigned char) (val >> 24);
+ }
+
+ /* defined for Zip archives */
+ enum {
+ kCompressStored = 0, // no compression
+ // shrunk = 1,
+ // reduced 1 = 2,
+ // reduced 2 = 3,
+ // reduced 3 = 4,
+ // reduced 4 = 5,
+ // imploded = 6,
+ // tokenized = 7,
+ kCompressDeflated = 8, // standard deflate
+ // Deflate64 = 9,
+ // lib imploded = 10,
+ // reserved = 11,
+ // bzip2 = 12,
+ };
+
+ /*
+ * Deletion flag. If set, the entry will be removed on the next
+ * call to "flush".
+ */
+ bool getDeleted(void) const { return mDeleted; }
+
+protected:
+ /*
+ * Initialize the structure from the file, which is pointing at
+ * our Central Directory entry.
+ */
+ status_t initFromCDE(FILE* fp);
+
+ /*
+ * Initialize the structure for a new file. We need the filename
+ * and comment so that we can properly size the LFH area. The
+ * filename is mandatory, the comment is optional.
+ */
+ void initNew(const char* fileName, const char* comment);
+
+ /*
+ * Initialize the structure with the contents of a ZipEntry from
+ * another file.
+ */
+ status_t initFromExternal(const ZipFile* pZipFile, const ZipEntry* pEntry);
+
+ /*
+ * Add some pad bytes to the LFH. We do this by adding or resizing
+ * the "extra" field.
+ */
+ status_t addPadding(int padding);
+
+ /*
+ * Set information about the data for this entry.
+ */
+ void setDataInfo(long uncompLen, long compLen, unsigned long crc32,
+ int compressionMethod);
+
+ /*
+ * Set the modification date.
+ */
+ void setModWhen(time_t when);
+
+ /*
+ * Return the offset of the local file header.
+ */
+ off_t getLFHOffset(void) const { return mCDE.mLocalHeaderRelOffset; }
+
+ /*
+ * Set the offset of the local file header, relative to the start of
+ * the current file.
+ */
+ void setLFHOffset(off_t offset) {
+ mCDE.mLocalHeaderRelOffset = (long) offset;
+ }
+
+ /* mark for deletion; used by ZipFile::remove() */
+ void setDeleted(void) { mDeleted = true; }
+
+private:
+ /* these are private and not defined */
+ ZipEntry(const ZipEntry& src);
+ ZipEntry& operator=(const ZipEntry& src);
+
+ /* returns "true" if the CDE and the LFH agree */
+ bool compareHeaders(void) const;
+ void copyCDEtoLFH(void);
+
+ bool mDeleted; // set if entry is pending deletion
+ bool mMarked; // app-defined marker
+
+ /*
+ * Every entry in the Zip archive starts off with one of these.
+ */
+ class LocalFileHeader {
+ public:
+ LocalFileHeader(void) :
+ mVersionToExtract(0),
+ mGPBitFlag(0),
+ mCompressionMethod(0),
+ mLastModFileTime(0),
+ mLastModFileDate(0),
+ mCRC32(0),
+ mCompressedSize(0),
+ mUncompressedSize(0),
+ mFileNameLength(0),
+ mExtraFieldLength(0),
+ mFileName(NULL),
+ mExtraField(NULL)
+ {}
+ virtual ~LocalFileHeader(void) {
+ delete[] mFileName;
+ delete[] mExtraField;
+ }
+
+ status_t read(FILE* fp);
+ status_t write(FILE* fp);
+
+ // unsigned long mSignature;
+ unsigned short mVersionToExtract;
+ unsigned short mGPBitFlag;
+ unsigned short mCompressionMethod;
+ unsigned short mLastModFileTime;
+ unsigned short mLastModFileDate;
+ unsigned long mCRC32;
+ unsigned long mCompressedSize;
+ unsigned long mUncompressedSize;
+ unsigned short mFileNameLength;
+ unsigned short mExtraFieldLength;
+ unsigned char* mFileName;
+ unsigned char* mExtraField;
+
+ enum {
+ kSignature = 0x04034b50,
+ kLFHLen = 30, // LocalFileHdr len, excl. var fields
+ };
+
+ void dump(void) const;
+ };
+
+ /*
+ * Every entry in the Zip archive has one of these in the "central
+ * directory" at the end of the file.
+ */
+ class CentralDirEntry {
+ public:
+ CentralDirEntry(void) :
+ mVersionMadeBy(0),
+ mVersionToExtract(0),
+ mGPBitFlag(0),
+ mCompressionMethod(0),
+ mLastModFileTime(0),
+ mLastModFileDate(0),
+ mCRC32(0),
+ mCompressedSize(0),
+ mUncompressedSize(0),
+ mFileNameLength(0),
+ mExtraFieldLength(0),
+ mFileCommentLength(0),
+ mDiskNumberStart(0),
+ mInternalAttrs(0),
+ mExternalAttrs(0),
+ mLocalHeaderRelOffset(0),
+ mFileName(NULL),
+ mExtraField(NULL),
+ mFileComment(NULL)
+ {}
+ virtual ~CentralDirEntry(void) {
+ delete[] mFileName;
+ delete[] mExtraField;
+ delete[] mFileComment;
+ }
+
+ status_t read(FILE* fp);
+ status_t write(FILE* fp);
+
+ // unsigned long mSignature;
+ unsigned short mVersionMadeBy;
+ unsigned short mVersionToExtract;
+ unsigned short mGPBitFlag;
+ unsigned short mCompressionMethod;
+ unsigned short mLastModFileTime;
+ unsigned short mLastModFileDate;
+ unsigned long mCRC32;
+ unsigned long mCompressedSize;
+ unsigned long mUncompressedSize;
+ unsigned short mFileNameLength;
+ unsigned short mExtraFieldLength;
+ unsigned short mFileCommentLength;
+ unsigned short mDiskNumberStart;
+ unsigned short mInternalAttrs;
+ unsigned long mExternalAttrs;
+ unsigned long mLocalHeaderRelOffset;
+ unsigned char* mFileName;
+ unsigned char* mExtraField;
+ unsigned char* mFileComment;
+
+ void dump(void) const;
+
+ enum {
+ kSignature = 0x02014b50,
+ kCDELen = 46, // CentralDirEnt len, excl. var fields
+ };
+ };
+
+ enum {
+ //kDataDescriptorSignature = 0x08074b50, // currently unused
+ kDataDescriptorLen = 16, // four 32-bit fields
+
+ kDefaultVersion = 20, // need deflate, nothing much else
+ kDefaultMadeBy = 0x0317, // 03=UNIX, 17=spec v2.3
+ kUsesDataDescr = 0x0008, // GPBitFlag bit 3
+ };
+
+ LocalFileHeader mLFH;
+ CentralDirEntry mCDE;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPENTRY_H
diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp
new file mode 100644
index 0000000..62c9383
--- /dev/null
+++ b/tools/aapt/ZipFile.cpp
@@ -0,0 +1,1297 @@
+/*
+ * 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.
+ */
+
+//
+// Access to Zip archives.
+//
+
+#define LOG_TAG "zip"
+
+#include <utils/ZipUtils.h>
+#include <utils/Log.h>
+
+#include "ZipFile.h"
+
+#include <zlib.h>
+#define DEF_MEM_LEVEL 8 // normally in zutil.h?
+
+#include <memory.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * Some environments require the "b", some choke on it.
+ */
+#define FILE_OPEN_RO "rb"
+#define FILE_OPEN_RW "r+b"
+#define FILE_OPEN_RW_CREATE "w+b"
+
+/* should live somewhere else? */
+static status_t errnoToStatus(int err)
+{
+ if (err == ENOENT)
+ return NAME_NOT_FOUND;
+ else if (err == EACCES)
+ return PERMISSION_DENIED;
+ else
+ return UNKNOWN_ERROR;
+}
+
+/*
+ * Open a file and parse its guts.
+ */
+status_t ZipFile::open(const char* zipFileName, int flags)
+{
+ bool newArchive = false;
+
+ assert(mZipFp == NULL); // no reopen
+
+ if ((flags & kOpenTruncate))
+ flags |= kOpenCreate; // trunc implies create
+
+ if ((flags & kOpenReadOnly) && (flags & kOpenReadWrite))
+ return INVALID_OPERATION; // not both
+ if (!((flags & kOpenReadOnly) || (flags & kOpenReadWrite)))
+ return INVALID_OPERATION; // not neither
+ if ((flags & kOpenCreate) && !(flags & kOpenReadWrite))
+ return INVALID_OPERATION; // create requires write
+
+ if (flags & kOpenTruncate) {
+ newArchive = true;
+ } else {
+ newArchive = (access(zipFileName, F_OK) != 0);
+ if (!(flags & kOpenCreate) && newArchive) {
+ /* not creating, must already exist */
+ LOGD("File %s does not exist", zipFileName);
+ return NAME_NOT_FOUND;
+ }
+ }
+
+ /* open the file */
+ const char* openflags;
+ if (flags & kOpenReadWrite) {
+ if (newArchive)
+ openflags = FILE_OPEN_RW_CREATE;
+ else
+ openflags = FILE_OPEN_RW;
+ } else {
+ openflags = FILE_OPEN_RO;
+ }
+ mZipFp = fopen(zipFileName, openflags);
+ if (mZipFp == NULL) {
+ int err = errno;
+ LOGD("fopen failed: %d\n", err);
+ return errnoToStatus(err);
+ }
+
+ status_t result;
+ if (!newArchive) {
+ /*
+ * Load the central directory. If that fails, then this probably
+ * isn't a Zip archive.
+ */
+ result = readCentralDir();
+ } else {
+ /*
+ * Newly-created. The EndOfCentralDir constructor actually
+ * sets everything to be the way we want it (all zeroes). We
+ * set mNeedCDRewrite so that we create *something* if the
+ * caller doesn't add any files. (We could also just unlink
+ * the file if it's brand new and nothing was added, but that's
+ * probably doing more than we really should -- the user might
+ * have a need for empty zip files.)
+ */
+ mNeedCDRewrite = true;
+ result = NO_ERROR;
+ }
+
+ if (flags & kOpenReadOnly)
+ mReadOnly = true;
+ else
+ assert(!mReadOnly);
+
+ return result;
+}
+
+/*
+ * Return the Nth entry in the archive.
+ */
+ZipEntry* ZipFile::getEntryByIndex(int idx) const
+{
+ if (idx < 0 || idx >= (int) mEntries.size())
+ return NULL;
+
+ return mEntries[idx];
+}
+
+/*
+ * Find an entry by name.
+ */
+ZipEntry* ZipFile::getEntryByName(const char* fileName) const
+{
+ /*
+ * Do a stupid linear string-compare search.
+ *
+ * There are various ways to speed this up, especially since it's rare
+ * to intermingle changes to the archive with "get by name" calls. We
+ * don't want to sort the mEntries vector itself, however, because
+ * it's used to recreate the Central Directory.
+ *
+ * (Hash table works, parallel list of pointers in sorted order is good.)
+ */
+ int idx;
+
+ for (idx = mEntries.size()-1; idx >= 0; idx--) {
+ ZipEntry* pEntry = mEntries[idx];
+ if (!pEntry->getDeleted() &&
+ strcmp(fileName, pEntry->getFileName()) == 0)
+ {
+ return pEntry;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Empty the mEntries vector.
+ */
+void ZipFile::discardEntries(void)
+{
+ int count = mEntries.size();
+
+ while (--count >= 0)
+ delete mEntries[count];
+
+ mEntries.clear();
+}
+
+
+/*
+ * Find the central directory and read the contents.
+ *
+ * The fun thing about ZIP archives is that they may or may not be
+ * readable from start to end. In some cases, notably for archives
+ * that were written to stdout, the only length information is in the
+ * central directory at the end of the file.
+ *
+ * Of course, the central directory can be followed by a variable-length
+ * comment field, so we have to scan through it backwards. The comment
+ * is at most 64K, plus we have 18 bytes for the end-of-central-dir stuff
+ * itself, plus apparently sometimes people throw random junk on the end
+ * just for the fun of it.
+ *
+ * This is all a little wobbly. If the wrong value ends up in the EOCD
+ * area, we're hosed. This appears to be the way that everbody handles
+ * it though, so we're in pretty good company if this fails.
+ */
+status_t ZipFile::readCentralDir(void)
+{
+ status_t result = NO_ERROR;
+ unsigned char* buf = NULL;
+ off_t fileLength, seekStart;
+ long readAmount;
+ int i;
+
+ fseek(mZipFp, 0, SEEK_END);
+ fileLength = ftell(mZipFp);
+ rewind(mZipFp);
+
+ /* too small to be a ZIP archive? */
+ if (fileLength < EndOfCentralDir::kEOCDLen) {
+ LOGD("Length is %ld -- too small\n", (long)fileLength);
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ buf = new unsigned char[EndOfCentralDir::kMaxEOCDSearch];
+ if (buf == NULL) {
+ LOGD("Failure allocating %d bytes for EOCD search",
+ EndOfCentralDir::kMaxEOCDSearch);
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ if (fileLength > EndOfCentralDir::kMaxEOCDSearch) {
+ seekStart = fileLength - EndOfCentralDir::kMaxEOCDSearch;
+ readAmount = EndOfCentralDir::kMaxEOCDSearch;
+ } else {
+ seekStart = 0;
+ readAmount = (long) fileLength;
+ }
+ if (fseek(mZipFp, seekStart, SEEK_SET) != 0) {
+ LOGD("Failure seeking to end of zip at %ld", (long) seekStart);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /* read the last part of the file into the buffer */
+ if (fread(buf, 1, readAmount, mZipFp) != (size_t) readAmount) {
+ LOGD("short file? wanted %ld\n", readAmount);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /* find the end-of-central-dir magic */
+ for (i = readAmount - 4; i >= 0; i--) {
+ if (buf[i] == 0x50 &&
+ ZipEntry::getLongLE(&buf[i]) == EndOfCentralDir::kSignature)
+ {
+ LOGV("+++ Found EOCD at buf+%d\n", i);
+ break;
+ }
+ }
+ if (i < 0) {
+ LOGD("EOCD not found, not Zip\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ /* extract eocd values */
+ result = mEOCD.readBuf(buf + i, readAmount - i);
+ if (result != NO_ERROR) {
+ LOGD("Failure reading %ld bytes of EOCD values", readAmount - i);
+ goto bail;
+ }
+ //mEOCD.dump();
+
+ if (mEOCD.mDiskNumber != 0 || mEOCD.mDiskWithCentralDir != 0 ||
+ mEOCD.mNumEntries != mEOCD.mTotalNumEntries)
+ {
+ LOGD("Archive spanning not supported\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+
+ /*
+ * So far so good. "mCentralDirSize" is the size in bytes of the
+ * central directory, so we can just seek back that far to find it.
+ * We can also seek forward mCentralDirOffset bytes from the
+ * start of the file.
+ *
+ * We're not guaranteed to have the rest of the central dir in the
+ * buffer, nor are we guaranteed that the central dir will have any
+ * sort of convenient size. We need to skip to the start of it and
+ * read the header, then the other goodies.
+ *
+ * The only thing we really need right now is the file comment, which
+ * we're hoping to preserve.
+ */
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ LOGD("Failure seeking to central dir offset %ld\n",
+ mEOCD.mCentralDirOffset);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * Loop through and read the central dir entries.
+ */
+ LOGV("Scanning %d entries...\n", mEOCD.mTotalNumEntries);
+ int entry;
+ for (entry = 0; entry < mEOCD.mTotalNumEntries; entry++) {
+ ZipEntry* pEntry = new ZipEntry;
+
+ result = pEntry->initFromCDE(mZipFp);
+ if (result != NO_ERROR) {
+ LOGD("initFromCDE failed\n");
+ delete pEntry;
+ goto bail;
+ }
+
+ mEntries.add(pEntry);
+ }
+
+
+ /*
+ * If all went well, we should now be back at the EOCD.
+ */
+ {
+ unsigned char checkBuf[4];
+ if (fread(checkBuf, 1, 4, mZipFp) != 4) {
+ LOGD("EOCD check read failed\n");
+ result = INVALID_OPERATION;
+ goto bail;
+ }
+ if (ZipEntry::getLongLE(checkBuf) != EndOfCentralDir::kSignature) {
+ LOGD("EOCD read check failed\n");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ LOGV("+++ EOCD read check passed\n");
+ }
+
+bail:
+ delete[] buf;
+ return result;
+}
+
+
+/*
+ * Add a new file to the archive.
+ *
+ * This requires creating and populating a ZipEntry structure, and copying
+ * the data into the file at the appropriate position. The "appropriate
+ * position" is the current location of the central directory, which we
+ * casually overwrite (we can put it back later).
+ *
+ * If we were concerned about safety, we would want to make all changes
+ * in a temp file and then overwrite the original after everything was
+ * safely written. Not really a concern for us.
+ */
+status_t ZipFile::addCommon(const char* fileName, const void* data, size_t size,
+ const char* storageName, int sourceType, int compressionMethod,
+ ZipEntry** ppEntry)
+{
+ ZipEntry* pEntry = NULL;
+ status_t result = NO_ERROR;
+ long lfhPosn, startPosn, endPosn, uncompressedLen;
+ FILE* inputFp = NULL;
+ unsigned long crc;
+ time_t modWhen;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+
+ assert(compressionMethod == ZipEntry::kCompressDeflated ||
+ compressionMethod == ZipEntry::kCompressStored);
+
+ /* make sure we're in a reasonable state */
+ assert(mZipFp != NULL);
+ assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+ /* make sure it doesn't already exist */
+ if (getEntryByName(storageName) != NULL)
+ return ALREADY_EXISTS;
+
+ if (!data) {
+ inputFp = fopen(fileName, FILE_OPEN_RO);
+ if (inputFp == NULL)
+ return errnoToStatus(errno);
+ }
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ pEntry = new ZipEntry;
+ pEntry->initNew(storageName, NULL);
+
+ /*
+ * From here on out, failures are more interesting.
+ */
+ mNeedCDRewrite = true;
+
+ /*
+ * Write the LFH, even though it's still mostly blank. We need it
+ * as a place-holder. In theory the LFH isn't necessary, but in
+ * practice some utilities demand it.
+ */
+ lfhPosn = ftell(mZipFp);
+ pEntry->mLFH.write(mZipFp);
+ startPosn = ftell(mZipFp);
+
+ /*
+ * Copy the data in, possibly compressing it as we go.
+ */
+ if (sourceType == ZipEntry::kCompressStored) {
+ if (compressionMethod == ZipEntry::kCompressDeflated) {
+ bool failed = false;
+ result = compressFpToFp(mZipFp, inputFp, data, size, &crc);
+ if (result != NO_ERROR) {
+ LOGD("compression failed, storing\n");
+ failed = true;
+ } else {
+ /*
+ * Make sure it has compressed "enough". This probably ought
+ * to be set through an API call, but I don't expect our
+ * criteria to change over time.
+ */
+ long src = inputFp ? ftell(inputFp) : size;
+ long dst = ftell(mZipFp) - startPosn;
+ if (dst + (dst / 10) > src) {
+ LOGD("insufficient compression (src=%ld dst=%ld), storing\n",
+ src, dst);
+ failed = true;
+ }
+ }
+
+ if (failed) {
+ compressionMethod = ZipEntry::kCompressStored;
+ if (inputFp) rewind(inputFp);
+ fseek(mZipFp, startPosn, SEEK_SET);
+ /* fall through to kCompressStored case */
+ }
+ }
+ /* handle "no compression" request, or failed compression from above */
+ if (compressionMethod == ZipEntry::kCompressStored) {
+ if (inputFp) {
+ result = copyFpToFp(mZipFp, inputFp, &crc);
+ } else {
+ result = copyDataToFp(mZipFp, data, size, &crc);
+ }
+ if (result != NO_ERROR) {
+ // don't need to truncate; happens in CDE rewrite
+ LOGD("failed copying data in\n");
+ goto bail;
+ }
+ }
+
+ // currently seeked to end of file
+ uncompressedLen = inputFp ? ftell(inputFp) : size;
+ } else if (sourceType == ZipEntry::kCompressDeflated) {
+ /* we should support uncompressed-from-compressed, but it's not
+ * important right now */
+ assert(compressionMethod == ZipEntry::kCompressDeflated);
+
+ bool scanResult;
+ int method;
+ long compressedLen;
+
+ scanResult = ZipUtils::examineGzip(inputFp, &method, &uncompressedLen,
+ &compressedLen, &crc);
+ if (!scanResult || method != ZipEntry::kCompressDeflated) {
+ LOGD("this isn't a deflated gzip file?");
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ result = copyPartialFpToFp(mZipFp, inputFp, compressedLen, NULL);
+ if (result != NO_ERROR) {
+ LOGD("failed copying gzip data in\n");
+ goto bail;
+ }
+ } else {
+ assert(false);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * We could write the "Data Descriptor", but there doesn't seem to
+ * be any point since we're going to go back and write the LFH.
+ *
+ * Update file offsets.
+ */
+ endPosn = ftell(mZipFp); // seeked to end of compressed data
+
+ /*
+ * Success! Fill out new values.
+ */
+ pEntry->setDataInfo(uncompressedLen, endPosn - startPosn, crc,
+ compressionMethod);
+ modWhen = getModTime(inputFp ? fileno(inputFp) : fileno(mZipFp));
+ pEntry->setModWhen(modWhen);
+ pEntry->setLFHOffset(lfhPosn);
+ mEOCD.mNumEntries++;
+ mEOCD.mTotalNumEntries++;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+ mEOCD.mCentralDirOffset = endPosn;
+
+ /*
+ * Go back and write the LFH.
+ */
+ if (fseek(mZipFp, lfhPosn, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+ pEntry->mLFH.write(mZipFp);
+
+ /*
+ * Add pEntry to the list.
+ */
+ mEntries.add(pEntry);
+ if (ppEntry != NULL)
+ *ppEntry = pEntry;
+ pEntry = NULL;
+
+bail:
+ if (inputFp != NULL)
+ fclose(inputFp);
+ delete pEntry;
+ return result;
+}
+
+/*
+ * Add an entry by copying it from another zip file. If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+status_t ZipFile::add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+ int padding, ZipEntry** ppEntry)
+{
+ ZipEntry* pEntry = NULL;
+ status_t result;
+ long lfhPosn, endPosn;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+
+ /* make sure we're in a reasonable state */
+ assert(mZipFp != NULL);
+ assert(mEntries.size() == mEOCD.mTotalNumEntries);
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0) {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ pEntry = new ZipEntry;
+ if (pEntry == NULL) {
+ result = NO_MEMORY;
+ goto bail;
+ }
+
+ result = pEntry->initFromExternal(pSourceZip, pSourceEntry);
+ if (result != NO_ERROR)
+ goto bail;
+ if (padding != 0) {
+ result = pEntry->addPadding(padding);
+ if (result != NO_ERROR)
+ goto bail;
+ }
+
+ /*
+ * From here on out, failures are more interesting.
+ */
+ mNeedCDRewrite = true;
+
+ /*
+ * Write the LFH. Since we're not recompressing the data, we already
+ * have all of the fields filled out.
+ */
+ lfhPosn = ftell(mZipFp);
+ pEntry->mLFH.write(mZipFp);
+
+ /*
+ * Copy the data over.
+ *
+ * If the "has data descriptor" flag is set, we want to copy the DD
+ * fields as well. This is a fixed-size area immediately following
+ * the data.
+ */
+ if (fseek(pSourceZip->mZipFp, pSourceEntry->getFileOffset(), SEEK_SET) != 0)
+ {
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ off_t copyLen;
+ copyLen = pSourceEntry->getCompressedLen();
+ if ((pSourceEntry->mLFH.mGPBitFlag & ZipEntry::kUsesDataDescr) != 0)
+ copyLen += ZipEntry::kDataDescriptorLen;
+
+ if (copyPartialFpToFp(mZipFp, pSourceZip->mZipFp, copyLen, NULL)
+ != NO_ERROR)
+ {
+ LOGW("copy of '%s' failed\n", pEntry->mCDE.mFileName);
+ result = UNKNOWN_ERROR;
+ goto bail;
+ }
+
+ /*
+ * Update file offsets.
+ */
+ endPosn = ftell(mZipFp);
+
+ /*
+ * Success! Fill out new values.
+ */
+ pEntry->setLFHOffset(lfhPosn); // sets mCDE.mLocalHeaderRelOffset
+ mEOCD.mNumEntries++;
+ mEOCD.mTotalNumEntries++;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+ mEOCD.mCentralDirOffset = endPosn;
+
+ /*
+ * Add pEntry to the list.
+ */
+ mEntries.add(pEntry);
+ if (ppEntry != NULL)
+ *ppEntry = pEntry;
+ pEntry = NULL;
+
+ result = NO_ERROR;
+
+bail:
+ delete pEntry;
+ return result;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data.
+ */
+status_t ZipFile::copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32)
+{
+ unsigned char tmpBuf[32768];
+ size_t count;
+
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+
+ while (1) {
+ count = fread(tmpBuf, 1, sizeof(tmpBuf), srcFp);
+ if (ferror(srcFp) || ferror(dstFp))
+ return errnoToStatus(errno);
+ if (count == 0)
+ break;
+
+ *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+ if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+ LOGD("fwrite %d bytes failed\n", (int) count);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Copy all of the bytes in "src" to "dst".
+ *
+ * On exit, "dstFp" will be seeked immediately past the data.
+ */
+status_t ZipFile::copyDataToFp(FILE* dstFp,
+ const void* data, size_t size, unsigned long* pCRC32)
+{
+ size_t count;
+
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+ if (size > 0) {
+ *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
+ if (fwrite(data, 1, size, dstFp) != size) {
+ LOGD("fwrite %d bytes failed\n", (int) size);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Copy some of the bytes in "src" to "dst".
+ *
+ * If "pCRC32" is NULL, the CRC will not be computed.
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the data just written.
+ */
+status_t ZipFile::copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+ unsigned long* pCRC32)
+{
+ unsigned char tmpBuf[32768];
+ size_t count;
+
+ if (pCRC32 != NULL)
+ *pCRC32 = crc32(0L, Z_NULL, 0);
+
+ while (length) {
+ long readSize;
+
+ readSize = sizeof(tmpBuf);
+ if (readSize > length)
+ readSize = length;
+
+ count = fread(tmpBuf, 1, readSize, srcFp);
+ if ((long) count != readSize) { // error or unexpected EOF
+ LOGD("fread %d bytes failed\n", (int) readSize);
+ return UNKNOWN_ERROR;
+ }
+
+ if (pCRC32 != NULL)
+ *pCRC32 = crc32(*pCRC32, tmpBuf, count);
+
+ if (fwrite(tmpBuf, 1, count, dstFp) != count) {
+ LOGD("fwrite %d bytes failed\n", (int) count);
+ return UNKNOWN_ERROR;
+ }
+
+ length -= readSize;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Compress all of the data in "srcFp" and write it to "dstFp".
+ *
+ * On exit, "srcFp" will be seeked to the end of the file, and "dstFp"
+ * will be seeked immediately past the compressed data.
+ */
+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;
+ 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) {
+ LOGV("+++ reading %d bytes\n", (int)kBufSize);
+ if (data) {
+ getSize = size > kBufSize ? kBufSize : size;
+ memcpy(inBuf, data, getSize);
+ data = ((const char*)data) + getSize;
+ size -= getSize;
+ } else {
+ getSize = fread(inBuf, 1, kBufSize, srcFp);
+ if (ferror(srcFp)) {
+ LOGD("deflate read failed (errno=%d)\n", errno);
+ goto z_bail;
+ }
+ }
+ if (getSize < kBufSize) {
+ LOGV("+++ got %d bytes, EOF reached\n",
+ (int)getSize);
+ 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));
+ if (fwrite(outBuf, 1, zstream.next_out - outBuf, dstFp) !=
+ (size_t)(zstream.next_out - outBuf))
+ {
+ LOGD("write %d failed in deflate\n",
+ (int) (zstream.next_out - outBuf));
+ goto z_bail;
+ }
+
+ zstream.next_out = outBuf;
+ zstream.avail_out = kBufSize;
+ }
+ } while (zerr == Z_OK);
+
+ assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+
+ *pCRC32 = crc;
+
+z_bail:
+ deflateEnd(&zstream); /* free up any allocated structures */
+
+bail:
+ delete[] inBuf;
+ delete[] outBuf;
+
+ return result;
+}
+
+/*
+ * Mark an entry as deleted.
+ *
+ * We will eventually need to crunch the file down, but if several files
+ * are being removed (perhaps as part of an "update" process) we can make
+ * things considerably faster by deferring the removal to "flush" time.
+ */
+status_t ZipFile::remove(ZipEntry* pEntry)
+{
+ /*
+ * Should verify that pEntry is actually part of this archive, and
+ * not some stray ZipEntry from a different file.
+ */
+
+ /* mark entry as deleted, and mark archive as dirty */
+ pEntry->setDeleted();
+ mNeedCDRewrite = true;
+ return NO_ERROR;
+}
+
+/*
+ * Flush any pending writes.
+ *
+ * In particular, this will crunch out deleted entries, and write the
+ * Central Directory and EOCD if we have stomped on them.
+ */
+status_t ZipFile::flush(void)
+{
+ status_t result = NO_ERROR;
+ long eocdPosn;
+ int i, count;
+
+ if (mReadOnly)
+ return INVALID_OPERATION;
+ if (!mNeedCDRewrite)
+ return NO_ERROR;
+
+ assert(mZipFp != NULL);
+
+ result = crunchArchive();
+ if (result != NO_ERROR)
+ return result;
+
+ if (fseek(mZipFp, mEOCD.mCentralDirOffset, SEEK_SET) != 0)
+ return UNKNOWN_ERROR;
+
+ count = mEntries.size();
+ for (i = 0; i < count; i++) {
+ ZipEntry* pEntry = mEntries[i];
+ pEntry->mCDE.write(mZipFp);
+ }
+
+ eocdPosn = ftell(mZipFp);
+ mEOCD.mCentralDirSize = eocdPosn - mEOCD.mCentralDirOffset;
+
+ mEOCD.write(mZipFp);
+
+ /*
+ * If we had some stuff bloat up during compression and get replaced
+ * with plain files, or if we deleted some entries, there's a lot
+ * of wasted space at the end of the file. Remove it now.
+ */
+ if (ftruncate(fileno(mZipFp), ftell(mZipFp)) != 0) {
+ LOGW("ftruncate failed %ld: %s\n", ftell(mZipFp), strerror(errno));
+ // not fatal
+ }
+
+ /* should we clear the "newly added" flag in all entries now? */
+
+ mNeedCDRewrite = false;
+ return NO_ERROR;
+}
+
+/*
+ * Crunch deleted files out of an archive by shifting the later files down.
+ *
+ * Because we're not using a temp file, we do the operation inside the
+ * current file.
+ */
+status_t ZipFile::crunchArchive(void)
+{
+ status_t result = NO_ERROR;
+ int i, count;
+ long delCount, adjust;
+
+#if 0
+ printf("CONTENTS:\n");
+ for (i = 0; i < (int) mEntries.size(); i++) {
+ printf(" %d: lfhOff=%ld del=%d\n",
+ i, mEntries[i]->getLFHOffset(), mEntries[i]->getDeleted());
+ }
+ printf(" END is %ld\n", (long) mEOCD.mCentralDirOffset);
+#endif
+
+ /*
+ * Roll through the set of files, shifting them as appropriate. We
+ * could probably get a slight performance improvement by sliding
+ * multiple files down at once (because we could use larger reads
+ * when operating on batches of small files), but it's not that useful.
+ */
+ count = mEntries.size();
+ delCount = adjust = 0;
+ for (i = 0; i < count; i++) {
+ ZipEntry* pEntry = mEntries[i];
+ long span;
+
+ if (pEntry->getLFHOffset() != 0) {
+ long nextOffset;
+
+ /* Get the length of this entry by finding the offset
+ * of the next entry. Directory entries don't have
+ * file offsets, so we need to find the next non-directory
+ * entry.
+ */
+ nextOffset = 0;
+ for (int ii = i+1; nextOffset == 0 && ii < count; ii++)
+ nextOffset = mEntries[ii]->getLFHOffset();
+ if (nextOffset == 0)
+ nextOffset = mEOCD.mCentralDirOffset;
+ span = nextOffset - pEntry->getLFHOffset();
+
+ assert(span >= ZipEntry::LocalFileHeader::kLFHLen);
+ } else {
+ /* This is a directory entry. It doesn't have
+ * any actual file contents, so there's no need to
+ * move anything.
+ */
+ span = 0;
+ }
+
+ //printf("+++ %d: off=%ld span=%ld del=%d [count=%d]\n",
+ // i, pEntry->getLFHOffset(), span, pEntry->getDeleted(), count);
+
+ if (pEntry->getDeleted()) {
+ adjust += span;
+ delCount++;
+
+ delete pEntry;
+ mEntries.removeAt(i);
+
+ /* adjust loop control */
+ count--;
+ i--;
+ } else if (span != 0 && adjust > 0) {
+ /* shuffle this entry back */
+ //printf("+++ Shuffling '%s' back %ld\n",
+ // pEntry->getFileName(), adjust);
+ result = filemove(mZipFp, pEntry->getLFHOffset() - adjust,
+ pEntry->getLFHOffset(), span);
+ if (result != NO_ERROR) {
+ /* this is why you use a temp file */
+ LOGE("error during crunch - archive is toast\n");
+ return result;
+ }
+
+ pEntry->setLFHOffset(pEntry->getLFHOffset() - adjust);
+ }
+ }
+
+ /*
+ * Fix EOCD info. We have to wait until the end to do some of this
+ * because we use mCentralDirOffset to determine "span" for the
+ * last entry.
+ */
+ mEOCD.mCentralDirOffset -= adjust;
+ mEOCD.mNumEntries -= delCount;
+ mEOCD.mTotalNumEntries -= delCount;
+ mEOCD.mCentralDirSize = 0; // mark invalid; set by flush()
+
+ assert(mEOCD.mNumEntries == mEOCD.mTotalNumEntries);
+ assert(mEOCD.mNumEntries == count);
+
+ return result;
+}
+
+/*
+ * Works like memmove(), but on pieces of a file.
+ */
+status_t ZipFile::filemove(FILE* fp, off_t dst, off_t src, size_t n)
+{
+ if (dst == src || n <= 0)
+ return NO_ERROR;
+
+ unsigned char readBuf[32768];
+
+ if (dst < src) {
+ /* shift stuff toward start of file; must read from start */
+ while (n != 0) {
+ size_t getSize = sizeof(readBuf);
+ if (getSize > n)
+ getSize = n;
+
+ if (fseek(fp, (long) src, SEEK_SET) != 0) {
+ LOGD("filemove src seek %ld failed\n", (long) src);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fread(readBuf, 1, getSize, fp) != getSize) {
+ LOGD("filemove read %ld off=%ld failed\n",
+ (long) getSize, (long) src);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fseek(fp, (long) dst, SEEK_SET) != 0) {
+ LOGD("filemove dst seek %ld failed\n", (long) dst);
+ return UNKNOWN_ERROR;
+ }
+
+ if (fwrite(readBuf, 1, getSize, fp) != getSize) {
+ LOGD("filemove write %ld off=%ld failed\n",
+ (long) getSize, (long) dst);
+ return UNKNOWN_ERROR;
+ }
+
+ src += getSize;
+ dst += getSize;
+ n -= getSize;
+ }
+ } else {
+ /* shift stuff toward end of file; must read from end */
+ assert(false); // write this someday, maybe
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
+/*
+ * Get the modification time from a file descriptor.
+ */
+time_t ZipFile::getModTime(int fd)
+{
+ struct stat sb;
+
+ if (fstat(fd, &sb) < 0) {
+ LOGD("HEY: fstat on fd %d failed\n", fd);
+ return (time_t) -1;
+ }
+
+ return sb.st_mtime;
+}
+
+
+#if 0 /* this is a bad idea */
+/*
+ * Get a copy of the Zip file descriptor.
+ *
+ * We don't allow this if the file was opened read-write because we tend
+ * to leave the file contents in an uncertain state between calls to
+ * flush(). The duplicated file descriptor should only be valid for reads.
+ */
+int ZipFile::getZipFd(void) const
+{
+ if (!mReadOnly)
+ return INVALID_OPERATION;
+ assert(mZipFp != NULL);
+
+ int fd;
+ fd = dup(fileno(mZipFp));
+ if (fd < 0) {
+ LOGD("didn't work, errno=%d\n", errno);
+ }
+
+ return fd;
+}
+#endif
+
+
+#if 0
+/*
+ * Expand data.
+ */
+bool ZipFile::uncompress(const ZipEntry* pEntry, void* buf) const
+{
+ return false;
+}
+#endif
+
+// free the memory when you're done
+void* ZipFile::uncompress(const ZipEntry* entry)
+{
+ size_t unlen = entry->getUncompressedLen();
+ size_t clen = entry->getCompressedLen();
+
+ void* buf = malloc(unlen);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ fseek(mZipFp, 0, SEEK_SET);
+
+ off_t offset = entry->getFileOffset();
+ if (fseek(mZipFp, offset, SEEK_SET) != 0) {
+ goto bail;
+ }
+
+ switch (entry->getCompressionMethod())
+ {
+ case ZipEntry::kCompressStored: {
+ ssize_t amt = fread(buf, 1, unlen, mZipFp);
+ if (amt != (ssize_t)unlen) {
+ goto bail;
+ }
+#if 0
+ printf("data...\n");
+ const unsigned char* p = (unsigned char*)buf;
+ const unsigned char* end = p+unlen;
+ for (int i=0; i<32 && p < end; i++) {
+ printf("0x%08x ", (int)(offset+(i*0x10)));
+ for (int j=0; j<0x10 && p < end; j++) {
+ printf(" %02x", *p);
+ p++;
+ }
+ printf("\n");
+ }
+#endif
+
+ }
+ break;
+ case ZipEntry::kCompressDeflated: {
+ if (!ZipUtils::inflateToBuffer(mZipFp, buf, unlen, clen)) {
+ goto bail;
+ }
+ }
+ break;
+ default:
+ goto bail;
+ }
+ return buf;
+
+bail:
+ free(buf);
+ return NULL;
+}
+
+
+/*
+ * ===========================================================================
+ * ZipFile::EndOfCentralDir
+ * ===========================================================================
+ */
+
+/*
+ * Read the end-of-central-dir fields.
+ *
+ * "buf" should be positioned at the EOCD signature, and should contain
+ * the entire EOCD area including the comment.
+ */
+status_t ZipFile::EndOfCentralDir::readBuf(const unsigned char* buf, int len)
+{
+ /* don't allow re-use */
+ assert(mComment == NULL);
+
+ if (len < kEOCDLen) {
+ /* looks like ZIP file got truncated */
+ LOGD(" Zip EOCD: expected >= %d bytes, found %d\n",
+ kEOCDLen, len);
+ return INVALID_OPERATION;
+ }
+
+ /* this should probably be an assert() */
+ if (ZipEntry::getLongLE(&buf[0x00]) != kSignature)
+ return UNKNOWN_ERROR;
+
+ mDiskNumber = ZipEntry::getShortLE(&buf[0x04]);
+ mDiskWithCentralDir = ZipEntry::getShortLE(&buf[0x06]);
+ mNumEntries = ZipEntry::getShortLE(&buf[0x08]);
+ mTotalNumEntries = ZipEntry::getShortLE(&buf[0x0a]);
+ mCentralDirSize = ZipEntry::getLongLE(&buf[0x0c]);
+ mCentralDirOffset = ZipEntry::getLongLE(&buf[0x10]);
+ mCommentLen = ZipEntry::getShortLE(&buf[0x14]);
+
+ // TODO: validate mCentralDirOffset
+
+ if (mCommentLen > 0) {
+ if (kEOCDLen + mCommentLen > len) {
+ LOGD("EOCD(%d) + comment(%d) exceeds len (%d)\n",
+ kEOCDLen, mCommentLen, len);
+ return UNKNOWN_ERROR;
+ }
+ mComment = new unsigned char[mCommentLen];
+ memcpy(mComment, buf + kEOCDLen, mCommentLen);
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Write an end-of-central-directory section.
+ */
+status_t ZipFile::EndOfCentralDir::write(FILE* fp)
+{
+ unsigned char buf[kEOCDLen];
+
+ ZipEntry::putLongLE(&buf[0x00], kSignature);
+ ZipEntry::putShortLE(&buf[0x04], mDiskNumber);
+ ZipEntry::putShortLE(&buf[0x06], mDiskWithCentralDir);
+ ZipEntry::putShortLE(&buf[0x08], mNumEntries);
+ ZipEntry::putShortLE(&buf[0x0a], mTotalNumEntries);
+ ZipEntry::putLongLE(&buf[0x0c], mCentralDirSize);
+ ZipEntry::putLongLE(&buf[0x10], mCentralDirOffset);
+ ZipEntry::putShortLE(&buf[0x14], mCommentLen);
+
+ if (fwrite(buf, 1, kEOCDLen, fp) != kEOCDLen)
+ return UNKNOWN_ERROR;
+ if (mCommentLen > 0) {
+ assert(mComment != NULL);
+ if (fwrite(mComment, mCommentLen, 1, fp) != mCommentLen)
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+/*
+ * Dump the contents of an EndOfCentralDir object.
+ */
+void ZipFile::EndOfCentralDir::dump(void) const
+{
+ LOGD(" EndOfCentralDir contents:\n");
+ LOGD(" diskNum=%u diskWCD=%u numEnt=%u totalNumEnt=%u\n",
+ mDiskNumber, mDiskWithCentralDir, mNumEntries, mTotalNumEntries);
+ LOGD(" centDirSize=%lu centDirOff=%lu commentLen=%u\n",
+ mCentralDirSize, mCentralDirOffset, mCommentLen);
+}
+
diff --git a/tools/aapt/ZipFile.h b/tools/aapt/ZipFile.h
new file mode 100644
index 0000000..dbbd072
--- /dev/null
+++ b/tools/aapt/ZipFile.h
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+
+//
+// General-purpose Zip archive access. This class allows both reading and
+// writing to Zip archives, including deletion of existing entries.
+//
+#ifndef __LIBS_ZIPFILE_H
+#define __LIBS_ZIPFILE_H
+
+#include <utils/Vector.h>
+#include <utils/Errors.h>
+#include <stdio.h>
+
+#include "ZipEntry.h"
+
+namespace android {
+
+/*
+ * Manipulate a Zip archive.
+ *
+ * Some changes will not be visible in the until until "flush" is called.
+ *
+ * The correct way to update a file archive is to make all changes to a
+ * copy of the archive in a temporary file, and then unlink/rename over
+ * the original after everything completes. Because we're only interested
+ * in using this for packaging, we don't worry about such things. Crashing
+ * after making changes and before flush() completes could leave us with
+ * an unusable Zip archive.
+ */
+class ZipFile {
+public:
+ ZipFile(void)
+ : mZipFp(NULL), mReadOnly(false), mNeedCDRewrite(false)
+ {}
+ ~ZipFile(void) {
+ if (!mReadOnly)
+ flush();
+ if (mZipFp != NULL)
+ fclose(mZipFp);
+ discardEntries();
+ }
+
+ /*
+ * Open a new or existing archive.
+ */
+ typedef enum {
+ kOpenReadOnly = 0x01,
+ kOpenReadWrite = 0x02,
+ kOpenCreate = 0x04, // create if it doesn't exist
+ kOpenTruncate = 0x08, // if it exists, empty it
+ };
+ status_t open(const char* zipFileName, int flags);
+
+ /*
+ * Add a file to the end of the archive. Specify whether you want the
+ * library to try to store it compressed.
+ *
+ * If "storageName" is specified, the archive will use that instead
+ * of "fileName".
+ *
+ * If there is already an entry with the same name, the call fails.
+ * Existing entries with the same name must be removed first.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const char* fileName, int compressionMethod,
+ ZipEntry** ppEntry)
+ {
+ return add(fileName, fileName, compressionMethod, ppEntry);
+ }
+ status_t add(const char* fileName, const char* storageName,
+ int compressionMethod, ZipEntry** ppEntry)
+ {
+ return addCommon(fileName, NULL, 0, storageName,
+ ZipEntry::kCompressStored,
+ compressionMethod, ppEntry);
+ }
+
+ /*
+ * Add a file that is already compressed with gzip.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t addGzip(const char* fileName, const char* storageName,
+ ZipEntry** ppEntry)
+ {
+ return addCommon(fileName, NULL, 0, storageName,
+ ZipEntry::kCompressDeflated,
+ ZipEntry::kCompressDeflated, ppEntry);
+ }
+
+ /*
+ * Add a file from an in-memory data buffer.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const void* data, size_t size, const char* storageName,
+ int compressionMethod, ZipEntry** ppEntry)
+ {
+ return addCommon(NULL, data, size, storageName,
+ ZipEntry::kCompressStored,
+ compressionMethod, ppEntry);
+ }
+
+ /*
+ * Add an entry by copying it from another zip file. If "padding" is
+ * nonzero, the specified number of bytes will be added to the "extra"
+ * field in the header.
+ *
+ * If "ppEntry" is non-NULL, a pointer to the new entry will be returned.
+ */
+ status_t add(const ZipFile* pSourceZip, const ZipEntry* pSourceEntry,
+ int padding, ZipEntry** ppEntry);
+
+ /*
+ * Mark an entry as having been removed. It is not actually deleted
+ * from the archive or our internal data structures until flush() is
+ * called.
+ */
+ status_t remove(ZipEntry* pEntry);
+
+ /*
+ * Flush changes. If mNeedCDRewrite is set, this writes the central dir.
+ */
+ status_t flush(void);
+
+ /*
+ * Expand the data into the buffer provided. The buffer must hold
+ * at least <uncompressed len> bytes. Variation expands directly
+ * to a file.
+ *
+ * Returns "false" if an error was encountered in the compressed data.
+ */
+ //bool uncompress(const ZipEntry* pEntry, void* buf) const;
+ //bool uncompress(const ZipEntry* pEntry, FILE* fp) const;
+ void* uncompress(const ZipEntry* pEntry);
+
+ /*
+ * Get an entry, by name. Returns NULL if not found.
+ *
+ * Does not return entries pending deletion.
+ */
+ ZipEntry* getEntryByName(const char* fileName) const;
+
+ /*
+ * Get the Nth entry in the archive.
+ *
+ * This will return an entry that is pending deletion.
+ */
+ int getNumEntries(void) const { return mEntries.size(); }
+ ZipEntry* getEntryByIndex(int idx) const;
+
+private:
+ /* these are private and not defined */
+ ZipFile(const ZipFile& src);
+ ZipFile& operator=(const ZipFile& src);
+
+ class EndOfCentralDir {
+ public:
+ EndOfCentralDir(void) :
+ mDiskNumber(0),
+ mDiskWithCentralDir(0),
+ mNumEntries(0),
+ mTotalNumEntries(0),
+ mCentralDirSize(0),
+ mCentralDirOffset(0),
+ mCommentLen(0),
+ mComment(NULL)
+ {}
+ virtual ~EndOfCentralDir(void) {
+ delete[] mComment;
+ }
+
+ status_t readBuf(const unsigned char* buf, int len);
+ status_t write(FILE* fp);
+
+ //unsigned long mSignature;
+ unsigned short mDiskNumber;
+ unsigned short mDiskWithCentralDir;
+ unsigned short mNumEntries;
+ unsigned short mTotalNumEntries;
+ unsigned long mCentralDirSize;
+ unsigned long mCentralDirOffset; // offset from first disk
+ unsigned short mCommentLen;
+ unsigned char* mComment;
+
+ enum {
+ kSignature = 0x06054b50,
+ kEOCDLen = 22, // EndOfCentralDir len, excl. comment
+
+ kMaxCommentLen = 65535, // longest possible in ushort
+ kMaxEOCDSearch = kMaxCommentLen + EndOfCentralDir::kEOCDLen,
+
+ };
+
+ void dump(void) const;
+ };
+
+
+ /* read all entries in the central dir */
+ status_t readCentralDir(void);
+
+ /* crunch deleted entries out */
+ status_t crunchArchive(void);
+
+ /* clean up mEntries */
+ void discardEntries(void);
+
+ /* common handler for all "add" functions */
+ status_t addCommon(const char* fileName, const void* data, size_t size,
+ const char* storageName, int sourceType, int compressionMethod,
+ ZipEntry** ppEntry);
+
+ /* copy all of "srcFp" into "dstFp" */
+ status_t copyFpToFp(FILE* dstFp, FILE* srcFp, unsigned long* pCRC32);
+ /* copy all of "data" into "dstFp" */
+ status_t copyDataToFp(FILE* dstFp,
+ const void* data, size_t size, unsigned long* pCRC32);
+ /* copy some of "srcFp" into "dstFp" */
+ status_t copyPartialFpToFp(FILE* dstFp, FILE* srcFp, long length,
+ unsigned long* pCRC32);
+ /* like memmove(), but on parts of a single file */
+ status_t filemove(FILE* fp, off_t dest, off_t src, size_t n);
+ /* compress all of "srcFp" into "dstFp", using Deflate */
+ status_t compressFpToFp(FILE* dstFp, FILE* srcFp,
+ const void* data, size_t size, unsigned long* pCRC32);
+
+ /* get modification date from a file descriptor */
+ time_t getModTime(int fd);
+
+ /*
+ * We use stdio FILE*, which gives us buffering but makes dealing
+ * with files >2GB awkward. Until we support Zip64, we're fine.
+ */
+ FILE* mZipFp; // Zip file pointer
+
+ /* one of these per file */
+ EndOfCentralDir mEOCD;
+
+ /* did we open this read-only? */
+ bool mReadOnly;
+
+ /* set this when we trash the central dir */
+ bool mNeedCDRewrite;
+
+ /*
+ * One ZipEntry per entry in the zip file. I'm using pointers instead
+ * of objects because it's easier than making operator= work for the
+ * classes and sub-classes.
+ */
+ Vector<ZipEntry*> mEntries;
+};
+
+}; // namespace android
+
+#endif // __LIBS_ZIPFILE_H
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
index 85ca5da..752ef7c 100755
--- a/tools/aidl/AST.cpp
+++ b/tools/aidl/AST.cpp
@@ -845,23 +845,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/generate_java.cpp b/tools/aidl/generate_java.cpp
index 622b691..0f18132 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/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java b/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
index df1876d..c562650 100644
--- a/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
+++ b/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
@@ -24,35 +24,40 @@ import java.util.Map;
* <p/>
* <p/>{@link #getApiLevel()} gives the ability to know which methods are available.
* <p/>
+ * Changes in API level 4:
+ * <ul>
+ * <li>new render method: {@link #computeLayout(IXmlPullParser, Object, int, int, boolean, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * <li>deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * </ul>
* Changes in API level 3:
* <ul>
- * <li>{@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
- * <li> deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * <li>new render method: {@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * <li>deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
* </ul>
* Changes in API level 2:
* <ul>
- * <li>{@link #getApiLevel()}</li>
- * <li>{@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * <li>new API Level method: {@link #getApiLevel()}</li>
+ * <li>new render method: {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
* <li>deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, Map, Map, IProjectCallback, ILayoutLog)}</li>
* </ul>
*/
public interface ILayoutBridge {
-
- final int API_CURRENT = 3;
+
+ final int API_CURRENT = 4;
/**
* Returns the API level of the layout library.
* While no methods will ever be removed, some may become deprecated, and some new ones
* will appear.
* <p/>If calling this method throws an {@link AbstractMethodError}, then the API level
- * should be considered to be 1.
+ * should be considered to be 1.
*/
int getApiLevel();
/**
* Initializes the Bridge object.
* @param fontOsLocation the location of the fonts.
- * @param enumValueMap map attrName => { map enumFlagName => Integer value }.
+ * @param enumValueMap map attrName => { map enumFlagName => Integer value }.
* @return true if success.
* @since 1
*/
@@ -65,6 +70,43 @@ public interface ILayoutBridge {
* @param projectKey An Object identifying the project. This is used for the cache mechanism.
* @param screenWidth the screen width
* @param screenHeight the screen height
+ * @param renderFullSize if true, the rendering will render the full size needed by the
+ * layout. This size is never smaller than <var>screenWidth</var> x <var>screenHeight</var>.
+ * @param density the density factor for the screen.
+ * @param xdpi the screen actual dpi in X
+ * @param ydpi the screen actual dpi in Y
+ * @param themeName The name of the theme to use.
+ * @param isProjectTheme true if the theme is a project theme, false if it is a framework theme.
+ * @param projectResources the resources of the project. The map contains (String, map) pairs
+ * where the string is the type of the resource reference used in the layout file, and the
+ * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
+ * and the value is the resource value.
+ * @param frameworkResources the framework resources. The map contains (String, map) pairs
+ * where the string is the type of the resource reference used in the layout file, and the map
+ * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
+ * value is the resource value.
+ * @param projectCallback The {@link IProjectCallback} object to get information from
+ * the project.
+ * @param logger the object responsible for displaying warning/errors to the user.
+ * @return an {@link ILayoutResult} object that contains the result of the layout.
+ * @since 4
+ */
+ ILayoutResult computeLayout(IXmlPullParser layoutDescription,
+ Object projectKey,
+ int screenWidth, int screenHeight, boolean renderFullSize,
+ int density, float xdpi, float ydpi,
+ String themeName, boolean isProjectTheme,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback projectCallback, ILayoutLog logger);
+
+ /**
+ * Computes and renders a layout
+ * @param layoutDescription the {@link IXmlPullParser} letting the LayoutLib Bridge visit the
+ * layout file.
+ * @param projectKey An Object identifying the project. This is used for the cache mechanism.
+ * @param screenWidth the screen width
+ * @param screenHeight the screen height
* @param density the density factor for the screen.
* @param xdpi the screen actual dpi in X
* @param ydpi the screen actual dpi in Y
@@ -84,6 +126,7 @@ public interface ILayoutBridge {
* @return an {@link ILayoutResult} object that contains the result of the layout.
* @since 3
*/
+ @Deprecated
ILayoutResult computeLayout(IXmlPullParser layoutDescription,
Object projectKey,
int screenWidth, int screenHeight, int density, float xdpi, float ydpi,
@@ -155,7 +198,7 @@ public interface ILayoutBridge {
Map<String, Map<String, IResourceValue>> projectResources,
Map<String, Map<String, IResourceValue>> frameworkResources,
IProjectCallback projectCallback, ILayoutLog logger);
-
+
/**
* Clears the resource cache for a specific project.
* <p/>This cache contains bitmaps and nine patches that are loaded from the disk and reused
diff --git a/tools/layoutlib/bridge/src/android/webkit/WebView.java b/tools/layoutlib/bridge/src/android/webkit/WebView.java
index 42e4dfa..3b66188 100644
--- a/tools/layoutlib/bridge/src/android/webkit/WebView.java
+++ b/tools/layoutlib/bridge/src/android/webkit/WebView.java
@@ -240,13 +240,6 @@ public class WebView extends MockView {
return null;
}
- public static synchronized PluginList getPluginList() {
- return null;
- }
-
- public void refreshPlugins(boolean reloadOpenPages) {
- }
-
public View getZoomControls() {
return null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 145a045..55fe4ac 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -312,6 +312,7 @@ public final class Bridge implements ILayoutBridge {
}
/*
+ * For compatilibty purposes, we implement the old deprecated version of computeLayout.
* (non-Javadoc)
* @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
*/
@@ -321,6 +322,23 @@ public final class Bridge implements ILayoutBridge {
Map<String, Map<String, IResourceValue>> projectResources,
Map<String, Map<String, IResourceValue>> frameworkResources,
IProjectCallback customViewLoader, ILayoutLog logger) {
+ return computeLayout(layoutDescription, projectKey,
+ screenWidth, screenHeight, false /* renderFullSize */,
+ density, xdpi, ydpi, themeName, isProjectTheme,
+ projectResources, frameworkResources, customViewLoader, logger);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, boolean, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
+ */
+ public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
+ int screenWidth, int screenHeight, boolean renderFullSize,
+ int density, float xdpi, float ydpi,
+ String themeName, boolean isProjectTheme,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback customViewLoader, ILayoutLog logger) {
if (logger == null) {
logger = sDefaultLogger;
}
@@ -393,15 +411,39 @@ public final class Bridge implements ILayoutBridge {
root.setBackgroundDrawable(d);
}
- int w_spec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);
- int h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
- MeasureSpec.EXACTLY);
-
// measure the views
+ int w_spec, h_spec;
+
+ if (renderFullSize) {
+ // measure the full size needed by the layout.
+ w_spec = MeasureSpec.makeMeasureSpec(screenWidth,
+ MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
+ h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
+ MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
+ view.measure(w_spec, h_spec);
+
+ int neededWidth = root.getChildAt(0).getMeasuredWidth();
+ if (neededWidth > screenWidth) {
+ screenWidth = neededWidth;
+ }
+
+ int neededHeight = root.getChildAt(0).getMeasuredHeight();
+ if (neededHeight > screenHeight - screenOffset) {
+ screenHeight = neededHeight + screenOffset;
+ }
+ }
+
+ // remeasure with only the size we need
+ // This must always be done before the call to layout
+ w_spec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);
+ h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
+ MeasureSpec.EXACTLY);
view.measure(w_spec, h_spec);
+
+ // now do the layout.
view.layout(0, screenOffset, screenWidth, screenHeight);
- // draw them
+ // draw the views
Canvas canvas = new Canvas(screenWidth, screenHeight - screenOffset, logger);
root.draw(canvas);
@@ -1014,6 +1056,10 @@ public final class Bridge implements ILayoutBridge {
// pass for now.
}
+ public void setWallpaperPosition(IBinder window, float x, float y) {
+ // pass for now.
+ }
+
public IBinder asBinder() {
// pass for now.
return null;
@@ -1041,12 +1087,12 @@ public final class Bridge implements ILayoutBridge {
}
@SuppressWarnings("unused")
- public void dispatchPointer(MotionEvent arg0, long arg1) throws RemoteException {
+ public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
// pass for now.
}
@SuppressWarnings("unused")
- public void dispatchTrackball(MotionEvent arg0, long arg1) throws RemoteException {
+ public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
// pass for now.
}
@@ -1067,6 +1113,11 @@ public final class Bridge implements ILayoutBridge {
// pass for now.
}
+ @SuppressWarnings("unused")
+ public void dispatchWallpaperOffsets(float x, float y) {
+ // pass for now.
+ }
+
public IBinder asBinder() {
// pass for now.
return null;
diff --git a/tools/localize/Perforce.cpp b/tools/localize/Perforce.cpp
index 1c644ed..ae11231 100644
--- a/tools/localize/Perforce.cpp
+++ b/tools/localize/Perforce.cpp
@@ -6,7 +6,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 2533f0a..184bfe0 100644
--- a/tools/localize/SourcePos.cpp
+++ b/tools/localize/SourcePos.cpp
@@ -3,6 +3,7 @@
#include <stdarg.h>
#include <cstdio>
#include <set>
+#include <cstdio>
using namespace std;
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 293e50e..775ce2f 100644
--- a/tools/localize/file_utils.cpp
+++ b/tools/localize/file_utils.cpp
@@ -8,6 +8,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 678cad8..1d0ac9a 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 e4ab562..6fe2629 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"
#include <stdio.h>
diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java
index f71bbea..6df612e 100644
--- a/vpn/java/android/net/vpn/VpnManager.java
+++ b/vpn/java/android/net/vpn/VpnManager.java
@@ -45,18 +45,25 @@ public class VpnManager {
/** Key to the error code of a connectivity broadcast event. */
public static final String BROADCAST_ERROR_CODE = "err";
/** Error code to indicate an error from authentication. */
- public static final int VPN_ERROR_AUTH = 1;
+ public static final int VPN_ERROR_AUTH = 51;
/** Error code to indicate the connection attempt failed. */
- public static final int VPN_ERROR_CONNECTION_FAILED = 2;
+ public static final int VPN_ERROR_CONNECTION_FAILED = 101;
/** Error code to indicate the server is not known. */
- public static final int VPN_ERROR_UNKNOWN_SERVER = 3;
+ public static final int VPN_ERROR_UNKNOWN_SERVER = 102;
/** Error code to indicate an error from challenge response. */
- public static final int VPN_ERROR_CHALLENGE = 4;
+ public static final int VPN_ERROR_CHALLENGE = 5;
/** Error code to indicate an error of remote server hanging up. */
- public static final int VPN_ERROR_REMOTE_HUNG_UP = 5;
+ public static final int VPN_ERROR_REMOTE_HUNG_UP = 7;
+ /** Error code to indicate an error of remote PPP server hanging up. */
+ public static final int VPN_ERROR_REMOTE_PPP_HUNG_UP = 48;
+ /** Error code to indicate a PPP negotiation error. */
+ public static final int VPN_ERROR_PPP_NEGOTIATION_FAILED = 42;
/** Error code to indicate an error of losing connectivity. */
- public static final int VPN_ERROR_CONNECTION_LOST = 6;
- private static final int VPN_ERROR_NO_ERROR = 0;
+ public static final int VPN_ERROR_CONNECTION_LOST = 103;
+ /** Largest error code used by VPN. */
+ public static final int VPN_ERROR_LARGEST = 200;
+ /** Error code to indicate a successful connection. */
+ public static final int VPN_ERROR_NO_ERROR = 0;
public static final String PROFILES_PATH = "/data/misc/vpn/profiles";
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index fa328e8..73dbb6f 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 74f4284..27755ed 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -565,14 +565,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;
}
@@ -959,7 +960,7 @@ public class WifiManager {
*
* If this MulticastLock is not reference-counted, the first call to
* {@code release} (after the radio was multicast locked using
- * {@linke #acquire}) will unlock the multicast, and subsequent calls
+ * {@link #acquire}) will unlock the multicast, and subsequent calls
* will be ignored.
*
* Note that if any other Wifi Multicast Locks are still outstanding
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 0799f5f..c3c519f 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -79,6 +79,8 @@ public class WifiNative {
public native static int getRssiCommand();
+ public native static int getRssiApproxCommand();
+
public native static int getLinkSpeedCommand();
public native static String getMacAddressCommand();
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 3aa31bf..fa24a98 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -39,6 +39,7 @@ import android.util.Log;
import android.util.Config;
import android.app.Notification;
import android.app.PendingIntent;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothA2dp;
import android.content.ContentResolver;
@@ -49,6 +50,7 @@ import com.android.internal.app.IBatteryStats;
import java.util.List;
import java.util.ArrayList;
+import java.util.Set;
import java.net.UnknownHostException;
/**
@@ -183,6 +185,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
/**
@@ -238,7 +244,6 @@ public class WifiStateTracker extends NetworkStateTracker {
private SettingsObserver mSettingsObserver;
private boolean mIsScanModeActive;
- private boolean mIsScanModeSetDueToAHiddenNetwork;
private boolean mEnableRssiPolling;
// Wi-Fi run states:
@@ -311,7 +316,6 @@ public class WifiStateTracker extends NetworkStateTracker {
mScanResults = new ArrayList<ScanResult>();
// Allocate DHCP info object once, and fill it in on each request
mDhcpInfo = new DhcpInfo();
- mIsScanModeSetDueToAHiddenNetwork = false;
mRunState = RUN_STATE_STARTING;
// Setting is in seconds
@@ -379,6 +383,14 @@ public class WifiStateTracker extends NetworkStateTracker {
}
/**
+ * Return the name of our WLAN network interface.
+ * @return the name of our interface.
+ */
+ public String getInterfaceName() {
+ return mInterfaceName;
+ }
+
+ /**
* Return the system properties name associated with the tcp buffer sizes
* for this network.
*/
@@ -576,9 +588,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;
}
@@ -592,6 +607,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);
}
@@ -631,10 +647,10 @@ public class WifiStateTracker extends NetworkStateTracker {
private void checkIsBluetoothPlaying() {
boolean isBluetoothPlaying = false;
- List<String> connected = mBluetoothA2dp.listConnectedSinks();
+ Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks();
- for (String address : connected) {
- if (mBluetoothA2dp.getSinkState(address) == BluetoothA2dp.STATE_PLAYING) {
+ for (BluetoothDevice device : connected) {
+ if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) {
isBluetoothPlaying = true;
break;
}
@@ -790,7 +806,7 @@ public class WifiStateTracker extends NetworkStateTracker {
WifiNative.closeSupplicantConnection();
}
if (died) {
- resetInterface();
+ resetInterface(false);
}
// When supplicant dies, kill the DHCP thread
if (mDhcpTarget != null) {
@@ -1023,17 +1039,12 @@ public class WifiStateTracker extends NetworkStateTracker {
* On receiving the first scan results after connecting to
* the supplicant, switch scan mode over to passive.
*/
- if (!mIsScanModeSetDueToAHiddenNetwork) {
- // This is the only place at the moment where we set
- // the scan mode NOT due to a hidden network. This is
- // what the second parameter value (false) stands for.
- setScanMode(false, false);
- }
+ setScanMode(false);
break;
case EVENT_POLL_INTERVAL:
if (mWifiInfo.getSupplicantState() != SupplicantState.UNINITIALIZED) {
- requestPolledInfo(mWifiInfo);
+ requestPolledInfo(mWifiInfo, true);
checkPollTimer();
}
break;
@@ -1164,9 +1175,7 @@ public class WifiStateTracker extends NetworkStateTracker {
return disabledNetwork;
}
- public synchronized void setScanMode(
- boolean isScanModeActive, boolean setDueToAHiddenNetwork) {
- mIsScanModeSetDueToAHiddenNetwork = setDueToAHiddenNetwork;
+ public synchronized void setScanMode(boolean isScanModeActive) {
if (mIsScanModeActive != isScanModeActive) {
WifiNative.setScanModeCommand(mIsScanModeActive = isScanModeActive);
}
@@ -1206,7 +1215,7 @@ public class WifiStateTracker extends NetworkStateTracker {
cancelDisconnect();
}
mDisconnectExpected = false;
- resetInterface();
+ resetInterface(true);
setDetailedState(newState);
sendNetworkStateChangeBroadcast(mLastBssid);
mWifiInfo.setBSSID(null);
@@ -1219,7 +1228,7 @@ public class WifiStateTracker extends NetworkStateTracker {
* Resets the Wi-Fi interface by clearing any state, resetting any sockets
* using the interface, stopping DHCP, and disabling the interface.
*/
- public void resetInterface() {
+ public void resetInterface(boolean reenable) {
mHaveIpAddress = false;
mObtainingIpAddress = false;
mWifiInfo.setIpAddress(0);
@@ -1240,6 +1249,9 @@ public class WifiStateTracker extends NetworkStateTracker {
}
NetworkUtils.disableInterface(mInterfaceName);
+ if (reenable) {
+ NetworkUtils.enableInterface(mInterfaceName);
+ }
}
/**
@@ -1278,7 +1290,7 @@ public class WifiStateTracker extends NetworkStateTracker {
*/
public WifiInfo requestConnectionInfo() {
requestConnectionStatus(mWifiInfo);
- requestPolledInfo(mWifiInfo);
+ requestPolledInfo(mWifiInfo, false);
return mWifiInfo;
}
@@ -1333,10 +1345,14 @@ public class WifiStateTracker extends NetworkStateTracker {
* Get the dynamic information that is not reported via events.
* @param info the object into which the information should be captured.
*/
- private synchronized void requestPolledInfo(WifiInfo info)
+ private synchronized void requestPolledInfo(WifiInfo info, boolean polling)
{
int newRssi = WifiNative.getRssiCommand();
- if (newRssi != -1 && -200 < newRssi && newRssi < 100) { // screen out invalid values
+ if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
+ /* some implementations avoid negative values by adding 256
+ * so we need to adjust for that here.
+ */
+ if (newRssi > 0) newRssi -= 256;
info.setRssi(newRssi);
/*
* Rather then sending the raw RSSI out every time it
@@ -1453,6 +1469,7 @@ public class WifiStateTracker extends NetworkStateTracker {
public synchronized boolean restart() {
if (mRunState == RUN_STATE_STOPPED) {
mRunState = RUN_STATE_STARTING;
+ resetInterface(true);
return WifiNative.startDriverCommand();
} else if (mRunState == RUN_STATE_STOPPING) {
mRunState = RUN_STATE_STARTING;
@@ -1879,7 +1896,7 @@ public class WifiStateTracker extends NetworkStateTracker {
oDns2 != mDhcpInfo.dns2));
if (changed) {
- resetInterface();
+ resetInterface(true);
configureInterface();
if (mUseStaticIp) {
mTarget.sendEmptyMessage(EVENT_CONFIGURATION_CHANGED);